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.
@@ -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