elm-visualization
elm-visualization copied to clipboard
Force.tick produces "NaN"s for x and y fields in Entity
Hello, I use Force.tick for an animated application of force.
I have a use case where a Entity, after a Force.tick call, comes back with "NaN" values for the x and y fields.
Here is the data. The logs happened immediatly before I call Force.tick and immediatly after I call it. I pretty-printed them for easier comprehension:
Input Force.tick:
Entities:
(x, y ) |(vx, vy)
-------------------------------------------|--------
((526.5759052118638, 293.3027712572425), |(0, 0))
((386.3512835644626, 415.9671753206878), |(0, 0))
((429.3073689756422, 189.14562685359772),|(0, 0))
((518.5317355646032, 355.4308242590064), |(0, 0))
((139.23370668342812, 246.1536023094656), |(0, 0))
----------------------------------------------------
Simulation-State:
{ alpha = 1
, alphaDecay = 0.02276277904418933
, alphaTarget = 0
, forces =
[ Links 1
[{ bias = 0.5, distance = 150, source = "3", strength = 0.5, target = "4" }
,{ bias = 0.5, distance = 150, source = "2", strength = 0.5, target = "4" }
,{ bias = 0.5, distance = 150, source = "1", strength = 0.5, target = "3" }
,{ bias = 0.5, distance = 150, source = "1", strength = 0.5, target = "2" }
,{ bias = 0.5, distance = 150, source = "0", strength = 0.5, target = "0" } -- source and target are the same here, but that is a valid state in my case!
]
, ManyBody 0.9
( Dict.fromList
[("0",-500)
,("1",-500)
,("2",-500)
,("3",-500)
,("4",-500)
]
)
,Center 400 300
]
, minAlpha = 0.001
, velocityDecay = 0.6
}
=====================================================
Output Force.tick:
(x, y ) |(vx, vy)
-------------------------------------------|--------
((527.2044879394728, 293.5724313492498), |(0, 0))
((386.14888774606607, 416.9074137596222), |(0, 0))
((430.6045558668222, 189.20225383801645),|(0, 0))
((520.0468122000351, 354.82321315627416),|(0, 0))
((NaN, NaN), |(0, 0))
----------------------------------------------------
Notice that the edge in question is a self-reference, so thi smight be the reason for this behavior? I can work around for it now, but maybe this points to a bigger issue?
Interesting. Possibly related to #35.
Note: Self referential link doesn't make much sense in the geometrical sense here. Remember that this is visualisation stuff - even if you have self-referential nodes in a graph, it doesn't mean that those edges should necessarily transform into link forces.
it doesn't mean that those edges should necessarily transform into link forces
That's a good point, thanks for clarifying. I filtered such references for my use case. Maybe it would be a reasonable default for the package to do so as well...?
What I mean is that link forces where the source and target field values are equal could be ignored when the force is applied... but maybe that's not a good idea ;)
I understood. I'm just not sure that's something elm-visualization should handle. I think the current behaviour of producing NaN is not too bad and perhaps more obvious than silently ignoring the force. The other option is to have a force function that can fail, but that doesn't seem too ergonomically.
Have you been able to identify where the NaN is produced? I'm more asking on a general level to understand how this can happen in Elm.
Regarding the idea to just keep producing NaN_s, I'm not sure about that, but then again I don't know the interals of your package. The design decision is certainly yours. From my point of view, if I (as a user) create Link-forces and my link is a point (since its start and end are identical, I would consider it a reasonable behavior if this link would not produce any force during a simulation. Getting back NaNs instead, having my Elm program crash, seems like a harsh effect, especially since it is not straightforward for a user to find out the cause of this effect.
Yes, it's not a straightforward decision. My thinking however is that getting back NaN immediately signals that something is wrong and allows the user to correct their code. Silently ignoring it doesn't.
The easiest way to produce NaN in Elm is 0 / 0, which is more or less what happens here.