Skip to main content

dartwork-mpl

PyPI version Python versions License: MIT CI Docs

Publication-quality matplotlib — a thin utility layer, not a wrapper.

dartwork-mpl keeps Figure / Axes 100% native and adds the parts matplotlib makes tedious: a physical-width geometry API, curated style presets, an OKLCH-aware color system, deterministic content-aware layout, visual validation, and a first-class integration for AI coding assistants (an MCP server + a bundled prompt corpus). You never learn a new plotting API — you keep writing matplotlib, just without the friction.

import matplotlib.pyplot as plt
import dartwork_mpl as dm

dm.style.use("scientific")                                       # 1. curated preset
fig, ax = plt.subplots(figsize=dm.figsize("13cm", "standard"))   # 2. physical width × aspect
ax.plot(x, y, color="oc.blue5", lw=dm.lw(0))
ax.set_xlabel("Time [s]")
dm.simple_layout(fig)                                            # 3. content-aware margins
dm.save_formats(fig, "figure", formats=("svg", "png", "pdf"))    # 4. multi-format save

That four-step pattern — preset → figsize(width, aspect) → simple_layout → save_formats — is the whole workflow. No tight_layout(), no hand-tuned figsize=(w, h) arithmetic, no dpi= guesswork.


Installation

pip install dartwork-mpl        # or:  uv add dartwork-mpl

Requires Python 3.10+. The core install is intentionally lean; add an extra only when you need it:

Extra Enables Pulls in
[notebook] dm.show() inline SVG display in Jupyter ipython
[mcp] the MCP server for AI assistants fastmcp, httpx
[ui] the interactive parameter viewer fastapi, uvicorn
pip install "dartwork-mpl[notebook]"   # or [mcp], [ui]

Highlights

  • Geometry, decoupled from inches. dm.figsize("13cm", "standard") takes a physical width (cm / in / mm / pt, or dm.col1 = 9 cm / dm.col2 = 17 cm) and one of ten aspect tokens (square / portrait / tall / standard / golden / wide / a4 / slide / cinema / panoramic); the height follows. Bare numbers are rejected so the unit is always explicit.
  • Deterministic layout. simple_layout(fig) measures every visible artist and places the GridSpec arithmetically — reproducible across machines, unlike tight_layout()'s heuristics. margin="2%" (or dm.mm(2)) adds a buffer.
  • OKLCH-aware color. Named palettes (oc.* Open Color, tw.* Tailwind, md.*, ad.*, cu.*, pr.*) plus a Color class spanning OKLab / OKLCH / RGB / hex with perceptual interpolation (cspace) and gamut-correct mapping.
  • Curated styling. Seven presets (scientific, report, presentation, …), each with a Korean -kr variant, and preset-relative scaling helpers fs / fw / lw so literals never drift when you switch themes.
  • Validation & export. validate_figure(fig) flags overflow, text/legend overlap, tick crowding, and empty axes — invisible failures in headless agent pipelines. save_formats(fig, ...) writes SVG / PNG / PDF / EPS at once, with deterministic SVG/PDF/SVGZ output for unchanged figures.
  • AI-native. A bundled MCP server exposes lint + auto-fix, figure validation, color lookup, and the live policy corpus to Claude Code / Cursor / Windsurf. No-MCP agents read the same corpus from disk.
  • Batteries included. Material Design Icons + Font Awesome 6 fonts, ready-made plot templates (plot_diverging_bar, …), and a FastAPI viewer for live tuning.

Core API at a glance

import dartwork_mpl as dm

# ── Geometry ──────────────────────────────────────────────────────────
dm.figsize("13cm", "wide")          # width × aspect token  → inch tuple
dm.figsize("13cm", 0.6)             # ...or a numeric ratio / "8cm" / dm.cm(8)
dm.cm(13); dm.mm(170); dm.inch(4.6); dm.pt(24)   # Length values
dm.col1; dm.col2                    # 9 cm / 17 cm academic-column sugar

# ── Styling & scaling ─────────────────────────────────────────────────
dm.style.use("scientific")          # apply a preset
dm.style.stack(["base", "font-scientific", "lang-kr"])   # compose
dm.fs(2); dm.fw(1); dm.lw(-0.3)     # preset-relative font size / weight / line width

# ── Color ─────────────────────────────────────────────────────────────
ax.plot(x, y, color="oc.blue5")     # named palettes register with matplotlib
dm.color("oc.blue5")                # parse name / "#4285F4" / "rgb(...)" / "oklch(...)"
dm.oklch(0.7, 0.15, 150); dm.rgb(66, 133, 244); dm.hex("#4285F4")
dm.cspace("#FF0000", "#0000FF", n=5, space="oklch")      # perceptual interpolation
dm.mix_colors("oc.blue5", "white", alpha=0.35)

# ── Layout & annotation ───────────────────────────────────────────────
dm.simple_layout(fig)               # deterministic content-aware margins
dm.simple_layout(fig, margin="2%", gs=gs)   # buffer + target a GridSpec
dm.label_axes(axes)                 # (a) (b) (c) panel labels
dm.arrow_axis(ax, "x", "Cost")      # Low ◄── Cost ──► High

# ── Validate, export, icons ───────────────────────────────────────────
dm.validate_figure(fig)             # overflow / overlap / tick-crowding / empty
dm.save_formats(fig, "fig", formats=("png", "svg", "pdf"), dpi=300)
mdi = dm.icon_font("mdi")           # also "fa-solid" / "fa-regular" / "fa-brands"

# ── Plot templates ────────────────────────────────────────────────────
from dartwork_mpl.templates import plot_diverging_bar
fig, ax = plot_diverging_bar(labels=["A", "B"], neg_values=[-30, -15], pos_values=[40, 55])

See the usage guide and API reference for the full surface.


