Coder Social home page Coder Social logo

Reheating the simulation about force-graph HOT 15 OPEN

vasturiano avatar vasturiano commented on June 21, 2024
Reheating the simulation

from force-graph.

Comments (15)

FrissAnalytics avatar FrissAnalytics commented on June 21, 2024 1

@vasturiano Thanks for your comments!

I'm happy to offer some bigger, more worked out examples for others, that also include vue and vuetify so others can see how your awesome package can be applied in those contexts. One nice thing of the vuetify docs is that they have a codepen for all the examples, which is especially nice if you want to play around with the code and experiment. If you want I can help in setting up a bunch of them for your package based on your existing code examples.

With respect to the ctx canvas context, previously I was not aware the requestAnimationFrame loop keeps running at all times unless you explicitly tell it not to via pauseAnimation.

Especially if you don't use the edge particles and you have largely unchanging data there is little need to keep the event loop running after the simulation freezes. For instance, currently on a graph of e.g. 200 nodes, even after the simulation freezes, the nodeCanvasObject callback will be executed approximately 200 * 60 = 12.000 per second, even when the data and the layout, i.e. the visual, do not change.

It's a bit unfortunate that currently when you apply pauseAnimation all event propagation always stops. I can see that in the generic scenario that needs to be done. However, in the above scenario, instead of wiping the canvas, it would be nice to be able to keep it alive after the layout freezes. That way you can still get the colors from the canvas to be able to generate hover events. When applying a drag move one could then quickly call resumeAnimation to facilitate the drag move and automatically call pauseAnimation after the layout stabilizes. Doing so will be less taxing for the browser, which helps in making additional transitions less choppy, especially when there are a lot of nodes in the network.

from force-graph.

FrissAnalytics avatar FrissAnalytics commented on June 21, 2024 1

@vasturiano I think it would be really helpful to decouple the pointer interaction events from the pauseAnimation and resumeAnimation functionality. I was thinking, wouldn't it be possible to use a mousedown event or say an invisible svg element at the location of the mouse cursor to signal the start of a drag move in case the rendering cycle of the component is paused?

from force-graph.

vasturiano avatar vasturiano commented on June 21, 2024 1

@klaraseitz if your overall intent is to improve the graph performance by bypassing rerenders after the simulation engine has stopped, note that there's been a flag added on v1.38.0 that addresses exactly this.

The option is autoPauseRedraw and it's enabled by default, so you should be automatically getting the performance improvement, if you upgrade your component version.

More details about it in this issue.

from force-graph.

klaraseitz avatar klaraseitz commented on June 21, 2024 1

@vasturiano Oh perfect!! I saw that option but thought my current version already had that. Now that I upgraded it works really smoothly. Thanks so much, Great library!

from force-graph.

vasturiano avatar vasturiano commented on June 21, 2024

Thanks for reaching out! Using the latest version (1.15.0) you can simply do myGraph.refresh() to reheat the force simulation engine.

As for the other configuration parameters, there are exposed properties that lets you manipulate this, such as d3AlphaDecay, d3VelocityDecay, d3Force, warmupTicks and cooldownTicks. If there's somehow an operation you're not able to control using these methods, please let me know and I'll consider adding additional support for.

from force-graph.

FrissAnalytics avatar FrissAnalytics commented on June 21, 2024

Hi,

thanks for the update, much appreciated! I had a few more questions if you don't mind :-)

With respect to the simulation, it would be nice to be able to manually control the tick function e.g. to say simulation.tick(20). Is there currently a good way to do that?

Furthermore, it would be handy to be able to manually- redraw - the canvas, e.g. because you've changed the color for a node. Currently I do this by using a function inside nodeCanvasObject that itself depends on a settings object. Of note, I need nodeCanvasObject because I draw more complex shapes as well. Hence if I change the settings object, the function changes the color. This is just an example of course, but in general it would be nice to be able to tell the graph object to re-render itself.

In that scenario, what would be the best way to redraw the canvas (without changing node positions etc.)?

Finally, it would also be handy to be able to have direct access to the ctx object, outside of nodeCanvasObject in order to control the canvas element by another process / function. For instance, I do some additional manipulations to ctx after the force engine has done its thing.

Clearly you could assign ctx to some variable from inside of nodeCanvasObject and then use that variable later, but it's a bit awkward to do it that way.

PS: I'm using your package in vue.js, which works quite well. No fancy binding, inside a component after mount I just create an instance of ForceGraph and define a few helper methods on the vue object that essentially call a few methods on a ForceGraph instance. For instance, now there is no zoom to fit function that zooms the canvas such that all nodes are inside the view port, so I created my own. A function like that would be useful to others as well I guess.

Anyways, thanks for you help, much appreciated! :-)

from force-graph.

havardl avatar havardl commented on June 21, 2024

PS: I'm using your package in vue.js, which works quite well. No fancy binding, inside a component after mount I just create an instance of ForceGraph and define a few helper methods on the vue object that essentially call a few methods on a ForceGraph instance. For instance, now there is no zoom to fit function that zooms the canvas such that all nodes are inside the view port, so I created my own. A function like that would be useful to others as well I guess.

Hi @FrissAnalytics, I'm looking into using this with vue as well, and was just wondering if you might be interested in sharing your own vue implementation for this?

from force-graph.

vasturiano avatar vasturiano commented on June 21, 2024

