pubify-mpl 1.0.0__tar.gz
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.
- pubify_mpl-1.0.0/LICENSE +21 -0
- pubify_mpl-1.0.0/MANIFEST.in +15 -0
- pubify_mpl-1.0.0/PKG-INFO +341 -0
- pubify_mpl-1.0.0/README.md +323 -0
- pubify_mpl-1.0.0/pyproject.toml +37 -0
- pubify_mpl-1.0.0/setup.cfg +4 -0
- pubify_mpl-1.0.0/src/pubify_mpl/__init__.py +15 -0
- pubify_mpl-1.0.0/src/pubify_mpl/assets/__init__.py +1 -0
- pubify_mpl-1.0.0/src/pubify_mpl/assets/pubify.sty +420 -0
- pubify_mpl-1.0.0/src/pubify_mpl/export.py +377 -0
- pubify_mpl-1.0.0/src/pubify_mpl/layout.py +240 -0
- pubify_mpl-1.0.0/src/pubify_mpl/resources.py +112 -0
- pubify_mpl-1.0.0/src/pubify_mpl/style.py +100 -0
- pubify_mpl-1.0.0/src/pubify_mpl.egg-info/SOURCES.txt +16 -0
- pubify_mpl-1.0.0/tests/test_build_gallery.py +76 -0
- pubify_mpl-1.0.0/tests/test_export.py +250 -0
- pubify_mpl-1.0.0/tests/test_layout.py +123 -0
- pubify_mpl-1.0.0/tests/test_readme.py +15 -0
- pubify_mpl-1.0.0/tests/test_resources.py +30 -0
pubify_mpl-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nelson V. Nunes
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
exclude .DS_Store .coverage coverage.xml
|
|
2
|
+
recursive-exclude * __pycache__ *.py[cod] .DS_Store
|
|
3
|
+
recursive-exclude * .ipynb_checkpoints/*
|
|
4
|
+
recursive-exclude * build/*
|
|
5
|
+
prune src/*.egg-info
|
|
6
|
+
prune build
|
|
7
|
+
prune dist
|
|
8
|
+
prune .pytest_cache
|
|
9
|
+
prune .mypy_cache
|
|
10
|
+
prune .ruff_cache
|
|
11
|
+
prune htmlcov
|
|
12
|
+
prune .venv
|
|
13
|
+
prune .conda
|
|
14
|
+
prune .idea
|
|
15
|
+
prune .vscode
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pubify-mpl
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Publication-oriented Matplotlib figure export and LaTeX layout helpers
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: matplotlib>=3.8
|
|
10
|
+
Requires-Dist: numpy>=1.26
|
|
11
|
+
Provides-Extra: dev
|
|
12
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
13
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
14
|
+
Requires-Dist: mkdocs>=1.6; extra == "dev"
|
|
15
|
+
Requires-Dist: mkdocstrings[python]>=0.30; extra == "dev"
|
|
16
|
+
Requires-Dist: twine>=5.0; extra == "dev"
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# pubify-mpl
|
|
20
|
+
|
|
21
|
+
`pubify-mpl` is a small Python tool for exporting Matplotlib figures at sizes that match your LaTeX document, so the figures drop cleanly into papers, theses, and proceedings without trial-and-error resizing.
|
|
22
|
+
|
|
23
|
+
It combines two parts of a publication workflow:
|
|
24
|
+
|
|
25
|
+
- Python helpers for exporting Matplotlib figures using document-aware sizes
|
|
26
|
+
- a LaTeX package, `pubify.sty`, for arranging exported figures into common panel layouts
|
|
27
|
+
|
|
28
|
+
This package is meant for researchers who already use Matplotlib and LaTeX and want a cleaner path from Python plots to publication-ready figures. It is not a replacement for Matplotlib. It sits at the export and layout stage.
|
|
29
|
+
|
|
30
|
+
## Requirements
|
|
31
|
+
|
|
32
|
+
- Python 3.10+
|
|
33
|
+
- Matplotlib and NumPy
|
|
34
|
+
- a working LaTeX installation
|
|
35
|
+
|
|
36
|
+
`save_fig()` uses `text.usetex=True`, so LaTeX must be available when you export figures from Python.
|
|
37
|
+
|
|
38
|
+
On macOS, a common choice is [MacTeX](https://www.tug.org/mactex/). If you want a smaller install, [BasicTeX](https://www.tug.org/mactex/morepackages.html) can also work, but you may need to add missing packages yourself.
|
|
39
|
+
|
|
40
|
+
LaTeX package requirements:
|
|
41
|
+
|
|
42
|
+
- `pubify.sty` depends on `graphicx`, `subcaption`, and `etoolbox`
|
|
43
|
+
- the staged gallery/debug workspace also uses `lipsum`, so minimal TeX installs may need that package separately
|
|
44
|
+
|
|
45
|
+
## How It Works
|
|
46
|
+
|
|
47
|
+
Technically, `save_fig(...)` does not modify your original Matplotlib figure in place. Instead it:
|
|
48
|
+
|
|
49
|
+
1. makes a copy of the figure
|
|
50
|
+
2. applies publication styling and any requested cleanup only to that copy
|
|
51
|
+
3. resizes the copy to match the requested width or named LaTeX layout
|
|
52
|
+
4. saves the copy to PDF
|
|
53
|
+
|
|
54
|
+
That means your original interactive figure stays unchanged in Python. This is important if you want to keep using the same figure object in a notebook or script after export.
|
|
55
|
+
|
|
56
|
+
On the export side, `save_fig(...)` can:
|
|
57
|
+
|
|
58
|
+
- remove titles, labels, annotations, grids, or colorbars from the exported copy
|
|
59
|
+
- scales your copied figure to match the named layout
|
|
60
|
+
- use LaTeX text rendering during export so fonts and math match the document more closely
|
|
61
|
+
|
|
62
|
+
## Quick Start
|
|
63
|
+
|
|
64
|
+
Install the package:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pip install pubify-mpl
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Export a figure into a LaTeX project:
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
import matplotlib.pyplot as plt
|
|
74
|
+
|
|
75
|
+
from pubify_mpl import prepare, save_fig
|
|
76
|
+
|
|
77
|
+
paper_dir = "~/my-paper"
|
|
78
|
+
figures_dir = "~/my-paper/figures"
|
|
79
|
+
|
|
80
|
+
template = {
|
|
81
|
+
# Values for the default LaTeX article class example.
|
|
82
|
+
"textwidth_in": 5.39643,
|
|
83
|
+
"textheight_in": 7.58960,
|
|
84
|
+
"base_fontsize_pt": 12.0,
|
|
85
|
+
"caption_lineheight_pt": 13.6,
|
|
86
|
+
"subcaption_lineheight_pt": 13.6,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
fig, ax = plt.subplots()
|
|
90
|
+
ax.plot([0, 1], [0, 1])
|
|
91
|
+
ax.set_xlabel("x")
|
|
92
|
+
ax.set_ylabel("y")
|
|
93
|
+
|
|
94
|
+
prepare(paper_dir, template=template)
|
|
95
|
+
save_fig(fig, "onewide", f"{figures_dir}/plot.pdf", template=template)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Then in LaTeX:
|
|
99
|
+
|
|
100
|
+
```tex
|
|
101
|
+
\usepackage{pubify}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Note that `prepare(...)` generates `pubify-template.tex`, and it contains specs that `pubify.sty` uses on the LaTeX side. Keep `pubify-template.tex` next to `pubify.sty`. Your paper directory will usually look like:
|
|
105
|
+
|
|
106
|
+
```text
|
|
107
|
+
main.tex
|
|
108
|
+
pubify.sty
|
|
109
|
+
pubify-template.tex
|
|
110
|
+
figures/plot.pdf
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
If you do not already know your document dimensions and typography settings, first run `prepare(...)` so `pubify.sty` is available in the LaTeX project. Then add `\figprintlayoutspec` to the LaTeX document once and compile it. That prints the current `textwidth`, `textheight`, base font size, and caption/subcaption line heights, which you can then copy into the Python `template` dictionary.
|
|
114
|
+
|
|
115
|
+
`pubify-mpl` is fully compatible with Overleaf. If your LaTeX project is synced locally, the same folder layout works directly. If you do not have local sync set up, copy `pubify.sty`, `pubify-template.tex`, and the exported figure PDFs into the Overleaf project manually.
|
|
116
|
+
|
|
117
|
+
## Examples
|
|
118
|
+
|
|
119
|
+
- [examples/quickstart.ipynb](/Users/nelsonnunes/Library/CloudStorage/Dropbox/Projects/pubify-mpl/examples/quickstart.ipynb): notebook version of the minimal quick-start example, writing into the tracked example project at [examples/tex/main.tex](/Users/nelsonnunes/Library/CloudStorage/Dropbox/Projects/pubify-mpl/examples/tex/main.tex)
|
|
120
|
+
- [gallery/layout-gallery.tex](/Users/nelsonnunes/Library/CloudStorage/Dropbox/Projects/pubify-mpl/gallery/layout-gallery.tex): sample LaTeX source showing the supported panel layouts and macro usage
|
|
121
|
+
|
|
122
|
+
## Layouts
|
|
123
|
+
|
|
124
|
+
See layout options in [gallery/layout-gallery.pdf](/Users/nelsonnunes/Library/CloudStorage/Dropbox/Projects/pubify-mpl/gallery/layout-gallery.pdf) including:
|
|
125
|
+
|
|
126
|
+
- `"one"`: one large panel
|
|
127
|
+
- `"onewide"`: one short wide panel
|
|
128
|
+
- `"two"`: two stacked panels
|
|
129
|
+
- `"twowide"`: two side-by-side panels
|
|
130
|
+
- `"three"`: three stacked panels
|
|
131
|
+
- `"threewide"`: three side-by-side panels
|
|
132
|
+
- `"four"`: 2x2 grid
|
|
133
|
+
- `"six"`: 2x3 grid
|
|
134
|
+
- `"sixwide"`: 3x2 grid
|
|
135
|
+
- `"nine"`: 3x3 grid
|
|
136
|
+
- `"twelve"`: 3x4 grid
|
|
137
|
+
- `"twelvewide"`: 4x3 grid
|
|
138
|
+
- `"fifteen"`: 3x5 grid
|
|
139
|
+
- `"sixteen"`: 4x4 grid
|
|
140
|
+
- `"twenty"`: 4x5 grid
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
## Typical Workflow
|
|
144
|
+
|
|
145
|
+
1. Run `prepare(...)` to install `pubify.sty` and write an initial `pubify-template.tex`.
|
|
146
|
+
2. Measure your real LaTeX document using `\figprintlayoutspec`.
|
|
147
|
+
3. Update the template with the values printed by `\figprintlayoutspec`.
|
|
148
|
+
4. Export your figures with `save_fig(...)`.
|
|
149
|
+
5. Include them in LaTeX with `\figfloat`, `\fig`, and the layout macros.
|
|
150
|
+
|
|
151
|
+
## Advanced Python Usage
|
|
152
|
+
|
|
153
|
+
This is an alternative way to use `pubify-mpl` when you export many figures for the same document or keep several document templates in Python.
|
|
154
|
+
|
|
155
|
+
Define a common set of templates:
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
PUBIFY_TEMPLATES = {
|
|
159
|
+
"article": {
|
|
160
|
+
"textwidth_in": 5.39643,
|
|
161
|
+
"textheight_in": 7.58960,
|
|
162
|
+
"base_fontsize_pt": 12.0,
|
|
163
|
+
"caption_lineheight_pt": 13.6,
|
|
164
|
+
"subcaption_lineheight_pt": 13.6,
|
|
165
|
+
},
|
|
166
|
+
"thesis": {
|
|
167
|
+
"textwidth_in": 6.5,
|
|
168
|
+
"textheight_in": 8.5,
|
|
169
|
+
"base_fontsize_pt": 11.0,
|
|
170
|
+
"caption_lineheight_pt": 13.0,
|
|
171
|
+
"subcaption_lineheight_pt": 13.0,
|
|
172
|
+
},
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Then when you export many figures for the same document, `use_template(...)` lets you set a default template inside a `with` block:
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
import matplotlib.pyplot as plt
|
|
180
|
+
from pubify_mpl import prepare, save_fig, use_template
|
|
181
|
+
|
|
182
|
+
paper_dir = "~/mythesis"
|
|
183
|
+
figures_dir = "~/mythesis/figures"
|
|
184
|
+
|
|
185
|
+
# do this once
|
|
186
|
+
prepare(paper_dir, template=PUBIFY_TEMPLATES["thesis"])
|
|
187
|
+
|
|
188
|
+
# create your figures
|
|
189
|
+
|
|
190
|
+
with use_template(PUBIFY_TEMPLATES["thesis"]):
|
|
191
|
+
save_fig(fig1, "one", f"{figures_dir}/plot-1.pdf")
|
|
192
|
+
save_fig(fig2, "twowide", f"{figures_dir}/plot-2.pdf")
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
For advanced styling on the exported copy, use `prepare_copy` together with
|
|
196
|
+
`apply_publication_style(...)`:
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
from pubify_mpl import apply_publication_style, save_fig
|
|
200
|
+
|
|
201
|
+
def _prepare_copy(fig_copy):
|
|
202
|
+
apply_publication_style(
|
|
203
|
+
fig_copy,
|
|
204
|
+
line_width=1.5,
|
|
205
|
+
tick_labelsize=9.0,
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
save_fig(
|
|
209
|
+
fig,
|
|
210
|
+
"onewide",
|
|
211
|
+
f"{figures_dir}/plot.pdf",
|
|
212
|
+
template=PUBIFY_TEMPLATES["thesis"],
|
|
213
|
+
prepare_copy=_prepare_copy,
|
|
214
|
+
)
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Template Keys
|
|
218
|
+
|
|
219
|
+
The template dictionary tells `pubify-mpl` how much space is available in your LaTeX document and what spacing `pubify.sty` should use around figure rows, subcaptions, and captions.
|
|
220
|
+
|
|
221
|
+
| Key | Meaning | Default |
|
|
222
|
+
| --- | --- | --- |
|
|
223
|
+
| `textwidth_in` | document `\textwidth` in inches | required |
|
|
224
|
+
| `textheight_in` | document `\textheight` in inches | required |
|
|
225
|
+
| `base_fontsize_pt` | base font size used when styling the exported figure copy | `12pt` |
|
|
226
|
+
| `caption_lineheight_pt` | measured line height used to estimate main caption height | `13.6pt` |
|
|
227
|
+
| `subcaption_lineheight_pt` | measured line height used to estimate subcaption height | `13.6pt` |
|
|
228
|
+
| `caption_allowance_in` | extra buffer added beyond the estimated main caption text height | `0.08in` |
|
|
229
|
+
| `subcaption_allowance_in` | extra buffer added beyond the estimated subcaption text height | `0.08in` |
|
|
230
|
+
| `single_row_layout_max_height_in` | maximum total layout height budget used for single-row layouts such as `"onewide"` or `"twowide"` | `textheight_in / 3` |
|
|
231
|
+
| `subcaption_skip_in` | vertical space between a panel and its subcaption | `0.08in` |
|
|
232
|
+
| `row_skip_in` | vertical space between rows in stacked layouts | `0.11in` |
|
|
233
|
+
| `caption_skip_in` | vertical space between the figure body and the main caption | `0.11in` |
|
|
234
|
+
| `post_caption_skip_in` | additional vertical space after the main caption | `0in` |
|
|
235
|
+
| `col_gap_in` | horizontal space between columns | `0.02 * textwidth_in` |
|
|
236
|
+
|
|
237
|
+
For the best match to a real document, copy `textwidth_in`, `textheight_in`, `base_fontsize_pt`, `caption_lineheight_pt`, and `subcaption_lineheight_pt` from `\figprintlayoutspec`.
|
|
238
|
+
|
|
239
|
+
## Most Common `save_fig()` Options
|
|
240
|
+
|
|
241
|
+
Some `save_fig()` options control how the exported figure fits into the LaTeX layout:
|
|
242
|
+
|
|
243
|
+
- `caption_lines=...`: estimate how many lines the main caption will use
|
|
244
|
+
- `subcaption_lines=...`: estimate how many lines each subcaption will use
|
|
245
|
+
- `force_width=...`: force a smaller export width, as long as it still fits inside the selected layout
|
|
246
|
+
- `force_aspect=...`: force a specific aspect ratio for the exported copy
|
|
247
|
+
|
|
248
|
+
Other options let you simplify the exported figure content without changing the original figure in Python:
|
|
249
|
+
|
|
250
|
+
- `hide_labels=True`: remove axis labels from the exported copy
|
|
251
|
+
- `hide_grid=True`: disable the grid on the exported copy
|
|
252
|
+
- `hide_cbar=True`: remove a colorbar when exporting a single-axes panel
|
|
253
|
+
- `hide_annotations=True`: remove `ax.text(...)` annotations from the exported copy
|
|
254
|
+
|
|
255
|
+
## LaTeX Macros
|
|
256
|
+
|
|
257
|
+
`pubify.sty` separates LaTeX figure layout into three pieces:
|
|
258
|
+
|
|
259
|
+
- `\figfloat[placement]{body}[caption][label]` creates the outer floating `figure` environment and adds the main caption and label.
|
|
260
|
+
- the layout macros such as `\figonewide`, `\figtwowide`, and `\figfour` arrange one or more `\fig{...}` panels into a specific layout.
|
|
261
|
+
- `\fig{file}[subcaption][label]` describes one exported panel. The optional subcaption and label are for subcaptions.
|
|
262
|
+
|
|
263
|
+
In normal use, you place one layout macro inside `\figfloat`. For example:
|
|
264
|
+
|
|
265
|
+
```tex
|
|
266
|
+
\figfloat[b!]
|
|
267
|
+
{\figonewide{\fig{figures/plot.pdf}}}
|
|
268
|
+
[A simple exported plot.]
|
|
269
|
+
[fig:plot]
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
For small multi-panel figures, you can use a direct panel-by-panel form:
|
|
273
|
+
|
|
274
|
+
```tex
|
|
275
|
+
\figfloat[t]
|
|
276
|
+
{
|
|
277
|
+
\figtwowide
|
|
278
|
+
{\fig{figures/left.pdf}[Left panel][fig:left]}
|
|
279
|
+
{\fig{figures/right.pdf}[Right panel][fig:right]}
|
|
280
|
+
}
|
|
281
|
+
[Two-panel figure.]
|
|
282
|
+
[fig:two-panel]
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
All layouts also support the row-grouped form. For larger grids, that is the normal pattern:
|
|
286
|
+
|
|
287
|
+
```tex
|
|
288
|
+
\figfloat[t]
|
|
289
|
+
{
|
|
290
|
+
\figfour
|
|
291
|
+
{{\fig{figures/a.pdf}}{\fig{figures/b.pdf}}}
|
|
292
|
+
{{\fig{figures/c.pdf}}{\fig{figures/d.pdf}}}
|
|
293
|
+
}
|
|
294
|
+
[Four-panel figure.]
|
|
295
|
+
[fig:four-panel]
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
The supported layout macros are:
|
|
299
|
+
|
|
300
|
+
- `\figone`, `\figonewide`
|
|
301
|
+
- `\figtwo`, `\figtwowide`
|
|
302
|
+
- `\figthree`, `\figthreewide`
|
|
303
|
+
- `\figfour`, `\figsix`, `\figsixwide`
|
|
304
|
+
- `\fignine`, `\figtwelve`, `\figtwelvewide`
|
|
305
|
+
- `\figfifteen`, `\figsixteen`, `\figtwenty`
|
|
306
|
+
|
|
307
|
+
## Troubleshooting
|
|
308
|
+
|
|
309
|
+
- If Python export fails with a LaTeX error, check that your TeX installation is available from the command line and includes the required packages.
|
|
310
|
+
- If exported figure sizes do not match your document, print `\figprintlayoutspec` from the real document and update your Python template values from that output.
|
|
311
|
+
- If LaTeX reports that a figure float is too large for the page, the usual fixes are to shorten the caption, choose a less tall layout, or adjust the template spacing and allowance values.
|
|
312
|
+
|
|
313
|
+
## Python API Reference
|
|
314
|
+
|
|
315
|
+
Detailed Python API documentation is in [site/api/index.html](site/api/index.html).
|
|
316
|
+
|
|
317
|
+
## LaTeX Package Reference
|
|
318
|
+
|
|
319
|
+
Common forms:
|
|
320
|
+
|
|
321
|
+
```tex
|
|
322
|
+
\usepackage{pubify}
|
|
323
|
+
\usepackage[template=path/pubify-template.tex]{pubify}
|
|
324
|
+
\usepackage[debug]{pubify}
|
|
325
|
+
\usepackage[template=path/pubify-template.tex,debug]{pubify}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Package options:
|
|
329
|
+
|
|
330
|
+
- `template=...`: load an explicit template file
|
|
331
|
+
- `debug`: add figure borders and print layout diagnostics to the LaTeX log
|
|
332
|
+
|
|
333
|
+
Template resolution:
|
|
334
|
+
|
|
335
|
+
- if `template=...` is given, `pubify.sty` loads that file
|
|
336
|
+
- otherwise, `pubify.sty` loads `pubify-template.tex` if it is present next to `pubify.sty`
|
|
337
|
+
- otherwise, `pubify.sty` falls back to its built-in default lengths
|
|
338
|
+
|
|
339
|
+
## License
|
|
340
|
+
|
|
341
|
+
MIT
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
# pubify-mpl
|
|
2
|
+
|
|
3
|
+
`pubify-mpl` is a small Python tool for exporting Matplotlib figures at sizes that match your LaTeX document, so the figures drop cleanly into papers, theses, and proceedings without trial-and-error resizing.
|
|
4
|
+
|
|
5
|
+
It combines two parts of a publication workflow:
|
|
6
|
+
|
|
7
|
+
- Python helpers for exporting Matplotlib figures using document-aware sizes
|
|
8
|
+
- a LaTeX package, `pubify.sty`, for arranging exported figures into common panel layouts
|
|
9
|
+
|
|
10
|
+
This package is meant for researchers who already use Matplotlib and LaTeX and want a cleaner path from Python plots to publication-ready figures. It is not a replacement for Matplotlib. It sits at the export and layout stage.
|
|
11
|
+
|
|
12
|
+
## Requirements
|
|
13
|
+
|
|
14
|
+
- Python 3.10+
|
|
15
|
+
- Matplotlib and NumPy
|
|
16
|
+
- a working LaTeX installation
|
|
17
|
+
|
|
18
|
+
`save_fig()` uses `text.usetex=True`, so LaTeX must be available when you export figures from Python.
|
|
19
|
+
|
|
20
|
+
On macOS, a common choice is [MacTeX](https://www.tug.org/mactex/). If you want a smaller install, [BasicTeX](https://www.tug.org/mactex/morepackages.html) can also work, but you may need to add missing packages yourself.
|
|
21
|
+
|
|
22
|
+
LaTeX package requirements:
|
|
23
|
+
|
|
24
|
+
- `pubify.sty` depends on `graphicx`, `subcaption`, and `etoolbox`
|
|
25
|
+
- the staged gallery/debug workspace also uses `lipsum`, so minimal TeX installs may need that package separately
|
|
26
|
+
|
|
27
|
+
## How It Works
|
|
28
|
+
|
|
29
|
+
Technically, `save_fig(...)` does not modify your original Matplotlib figure in place. Instead it:
|
|
30
|
+
|
|
31
|
+
1. makes a copy of the figure
|
|
32
|
+
2. applies publication styling and any requested cleanup only to that copy
|
|
33
|
+
3. resizes the copy to match the requested width or named LaTeX layout
|
|
34
|
+
4. saves the copy to PDF
|
|
35
|
+
|
|
36
|
+
That means your original interactive figure stays unchanged in Python. This is important if you want to keep using the same figure object in a notebook or script after export.
|
|
37
|
+
|
|
38
|
+
On the export side, `save_fig(...)` can:
|
|
39
|
+
|
|
40
|
+
- remove titles, labels, annotations, grids, or colorbars from the exported copy
|
|
41
|
+
- scales your copied figure to match the named layout
|
|
42
|
+
- use LaTeX text rendering during export so fonts and math match the document more closely
|
|
43
|
+
|
|
44
|
+
## Quick Start
|
|
45
|
+
|
|
46
|
+
Install the package:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install pubify-mpl
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Export a figure into a LaTeX project:
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
import matplotlib.pyplot as plt
|
|
56
|
+
|
|
57
|
+
from pubify_mpl import prepare, save_fig
|
|
58
|
+
|
|
59
|
+
paper_dir = "~/my-paper"
|
|
60
|
+
figures_dir = "~/my-paper/figures"
|
|
61
|
+
|
|
62
|
+
template = {
|
|
63
|
+
# Values for the default LaTeX article class example.
|
|
64
|
+
"textwidth_in": 5.39643,
|
|
65
|
+
"textheight_in": 7.58960,
|
|
66
|
+
"base_fontsize_pt": 12.0,
|
|
67
|
+
"caption_lineheight_pt": 13.6,
|
|
68
|
+
"subcaption_lineheight_pt": 13.6,
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
fig, ax = plt.subplots()
|
|
72
|
+
ax.plot([0, 1], [0, 1])
|
|
73
|
+
ax.set_xlabel("x")
|
|
74
|
+
ax.set_ylabel("y")
|
|
75
|
+
|
|
76
|
+
prepare(paper_dir, template=template)
|
|
77
|
+
save_fig(fig, "onewide", f"{figures_dir}/plot.pdf", template=template)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Then in LaTeX:
|
|
81
|
+
|
|
82
|
+
```tex
|
|
83
|
+
\usepackage{pubify}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Note that `prepare(...)` generates `pubify-template.tex`, and it contains specs that `pubify.sty` uses on the LaTeX side. Keep `pubify-template.tex` next to `pubify.sty`. Your paper directory will usually look like:
|
|
87
|
+
|
|
88
|
+
```text
|
|
89
|
+
main.tex
|
|
90
|
+
pubify.sty
|
|
91
|
+
pubify-template.tex
|
|
92
|
+
figures/plot.pdf
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
If you do not already know your document dimensions and typography settings, first run `prepare(...)` so `pubify.sty` is available in the LaTeX project. Then add `\figprintlayoutspec` to the LaTeX document once and compile it. That prints the current `textwidth`, `textheight`, base font size, and caption/subcaption line heights, which you can then copy into the Python `template` dictionary.
|
|
96
|
+
|
|
97
|
+
`pubify-mpl` is fully compatible with Overleaf. If your LaTeX project is synced locally, the same folder layout works directly. If you do not have local sync set up, copy `pubify.sty`, `pubify-template.tex`, and the exported figure PDFs into the Overleaf project manually.
|
|
98
|
+
|
|
99
|
+
## Examples
|
|
100
|
+
|
|
101
|
+
- [examples/quickstart.ipynb](/Users/nelsonnunes/Library/CloudStorage/Dropbox/Projects/pubify-mpl/examples/quickstart.ipynb): notebook version of the minimal quick-start example, writing into the tracked example project at [examples/tex/main.tex](/Users/nelsonnunes/Library/CloudStorage/Dropbox/Projects/pubify-mpl/examples/tex/main.tex)
|
|
102
|
+
- [gallery/layout-gallery.tex](/Users/nelsonnunes/Library/CloudStorage/Dropbox/Projects/pubify-mpl/gallery/layout-gallery.tex): sample LaTeX source showing the supported panel layouts and macro usage
|
|
103
|
+
|
|
104
|
+
## Layouts
|
|
105
|
+
|
|
106
|
+
See layout options in [gallery/layout-gallery.pdf](/Users/nelsonnunes/Library/CloudStorage/Dropbox/Projects/pubify-mpl/gallery/layout-gallery.pdf) including:
|
|
107
|
+
|
|
108
|
+
- `"one"`: one large panel
|
|
109
|
+
- `"onewide"`: one short wide panel
|
|
110
|
+
- `"two"`: two stacked panels
|
|
111
|
+
- `"twowide"`: two side-by-side panels
|
|
112
|
+
- `"three"`: three stacked panels
|
|
113
|
+
- `"threewide"`: three side-by-side panels
|
|
114
|
+
- `"four"`: 2x2 grid
|
|
115
|
+
- `"six"`: 2x3 grid
|
|
116
|
+
- `"sixwide"`: 3x2 grid
|
|
117
|
+
- `"nine"`: 3x3 grid
|
|
118
|
+
- `"twelve"`: 3x4 grid
|
|
119
|
+
- `"twelvewide"`: 4x3 grid
|
|
120
|
+
- `"fifteen"`: 3x5 grid
|
|
121
|
+
- `"sixteen"`: 4x4 grid
|
|
122
|
+
- `"twenty"`: 4x5 grid
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
## Typical Workflow
|
|
126
|
+
|
|
127
|
+
1. Run `prepare(...)` to install `pubify.sty` and write an initial `pubify-template.tex`.
|
|
128
|
+
2. Measure your real LaTeX document using `\figprintlayoutspec`.
|
|
129
|
+
3. Update the template with the values printed by `\figprintlayoutspec`.
|
|
130
|
+
4. Export your figures with `save_fig(...)`.
|
|
131
|
+
5. Include them in LaTeX with `\figfloat`, `\fig`, and the layout macros.
|
|
132
|
+
|
|
133
|
+
## Advanced Python Usage
|
|
134
|
+
|
|
135
|
+
This is an alternative way to use `pubify-mpl` when you export many figures for the same document or keep several document templates in Python.
|
|
136
|
+
|
|
137
|
+
Define a common set of templates:
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
PUBIFY_TEMPLATES = {
|
|
141
|
+
"article": {
|
|
142
|
+
"textwidth_in": 5.39643,
|
|
143
|
+
"textheight_in": 7.58960,
|
|
144
|
+
"base_fontsize_pt": 12.0,
|
|
145
|
+
"caption_lineheight_pt": 13.6,
|
|
146
|
+
"subcaption_lineheight_pt": 13.6,
|
|
147
|
+
},
|
|
148
|
+
"thesis": {
|
|
149
|
+
"textwidth_in": 6.5,
|
|
150
|
+
"textheight_in": 8.5,
|
|
151
|
+
"base_fontsize_pt": 11.0,
|
|
152
|
+
"caption_lineheight_pt": 13.0,
|
|
153
|
+
"subcaption_lineheight_pt": 13.0,
|
|
154
|
+
},
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Then when you export many figures for the same document, `use_template(...)` lets you set a default template inside a `with` block:
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
import matplotlib.pyplot as plt
|
|
162
|
+
from pubify_mpl import prepare, save_fig, use_template
|
|
163
|
+
|
|
164
|
+
paper_dir = "~/mythesis"
|
|
165
|
+
figures_dir = "~/mythesis/figures"
|
|
166
|
+
|
|
167
|
+
# do this once
|
|
168
|
+
prepare(paper_dir, template=PUBIFY_TEMPLATES["thesis"])
|
|
169
|
+
|
|
170
|
+
# create your figures
|
|
171
|
+
|
|
172
|
+
with use_template(PUBIFY_TEMPLATES["thesis"]):
|
|
173
|
+
save_fig(fig1, "one", f"{figures_dir}/plot-1.pdf")
|
|
174
|
+
save_fig(fig2, "twowide", f"{figures_dir}/plot-2.pdf")
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
For advanced styling on the exported copy, use `prepare_copy` together with
|
|
178
|
+
`apply_publication_style(...)`:
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
from pubify_mpl import apply_publication_style, save_fig
|
|
182
|
+
|
|
183
|
+
def _prepare_copy(fig_copy):
|
|
184
|
+
apply_publication_style(
|
|
185
|
+
fig_copy,
|
|
186
|
+
line_width=1.5,
|
|
187
|
+
tick_labelsize=9.0,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
save_fig(
|
|
191
|
+
fig,
|
|
192
|
+
"onewide",
|
|
193
|
+
f"{figures_dir}/plot.pdf",
|
|
194
|
+
template=PUBIFY_TEMPLATES["thesis"],
|
|
195
|
+
prepare_copy=_prepare_copy,
|
|
196
|
+
)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Template Keys
|
|
200
|
+
|
|
201
|
+
The template dictionary tells `pubify-mpl` how much space is available in your LaTeX document and what spacing `pubify.sty` should use around figure rows, subcaptions, and captions.
|
|
202
|
+
|
|
203
|
+
| Key | Meaning | Default |
|
|
204
|
+
| --- | --- | --- |
|
|
205
|
+
| `textwidth_in` | document `\textwidth` in inches | required |
|
|
206
|
+
| `textheight_in` | document `\textheight` in inches | required |
|
|
207
|
+
| `base_fontsize_pt` | base font size used when styling the exported figure copy | `12pt` |
|
|
208
|
+
| `caption_lineheight_pt` | measured line height used to estimate main caption height | `13.6pt` |
|
|
209
|
+
| `subcaption_lineheight_pt` | measured line height used to estimate subcaption height | `13.6pt` |
|
|
210
|
+
| `caption_allowance_in` | extra buffer added beyond the estimated main caption text height | `0.08in` |
|
|
211
|
+
| `subcaption_allowance_in` | extra buffer added beyond the estimated subcaption text height | `0.08in` |
|
|
212
|
+
| `single_row_layout_max_height_in` | maximum total layout height budget used for single-row layouts such as `"onewide"` or `"twowide"` | `textheight_in / 3` |
|
|
213
|
+
| `subcaption_skip_in` | vertical space between a panel and its subcaption | `0.08in` |
|
|
214
|
+
| `row_skip_in` | vertical space between rows in stacked layouts | `0.11in` |
|
|
215
|
+
| `caption_skip_in` | vertical space between the figure body and the main caption | `0.11in` |
|
|
216
|
+
| `post_caption_skip_in` | additional vertical space after the main caption | `0in` |
|
|
217
|
+
| `col_gap_in` | horizontal space between columns | `0.02 * textwidth_in` |
|
|
218
|
+
|
|
219
|
+
For the best match to a real document, copy `textwidth_in`, `textheight_in`, `base_fontsize_pt`, `caption_lineheight_pt`, and `subcaption_lineheight_pt` from `\figprintlayoutspec`.
|
|
220
|
+
|
|
221
|
+
## Most Common `save_fig()` Options
|
|
222
|
+
|
|
223
|
+
Some `save_fig()` options control how the exported figure fits into the LaTeX layout:
|
|
224
|
+
|
|
225
|
+
- `caption_lines=...`: estimate how many lines the main caption will use
|
|
226
|
+
- `subcaption_lines=...`: estimate how many lines each subcaption will use
|
|
227
|
+
- `force_width=...`: force a smaller export width, as long as it still fits inside the selected layout
|
|
228
|
+
- `force_aspect=...`: force a specific aspect ratio for the exported copy
|
|
229
|
+
|
|
230
|
+
Other options let you simplify the exported figure content without changing the original figure in Python:
|
|
231
|
+
|
|
232
|
+
- `hide_labels=True`: remove axis labels from the exported copy
|
|
233
|
+
- `hide_grid=True`: disable the grid on the exported copy
|
|
234
|
+
- `hide_cbar=True`: remove a colorbar when exporting a single-axes panel
|
|
235
|
+
- `hide_annotations=True`: remove `ax.text(...)` annotations from the exported copy
|
|
236
|
+
|
|
237
|
+
## LaTeX Macros
|
|
238
|
+
|
|
239
|
+
`pubify.sty` separates LaTeX figure layout into three pieces:
|
|
240
|
+
|
|
241
|
+
- `\figfloat[placement]{body}[caption][label]` creates the outer floating `figure` environment and adds the main caption and label.
|
|
242
|
+
- the layout macros such as `\figonewide`, `\figtwowide`, and `\figfour` arrange one or more `\fig{...}` panels into a specific layout.
|
|
243
|
+
- `\fig{file}[subcaption][label]` describes one exported panel. The optional subcaption and label are for subcaptions.
|
|
244
|
+
|
|
245
|
+
In normal use, you place one layout macro inside `\figfloat`. For example:
|
|
246
|
+
|
|
247
|
+
```tex
|
|
248
|
+
\figfloat[b!]
|
|
249
|
+
{\figonewide{\fig{figures/plot.pdf}}}
|
|
250
|
+
[A simple exported plot.]
|
|
251
|
+
[fig:plot]
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
For small multi-panel figures, you can use a direct panel-by-panel form:
|
|
255
|
+
|
|
256
|
+
```tex
|
|
257
|
+
\figfloat[t]
|
|
258
|
+
{
|
|
259
|
+
\figtwowide
|
|
260
|
+
{\fig{figures/left.pdf}[Left panel][fig:left]}
|
|
261
|
+
{\fig{figures/right.pdf}[Right panel][fig:right]}
|
|
262
|
+
}
|
|
263
|
+
[Two-panel figure.]
|
|
264
|
+
[fig:two-panel]
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
All layouts also support the row-grouped form. For larger grids, that is the normal pattern:
|
|
268
|
+
|
|
269
|
+
```tex
|
|
270
|
+
\figfloat[t]
|
|
271
|
+
{
|
|
272
|
+
\figfour
|
|
273
|
+
{{\fig{figures/a.pdf}}{\fig{figures/b.pdf}}}
|
|
274
|
+
{{\fig{figures/c.pdf}}{\fig{figures/d.pdf}}}
|
|
275
|
+
}
|
|
276
|
+
[Four-panel figure.]
|
|
277
|
+
[fig:four-panel]
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
The supported layout macros are:
|
|
281
|
+
|
|
282
|
+
- `\figone`, `\figonewide`
|
|
283
|
+
- `\figtwo`, `\figtwowide`
|
|
284
|
+
- `\figthree`, `\figthreewide`
|
|
285
|
+
- `\figfour`, `\figsix`, `\figsixwide`
|
|
286
|
+
- `\fignine`, `\figtwelve`, `\figtwelvewide`
|
|
287
|
+
- `\figfifteen`, `\figsixteen`, `\figtwenty`
|
|
288
|
+
|
|
289
|
+
## Troubleshooting
|
|
290
|
+
|
|
291
|
+
- If Python export fails with a LaTeX error, check that your TeX installation is available from the command line and includes the required packages.
|
|
292
|
+
- If exported figure sizes do not match your document, print `\figprintlayoutspec` from the real document and update your Python template values from that output.
|
|
293
|
+
- If LaTeX reports that a figure float is too large for the page, the usual fixes are to shorten the caption, choose a less tall layout, or adjust the template spacing and allowance values.
|
|
294
|
+
|
|
295
|
+
## Python API Reference
|
|
296
|
+
|
|
297
|
+
Detailed Python API documentation is in [site/api/index.html](site/api/index.html).
|
|
298
|
+
|
|
299
|
+
## LaTeX Package Reference
|
|
300
|
+
|
|
301
|
+
Common forms:
|
|
302
|
+
|
|
303
|
+
```tex
|
|
304
|
+
\usepackage{pubify}
|
|
305
|
+
\usepackage[template=path/pubify-template.tex]{pubify}
|
|
306
|
+
\usepackage[debug]{pubify}
|
|
307
|
+
\usepackage[template=path/pubify-template.tex,debug]{pubify}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
Package options:
|
|
311
|
+
|
|
312
|
+
- `template=...`: load an explicit template file
|
|
313
|
+
- `debug`: add figure borders and print layout diagnostics to the LaTeX log
|
|
314
|
+
|
|
315
|
+
Template resolution:
|
|
316
|
+
|
|
317
|
+
- if `template=...` is given, `pubify.sty` loads that file
|
|
318
|
+
- otherwise, `pubify.sty` loads `pubify-template.tex` if it is present next to `pubify.sty`
|
|
319
|
+
- otherwise, `pubify.sty` falls back to its built-in default lengths
|
|
320
|
+
|
|
321
|
+
## License
|
|
322
|
+
|
|
323
|
+
MIT
|