Невозможно нарисовать ссылки по свойству узла, используя раскладку D3

1

Я пытаюсь сделать силовой макет на D3 для сетевой визуализации с узлами и ссылками. Я немного использовал v3, но я переключился на v5, чтобы иметь возможность связывать узлы с использованием атрибутов узлов вместо индексов узлов (что требовало дополнительных шагов в d3 v3).

Я получил этот код

https://jsfiddle.net/lioneluranl/4fxpp2co/1/

var linkpath = ("links.csv");
var nodepath = ("nodes.csv");
var svg = d3.select("svg");
var width = svg.attr("width");
var height = svg.attr("height");
var simulation = d3.forceSimulation();   

var nodes = [];
var links = [];

d3.csv(nodepath, function(d){
  node = {
    id: d.node,
    group: d.group,
    node: d.node
  };  

  nodes.push(node);

  d3.csv(linkpath, function(d){
    link = {
      source: d.source,
      target: d.target,
      type: d.type
    }; 

    links.push(link);

  });

}).then( function() {

  //console.log(links);
  //console.log(nodes);

  simulation
      .force("link", d3.forceLink().id(function(d) { /*console.log(d);*/ return d.id; }))
      .nodes(nodes)      
      .force("collide", d3.forceCollide().radius(10))
      .force("r", d3.forceRadial(function(d) { 
        if(d.group === "compound"){          
          return 240;
        } else { return d.group === "annotation" ? 0 : 100; }}))      

  // Create the link lines.
  var link = svg.append("g")
    .attr("class", "links")
    .selectAll("line")
    .data(links)
    .enter().append("line")
    .attr("stroke", "black")
    .attr("stroke-width", 4)
    .attr("class", function(d) { return "link " + d.type; });

  // Create the node circles.
 var node = svg.append("g")
      .attr("class", "node")
      .selectAll("circle")
      .data(nodes)
      .enter().append("circle")
      .attr("r", 8)
      .attr("class", function (d){ 

        return d.group;

      });

 simulation.on("tick", ticked);
 simulation.force("link").links(links);

function ticked() {
  node
      .attr("cx", function(d) { return d.x; })
      .attr("cy", function(d) { return d.y; });

  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; });
}


}); 

Которая была адаптирована из этого

https://bl.ocks.org/mbostock/cd98bf52e9067e26945edd95e8cf6ef9

У меня нет проблем с рисованием узлов, но я не могу нарисовать ссылки. Связанная документация указывает, что, как я думаю, я делаю, атрибуты узлов должны быть переданы в синтаксические ссылки, но я получаю эту ошибку:

TypeError: can't assign to property "vx" on "PF05257": not an object

Кроме того, при этом узлы будут вести себя не так, как ожидалось на макете (набор радиальных сил не будет работать, см. Прикрепленные изображения), предполагая, что этот атрибут link-by-node возится с моей симуляцией.

Изображение 174551 Изображение 174551

CSV содержат следующие данные:

nodes.csv:

node,group
C236103,compound
C327961,compound
C337527,compound
C376038,compound
C543486,compound
T24871,target
T27222,target
T33516,target
T33937,target
OG5_135897,annotation
PF01529,annotation
PF05257,annotation
PF11669,annotation
...

links.csv

source,target,type
T24871,PF05257,annotation
T27222,PF05257,annotation
T33516,PF01529,annotation
T33516,PF05257,annotation
T33516,PF11669,annotation
T33937,PF05257,annotation
T24871,C561727,bioactivity
T24871,C337527,bioactivity
T24871,C585910,bioactivity
...

Просто для справки и проверки целостности целостности данных, я получил эту работу на d3 v3. Изображение 174551

Есть идеи?

Теги:
d3.js
promise

1 ответ

2
Лучший ответ

Вот конструктивная критика: правильно откорректируйте свой код 1.

В первый раз, когда я прочитал его, я пропустил проблему из-за неправильного отступа. Но тогда, с правильным отступом, вопрос ясен, посмотрите на это:

d3.csv(nodepath, function(d) {
    node = {
        id: d.node,
        group: d.group,
        node: d.node
    };

    nodes.push(node);

    d3.csv(linkpath, function(d) {
        link = {
            source: d.source,
            target: d.target,
            type: d.type
        };

        links.push(link);

    });
})

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

Правильный подход здесь заключался бы в определении обещаний (для некоторых это анти-шаблон) или, что еще лучше, использования Promise.all (поскольку в v5 нет d3.queue):

var promises = [d3.csv("nodes.csv"), d3.csv("links.csv")];

Promise.all(promises).then(function(data) {
    var links = data[1];
    var nodes = data[0];
    //rest of the code here
});

В качестве дополнительного наконечника, вам не нужно раздвигать объекты массивов во внешней сфере: просто иметь дело с параметром внутри then.

Кроме того, вам не нужна функция row для обоих CSV, так как ваши функции строк ничего не делают прямо сейчас (помимо дублирования node как id они просто возвращают тот же объект, который у вас будет без них).

Вот bl.ocks с вашим кодом и данными, используя Promise.all:

https://bl.ocks.org/GerardoFurtado/30cb90cc9eb4f239f59b323bbdfe4293/3049fc77b8461232b6b149f39066ec39e0d111c1


1 Большинство текстовых редакторов, таких как Sublime Text, имеют плагины для отступов. Вы также можете найти несколько хороших инструментов онлайн, например, таких, как этот.

  • 0
    Snap ... большое спасибо! Я пойду и протестирую это. Извините за проблему с отступами. Я использовал функцию Jsfiddle beautify, но на самом деле не проверял, правильно ли она имеет отступ.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню