d3plus / d3plus-react

React components for d3plus visualizations.
MIT License
31 stars 6 forks source link

Network error when using string value matching the id of the node in links #19

Closed AlmahaAlmalki closed 6 years ago

AlmahaAlmalki commented 6 years ago

Hi @davelandry,

I've been using d3plus-react extensively now; I like everything about it. It takes a couple of days to know all the names of the props you need. But, once you know them it's amazing.

So I tried to use the network graph, but for some reason, it only accepts this format for links (index of the node in the nodes array).

    const methods = {
      links:  [
        {source: 0, target: 1},
        {source: 0, target: 2},
        {source: 3, target: 4},
        {source: 3, target: 5},
        {source: 5, target: 0}
      ] ,
      nodes:  [
        {id:'alpha',   x: 1,   y: 1},
        {id:'beta',    x: 2,   y: 1},
        {id:'gamma',   x: 1,   y: 2},
        {id:'epsilon', x: 3,   y: 2},
        {id:'zeta',    x: 2.5, y: 1.5},
        {id:'theta',   x: 2,   y: 2}
      ],
    }

    let network = <Network config={methods} />

when I try to create the links based on the string value matching the id of the node, it just doesn't work.


    const methods = {
      links:  [
        {source: 'alpha', target: 'beta'},
        {source: 'alpha', target: 'gamma'},
        {source: 'epsilon', target: 'zeta'},
        {source: 'epsilon', target: 'theta'},
        {source: 'theta', target: 'alpha'}
      ] ,
      nodes:  [
        {id: 'alpha',   x: 1,   y: 1},
        {id: 'beta',    x: 2,   y: 1},
        {id: 'gamma',   x: 1,   y: 2},
        {id: 'epsilon', x: 3,   y: 2},
        {id: 'zeta',    x: 2.5, y: 1.5},
        {id: 'theta',   x: 2,   y: 2}
      ],
    }

    let network = <Network config={methods} />
davelandry commented 6 years ago

@AlmahaAlmalki thank you for the kind words! glad you're enjoying using d3plus 😄

This is actually intended behavior, because internally there's no way to know if the integer passed as the source/target is an index or an actual ids (because ids can be integers). The value for source and target need to either be the index of the node in the nodes array, or the actual node itself! For example, you could transform your links array like this:

const methods = {
  links:  [
    {source: 'alpha', target: 'beta'},
    {source: 'alpha', target: 'gamma'},
    {source: 'epsilon', target: 'zeta'},
    {source: 'epsilon', target: 'theta'},
    {source: 'theta', target: 'alpha'}
  ] ,
  nodes:  [
    {id: 'alpha',   x: 1,   y: 1},
    {id: 'beta',    x: 2,   y: 1},
    {id: 'gamma',   x: 1,   y: 2},
    {id: 'epsilon', x: 3,   y: 2},
    {id: 'zeta',    x: 2.5, y: 1.5},
    {id: 'theta',   x: 2,   y: 2}
  ],
}

methods.links.forEach(function(link) {
  link.source = methods.nodes.filter(function(node) {
    return node.id === link.source;
  })[0];
  link.target = methods.nodes.filter(function(node) {
    return node.id === link.target;
  })[0];
});

Let me know if that doesn't work for you!

AlmahaAlmalki commented 6 years ago

Hi @davelandry

Thanks that makes a lot of sense, there's another issue with dynamic nodes position. However, I used d3 force layout to generate the positions dynamically. But, I was wondering if there's another way to set the x and y using d3plus only?

davelandry commented 6 years ago

@AlmahaAlmalki force-directed layouts have not been implemented in 2.0 yet: https://github.com/d3plus/d3plus-network/issues/28