<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 More examples
<i class="fa fa-2x fa-paper-plane text-info fa-fw"> </i> Simple example
<i class="fa fa-2x fa-space-shuttle text-info fa-fw"> </i> Advanced examples
<i class="fa fa-2x fa-link text-info fa-fw"> </i> Linking and Layout
<i class="fa fa-2x fa-image text-info fa-fw"> </i> Exporting Images
Step2:  <i class="fa fa-gears fa-2x fa-fw text-info"></i> A convenience factory function
Step3:  Rank assignment
Rank sets
You can adjust the left-right placement of nodes by putting them in rank sets
Step4:  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.
Step5:  Variations
Step6:  Styling
By default, the links are coloured according to their type
Step7:  You can also set the colours directly
Step8:  Process titles default to their ids, but can be overridden. There are also one built-in alternative "style" of node
Step9:  Of course, you can also use CSS to adjust the styling
Step10:  Aligning link types
Step11:  Dynamic updating
Step12:  Node groups
Step13:  Link labels
Link labels show the numeric value of the link on the diagram
Step14:  By default the labels for small links are hidden, but you can customize this using linkLabelMinWidth
Step15:  Link markers
Warning
Step16:  Extra link info
Warning
Step17:  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.
Step18:  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.
<ASSISTANT_TASK:>
Python Code:
from ipysankeywidget import SankeyWidget
from ipywidgets import Layout
Explanation: More examples
<i class="fa fa-2x fa-paper-plane text-info fa-fw"> </i> Simple example
<i class="fa fa-2x fa-space-shuttle text-info fa-fw"> </i> Advanced examples
<i class="fa fa-2x fa-link text-info fa-fw"> </i> Linking and Layout
<i class="fa fa-2x fa-image text-info fa-fw"> </i> Exporting Images
End of explanation
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)
Explanation: <i class="fa fa-gears fa-2x fa-fw text-info"></i> A convenience factory function
End of explanation
links = [
    {'source': 'A', 'target': 'B', 'value': 1},
    {'source': 'B', 'target': 'C', 'value': 1},
    {'source': 'A', 'target': 'D', 'value': 1},
]
sankey(links=links)
rank_sets = [
    { 'type': 'same', 'nodes': ['C', 'D'] }
]
sankey(links=links, rank_sets=rank_sets)
order = [
    ['A'],
    ['D', 'B'],
    ['C'],
]
sankey(links=links, order=order)
order = [
    [ [   ], ['A'], [],   ],
    [ ['B'], [   ], ['D'] ],
    [ [   ], ['C'], []    ],
]
sankey(links=links, order=order)
Explanation: 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.
End of explanation
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)
Explanation: 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.
End of explanation
nodes = [
    {'id': 'C', 'direction': 'r'},
    {'id': 'D', 'direction': 'l'},
]
sankey(links=links, nodes=nodes)
nodes = [
    {'id': 'C', 'direction': 'l'},
    {'id': 'D', 'direction': 'r'},
]
sankey(links=links, nodes=nodes)
Explanation: Variations:
End of explanation
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)
Explanation: Styling
By default, the links are coloured according to their type:
End of explanation
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)
Explanation: You can also set the colours directly:
End of explanation
nodes = [
    {'id': 'B', 'title': 'Middle node', 'style': 'process' },
]
sankey(links=links, nodes=nodes)
Explanation: 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
End of explanation
%%html
<style>
.sankey .node {
    font-style: italic;
}
</style>
Explanation: Of course, you can also use CSS to adjust the styling:
End of explanation
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=[])
sankey(links=links, align_link_types=True)
order = [
    ['A2', 'A1'],
    ['B'],
    ['C'],
]
sankey(links=links, align_link_types=True, order=order)
Explanation: Aligning link types
End of explanation
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])
Explanation: Dynamic updating
End of explanation
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)
Explanation: Node groups
End of explanation
sankey(links=links, linkLabelFormat='.1f')
Explanation: Link labels
Link labels show the numeric value of the link on the diagram:
End of explanation
links[2]['value'] = 0.1
links[1]['value'] = 2.9
sankey(links=links, linkLabelFormat='.1f')
sankey(links=links, linkLabelFormat='.1f', linkLabelMinWidth=4)
Explanation: By default the labels for small links are hidden, but you can customize this using linkLabelMinWidth:
End of explanation
links[0]['marker'] = 2.5
sankey(links=links)
Explanation: Link markers
Warning: this feature is experimental and may be changed.
End of explanation
links = [
    {'source': 'A', 'target': 'B', 'value': 3, 'type': 'x', 'info_html': 'Hi!'},
    {'source': 'B', 'target': 'C', 'value': 2, 'type': 'y', 'info_html': 'B <b>to</b> C'},
    {'source': 'B', 'target': 'D', 'value': 1, 'type': 'z'},
]
sankey(links=links, show_link_info_html=True)
Explanation: Extra link info
Warning: this feature is experimental and may be changed.
End of explanation
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
Explanation: 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.
End of explanation
# Try changing this
w.scale = 2
# Try changing this
w.nodes[0]['position'] = [50, 50]
w.send_state()
# w.node_position_attr = None
Explanation: 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.
End of explanation
<END_TASK>