Skip to content

Fix docs to include sankey api docs. #562

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 8, 2011
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
nxutils_api.rst
path_api.rst
pyplot_api.rst
sankey_api.rst
spines_api.rst
ticker_api.rst
tight_layout_api.rst
Expand Down
12 changes: 12 additions & 0 deletions doc/api/sankey_api.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
******
sankey
******


:mod:`matplotlib.sankey`
=======================

.. automodule:: matplotlib.sankey
:members:
:undoc-members:
:show-inheritance:
104 changes: 67 additions & 37 deletions lib/matplotlib/sankey.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,14 @@ def _arc(self, quadrant=0, cw=True, radius=1, center=(0,0)):
# Negate x.
if cw:
# Swap x and y.
vertices = np.column_stack((-ARC_VERTICES[:,1], ARC_VERTICES[:,0]))
vertices = np.column_stack((-ARC_VERTICES[:,1],
ARC_VERTICES[:,0]))
else:
vertices = np.column_stack((-ARC_VERTICES[:,0], ARC_VERTICES[:,1]))
vertices = np.column_stack((-ARC_VERTICES[:,0],
ARC_VERTICES[:,1]))
if quadrant > 1: radius = -radius # Rotate 180 deg.
return zip(ARC_CODES,
radius*vertices + np.tile(center, (ARC_VERTICES.shape[0], 1)))
return zip(ARC_CODES, radius*vertices +
np.tile(center, (ARC_VERTICES.shape[0], 1)))

