D3 Pre-Rendering

I'm still a beginner with JS + Python and I'd be really happy to get your help on one problem. What I basically need to to is to pre-render a d3js visualization of a network (as for example http://bl.ocks.org/mbostock/4062045) into a static page. The main aim is to reduce the pageload. As a side-effect, a static page would also be a better input for scripts that render a png that could be used for thumbnails of the graph.

So I imagine one site where I run the Force Directed algorithm once and then store the values of final node positions into a static file (where the node positions then are embedded). The system is currently running with Python/Django on Google App Engine. Is that possible?

Code examples/Fiddle would be great!

Disclosure: I have read this one here d3js large force-directed graph server side simulation and this one http://mango-is.com/blog/engineering/pre-render-d3-js-charts-at-server-side.html

Answers:

Answer

You can satisfy both requirements with CasperJS. Casper is a library that will use a headless browser to request a web page, which it can also programmatically interact with. A simple snippet of how to grab a screen shot goes something like this:

casper.start('http://ninjaPixel.io/', function() {
  this.capture('page.png', undefined, {
      format: 'png'
  });
});

You can add a delay to this, to make sure that your force diagram is in a stable state when you take the screen shot. Casper can grab anything off the page, so if you display your computed node values in a html table, for example, tell Casper the id of that table and it can then grab it and save the values for you. You could even save the SVG object generated by your d3.js code.

Answer

This excellent graphic (by mbostock for nytimes) shows how to render a static graph layout in the DOM based on pre-computed positions. All the code is on the main html doc, so just "view source".

It first loads the data, and then calls ready:

queue()
  .defer(d3.json, "http://graphics8.nytimes.com/newsgraphics/2013/09/07/director-star-chart/ed9eaa686bc2e11f0657a78d9be292a730c0567a/graph.json")
  .defer(d3.json, "http://graphics8.nytimes.com/newsgraphics/2013/09/07/director-star-chart/ed9eaa686bc2e11f0657a78d9be292a730c0567a/layout.json")
  .await(ready);

If you dig look inside the .json files, you'll get a sense of how they chose to capture the graph data.

The ready handler begins like this:

function ready(error, graph, positions) {
  force
    .nodes(graph.nodes)
    .links(graph.links)
    .on("tick", ticked)
    .start();

  if (positions) force.alpha(.0051);

  ....

You can see that it's initializing a force layout and setting its alpha() to a very low number, signaling that the layout is essentially settled. As a result, the tick handler ticked() probably only gets called one time, before the layout stops ticking due to the low alpha value.

However, also note that the setting of alpha to a very low value is conditional, depending on positions being available. So if positions were not pre-loaded and hence would be undefined, the layout would tick repeatedly for a while until it settles on some positioning. This suggests to me that the same code rendering this static layout was also used — probably with some additional code but without the calculated positions being loaded — during their process of exporting the positions. That's really quite clever of them(!).

The code that was used to gather and write the positions to file does not appear to be part of this page's source code, which makes sense, but you can hopefully come up with a way to do that within your project environment.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us Javascript

©2020 All rights reserved.