Metadata-Version: 2.4
Name: mpl-tectonic
Version: 0.1.2
Summary: Opt-in Tectonic support for Matplotlib's usetex mode
Author: Anton Akhmerov
License-Expression: BSD-3-Clause
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Scientific/Engineering :: Visualization
Requires-Python: >=3.11
Requires-Dist: matplotlib<3.12,>=3.11
Description-Content-Type: text/markdown

# mpl-tectonic

`mpl-tectonic` makes Matplotlib's `text.usetex` pipeline use
[Tectonic](https://tectonic-typesetting.github.io/) instead of a traditional
`latex` executable. It is a small, opt-in compatibility layer for Matplotlib
3.11.

## Installation

Install the Python package together with its tightly constrained Matplotlib
dependency:

```console
python -m pip install mpl-tectonic
```

The `tectonic` executable is also required on `PATH`. It is an external runtime
dependency, not a Python package. This repository's Pixi environment installs
the validated Tectonic 0.17 release; the test suite also passes with Tectonic
0.15 and 0.16.

## Usage

Importing `mpl_tectonic` does not change Matplotlib. Call `enable()` once before
rendering any text with `usetex`:

```python
import matplotlib.pyplot as plt
import mpl_tectonic

mpl_tectonic.enable()

with plt.rc_context({"text.usetex": True}):
    fig, ax = plt.subplots()
    ax.set_xlabel(r"energy $E / \Delta$")
    ax.set_title(r"$E_n = \hbar\omega(n + \frac{1}{2})$")
    fig.savefig("figure.pdf")  # PNG and SVG work too.
```

`enable()` is idempotent. It validates Matplotlib and Tectonic before changing
anything, then installs the integration process-wide. The intentionally small
public runtime API contains only `mpl_tectonic.enable()`; there is no disable,
status, or context-manager API.

## How it works

Matplotlib 3.11 can read XeTeX's XDV format, but its `usetex` manager invokes
`latex` and expects a `.dvi` cache file. `mpl-tectonic` asks Tectonic for XDV,
places it in Matplotlib's TeX cache, and adapts the remaining private
integration points:

- Matplotlib's pdfLaTeX-only UTF-8 setup is adapted to XeTeX:
  `\DeclareUnicodeCharacter` declarations, such as Matplotlib's rendering of
  U+2212 as a math minus, take effect, and a character missing from its font is
  an error instead of being dropped;
- native fonts and classic TeX resources are materialized from Tectonic's
  bundle, keeping resource resolution consistent with the compiler; found
  resources are cached on disk and absent ones for the process, so each costs
  at most one Tectonic call;
- XDV native OpenType fonts use Matplotlib's TrueType PDF embedding path and
  safe PDF resource names;
- Matplotlib's opaque one-byte native-glyph failure is replaced with an
  actionable error.

Tectonic's diagnostics, such as the notes it prints while downloading fonts, do
not reach stderr. They are logged by the `mpl_tectonic` logger at debug level
and included in the error message when a Tectonic call fails.

SVG text is emitted as vector glyph paths. Native PDF output contains embedded,
subsetted fonts rather than converting an SVG or raster image.

## Compatibility and limitations

- Only Matplotlib `>=3.11,<3.12` is supported. The narrow range is deliberate:
  the package patches six private Matplotlib integration points.
- Activation is process-global and permanent. Call `enable()` during
  single-threaded application setup, before concurrent rendering begins.
- PNG, path-based SVG, and native PDF are supported.
- Every label must be valid TeX once `text.usetex` is enabled. For example,
  literal `e^2/h` must be written as `$e^2/h$`; the package intentionally does
  not rewrite project text.
- The ordinary research-figure PDF regime—ASCII prose plus TeX math
  commands—is supported. Literal or TeX-accented non-ASCII prose may select an
  XDV native-font glyph ID above 255, which Matplotlib 3.11's PDF renderer
  cannot encode. In that case `mpl-tectonic` raises an explicit error advising
  SVG output or supported TeX math commands. SVG remains the path-based
  fallback for such labels.
- Tectonic may need network access on its first run to obtain its default
  bundle, depending on how Tectonic was installed and cached.
- Every distinct label is one Tectonic compilation. Tectonic 0.16 contacts its
  bundle server on every call, which takes about 1.5 s even with a warm cache,
  so the first render of a figure with many labels is slow; Tectonic 0.15 and
  0.17 take about 0.1 s per label. Matplotlib's TeX cache makes later renders
  fast with any version.

## Development

The locked Pixi workflow builds both distributions, tests the installed
development package, inspects wheel and sdist contents, and installs and runs
the full output checks from each artifact:

```console
pixi run test
```

The same manifest also builds a noarch conda package with explicit Python,
Matplotlib, and Tectonic runtime dependencies:

```console
pixi run build-conda
```

The test task includes the local pre-commit suite: Ruff linting, a Ruff format
check, and codespell. To apply formatting or install the Git hook explicitly,
use:

```console
pixi run format
pixi run install-hooks
```

GitHub Actions runs the same workflow. Version tags matching `v*` trigger a
separate Trusted Publishing workflow: it builds once, tests those exact wheel
and sdist files, transfers them as one immutable Actions artifact, and publishes
without an API-token secret. The `pypi` environment must be configured for this
repository in PyPI before a release can succeed.

## License

BSD-3-Clause. See [LICENSE](LICENSE).
