<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 System boundaries
Often we don't want to show all of the data in one Sankey diagram
Step1:  What happens if we remove farm2 from the ProcessGroup?
Step2:  The flow is still there! But it is labelled with a little arrow to show that it is coming "from elsewhere". This is important because we are still showing Susan and Fred in the diagram, and they get fruit from farm2. If we didn't show those flows, Susan's and Fred's inputs and outputs would not balance.
Try now removing Susan and Fred from the diagram
Step3:  Now they're gone, we no longer see the incoming flows from farm2. But we see some outgoing flows "to elsewhere" from farm3 and the other group. This is because farm3 is within the system boundary -- it is shown in the diagram -- so its output flow has to go somewhere.
Controlling Elsewhere flows
These flows are added automatically to make sure that mass is conserved, but because they are automatic, we have little control over them. By explicitly adding a flow to or from Elsewhere to the diagram, we can control where they appear and what they look like.
To do this, add a Waypoint for the outgoing flows to 'pass through' on their way across the system boundary
Step4:  This is pretty similar to what we had already, but now the waypoint is explicitly listed as part of the SankeyDefinition, we have more control over it.
For example, we can put the exports above James and Mary by changing the ordering
Step5:  Or we can partition the exports Waypoint to show how much of it is apples and bananas
Step6:  Horizontal bands
Often, import/exports and loss flows are shown in a separate horizontal "band" either above or below the main flows. We can do this by modifying the ordering a little bit.
The ordering style we have used so far looks like this
<ASSISTANT_TASK:>
Python Code:
import pandas as pd
flows = pd.read_csv('simple_fruit_sales.csv')
from floweaver import *
# Set the default size to fit the documentation better.
size = dict(width=570, height=300)
# Same partitions as the Quickstart tutorial
farms_with_other = Partition.Simple('process', [
    'farm1',
    'farm2',
    'farm3',
    ('other', ['farm4', 'farm5', 'farm6']),
])
customers_by_name = Partition.Simple('process', [
    'James', 'Mary', 'Fred', 'Susan'
])
# Define the nodes, this time setting the partition from the start
nodes = {
    'farms': ProcessGroup(['farm1', 'farm2', 'farm3', 
                           'farm4', 'farm5', 'farm6'],
                          partition=farms_with_other),
    'customers': ProcessGroup(['James', 'Mary', 'Fred', 'Susan'],
                              partition=customers_by_name),
}
# Ordering and bundles as before
ordering = [
    ['farms'],       # put "farms" on the left...
    ['customers'],   # ... and "customers" on the right.
]
bundles = [
    Bundle('farms', 'customers'),
]
sdd = SankeyDefinition(nodes, bundles, ordering)
weave(sdd, flows).to_widget(**size)
Explanation: System boundaries
Often we don't want to show all of the data in one Sankey diagram: you focus on one part of the system. But we still want conservation of mass (or whatever is being shown in the diagram) to work, so we end up with flows to & from "elsewhere". These can also be thought of as imports and exports.
Let's start by recreating the Quickstart example:
End of explanation
nodes['farms'].selection = [
    'farm1', 'farm3', 'farm4', 'farm5', 'farm6'
]
weave(sdd, flows).to_widget(**size)
Explanation: What happens if we remove farm2 from the ProcessGroup?
End of explanation
nodes['customers'].selection = ['James', 'Mary']
weave(sdd, flows).to_widget(**size)
Explanation: The flow is still there! But it is labelled with a little arrow to show that it is coming "from elsewhere". This is important because we are still showing Susan and Fred in the diagram, and they get fruit from farm2. If we didn't show those flows, Susan's and Fred's inputs and outputs would not balance.
Try now removing Susan and Fred from the diagram:
End of explanation
# Define a new Waypoint
nodes['exports'] = Waypoint(title='exports here')
# Update the ordering to include the waypoint
ordering = [
    ['farms'],                  #     put "farms" on the left...
    ['customers', 'exports'],   # ... and "exports" below "customers"
]                               #     on the right.
# Add a new bundle from "farms" to Elsewhere, via the waypoint
bundles = [
    Bundle('farms', 'customers'),
    Bundle('farms', Elsewhere, waypoints=['exports']),
]
sdd = SankeyDefinition(nodes, bundles, ordering)
weave(sdd, flows).to_widget(**size)
Explanation: Now they're gone, we no longer see the incoming flows from farm2. But we see some outgoing flows "to elsewhere" from farm3 and the other group. This is because farm3 is within the system boundary -- it is shown in the diagram -- so its output flow has to go somewhere.
Controlling Elsewhere flows
These flows are added automatically to make sure that mass is conserved, but because they are automatic, we have little control over them. By explicitly adding a flow to or from Elsewhere to the diagram, we can control where they appear and what they look like.
To do this, add a Waypoint for the outgoing flows to 'pass through' on their way across the system boundary:
End of explanation
ordering = [
    ['farms'],
    ['exports', 'customers'],
]
sdd = SankeyDefinition(nodes, bundles, ordering)
weave(sdd, flows).to_widget(**size)
Explanation: This is pretty similar to what we had already, but now the waypoint is explicitly listed as part of the SankeyDefinition, we have more control over it.
For example, we can put the exports above James and Mary by changing the ordering:
End of explanation
fruits_by_type = Partition.Simple('type', ['apples', 'bananas'])
nodes['exports'].partition = fruits_by_type
weave(sdd, flows).to_widget(**size)
Explanation: Or we can partition the exports Waypoint to show how much of it is apples and bananas:
End of explanation
ordering = [
    [[],          ['farms'    ]],
    [['exports'], ['customers']],
]
sdd = SankeyDefinition(nodes, bundles, ordering)
weave(sdd, flows).to_widget(**size)
Explanation: Horizontal bands
Often, import/exports and loss flows are shown in a separate horizontal "band" either above or below the main flows. We can do this by modifying the ordering a little bit.
The ordering style we have used so far looks like this:
python
ordering = [
    [list of nodes in layer 1],  # left-hand side
    [list of nodes in layer 2],
    ...
    [list of nodes in layer N],  # right-hand side
]
But we can add another layer of nesting to make it look like this:
python
ordering = [
    # |top band|  |bottom band|
    [ [........], [...........] ],  # left-hand side
    [ [........], [...........] ],
    ...
    [ [........], [...........] ],  # right-hand side
]
Here's an example:
End of explanation
<END_TASK>