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

Enhanced matplotlib styling, color management, and utility library engineered by dartwork.

dartwork-mpl is a utility collection designed to elevate matplotlib visuals to publication-level elegance. Instead of wrapping matplotlib with a new API layer, it provides thin utilities that enhance matplotlib's native capabilities while keeping you in full control.

[!TIP] AI coding assistants: read CLAUDE.md (or AGENTS.md) at the repo root for the 30-second onboarding. The link index follows the llmstxt.org spec at llms.txt; a single-file concatenated dump is at llms-full.txt.

[!IMPORTANT] Migrating from earlier dartwork-mpl? Both the 0.3 names (dm.SW/MW/TW/DW, dm.FS_*, dm.WIDTHS, dm.cm2in, dm.agent_utils, dm.xplot) and the 0.4-era figure constructors (dm.subplots, dm.figure) have been removed. Each old access path now raises AttributeError / ModuleNotFoundError / TypeError with a message naming the new API. The canonical pattern is plt.subplots(figsize=dm.figsize("<n>cm", "<aspect>")) paired with a separate dm.style.use(...). See docs/migration.md and the CHANGELOG for the full mapping.


Features

  • Style Presets: Apply curated themes (scientific, report, presentation) with one call.
  • Width × Aspect Geometry: plt.subplots(figsize=dm.figsize("13cm", "standard")) — pick a physical width (cm/in/mm) and one of six aspect tokens (square / portrait / standard / golden / wide / cinema); height is derived. No more raw figsize=(w, h) math.
  • Advanced Color System: Named color palettes (oc.*, tw.*, md.*, ad.*, cu.*, pr.*) plus a Color class supporting OKLab / OKLCH / RGB / hex color spaces with perceptual interpolation via cspace().
  • Smart Layout: simple_layout(fig) is a deterministic, content-aware margin pass that measures every visible artist and places the GridSpec arithmetically. Default margin=0 snaps content flush to figure edges; margin="2%" / dm.mm(2) adds a buffer. Replaces tight_layout().
  • Scaling Helpers: Relative font size (fs), font weight (fw), and line width (lw) that respect the active style preset.
  • Icon Fonts: Built-in Material Design Icons (7,448+) and Font Awesome 6.
  • Visual Validation: Automatic detection of overflow, text overlap, legend overflow, tick crowding, and empty axes via validate_figure().
  • Extended Plots: Ready-to-use plot templates like plot_diverging_bar().
  • Interactive Viewer: FastAPI-powered web UI (dartwork_mpl.ui) for real-time parameter tuning.
  • Multi-format Export: Save figures in SVG, PNG, PDF, and EPS simultaneously.
  • Prompt System: Bundled prompt guides for AI coding assistants, with get_prompt() and copy_prompt().
  • MCP Server: AI coding assistant integration via Model Context Protocol (12 resources + 3 resource templates / 13 tools / 2 prompts).
  • LLM Integration: Install usage guides for 9 AI tools (Claude Code, Cursor + MDC rules, GitHub Copilot, Codex CLI / AGENTS.md, Gemini CLI / Antigravity, Continue, Aider, Windsurf) with install_llm_txt(targets="all").

Getting Started

Installation

Using uv (Recommended)

# Add to your project
uv add git+https://github.com/dartworklabs/dartwork-mpl

# Or install directly
uv pip install git+https://github.com/dartworklabs/dartwork-mpl

Using pip

pip install git+https://github.com/dartworklabs/dartwork-mpl

Quick Start

import matplotlib.pyplot as plt

import dartwork_mpl as dm

dm.style.use('scientific')

# Pick the physical width (cm/in/mm) and an aspect token. Height
# follows from aspect, so you never hand-tune figsize.
fig, ax = plt.subplots(figsize=dm.figsize('13cm', 'standard'))
ax.plot(x, y, color='oc.blue5', lw=dm.lw(0))
ax.set_xlabel('Time [s]')

