You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'll preface with a disclaimer that I might be using the library wrong. Still, it would be helpful to know what the expected answer to this problem is. Roughly what I'm doing:
Have a var simNodes that contains the nodes used for the sims.
Have a var simLinks that contains the links used.
Remove a node (let's call it node11) from simNodes along with any simLinks entry that references it.
Call simulation.nodes(simNodes) to remove the node from the simulation.
Call simulation.force("links").links(simLinks) to remove the forces that were acting on that node.
Call alpha and restart to kick the graph into action.
After a bunch of debugging I discovered that the problem I'm running into is that the objects in simLinks have source and target defined as getters instead of just references. When a force that acted on node11 was evaluated by the simulation the getter would return the entry in simNodes for node11 ... which is fine if the node exists, but those links are getting evaluated after I removed the node and that's a problem. I thought I had accidentally left a link somehow but couldn't find a source. Much digging later I found this note:
If nodes is specified, sets the simulation’s nodes to the specified array of objects, initializing their positions and velocities if necessary, and then re-initializes any bound forces; returns the simulation.
Re-initializes the forces? Eh? Further down, forceLink says...
When the link force is initialized (or re-initialized, as when the nodes or links change), any link.source or link.target property which is not an object is replaced by an object reference to the corresponding node with the given identifier.
So, if I'm understanding all this correctly, updating either the nodes or links causes an evaluation of the source and target of all links, which in this case means step 4 triggers access of the links before I can update them in step 5. If I flip those two steps, so I update the links before nodes, I'll hit the same issue when adding nodes instead. If I have a change set that both adds and removes nodes I'd get the error regardless of which I tried to update first.
I know the obvious answer here is to not use a getter but I'd prefer to keep them if possible. Another obvious answer would be to return a dummy object, but that feels event worse. Looking at the code, though, it seems like the same issue exists when links are referenced by identifier like in the second quote...
link = links[i], link.index = i;
if (typeof link.source !== "object") link.source = find(nodeById, link.source);
if (typeof link.target !== "object") link.target = find(nodeById, link.target);
count[link.source.index] = (count[link.source.index] || 0) + 1;
count[link.target.index] = (count[link.target.index] || 0) + 1;
}```
It seems to me that if initialize gets called with links where the source or target are identifiers, and that identifier refers to a node not in the sim, find throws an error and the call to links() fails. Since the property is overwritten it shouldn't be an issue when removing nodes, no lookup is done in that case. It would be a problem if you tried to add to the simulation though, specifically when adding the link before adding the node.
Thoughts? Is there a sensible way to do this without making `.source` and `.target` be objects? Is there supposed to be an order for updating the nodes and forces?
For the time being I'm using a work around of calling `simulation.force("links").links([])" before updating the node list in step 4, so as to change the node list while there's no links present, but that's not exactly optimal.
This discussion was converted from issue #3622 on January 08, 2023 16:08.
Heading
Bold
Italic
Quote
Code
Link
Numbered list
Unordered list
Task list
Attach files
Mention
Reference
Menu
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
I'll preface with a disclaimer that I might be using the library wrong. Still, it would be helpful to know what the expected answer to this problem is. Roughly what I'm doing:
var simNodes
that contains the nodes used for the sims.var simLinks
that contains the links used.node11
) from simNodes along with any simLinks entry that references it.simulation.nodes(simNodes)
to remove the node from the simulation.simulation.force("links").links(simLinks)
to remove the forces that were acting on that node.After a bunch of debugging I discovered that the problem I'm running into is that the objects in
simLinks
havesource
andtarget
defined as getters instead of just references. When a force that acted onnode11
was evaluated by the simulation the getter would return the entry insimNodes
fornode11
... which is fine if the node exists, but those links are getting evaluated after I removed the node and that's a problem. I thought I had accidentally left a link somehow but couldn't find a source. Much digging later I found this note:Re-initializes the forces? Eh? Further down, forceLink says...
So, if I'm understanding all this correctly, updating either the nodes or links causes an evaluation of the source and target of all links, which in this case means step 4 triggers access of the links before I can update them in step 5. If I flip those two steps, so I update the links before nodes, I'll hit the same issue when adding nodes instead. If I have a change set that both adds and removes nodes I'd get the error regardless of which I tried to update first.
I know the obvious answer here is to not use a getter but I'd prefer to keep them if possible. Another obvious answer would be to return a dummy object, but that feels event worse. Looking at the code, though, it seems like the same issue exists when links are referenced by identifier like in the second quote...
https://github.com/d3/d3-force/blob/main/src/link.js#L58
Beta Was this translation helpful? Give feedback.
All reactions