Как я могу сделать выпуклые оболочки нескольких узлов групповой сети в D3.js

Я пытаюсь создать сетевую диаграмму, в которой узлы сгруппированы по свойству и в которой они объединены в группу как с расположением (принудительное расположение), так и с использованием выпуклой оболочки. Подобно этому, но без щелчка, чтобы свернуть/развернуть. Эта модель/код слишком сложна для новичка, чтобы анализировать и учиться.

Мой вопрос можно сформулировать проще: есть ли пример кода возможности network+grouped, который включает возможность узлов в нескольких группах?

Иногда в группе будет только один узел, а базовая выпуклая оболочка не работает менее чем для трех. В приведенном выше примере есть исправление для этого (чего я не понимаю), как и в этом, который создает невидимые узлы и может быть проще.

Группы могут быть вложены в несколько слоев. Это руководство содержит всю информацию, необходимую для использования d3.nest() для получения данных в иерархии. Но это может быть и не иерархия, может случиться так, что узел находится в нескольких группах и должен находиться в правильном корпусе и месте. Некоторые узлы не будут входить ни в одну группу, но все равно будут подключены к сети.

Я знаю, что силы в макетах сил складываются, поэтому не должно быть проблемой, чтобы и группы, и связи влияли на расположение узлов простым способом, но я не видел простого примера этого. Мой подход состоит в том, чтобы добавить сетевые подключения к примеру с несколькими фокусами и посмотреть, смогу ли я заставить это работать.

В качестве бонуса узлы не должны перекрываться, а для иерархических элементов узлы базового слоя должны располагаться по кругу так, чтобы узлы, находящиеся в нескольких группах, находились между этими группами вот так. Я упомянул об этом сейчас, потому что стремление к этим функциям может привести к лучшему решению вышеуказанных желаний.

Я буду работать над этим созданием из этого JSFiddle; Я буду продолжать обновлять и уточнять этот вопрос по мере того, как буду работать над кодом самостоятельно. Я был бы признателен за любые указатели на код, который ближе, чем складной, к тому, что я хочу, оговорки об ограничениях/проблемах D3 (например, необходимость обходного пути для выпуклых оболочек из 1-2 узлов) и код, который обеспечивает один из этих возможности в понятной и модульной форме для достижения конечной цели. Действительно, любая помощь приветствуется.


person Aaron Bramson    schedule 09.11.2015    source источник
comment
Я вычислил слоистую выпуклую оболочку как для перекрывающихся, так и для иерархических групп, включая группы с одним узлом. Вы можете проверить это в этом обновленном JSFiddle. Я также смог получить подгруппы по всему кругу, но я прокомментировал это, чтобы вместо этого иметь более тесные связи внутри групп. Это может быть возможно, просто используя умные функции для linkDistance и linkStrength в зависимости от групп... каким-то образом. Кроме того, как мы можем получить ссылки поверх выпуклых оболочек? Перерисовывать их каждый тик вместо обновления их координат x, y?   -  person Aaron Bramson    schedule 12.11.2015
comment
Я задал и ответил на вопрос о том, как заставить выпуклые оболочки обернуть узлы разных размеров в этот вопрос, который приводит нас к этому самый последний JSFiddle для этого вопроса.   -  person Aaron Bramson    schedule 16.11.2015
comment
Хорошо, теперь у меня перерисованы ребра поверх выпуклых оболочек, а затем узлы перерисованы поверх ссылок в этот обновленный JSFiddle. Все, что осталось для этой возможности, — заставить группировки соответствующим образом влиять на расположение сил, как в в этом примере, но без всего лишнего.   -  person Aaron Bramson    schedule 16.11.2015


Ответы (2)


Хотя этот вопрос не привлек особого внимания на прошлой неделе, надеюсь, ответ будет полезен для некоторых людей. Мне удалось использовать функцию для linkDistance, которая начинается с большого размера и уменьшается в зависимости от (1) того, находятся ли источник и цель в одной и той же коллекции, и (2) уровня этой коллекции, то есть групп, подгрупп или подгрупп.

Основная идея решения возникла из единственного примера этой возможности, который мне удалось найти. Фактическая функция linkDistance, которую я использовал, представляет собой несколько упрощенный подход, но он хорошо справляется со своей задачей и может быть легко адаптирован для множества других целей для многих других людей (я надеюсь). В зависимости от ваших группировок вы можете настроить другие функции ссылок (например, цвет) с помощью функций, подобных тем, которые я использовал здесь.

force
    .nodes(graph.nodes)
    .links(graph.links)
    .linkDistance(function(thisLink) { 
        var myLength = 100, theSource = thisLink.source, theTarget = thisLink.target;
        groupNodes.forEach(function(groupList) { 
            if (groupList.indexOf(theSource) >= 0 && groupList.indexOf(theTarget) >= 0) {
                myLength = myLength * 0.7;
            }
        });
        subgroupNodes.forEach(function(groupList) { 
            if (groupList.indexOf(theSource) >= 0 && groupList.indexOf(theTarget) >= 0) {
                myLength = myLength * 0.4;
            }
        });
        subsubgroupNodes.forEach(function(groupList) { 
            if (groupList.indexOf(theSource) >= 0 && groupList.indexOf(theTarget) >= 0) {
                myLength = myLength * 0.2;
            }
        });
        return myLength; } )
    .linkStrength(function(l, i) { return 1; } )
    .gravity(0.05)   
    .charge(-600)   
    .friction(0.5)  
    .start();

Версию этого решения вместе с другими улучшениями можно найти по адресу этот JSFiddle.

Хотя это отвечает на мой вопрос, регулируя силы ссылок по членству в группе, оно не объединяет силы ссылок + группы так, как я планировал изначально. Хотелось бы еще возможности придать подподгруппам "желание" отходить друг от друга в углы, но сдерживаться соединяющими их ребрами (а не заставлять их располагаться по кругу).

Обратите внимание, что мои группы определяются экзогенно как списки списков. Если членство в группе в вашем случае является свойством узла, то вы можете использовать функцию d3.nest() для создания групп узлов, которые мне пришлось создать с помощью функции сопоставления, но я не думаю, что это сработает, если группы имеют перекрывающиеся элементы.

person Aaron Bramson    schedule 16.11.2015

Это отличный пример, многие сетевые библиотеки, включая Cytoscape.js, не допускают такого сложного группирования. У меня есть 2 вопроса:

  1. Со ссылкой на: «Все, что осталось для этой возможности, — это заставить группировки соответствующим образом влиять на принудительное размещение», сильно ли это повлияет на более крупные сети? Это в основном позволяет алгоритму компоновки учитывать группы?

  2. Я пытаюсь перенести ваш подход на d3 v4, и мне просто интересно, пытались ли вы уже это сделать?

person Fede    schedule 04.03.2020
comment
Для (1) возможно, но я не знаю. Вернее, в какой-то момент, конечно, будет, но мои сети не были достаточно большими, чтобы этот эффект был проблемой (особенно по сравнению с проблемами, вызванными большим количеством ребер) (2) я еще не трогал D3 v4 . - person Aaron Bramson; 05.03.2020