Can D3js be used as a script to create SVG or PNG files? There are many examples out there for creating aweseome maps made with D3, but made to be run with the browser. It would be great to make scripts to create the same files to include them in reports, or to edit them using Inkscape, as Kartograph used to do.
I started looking how to do this when testing d3-composite-projections, so I could create a map to check if the library was working ok without opening the browser.
As usual, the code can be found at GitHub.
To run the examples, you need the package.json file copied in the working dir and execute:
There is an external dependency to be able to create the Canvas examples: the Cairo library. Here you can find how to install it in different platforms.
About a moth ago, the library jsdom didn’t work with the last version in nodejs, but now this seems to be solved. If you get the error message, just fix the problem by changing the line in package.json to:
The easiest way to explore the use of d3 and nodejs is creating PNG files using the node-canvas library.
The script for generating the PNG above:
The main parts of the script are:
- Requiring the libraries
- Creating the Image, Canvas and context objects with Canvas.Image, new Canvas(width, height) and context = canvas.getContext(‘2d’)
- Creating the map with d3 as usual
- Note how are the JSON files loaded locally, using fs.readFileSync.
- __dirname gives the absolute path to the script, which is mandatory to open the file
To create an SVG file, a DOM has to be created before. This is done using the jsdom library and it’s a bit more complicated.
The script for generating the SVG above:
There are four parts in this scripts:
- The requires section. All the used libraries are imported, excepting for D3, since D3 must be used as in the browser to be able to detect the DOM.
- jsdom.env is called. This will initialize the DOM so d3 can work as in the browser. I had some problems, solved using this page
- The second argument of the function calls the libraries to include. Is here where d3 is loaded.
- Note the use of __dirname variable to get the absolute path. It did’t work otherwise. Some webs recommend using documentRoot: __dirname, but it didn’t work for me.
- d3 must be invoked from the window object so it loads properly
- The SVG element must have .attr(“xmlns”, “http://www.w3.org/2000/svg”); so the browser can load the generated file. When creating it dynamically (in a browser), this is not necessary
- The JSON files can be stored locally and read with fs.readFileSync using absolute paths again
- The generated file is written using fs.writeFileSync
Cool, I can create d3 maps from the command line, but is it fast?
I made a script that makes the 900x500px map for each country in the world-50m topojson (235 files).
- In my computer lasts more or less 30s
- Without drawing the land around the country, the time is 9s
- I made another script that uses an asyncronous approach, but the performace is worse, about 50s in my computer
I haven’t compared it with other libaries such as using Python + PIL with the same data, but the results seem quite good. And you can generate SVGs too!
The output file for Gambia