-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcharp.py
142 lines (115 loc) · 4.11 KB
/
charp.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
"""
CharP is Charts for Paulo — Paulos aux functions and preferences for beautiful
and functional charts
"""
from typing import Iterable, List
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.text import Text
from pathlib import Path
default_style = Path(__file__).parent / "paulo.mplstyle"
assert default_style.exists(), f"Arquivo de estilo padrão não encontrado: {default_style}"
plt.style.use(default_style)
# default is orange
color_highlight = plt.rcParams["lines.color"] # type: ignore
color_highlight2 = (0, 153, 51)
color_highlight3 = (30, 66, 139)
def set_title(title, fontsize=16, ax=None):
"""Title always aligned to the left axis label.
Call after changing labels"""
# https://stackoverflow.com/questions/62997001/matplotlib-how-to-exact-align-the-title-to-the-y-label
if ax is None:
ax = plt.gca()
plt.gcf().canvas.draw() # without this, it won't work
x_min = min(lb.get_window_extent().x0 for lb in ax.get_yticklabels())
x_min = min(Text.get_window_extent(lb).x0 for lb in ax.get_yticklabels()) # type: ignore
x, _ = ax.transAxes.inverted().transform([x_min, 0])
plt.gcf().canvas.draw() # without this, it won't work
return ax.set_title(title, ha="left", x=x, fontsize=fontsize)
def rotate_xlabels(angle=45):
plt.tick_params(axis="x", labelrotation=angle, ha="right")
def _break2lines(s: str, acceptable_size: int = None) -> List[str]:
if acceptable_size is not None and len(s) <= acceptable_size:
return [s]
split = s.split()
min_diff_pos = None
min_diff = 10000
for i in range(1, len(split)):
first_line = " ".join(split[:i])
second_line = " ".join(split[i:])
diff = abs(len(first_line) - len(second_line))
if diff <= min_diff:
min_diff = diff
min_diff_pos = i
return [" ".join(split[:min_diff_pos]), " ".join(split[min_diff_pos:])]
def barh(break_lines=False, ax=None):
if ax is None:
ax = plt.gca()
# label on top
ax.tick_params(
axis="x",
top=False,
labeltop=True,
bottom=False,
labelbottom=False,
pad=-13, # hardcoded looks wrong
)
# white grid
ax.grid(axis="x", color="white", linestyle="--")
ax.grid(False, axis="y")
ax.set_axisbelow(False)
# spines
ax.spines["bottom"].set_visible(False)
# labels
if break_lines:
ax.set_yticklabels(break_labels(ax.get_yticklabels()))
def break_labels(tick_labels: Iterable[Text]) -> List[str]:
label_biggest = max([label.get_text() for label in tick_labels], key=len)
line1, line2 = _break2lines(label_biggest)
acceptable_size = max(len(line1), len(line2))
labels_breaked = [
"\n".join(_break2lines(label.get_text(), acceptable_size)) for label in tick_labels
]
return labels_breaked
def bar(ax=None):
if ax is None:
ax = plt.gca()
# white grid
ax.grid(axis="y", color="white", linestyle="dotted")
ax.set_axisbelow(False)
ax.tick_params(
axis="x", bottom=False,
)
def line(ax=None):
if ax is None:
ax = plt.gca()
ax.spines["bottom"].set_visible(False)
for line in ax.lines:
data_x, data_y = line.get_data()
right_most_x = right_most_y = None
for i in reversed(range(len(data_x))):
right_most_x = data_x[i]
right_most_y = data_y[i]
if np.isreal(right_most_x) and np.isreal(right_most_y):
break
assert (
right_most_x is not None and right_most_y is not None
), f"Line {line.get_label()} has no valid points"
ax.annotate(
line.get_label(),
xy=(right_most_x, right_most_y),
xytext=(5, 0),
textcoords="offset points",
va="center",
color=line.get_color(),
)
ax.legend().set_visible(False)
def example_chart():
# in ipython type: %matplotlib
import seaborn as sns
df = sns.load_dataset("iris")
fig = plt.figure()
ax = fig.gca()
plt.plot(df.query('species=="virginica"').petal_length)
ax.set_title("Maria vai com as outras")
return ax