|
1 | 1 | """Demonstrate the Sankey class.
|
| 2 | +
|
| 3 | +Accepts an optional argument indicating the example to produce (1 through 5). If |
| 4 | +the argument isn't provided (or is 0), all the examples will be generated. |
2 | 5 | """
|
3 | 6 | import numpy as np
|
4 | 7 | import matplotlib.pyplot as plt
|
| 8 | +import sys |
5 | 9 |
|
6 | 10 | from matplotlib.sankey import Sankey
|
7 | 11 | from itertools import cycle
|
8 | 12 |
|
| 13 | + |
| 14 | +# Read the optional argument indentifying the example to run. |
| 15 | +try: |
| 16 | + example_num = int(sys.argv[1]) |
| 17 | +except: |
| 18 | + example_num = 0 |
| 19 | + |
9 | 20 | # Example 1 -- Mostly defaults
|
10 | 21 | # This demonstrates how to create a simple diagram by implicitly calling the
|
11 | 22 | # Sankey.add() method and by appending finish() to the call to the class.
|
12 |
| -Sankey(flows=[0.25, 0.15, 0.60, -0.20, -0.15, -0.05, -0.50, -0.10], |
13 |
| - labels=['', '', '', 'First', 'Second', 'Third', 'Fourth', 'Fifth'], |
14 |
| - orientations=[-1, 1, 0, 1, 1, 1, 0, -1]).finish() |
15 |
| -plt.title("The default settings produce a diagram like this.") |
16 |
| -# Notice: |
17 |
| -# 1. Axes weren't provided when Sankey() was instantiated, so they were |
18 |
| -# created automatically. |
19 |
| -# 2. The scale argument wasn't necessary since the data was already |
20 |
| -# normalized. |
21 |
| -# 3. By default, the lengths of the paths are justified. |
| 23 | +if example_num == 1 or example_num == 0: |
| 24 | + Sankey(flows=[0.25, 0.15, 0.60, -0.20, -0.15, -0.05, -0.50, -0.10], |
| 25 | + labels=['', '', '', 'First', 'Second', 'Third', 'Fourth', 'Fifth'], |
| 26 | + orientations=[-1, 1, 0, 1, 1, 1, 0, -1]).finish() |
| 27 | + plt.title("The default settings produce a diagram like this.") |
| 28 | + # Notice: |
| 29 | + # 1. Axes weren't provided when Sankey() was instantiated, so they were |
| 30 | + # created automatically. |
| 31 | + # 2. The scale argument wasn't necessary since the data was already |
| 32 | + # normalized. |
| 33 | + # 3. By default, the lengths of the paths are justified. |
22 | 34 |
|
23 | 35 | # Example 2
|
24 | 36 | # This demonstrates:
|
|
31 | 43 | # 7. Formatting the numbers in the path labels and the associated unit
|
32 | 44 | # 8. Changing the appearance of the patch and the labels after the figure is
|
33 | 45 | # created
|
34 |
| -fig = plt.figure() |
35 |
| -ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], |
36 |
| - title="Flow Diagram of a Widget") |
37 |
| -sankey = Sankey(ax=ax, scale=0.01, offset=0.2, head_angle=180, |
38 |
| - format='%.0f', unit='%') |
39 |
| -sankey.add(flows=[25, 0, 60, -10, -20, -5, -15, -10, -40], |
40 |
| - labels = ['', '', '', 'First', 'Second', 'Third', 'Fourth', |
41 |
| - 'Fifth', 'Hurray!'], |
42 |
| - orientations=[-1, 1, 0, 1, 1, 1, -1, -1, 0], |
43 |
| - pathlengths = [0.25, 0.25, 0.25, 0.25, 0.25, 0.6, 0.25, 0.25, |
44 |
| - 0.25], |
45 |
| - patchlabel="Widget\nA", |
46 |
| - alpha=0.2, lw=2.0) # Arguments to matplotlib.patches.PathPatch() |
47 |
| -diagrams = sankey.finish() |
48 |
| -diagrams[0].patch.set_facecolor('#37c959') |
49 |
| -diagrams[0].texts[-1].set_color('r') |
50 |
| -diagrams[0].text.set_fontweight('bold') |
51 |
| -# Notice: |
52 |
| -# 1. Since the sum of the flows is nonzero, the width of the trunk isn't |
53 |
| -# uniform. If verbose.level is helpful (in matplotlibrc), a message is |
54 |
| -# given in the terminal window. |
55 |
| -# 2. The second flow doesn't appear because its value is zero. Again, if |
56 |
| -# verbose.level is helpful, a message is given in the terminal window. |
| 46 | +if example_num == 2 or example_num == 0: |
| 47 | + fig = plt.figure() |
| 48 | + ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], |
| 49 | + title="Flow Diagram of a Widget") |
| 50 | + sankey = Sankey(ax=ax, scale=0.01, offset=0.2, head_angle=180, |
| 51 | + format='%.0f', unit='%') |
| 52 | + sankey.add(flows=[25, 0, 60, -10, -20, -5, -15, -10, -40], |
| 53 | + labels = ['', '', '', 'First', 'Second', 'Third', 'Fourth', |
| 54 | + 'Fifth', 'Hurray!'], |
| 55 | + orientations=[-1, 1, 0, 1, 1, 1, -1, -1, 0], |
| 56 | + pathlengths = [0.25, 0.25, 0.25, 0.25, 0.25, 0.6, 0.25, 0.25, |
| 57 | + 0.25], |
| 58 | + patchlabel="Widget\nA", |
| 59 | + alpha=0.2, lw=2.0) # Arguments to matplotlib.patches.PathPatch() |
| 60 | + diagrams = sankey.finish() |
| 61 | + diagrams[0].patch.set_facecolor('#37c959') |
| 62 | + diagrams[0].texts[-1].set_color('r') |
| 63 | + diagrams[0].text.set_fontweight('bold') |
| 64 | + # Notice: |
| 65 | + # 1. Since the sum of the flows is nonzero, the width of the trunk isn't |
| 66 | + # uniform. If verbose.level is helpful (in matplotlibrc), a message is |
| 67 | + # given in the terminal window. |
| 68 | + # 2. The second flow doesn't appear because its value is zero. Again, if |
| 69 | + # verbose.level is helpful, a message is given in the terminal window. |
57 | 70 |
|
58 | 71 | # Example 3
|
59 | 72 | # This demonstrates:
|
60 | 73 | # 1. Connecting two systems
|
61 | 74 | # 2. Turning off the labels of the quantities
|
62 | 75 | # 3. Adding a legend
|
63 |
| -fig = plt.figure() |
64 |
| -ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], title="Two Systems") |
65 |
| -flows = [0.25, 0.15, 0.60, -0.10, -0.05, -0.25, -0.15, -0.10, -0.35] |
66 |
| -sankey = Sankey(ax=ax, unit=None) |
67 |
| -sankey.add(flows=flows, label='one', |
68 |
| - orientations=[-1, 1, 0, 1, 1, 1, -1, -1, 0]) |
69 |
| -sankey.add(flows=[-0.25, 0.15, 0.1], fc='#37c959', label='two', |
70 |
| - orientations=[-1, -1, -1], prior=0, connect=(0, 0)) |
71 |
| -diagrams = sankey.finish() |
72 |
| -diagrams[-1].patch.set_hatch('/') |
73 |
| -plt.legend(loc='best') |
74 |
| -# Notice that only one connection is specified, but the systems form a circuit |
75 |
| -# since: (1) the lengths of the paths are justified and (2) the orientation and |
76 |
| -# ordering of the flows is mirrored. |
| 76 | +if example_num == 3 or example_num == 0: |
| 77 | + fig = plt.figure() |
| 78 | + ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], title="Two Systems") |
| 79 | + flows = [0.25, 0.15, 0.60, -0.10, -0.05, -0.25, -0.15, -0.10, -0.35] |
| 80 | + sankey = Sankey(ax=ax, unit=None) |
| 81 | + sankey.add(flows=flows, label='one', |
| 82 | + orientations=[-1, 1, 0, 1, 1, 1, -1, -1, 0]) |
| 83 | + sankey.add(flows=[-0.25, 0.15, 0.1], fc='#37c959', label='two', |
| 84 | + orientations=[-1, -1, -1], prior=0, connect=(0, 0)) |
| 85 | + diagrams = sankey.finish() |
| 86 | + diagrams[-1].patch.set_hatch('/') |
| 87 | + plt.legend(loc='best') |
| 88 | + # Notice that only one connection is specified, but the systems form a |
| 89 | + # circuit since: (1) the lengths of the paths are justified and (2) the |
| 90 | + # orientation and ordering of the flows is mirrored. |
77 | 91 |
|
78 | 92 | # Example 4
|
79 | 93 | # This tests a long chain of connections.
|
80 |
| -links_per_side = 6 |
81 |
| -def side(sankey, n=1): |
82 |
| - """Generate a side chain. |
83 |
| - """ |
84 |
| - prior = len(sankey.diagrams) |
85 |
| - colors = cycle(['orange', 'b', 'g', 'r', 'c', 'm', 'y']) |
86 |
| - for i in range(0, 2*n, 2): |
87 |
| - sankey.add(flows=[1, -1], orientations=[-1, -1], |
88 |
| - patchlabel=str(prior+i), facecolor=colors.next(), |
89 |
| - prior=prior+i-1, connect=(1, 0), alpha=0.5) |
90 |
| - sankey.add(flows=[1, -1], orientations=[1, 1], |
91 |
| - patchlabel=str(prior+i+1), facecolor=colors.next(), |
92 |
| - prior=prior+i, connect=(1, 0), alpha=0.5) |
93 |
| -def corner(sankey): |
94 |
| - """Generate a corner link. |
95 |
| - """ |
96 |
| - prior = len(sankey.diagrams) |
| 94 | +if example_num == 4 or example_num == 0: |
| 95 | + links_per_side = 6 |
| 96 | + def side(sankey, n=1): |
| 97 | + """Generate a side chain. |
| 98 | + """ |
| 99 | + prior = len(sankey.diagrams) |
| 100 | + colors = cycle(['orange', 'b', 'g', 'r', 'c', 'm', 'y']) |
| 101 | + for i in range(0, 2*n, 2): |
| 102 | + sankey.add(flows=[1, -1], orientations=[-1, -1], |
| 103 | + patchlabel=str(prior+i), facecolor=colors.next(), |
| 104 | + prior=prior+i-1, connect=(1, 0), alpha=0.5) |
| 105 | + sankey.add(flows=[1, -1], orientations=[1, 1], |
| 106 | + patchlabel=str(prior+i+1), facecolor=colors.next(), |
| 107 | + prior=prior+i, connect=(1, 0), alpha=0.5) |
| 108 | + def corner(sankey): |
| 109 | + """Generate a corner link. |
| 110 | + """ |
| 111 | + prior = len(sankey.diagrams) |
| 112 | + sankey.add(flows=[1, -1], orientations=[0, 1], |
| 113 | + patchlabel=str(prior), facecolor='k', |
| 114 | + prior=prior-1, connect=(1, 0), alpha=0.5) |
| 115 | + fig = plt.figure() |
| 116 | + ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], |
| 117 | + title="Why would you want to do this?\n(But you could.)") |
| 118 | + sankey = Sankey(ax=ax, unit=None) |
97 | 119 | sankey.add(flows=[1, -1], orientations=[0, 1],
|
98 |
| - patchlabel=str(prior), facecolor='k', |
99 |
| - prior=prior-1, connect=(1, 0), alpha=0.5) |
100 |
| -fig = plt.figure() |
101 |
| -ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], |
102 |
| - title="Why would you want to do this?\n(But you could.)") |
103 |
| -sankey = Sankey(ax=ax, unit=None) |
104 |
| -sankey.add(flows=[1, -1], orientations=[0, 1], |
105 |
| - patchlabel="0", facecolor='k', |
106 |
| - rotation=45) |
107 |
| -side(sankey, n=links_per_side) |
108 |
| -corner(sankey) |
109 |
| -side(sankey, n=links_per_side) |
110 |
| -corner(sankey) |
111 |
| -side(sankey, n=links_per_side) |
112 |
| -corner(sankey) |
113 |
| -side(sankey, n=links_per_side) |
114 |
| -sankey.finish() |
115 |
| -# Notice: |
116 |
| -# 1. The alignment doesn't drift significantly (if at all; with 16007 |
117 |
| -# subdiagrams there is still closure). |
118 |
| -# 2. The first diagram is rotated 45 deg, so all other diagrams are rotated |
119 |
| -# accordingly. |
| 120 | + patchlabel="0", facecolor='k', |
| 121 | + rotation=45) |
| 122 | + side(sankey, n=links_per_side) |
| 123 | + corner(sankey) |
| 124 | + side(sankey, n=links_per_side) |
| 125 | + corner(sankey) |
| 126 | + side(sankey, n=links_per_side) |
| 127 | + corner(sankey) |
| 128 | + side(sankey, n=links_per_side) |
| 129 | + sankey.finish() |
| 130 | + # Notice: |
| 131 | + # 1. The alignment doesn't drift significantly (if at all; with 16007 |
| 132 | + # subdiagrams there is still closure). |
| 133 | + # 2. The first diagram is rotated 45 deg, so all other diagrams are rotated |
| 134 | + # accordingly. |
120 | 135 |
|
121 | 136 | # Example 5
|
122 | 137 | # This is a practical example of a Rankine power cycle.
|
123 |
| -fig = plt.figure(figsize=(8, 12)) |
124 |
| -ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], |
125 |
| - title="Rankine Power Cycle: Example 8.6 from Moran and Shapiro\n" |
126 |
| - + "\x22Fundamentals of Engineering Thermodynamics\x22, 6th ed., 2008") |
127 |
| -Hdot = [260.431, 35.078, 180.794, 221.115, 22.700, |
128 |
| - 142.361, 10.193, 10.210, 43.670, 44.312, |
129 |
| - 68.631, 10.758, 10.758, 0.017, 0.642, |
130 |
| - 232.121, 44.559, 100.613, 132.168] # MW |
131 |
| -sankey = Sankey(ax=ax, format='%.3G', unit=' MW', gap=0.5, scale=1.0/Hdot[0]) |
132 |
| -sankey.add(patchlabel='\n\nPump 1', rotation=90, facecolor='#37c959', |
133 |
| - flows=[Hdot[13], Hdot[6], -Hdot[7]], |
134 |
| - labels=['Shaft power', '', None], |
135 |
| - pathlengths=[0.4, 0.883, 0.25], |
136 |
| - orientations=[1, -1, 0]) |
137 |
| -sankey.add(patchlabel='\n\nOpen\nheater', facecolor='#37c959', |
138 |
| - flows=[Hdot[11], Hdot[7], Hdot[4], -Hdot[8]], |
139 |
| - labels=[None, '', None, None], |
140 |
| - pathlengths=[0.25, 0.25, 1.93, 0.25], |
141 |
| - orientations=[1, 0, -1, 0], prior=0, connect=(2, 1)) |
142 |
| -sankey.add(patchlabel='\n\nPump 2', facecolor='#37c959', |
143 |
| - flows=[Hdot[14], Hdot[8], -Hdot[9]], |
144 |
| - labels=['Shaft power', '', None], |
145 |
| - pathlengths=[0.4, 0.25, 0.25], |
146 |
| - orientations=[1, 0, 0], prior=1, connect=(3, 1)) |
147 |
| -sankey.add(patchlabel='Closed\nheater', trunklength=2.914, fc='#37c959', |
148 |
| - flows=[Hdot[9], Hdot[1], -Hdot[11], -Hdot[10]], |
149 |
| - pathlengths=[0.25, 1.543, 0.25, 0.25], |
150 |
| - labels=['', '', None, None], |
151 |
| - orientations=[0, -1, 1, -1], prior=2, connect=(2, 0)) |
152 |
| -sankey.add(patchlabel='Trap', facecolor='#37c959', trunklength=5.102, |
153 |
| - flows=[Hdot[11], -Hdot[12]], |
154 |
| - labels=['\n', None], |
155 |
| - pathlengths=[1.0, 1.01], |
156 |
| - orientations=[1, 1], prior=3, connect=(2, 0)) |
157 |
| -sankey.add(patchlabel='Steam\ngenerator', facecolor='#ff5555', |
158 |
| - flows=[Hdot[15], Hdot[10], Hdot[2], -Hdot[3], -Hdot[0]], |
159 |
| - labels=['Heat rate', '', '', None, None], |
160 |
| - pathlengths=0.25, |
161 |
| - orientations=[1, 0, -1, -1, -1], prior=3, connect=(3, 1)) |
162 |
| -sankey.add(patchlabel='\n\n\nTurbine 1', facecolor='#37c959', |
163 |
| - flows=[Hdot[0], -Hdot[16], -Hdot[1], -Hdot[2]], |
164 |
| - labels=['', None, None, None], |
165 |
| - pathlengths=[0.25, 0.153, 1.543, 0.25], |
166 |
| - orientations=[0, 1, -1, -1], prior=5, connect=(4, 0)) |
167 |
| -sankey.add(patchlabel='\n\n\nReheat', facecolor='#37c959', |
168 |
| - flows=[Hdot[2], -Hdot[2]], |
169 |
| - labels=[None, None], |
170 |
| - pathlengths=[0.725, 0.25], |
171 |
| - orientations=[-1, 0], prior=6, connect=(3, 0)) |
172 |
| -sankey.add(patchlabel='Turbine 2', trunklength=3.212, facecolor='#37c959', |
173 |
| - flows=[Hdot[3], Hdot[16], -Hdot[5], -Hdot[4], -Hdot[17]], |
174 |
| - labels=[None, 'Shaft power', None, '', 'Shaft power'], |
175 |
| - pathlengths=[0.751, 0.15, 0.25, 1.93, 0.25], |
176 |
| - orientations=[0, -1, 0, -1, 1], prior=6, connect=(1, 1)) |
177 |
| -sankey.add(patchlabel='Condenser', facecolor='#58b1fa', trunklength=1.764, |
178 |
| - flows=[Hdot[5], -Hdot[18], -Hdot[6]], |
179 |
| - labels=['', 'Heat rate', None], |
180 |
| - pathlengths=[0.45, 0.25, 0.883], |
181 |
| - orientations=[-1, 1, 0], prior=8, connect=(2, 0)) |
182 |
| -diagrams = sankey.finish() |
183 |
| -for diagram in diagrams: |
184 |
| - diagram.text.set_fontweight('bold') |
185 |
| - diagram.text.set_fontsize('10') |
186 |
| - for text in diagram.texts: |
187 |
| - text.set_fontsize('10') |
188 |
| -# Notice that the explicit connections are handled automatically, but the |
189 |
| -# implicit ones currently are not. The lengths of the paths and the trunks |
190 |
| -# must be adjusted manually, and that is a bit tricky. |
| 138 | +if example_num == 5 or example_num == 0: |
| 139 | + fig = plt.figure(figsize=(8, 12)) |
| 140 | + ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], |
| 141 | + title="Rankine Power Cycle: Example 8.6 from Moran and Shapiro\n" |
| 142 | + + "\x22Fundamentals of Engineering Thermodynamics\x22, 6th ed., 2008") |
| 143 | + Hdot = [260.431, 35.078, 180.794, 221.115, 22.700, |
| 144 | + 142.361, 10.193, 10.210, 43.670, 44.312, |
| 145 | + 68.631, 10.758, 10.758, 0.017, 0.642, |
| 146 | + 232.121, 44.559, 100.613, 132.168] # MW |
| 147 | + sankey = Sankey(ax=ax, format='%.3G', unit=' MW', gap=0.5, scale=1.0/Hdot[0]) |
| 148 | + sankey.add(patchlabel='\n\nPump 1', rotation=90, facecolor='#37c959', |
| 149 | + flows=[Hdot[13], Hdot[6], -Hdot[7]], |
| 150 | + labels=['Shaft power', '', None], |
| 151 | + pathlengths=[0.4, 0.883, 0.25], |
| 152 | + orientations=[1, -1, 0]) |
| 153 | + sankey.add(patchlabel='\n\nOpen\nheater', facecolor='#37c959', |
| 154 | + flows=[Hdot[11], Hdot[7], Hdot[4], -Hdot[8]], |
| 155 | + labels=[None, '', None, None], |
| 156 | + pathlengths=[0.25, 0.25, 1.93, 0.25], |
| 157 | + orientations=[1, 0, -1, 0], prior=0, connect=(2, 1)) |
| 158 | + sankey.add(patchlabel='\n\nPump 2', facecolor='#37c959', |
| 159 | + flows=[Hdot[14], Hdot[8], -Hdot[9]], |
| 160 | + labels=['Shaft power', '', None], |
| 161 | + pathlengths=[0.4, 0.25, 0.25], |
| 162 | + orientations=[1, 0, 0], prior=1, connect=(3, 1)) |
| 163 | + sankey.add(patchlabel='Closed\nheater', trunklength=2.914, fc='#37c959', |
| 164 | + flows=[Hdot[9], Hdot[1], -Hdot[11], -Hdot[10]], |
| 165 | + pathlengths=[0.25, 1.543, 0.25, 0.25], |
| 166 | + labels=['', '', None, None], |
| 167 | + orientations=[0, -1, 1, -1], prior=2, connect=(2, 0)) |
| 168 | + sankey.add(patchlabel='Trap', facecolor='#37c959', trunklength=5.102, |
| 169 | + flows=[Hdot[11], -Hdot[12]], |
| 170 | + labels=['\n', None], |
| 171 | + pathlengths=[1.0, 1.01], |
| 172 | + orientations=[1, 1], prior=3, connect=(2, 0)) |
| 173 | + sankey.add(patchlabel='Steam\ngenerator', facecolor='#ff5555', |
| 174 | + flows=[Hdot[15], Hdot[10], Hdot[2], -Hdot[3], -Hdot[0]], |
| 175 | + labels=['Heat rate', '', '', None, None], |
| 176 | + pathlengths=0.25, |
| 177 | + orientations=[1, 0, -1, -1, -1], prior=3, connect=(3, 1)) |
| 178 | + sankey.add(patchlabel='\n\n\nTurbine 1', facecolor='#37c959', |
| 179 | + flows=[Hdot[0], -Hdot[16], -Hdot[1], -Hdot[2]], |
| 180 | + labels=['', None, None, None], |
| 181 | + pathlengths=[0.25, 0.153, 1.543, 0.25], |
| 182 | + orientations=[0, 1, -1, -1], prior=5, connect=(4, 0)) |
| 183 | + sankey.add(patchlabel='\n\n\nReheat', facecolor='#37c959', |
| 184 | + flows=[Hdot[2], -Hdot[2]], |
| 185 | + labels=[None, None], |
| 186 | + pathlengths=[0.725, 0.25], |
| 187 | + orientations=[-1, 0], prior=6, connect=(3, 0)) |
| 188 | + sankey.add(patchlabel='Turbine 2', trunklength=3.212, facecolor='#37c959', |
| 189 | + flows=[Hdot[3], Hdot[16], -Hdot[5], -Hdot[4], -Hdot[17]], |
| 190 | + labels=[None, 'Shaft power', None, '', 'Shaft power'], |
| 191 | + pathlengths=[0.751, 0.15, 0.25, 1.93, 0.25], |
| 192 | + orientations=[0, -1, 0, -1, 1], prior=6, connect=(1, 1)) |
| 193 | + sankey.add(patchlabel='Condenser', facecolor='#58b1fa', trunklength=1.764, |
| 194 | + flows=[Hdot[5], -Hdot[18], -Hdot[6]], |
| 195 | + labels=['', 'Heat rate', None], |
| 196 | + pathlengths=[0.45, 0.25, 0.883], |
| 197 | + orientations=[-1, 1, 0], prior=8, connect=(2, 0)) |
| 198 | + diagrams = sankey.finish() |
| 199 | + for diagram in diagrams: |
| 200 | + diagram.text.set_fontweight('bold') |
| 201 | + diagram.text.set_fontsize('10') |
| 202 | + for text in diagram.texts: |
| 203 | + text.set_fontsize('10') |
| 204 | + # Notice that the explicit connections are handled automatically, but the |
| 205 | + # implicit ones currently are not. The lengths of the paths and the trunks |
| 206 | + # must be adjusted manually, and that is a bit tricky. |
191 | 207 |
|
192 | 208 | plt.show()
|
0 commit comments