Skip to main content

Enhanced matplotlib styling, color management, and utility library for publication-quality figures

Project description

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_layoutsave_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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dartwork_mpl-0.5.6.tar.gz (60.9 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dartwork_mpl-0.5.6-py3-none-any.whl (61.1 MB view details)

Uploaded Python 3

File details

Details for the file dartwork_mpl-0.5.6.tar.gz.

File metadata

  • Download URL: dartwork_mpl-0.5.6.tar.gz
  • Upload date:
  • Size: 60.9 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dartwork_mpl-0.5.6.tar.gz
Algorithm Hash digest
SHA256 a676f6142efebbfb4dff3cf53720b285ce89db8842ed5578133af9cc1cb30d66
MD5 3a10855b40d3de8ac3f0663f9fb98866
BLAKE2b-256 0945d243d6976a8371c578d7042ef7fc3f08cdb31219beb540b44bdeae64c1c2

See more details on using hashes here.

Provenance

The following attestation bundles were made for dartwork_mpl-0.5.6.tar.gz:

Publisher: release.yml on dartworklabs/dartwork-mpl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dartwork_mpl-0.5.6-py3-none-any.whl.

File metadata

  • Download URL: dartwork_mpl-0.5.6-py3-none-any.whl
  • Upload date:
  • Size: 61.1 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dartwork_mpl-0.5.6-py3-none-any.whl
Algorithm Hash digest
SHA256 5e0df5c07cb9ba40a0c38b37ed1b60d42ce7c7be0efe48339dd7b2271b495916
MD5 120c61c4ce141011c50b77a87c62ed6b
BLAKE2b-256 8b589feb782f7afb804c72e86e80dfd03e7521f670b7714f09c7639f3296aa88

See more details on using hashes here.

Provenance

The following attestation bundles were made for dartwork_mpl-0.5.6-py3-none-any.whl:

Publisher: release.yml on dartworklabs/dartwork-mpl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page