acadplot 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- acadplot/__init__.py +70 -0
- acadplot/bar.py +428 -0
- acadplot/charts.py +376 -0
- acadplot/draw.py +126 -0
- acadplot/line.py +184 -0
- acadplot/plot.py +70 -0
- acadplot/styles.py +911 -0
- acadplot/utils.py +440 -0
- acadplot-0.1.0.dist-info/METADATA +840 -0
- acadplot-0.1.0.dist-info/RECORD +12 -0
- acadplot-0.1.0.dist-info/WHEEL +4 -0
- acadplot-0.1.0.dist-info/licenses/LICENSE +21 -0
acadplot/__init__.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from .styles import (
|
|
2
|
+
available_fonts,
|
|
3
|
+
available_layouts,
|
|
4
|
+
available_text_colors,
|
|
5
|
+
available_themes,
|
|
6
|
+
configure_plot_style,
|
|
7
|
+
despine,
|
|
8
|
+
figure_size,
|
|
9
|
+
format_axes,
|
|
10
|
+
get_current_style,
|
|
11
|
+
use_style,
|
|
12
|
+
)
|
|
13
|
+
from .draw import draw, draw_bar
|
|
14
|
+
from .line import plot_line
|
|
15
|
+
from .bar import plot_bar, plot_grouped_bar, plot_stacked_bar
|
|
16
|
+
from .charts import plot_box, plot_errorbar, plot_heatmap, plot_scatter
|
|
17
|
+
from .utils import (
|
|
18
|
+
annotate_points,
|
|
19
|
+
available_patterns,
|
|
20
|
+
blend_color,
|
|
21
|
+
colors,
|
|
22
|
+
format_legend,
|
|
23
|
+
get_output_dir,
|
|
24
|
+
markers,
|
|
25
|
+
new_alpha,
|
|
26
|
+
panel_labels,
|
|
27
|
+
patterns,
|
|
28
|
+
save,
|
|
29
|
+
save_all,
|
|
30
|
+
set_output_dir,
|
|
31
|
+
theme_preview,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
__version__ = "0.1.0"
|
|
35
|
+
__all__ = [
|
|
36
|
+
"plot_line",
|
|
37
|
+
"plot_bar",
|
|
38
|
+
"plot_grouped_bar",
|
|
39
|
+
"plot_stacked_bar",
|
|
40
|
+
"plot_scatter",
|
|
41
|
+
"plot_errorbar",
|
|
42
|
+
"plot_box",
|
|
43
|
+
"plot_heatmap",
|
|
44
|
+
"draw",
|
|
45
|
+
"draw_bar",
|
|
46
|
+
"configure_plot_style",
|
|
47
|
+
"available_fonts",
|
|
48
|
+
"available_layouts",
|
|
49
|
+
"available_text_colors",
|
|
50
|
+
"available_themes",
|
|
51
|
+
"figure_size",
|
|
52
|
+
"format_axes",
|
|
53
|
+
"format_legend",
|
|
54
|
+
"despine",
|
|
55
|
+
"get_current_style",
|
|
56
|
+
"use_style",
|
|
57
|
+
"save",
|
|
58
|
+
"save_all",
|
|
59
|
+
"set_output_dir",
|
|
60
|
+
"get_output_dir",
|
|
61
|
+
"panel_labels",
|
|
62
|
+
"annotate_points",
|
|
63
|
+
"theme_preview",
|
|
64
|
+
"available_patterns",
|
|
65
|
+
"colors",
|
|
66
|
+
"markers",
|
|
67
|
+
"patterns",
|
|
68
|
+
"new_alpha",
|
|
69
|
+
"blend_color",
|
|
70
|
+
]
|
acadplot/bar.py
ADDED
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
from typing import List, Optional, Sequence, Tuple
|
|
2
|
+
|
|
3
|
+
import matplotlib.pyplot as plt
|
|
4
|
+
from matplotlib.colors import to_rgba
|
|
5
|
+
|
|
6
|
+
from .draw import draw_bar, resolve_color_key, resolve_pattern_key
|
|
7
|
+
from .styles import (
|
|
8
|
+
apply_axis_style,
|
|
9
|
+
apply_grid,
|
|
10
|
+
configure_plot_style,
|
|
11
|
+
get_current_style,
|
|
12
|
+
)
|
|
13
|
+
from .utils import new_alpha, save, styled_legend
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _prepare_axes(ax, fig_size):
|
|
17
|
+
if ax is None:
|
|
18
|
+
return plt.subplots(figsize=fig_size)
|
|
19
|
+
return ax.figure, ax
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _resolve_text_sizes(style, font_size, label_size, tick_size, legend_size):
|
|
23
|
+
font_size_override = font_size
|
|
24
|
+
if font_size is None:
|
|
25
|
+
font_size = float(style["font_size"])
|
|
26
|
+
if label_size is None:
|
|
27
|
+
label_size = (
|
|
28
|
+
font_size_override
|
|
29
|
+
if font_size_override is not None
|
|
30
|
+
else float(style["label_size"])
|
|
31
|
+
)
|
|
32
|
+
if tick_size is None:
|
|
33
|
+
tick_size = (
|
|
34
|
+
font_size_override
|
|
35
|
+
if font_size_override is not None
|
|
36
|
+
else float(style["tick_size"])
|
|
37
|
+
)
|
|
38
|
+
if legend_size is None:
|
|
39
|
+
legend_size = (
|
|
40
|
+
font_size_override
|
|
41
|
+
if font_size_override is not None
|
|
42
|
+
else float(style["legend_size"])
|
|
43
|
+
)
|
|
44
|
+
return font_size, label_size, tick_size, legend_size
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _apply_bar_axis_style(ax, tick_size: float) -> None:
|
|
48
|
+
ax.tick_params(axis="both", labelsize=tick_size)
|
|
49
|
+
apply_axis_style(ax)
|
|
50
|
+
ax.tick_params(axis="x", length=0)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _parse_bar(bar):
|
|
54
|
+
if len(bar) == 5:
|
|
55
|
+
x, y, color_key, pattern_key, bar_label = bar
|
|
56
|
+
return x, y, color_key, pattern_key, bar_label
|
|
57
|
+
if len(bar) == 4:
|
|
58
|
+
x, y, color_key, bar_label = bar
|
|
59
|
+
return x, y, color_key, None, bar_label
|
|
60
|
+
if len(bar) == 3:
|
|
61
|
+
x, y, bar_label = bar
|
|
62
|
+
return x, y, None, None, bar_label
|
|
63
|
+
raise ValueError("Bar entries must be (x, y, color, label) or (x, y, label).")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _parse_group_bar(entry):
|
|
67
|
+
if len(entry) == 4:
|
|
68
|
+
value, color_key, pattern_key, bar_label = entry
|
|
69
|
+
return value, color_key, pattern_key, bar_label
|
|
70
|
+
if len(entry) == 3:
|
|
71
|
+
value, color_key, bar_label = entry
|
|
72
|
+
return value, color_key, None, bar_label
|
|
73
|
+
if len(entry) == 2:
|
|
74
|
+
value, bar_label = entry
|
|
75
|
+
return value, None, None, bar_label
|
|
76
|
+
raise ValueError(
|
|
77
|
+
"Grouped bar entries must be (value, color, label) or (value, label)."
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _parse_stack(stack):
|
|
82
|
+
if len(stack) == 4:
|
|
83
|
+
values, color_key, pattern_key, stack_label = stack
|
|
84
|
+
return values, color_key, pattern_key, stack_label
|
|
85
|
+
if len(stack) == 3:
|
|
86
|
+
values, color_key, stack_label = stack
|
|
87
|
+
return values, color_key, None, stack_label
|
|
88
|
+
if len(stack) == 2:
|
|
89
|
+
values, stack_label = stack
|
|
90
|
+
return values, None, None, stack_label
|
|
91
|
+
raise ValueError("Stack entries must be (values, color, label) or (values, label).")
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _resolve_pattern(patterns, index: int, label: str, explicit_pattern):
|
|
95
|
+
if explicit_pattern is not None:
|
|
96
|
+
return resolve_pattern_key(explicit_pattern)
|
|
97
|
+
if patterns is None:
|
|
98
|
+
return None
|
|
99
|
+
if isinstance(patterns, dict):
|
|
100
|
+
return resolve_pattern_key(patterns.get(label))
|
|
101
|
+
if not patterns:
|
|
102
|
+
return None
|
|
103
|
+
return resolve_pattern_key(patterns[index % len(patterns)])
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _add_legend(
|
|
107
|
+
ax,
|
|
108
|
+
location: str,
|
|
109
|
+
legend_size: float,
|
|
110
|
+
ncols: int,
|
|
111
|
+
columnspacing: float,
|
|
112
|
+
legend_outside: bool | str,
|
|
113
|
+
):
|
|
114
|
+
return styled_legend(
|
|
115
|
+
ax,
|
|
116
|
+
location,
|
|
117
|
+
legend_size=legend_size,
|
|
118
|
+
ncols=ncols,
|
|
119
|
+
columnspacing=columnspacing,
|
|
120
|
+
legend_outside=legend_outside,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def plot_bar(
|
|
125
|
+
bars: List[Tuple],
|
|
126
|
+
location: str,
|
|
127
|
+
fig_size: Optional[Tuple[float, float]] = None,
|
|
128
|
+
label: Tuple[str, str] = ("x-label", "y-label"),
|
|
129
|
+
ax=None,
|
|
130
|
+
xticklabels: Optional[List[str]] = None,
|
|
131
|
+
rotation: float = 0.0,
|
|
132
|
+
font_size: Optional[float] = None,
|
|
133
|
+
label_size: Optional[float] = None,
|
|
134
|
+
tick_size: Optional[float] = None,
|
|
135
|
+
legend_size: Optional[float] = None,
|
|
136
|
+
ncols: int = 1,
|
|
137
|
+
columnspacing: float = 0.5,
|
|
138
|
+
bar_width: float = 0.35,
|
|
139
|
+
patterns: Optional[Sequence[str | int] | dict[str, str | int]] = None,
|
|
140
|
+
grid: Optional[str] = None,
|
|
141
|
+
fname: Optional[str] = "bar_plot.pdf",
|
|
142
|
+
legend_outside: bool | str = False,
|
|
143
|
+
):
|
|
144
|
+
"""Plot a bar chart with a legend.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
bars (List[Tuple]): List of bars, each defined by x positions, y values,
|
|
148
|
+
optional color name/index/raw Matplotlib color, and label. Omit color
|
|
149
|
+
to use the active theme palette cycle.
|
|
150
|
+
location (str): Location of the legend.
|
|
151
|
+
fig_size (Tuple[float, float], optional): Figure size. Defaults to the active style.
|
|
152
|
+
label (Tuple[str, str], optional): Labels for the x and y axes. Defaults to ("x-label", "y-label").
|
|
153
|
+
ax (Optional[plt.Axes], optional): Axes to plot on. Creates new if None. Defaults to None.
|
|
154
|
+
xticklabels (Optional[List[str]], optional): Labels for x-axis ticks. Defaults to None.
|
|
155
|
+
rotation (float, optional): Rotation angle for x-tick labels. Defaults to 0.0.
|
|
156
|
+
font_size (float, optional): Base font size for labels, ticks, and legend. Defaults to the active style.
|
|
157
|
+
label_size (float, optional): Axis label size. Defaults to font_size or the active style.
|
|
158
|
+
tick_size (float, optional): Tick label size. Defaults to font_size or the active style.
|
|
159
|
+
legend_size (float, optional): Legend text size. Defaults to font_size or the active style.
|
|
160
|
+
ncols (int, optional): Number of columns in the legend. Defaults to 1.
|
|
161
|
+
columnspacing (float, optional): Spacing between legend columns. Defaults to 0.5.
|
|
162
|
+
bar_width (float, optional): Width of the bars. Defaults to 0.35.
|
|
163
|
+
grid (str, optional): Grid preset: "major-y", "major", "major-minor", or "none".
|
|
164
|
+
fname (Optional[str], optional): Filename to save the plot. Defaults to "bar_plot.pdf".
|
|
165
|
+
"""
|
|
166
|
+
style = get_current_style()
|
|
167
|
+
if fig_size is None:
|
|
168
|
+
fig_size = style["fig_size"]
|
|
169
|
+
font_size, label_size, tick_size, legend_size = _resolve_text_sizes(
|
|
170
|
+
style,
|
|
171
|
+
font_size,
|
|
172
|
+
label_size,
|
|
173
|
+
tick_size,
|
|
174
|
+
legend_size,
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
fig, ax = _prepare_axes(ax, fig_size)
|
|
178
|
+
|
|
179
|
+
ax.set_prop_cycle(color=list(style["palette"]))
|
|
180
|
+
ax.set_xlabel(label[0], fontsize=label_size)
|
|
181
|
+
ax.set_ylabel(label[1], fontsize=label_size)
|
|
182
|
+
apply_grid(ax, grid or str(style["bar_grid"]))
|
|
183
|
+
|
|
184
|
+
for bar_idx, bar in enumerate(bars):
|
|
185
|
+
x, y, color_key, pattern_key, bar_label = _parse_bar(bar)
|
|
186
|
+
pattern = _resolve_pattern(patterns, bar_idx, bar_label, pattern_key)
|
|
187
|
+
draw_bar(ax, x, y, color_key, bar_label, bar_width, pattern)
|
|
188
|
+
|
|
189
|
+
_add_legend(ax, location, legend_size, ncols, columnspacing, legend_outside)
|
|
190
|
+
|
|
191
|
+
if xticklabels is not None and bars:
|
|
192
|
+
ax.set_xticks(bars[0][0])
|
|
193
|
+
ax.set_xticklabels(xticklabels, rotation=rotation, fontsize=tick_size)
|
|
194
|
+
|
|
195
|
+
_apply_bar_axis_style(ax, tick_size)
|
|
196
|
+
|
|
197
|
+
if fname:
|
|
198
|
+
save(fig, fname, close=False)
|
|
199
|
+
|
|
200
|
+
return fig, ax
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def plot_grouped_bar(
|
|
204
|
+
groups: List[Tuple[str, List[Tuple]]],
|
|
205
|
+
location: str,
|
|
206
|
+
fig_size: Optional[Tuple[float, float]] = None,
|
|
207
|
+
label: Tuple[str, str] = ("x-label", "y-label"),
|
|
208
|
+
ax=None,
|
|
209
|
+
rotation: float = 0.0,
|
|
210
|
+
font_size: Optional[float] = None,
|
|
211
|
+
label_size: Optional[float] = None,
|
|
212
|
+
tick_size: Optional[float] = None,
|
|
213
|
+
legend_size: Optional[float] = None,
|
|
214
|
+
ncols: int = 1,
|
|
215
|
+
columnspacing: float = 0.5,
|
|
216
|
+
bar_width: float = 0.25,
|
|
217
|
+
patterns: Optional[Sequence[str | int] | dict[str, str | int]] = None,
|
|
218
|
+
grid: Optional[str] = None,
|
|
219
|
+
fname: Optional[str] = "grouped_bar_plot.pdf",
|
|
220
|
+
legend_outside: bool | str = False,
|
|
221
|
+
):
|
|
222
|
+
"""Plot a grouped bar chart with multiple bars per group.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
groups (List[Tuple[str, List[Tuple]]]): List of groups, each defined by
|
|
226
|
+
group name and a list of (value, optional color, label) tuples. Omit
|
|
227
|
+
color to use the active theme palette cycle.
|
|
228
|
+
location (str): Location of the legend.
|
|
229
|
+
fig_size (Tuple[float, float], optional): Figure size. Defaults to the active style.
|
|
230
|
+
label (Tuple[str, str], optional): Labels for the x and y axes. Defaults to ("x-label", "y-label").
|
|
231
|
+
ax (Optional[plt.Axes], optional): Axes to plot on. Creates new if None. Defaults to None.
|
|
232
|
+
rotation (float, optional): Rotation angle for x-tick labels. Defaults to 0.0.
|
|
233
|
+
font_size (float, optional): Base font size for labels, ticks, and legend. Defaults to the active style.
|
|
234
|
+
label_size (float, optional): Axis label size. Defaults to font_size or the active style.
|
|
235
|
+
tick_size (float, optional): Tick label size. Defaults to font_size or the active style.
|
|
236
|
+
legend_size (float, optional): Legend text size. Defaults to font_size or the active style.
|
|
237
|
+
ncols (int, optional): Number of columns in the legend. Defaults to 1.
|
|
238
|
+
columnspacing (float, optional): Spacing between legend columns. Defaults to 0.5.
|
|
239
|
+
bar_width (float, optional): Width of each bar. Defaults to 0.25.
|
|
240
|
+
grid (str, optional): Grid preset: "major-y", "major", "major-minor", or "none".
|
|
241
|
+
fname (Optional[str], optional): Filename to save the plot. Defaults to "grouped_bar_plot.pdf".
|
|
242
|
+
"""
|
|
243
|
+
style = get_current_style()
|
|
244
|
+
if fig_size is None:
|
|
245
|
+
fig_size = style["fig_size"]
|
|
246
|
+
font_size, label_size, tick_size, legend_size = _resolve_text_sizes(
|
|
247
|
+
style,
|
|
248
|
+
font_size,
|
|
249
|
+
label_size,
|
|
250
|
+
tick_size,
|
|
251
|
+
legend_size,
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
fig, ax = _prepare_axes(ax, fig_size)
|
|
255
|
+
|
|
256
|
+
ax.set_prop_cycle(color=list(style["palette"]))
|
|
257
|
+
ax.set_xlabel(label[0], fontsize=label_size)
|
|
258
|
+
ax.set_ylabel(label[1], fontsize=label_size)
|
|
259
|
+
apply_grid(ax, grid or str(style["bar_grid"]))
|
|
260
|
+
|
|
261
|
+
n_bars = len(groups[0][1]) if groups else 0
|
|
262
|
+
group_positions = range(len(groups))
|
|
263
|
+
|
|
264
|
+
for bar_idx in range(n_bars):
|
|
265
|
+
positions = [
|
|
266
|
+
pos + (bar_idx - n_bars / 2 + 0.5) * bar_width for pos in group_positions
|
|
267
|
+
]
|
|
268
|
+
values = [group[1][bar_idx][0] for group in groups]
|
|
269
|
+
_, color_key, pattern_key, bar_label = _parse_group_bar(groups[0][1][bar_idx])
|
|
270
|
+
pattern = _resolve_pattern(patterns, bar_idx, bar_label, pattern_key)
|
|
271
|
+
draw_bar(ax, positions, values, color_key, bar_label, bar_width, pattern)
|
|
272
|
+
|
|
273
|
+
ax.set_xticks(list(group_positions))
|
|
274
|
+
ax.set_xticklabels([g[0] for g in groups], rotation=rotation, fontsize=tick_size)
|
|
275
|
+
|
|
276
|
+
_add_legend(ax, location, legend_size, ncols, columnspacing, legend_outside)
|
|
277
|
+
_apply_bar_axis_style(ax, tick_size)
|
|
278
|
+
|
|
279
|
+
if fname:
|
|
280
|
+
save(fig, fname, close=False)
|
|
281
|
+
|
|
282
|
+
return fig, ax
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def plot_stacked_bar(
|
|
286
|
+
categories: List[str],
|
|
287
|
+
stacks: List[Tuple],
|
|
288
|
+
location: str,
|
|
289
|
+
fig_size: Optional[Tuple[float, float]] = None,
|
|
290
|
+
label: Tuple[str, str] = ("x-label", "y-label"),
|
|
291
|
+
ax=None,
|
|
292
|
+
rotation: float = 0.0,
|
|
293
|
+
font_size: Optional[float] = None,
|
|
294
|
+
label_size: Optional[float] = None,
|
|
295
|
+
tick_size: Optional[float] = None,
|
|
296
|
+
legend_size: Optional[float] = None,
|
|
297
|
+
ncols: int = 1,
|
|
298
|
+
columnspacing: float = 0.5,
|
|
299
|
+
bar_width: float = 0.35,
|
|
300
|
+
patterns: Optional[Sequence[str | int] | dict[str, str | int]] = None,
|
|
301
|
+
grid: Optional[str] = None,
|
|
302
|
+
fname: Optional[str] = "stacked_bar_plot.pdf",
|
|
303
|
+
legend_outside: bool | str = False,
|
|
304
|
+
):
|
|
305
|
+
"""Plot a stacked bar chart.
|
|
306
|
+
|
|
307
|
+
Args:
|
|
308
|
+
categories (List[str]): Category labels for the x-axis.
|
|
309
|
+
stacks (List[Tuple]): List of stacks, each defined by values, optional
|
|
310
|
+
color name/index/raw Matplotlib color, and label. Omit color to use
|
|
311
|
+
the active theme palette cycle.
|
|
312
|
+
location (str): Location of the legend.
|
|
313
|
+
fig_size (Tuple[float, float], optional): Figure size. Defaults to the active style.
|
|
314
|
+
label (Tuple[str, str], optional): Labels for the x and y axes. Defaults to ("x-label", "y-label").
|
|
315
|
+
ax (Optional[plt.Axes], optional): Axes to plot on. Creates new if None. Defaults to None.
|
|
316
|
+
rotation (float, optional): Rotation angle for x-tick labels. Defaults to 0.0.
|
|
317
|
+
font_size (float, optional): Base font size for labels, ticks, and legend. Defaults to the active style.
|
|
318
|
+
label_size (float, optional): Axis label size. Defaults to font_size or the active style.
|
|
319
|
+
tick_size (float, optional): Tick label size. Defaults to font_size or the active style.
|
|
320
|
+
legend_size (float, optional): Legend text size. Defaults to font_size or the active style.
|
|
321
|
+
ncols (int, optional): Number of columns in the legend. Defaults to 1.
|
|
322
|
+
columnspacing (float, optional): Spacing between legend columns. Defaults to 0.5.
|
|
323
|
+
bar_width (float, optional): Width of the bars. Defaults to 0.35.
|
|
324
|
+
grid (str, optional): Grid preset: "major-y", "major", "major-minor", or "none".
|
|
325
|
+
fname (Optional[str], optional): Filename to save the plot. Defaults to "stacked_bar_plot.pdf".
|
|
326
|
+
"""
|
|
327
|
+
style = get_current_style()
|
|
328
|
+
if fig_size is None:
|
|
329
|
+
fig_size = style["fig_size"]
|
|
330
|
+
font_size, label_size, tick_size, legend_size = _resolve_text_sizes(
|
|
331
|
+
style,
|
|
332
|
+
font_size,
|
|
333
|
+
label_size,
|
|
334
|
+
tick_size,
|
|
335
|
+
legend_size,
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
fig, ax = _prepare_axes(ax, fig_size)
|
|
339
|
+
|
|
340
|
+
ax.set_prop_cycle(color=list(style["palette"]))
|
|
341
|
+
ax.set_xlabel(label[0], fontsize=label_size)
|
|
342
|
+
ax.set_ylabel(label[1], fontsize=label_size)
|
|
343
|
+
apply_grid(ax, grid or str(style["bar_grid"]))
|
|
344
|
+
|
|
345
|
+
x_positions = range(len(categories))
|
|
346
|
+
bottoms = [0.0] * len(categories)
|
|
347
|
+
|
|
348
|
+
for stack_idx, stack in enumerate(stacks):
|
|
349
|
+
values, color_key, pattern_key, stack_label = _parse_stack(stack)
|
|
350
|
+
color = resolve_color_key(color_key)
|
|
351
|
+
pattern = _resolve_pattern(patterns, stack_idx, stack_label, pattern_key)
|
|
352
|
+
bar_alpha = float(style["bar_alpha"])
|
|
353
|
+
bar_edge_color = str(style["bar_edge_color"])
|
|
354
|
+
color_kwargs = {"edgecolor": bar_edge_color}
|
|
355
|
+
if color is not None:
|
|
356
|
+
color_kwargs["facecolor"] = new_alpha(to_rgba(color), bar_alpha)
|
|
357
|
+
container = ax.bar(
|
|
358
|
+
x_positions,
|
|
359
|
+
values,
|
|
360
|
+
bar_width,
|
|
361
|
+
bottom=bottoms,
|
|
362
|
+
linewidth=float(style["bar_edge_width"]),
|
|
363
|
+
hatch=pattern,
|
|
364
|
+
label=stack_label,
|
|
365
|
+
zorder=3,
|
|
366
|
+
**color_kwargs,
|
|
367
|
+
)
|
|
368
|
+
for patch in container.patches:
|
|
369
|
+
if color is None:
|
|
370
|
+
patch.set_facecolor(
|
|
371
|
+
new_alpha(to_rgba(patch.get_facecolor()), bar_alpha)
|
|
372
|
+
)
|
|
373
|
+
patch.set_edgecolor(bar_edge_color)
|
|
374
|
+
patch.set_alpha(None)
|
|
375
|
+
bottoms = [bottom + value for bottom, value in zip(bottoms, values)]
|
|
376
|
+
|
|
377
|
+
ax.set_xticks(list(x_positions))
|
|
378
|
+
ax.set_xticklabels(categories, rotation=rotation, fontsize=tick_size)
|
|
379
|
+
|
|
380
|
+
_add_legend(ax, location, legend_size, ncols, columnspacing, legend_outside)
|
|
381
|
+
_apply_bar_axis_style(ax, tick_size)
|
|
382
|
+
|
|
383
|
+
if fname:
|
|
384
|
+
save(fig, fname, close=False)
|
|
385
|
+
|
|
386
|
+
return fig, ax
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
if __name__ == "__main__":
|
|
390
|
+
configure_plot_style()
|
|
391
|
+
|
|
392
|
+
bar_data: List[Tuple[List[float], List[float], str | int, str]] = [
|
|
393
|
+
([0, 1, 2, 3], [10, 20, 15, 25], "blue", "Bar A"),
|
|
394
|
+
([0, 1, 2, 3], [8, 15, 12, 20], "orange", "Bar B"),
|
|
395
|
+
]
|
|
396
|
+
plot_bar(
|
|
397
|
+
bar_data,
|
|
398
|
+
"upper left",
|
|
399
|
+
xticklabels=["A", "B", "C", "D"],
|
|
400
|
+
fname="examples/bar_plot.png",
|
|
401
|
+
font_size=8,
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
grouped_data: List[Tuple[str, List[Tuple[float, str | int, str]]]] = [
|
|
405
|
+
("Model X", [(10, "blue", "Train"), (8, "orange", "Val")]),
|
|
406
|
+
("Model Y", [(15, "blue", "Train"), (12, "orange", "Val")]),
|
|
407
|
+
("Model Z", [(12, "blue", "Train"), (14, "orange", "Val")]),
|
|
408
|
+
]
|
|
409
|
+
plot_grouped_bar(
|
|
410
|
+
grouped_data,
|
|
411
|
+
"upper left",
|
|
412
|
+
fname="examples/grouped_bar_plot.png",
|
|
413
|
+
font_size=8,
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
categories = ["Dataset A", "Dataset B", "Dataset C"]
|
|
417
|
+
stacked_data: List[Tuple[List[float], str | int, str]] = [
|
|
418
|
+
([10, 20, 15], "blue", "Method A"),
|
|
419
|
+
([5, 10, 8], "orange", "Method B"),
|
|
420
|
+
([3, 5, 4], "green", "Method C"),
|
|
421
|
+
]
|
|
422
|
+
plot_stacked_bar(
|
|
423
|
+
categories,
|
|
424
|
+
stacked_data,
|
|
425
|
+
"upper left",
|
|
426
|
+
fname="examples/stacked_bar_plot.png",
|
|
427
|
+
font_size=8,
|
|
428
|
+
)
|