Настроить статический граф фиксированной макеты в d3.js - программирование

Настроить статический граф фиксированной макеты в d3.js

У меня есть пример рабочего кода (только часть <script type="text/javascript">) статического графика с использованием d3.js, как показано ниже:

        /* Create graph data */
        var nodes = [];
        for (var i = 0; i < 13; i++) 
        {
            var datum = {
                "value": i
            };
            nodes.push(datum);
        }

        var links = [{"source": 0, "target": 1},
                     {"source": 1, "target": 2},
                     {"source": 2, "target": 0},
                     {"source": 1, "target": 3},
                     {"source": 3, "target": 2},
                     {"source": 3, "target": 4},
                     {"source": 4, "target": 5},
                     {"source": 5, "target": 6},
                     {"source": 5, "target": 7},
                     {"source": 6, "target": 7},
                     {"source": 6, "target": 8},
                     {"source": 7, "target": 8},
                     {"source": 9, "target": 4},
                     {"source": 9, "target": 11},
                     {"source": 9, "target": 10},
                     {"source": 10, "target": 11},
                     {"source": 11, "target": 12},
                     {"source": 12, "target": 10}];

        /* Create force graph */
        var w = 800;
        var h = 500;

        var size = nodes.length;
        nodes.forEach(function(d, i) { d.x = d.y = w / size * i});

        var svg = d3.select("body").append("svg")
                    .attr("width", w)
                    .attr("weight", h);

        var force = d3.layout.force()
                      .nodes(nodes)
                      .links(links)
                      .linkDistance(200)
                      .size([w, h]);

        setTimeout(function() {

            var n = 400
            force.start();
            for (var i = n * n; i > 0; --i) force.tick();
            force.stop();

            svg.selectAll("line")
               .data(links)
               .enter().append("line")
               .attr("class", "link")
               .attr("x1", function(d) { return d.source.x; })
               .attr("y1", function(d) { return d.source.y; })
               .attr("x2", function(d) { return d.target.x; })
               .attr("y2", function(d) { return d.target.y; });

            svg.append("svg:g")
               .selectAll("circle")
               .data(nodes)
               .enter().append("svg:circle")
               .attr("class", "node")
               .attr("cx", function(d) { return d.x; })
               .attr("cy", function(d) { return d.y; })
               .attr("r", 15);

            svg.append("svg:g")
               .selectAll("text")
               .data(nodes)
               .enter().append("svg:text")
               .attr("class", "label")
               .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
               .attr("text-anchor", "middle")
               .attr("y", ".3em")
               .text(function(d) { return d.value; });

        }, 10);

и он создает этот довольно скремблированный макет:

enter image description here

Хотя это технически правильный граф, идеальный макет должен быть чем-то вроде этого (игнорируя различную визуальную графику):

enter image description here

Обратите внимание, что макет должен быть исправлен, так что перезагрузка страницы не изменяет расположение каждого node; макет также должен быть статичным, поскольку нет эффекта анимации, и узлы не перетаскиваются. Оба требования уже достигнуты в script выше.

Итак, как мне настроить этот d3 script, чтобы создать макет, показанный на втором изображении?

4b9b3361

Ответ 1

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

feYPL.png

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