Sankey Diagram Generator

Sankey Demo

Check out the Sankey Diagram Generator I have just made. It supports self loops, moving around nodes in both horizontal and vertical directions and loading and saving diagrams! You can also change the opacity and the density of the links.

Use the Load/Save button to edit/create complex Sankey’s.

The source code for the Sankey displayed above is:

{"nodes":[{"name":"Oil"},{"name":"Natural Gas"},{"name":"Coal"},{"name":"Fossil Fuels"},{"name":"Electricity"},{"name":"Energy"}],"links":[{"source":0,"target":3,"value":15},{"source":1,"target":3,"value":20},{"source":2,"target":3,"value":25},{"source":2,"target":4,"value":25},{"source":3,"target":5,"value":60},{"source":4,"target":5,"value":25},{"source":4,"target":4,"value":5}]} 

You can also use the keyword layer to create nodes fixed along the x-axis. In the above example, if you use “layer”: 3 for the node Fossil Fuels and “layer”:4 for Electricity, they will not be aligned, with the latter being placed to the right of the former.

{"nodes":[{"name":"Oil"},{"name":"Natural Gas"},{"name":"Coal"},{"name":"Fossil Fuels","layer":3},{"name":"Electricity","layer":4},{"name":"Energy"}],"links":[{"source":0,"target":3,"value":15},{"source":1,"target":3,"value":20},{"source":2,"target":3,"value":25},{"source":2,"target":4,"value":25},{"source":3,"target":5,"value":60},{"source":4,"target":5,"value":25},{"source":4,"target":4,"value":5}]} 


You can also fix the size of a node using the keyword value.

{"nodes":[{"name":"Oil"},{"name":"Natural Gas"},{"name":"Coal"},{"name":"Fossil Fuels","layer":3,"value":10},{"name":"Electricity","layer":4},{"name":"Energy"}],"links":[{"source":0,"target":3,"value":15},{"source":1,"target":3,"value":20},{"source":2,"target":3,"value":25},{"source":2,"target":4,"value":25},{"source":3,"target":5,"value":60},{"source":4,"target":5,"value":25},{"source":4,"target":4,"value":5}]} 


UDPATE: Using the keyword fill, you can also color the nodes (and automatically their links).

{"nodes":[{"name":"Oil"},{"name":"Natural Gas"},{"name":"Coal","fill":"black"},{"name":"Fossil Fuels","layer":3,"value":10},{"name":"Electricity","layer":4},{"name":"Energy"}],"links":[{"source":0,"target":3,"value":15},{"source":1,"target":3,"value":20},{"source":2,"target":3,"value":25},{"source":2,"target":4,"value":25},{"source":3,"target":5,"value":60},{"source":4,"target":5,"value":25},{"source":4,"target":4,"value":5}]} 


UDPATE 2: Today the Sankey Diagram Generator got a major update: I have been working on the load and save functions to include the layout. Another minor update is that now you can toggle the node labels (both the text and values) on/off. On top giving you the option to save the Sankey structure and layout, now you can also save the diagram as a PNG image.

Now, when trying to save the Sankey code, a checkbox shows up next to the Done button, giving you the option to save the Sankey layout for loading later. This includes the node and link positions, as well as the settings for opacity and density. This is a major milestone as it has been a headache to redesign Sankeys, as previously only the structure was saved but not the layout. On the save screen now you also have the option to download the diagram as image.

As a result of these modifications, the Sankey save string changed a little bit in structure. In order to preserve background compatibility, the Sankey structure code – which made up the entirety of the save string up until now – was put under the key “sankey“, the parameters on whether to display labels, density and opacity under the key “params” and finally, the layout, if selected, under “fixedlayout“. Subsequently, when loading back the Sankey save string you are given the option to try to read the layout from the string. If you do not provide the layout, or you choose to ignore it (via a checkbox next to the Done button), the algorithm computes the layout for you automatically, as before.

UDPATE 3: Some users have requested to be able to create Sankeys with multiple flows between the same two nodes. This can be interpreted as having parallel links. While with a small number of parallel links, this is not a problem, the relaxation algorithm fails to lay out the links correctly in case of many. This algorithm is at the core of the rendering and therefore hard to change as it is designed to optimize the layout in general (minimize the total link path length in the connected component). However, I have included an experimental feature to correctly display Sankeys with many parallel links – this will not necessary offer the best layout for regular Sankeys though. In the sankey.js, there is a function called computeLinkDepths which sorts the links in ascending order at the sources and subsequently at the targets. This leads to some ordering conflicts (two source nodes going to the same target, with links of different value, will not both have their top link at the top at the target), which are then solved be the least in number. In case of parallel links, this creates a messy layout. To solve this, I have included a toggle for parallel rendering. This is a bit of an advanced feature and I encourage you to try to understand the sankey.js code structure before you turn this on. How to turn it on? First, make sure that in your input string all parallel links are sorted by value and grouped by source node. An example of this would be:


.Then open up a console in your browser and turn on parallel rendering by typing the following:


Then hit the Draw Sankey button to redraw the diagram and you should be seeing your Sankey with many parallel links loaded correctly. You can turn it off either by refreshing the page or setting it back to false in the console. Have fun!

UDPATE 4: Added option for adjusting decimals for nodes and links, as well a counter for the node editor on the right, making it easier to create larger diagrams.

UPDATE 5: Sankey Diagram Generator is now on GitHub.

Made with D3.js & Dragdealer. If you would like to show your support for my work, please consider a small donation. For a more advanced, applied implementation of this tool, see the Food Energy Flows Exploratorium.

Donate for more datawizardry!


44 replies »

  1. Hi Flavio! You can now! Just use the fill keyword on the node definition dictionary for the nodes that you want to have a fixed color, such as “fill”:”black” or “fill”:”#ff4411″. Others will take a random color. I’ve updated the main post too to illustrate this.

    Liked by 1 person

  2. Hi Zhou. In the food.js file from the webpage, look at line 138 (g.attr). That controls the flows’ colro, currently set to be defined by the source node. You can change it there for the target or a fixed color, or include a separate field in the JSON of your flows, if you would like to have custom colored flows for many diagrams.


    • Awesome! Thanks for your sharing. I was wondering how can I set custom colored flows by indicating separate field in the JSON string? Thanks again!


  3. Hi
    I would like to link a zone, let’s say value 1, to another zone of value 1.5 to the right. when i do that, the entire zone is not covered since it is covering the same area or less


  4. Hi, thank You so much for share it. I’m just testing your sankey diagram generator to create saving diagrams in my plant. I’m wondering if it is possible to change direction in to saving view. Left side Electricity and right side for e.g. Light, motors etc.


    • Hi KZ! For now, you would have to enter the data backwards, as there is no reverse display option. If you are handy with Javascript, it is possible to edit the sankey.js file and negate the x coordinates of nodes : )


  5. Hello!
    I tried using this, but if I enter many values for the same source and target, they are not grouped anymore but split up in many single lines that even cross each other, so it does not look like a normal sankey anymore. Do you have the same problem?


    • Hi Laura, Sankey Diagrams by default can have only one flow between nodes. However, this one does support multiple flows. Try to load this code to see: {"sankey":{"nodes":[{"name":"Oil"},{"name":"Natural Gas"},{"name":"Coal","fill":"seaGreen"},{"name":"Fossil Fuels","value":65,"layer":2},{"name":"Electricity","layer":2},{"name":"Energy","fill":"grey"}],"links":[{"source":0,"target":3,"value":15},{"source":1,"target":3,"value":20},{"source":2,"target":3,"value":25},{"source":2,"target":4,"value":25},{"source":3,"target":5,"value":60},{"source":4,"target":5,"value":25},{"source":4,"target":4,"value":5},{"source":2,"target":4,"value":2},{"source":2,"target":4,"value":2},{"source":2,"target":4,"value":2}]},"params":[0.5,0.25,0,0]}


      • Thank you for your fast answer 🙂 Could you please try this:



    • As a temporary workaround, try to sort your keys, such as

      This is still not perfect, but almost there.


  6. I see – yeah, you’re right. Currently I’ve only tried it with a small number of parallel links (3-4), After that the relaxation algorithm just messes things up. I’ll try to lay them out nicely when I’ll have some time. For now you can try to group them into parallel flows of 3 or 4. Or if you’re adventurous, edit the code and see where it goes!


    • Hi Natt, click on “save layout” an additional key named “fixedlayout” should be added to the Sankey save string, with an array of [x,y] coordinates as the layout. Seems to be working for me..


  7. Hi Denes, using your work quite frequently now. Can you add an export image function, or is there one that I am missing? I can print screen and edit elsewhere, but Sankeymatic for example offers the option to export to a larger PNG.


    • Nat, if you open the Save Tab, there is a link called Save Image. Doens’t fully preserve the fonts because of SVG/CANVAS problems, but it still looks good. And now you can include teh layout too in your sankey save string, so bascially you can recreate everything exactly as you left it. Cheers. Denes


  8. Hello Dénes,
    first thank you very much for your great documentation and help here. But of course I also have a question.
    I do have many flows in one Sankey Chart with very different values. So I have now the problem, that the vertically displayed values in the nodes are larger than the nodes and are overlapping each other. Is there an easy possibility to display the values directly besides the node label horizontally outside the nodes in regular style like node label?
    E.g. like in your example: “Coal; 50” or something like this.

    I’m not so handy with javascript yet so I would be happy about help 🙂


    • Hey Simon, this is not hard, but it does require javascript….What you need to do is to run the Sankey Diagram generator locally (I explain on this blog in a post called How to make a d3js visualization how to do this), then edit the file. In this file, lines 228-248 you will find the node label controls. Here, the first text element is the node value, and you can see where it is roated (“transform”, “rotate(270)”) and that the label is only displayed if its height (dy) is above 50 pixels. Try to play with these, you can remove the rotation or move the label around by adjusting its x or y coordinates. The other text element – you guessed it – is the node name. Cheers.


  9. Hello Denes, great tool, thanks for making it public. Quick question: if I try to add more than 14 nodes the diagram won’t render. Is there a limit, or am I possible doing something incorrectly?


    • {"sankey":{"nodes":[{"name":"Oil"},{"name":"Natural Gas"},{"name":"Coal","fill":"seaGreen"},{"name":"Fossil Fuels","value":65,"layer":2},{"name":"Electricity","layer":2},{"name":"Energy","fill":"grey"},{"name":"New Node"},{"name":"New Node"},{"name":"New Node"},{"name":"New Node"},{"name":"New Node"},{"name":"New Node"},{"name":"New Node"},{"name":"New Node"},{"name":"New Node"},{"name":"New Node"},{"name":"New Node"},{"name":"New Node"},{"name":"New Node"},{"name":"New Node"}],"links":[{"source":0,"target":3,"value":15},{"source":1,"target":3,"value":20},{"source":2,"target":3,"value":25},{"source":2,"target":4,"value":25},{"source":3,"target":5,"value":60},{"source":4,"target":5,"value":25},{"source":4,"target":4,"value":5},{"source":0,"target":14,"value":0.52},{"source":0,"target":13,"value":0.52},{"source":0,"target":12,"value":0.52},{"source":0,"target":11,"value":0.52},{"source":0,"target":10,"value":0.52},{"source":0,"target":9,"value":0.52},{"source":0,"target":8,"value":0.52},{"source":0,"target":7,"value":0.52},{"source":0,"target":6,"value":0.52},{"source":0,"target":17,"value":0.52},{"source":0,"target":18,"value":0.52},{"source":0,"target":19,"value":0.52},{"source":0,"target":16,"value":0.52},{"source":0,"target":15,"value":0.52}]},"params":[0.75,0.25,0,0]} This has more than 14 and it seems to be working fine for me… Can you check if this works on your side?


  10. Hello, like I wrote in July, the grouping is working in all browsers, except Chrome. Why is that so that the browser makes such a difference here?


  11. I have a parameterized URL (date ranges) that creates the JSON dynamically and I can copy & paste to load it manually no problem (it looks GREAT! Thanks for all of your work on this.), but I’m not sure how to load my data by default. Can you provide an example?


  12. This is an awesome tool! Thank you. When entering data, how do I keep information in the vertical order I need it to show proper flows of work?


  13. Hey, thanks, this is an awesome tool! I think I’m having a font issue tho, the values that show on the nodes are coming up as a outline fonts which don’t display well at lower resolutions. If I have a corrupt font, could you tell me what font it is to look for?

    Also, I couldn’t figure out how to force it to display all values on nodes, some of the smaller values don’t display when they are too small, but I’d still like to have that option.

    Thanks again for an awesome tool! I made an excel sheet to (slightly) automate writing the code.

    Liked by 1 person

    • Hey aaronmichels2014, I’ll add these functions in a day or two, great suggestions, thanks! I’ll add a font selector. The node value display is currently hard-coded, so let me make a parameter out of it quickly.

      Liked by 1 person

      • Open up a console, and set minnodewidth=0 or 1, or what you’d like. Then click to draw the diagram again. By default this is set 50, so everything with a height below 50 pixels won’t have a label. Cheers!


      • Awesome. Thanks for the minnodewidth parameter.

        Another question I had, I’m trying to make a number of different Sankeys where the width of a node with a certain value is consistent between renderings. Could you give me a hint toward understanding how you determine width with density? For example, I want to generate 1 sankey where the 1st layer nodes total 1000, and then a second sankey where the first layer nodes total 500, but where the 500 is the same width as half of the 1000 in the first sankey. I was trying to put in an additional “spacer” node to compensate for resizing, but I’m not quite understanding how you determine density when all of the layers are changing.

        Thanks again,
        Great tool!


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s