dm.simple_layout(fig)
dm.save_formats(fig, 'output/figure', formats=('svg', 'png'))

dm.figsize(width, aspect) returns the inch tuple matplotlib's figsize= expects. width accepts unit-suffixed strings ("13cm", "6.7in", "170mm", "24pt") or Length values from the helper calls (dm.cm(11.3), dm.inch(4.6), dm.mm(170), dm.pt(24)); the academic-column shortcuts dm.col1 (9 cm) and dm.col2 (17 cm) work too. Bare int / float are rejected so the unit is always explicit.

The second argument is polymorphic — pick whichever form reads naturally for the call site (the four forms are equivalent for fixed dimensions; the first matching form wins):

dm.figsize("13cm", "wide")        # aspect token  → 13 × 8.67 cm
dm.figsize("13cm", 0.6)           # numeric ratio → 13 ×  7.8 cm
dm.figsize("13cm", "8cm")         # unit-string height
dm.figsize("13cm", dm.cm(8))      # Length height
dm.figsize("13cm", "5in")         # mixed units (height in inches)

Aspect tokens are square / portrait / standard / golden / wide / cinema. Bare numeric strings ("0.5") are rejected with a "drop the quotes" hint to keep the API unambiguous.


Core Modules

Style Management

Ready-to-use presets with style.use(), or stack individual styles for fine-grained control with style.stack().

dm.style.use('scientific')                     # apply preset
dm.style.stack(['base', 'font-scientific', 'lang-kr'])  # stack custom
dm.list_styles()                               # list available .mplstyle files
dm.load_style_dict('font-presentation')        # inspect style params

Color System

Named Colors

Importing dartwork_mpl registers palettes with oc.*, tw.*, md.*, ad.*, cu.*, pr.* prefixes:

ax.plot(x, y, color='oc.blue5')       # Open Color
ax.bar(x, y, color='tw.emerald500')   # Tailwind CSS
lighter = dm.mix_colors('oc.blue5', 'white', alpha=0.35)
muted = dm.pseudo_alpha('oc.blue7', alpha=0.6)

Color Class

The Color class provides perceptually uniform color manipulation across OKLab, OKLCH, RGB, and hex:

# Create from any color space
color = dm.oklch(0.7, 0.15, 150)      # L, C, h (degrees)
color = dm.rgb(66, 133, 244)          # auto-detects 0-255 range
color = dm.hex('#4285F4')
color = dm.named('oc.blue5')

# Read/write via views (mutable references)
color.oklch.C *= 1.2                  # boost chroma
r, g, b = color.rgb                   # unpack RGB

# Perceptual interpolation
palette = dm.cspace('#FF0000', '#0000FF', n=5, space='oklch')

Layout & Annotation

dm.simple_layout(fig)                   # deterministic content-aware margin pass
dm.simple_layout(fig, margin="2%")      # uniform 2% buffer; also dm.mm(2), dm.cm(0.5), "5mm"
dm.simple_layout(fig, gs=gs)            # multi-panel: target a specific GridSpec
dm.label_axes(axes)                     # add (a), (b), (c) panel labels
dm.arrow_axis(ax, 'x', 'Cost')         # Low ◄── Cost ──► High
dm.set_decimal(ax, xn=2, yn=1)         # format tick decimals
offset = dm.make_offset(4, -4, fig)    # point-based translation

Scaling Helpers

dm.fs(2)     # base font size + 2pt
dm.fw(1)     # base font weight + 100
dm.lw(-0.3)  # base line width - 0.3

Length Helpers

dm.cm(13)        # 13 cm  → Length
dm.inch(4.6)     # 4.6 in → Length
dm.mm(170)       # 170 mm → Length
dm.pt(24)        # 24 pt  → Length (1 pt = 1/72 in)
dm.length('13cm')  # parse a unit string → Length
dm.col1          # 9 cm  — academic single-column sugar
dm.col2          # 17 cm — academic two-column sugar

