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}]} 

Clipboard01

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}]} 

Clipboard02

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}]} 

sankey_colored_nodes


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:

{"sankey":{"nodes":[{"name":"a"},{"name":"b"},{"name":"c"},"name":"d"}],"links":[{"source":0,"target":1,"value":10},{"source":0,"target":1,"value":70},{"source":0,"target":1,"value":80},{"source":0,"target":1,"value":100},{"source":0,"target":1,"value":200},{"source":0,"target":1,"value":700},{"source":0,"target":1,"value":800},{"source":0,"target":2,"value":20},{"source":0,"target":2,"value":30},{"source":0,"target":2,"value":40},{"source":0,"target":2,"value":300},{"source":0,"target":2,"value":400},{"source":0,"target":3,"value":60},{"source":0,"target":3,"value":600},{"source":2,"target":3,"value":50}]},"params":[0.5,0.25,0,0]} 

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

parallelrendering=true

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!

Advertisements

65 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.

    Like

  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

    Like

  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.

    Like

    • 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 : )

      Like

  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?

    Like

    • 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]}

      Like

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

        {“sankey”:{“nodes”:[{“name”:”a”},{“name”:”b”},{“name”:”c”},{“name”:”d”}],”links”:[{“source”:0,”target”:1,”value”:100},{“source”:0,”target”:1,”value”:10},{“source”:0,”target”:1,”value”:200},{“source”:0,”target”:2,”value”:20},{“source”:0,”target”:2,”value”:300},{“source”:0,”target”:2,”value”:30},{“source”:0,”target”:2,”value”:400},{“source”:0,”target”:2,”value”:40},{“source”:2,”target”:3,”value”:50},{“source”:0,”target”:3,”value”:600},{“source”:0,”target”:3,”value”:60},{“source”:0,”target”:1,”value”:700},{“source”:0,”target”:1,”value”:70},{“source”:0,”target”:1,”value”:800},{“source”:0,”target”:1,”value”:80}]},”params”:[0.5,0.25,0,0]}

        Like

    • As a temporary workaround, try to sort your keys, such as
      {"sankey":{"nodes":[{"name":"a"},{"name":"b"},{"name":"c"},{"name":"d"}],"links":[
      {"source":0,"target":1,"value":10},
      {"source":0,"target":1,"value":70},
      {"source":0,"target":1,"value":80},
      {"source":0,"target":1,"value":100},
      {"source":0,"target":1,"value":200},
      {"source":0,"target":1,"value":700},
      {"source":0,"target":1,"value":800},
      {"source":0,"target":2,"value":20},
      {"source":0,"target":2,"value":30},
      {"source":0,"target":2,"value":40},
      {"source":0,"target":2,"value":300},
      {"source":0,"target":2,"value":400},
      {"source":0,"target":3,"value":60},
      {"source":0,"target":3,"value":600},
      {"source":2,"target":3,"value":50}]},
      "params":[0.5,0.25,0,0]}

      This is still not perfect, but almost there.

      Like

  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!

    Like

    • 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..

      Like

  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.

    Like

    • 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

      Like

  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 🙂

    Like

    • 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 http://sankey.csaladen.es/js/food.js 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.

      Like

  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?

    Like

    • {"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?

      Like

  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?

    Like

  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?

    Like

  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?

    Like

  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!

        Liked by 1 person

      • 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!

        Like

      • Hey again – the layout unfortunately is calculated to fill the whole screen, therefore it would require some coding to have a “fixed size” across multiple renderings. Not impossible, I’ll add it to the todo list. BTW, you can add it too, on GitHub.

        Like

  14. Love the tool! Any suggestions about who to do if the diagram is off the screen? I can’t see the end of the nodes to drag and drop. I tried the ‘save image’ function but that is also off the screen.

    Like

  15. This is really excellent. A quick Q, however: the “load” function doesn’t seem to be working when I copy & paste the string in.

    I also could not move around the order of the nodes (perhaps because I had a lot of data?)

    These could all very well be my own browser/computer issues.

    Many thanks for your time!

    Like

    • Hi Stephen, size of data shouldn’t be a problem. However, if you’ve checked for all commas, dots, etc and it’s all OK, a lot of times what break is it the parenthesis and the quote character.Make sure you use exactly these characters: ( ) ” and not their very visually similar but different ASCII versions. Sometimes location-settings of the browsers mess with these…

      Like

  16. Hi there, great product. I have two questions (potentially/likely of my mistake):

    1. I lost the ability to re-order the nodes once I reached a certain number. I couldn’t drag & drop them like I used to in the fossil fuel sample provided.

    2. I was able to save my string code, but once I tried to load it, nothing appeared — it just stayed at the sample fossil fuel example.

    Much appreciated for your time!

    -Stephen

    Like

  17. Excellent work!
    I have used for own data which may be filtered interactively. This may leave a node with no connection, if filter is strong. I have three columns of nodes, each node fixed by layer-option 0, 1 or 2. This works fine, until one node of the center column has no connection. In this case it is displayed in column 3 (=layer 2), while it is attributed with layer 1. Any idea how to fix nodes in their ciolumn, if no connection is active? Thank you.

    Like

  18. Excellent work!
    I have used for own data which may be filtered interactively. This may leave a node with no connection, if filter is strong. I have three columns of nodes, each node fixed by layer-option 0, 1 or 2. This works fine, until one node of the center column has no connection. In this case it is displayed in column 3 (=layer 2), while it is attributed with layer 1. Any idea how to fix nodes in their ciolumn, if no connection is active? Thank you.

    Liked by 1 person

  19. Great job on the sankey diagram, Im having issues with the layers. Its seems they are not adhered to.

    If you use:

    {“sankey”:{“nodes”:[{“name”:”Oil”,”layer”:0},{“name”:”Natural Gas”,”layer”:1},{“name”:”Coal”,”layer”:2},{“name”:”Wind”,”layer”:3}],”links”:[{“source”:0,”target”:1,”value”:15},{“source”:0,”target”:2,”value”:20},{“source”:0,”target”:3,”value”:25}]},”params”:[0.5,0.25,0,0,0]}

    The node on layer 0 is correct the rest all go to the right most layer?

    Like

    • Hi Dean – you cannot have “floating” layers – that is, if a node does not have an outflow it will automatically go to the rightmost. You can still place them manually though and save the layout as a workaround…

      Like

    • Or you could, in theory use a dummy link going from say Gas to Coal, but it wont work with exactly a 0 value, it has to be positive. So, unfortunately, it will still show.

      Like

      • Thanks for the functionality… A nice feature to add would be “Layer” headings… I have done this on my local version and works well… Along with links and nodes, I added layers, simple object array with a name attribute… Just as a heads up, the double click doesnt work… If you remove the drag “on” bindings it works again…

        Liked by 1 person

  20. Hey, thank you for sharing this great app. I would like to set up different colors for each flow. I have seen some explanations about JSON but don’t know how it works. Can you help me ?

    Like

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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