Common pitfalls

Three patterns trip up new users (and AI assistants) more than any others. The built-in lint engine flags all three; dm.migrate_legacy_code rewrites them in place.

Pitfall Why it's wrong Use instead
plt.subplots(figsize=(8, 5)) (raw inch tuple) dartwork-mpl's geometry is physical (cm/mm) and aspect-driven; raw tuples bypass the preset's typography pairing plt.subplots(figsize=dm.figsize("13cm", "standard"))
plt.tight_layout() / fig.tight_layout() Non-deterministic outer-margin solver; fights with simple_layout's GridSpec arithmetic dm.simple_layout(fig)
ax.set_title("…", fontsize=14) (raw font literal) Becomes wrong the moment you switch from scientific to presentation or a *-kr preset ax.set_title("…", fontsize=dm.fs(0)) (same for dm.lw(n), dm.fw(n))

Full catalog: 02-anti-patterns.yaml. Reachable at runtime via dm.get_prompt("02-anti-patterns") or lint_dartwork_mpl_code(code) over MCP.

Upgrading from v4? See the Migration Guide for the palette codemod and removed-name map.


Style presets

Preset Use case
scientific Compact fonts for academic papers and journals
report Reports and dashboards, cleaner spines
minimal Tufte-style, data-ink focus — no spines or ticks
presentation Large fonts for projected slides
poster Extra-large fonts and thick lines for posters
web On-screen readability for docs and notebooks
dark Dark backgrounds for Jupyter and dark-mode slides

Each has a Korean -kr variant (scientific-kr, report-kr, …) with Korean-aware fonts. List them with dm.list_styles().


AI-assisted development (MCP)

dartwork-mpl ships a built-in Model Context Protocol server so AI coding assistants pull the current policy guides, color palettes, lint catalog, and helper tools straight into the chat — no copy-pasting docs. It exposes 16 tools (lint + auto-fix, figure validation, render, color lookup, info, chart-type recommender, layered-plot composer, advanced-tier render), 10 resources + 4 resource templates (the prompt corpus + 18 basic + 18 tier-2 advanced plot templates), and 2 prompts.

pip install "dartwork-mpl[mcp]"     # installs fastmcp + httpx; adds the dartwork-mpl-mcp script

Point your client at the dartwork-mpl-mcp console script — e.g. Claude Code (~/.claude.json) or Cursor (~/.cursor/mcp.json):

{
  "mcpServers": {
    "dartwork-mpl": { "command": "dartwork-mpl-mcp" }
  }
}

Restart the client and ask it to list its MCP resources to confirm. Windsurf, Antigravity, generic stdio setups, the full tool/resource catalog, and the local-clone variant are covered in docs/integrations/mcp_server.md.

No MCP? The same corpus is bundled in the wheel and reachable from Python — dm.get_agent_doc("llms-full") (also "AGENTS", "CLAUDE", "llms") returns the text, dm.agent_doc_path(name) its path. The repo-root CLAUDE.md / AGENTS.md / llms.txt (per the llmstxt.org spec) are the 30-second onboarding.


Documentation

📚 Full documentation


Project layout

src/dartwork_mpl/
├── units.py / scale.py        # figsize, cm/mm/inch/pt, col1/col2 · fs/fw/lw
├── style.py                   # Style class + preset management
├── colors/                    # Color (OKLab/OKLCH/RGB/hex) + named palettes
├── layout.py / annotation.py  # simple_layout, label_axes, arrow_axis
├── validate.py / lint.py      # validate_figure · lint + migrate_legacy_code
├── io.py / formatting.py      # save_formats, show · format_axis_*
├── icon.py / font.py / cmap.py / diagnostics/   # fonts, colormaps, viz helpers
├── templates/ / helpers/      # plot templates · high-level composition helpers
├── agent.py / prompt.py       # bundled LLM corpus · prompt guides
├── mcp/                       # MCP server (server / resources / tools / prompts)
├── ui/                        # interactive FastAPI viewer
└── asset/                     # bundled styles, colors, fonts, icons, prompts

Contributing & issues

Bug reports and feature requests go to the GitHub issue tracker. Released under the MIT License.

Metadata

Release files for dartwork-mpl 0.5.6

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

Source distribution (sdist)

Source distribution for dartwork-mpl 0.5.6
File Size Uploaded Provenance
dartwork_mpl-0.5.6.tar.gz 60.9 MB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for dartwork-mpl 0.5.6
File Interpreter ABI Platform
dartwork_mpl-0.5.6-py3-none-any.whl Python 3 none any Details

Total release size: 122.0 MB

Release files / dartwork_mpl-0.5.6.tar.gz

Download URL dartwork_mpl-0.5.6.tar.gz
Size 60.9 MB
Tags Source
SHA-256 checksum
How to use checksums
a676f6142efebbfb4dff3cf53720b285ce89db8842ed5578133af9cc1cb30d66
BLAKE2b-256 checksum
How to use checksums
0945d243d6976a8371c578d7042ef7fc3f08cdb31219beb540b44bdeae64c1c2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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 Jul 5, 2026.

Transparency log

Release files / dartwork_mpl-0.5.6-py3-none-any.whl

Download URL dartwork_mpl-0.5.6-py3-none-any.whl
Size 61.1 MB
Tags Python 3
SHA-256 checksum
How to use checksums
5e0df5c07cb9ba40a0c38b37ed1b60d42ce7c7be0efe48339dd7b2271b495916
BLAKE2b-256 checksum
How to use checksums
8b589feb782f7afb804c72e86e80dfd03e7521f670b7714f09c7639f3296aa88
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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 Jul 5, 2026.

Transparency log

Security for dartwork-mpl 0.5.6

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for dartwork_mpl-0.5.6.tar.gz

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 Jul 5, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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