# Multi-unit views (Color-style):
dm.cm(13).inch   # 5.118
dm.cm(13).mm     # 130.0
dm.cm(13).pt     # 368.5

Migrating? Replace figsize=(dm.cm2in(13), dm.cm2in(9.75)) and dm.subplots(width="13cm", aspect="standard") with plt.subplots(figsize=dm.figsize("13cm", "standard")). The legacy aliases (SW / MW / TW / DW, FS_*, cm2in, agent_utils, xplot, dm.subplots, dm.figure) all raise at access time now.

Visual Validation

Automatic detection of rendering issues invisible in stdout-only environments (e.g., AI agent pipelines):

warnings = dm.validate_figure(fig)
# Checks: overflow, overlap, legend_overflow, tick_crowding, empty_axes
# Integrated into save_formats() by default

Icon Font System

mdi = dm.icon_font('mdi')              # Material Design Icons
fa  = dm.icon_font('fa-solid')         # Font Awesome 6 Solid
ax.text(0.5, 0.5, "\U000F050F", fontproperties=mdi, fontsize=20)
dm.list_icon_fonts()                   # ['fa-brands', 'fa-regular', 'fa-solid', 'mdi']

File I/O & Prompts

dm.save_formats(fig, 'output/fig', formats=('png', 'svg', 'pdf'), dpi=300)
dm.save_and_show(fig, size=720)        # save + inline preview

# Prompt guides for AI assistants
dm.list_prompts()                      # available guides
dm.get_prompt('00-index')              # read the entry-point index (0.4 SSOT)
dm.copy_prompt('01-policy', '.cursor/rules/')

Extended Plots (templates)

Ready-to-use specialized visualization templates:

from dartwork_mpl.templates import plot_diverging_bar

fig, ax = plot_diverging_bar(
    categories=['A', 'B', 'C'],
    negatives=[-30, -15, -25],
    positives=[40, 55, 35],
)

Interactive Viewer (UI)

FastAPI-powered web UI for real-time parameter tuning:

from dartwork_mpl.ui import ParamModel, run
from pydantic import Field

class Params(ParamModel):
    n: int = Field(default=100, ge=10, le=1000)
    alpha: float = Field(default=0.5, ge=0, le=1)

def my_plot(params: Params):
    fig, ax = plt.subplots(figsize=dm.figsize("13cm", "standard"))
    ax.scatter(range(params.n), np.random.randn(params.n), alpha=params.alpha)
    return fig

run(my_plot)  # opens browser at localhost:8501

LLM Integration

dm.install_llm_txt()      # install usage guides to .claude/ and .cursor/
dm.uninstall_llm_txt()    # remove installed guides

Available Presets

Preset Description
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

All presets have a -kr Korean variant (e.g., scientific-kr, report-kr).


Documentation

📚 Full Documentation — Sphinx docs with:


AI-Assisted Development (MCP Server)

dartwork-mpl ships a built-in Model Context Protocol (MCP) server so that AI coding assistants — Claude Code, Cursor, Windsurf, Antigravity — can pull the latest policy guides, color palettes, lint catalog, and helper tools straight into the chat context. No copy-pasting docs.

Install

# pip
pip install "dartwork-mpl[mcp]"

# uv
uv add "dartwork-mpl[mcp]"

The [mcp] extra installs fastmcp (>=2.13.3,<4) and httpx. After install, the dartwork-mpl-mcp console script is on your PATH.

Claude Code

Add to ~/.claude.json (global) or <project>/.claude/mcp_servers.json:

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

Cursor

Add to ~/.cursor/mcp.json (global) or <project>/.cursor/mcp.json:

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

After saving, restart the client (or start a new conversation) and ask the assistant to list its MCP resources to confirm the server is reachable. For Windsurf, Antigravity (Gemini), generic stdio, troubleshooting, and the full resource/tool catalog, see docs/integrations/mcp_server.md (or the hosted version).

