D3.js направленный граф, уменьшает пересечения кромок, заставляя края отталкивать друг друга
Итак, у меня есть страница, которая рисует диаграмму направленности силы, например, показанную здесь здесь.
И это прекрасно работает. Я использую JS из здесь, с несколькими настройками, чтобы немного расширить узлы.
Это более или менее единственные отличия:
d3.json("force.json", function(json) {
var force = d3.layout.force()
.gravity(0.1)
.charge(-2000)
.linkDistance(1)
.linkStrength(0.1)
.nodes(json.nodes)
.links(json.links)
.size([w, h])
.start();
Там, где сокращение прочности связи, похоже, делает ссылки более похожими на пружины, поэтому она становится похожей на часто используемую технику Fruchterman и Reingold. Это работает достаточно хорошо, но только для довольно небольших графиков. С большими графиками количество переходов просто растет - как и следовало ожидать, но решение, на которое он приземляется, обычно далек от оптимального. Я не ищу способ получить оптимальное решение, я знаю, что это очень сложно. Я просто хотел бы, чтобы у него было грубое дополнение, которое пытается закрепить линии друг от друга, а также узлы.
Есть ли способ добавить отталкивание между ссылками, а также между узлами? Я не знаком с тем, как работает сила D3, и я не могу найти ничего что это возможно...
Ответы
Ответ 1
К сожалению, ответа на ваш вопрос не существует.
В D3 нет встроенного механизма, который отталкивает края или сводит к минимуму пересечения кромок. Вы могли бы подумать, что было бы трудно реализовать заряд на грани, но мы здесь.
Кроме того, не существует какого-либо механизма где-либо, который уменьшает пересечения ребер в целом. Я просмотрел десятки библиотек визуализации и алгоритмов компоновки, и ни один из них не связан с уменьшением пересечений границ на общем неориентированном графе.
Существует ряд алгоритмов, которые хорошо работают для планарных графиков или двухуровневых графиков или других упрощений. dagre хорошо работает в теории для двухуровневых графиков, хотя полная нехватка документации делает практически невозможным работу.
Частично это объясняется тем, что выкладка графиков жесткая. В частности, минимизация пересечений кромок NP-hard, поэтому я подозреваю, что большинство дизайнеров макетов поразило эту проблему, несколько раз ударило головой о клавиатуру и сдался.
Если у кого-то есть хорошая библиотека для этого, пожалуйста, опубликуйте ее для остальных из нас:)
Ответ 2
Что-то, что может быть проще, чем пытаться сильно отразить ребра, - это покачивать узлы вокруг, пока количество линий пересечения в системе не будет ниже.
http://en.wikipedia.org/wiki/Simulated_annealing
Начните с узлов с наименьшим количеством соединений и пошагите.
Если вы попытаетесь использовать ребра в качестве узлов, я подозреваю, что вы просто получите те же проблемы с пространственной блокировкой. Решение состоит в том, чтобы выяснить, где есть пересечения ребер, и если они могут быть разрешены. Вы можете обнаружить, что разрешить многие перекрестки края невозможно
Более латеральный подход к визуализации заключается в том, чтобы анимировать его таким образом, чтобы он отображал только подмножество узлов и соединений за раз. Или сделать края прозрачными, пока пользователь не наложит фокус мыши на node, что указывает на то, что связанные ребра становятся более видимыми.
Ответ 3
Я следовал примеру Force Editor, и я увидел, что параметры charge
и linkDistance
решают проблему.
...
.charge(-200)
.linkDistance(50)
...
Скриншот:
![enter image description here]()
Ответ 4
Я "решил" проблему с этим:
nodes[0].x = width / 2;
nodes[0].y = 100;
nodes[0].fixed = true;
force.on("tick", function(e) {
var kx = .4 * e.alpha, ky = 1.4 * e.alpha;
links.forEach(function(d, i) {
d.target.x += (d.source.x - d.target.x) * kx;
d.target.y += (d.source.y + 80 - d.target.y) * ky;
});
[...]
}
http://mbostock.github.io/d3/talk/20110921/parent-foci.html
Это не совсем то, что мы хотели, но лучше, чем раньше.
Importend - это то, что вы определяете "root" - Node и исправляете его.
nodes[0].fixed = true;
Он выглядит больше как дерево, но так яснее.