#!/usr/bin/env python # coding: utf-8 # # More examples # # > [ Simple example](./Simple%20example.ipynb) # > # > Advanced examples # > # > [ Linking and Layout](./Linking%20and%20Layout.ipynb) # > # > [ Exporting Images](./Exporting%20Images.ipynb) # In[1]: from ipysankeywidget import SankeyWidget from ipywidgets import Layout # > A convenience factory function # In[2]: layout = Layout(width="300", height="200") def sankey(margin_top=10, **value): """Show SankeyWidget with default values for size and margins""" return SankeyWidget(layout=layout, margins=dict(top=margin_top, bottom=0, left=30, right=60), **value) # ## Rank assignment # ### Rank sets # You can adjust the left-right placement of nodes by putting them in rank sets: all nodes in the same set end up with the same rank. # In[3]: links = [ {'source': 'A', 'target': 'B', 'value': 1}, {'source': 'B', 'target': 'C', 'value': 1}, {'source': 'A', 'target': 'D', 'value': 1}, ] sankey(links=links) # In[4]: rank_sets = [ { 'type': 'same', 'nodes': ['C', 'D'] } ] sankey(links=links, rank_sets=rank_sets) # In[5]: order = [ ['A'], ['D', 'B'], ['C'], ] sankey(links=links, order=order) # In[6]: order = [ [ [ ], ['A'], [], ], [ ['B'], [ ], ['D'] ], [ [ ], ['C'], [] ], ] sankey(links=links, order=order) # ### Reversed nodes # Most nodes are assumed to link from left to right, but sometimes there are return links which should be shown from right to left. # In[7]: links = [ {'source': 'A', 'target': 'B', 'value': 1}, {'source': 'B', 'target': 'C', 'value': 1}, {'source': 'C', 'target': 'D', 'value': 1}, {'source': 'A', 'target': 'E', 'value': 0.5}, ] nodes = [ {'id': 'C', 'direction': 'l'}, {'id': 'D', 'direction': 'l'}, ] sankey(links=links, nodes=nodes) # Variations: # In[8]: nodes = [ {'id': 'C', 'direction': 'r'}, {'id': 'D', 'direction': 'l'}, ] sankey(links=links, nodes=nodes) # In[9]: nodes = [ {'id': 'C', 'direction': 'l'}, {'id': 'D', 'direction': 'r'}, ] sankey(links=links, nodes=nodes) # ## Styling # By default, the links are coloured according to their type: # In[10]: links = [ {'source': 'A', 'target': 'B', 'value': 3, 'type': 'x'}, {'source': 'B', 'target': 'C', 'value': 2, 'type': 'y'}, {'source': 'B', 'target': 'D', 'value': 1, 'type': 'z'}, ] sankey(links=links) # You can also set the colours directly: # In[11]: links = [ {'source': 'A', 'target': 'B', 'value': 3, 'color': 'steelblue'}, {'source': 'B', 'target': 'C', 'value': 2, 'color': '#aaa'}, {'source': 'B', 'target': 'D', 'value': 1, 'color': 'goldenrod'}, ] sankey(links=links) # Process titles default to their ids, but can be overridden. There are also one built-in alternative "style" of node: # - `process` is drawn with a thicker line # In[12]: nodes = [ {'id': 'B', 'title': 'Middle node', 'style': 'process' }, ] sankey(links=links, nodes=nodes) # Of course, you can also use CSS to adjust the styling: # In[13]: get_ipython().run_cell_magic('html', '', '\n') # ## Aligning link types # In[14]: links = [ {'source': 'A1', 'target': 'B', 'value': 1.5, 'type': 'x'}, {'source': 'A1', 'target': 'B', 'value': 0.5, 'type': 'y'}, {'source': 'A2', 'target': 'B', 'value': 0.5, 'type': 'x'}, {'source': 'A2', 'target': 'B', 'value': 1.5, 'type': 'y'}, {'source': 'B', 'target': 'C', 'value': 2.0, 'type': 'x'}, {'source': 'B', 'target': 'C', 'value': 2.0, 'type': 'y'}, ] sankey(links=links, nodes=[]) # In[15]: sankey(links=links, align_link_types=True) # In[16]: order = [ ['A2', 'A1'], ['B'], ['C'], ] sankey(links=links, align_link_types=True, order=order) # ## Dynamic updating # In[17]: from ipywidgets import Button, VBox links = [ {'source': 'A', 'target': 'B', 'value': 1}, {'source': 'B', 'target': 'C', 'value': 1}, {'source': 'A', 'target': 'D', 'value': 1}, ] order = [ ['A'], ['D', 'B'], ['C'], ] s = sankey(links=links, order=order) def swap(x): global order order = [list(reversed(o)) for o in order] s.order = order b = Button(description='Swap') b.on_click(swap) VBox([b, s]) # ## Node groups # In[18]: links = [ {'source': 'A', 'target': 'B', 'value': 3, 'type': 'x'}, {'source': 'B', 'target': 'C', 'value': 2, 'type': 'y'}, {'source': 'B', 'target': 'D', 'value': 1, 'type': 'z'}, ] groups = [ {'id': 'G', 'title': 'Group', 'nodes': ['C', 'D']} ] sankey(links=links, nodes=[], groups=groups, margin_top=30) # ## Link labels # # Link labels show the numeric value of the link on the diagram: # In[19]: sankey(links=links, linkLabelFormat='.1f') # By default the labels for small links are hidden, but you can customize this using `linkLabelMinWidth`: # In[20]: links[2]['value'] = 0.1 links[1]['value'] = 2.9 sankey(links=links, linkLabelFormat='.1f') # In[21]: sankey(links=links, linkLabelFormat='.1f', linkLabelMinWidth=4) # ### Link markers # # **Warning**: this feature is experimental and may be changed. # In[22]: links[0]['marker'] = 2.5 sankey(links=links) # ### Extra link info # # **Warning**: this feature is experimental and may be changed. # In[23]: links = [ {'source': 'A', 'target': 'B', 'value': 3, 'type': 'x', 'info_html': 'Hi!'}, {'source': 'B', 'target': 'C', 'value': 2, 'type': 'y', 'info_html': 'B to C'}, {'source': 'B', 'target': 'D', 'value': 1, 'type': 'z'}, ] sankey(links=links, show_link_info_html=True) # ## Custom layout # # The d3-sankey-diagram layout algorithm can be bypassed completely by specifying coordinates for the nodes directly. This must be activated by the `node_position_attr` option. # In[24]: links = [ {'source': 'A', 'target': 'B', 'value': 30}, {'source': 'B', 'target': 'C', 'value': 20}, {'source': 'B', 'target': 'D', 'value': 10}, ] nodes = [ {'id': 'A', 'position': [0, 50]}, {'id': 'B', 'position': [100, 50]}, {'id': 'C', 'position': [200, 30]}, {'id': 'D', 'position': [200, 100]}, ] w = sankey( links=links, nodes=nodes, node_position_attr='position' ) w # The positions are in display coordinates, within the margins specified. The scale is set to 1 by default, if not specified. When node positions are specified manually, they are not affected by the scale -- only the width of the lines is scaled. # In[25]: # Try changing this w.scale = 2 # In[26]: # Try changing this w.nodes[0]['position'] = [50, 50] w.send_state() # In[27]: # w.node_position_attr = None