Skip to main content

mosaickit

mosaickit

PyPI Python License Tests

A domain-neutral toolkit for assembling two-dimensional diagrams from reusable scenes, layers, styles, parameters, and renderers.

Domain libraries define their own models and semantic roles; MosaicKit composes their visual layers and renders the result. It knows nothing about any domain and does not depend on a model package or a curve-fitting library.

Installation

Add MosaicKit to a project with uv:

uv add mosaickit

A plain pip install mosaickit also works. MosaicKit supports Python 3.10–3.13.

Python API

from mosaickit import (
    Canvas,
    Fill,
    FillLayer,
    MarkerLayer,
    PathLayer,
    Stroke,
    TextLayer,
    quadrant_axes,
)

canvas = Canvas().extend(quadrant_axes(10, 10))
canvas.add(
    FillLayer(
        [(1, 1), (1, 7), (8, 1)],
        fill=Fill(color="#377EB8", opacity=0.12),
        z_index=-1,
    )
)
canvas.add(
    PathLayer(
        [(1, 8), (2, 5), (4, 3), (7, 1.5), (9, 1)],
        stroke=Stroke(color="#984EA3", width=2),
        id="curve",
    )
)
canvas.add(MarkerLayer([(4, 3)], id="point"))
canvas.add(TextLayer((4, 3), "A", offset=(8, 8)))
canvas.save("diagram.svg")

Canvas.add(), extend(), remove(), and clear() are fluent builder operations. snapshot() returns an immutable Scene; copy() and bind() produce a new canvas without changing the original. Public layers never contain Matplotlib artists, and importing mosaickit does not import Matplotlib.

Scenes and layers

The scene graph is deliberately small:

  • PathLayer joins ordered finite (x, y) coordinates with straight segments.
  • FillLayer describes filled regions.
  • MarkerLayer, TextLayer, and ArrowLayer add annotations.
  • LegendLayer builds legends from stable layer IDs.
  • GroupLayer groups layers without adding renderer-specific state.

AxisSpec and build_axes() construct axes from the same ordinary path and text layers. quadrant_axes(), crosshair_axes(), and box_frame() cover common layouts. CanvasSpec owns ranges, physical size, DPI, labels, and title.

Curve construction and TikZ export intentionally live outside MosaicKit. Domain packages can call a geometry package such as BezierKit directly, then pass the resulting coordinates or renderer-specific output to their own export pipeline.

Styles and themes

from mosaickit import Config, Stroke, StyleBundle, Theme, use_config

paper = Theme(
    "paper",
    {"mypkg.boundary": StyleBundle(stroke=Stroke(color="#984EA3", width=2))},
)

with use_config(Config(theme=paper)):
    canvas = Canvas()

Style resolution proceeds from layer style to canvas role override, configuration role override, theme, and finally primitive defaults. A field set to None inherits; falsey values such as opacity=0, width=0, and LegendStyle(visible=False) remain explicit overrides.

Domain packages register dotted role names through ThemeRegistry. Typed RolePack dataclasses and expand_roles() let those packages author themes without making MosaicKit import their domain types.

Configuration can also be loaded from TOML:

[canvas]
x_range = [0, 20]
dpi = 150

[styles."mypkg.boundary".stroke]
color = "#984EA3"
width = 2
dash = "dashed"

Use Config.load(path) to validate it. Runtime defaults are isolated with contextvars, while explicit constructor arguments always take precedence.

Grids, parameters, and animation

from mosaickit import Animation, Canvas, CanvasGrid, Parameter, TextLayer

position = Parameter("position", value_type=float)
template = Canvas().add(TextLayer((position, 5), "moving"))
values = position.values([1.0, 3.0, 5.0])

CanvasGrid.sweep(template, values, cols=3).save("sweep.svg")
Animation.sweep(template, values, fps=2).save("sweep.gif")

CanvasGrid accepts flat canvases, nested rows, None cells, and Span(canvas, rows=..., cols=...). A flat list infers a roughly square grid; explicit rows and cols may leave trailing cells empty.

Parameters and expressions support arithmetic, ordered comparisons, partial binding, and stable structural equality. Animation.frames() yields backend-neutral scenes. GIF output uses Pillow; MP4 output requires ffmpeg.

Rendering

PNG, SVG, and PDF use the built-in Matplotlib renderer:

result = canvas.render()
try:
    result.show()
finally:
    result.close()

canvas.save() closes its temporary render result automatically. The public Renderer protocol and RendererRegistry allow other backends without placing backend state in the scene graph. Render plans and contexts remain private while the built-in backends evolve.

Each render, grid, or animation job owns its cache. Pass an explicit RenderCache to reuse work across jobs. Non-hashable models bypass caching and emit one warning per model type and cache.

Scope

MosaicKit owns domain-neutral scene composition, styles, themes, parameter binding, grid layout, animation frames, renderer contracts, and static/animated output. Domain semantics belong to the packages that build on it. Mathematical curve construction and native TikZ path generation belong to geometry packages such as BezierKit.

Development

uv sync --locked
uv run pre-commit install
uv run pytest
uv run ruff check .
uv run ruff format --check .
uv run mypy
uv run lint-imports
uv build

The lockfile pins all development dependencies.

Metadata

Release files for mosaickit 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mosaickit 0.2.0
File Size Uploaded
mosaickit-0.2.0.tar.gz 205.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mosaickit 0.2.0
File Interpreter ABI Platform
mosaickit-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 269.5 kB

Release files / mosaickit-0.2.0.tar.gz

Download URL mosaickit-0.2.0.tar.gz
Size 205.6 kB
Tags Source
SHA-256 checksum
How to use checksums
dec751168969dc328a7c7b5312c48fa9ff56e335e70feefaf8ebd296f79123f2
BLAKE2b-256 checksum
How to use checksums
a8c314ba62b15a17d06e13185e8ca43cdfb6aea22295084215b33a01d77efb64
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.

Transparency log

Release files / mosaickit-0.2.0-py3-none-any.whl

Download URL mosaickit-0.2.0-py3-none-any.whl
Size 63.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b5f8abb474fe2e18e9bb3f695fab18c0da39dccc38fbf5c7cb4d03959e61d751
BLAKE2b-256 checksum
How to use checksums
d81f86bfc6b5b75ace2c123b20bdf11057b3c43626221e2a01f8ce27a54690ce
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.

Transparency log

Release history Release notifications | RSS feed

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page