texformules 0.1.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.
- texformules-0.1.0/.gitignore +17 -0
- texformules-0.1.0/CHANGELOG.md +52 -0
- texformules-0.1.0/LICENSE +21 -0
- texformules-0.1.0/PKG-INFO +317 -0
- texformules-0.1.0/README.md +282 -0
- texformules-0.1.0/docs/DOC.md +540 -0
- texformules-0.1.0/examples/figure.py +30 -0
- texformules-0.1.0/examples/render_formulas.py +41 -0
- texformules-0.1.0/pyproject.toml +100 -0
- texformules-0.1.0/src/texformules/__init__.py +51 -0
- texformules-0.1.0/src/texformules/figures/__init__.py +66 -0
- texformules-0.1.0/src/texformules/figures/_require.py +16 -0
- texformules-0.1.0/src/texformules/figures/axes.py +93 -0
- texformules-0.1.0/src/texformules/figures/export.py +70 -0
- texformules-0.1.0/src/texformules/figures/legacy.py +90 -0
- texformules-0.1.0/src/texformules/figures/style.py +135 -0
- texformules-0.1.0/src/texformules/formulas.py +595 -0
- texformules-0.1.0/src/texformules/fragments.py +382 -0
- texformules-0.1.0/src/texformules/py.typed +0 -0
- texformules-0.1.0/tests/conftest.py +105 -0
- texformules-0.1.0/tests/test_figures_axes.py +75 -0
- texformules-0.1.0/tests/test_figures_export.py +61 -0
- texformules-0.1.0/tests/test_figures_legacy.py +77 -0
- texformules-0.1.0/tests/test_figures_style.py +86 -0
- texformules-0.1.0/tests/test_formulas.py +287 -0
- texformules-0.1.0/tests/test_fragments.py +179 -0
- texformules-0.1.0/tests/test_init.py +35 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
|
|
4
|
+
[Semantic Versioning](https://semver.org/).
|
|
5
|
+
|
|
6
|
+
## [0.1.0] — 2026-10-18
|
|
7
|
+
|
|
8
|
+
First release on PyPI. The formulas were a module shared by two private projects; the
|
|
9
|
+
figures were the `latex_figures` package, never published.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **`split(text)`** cuts a line into text and LaTeX `Fragment`s on latexdetok's tree:
|
|
14
|
+
a formula takes its whole word, punctuation included, and a command keeps its
|
|
15
|
+
arguments even without braces; `%` comments are removed (`comments` returns them);
|
|
16
|
+
text commands, `~` and ligatures are rendered without LaTeX. The whole line is
|
|
17
|
+
checked by latexdetok, and a word with an error or a warning, or with a command
|
|
18
|
+
that would affect the other formulas of the batch, stays text, with its `Problem`s
|
|
19
|
+
located.
|
|
20
|
+
- **`FormulaBook(cache, preamble=…, engine=…)`** typesets the missing formulas in a
|
|
21
|
+
single compilation (`render`), and keeps each one as a grey transparent PNG and as
|
|
22
|
+
a one-page vector PDF, with its width, height and depth (`Formula`, and `PdfBox` in
|
|
23
|
+
PDF points). The cache key follows the content of every file the preamble reads
|
|
24
|
+
outside the distribution, recorded with `-recorder`. Rejected formulas keep TeX's
|
|
25
|
+
message, and the places of an undefined command (`Formula.marks`).
|
|
26
|
+
`Formula.to_json()` gives sizes in em for web pages.
|
|
27
|
+
- `default_cache()`, `default_preamble()` (amsmath, amssymb and siunitx),
|
|
28
|
+
`french_spacing()`, `BP_PER_PT`.
|
|
29
|
+
- **`texformules.figures`**, with the `figures` extra (matplotlib ≥ 3.8):
|
|
30
|
+
`apply_style`, `style_params`, `restore_style`, `figure_size`, `style_axes` (with
|
|
31
|
+
`decimal_comma`), `DecimalCommaFormatter`, `add_inset`, `save_figure` (cropped by
|
|
32
|
+
pdfcrop, ImageMagick or epstool), from `latex_figures` 0.1.0.
|
|
33
|
+
- The names of `latex_figures` (`latexify`, `parametres_latex`, `restaurer`,
|
|
34
|
+
`fig_size`, `format_axes`, `ScalarFormatterVirgule`, `add_subplot_axes`, `save_fig`,
|
|
35
|
+
`PREAMBULE`) as deprecated aliases, with their old keywords and defaults.
|
|
36
|
+
- `py.typed`, documentation in `docs/DOC.md`, examples, CI on Linux and macOS with
|
|
37
|
+
Python 3.13 and 3.14 and a job compiling with TeX Live, publication through PyPI
|
|
38
|
+
trusted publishing.
|
|
39
|
+
|
|
40
|
+
### Changed, for those who used the unpublished code
|
|
41
|
+
|
|
42
|
+
- Comments, docstrings and error messages are in English: `rejected by LaTeX`,
|
|
43
|
+
`preamble: …`, `compilation interrupted`, `no LaTeX distribution on this machine`.
|
|
44
|
+
- Importing `texformules` no longer sets latexdetok's language to French nor lowers
|
|
45
|
+
its logger's level: call `latexdetok.set_language("fr")` and set the `latexdetok`
|
|
46
|
+
logger's level yourself.
|
|
47
|
+
- The preamble manifest is now `preamble-<hash>.json` (was `preambule-…`): formulas
|
|
48
|
+
cached before are typeset once more, under new keys.
|
|
49
|
+
- The figures' new default preamble loads amsmath and siunitx instead of French babel
|
|
50
|
+
and siunitx; the deprecated `latexify` and `parametres_latex` keep the old one.
|
|
51
|
+
|
|
52
|
+
[0.1.0]: https://github.com/antnardo/texformules/releases/tag/v0.1.0
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 antnardo
|
|
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,317 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: texformules
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: LaTeX formulas typeset in one batch, cached as PNG and one-page PDF with their baseline; matplotlib figures styled for LaTeX documents.
|
|
5
|
+
Project-URL: Homepage, https://github.com/antnardo/texformules
|
|
6
|
+
Project-URL: Documentation, https://github.com/antnardo/texformules/blob/main/docs/DOC.md
|
|
7
|
+
Project-URL: Repository, https://github.com/antnardo/texformules
|
|
8
|
+
Project-URL: Issues, https://github.com/antnardo/texformules/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/antnardo/texformules/blob/main/CHANGELOG.md
|
|
10
|
+
Author-email: antnardo <antnardo@users.noreply.github.com>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: baseline,formula,latex,math,matplotlib,pdf,png,reportlab,siunitx
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: Education
|
|
17
|
+
Classifier: Intended Audience :: Science/Research
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Natural Language :: English
|
|
20
|
+
Classifier: Operating System :: OS Independent
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Classifier: Topic :: Printing
|
|
25
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
26
|
+
Classifier: Topic :: Text Processing :: Markup :: LaTeX
|
|
27
|
+
Classifier: Typing :: Typed
|
|
28
|
+
Requires-Python: >=3.13
|
|
29
|
+
Requires-Dist: latexdetok>=0.7.0
|
|
30
|
+
Requires-Dist: pillow>=10.0
|
|
31
|
+
Requires-Dist: pypdfium2>=4.30
|
|
32
|
+
Provides-Extra: figures
|
|
33
|
+
Requires-Dist: matplotlib>=3.8; extra == 'figures'
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
|
|
36
|
+
# texformules
|
|
37
|
+
|
|
38
|
+
[](https://github.com/antnardo/texformules/actions/workflows/ci.yml)
|
|
39
|
+
[](https://pypi.org/project/texformules/)
|
|
40
|
+
[](https://pypi.org/project/texformules/)
|
|
41
|
+
[](https://github.com/antnardo/texformules/blob/main/LICENSE)
|
|
42
|
+
|
|
43
|
+
Real LaTeX formulas for documents built in Python. texformules cuts a line of text
|
|
44
|
+
into prose and LaTeX fragments, typesets all the missing fragments in **one LaTeX
|
|
45
|
+
compilation**, and keeps each one in a cache as a PNG and as a **one-page PDF**,
|
|
46
|
+
together with its **baseline**, so that it sits on the line of the surrounding text.
|
|
47
|
+
An optional extra, `texformules.figures`, styles matplotlib figures to match the same
|
|
48
|
+
LaTeX documents.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install texformules # formulas
|
|
52
|
+
pip install "texformules[figures]" # and the matplotlib figures
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from texformules import FormulaBook, default_cache, split
|
|
57
|
+
|
|
58
|
+
book = FormulaBook(default_cache())
|
|
59
|
+
fragments = split(r"Kinetic energy theorem: $\Delta E_c = W(\vec F)$, 2 marks")
|
|
60
|
+
formulas = book.render(f.text for f in fragments if f.latex)
|
|
61
|
+
|
|
62
|
+
for fragment in fragments:
|
|
63
|
+
if fragment.latex and formulas[fragment.text].ok:
|
|
64
|
+
formula = formulas[fragment.text]
|
|
65
|
+
print(book.pdf(formula.key), formula.pdf_box) # page, and its box in PDF points
|
|
66
|
+
else:
|
|
67
|
+
print(fragment.text)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Full reference: [docs/DOC.md](https://github.com/antnardo/texformules/blob/main/docs/DOC.md).
|
|
71
|
+
|
|
72
|
+
## Why
|
|
73
|
+
|
|
74
|
+
Formulas written for a LaTeX document use the macros of its preamble: `\SI` from
|
|
75
|
+
siunitx, `\vect`, `\dd`, whatever the author defined. Nothing short of LaTeX knows
|
|
76
|
+
them: not a conversion to Unicode, not matplotlib's mathtext, not KaTeX. So when a
|
|
77
|
+
Python program has to show those formulas — in a PDF report built with reportlab, on
|
|
78
|
+
a web page, in a desktop application — the only faithful renderer is LaTeX itself,
|
|
79
|
+
with the same preamble.
|
|
80
|
+
|
|
81
|
+
Calling LaTeX once per formula is slow: loading a large preamble alone takes seconds.
|
|
82
|
+
texformules sends all the formulas still missing from the cache to a single
|
|
83
|
+
compilation, then keeps each of them:
|
|
84
|
+
|
|
85
|
+
- **a PNG**, grey and transparent, at the resolution you ask for (288 dpi by default,
|
|
86
|
+
600 for print);
|
|
87
|
+
- **a one-page PDF**, the very page LaTeX produced, cut out of the batch: vector, sharp
|
|
88
|
+
at any zoom and on any printer;
|
|
89
|
+
- **its box**: width, height and depth in TeX points, and in PDF points through
|
|
90
|
+
`Formula.pdf_box`. The depth puts the baseline of the formula on the baseline of
|
|
91
|
+
the text.
|
|
92
|
+
|
|
93
|
+
The next request for the same formula, with the same preamble, is served from the
|
|
94
|
+
cache without LaTeX.
|
|
95
|
+
|
|
96
|
+
## Requirements
|
|
97
|
+
|
|
98
|
+
- Python 3.13 or later (latexdetok, which reads the LaTeX, requires it).
|
|
99
|
+
- A TeX distribution on the `PATH` for anything to be typeset: TeX Live, MacTeX or
|
|
100
|
+
MiKTeX, with `lualatex` (preferred) or `pdflatex`, `kpsewhich`, and the `preview`
|
|
101
|
+
package. The default preamble also needs `amsmath`, `amssymb` and `siunitx`. On
|
|
102
|
+
Debian or Ubuntu:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
sudo apt-get install texlive-luatex texlive-latex-extra texlive-science preview-latex-style
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
- Without TeX, the package still imports and splits text; `FormulaBook.available` is
|
|
109
|
+
false and every formula comes back rejected, with the reason, so that you can show
|
|
110
|
+
the source instead.
|
|
111
|
+
|
|
112
|
+
The Python dependencies are latexdetok, pypdfium2 (renders and cuts the PDF pages,
|
|
113
|
+
no dvipng nor ImageMagick) and Pillow. The `figures` extra adds matplotlib.
|
|
114
|
+
|
|
115
|
+
## Splitting text
|
|
116
|
+
|
|
117
|
+
`split(text)` reads the line as TeX would (with latexdetok) and returns a list of
|
|
118
|
+
`Fragment`s: `text`, `latex` (true for a fragment to typeset) and `problems`.
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
>>> [(f.text, f.latex) for f in split(r"so ($x=1$), then \SI{5e-8}N % note to self")]
|
|
122
|
+
[('so ', False), ('($x=1$),', True), (' then ', False), ('\\SI{5e-8}N', True)]
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
- A LaTeX fragment covers the whole word around the formula, punctuation included,
|
|
126
|
+
so that a line break never leaves "(" or "," alone; and a command keeps its
|
|
127
|
+
arguments, even without braces (`\SI{5e-8}N`).
|
|
128
|
+
- `%` comments are removed: they are notes for the author, not for the reader
|
|
129
|
+
(`comments(text)` returns them).
|
|
130
|
+
- What TeX would print as plain text is translated without LaTeX: `~`, `--`, `---`,
|
|
131
|
+
`\og`/`\fg`, `\%`, group braces…
|
|
132
|
+
- The whole line is checked by latexdetok. A word with an error or a warning (a `$`
|
|
133
|
+
never closed, `_` outside math, `\input` or `\def` inside a formula) is **not** sent
|
|
134
|
+
to LaTeX, where it would break the batch: it stays as typed, and its `problems`
|
|
135
|
+
say where (`start`, `end`), how bad (`severity`) and why (`message`,
|
|
136
|
+
`suggestion`).
|
|
137
|
+
|
|
138
|
+
`french_spacing(text)` sets the no-break spaces of French typography, for the text
|
|
139
|
+
fragments of French documents.
|
|
140
|
+
|
|
141
|
+
## Rendering
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
from texformules import FormulaBook, default_cache
|
|
145
|
+
|
|
146
|
+
book = FormulaBook(default_cache(), dpi=600, size=10)
|
|
147
|
+
formulas = book.render([r"$\frac{a}{b}$", r"\SI{9.81}{m/s^2}", r"$\oops$"])
|
|
148
|
+
|
|
149
|
+
ok = formulas[r"$\frac{a}{b}$"]
|
|
150
|
+
ok.width, ok.height, ok.depth # TeX points, half-point border included
|
|
151
|
+
ok.pdf_box # PdfBox(width, height, depth) in PDF points
|
|
152
|
+
book.image(ok.key) # Path to the PNG
|
|
153
|
+
book.pdf(ok.key) # Path to the one-page PDF
|
|
154
|
+
|
|
155
|
+
bad = formulas[r"$\oops$"]
|
|
156
|
+
bad.ok, bad.error, bad.marks # False, 'Undefined control sequence.', ((1, 6),)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
`render` returns a dict keyed by source. A formula LaTeX rejects keeps its error
|
|
160
|
+
message and, for an undefined command, the places of that command in its source
|
|
161
|
+
(`marks`), so you can highlight them. `Formula.to_json()` gives a JSON-ready summary
|
|
162
|
+
(size in em for web pages, or the error).
|
|
163
|
+
|
|
164
|
+
`render` holds a lock: one `FormulaBook` can be shared by the threads of a web server.
|
|
165
|
+
pdfium itself is not thread-safe: if other code in your process uses pypdfium2, hold
|
|
166
|
+
your own lock around `render` as well.
|
|
167
|
+
|
|
168
|
+
## With reportlab-layout
|
|
169
|
+
|
|
170
|
+
[reportlab-layout](https://pypi.org/project/reportlab_layout/) sets a PDF page inline,
|
|
171
|
+
on the baseline, with `inline_pdf` (version 1.10 with the `pdf` extra), and an image
|
|
172
|
+
with `inline_image`. Both take the box of `Formula.pdf_box`:
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
from xml.sax.saxutils import escape
|
|
176
|
+
|
|
177
|
+
from reportlab_layout import inline_pdf
|
|
178
|
+
from texformules import FormulaBook, default_cache, split
|
|
179
|
+
|
|
180
|
+
book = FormulaBook(default_cache())
|
|
181
|
+
|
|
182
|
+
def markup(text: str) -> str:
|
|
183
|
+
fragments = split(text)
|
|
184
|
+
formulas = book.render(f.text for f in fragments if f.latex)
|
|
185
|
+
parts = []
|
|
186
|
+
for fragment in fragments:
|
|
187
|
+
formula = formulas.get(fragment.text) if fragment.latex else None
|
|
188
|
+
if formula is not None and formula.ok:
|
|
189
|
+
box = formula.pdf_box
|
|
190
|
+
parts.append(inline_pdf(book.pdf(formula.key), width=box.width,
|
|
191
|
+
height=box.height, depth=box.depth))
|
|
192
|
+
else:
|
|
193
|
+
parts.append(escape(fragment.text)) # french_spacing(...) first, for French
|
|
194
|
+
return "".join(parts)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Pass the markup to reportlab-layout's `InlineParagraph` (a plain `Paragraph` cannot
|
|
198
|
+
draw PDF pages); the paragraph style needs `autoLeading="max"`. A rejected formula
|
|
199
|
+
falls back to its source here; set it in a monospaced font if you prefer. reportlab-layout writes each font
|
|
200
|
+
stream once, however many formulas share it, so a page of vector formulas weighs less
|
|
201
|
+
than the same page with 600 dpi PNGs.
|
|
202
|
+
|
|
203
|
+
## Elsewhere
|
|
204
|
+
|
|
205
|
+
- **Web pages**: serve `book.image(key)` and use `formula.to_json()`: `width`,
|
|
206
|
+
`height` and `depth` are in em of the type size, so `height: {height}em;
|
|
207
|
+
vertical-align: -{depth}em` sets the image on the baseline at any font size.
|
|
208
|
+
- **Other PDF libraries**: the one-page PDF can be laid down as a form XObject; its
|
|
209
|
+
MediaBox is the box, and the baseline lies `pdf_box.depth` above its bottom.
|
|
210
|
+
|
|
211
|
+
## Your own preamble
|
|
212
|
+
|
|
213
|
+
By default the preamble loads amsmath, amssymb and siunitx. Pass any preamble, without
|
|
214
|
+
`\documentclass` (the batch uses `book` at 10 pt):
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
book = FormulaBook(
|
|
218
|
+
default_cache(),
|
|
219
|
+
preamble=r"""
|
|
220
|
+
\usepackage{amsmath,amssymb}
|
|
221
|
+
\usepackage{siunitx}
|
|
222
|
+
\usepackage{fontspec}\setmainfont{TeX Gyre Pagella}
|
|
223
|
+
\newcommand\vect[1]{\vec{#1}}
|
|
224
|
+
\input{mymacros}
|
|
225
|
+
""",
|
|
226
|
+
engine="lualatex",
|
|
227
|
+
)
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
- `engine` is a name or a path; by default `lualatex`, else `pdflatex`. fontspec needs
|
|
231
|
+
lualatex (or xelatex).
|
|
232
|
+
- `size` is the type size in TeX points, `dpi` the PNG resolution; both enter the
|
|
233
|
+
cache key.
|
|
234
|
+
- A preamble may `\input` files of yours: they are followed (see below).
|
|
235
|
+
- `default_preamble()` uses `\input{ampackages}` instead when `kpsewhich` finds that
|
|
236
|
+
file: it is the author's own macro suite, absent anywhere else.
|
|
237
|
+
|
|
238
|
+
## The cache
|
|
239
|
+
|
|
240
|
+
`default_cache()` is `~/Library/Caches/texformules` on macOS,
|
|
241
|
+
`%LOCALAPPDATA%\texformules\Cache` on Windows and `$XDG_CACHE_HOME/texformules`
|
|
242
|
+
(`~/.cache/texformules` by default) elsewhere; any folder will do. Each formula is stored under a
|
|
243
|
+
24-character key as `<key>.json`, `<key>.png` and `<key>.pdf`, written atomically, so
|
|
244
|
+
several programs can share the folder.
|
|
245
|
+
|
|
246
|
+
The key is a hash of the source, the engine, the preamble, the size, the resolution,
|
|
247
|
+
and **the content of every file the preamble reads outside the TeX distribution**.
|
|
248
|
+
Each compilation runs with `-recorder`; the files listed in its `.fls` that do not
|
|
249
|
+
belong to the distribution (your `.tex`, `.sty`, `.lua`… including `TEXMFHOME`) are
|
|
250
|
+
recorded in a manifest, `preamble-<hash>.json`. Edit a macro in one of them and the
|
|
251
|
+
next batch typesets the formulas again. Data files (`.py`, `.csv`…) are not followed:
|
|
252
|
+
they change often, and never a formula.
|
|
253
|
+
|
|
254
|
+
To clear the cache, delete the folder. Rejections that are the formula's own fault
|
|
255
|
+
are cached too; those due to the preamble, an interrupted compilation or a missing
|
|
256
|
+
TeX are not, and are retried.
|
|
257
|
+
|
|
258
|
+
## Figures
|
|
259
|
+
|
|
260
|
+
`texformules.figures` (extra `figures`) styles matplotlib for figures inserted in a
|
|
261
|
+
LaTeX document: sizes in centimetres, LaTeX fonts and preamble, a decimal comma that
|
|
262
|
+
does not touch the locale, insets, and cropping to the ink.
|
|
263
|
+
|
|
264
|
+
```python
|
|
265
|
+
import matplotlib.pyplot as plt
|
|
266
|
+
import numpy as np
|
|
267
|
+
from texformules.figures import apply_style, save_figure, style_axes
|
|
268
|
+
|
|
269
|
+
apply_style(8, 6) # 8 cm by 6 cm, before creating the figure
|
|
270
|
+
x = np.linspace(-4, 4, 500)
|
|
271
|
+
fig, ax = plt.subplots()
|
|
272
|
+
ax.plot(x, np.sinc(x) ** 2)
|
|
273
|
+
ax.set_xlabel(r"$\theta$ (\unit{\radian})") # siunitx is in the preamble
|
|
274
|
+
style_axes(ax) # grey spines, outward ticks, 0,5 and ×10⁵
|
|
275
|
+
save_figure(fig, "slit.pdf") # saved, then cropped by pdfcrop
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
`apply_style` changes `rcParams` for every figure to come, `restore_style()` undoes it,
|
|
279
|
+
and `style_params(...)` returns the same settings for `plt.rc_context`. The figures
|
|
280
|
+
came from the `latex_figures` package; its names (`latexify`, `format_axes`,
|
|
281
|
+
`save_fig`, `restaurer`, `ScalarFormatterVirgule`…) still work, as deprecated aliases
|
|
282
|
+
listed in DOC.md.
|
|
283
|
+
|
|
284
|
+
## Limits
|
|
285
|
+
|
|
286
|
+
- One formula is one line of the batch document: display environments that need
|
|
287
|
+
several paragraphs (`align` outside math…) are not supported; `$$…$$` and `\[…\]`
|
|
288
|
+
are set inline in `\displaystyle`.
|
|
289
|
+
- Commands that would affect the other formulas of the batch — definitions, file
|
|
290
|
+
input and output, catcode changes, the `document` environment — are refused inside
|
|
291
|
+
a formula. Define your macros in the preamble.
|
|
292
|
+
- Only an undefined command is located inside a rejected formula; for other errors,
|
|
293
|
+
the message is all TeX gives.
|
|
294
|
+
- Each one-page PDF embeds the fonts subset for its whole batch: on its own it is
|
|
295
|
+
heavier than its PNG (about 15 kB against 6 kB); it pays off when the document
|
|
296
|
+
embeds each font stream once.
|
|
297
|
+
- latexdetok's messages are in English; for French, call
|
|
298
|
+
`latexdetok.set_language("fr")` or set `LATEXDETOK_LANG=fr`.
|
|
299
|
+
|
|
300
|
+
## Development
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
uv sync --group dev
|
|
304
|
+
uv run ruff format src tests examples
|
|
305
|
+
uv run ruff check src tests examples
|
|
306
|
+
uv run mypy
|
|
307
|
+
uv run pytest -q # the `latex` tests are skipped without TeX
|
|
308
|
+
uv run pytest -q -m latex # only those that compile
|
|
309
|
+
uv build
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
The version is `texformules.__version__`; a GitHub release tagged `v<version>`
|
|
313
|
+
publishes to PyPI through trusted publishing.
|
|
314
|
+
|
|
315
|
+
## License
|
|
316
|
+
|
|
317
|
+
MIT, see [LICENSE](https://github.com/antnardo/texformules/blob/main/LICENSE).
|