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
|
@@ -0,0 +1,840 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: acadplot
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A simple plotting tool using matplotlib for generating plots and subplots for research papers.
|
|
5
|
+
Author: Sudip Bhujel
|
|
6
|
+
Author-email: Sudip Bhujel <code@sudipbhujel.com.np>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: matplotlib>=3.10.8
|
|
10
|
+
Requires-Python: >=3.14
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# AcadPlot
|
|
14
|
+
|
|
15
|
+
A simple plotting tool using matplotlib for generating publication-quality plots and subplots for research papers.
|
|
16
|
+
|
|
17
|
+
AcadPlot defaults to an academic Inconsolata-style setup with LaTeX rendering when available.
|
|
18
|
+
|
|
19
|
+
## Examples
|
|
20
|
+
|
|
21
|
+
Regenerate every example from source with:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
uv run python examples/generate_examples.py
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The committed examples use LaTeX Inconsolata; regeneration requires a TeX installation with the `zi4` package.
|
|
28
|
+
|
|
29
|
+
### Core Figures
|
|
30
|
+
|
|
31
|
+
<img src="examples/plot.png" width="400">
|
|
32
|
+
|
|
33
|
+
<img src="examples/subplot.png" width="500">
|
|
34
|
+
|
|
35
|
+
<img src="examples/top_legend_plot.png" width="400">
|
|
36
|
+
|
|
37
|
+
<img src="examples/text_color_styles.png" width="500">
|
|
38
|
+
|
|
39
|
+
### Bar Figures
|
|
40
|
+
|
|
41
|
+
<img src="examples/bar_plot.png" width="400">
|
|
42
|
+
|
|
43
|
+
<img src="examples/grouped_bar_plot.png" width="500">
|
|
44
|
+
|
|
45
|
+
<img src="examples/stacked_bar_plot.png" width="400">
|
|
46
|
+
|
|
47
|
+
<img src="examples/pattern_bar_plot.png" width="400">
|
|
48
|
+
|
|
49
|
+
### Additional Academic Figures
|
|
50
|
+
|
|
51
|
+
<img src="examples/scatter_plot.png" width="400">
|
|
52
|
+
|
|
53
|
+
<img src="examples/errorbar_plot.png" width="400">
|
|
54
|
+
|
|
55
|
+
<img src="examples/box_plot.png" width="400">
|
|
56
|
+
|
|
57
|
+
<img src="examples/heatmap.png" width="400">
|
|
58
|
+
|
|
59
|
+
<img src="examples/utility_panel.png" width="500">
|
|
60
|
+
|
|
61
|
+
### Style Coverage
|
|
62
|
+
|
|
63
|
+
The examples cover all built-in themes and layout profiles:
|
|
64
|
+
|
|
65
|
+
- `classic` with `paper-1col`: line plot
|
|
66
|
+
- `classic` with `paper-2col`: compact monospace line plot
|
|
67
|
+
- `nature` with `paper-1col`: bar plot
|
|
68
|
+
- `colorblind` with `paper-2col`: grouped bar plot for one column in a two-column paper
|
|
69
|
+
- `colorblind` with `paper-2col-subplot`: two small subplots inside one column of a two-column paper
|
|
70
|
+
- `mono` with `paper-1col`: stacked bar plot
|
|
71
|
+
- `warm` with `presentation`: presentation-scale line plot
|
|
72
|
+
|
|
73
|
+
<img src="examples/presentation_style.png" width="500">
|
|
74
|
+
|
|
75
|
+
<img src="examples/monospace_style.png" width="400">
|
|
76
|
+
|
|
77
|
+
<img src="examples/style_gallery.png" width="500">
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
## Features
|
|
81
|
+
|
|
82
|
+
- 📊 Easy-to-use API for creating academic plots
|
|
83
|
+
- 🎨 Pre-defined color schemes optimized for academic publications
|
|
84
|
+
- 🖋️ Theme-controlled axis, tick, and legend colors for consistent figures
|
|
85
|
+
- 🔷 Multiple marker styles for distinguishing data series
|
|
86
|
+
- 📐 LaTeX support for mathematical notation
|
|
87
|
+
- 🔧 Customizable plot elements (ticks, grids, legends)
|
|
88
|
+
- 📈 Line, bar, scatter, error-bar, box, and heatmap chart helpers
|
|
89
|
+
- 💾 Publication-safe `save()` utility for PNG, PDF, and SVG output
|
|
90
|
+
- 📑 Support for both single plots and subplots
|
|
91
|
+
|
|
92
|
+
## Installation
|
|
93
|
+
|
|
94
|
+
### From GitHub
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
pip install git+https://github.com/sudip-bhujel/acadplot.git
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
or with `uv`:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
uv add git+https://github.com/sudip-bhujel/acadplot.git
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Local Installation (Development)
|
|
107
|
+
|
|
108
|
+
For local development, clone the repository and install in editable mode:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
git clone https://github.com/sudip-bhujel/acadplot.git
|
|
112
|
+
cd acadplot
|
|
113
|
+
pip install -e .
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Requirements
|
|
117
|
+
|
|
118
|
+
- Python >= 3.14
|
|
119
|
+
- matplotlib >= 3.10.8
|
|
120
|
+
|
|
121
|
+
## Usage
|
|
122
|
+
|
|
123
|
+
### Global Publication Style
|
|
124
|
+
|
|
125
|
+
Declare the figure style once near the top of your script, then call plotting functions normally:
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from acadplot import configure_plot_style
|
|
129
|
+
|
|
130
|
+
configure_plot_style(layout="paper-1col", theme="classic")
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Override the layout font size when a paper template or reviewer copy needs it:
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
configure_plot_style(
|
|
137
|
+
layout="paper-2col",
|
|
138
|
+
theme="classic",
|
|
139
|
+
font_size=10.5,
|
|
140
|
+
)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Use separate font sizes when labels, ticks, legends, or titles need different treatment:
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
configure_plot_style(
|
|
147
|
+
layout="paper-2col",
|
|
148
|
+
label_size=10.5,
|
|
149
|
+
tick_size=8.5,
|
|
150
|
+
legend_size=8.5,
|
|
151
|
+
title_size=11,
|
|
152
|
+
)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Use one text-color knob when the default text is too light for a paper or
|
|
156
|
+
projector:
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
configure_plot_style(
|
|
160
|
+
layout="paper-2col",
|
|
161
|
+
theme="classic",
|
|
162
|
+
text_color="dark",
|
|
163
|
+
)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
`text_color` applies to axis labels, tick labels, legend text, titles, and
|
|
167
|
+
AcadPlot annotations. Built-in text presets are separate from the data-series
|
|
168
|
+
color names:
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
from acadplot import available_text_colors
|
|
172
|
+
|
|
173
|
+
print(available_text_colors())
|
|
174
|
+
# ("theme", "default", "dark", "black", "charcoal", "slate", "gray", "dimgray", "muted", "soft", "light")
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
You can also pass any Matplotlib-compatible color:
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
configure_plot_style(text_color="#202020")
|
|
181
|
+
configure_plot_style(text_color="tab:blue")
|
|
182
|
+
configure_plot_style(text_color=(0.1, 0.2, 0.3))
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Example with a built-in preset:
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
from acadplot import configure_plot_style, plot_line
|
|
189
|
+
|
|
190
|
+
configure_plot_style(
|
|
191
|
+
layout="paper-2col",
|
|
192
|
+
theme="classic",
|
|
193
|
+
text_color="dark",
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
plot_line(
|
|
197
|
+
data,
|
|
198
|
+
"lower right",
|
|
199
|
+
label=("Budget", "Accuracy (%)"),
|
|
200
|
+
fname="dark_text_plot.pdf",
|
|
201
|
+
)
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Example with a custom hex color:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
configure_plot_style(text_color="#202020")
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Scale an entire style when the figure needs to be uniformly stronger:
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
configure_plot_style(layout="paper-2col", scale=1.1)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Layout meaning:
|
|
217
|
+
|
|
218
|
+
- `paper-1col`: full-width figure for a single-column paper.
|
|
219
|
+
- `paper-2col`: one-column figure inside a two-column paper; narrower, with the largest paper font and heavier marks because it is visually reduced on the page.
|
|
220
|
+
- `paper-2col-subplot`: two compact panels inside one column of a two-column paper; same width as `paper-2col`, with smaller fonts and lighter marks to avoid crowding.
|
|
221
|
+
- `paper-2col-span`: figure spanning both columns in a two-column paper.
|
|
222
|
+
- `presentation`: larger screen/projector figures.
|
|
223
|
+
|
|
224
|
+
Layout defaults:
|
|
225
|
+
|
|
226
|
+
| Layout | Figure size | Font defaults | Use when |
|
|
227
|
+
|---|---:|---:|---|
|
|
228
|
+
| `paper-1col` | `5.5 x 3.2 in` | balanced paper text | single-column paper figure |
|
|
229
|
+
| `paper-2col` | `3.35 x 2.15 in` | larger text and marks | one plot in one column of a two-column paper |
|
|
230
|
+
| `paper-2col-subplot` | `3.35 x 1.45 in` | smaller ticks/legend, compact marks | two small panels inside one column of a two-column paper |
|
|
231
|
+
| `paper-2col-span` | `6.8 x 2.8 in` | medium paper text | figure spanning both columns |
|
|
232
|
+
| `presentation` | `7.2 x 4.2 in` | large labels and heavier marks | slides and talks |
|
|
233
|
+
|
|
234
|
+
`paper-2col-subplot` intentionally uses smaller tick labels than axis labels:
|
|
235
|
+
`tick_size=4.8`, `legend_size=5.0`, `label_size=5.8`, and `title_size=5.8`.
|
|
236
|
+
This keeps dense two-panel figures legible without letting x/y tick labels
|
|
237
|
+
dominate the plot area.
|
|
238
|
+
|
|
239
|
+
Use `font="libertine"` when a serif academic style is preferred:
|
|
240
|
+
|
|
241
|
+
```python
|
|
242
|
+
configure_plot_style(layout="paper-2col", theme="classic", font="libertine")
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
For two subplots inside one column of a two-column paper, let the layout drive
|
|
246
|
+
the figure size:
|
|
247
|
+
|
|
248
|
+
```python
|
|
249
|
+
import matplotlib.pyplot as plt
|
|
250
|
+
from acadplot import configure_plot_style, figure_size, plot_line, save
|
|
251
|
+
|
|
252
|
+
configure_plot_style(layout="paper-2col-subplot", theme="colorblind")
|
|
253
|
+
fig, axes = plt.subplots(
|
|
254
|
+
1,
|
|
255
|
+
2,
|
|
256
|
+
figsize=figure_size(),
|
|
257
|
+
sharey=True,
|
|
258
|
+
gridspec_kw={"wspace": 0.18},
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
plot_line(data_a, "lower right", ax=axes[0], fname=None)
|
|
262
|
+
plot_line(data_b, "lower right", ax=axes[1], fname=None)
|
|
263
|
+
axes[1].set_ylabel("")
|
|
264
|
+
axes[1].tick_params(axis="y", left=False)
|
|
265
|
+
fig.subplots_adjust(left=0.14, right=0.99, bottom=0.24, top=0.86, wspace=0.18)
|
|
266
|
+
save(fig, "one_column_two_panel.pdf", tight_layout=False)
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Saving Figures
|
|
270
|
+
|
|
271
|
+
Plot functions save directly when `fname` is provided. For manual figures,
|
|
272
|
+
subplots, or multi-format exports, use `save()`:
|
|
273
|
+
|
|
274
|
+
```python
|
|
275
|
+
from acadplot import save, save_all, set_output_dir
|
|
276
|
+
|
|
277
|
+
save(fig, "figure", pdf=True, svg=True)
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
This writes `figure.png`, `figure.pdf`, and `figure.svg` with
|
|
281
|
+
`bbox_inches="tight"` and `pad_inches=0`. Pass a filename with an extension
|
|
282
|
+
when you want one exact target:
|
|
283
|
+
|
|
284
|
+
```python
|
|
285
|
+
save(fig, "figures/model_comparison.pdf")
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Useful options:
|
|
289
|
+
|
|
290
|
+
- `directory="examples"`: write relative names into a directory
|
|
291
|
+
- `formats=("pdf", "svg")`: choose formats explicitly
|
|
292
|
+
- `close=False`: keep the figure open after saving
|
|
293
|
+
- `dpi=600`: increase raster output resolution
|
|
294
|
+
- `metadata=True`: write a small `.acadplot.json` reproducibility sidecar
|
|
295
|
+
|
|
296
|
+
For project-wide figure output:
|
|
297
|
+
|
|
298
|
+
```python
|
|
299
|
+
set_output_dir("figures")
|
|
300
|
+
save_all(fig, "model_comparison") # PNG, PDF, and SVG
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Custom Matplotlib Figures
|
|
304
|
+
|
|
305
|
+
AcadPlot can also style figures that you build manually:
|
|
306
|
+
|
|
307
|
+
```python
|
|
308
|
+
import matplotlib.pyplot as plt
|
|
309
|
+
from acadplot import format_axes, format_legend, panel_labels, annotate_points, save
|
|
310
|
+
|
|
311
|
+
fig, axes = plt.subplots(1, 2)
|
|
312
|
+
axes[0].plot([1, 2, 3], [0.4, 0.6, 0.7])
|
|
313
|
+
axes[1].scatter([1, 2, 3], [0.5, 0.55, 0.63])
|
|
314
|
+
|
|
315
|
+
for ax in axes:
|
|
316
|
+
format_axes(ax, grid="major-y", despine=True)
|
|
317
|
+
|
|
318
|
+
panel_labels(axes)
|
|
319
|
+
annotate_points(axes[0], [(3, 0.7, "best")])
|
|
320
|
+
format_legend(axes[0].legend())
|
|
321
|
+
save(fig, "custom_panel.pdf")
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Use `legend_outside` on built-in chart helpers when the plot area is crowded:
|
|
325
|
+
|
|
326
|
+
```python
|
|
327
|
+
plot_line(data, "upper left", legend_outside="right", fname="outside_legend.pdf")
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
For a legend above the plot with multiple columns:
|
|
331
|
+
|
|
332
|
+
```python
|
|
333
|
+
plot_line(
|
|
334
|
+
data,
|
|
335
|
+
"lower center",
|
|
336
|
+
label=("Training budget", "Accuracy (%)"),
|
|
337
|
+
ncols=3,
|
|
338
|
+
columnspacing=0.9,
|
|
339
|
+
legend_outside="top",
|
|
340
|
+
fname="top_legend.pdf",
|
|
341
|
+
)
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
To inspect style choices:
|
|
345
|
+
|
|
346
|
+
```python
|
|
347
|
+
from acadplot import figure_size, theme_preview
|
|
348
|
+
|
|
349
|
+
print(figure_size("paper-2col"))
|
|
350
|
+
fig, _ = theme_preview()
|
|
351
|
+
save(fig, "theme_preview.pdf")
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
Available layouts:
|
|
355
|
+
|
|
356
|
+
```python
|
|
357
|
+
from acadplot import available_layouts
|
|
358
|
+
|
|
359
|
+
print(available_layouts())
|
|
360
|
+
# ("paper-1col", "paper-2col", "paper-2col-subplot", "paper-2col-span", "presentation")
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Available professional themes:
|
|
364
|
+
|
|
365
|
+
```python
|
|
366
|
+
from acadplot import available_themes
|
|
367
|
+
|
|
368
|
+
print(available_themes())
|
|
369
|
+
# ("classic", "nature", "colorblind", "mono", "warm")
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Available fonts:
|
|
373
|
+
|
|
374
|
+
```python
|
|
375
|
+
from acadplot import available_fonts
|
|
376
|
+
|
|
377
|
+
print(available_fonts())
|
|
378
|
+
# ("libertine", "inconsolata", "serif", "sans")
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
The default `classic` cycle uses a muted publication palette inspired by Paul
|
|
382
|
+
Tol's qualitative color schemes, so omitted colors are less saturated than
|
|
383
|
+
Matplotlib defaults while remaining distinct on screen and paper. Use
|
|
384
|
+
`theme="colorblind"` for an Okabe-Ito style accessible palette.
|
|
385
|
+
|
|
386
|
+
Use a temporary style override when needed:
|
|
387
|
+
|
|
388
|
+
```python
|
|
389
|
+
from acadplot import use_style
|
|
390
|
+
|
|
391
|
+
with use_style(layout="paper-2col", theme="colorblind"):
|
|
392
|
+
plot_line(data, location="upper left", fname="column_plot.pdf")
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
You can also override font size for one plot call:
|
|
396
|
+
|
|
397
|
+
```python
|
|
398
|
+
plot_line(data, location="upper left", font_size=10.5, fname="column_plot.pdf")
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
Use `latex="auto"` to use LaTeX only when the local TeX installation and required font package are available:
|
|
402
|
+
|
|
403
|
+
```python
|
|
404
|
+
configure_plot_style(layout="paper-2col", latex="auto")
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Basic Plot
|
|
408
|
+
|
|
409
|
+
```python
|
|
410
|
+
from acadplot import plot_line, configure_plot_style
|
|
411
|
+
|
|
412
|
+
configure_plot_style(layout="paper-1col", theme="classic")
|
|
413
|
+
|
|
414
|
+
# Define your data: (x_values, y_values, marker, label)
|
|
415
|
+
# Colors are optional; omitted colors use the active professional theme palette.
|
|
416
|
+
data = [
|
|
417
|
+
([10, 20, 30, 40, 50], [5, 10, 15, 20, 25], "x_filled", "Method A"),
|
|
418
|
+
([10, 20, 30, 40, 50], [6, 11, 14, 18, 22], "square", "Method B"),
|
|
419
|
+
([10, 20, 30, 40, 50], [7, 9, 13, 19, 24], "triangle_up", "Method C"),
|
|
420
|
+
]
|
|
421
|
+
|
|
422
|
+
# Create the plot
|
|
423
|
+
plot_line(
|
|
424
|
+
data,
|
|
425
|
+
location="upper left",
|
|
426
|
+
label=("X-axis Label", "Y-axis Label"),
|
|
427
|
+
grid="major",
|
|
428
|
+
ystart=0,
|
|
429
|
+
yticks=range(0, 30, 5),
|
|
430
|
+
fname="output.pdf"
|
|
431
|
+
)
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### Custom Figure Size
|
|
435
|
+
|
|
436
|
+
```python
|
|
437
|
+
from acadplot import plot_line, configure_plot_style
|
|
438
|
+
|
|
439
|
+
configure_plot_style()
|
|
440
|
+
|
|
441
|
+
data = [
|
|
442
|
+
([10, 20, 30, 40, 50], [5, 10, 15, 20, 25], "x_filled", "Method A"),
|
|
443
|
+
([10, 20, 30, 40, 50], [6, 11, 14, 18, 22], "square", "Method B"),
|
|
444
|
+
]
|
|
445
|
+
|
|
446
|
+
# Create a larger plot
|
|
447
|
+
plot_line(
|
|
448
|
+
data,
|
|
449
|
+
location="upper left",
|
|
450
|
+
fig_size=(5, 3), # Custom figure size (width, height)
|
|
451
|
+
label=("X-axis Label", "Y-axis Label"),
|
|
452
|
+
fname="large_plot.pdf"
|
|
453
|
+
)
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
### Creating Subplots
|
|
457
|
+
|
|
458
|
+
```python
|
|
459
|
+
import matplotlib.pyplot as plt
|
|
460
|
+
from acadplot import plot_line, configure_plot_style, save
|
|
461
|
+
|
|
462
|
+
configure_plot_style()
|
|
463
|
+
|
|
464
|
+
data = [
|
|
465
|
+
([10, 20, 30, 40, 50], [5, 10, 15, 20, 25], "x_filled", "Method A"),
|
|
466
|
+
([10, 20, 30, 40, 50], [6, 11, 14, 18, 22], "square", "Method B"),
|
|
467
|
+
([10, 20, 30, 40, 50], [7, 9, 13, 19, 24], "triangle_up", "Method C"),
|
|
468
|
+
]
|
|
469
|
+
|
|
470
|
+
# Create figure with subplots
|
|
471
|
+
fig, axes = plt.subplots(1, 2, figsize=(6, 2))
|
|
472
|
+
|
|
473
|
+
# Plot on each subplot
|
|
474
|
+
plot_line(data, "upper left", ax=axes[0], fname=None)
|
|
475
|
+
plot_line(data, "upper right", ax=axes[1], fname=None)
|
|
476
|
+
|
|
477
|
+
# Adjust layout and save
|
|
478
|
+
plt.tight_layout(pad=0.2)
|
|
479
|
+
plt.subplots_adjust(wspace=0.27)
|
|
480
|
+
save(fig, "subplots.pdf")
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
### Subplots with Shared Legend
|
|
484
|
+
|
|
485
|
+
```python
|
|
486
|
+
import matplotlib.pyplot as plt
|
|
487
|
+
from acadplot import plot_line, configure_plot_style, save
|
|
488
|
+
|
|
489
|
+
configure_plot_style()
|
|
490
|
+
|
|
491
|
+
data = [
|
|
492
|
+
([10, 20, 30, 40, 50], [5, 10, 15, 20, 25], "x_filled", "Method A"),
|
|
493
|
+
([10, 20, 30, 40, 50], [6, 11, 14, 18, 22], "square", "Method B"),
|
|
494
|
+
([10, 20, 30, 40, 50], [7, 9, 13, 19, 24], "triangle_up", "Method C"),
|
|
495
|
+
]
|
|
496
|
+
|
|
497
|
+
fig, axes = plt.subplots(1, 2, figsize=(6, 2))
|
|
498
|
+
|
|
499
|
+
# Plot on each subplot
|
|
500
|
+
plot_line(data, "upper left", ax=axes[0], fname=None)
|
|
501
|
+
plot_line(data, "upper right", ax=axes[1], fname=None)
|
|
502
|
+
|
|
503
|
+
# Remove individual legends
|
|
504
|
+
axes[0].get_legend().remove()
|
|
505
|
+
axes[1].get_legend().remove()
|
|
506
|
+
|
|
507
|
+
# Get handles and labels from one subplot
|
|
508
|
+
handles, labels = axes[0].get_legend_handles_labels()
|
|
509
|
+
|
|
510
|
+
# Create a single legend at the bottom center
|
|
511
|
+
fig.legend(
|
|
512
|
+
handles,
|
|
513
|
+
labels,
|
|
514
|
+
loc="lower center",
|
|
515
|
+
bbox_to_anchor=(0.5, -0.1),
|
|
516
|
+
prop=dict(size=6, family="DejaVu Serif"),
|
|
517
|
+
framealpha=0.6,
|
|
518
|
+
columnspacing=0.5,
|
|
519
|
+
ncols=3,
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
plt.tight_layout(pad=0.2)
|
|
523
|
+
plt.subplots_adjust(wspace=0.27)
|
|
524
|
+
save(fig, "subplots_shared_legend.pdf")
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
## Bar Plots
|
|
528
|
+
|
|
529
|
+
Use the bar plotting functions to create single, grouped, or stacked bar charts.
|
|
530
|
+
|
|
531
|
+
### Single Bar Plot
|
|
532
|
+
|
|
533
|
+
```python
|
|
534
|
+
from acadplot import plot_bar, configure_plot_style
|
|
535
|
+
|
|
536
|
+
configure_plot_style()
|
|
537
|
+
|
|
538
|
+
data = [
|
|
539
|
+
([0, 1, 2], [5, 7, 6], "Method A"),
|
|
540
|
+
([0, 1, 2], [3, 6, 5], "Method B"),
|
|
541
|
+
]
|
|
542
|
+
|
|
543
|
+
plot_bar(
|
|
544
|
+
data,
|
|
545
|
+
location="upper left",
|
|
546
|
+
label=("X-axis Label", "Y-axis Label"),
|
|
547
|
+
xticklabels=["Group A", "Group B", "Group C"],
|
|
548
|
+
fname="single_bar.pdf"
|
|
549
|
+
)
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
### Grouped Bar Plot
|
|
553
|
+
|
|
554
|
+
```python
|
|
555
|
+
from acadplot import plot_grouped_bar, configure_plot_style
|
|
556
|
+
|
|
557
|
+
configure_plot_style()
|
|
558
|
+
|
|
559
|
+
grouped_data = [
|
|
560
|
+
("Dataset A", [(10, "Train"), (8, "Val")]),
|
|
561
|
+
("Dataset B", [(15, "Train"), (12, "Val")]),
|
|
562
|
+
("Dataset C", [(12, "Train"), (14, "Val")]),
|
|
563
|
+
]
|
|
564
|
+
|
|
565
|
+
plot_grouped_bar(
|
|
566
|
+
grouped_data,
|
|
567
|
+
location="upper left",
|
|
568
|
+
label=("X-axis Label", "Y-axis Label"),
|
|
569
|
+
fname="grouped_bar.pdf"
|
|
570
|
+
)
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
### Bar Patterns
|
|
574
|
+
|
|
575
|
+
Use named pattern presets, integer pattern indices, or raw Matplotlib hatch
|
|
576
|
+
strings. Patterns work for `plot_bar`, `plot_grouped_bar`, and
|
|
577
|
+
`plot_stacked_bar`. Bar plots use a solid black border by default, which keeps
|
|
578
|
+
adjacent bars and hatch patterns legible in print and grayscale output.
|
|
579
|
+
|
|
580
|
+
```python
|
|
581
|
+
from acadplot import plot_grouped_bar, configure_plot_style, available_patterns
|
|
582
|
+
|
|
583
|
+
print(available_patterns())
|
|
584
|
+
# ("none", "diagonal", "back_diagonal", "cross", "plus", "dots", "circles", "stars", "horizontal", "vertical", "grid")
|
|
585
|
+
|
|
586
|
+
configure_plot_style(layout="paper-1col", theme="colorblind", text_color="dark")
|
|
587
|
+
|
|
588
|
+
plot_grouped_bar(
|
|
589
|
+
[
|
|
590
|
+
("Dataset A", [(81.2, "Baseline"), (83.5, "AcadPlot")]),
|
|
591
|
+
("Dataset B", [(84.4, "Baseline"), (86.2, "AcadPlot")]),
|
|
592
|
+
("Dataset C", [(86.1, "Baseline"), (88.0, "AcadPlot")]),
|
|
593
|
+
],
|
|
594
|
+
location="upper left",
|
|
595
|
+
label=("Dataset", "Score"),
|
|
596
|
+
patterns=["none", "diagonal"],
|
|
597
|
+
ncols=2,
|
|
598
|
+
fname="pattern_bar.pdf",
|
|
599
|
+
)
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
For per-series control, add the pattern before the label:
|
|
603
|
+
|
|
604
|
+
```python
|
|
605
|
+
plot_stacked_bar(
|
|
606
|
+
["A", "B"],
|
|
607
|
+
[
|
|
608
|
+
([35, 42], "blue", "diagonal", "Compute"),
|
|
609
|
+
([25, 22], "green", "dots", "Memory"),
|
|
610
|
+
],
|
|
611
|
+
location="upper left",
|
|
612
|
+
)
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
### Stacked Bar Plot
|
|
616
|
+
|
|
617
|
+
```python
|
|
618
|
+
from acadplot import plot_stacked_bar, configure_plot_style
|
|
619
|
+
|
|
620
|
+
configure_plot_style()
|
|
621
|
+
|
|
622
|
+
categories = ["Dataset A", "Dataset B", "Dataset C"]
|
|
623
|
+
stacks = [
|
|
624
|
+
([10, 20, 15], "Method A"),
|
|
625
|
+
([5, 10, 8], "Method B"),
|
|
626
|
+
([3, 5, 4], "Method C"),
|
|
627
|
+
]
|
|
628
|
+
|
|
629
|
+
plot_stacked_bar(
|
|
630
|
+
categories,
|
|
631
|
+
stacks,
|
|
632
|
+
location="upper left",
|
|
633
|
+
label=("X-axis Label", "Y-axis Label"),
|
|
634
|
+
fname="stacked_bar.pdf"
|
|
635
|
+
)
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
## Additional Academic Charts
|
|
639
|
+
|
|
640
|
+
These helpers follow the same style model as line and bar plots. Omit colors,
|
|
641
|
+
`fig_size`, and font-size arguments to use the active global style; pass explicit
|
|
642
|
+
values when a figure needs local overrides.
|
|
643
|
+
|
|
644
|
+
### Scatter Plot
|
|
645
|
+
|
|
646
|
+
```python
|
|
647
|
+
from acadplot import plot_scatter, configure_plot_style
|
|
648
|
+
|
|
649
|
+
configure_plot_style(layout="paper-2col", theme="classic")
|
|
650
|
+
|
|
651
|
+
plot_scatter(
|
|
652
|
+
[
|
|
653
|
+
([1.0, 1.4, 1.8], [0.42, 0.45, 0.49], "circle", "Lab A"),
|
|
654
|
+
([1.1, 1.6, 2.0], [0.38, 0.43, 0.47], "square", "Lab B"),
|
|
655
|
+
],
|
|
656
|
+
location="upper left",
|
|
657
|
+
label=("Signal strength", "Response"),
|
|
658
|
+
fname="scatter.pdf",
|
|
659
|
+
)
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
### Error Bar Plot
|
|
663
|
+
|
|
664
|
+
```python
|
|
665
|
+
from acadplot import plot_errorbar, configure_plot_style
|
|
666
|
+
|
|
667
|
+
configure_plot_style(layout="paper-2col", theme="colorblind")
|
|
668
|
+
|
|
669
|
+
plot_errorbar(
|
|
670
|
+
[
|
|
671
|
+
([1, 2, 3], [82.1, 84.0, 85.2], [0.7, 0.6, 0.5], "circle", "Method A"),
|
|
672
|
+
([1, 2, 3], [80.4, 82.5, 83.4], [0.8, 0.7, 0.6], "square", "Method B"),
|
|
673
|
+
],
|
|
674
|
+
location="lower right",
|
|
675
|
+
label=("Data fraction", "Accuracy"),
|
|
676
|
+
fname="errorbar.pdf",
|
|
677
|
+
)
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
### Box Plot
|
|
681
|
+
|
|
682
|
+
```python
|
|
683
|
+
from acadplot import plot_box, configure_plot_style
|
|
684
|
+
|
|
685
|
+
configure_plot_style(layout="paper-2col", theme="nature")
|
|
686
|
+
|
|
687
|
+
plot_box(
|
|
688
|
+
[
|
|
689
|
+
([0.61, 0.65, 0.66, 0.70], "Baseline"),
|
|
690
|
+
([0.68, 0.70, 0.73, 0.77], "Model A"),
|
|
691
|
+
([0.71, 0.74, 0.76, 0.79], "Model B"),
|
|
692
|
+
],
|
|
693
|
+
label=("Method", "F1 score"),
|
|
694
|
+
fname="box.pdf",
|
|
695
|
+
)
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
### Heatmap
|
|
699
|
+
|
|
700
|
+
```python
|
|
701
|
+
from acadplot import plot_heatmap, configure_plot_style
|
|
702
|
+
|
|
703
|
+
configure_plot_style(layout="paper-2col", theme="classic")
|
|
704
|
+
|
|
705
|
+
plot_heatmap(
|
|
706
|
+
[[0.91, 0.06, 0.03], [0.08, 0.84, 0.08], [0.04, 0.10, 0.86]],
|
|
707
|
+
label=("Predicted", "True"),
|
|
708
|
+
xticklabels=["A", "B", "C"],
|
|
709
|
+
yticklabels=["A", "B", "C"],
|
|
710
|
+
colorbar_label="Share",
|
|
711
|
+
annotate=True,
|
|
712
|
+
fname="heatmap.pdf",
|
|
713
|
+
)
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
Omit colors to use the active theme palette. When needed, pass a color name,
|
|
717
|
+
index, hex code, or any Matplotlib color:
|
|
718
|
+
|
|
719
|
+
```python
|
|
720
|
+
explicit_data = [
|
|
721
|
+
([1, 2, 3], [4, 5, 6], "blue", "circle", "Named color"),
|
|
722
|
+
([1, 2, 3], [3, 4, 5], "#5F8A8B", "square", "Raw color"),
|
|
723
|
+
]
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
Available color names or indices (0-19):
|
|
727
|
+
|
|
728
|
+
```python
|
|
729
|
+
colors = {
|
|
730
|
+
"blue", "orange", "green", "purple", "brown", "yellow",
|
|
731
|
+
"sky_blue", "gray", "red", "pink", "teal", "olive",
|
|
732
|
+
"navy", "maroon", "lime", "cyan", "magenta",
|
|
733
|
+
"dark_gray", "light_gray"
|
|
734
|
+
}
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
## Available Markers
|
|
738
|
+
|
|
739
|
+
Use marker names or indices (0-26):
|
|
740
|
+
|
|
741
|
+
```python
|
|
742
|
+
markers = {
|
|
743
|
+
"square", "triangle_up", "pentagon", "circle", "star",
|
|
744
|
+
"plus_filled", "triangle_down", "diamond", "x_filled",
|
|
745
|
+
"triangle_left", "triangle_right", "thin_diamond",
|
|
746
|
+
"hexagon1", "hexagon2", "plus", "x", "vline", "hline",
|
|
747
|
+
"point", "pixel", "tri_down", "tri_up", "tri_left",
|
|
748
|
+
"tri_right", "octagon", "none"
|
|
749
|
+
}
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
## API Reference
|
|
753
|
+
|
|
754
|
+
### `plot_line(lines, location, fig_size, label, ax, xticks, yticks, xstart, ystart, font_size, grid, fname)`
|
|
755
|
+
|
|
756
|
+
**Parameters:**
|
|
757
|
+
|
|
758
|
+
- `lines` (List[Tuple]): List of lines to plot, each defined by `(x_values, y_values, marker, label)` or `(x_values, y_values, color, marker, label)`
|
|
759
|
+
- `location` (str): Location of the legend (e.g., "upper left", "lower right")
|
|
760
|
+
- `fig_size` (Tuple[float, float]): Figure size (width, height) in inches. Defaults to the active layout profile
|
|
761
|
+
- `label` (Tuple[str, str]): Labels for x and y axes. Default: `("x-label", "y-label")`
|
|
762
|
+
- `ax` (Optional[plt.Axes]): Axes to plot on. Creates new if None
|
|
763
|
+
- `xticks` (Optional[List[float] | range]): Custom x-axis ticks
|
|
764
|
+
- `yticks` (Optional[List[float] | range]): Custom y-axis ticks
|
|
765
|
+
- `xstart` (Optional[float]): Minimum x-axis value
|
|
766
|
+
- `ystart` (Optional[float]): Minimum y-axis value
|
|
767
|
+
- `font_size` (int): Font size for the plot. Defaults to the active layout profile
|
|
768
|
+
- `grid` (str): Grid preset: `"major-y"`, `"major"`, `"major-minor"`, or `"none"`
|
|
769
|
+
- `fname` (Optional[str]): Filename to save the plot. Default: `"plot.pdf"`
|
|
770
|
+
|
|
771
|
+
### `draw(ax, x, y, color_key, marker_key, label)`
|
|
772
|
+
|
|
773
|
+
Draw a single line with markers on the given axes.
|
|
774
|
+
|
|
775
|
+
### `configure_plot_style(layout, theme, font, latex, font_size, label_size, tick_size, legend_size, title_size, scale, text_color)`
|
|
776
|
+
|
|
777
|
+
Configure global plot style settings with LaTeX rendering. Layouts and themes
|
|
778
|
+
are composable. Each layout has its own default figure size and typography, but
|
|
779
|
+
explicit `font_size`, `label_size`, `tick_size`, `legend_size`, and `title_size`
|
|
780
|
+
arguments always override those defaults. Use `text_color` as a universal text
|
|
781
|
+
color override for axis labels, tick labels, legend text, titles, and AcadPlot
|
|
782
|
+
annotations:
|
|
783
|
+
|
|
784
|
+
```python
|
|
785
|
+
configure_plot_style(
|
|
786
|
+
layout="paper-2col-span",
|
|
787
|
+
theme="nature",
|
|
788
|
+
latex="auto",
|
|
789
|
+
font_size=9.5,
|
|
790
|
+
label_size=10,
|
|
791
|
+
tick_size=8.5,
|
|
792
|
+
legend_size=8.5,
|
|
793
|
+
text_color="#202020",
|
|
794
|
+
scale=1.05,
|
|
795
|
+
)
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
Helper APIs:
|
|
799
|
+
|
|
800
|
+
- `available_fonts()`: Return supported font preset names
|
|
801
|
+
- `available_layouts()`: Return supported layout profile names
|
|
802
|
+
- `available_patterns()`: Return built-in bar pattern preset names
|
|
803
|
+
- `available_text_colors()`: Return built-in text color preset names
|
|
804
|
+
- `available_themes()`: Return supported theme names
|
|
805
|
+
- `figure_size(layout=None)`: Return the active or named layout figure size
|
|
806
|
+
- `get_current_style()`: Return the active style settings
|
|
807
|
+
- `use_style(...)`: Temporarily apply a style inside a `with` block
|
|
808
|
+
|
|
809
|
+
For manual subplots, use `figure_size()` instead of hardcoding `figsize` if you
|
|
810
|
+
want layout changes to affect the canvas.
|
|
811
|
+
|
|
812
|
+
### Utility Functions
|
|
813
|
+
|
|
814
|
+
- `save(fig, name, ...)`: Save figures with tight publication defaults and optional PNG/PDF/SVG multi-format output
|
|
815
|
+
- `save_all(fig, name, ...)`: Save PNG, PDF, and SVG outputs
|
|
816
|
+
- `set_output_dir(path)`: Set a default directory for relative save paths
|
|
817
|
+
- `get_output_dir()`: Return the active default output directory
|
|
818
|
+
- `format_axes(ax, ...)`: Apply AcadPlot style to custom Matplotlib axes
|
|
819
|
+
- `format_legend(legend=None)`: Apply AcadPlot style to an existing legend
|
|
820
|
+
- `despine(ax, ...)`: Hide selected axes spines
|
|
821
|
+
- `panel_labels(axes, ...)`: Add `(a)`, `(b)`, `(c)` labels to panels
|
|
822
|
+
- `annotate_points(ax, points, ...)`: Label selected points with styled annotations
|
|
823
|
+
- `theme_preview()`: Generate a compact preview of theme palettes
|
|
824
|
+
- `new_alpha(color, alpha)`: Create new color with specified alpha
|
|
825
|
+
- `blend_color(rgba1, rgba2)`: Blend two RGBA colors
|
|
826
|
+
- `colors`: Dictionary of pre-defined color names and hex values
|
|
827
|
+
- `markers`: Dictionary of marker names and their matplotlib properties
|
|
828
|
+
- `patterns`: Dictionary of pattern names and Matplotlib hatch strings
|
|
829
|
+
|
|
830
|
+
## License
|
|
831
|
+
|
|
832
|
+
MIT License - see the [LICENSE](LICENSE) file for details.
|
|
833
|
+
|
|
834
|
+
## Contributing
|
|
835
|
+
|
|
836
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
837
|
+
|
|
838
|
+
## Author
|
|
839
|
+
|
|
840
|
+
Sudip Bhujel
|