vasturiano / 3d-force-graph

3D force-directed graph component using ThreeJS/WebGL
https://vasturiano.github.io/3d-force-graph/example/large-graph/
MIT License
4.79k stars 831 forks source link

Display wrong when there are links.id not in nodes.id #629

Open Yrobot opened 1 year ago

Yrobot commented 1 year ago

Describe the bug There will be only one node displayed in the canvas if there are link which target ot source not in the nodes list

To Reproduce

https://codesandbox.io/s/3d-force-directed-graph-bug-links-id-p5fkgt?file=/index.html

when set source to '4'

Expected behavior

At least ignore the wrong link, not effect the nodes display.

Screenshots

image image
vasturiano commented 1 year ago

This exception is thrown in the underlying library d3-force-3d at the time that the links are indexed. I'm not sure that silently ignoring the broken links would be a good design here, because it wouldn't alert the developer to it. This is an issue with the input data, if the data is incorrect the module should surface the error.

Yrobot commented 1 year ago

Hi @vasturiano, love the package, thanks a lot.

For the data issue, i get your point, which is better for the development. But for the production env, this will make thing worse. The error log is enough for debug, the availability is more important for the production env.

thephox1982 commented 1 year ago

I am trying to work around the same issue, with adding dynamic data. Say you have one set and another set and if the second set loads before the first based on user search query, it throws error and breaks the entire graph just because links are missing, and the graph can no longer work properly, this is HIGHLY annoying as I want the end user to search for something and then add another result and see what links to who based on multiple result sets.

Right now in order for say a user to search for a brand name and then later add Company results to the graph, it has to be done Company > Brand as the other way breaks the graph. So I'm having to make a dataset builder on the server side to get results for Brands then also retrieve a growing list of companies and search through them to find the parents adding more processing expense then just say, having the links refresh when data gets added and ignoring or at least not breaking results. I can't even wrap the graphData into a try/catch as it doesn't catch the error as it throws it anyways which is just nasty.

thephox1982 commented 1 year ago

I was able to solve my issue by doing;

      var { nodes, links } = graph.graphData();
      let newNodes = [...nodes];
      let newLinks = [...links];

      if(res.error !== true){
        let theNodes = res.nodes;
        let theLinks = res.links;

        $.each(theNodes, (i, v) => {
          newNodes.push(v);

          $.each(theLinks, (ii, vv) => {
            // Check links for node in target
            if(v.id === vv.target){
              // Check graph for the node before adding link!
              let fnd = false;
              $.each(newNodes, (iii, vvv) => {
                if(vv.source === vvv.id){
                  newLinks.push(vv);
                }
              });
            }
            if(v.id === vv.source){
              console.log(v.id, vv.source);
            }
          });
        });
      }

Basically, I check the incoming links against the nodes already in the graph. First it checks whether the current node that was just added to the graph is found as a target in the incoming links, if it is then it checks if the link source is in the graph by iterating through the nodes checking if their id matches the link source. If it does match, it adds the link to the graph links, else it doesn't add the link.