-
-
Notifications
You must be signed in to change notification settings - Fork 37
/
Copy pathplot.py
144 lines (123 loc) · 3.76 KB
/
plot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# Standard library
import os
import sys
# Third-party
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
from matplotlib import colormaps
# Add parent directory so shared can be imported
sys.path.append(os.path.dirname(__file__))
# First-party/Local
import shared # noqa: E402
def annotate_ylabels(ax, data, data_label, colors):
i = 0
c = 0
ytick = ax.yaxis.get_major_ticks(numticks=1)[0]
# defaults: ytick.major.size + ytick.major.pad
indent = -1 * (ytick.get_tick_padding() + ytick.get_pad())
for index, row in data.iterrows():
if c > len(colors):
c = 0
# annotate totals
ax.annotate(
f" {row[data_label]:>15,d}",
(indent, i - 0.1),
xycoords=("axes points", "data"),
color=colors[c],
fontsize="x-small",
horizontalalignment="right",
verticalalignment="top",
)
# annotate percentages
percent = row[data_label] / data[data_label].sum() * 100
if percent < 0.1:
percent = "< .1%"
else:
percent = f"{percent:4.1f}%"
ax.annotate(
percent,
(1.02, i),
xycoords=("axes fraction", "data"),
backgroundcolor=colors[c],
color="white",
fontsize="x-small",
horizontalalignment="left",
verticalalignment="center",
)
i += 1
c += 1
return ax
def combined_plot(
args, data, title, name_label, data_label, bar_xscale=None, bar_ylabel=None
):
if len(data) > 10:
raise shared.QuantifyingException(
"the combined_plot() function is limited to a maximum of 10 data"
" points"
)
plt.rcParams.update({"font.family": "monospace", "figure.dpi": 300})
height = 1 + len(data) * 0.5
if height < 2.5:
height = 2.5
fig, (ax1, ax2) = plt.subplots(
1, 2, figsize=(8, height), width_ratios=(2, 1), layout="constrained"
)
colors = colormaps["tab10"].colors
# 1st axes: horizontal barplot of counts
# pad tick labels to make room for annotation
tick_labels = []
for index, row in data.iterrows():
count = f"{row[data_label]:,d}"
tick_labels.append(f"{index}\n{' ' * len(count)}")
if bar_xscale == "log":
log = True
else:
bar_xscale = "linear"
log = False
ax1.barh(y=tick_labels, width=data[data_label], color=colors, log=log)
ax1.tick_params(axis="x", which="major", labelrotation=45)
ax1.set_xlabel("Number of works")
ax1.xaxis.set_major_formatter(ticker.FuncFormatter(number_formatter))
if bar_ylabel is not None:
ax1.set_ylabel(bar_ylabel)
else:
ax1.set_ylabel(name_label)
ax1 = annotate_ylabels(ax1, data, data_label, colors)
# 2nd axes: pie chart of percentages
data.plot.pie(
ax=ax2,
y=data_label,
colors=colors,
labels=None,
legend=False,
radius=1.25,
)
ax2.set_title("Percent")
ax2.set_ylabel(None)
# plot
plt.suptitle(title)
plt.annotate(
f"Creative Commons (CC)\nbar x scale: {bar_xscale}, data from"
f" {args.quarter}",
(0.95, 5),
xycoords=("figure fraction", "figure points"),
color="gray",
fontsize="x-small",
horizontalalignment="right",
)
if args.show_plots:
plt.show()
return plt
def number_formatter(x, pos):
"""
Use the millions formatter for x-axis
The two args are the value (x) and tick position (pos)
"""
if x >= 1e9:
return f"{x * 1e-9:,.0f}B"
elif x >= 1e6:
return f"{x * 1e-6:,.0f}M"
elif x >= 1e3:
return f"{x * 1e-3:,.0f}K"
else:
return f"{x:,.0f}"