Working from a local clone instead of PyPI? Use command: "uv" with args: ["run", "--directory", "/abs/path/to/dartwork-mpl", "dartwork-mpl-mcp"]. The detailed docs cover this case.


Project Structure

src/dartwork_mpl/
├── __init__.py             # Public API exports + lazy 0.3 alias shim
├── py.typed                # PEP 561 type marker
├── units.py                # cm/inch/mm, col1/col2, figsize, parse_width/parse_aspect
├── style.py                # Style class + preset management
├── color/                  # Color class (OKLab/OKLCH/RGB/hex) + palettes
├── layout.py               # simple_layout(), label_axes()
├── annotation.py           # arrow_axis(), label_axes()
├── scale.py                # fs(), fw(), lw()
├── spines.py               # hide_spines(), add_grid(), minimal_axes()
├── formatting.py           # format_axis_*(), rotate_tick_labels()
├── io.py                   # save_formats(), save_and_show()
├── prompt.py               # get_prompt(), copy_prompt(), list_prompts()
├── validate.py             # validate_figure() — visual checks
├── validate_fixes.py       # validate_with_fixes() — auto-fix helpers
├── lint.py                 # lint() against the anti-pattern catalog
├── diagnostics.py          # plot_colormaps/plot_colors/plot_fonts
├── explore.py              # list_palettes/list_colormaps/show_palette
├── icon.py                 # Icon font system (MDI, Font Awesome)
├── font.py                 # Font registration (lazy, locked)
├── cmap.py                 # Custom colormap registration (lazy, locked)
├── helpers/                # Stable helper utilities (data, labels, …)
├── templates/              # Extended plot templates (plot_diverging_bar)
├── install.py              # LLM integration installer
├── cli.py                  # console-script entry (dartwork-mpl-mcp)
├── util.py                 # Legacy re-exports (deprecated cm2in, etc.)
├── constant.py             # Deprecated 0.3 width constants (SW/MW/TW/DW)
├── ui/                     # Interactive FastAPI viewer
├── mcp/                    # MCP server for AI assistants
│   ├── server.py           #   FastMCP instance + wiring
│   ├── resources.py        #   12 resources + 3 templates
│   ├── tools.py            #   13 tools (color, lint+autofix, validate+render, migrate, info)
│   └── prompts.py          #   2 prompts (create_plot, style_review)
└── asset/                  # Bundled styles, colors, fonts, icons, prompts

Reporting Issues

Encountered a bug or have a feature request? Please open an issue through our GitHub issue tracker.

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.4.1.tar.gz (28.8 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.4.1-py3-none-any.whl (28.9 MB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: dartwork_mpl-0.4.1.tar.gz
  • Upload date:
  • Size: 28.8 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.22 {"installer":{"name":"uv","version":"0.9.22","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for dartwork_mpl-0.4.1.tar.gz
Algorithm Hash digest
SHA256 2937c465875b4a7c33623b94e6f1db578f4303b735efc1532cfa01b229e8ab84
MD5 cc13fc7b85a12a16e4ad5d28b891b7b0
BLAKE2b-256 8692dea3ace9aa21a5fcf951619da16ef46cb9d1630866a44255c3cc4d2df9e6

See more details on using hashes here.

File details

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

File metadata

  • Download URL: dartwork_mpl-0.4.1-py3-none-any.whl
  • Upload date:
  • Size: 28.9 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.22 {"installer":{"name":"uv","version":"0.9.22","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for dartwork_mpl-0.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4ab5f5a6c25e455ee7cbb3a2786e5e2498c53c66d7e790db75312a04851b1205
MD5 ed2dc044ae3f5502c1b4495bece2a27b
BLAKE2b-256 8fc45dbb7ae736b264f19d6726d4a9c39c59c18afceb8772902d0e6bbb0eddf5

See more details on using hashes here.

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