@FrissAnalytics a few answers to your questions:

With respect to the simulation, it would be nice to be able to manually control the tick function e.g. to say simulation.tick(20). Is there currently a good way to do that?

You can control the dry-run ticks by doing .warmupTicks(20). The effect is exactly the same.

Furthermore, it would be handy to be able to manually- redraw - the canvas, e.g. because you've changed the color for a node. Currently I do this by using a function inside nodeCanvasObject that itself depends on a settings object. Of note, I need nodeCanvasObject because I draw more complex shapes as well. Hence if I change the settings object, the function changes the color. This is just an example of course, but in general it would be nice to be able to tell the graph object to re-render itself.

Changing the assignment or the behavior of nodeCanvasObject will not cause a reheating of the simulation. The nodeCanvasObject method is called at every canvas refresh tick using raf (requestAnimationFrame), therefore any behavioral changes you make to the to the nodeCanvasObject mode should reflect automatically in the following raf tick, you shouldn't need to do anything to cause an update.

Finally, it would also be handy to be able to have direct access to the ctx object, outside of nodeCanvasObject in order to control the canvas element by another process / function. For instance, I do some additional manipulations to ctx after the force engine has done its thing.

The issue with exposing the context is that you wouldn't be able to do much manipulation with it, since it is cleared at every raf tick. Anything you'd write to it would be wiped almost immediately in the following tick. This is why it's not exposed, and all the relevant draws need to happen in the nodeCanvasObject method. If you'd like to have some other persistent visual elements I'd suggest to have another canvas that you maintain externally that aligns exactly underneath (or above it) to this dom element. That way you're just layering the multiple canvases and you get better update performance by not repetitively drawing the same things.

As for vue.js I can't be of much help because I haven't attempted the integration, but feel free to post examples here for the benefit of other users that may want to do the same thing. :)

from force-graph.

vasturiano avatar vasturiano commented on June 21, 2024

@FrissAnalytics good points. It's a little difficult to keep track of the variety of scenarios that the simulation could go dormant, even though there is certainly room for performance improvement.

Currently the decision is to let the consumer handle that state by choosing when to call pauseAnimation and resumeAnimation. A possible improvement is to decouple that from the pointer interaction events, so that one could still detect hover interactions and resume/pause the animation engine to permit node dragging. Actually the fact that dragging is not possible when the animation engine is off is the main reason why the pointer interactions are also disabled on pauseAnimation.

As for vue.js I would love to see a bindings repo, similar to what there is for React at react-force-graph.

from force-graph.

klaraseitz avatar klaraseitz commented on June 21, 2024

@vasturiano I would also be interested in decoupling the pointer events from pause and resumeAnimation functions.
Is there any (planned) progress on this?

Mainly I would like to render the graph only once it's done with positioning, allow the user to add nodes through click (triggering a rerender) and only ever show the result of the finished positioning and not showing the steps to reach the new position.

from force-graph.

vasturiano avatar vasturiano commented on June 21, 2024

@klaraseitz you can achieve this by setting cooldownTicks(0) and warmupTicks(80) (adjust value to your case). This will essentially compute the final node positions in the warmup phase, and bypass the cooldown phase where the graph build-up is normally being animated.

from force-graph.

klaraseitz avatar klaraseitz commented on June 21, 2024

@vasturiano great thanks!

And as for the pointer events. I would like to pauseAnimations onEngineStop. Such that neither the linkCanvasObject nor the nodeCanvasObject get called after the enginestop but click/hover interactions can still be caught. (on clicking/dragging a node animations should resume)

I tried
this.graph.onEngineStop(() => { this.graph.pauseAnimation() })
but the linkCanvasObject and nodeCanvasObject callbacks keep being called and interactions were not deactivated.

from force-graph.

kohlerpop1 avatar kohlerpop1 commented on June 21, 2024

@vasturiano Sorry for bringing this back up but I am running into a refresh issue with the graph.
image

This is occurred using the latest version!
image

from force-graph.

pebubblemaps avatar pebubblemaps commented on June 21, 2024

Hi,
First of all, thanks for your amazing job @vasturiano ! It's a great lib and I'm having fun using it.
I have some trouble with the interactions and the forces/reheat:
I would like to have hover and be able to pan/zoom, but without it triggering a re-heat; all while keeping the ability to drag (and that would of course trigger the reheat).
The end goal is to recreate the example of d3-force but with your great library !
I'm pulling my hair over this, but don't seem to be able to figure it out.
Is it possible to do that ?

from force-graph.

FrissAnalytics avatar FrissAnalytics commented on June 21, 2024

@pebubblemaps don't know if I understand your question completely, but you can just fix nodes into place by setting a fx and fy value.

For instance, after a given number of ticks, when the layout engine has done its thing, loop over all the nodes and fix all the node x, y positions. See this. example for details.

The difference with the example is that in the example only the node that gets dragged is fixed, but if you fix all the nodes, the graph does not move.

Assuming gData has you nodes, you can say

gData.nodes.map(node => {
       node.fx = node.x;
       node.fy = node.y;
})

You can set the node fx or fy position to null to unfreeze it. See the example on how to move a node with a drag move.

After the nodes have a fixed position, you can pan and zoom the graph with node hovers without a reheat, meaning that the nodes do not change position anymore.

from force-graph.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.