Metadata-Version: 2.4
Name: py-probelab
Version: 0.1.0
Summary: Shared ProbeLab utilities
Project-URL: Homepage, https://probelab.io
Project-URL: Source, https://github.com/probe-lab/py-probelab
Author-email: ProbeLab <dennis@probelab.io>
License-Expression: MIT AND OFL-1.1
License-File: LICENSE
License-File: src/probelab/plot/assets/fonts/OFL.txt
Keywords: matplotlib,probelab,style,visualization
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: Matplotlib
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering :: Visualization
Requires-Python: >=3.14
Requires-Dist: matplotlib>=3.11.1
Requires-Dist: numpy>=2.5.1
Requires-Dist: pillow>=12.3
Description-Content-Type: text/markdown

# py-probelab

Shared ProbeLab utilities. Install as `py-probelab`, import as `probelab`.

```bash
uv add py-probelab
# or: pip install py-probelab
```

Today this is brand colors and matplotlib styling, so every chart we publish
looks like it came from the same place. More common utilities will land here
over time.

## Charts

```python
import matplotlib.pyplot as plt
import numpy as np
import probelab.plot as pplot

pplot.use()

fig, ax = plt.subplots()
ax.plot(np.arange(100), np.random.randn(100).cumsum(), label="dht")
ax.set_title("Lookup latency")
ax.set_xlabel("time")
ax.legend()

pplot.watermark(fig, loc="lower right")
fig.savefig("latency.png")
```

`use()` applies the theme globally for the rest of the process. Inside library
code, or when you only want it for one figure, use the context manager instead
so the caller's session is left alone:

```python
with pplot.style():
    fig, ax = plt.subplots()
    ...
```

Importing `probelab.plot` registers the theme with matplotlib itself, so you can
skip the helpers entirely and compose it with any other style:

```python
import probelab.plot  # noqa: F401  - registers the style

plt.style.use("probelab-dark")
plt.style.use(["probelab-dark", "seaborn-v0_8-poster"])
```

### Watermark

```python
pplot.watermark(fig)                      # centered, faint
pplot.watermark(ax, loc="upper right")    # per-panel
pplot.watermark(fig, alpha=0.2, zoom=0.1) # more visible, smaller
```

Pass a `Figure` to place the mark in figure coordinates (usually what you want
for a multi-panel chart) or an `Axes` to place it within one panel. Positions
are `center`, `upper left`, `upper right`, `lower left`, `lower right`.

## Colors

`probelab.colors` has no third-party imports, so it is safe to use from
dashboards, reports and terminal output as well as from plotting code:

```python
from probelab import colors

colors.PALETTE           # the 9 categorical series colors, in cycle order
colors.categorical(4)    # first 4 of them
colors.PRIMARY           # "#FFD7C5" - titles, axis labels
colors.BASE_100          # page/figure background
```

## Fonts

The package vendors eight static DM Sans weights and registers them with
matplotlib on first use, so charts render identically on a laptop and in CI
without anyone installing fonts system-wide.

```python
pplot.fonts_available()   # False means charts fell back to a system sans
pplot.use(fonts=False)    # prefer a system-wide DM Sans instead
```

## Development

```bash
uv sync
uv run pytest
uv build
```

### Changing the theme

`src/probelab/plot/styles/probelab-dark.mplstyle` is the source of truth for the
theme; `src/probelab/colors.py` mirrors its color tokens for non-matplotlib
consumers. A test asserts the two agree, so change them together.

Two things to know about editing `.mplstyle` files:

- Hex colors are written **without** a leading `#`, because `#` starts a comment
  there. `figure.facecolor: 2e3438`, not `#2e3438` - the latter silently parses
  as an empty value and raises on load.
- Font weights must match a weight the vendored family actually declares, or
  matplotlib logs a `findfont` warning on every render. DM Sans ExtraLight
  declares 250, not 200.

## Licensing

The code is MIT. The bundled DM Sans family is redistributed under the SIL Open
Font License 1.1 (`src/probelab/plot/assets/fonts/OFL.txt`).
