|
11 | 11 | import traceback |
12 | 12 |
|
13 | 13 | # Third-party |
14 | | -import matplotlib.pyplot as plt |
15 | | -import matplotlib.ticker as ticker |
16 | 14 | import pandas as pd |
17 | | -from matplotlib import colormaps |
18 | 15 | from pygments import highlight |
19 | 16 | from pygments.formatters import TerminalFormatter |
20 | 17 | from pygments.lexers import PythonTracebackLexer |
|
23 | 20 | sys.path.append(os.path.join(os.path.dirname(__file__), "..")) |
24 | 21 |
|
25 | 22 | # First-party/Local |
| 23 | +import plot # noqa: E402 |
26 | 24 | import shared # noqa: E402 |
27 | 25 |
|
28 | 26 | # Setup |
@@ -71,136 +69,6 @@ def parse_arguments(): |
71 | 69 | return args |
72 | 70 |
|
73 | 71 |
|
74 | | -def number_formatter(x, pos): |
75 | | - """ |
76 | | - Use the millions formatter for x-axis |
77 | | -
|
78 | | - The two args are the value (x) and tick position (pos) |
79 | | - """ |
80 | | - if x >= 1e9: |
81 | | - return f"{x * 1e-9:,.0f}B" |
82 | | - elif x >= 1e6: |
83 | | - return f"{x * 1e-6:,.0f}M" |
84 | | - elif x >= 1e3: |
85 | | - return f"{x * 1e-3:,.0f}K" |
86 | | - else: |
87 | | - return f"{x:,.0f}" |
88 | | - |
89 | | - |
90 | | -def annotate_ylabels(ax, data, data_label, colors): |
91 | | - i = 0 |
92 | | - c = 0 |
93 | | - ytick = ax.yaxis.get_major_ticks(numticks=1)[0] |
94 | | - # defaults: ytick.major.size + ytick.major.pad |
95 | | - indent = -1 * (ytick.get_tick_padding() + ytick.get_pad()) |
96 | | - for index, row in data.iterrows(): |
97 | | - if c > len(colors): |
98 | | - c = 0 |
99 | | - |
100 | | - # annotate totals |
101 | | - ax.annotate( |
102 | | - f" {row[data_label]:>15,d}", |
103 | | - (indent, i - 0.1), |
104 | | - xycoords=("axes points", "data"), |
105 | | - color=colors[c], |
106 | | - fontsize="x-small", |
107 | | - horizontalalignment="right", |
108 | | - verticalalignment="top", |
109 | | - ) |
110 | | - |
111 | | - # annotate percentages |
112 | | - percent = row[data_label] / data[data_label].sum() * 100 |
113 | | - if percent < 0.1: |
114 | | - percent = "< .1%" |
115 | | - else: |
116 | | - percent = f"{percent:4.1f}%" |
117 | | - ax.annotate( |
118 | | - percent, |
119 | | - (1.02, i), |
120 | | - xycoords=("axes fraction", "data"), |
121 | | - backgroundcolor=colors[c], |
122 | | - color="white", |
123 | | - fontsize="x-small", |
124 | | - horizontalalignment="left", |
125 | | - verticalalignment="center", |
126 | | - ) |
127 | | - |
128 | | - i += 1 |
129 | | - c += 1 |
130 | | - return ax |
131 | | - |
132 | | - |
133 | | -def combined_plot( |
134 | | - args, data, title, name_label, data_label, bar_xscale=None, bar_ylabel=None |
135 | | -): |
136 | | - if len(data) > 10: |
137 | | - raise shared.QuantifyingException( |
138 | | - "the combined_plot() function is limited to a maximum of 10 data" |
139 | | - " points" |
140 | | - ) |
141 | | - |
142 | | - plt.rcParams.update({"font.family": "monospace", "figure.dpi": 300}) |
143 | | - |
144 | | - height = 1 + len(data) * 0.5 |
145 | | - if height < 2.5: |
146 | | - height = 2.5 |
147 | | - |
148 | | - fig, (ax1, ax2) = plt.subplots( |
149 | | - 1, 2, figsize=(8, height), width_ratios=(2, 1), layout="constrained" |
150 | | - ) |
151 | | - colors = colormaps["tab10"].colors |
152 | | - |
153 | | - # 1st axes: horizontal barplot of counts |
154 | | - # pad tick labels to make room for annotation |
155 | | - tick_labels = [] |
156 | | - for index, row in data.iterrows(): |
157 | | - count = f"{row[data_label]:,d}" |
158 | | - tick_labels.append(f"{index}\n{' ' * len(count)}") |
159 | | - if bar_xscale == "log": |
160 | | - log = True |
161 | | - else: |
162 | | - bar_xscale = "linear" |
163 | | - log = False |
164 | | - ax1.barh(y=tick_labels, width=data[data_label], color=colors, log=log) |
165 | | - ax1.tick_params(axis="x", which="major", labelrotation=45) |
166 | | - ax1.set_xlabel("Number of works") |
167 | | - ax1.xaxis.set_major_formatter(ticker.FuncFormatter(number_formatter)) |
168 | | - if bar_ylabel is not None: |
169 | | - ax1.set_ylabel(bar_ylabel) |
170 | | - else: |
171 | | - ax1.set_ylabel(name_label) |
172 | | - ax1 = annotate_ylabels(ax1, data, data_label, colors) |
173 | | - |
174 | | - # 2nd axes: pie chart of percentages |
175 | | - data.plot.pie( |
176 | | - ax=ax2, |
177 | | - y=data_label, |
178 | | - colors=colors, |
179 | | - labels=None, |
180 | | - legend=False, |
181 | | - radius=1.25, |
182 | | - ) |
183 | | - ax2.set_title("Percent") |
184 | | - ax2.set_ylabel(None) |
185 | | - |
186 | | - # plot |
187 | | - plt.suptitle(title) |
188 | | - plt.annotate( |
189 | | - f"Creative Commons (CC)\nbar x scale: {bar_xscale}, data from" |
190 | | - f" {args.quarter}", |
191 | | - (0.95, 5), |
192 | | - xycoords=("figure fraction", "figure points"), |
193 | | - color="gray", |
194 | | - fontsize="x-small", |
195 | | - horizontalalignment="right", |
196 | | - ) |
197 | | - |
198 | | - if args.show_plots: |
199 | | - plt.show() |
200 | | - |
201 | | - return plt |
202 | | - |
203 | | - |
204 | 72 | def gcs_intro(args): |
205 | 73 | """ |
206 | 74 | Write Google Custom Search (GCS) introduction. |
@@ -247,7 +115,7 @@ def plot_products(args): |
247 | 115 | data = data[::-1] # reverse order |
248 | 116 |
|
249 | 117 | title = "Products totals and percentages " |
250 | | - plt = combined_plot( |
| 118 | + plt = plot.combined_plot( |
251 | 119 | args=args, |
252 | 120 | data=data, |
253 | 121 | title=title, |
@@ -292,7 +160,7 @@ def plot_tool_status(args): |
292 | 160 | data.sort_values(name_label, ascending=False, inplace=True) |
293 | 161 |
|
294 | 162 | title = "CC legal tools status" |
295 | | - plt = combined_plot( |
| 163 | + plt = plot.combined_plot( |
296 | 164 | args=args, |
297 | 165 | data=data, |
298 | 166 | title=title, |
@@ -335,7 +203,7 @@ def plot_current_tools(args): |
335 | 203 | data.sort_values(name_label, ascending=False, inplace=True) |
336 | 204 |
|
337 | 205 | title = "Current CC legal tools" |
338 | | - plt = combined_plot( |
| 206 | + plt = plot.combined_plot( |
339 | 207 | args=args, |
340 | 208 | data=data, |
341 | 209 | title=title, |
@@ -377,7 +245,7 @@ def plot_old_tools(args): |
377 | 245 | data.sort_values(name_label, ascending=False, inplace=True) |
378 | 246 |
|
379 | 247 | title = "Old CC legal tools" |
380 | | - plt = combined_plot( |
| 248 | + plt = plot.combined_plot( |
381 | 249 | args=args, |
382 | 250 | data=data, |
383 | 251 | title=title, |
@@ -422,7 +290,7 @@ def plot_retired_tools(args): |
422 | 290 | data.sort_values(name_label, ascending=False, inplace=True) |
423 | 291 |
|
424 | 292 | title = "Retired CC legal tools" |
425 | | - plt = combined_plot( |
| 293 | + plt = plot.combined_plot( |
426 | 294 | args=args, |
427 | 295 | data=data, |
428 | 296 | title=title, |
@@ -471,7 +339,7 @@ def plot_countries_highest_usage(args): |
471 | 339 | data = data[::-1] # reverse order |
472 | 340 |
|
473 | 341 | title = "Countries with highest usage of current tools" |
474 | | - plt = combined_plot( |
| 342 | + plt = plot.combined_plot( |
475 | 343 | args=args, |
476 | 344 | data=data, |
477 | 345 | title=title, |
@@ -524,7 +392,7 @@ def plot_languages_highest_usage(args): |
524 | 392 | data = data[::-1] # reverse order |
525 | 393 |
|
526 | 394 | title = "Languages with highest usage of current tools" |
527 | | - plt = combined_plot( |
| 395 | + plt = plot.combined_plot( |
528 | 396 | args=args, |
529 | 397 | data=data, |
530 | 398 | title=title, |
@@ -574,7 +442,7 @@ def plot_free_culture(args): |
574 | 442 | data = pd.read_csv(file_path, index_col=name_label) |
575 | 443 |
|
576 | 444 | title = "Approved for Free Cultural Works" |
577 | | - plt = combined_plot( |
| 445 | + plt = plot.combined_plot( |
578 | 446 | args=args, |
579 | 447 | data=data, |
580 | 448 | title=title, |
|
0 commit comments