Разметка силы D3 из CSV с несколькими ребрами в ряду - PullRequest
0 голосов
/ 29 апреля 2018

Я пытаюсь создать расклад сил D3 (v3) из CSV, содержащего несколько ребер в строке:

"c.compound","mt.entry","mt.protein_names","tt.gene_name","tt.gene_product","omcl.omcl_clusterid"
"TCMDC-143527","A0A059UE90","Glycogen synthase kinase-3 beta splice variant X1","TcCLB.507993.80","glycogen synthase kinase 3, putative","OG5_126888"
"TCMDC-143376","A0A059UE90","Glycogen synthase kinase-3 beta splice variant X1","TcCLB.507993.80","glycogen synthase kinase 3, putative","OG5_126888"
"TCMDC-143527","A0A059UE90","Glycogen synthase kinase-3 beta splice variant X1","Tb427.10.13780","glycogen synthase kinase 3","OG5_126888"
"TCMDC-143376","A0A059UE90","Glycogen synthase kinase-3 beta splice variant X1","Tb427.10.13780","glycogen synthase kinase 3","OG5_126888"
...

Мне нужна эта раскладка силы для отражения следующих ребер:

c.compound -> mt.accession
mt.entry -> omcl.omcl_clusterid
tt.gene_name -> omcl.omcl_clusterid

Я новичок в D3, поэтому я начал с примера кода, задающего mbostock на github. Этот пример получает файл CSV, анализирует его строка за строкой и извлекает ребра от A до B (один за рядом) из CSV, как показано ниже

source, target
"A", "B"
"B", "C"
...

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

  d3.csv("allomcl_putative_test.csv", function(error, links) {
  if (error) throw error;

  var nodesByName = {};
  var rels = [];
  // Create nodes for each unique source and target.
  links.forEach(function(link) {

      var compound = nodeByName(link["c.compound"]);
      var mt = nodeByName(link["mt.entry"]);
      var tt = nodeByName(link["tt.gene_name"]);
      var omcl = nodeByName(link["omcl.omcl_clusterid"]);

      rels.push({
          "source": compound.name,
          "target": mt.name
      });
      rels.push({
          "source": mt.name,
          "target": omcl.name
      });
      rels.push({
          "source": tt.name,
          "target": omcl.name
      });

  });

  rels.forEach(function(d) {

      link = {
          "source": d.source,
          "target": d.target
      };
  });

...

Я вошел в консоль, что и ссылки, и узлы собираются должным образом, но я не могу запустить принудительную компоновку. Консоль Javascript выдаст следующую ошибку:

TypeError: r.source is undefined[Learn More]
d3.v3.min.js:4:22668
ao.layout.force/l.start
https://d3js.org/d3.v3.min.js:4:22668
<anonymous>
file:///root/to/my/file/test.js:74:7
Cn/u.send/<
https://d3js.org/d3.v3.min.js:1:11277
t
https://d3js.org/d3.v3.min.js:1:1563
i
https://d3js.org/d3.v3.min.js:1:10130

Есть идеи как это исправить?

1 Ответ

0 голосов
/ 29 апреля 2018

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

  function nodeByName(name) {
      return nodesByName[name] || (nodesByName[name] = {
          name: name,
          index: nodeid++
      });
  }

... с переменным nodeid, созданным перед синтаксическим анализом csv, и автоинкрементом себя при каждом создании узла.

Затем я изменил кусок кода создания края, чтобы использовать эти индексы:

  rows.forEach(function(link) {

      var compound = nodeByName(link["c.compound"]);
      var mt = nodeByName(link["mt.entry"], link["mt.protein_names"]);
      var tt = nodeByName(link["tt.gene_name"], link["tt.gene_product"]);
      var omcl = nodeByName(link["omcl.omcl_clusterid"]);          

      rels.push({
          "source": compound.index,
          "target": mt.index
      });
      rels.push({
          "source": mt.index,
          "target": omcl.index
      });
      rels.push({
          "source": tt.index,
          "target": omcl.index
      });

  });

Теперь он работает как положено:

enter image description here

...