def _add_input(self, path, angle, flow, length):
"""Add an input to a path and return its tip and label locations.
Expand Down Expand Up @@ -196,9 +198,11 @@ def _add_output(self, path, angle, flow, length):
else:
path.append((Path.LINETO, [x, y]))
path.extend([(Path.LINETO, [x, y + sign * length]),
(Path.LINETO, [x - self.shoulder, y + sign * length]),
(Path.LINETO, [x - self.shoulder,
y + sign * length]),
(Path.LINETO, tip),
(Path.LINETO, [x + self.shoulder - flow, y + sign * length]),
(Path.LINETO, [x + self.shoulder - flow,
y + sign * length]),
(Path.LINETO, [x - flow, y + sign * length])])
path.extend(self._arc(quadrant=quadrant,
cw=angle==DOWN,
Expand Down Expand Up @@ -317,13 +321,13 @@ def add(self, patchlabel='', flows=np.array([1.0,-1.0]), orientations=[0,0],
if rotation == None:
rotation = 0
else:
rotation /= 90.0 # In the code below, angles are expressed in deg/90.
rotation /= 90.0 # In the code below, angles are expressed in deg/90
assert len(orientations) == n, ("orientations and flows must have the "
"same length.\norientations has length "
"%d, but flows has length %d."
% len(orientations), n)
if getattr(labels, '__iter__', False):
# iterable() isn't used because it would give True if labels is a string.
# iterable() isn't used because it would give True if labels is a string
assert len(labels) == n, ("If labels is a list, then labels and "
"flows must have the same length.\n"
"labels has length %d, but flows has "
Expand Down Expand Up @@ -422,7 +426,8 @@ def add(self, patchlabel='', flows=np.array([1.0,-1.0]), orientations=[0,0],
lllength = pathlengths
d = dict(RIGHT=pathlengths)
pathlengths = [d.get(angle, 0) for angle in angles]
# Determine the lengths of the top-side arrows from the middle outwards.
# Determine the lengths of the top-side arrows
# from the middle outwards.
for i, (angle, is_input, flow) \
in enumerate(zip(angles, are_inputs, scaled_flows)):
if angle == DOWN and is_input:
Expand All @@ -431,7 +436,8 @@ def add(self, patchlabel='', flows=np.array([1.0,-1.0]), orientations=[0,0],
elif angle == UP and not is_input:
pathlengths[i] = urlength
urlength -= flow # Flow is negative for outputs.
# Determine the lengths of the bottom-side arrows from the middle outwards.
# Determine the lengths of the bottom-side arrows
# from the middle outwards.
for i, (angle, is_input, flow) \
in enumerate(zip(angles, are_inputs, scaled_flows)[::-1]):
if angle == UP and is_input:
Expand All @@ -440,7 +446,8 @@ def add(self, patchlabel='', flows=np.array([1.0,-1.0]), orientations=[0,0],
elif angle == DOWN and not is_input:
pathlengths[n-i-1] = lrlength
lrlength -= flow
# Determine the lengths of the left-side arrows from the bottom upwards.
# Determine the lengths of the left-side arrows
# from the bottom upwards.
has_left_input = False
for i, (angle, is_input, spec) \
in enumerate(zip(angles, are_inputs, zip(scaled_flows,
Expand All @@ -451,7 +458,8 @@ def add(self, patchlabel='', flows=np.array([1.0,-1.0]), orientations=[0,0],
pathlengths[n-i-1] = 0
else:
has_left_input = True
# Determine the lengths of the right-side arrows from the top downwards.
# Determine the lengths of the right-side arrows
# from the top downwards.
has_right_output = False
for i, (angle, is_input, spec) \
in enumerate(zip(angles, are_inputs, zip(scaled_flows,
Expand Down Expand Up @@ -499,40 +507,57 @@ def add(self, patchlabel='', flows=np.array([1.0,-1.0]), orientations=[0,0],
label_locations = np.zeros((n,2))
# Add the top-side inputs and outputs from the middle outwards.
for i, (angle, is_input, spec) \
in enumerate(zip(angles, are_inputs, zip(scaled_flows, pathlengths))):
in enumerate(zip(angles, are_inputs,
zip(scaled_flows, pathlengths))):
if angle == DOWN and is_input:
tips[i,:], label_locations[i,:] = self._add_input(ulpath, angle, *spec)
tips[i,:], label_locations[i,:] = self._add_input(ulpath, angle,
*spec)
elif angle == UP and not is_input:
tips[i,:], label_locations[i,:] = self._add_output(urpath, angle, *spec)
tips[i,:], label_locations[i,:] = self._add_output(urpath,
angle, *spec)
# Add the bottom-side inputs and outputs from the middle outwards.
for i, (angle, is_input, spec) \
in enumerate(zip(angles, are_inputs, zip(scaled_flows, pathlengths))[::-1]):
in enumerate(zip(angles, are_inputs,
zip(scaled_flows, pathlengths))[::-1]):
if angle == UP and is_input:
tips[n-i-1,:], label_locations[n-i-1,:] = self._add_input(llpath, angle, *spec)
(tips[n-i-1,:],
label_locations[n-i-1,:]) = self._add_input(llpath, angle,
*spec)
elif angle == DOWN and not is_input:
tips[n-i-1,:], label_locations[n-i-1,:] = self._add_output(lrpath, angle, *spec)
(tips[n-i-1,:],
label_locations[n-i-1,:]) = self._add_output(lrpath, angle,
*spec)
# Add the left-side inputs from the bottom upwards.
has_left_input = False
for i, (angle, is_input, spec) \
in enumerate(zip(angles, are_inputs, zip(scaled_flows, pathlengths))[::-1]):
in enumerate(zip(angles, are_inputs,
zip(scaled_flows, pathlengths))[::-1]):
if angle == RIGHT and is_input:
if not has_left_input:
# Make sure the lower path extends at least as far as the upper one.
# Make sure the lower path extends
# at least as far as the upper one.
if llpath[-1][1][0] > ulpath[-1][1][0]:
llpath.append((Path.LINETO, [ulpath[-1][1][0], llpath[-1][1][1]]))
llpath.append((Path.LINETO, [ulpath[-1][1][0],
llpath[-1][1][1]]))
has_left_input = True
tips[n-i-1,:], label_locations[n-i-1,:] = self._add_input(llpath, angle, *spec)
(tips[n-i-1,:],
label_locations[n-i-1,:]) = self._add_input(llpath, angle,
*spec)
# Add the right-side outputs from the top downwards.
has_right_output = False
for i, (angle, is_input, spec) \
in enumerate(zip(angles, are_inputs, zip(scaled_flows, pathlengths))):
in enumerate(zip(angles, are_inputs,
zip(scaled_flows, pathlengths))):
if angle == RIGHT and not is_input:
if not has_right_output:
# Make sure the upper path extends at least as far as the lower one.
# Make sure the upper path extends
# at least as far as the lower one.
if urpath[-1][1][0] < lrpath[-1][1][0]:
urpath.append((Path.LINETO, [lrpath[-1][1][0], urpath[-1][1][1]]))
urpath.append((Path.LINETO, [lrpath[-1][1][0],
urpath[-1][1][1]]))
has_right_output = True
tips[i,:], label_locations[i,:] = self._add_output(urpath, angle, *spec)
(tips[i,:],
label_locations[i,:]) = self._add_output(urpath, angle, *spec)
# Trim any hanging vertices.
if not has_left_input:
ulpath.pop()
Expand All @@ -542,8 +567,8 @@ def add(self, patchlabel='', flows=np.array([1.0,-1.0]), orientations=[0,0],
urpath.pop()

# Concatenate the subpaths in the correct order (clockwise from top).
path = (urpath + self._revert(lrpath) + llpath + self._revert(ulpath)
+ [(Path.CLOSEPOLY, urpath[0][1])])
path = (urpath + self._revert(lrpath) + llpath + self._revert(ulpath) +
[(Path.CLOSEPOLY, urpath[0][1])])

# Create a patch with the Sankey outline.
codes, vertices = zip(*path)
Expand All @@ -561,7 +586,8 @@ def _get_angle(a, r):
vertices = rotate(vertices)
text = self.ax.text(0, 0, s=patchlabel, ha='center', va='center')
else:
rotation = self.diagrams[prior].angles[connect[0]] - angles[connect[1]]
rotation = (self.diagrams[prior].angles[connect[0]] -
angles[connect[1]])
angles = [_get_angle(angle, rotation) for angle in angles]
rotate = Affine2D().rotate_deg(rotation*90).transform_point
tips = rotate(tips)
Expand All @@ -580,8 +606,8 @@ def _get_angle(a, r):
xs, ys = zip(*vertices)
self.ax.plot(xs, ys, 'go-')
patch = PathPatch(Path(vertices, codes),
fc=kwargs.pop('fc', kwargs.pop('facecolor', # Custom defaults
'#bfd1d4')),
fc=kwargs.pop('fc', kwargs.pop('facecolor',
'#bfd1d4')), # Custom defaults
lw=kwargs.pop('lw', kwargs.pop('linewidth',
'0.5')),
**kwargs)
Expand All @@ -592,7 +618,7 @@ def _get_angle(a, r):
if labels[i] is None or angle is None:
labels[i] = ''
elif self.unit is not None:
quantity = self.format%abs(number) + self.unit
quantity = self.format % abs(number) + self.unit
if labels[i] != '':
labels[i] += "\n"
labels[i] += quantity
Expand All @@ -608,10 +634,14 @@ def _get_angle(a, r):
# user wants to provide labels later.

# Expand the size of the diagram if necessary.
self.extent = (min(np.min(vertices[:,0]), np.min(label_locations[:,0]), self.extent[0]),
max(np.max(vertices[:,0]), np.max(label_locations[:,0]), self.extent[1]),
min(np.min(vertices[:,1]), np.min(label_locations[:,1]), self.extent[2]),
max(np.max(vertices[:,1]), np.max(label_locations[:,1]), self.extent[3]))
self.extent = (min(np.min(vertices[:,0]), np.min(label_locations[:,0]),
self.extent[0]),
max(np.max(vertices[:,0]), np.max(label_locations[:,0]),
self.extent[1]),
min(np.min(vertices[:,1]), np.min(label_locations[:,1]),
self.extent[2]),
max(np.max(vertices[:,1]), np.max(label_locations[:,1]),
self.extent[3]))
# Include both vertices _and_ label locations in the extents; there are
# where either could determine the margins (e.g., arrow shoulders).

Expand Down Expand Up @@ -750,7 +780,7 @@ def __init__(self, ax=None, scale=1.0, unit='', format='%G', gap=0.25,

**Examples:**

.. plot:: mpl_examples/api/sankey_demo.py
.. plot:: mpl_examples/api/sankey_demo_basics.py
"""
# Check the arguments.
assert gap >= 0, ("The gap is negative.\nThis isn't allowed because it "
Expand Down