2
2
"""
3
3
Module for creating Sankey diagrams using matplotlib
4
4
"""
5
+ from __future__ import print_function
5
6
__author__ = "Kevin L. Davies"
6
7
__credits__ = ["Yannick Copin" ]
7
8
__license__ = "BSD"
12
13
# http://matplotlib.org/examples/api/sankey_demo_old.html
13
14
# Modifications by Kevin Davies (kld@alumni.carnegiemellon.edu) 6/3/2011:
14
15
# --Used arcs for the curves (so that the widths of the paths are uniform)
15
- # --Converted the function to a class and created methods to join
16
- # multiple simple Sankey diagrams
16
+ # --Converted the function to a class and created methods to join multiple
17
+ # simple Sankey diagrams
17
18
# --Provided handling for cases where the total of the inputs isn't 100
18
19
# Now, the default layout is based on the assumption that the inputs sum to
19
20
# 1. A scaling parameter can be used in other cases.
29
30
# inputs/outputs are now specified via an orientation of 0, and there may
30
31
# be several of each.
31
32
# --Added assertions to catch common calling errors
32
- # -Added the physical unit as a string argument to be used in the labels, so
33
+ # - -Added the physical unit as a string argument to be used in the labels, so
33
34
# that the values of the flows can usually be applied automatically
34
35
# --Added an argument for a minimum magnitude below which flows are not shown
35
36
# --Added a tapered trunk in the case that the flows do not sum to 0
@@ -395,10 +396,10 @@ def add(self, patchlabel='', flows=None, orientations=None, labels='',
395
396
*orientations* == 0, inputs will break in from the
396
397
left and outputs will break away to the right.
397
398
*labels* list of specifications of the labels for the flows
398
- Each value may be None (no labels), '' (just label
399
- the quantities), or a labeling string. If a single
400
- value is provided, it will be applied to all flows.
401
- If an entry is a non-empty string, then the
399
+ Each value may be * None* (no labels), '' (just
400
+ label the quantities), or a labeling string. If a
401
+ single value is provided, it will be applied to all
402
+ flows. If an entry is a non-empty string, then the
402
403
quantity for the corresponding flow will be shown
403
404
below the string. However, if the *unit* of the
404
405
main diagram is None, then quantities are never
@@ -417,7 +418,7 @@ def add(self, patchlabel='', flows=None, orientations=None, labels='',
417
418
*connect* a (prior, this) tuple indexing the flow of the
418
419
prior diagram and the flow of this diagram which
419
420
should be connected
420
- If this is the first diagram or *prior* is None,
421
+ If this is the first diagram or *prior* is * None* ,
421
422
*connect* will be ignored.
422
423
*rotation* angle of rotation of the diagram [deg]
423
424
*rotation* is ignored if this diagram is connected
@@ -460,7 +461,7 @@ def add(self, patchlabel='', flows=None, orientations=None, labels='',
460
461
if rotation is None :
461
462
rotation = 0
462
463
else :
463
- # In the code below, angles are expressed in deg/90
464
+ # In the code below, angles are expressed in deg/90.
464
465
rotation /= 90.0
465
466
if orientations is None :
466
467
orientations = [0 , 0 ]
@@ -741,10 +742,10 @@ def _get_angle(a, r):
741
742
kwds = dict (s = patchlabel , ha = 'center' , va = 'center' )
742
743
text = self .ax .text (* offset , ** kwds )
743
744
if False : # Debug
744
- print "llpath\n " , llpath
745
- print "ulpath\n " , self ._revert (ulpath )
746
- print "urpath\n " , urpath
747
- print "lrpath\n " , self ._revert (lrpath )
745
+ print ( "llpath\n " , llpath )
746
+ print ( "ulpath\n " , self ._revert (ulpath ) )
747
+ print ( "urpath\n " , urpath )
748
+ print ( "lrpath\n " , self ._revert (lrpath ) )
748
749
xs , ys = zip (* vertices )
749
750
self .ax .plot (xs , ys , 'go-' )
750
751
patch = PathPatch (Path (vertices , codes ),
@@ -755,22 +756,18 @@ def _get_angle(a, r):
755
756
self .ax .add_patch (patch )
756
757
757
758
# Add the path labels.
758
- for i , (number , angle ) in enumerate (zip (flows , angles )):
759
- if labels [i ] is None or angle is None :
760
- labels [i ] = ''
759
+ texts = []
760
+ for number , angle , label , location in zip (flows , angles , labels ,
761
+ label_locations ):
762
+ if label is None or angle is None :
763
+ label = ''
761
764
elif self .unit is not None :
762
765
quantity = self .format % abs (number ) + self .unit
763
- if labels [i ] != '' :
764
- labels [i ] += "\n "
765
- labels [i ] += quantity
766
- texts = []
767
- for i , (label , location ) in enumerate (zip (labels , label_locations )):
768
- if label :
769
- s = label
770
- else :
771
- s = ''
766
+ if label != '' :
767
+ label += "\n "
768
+ label += quantity
772
769
texts .append (self .ax .text (x = location [0 ], y = location [1 ],
773
- s = s ,
770
+ s = label ,
774
771
ha = 'center' , va = 'center' ))
775
772
# Text objects are placed even they are empty (as long as the magnitude
776
773
# of the corresponding flow is larger than the tolerance) in case the
@@ -820,7 +817,7 @@ def finish(self):
820
817
(DOWN), and an output from the top side will have
821
818
an angle of 1 (UP). If a flow has been skipped
822
819
(because its magnitude is less than *tolerance*),
823
- then its angle will be None.
820
+ then its angle will be * None* .
824
821
*tips* array in which each row is an [x, y] pair
825
822
indicating the positions of the tips (or "dips") of
826
823
the flow paths
@@ -844,5 +841,3 @@ def finish(self):
844
841
self .extent [3 ] + self .margin ])
845
842
self .ax .set_aspect ('equal' , adjustable = 'datalim' )
846
843
return self .diagrams
847
-
848
-
0 commit comments