Metadata-Version: 2.4
Name: dartwork-mpl
Version: 0.4.1
Summary: Enhanced matplotlib styling, color management, and utility library for publication-quality figures
Project-URL: Homepage, https://dartworklabs.github.io/dartwork-mpl/
Project-URL: Repository, https://github.com/dartworklabs/dartwork-mpl
Project-URL: Issues, https://github.com/dartworklabs/dartwork-mpl/issues
Project-URL: Changelog, https://github.com/dartworklabs/dartwork-mpl/blob/main/CHANGELOG.md
Author-email: Sangwon Lee <lsw91.main@gmail.com>, Wonjun Choi <wonjunn.choi@gmail.com>
License: MIT
License-File: LICENSE
Keywords: color,matplotlib,publication,styling,visualization
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: Matplotlib
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Classifier: Topic :: Scientific/Engineering :: Visualization
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: colorspacious>=1.1.2
Requires-Dist: ipython>=8.32.0
Requires-Dist: matplotlib>=3.10.1
Requires-Dist: numpy>=1.26
Requires-Dist: palettable>=3.3.3
Requires-Dist: pyyaml>=6.0
Requires-Dist: scipy>=1.15.2
Provides-Extra: mcp
Requires-Dist: fastmcp<4,>=2.13.3; extra == 'mcp'
Requires-Dist: httpx>=0.27.0; extra == 'mcp'
Provides-Extra: ui
Requires-Dist: fastapi>=0.110.0; extra == 'ui'
Requires-Dist: inquirerpy>=0.3.4; extra == 'ui'
Requires-Dist: pydantic>=2.0.0; extra == 'ui'
Requires-Dist: uvicorn[standard]>=0.27.0; extra == 'ui'
Description-Content-Type: text/markdown

# dartwork-mpl

[![PyPI version](https://img.shields.io/pypi/v/dartwork-mpl.svg)](https://pypi.org/project/dartwork-mpl/)
[![Python versions](https://img.shields.io/pypi/pyversions/dartwork-mpl.svg)](https://pypi.org/project/dartwork-mpl/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![CI](https://github.com/dartworklabs/dartwork-mpl/actions/workflows/ci.yml/badge.svg)](https://github.com/dartworklabs/dartwork-mpl/actions/workflows/ci.yml)
[![Docs](https://github.com/dartworklabs/dartwork-mpl/actions/workflows/docs.yml/badge.svg)](https://dartworklabs.github.io/dartwork-mpl/)

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`](CLAUDE.md) (or [`AGENTS.md`](AGENTS.md)) at the repo root for the 30-second onboarding. The link index follows the [llmstxt.org](https://llmstxt.org) spec at [`llms.txt`](llms.txt); a single-file concatenated dump is at [`llms-full.txt`](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`](docs/migration.md) and the [CHANGELOG](CHANGELOG.md) for the full mapping.

<br/>

## 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")`.

<br/>

## Getting Started

### Installation

#### Using uv (Recommended)

```shell
# 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

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

### Quick Start

```python
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):

```python
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.

<br/>

## Core Modules

### Style Management

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

```python
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:

```python
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:

```python
# 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

```python
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

```python
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

```python
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):

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

### Icon Font System

```python
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

```python
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:

```python
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:

```python
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

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

<br/>

## 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`).

<br/>

## Documentation

📚 **[Full Documentation](https://dartworklabs.github.io/dartwork-mpl/)** — Sphinx docs with:

- **[Installation](https://dartworklabs.github.io/dartwork-mpl/installation/index.html)** — Setup guide
- **[Design Philosophy](https://dartworklabs.github.io/dartwork-mpl/philosophy/index.html)** — Why thin utilities, not wrappers
- **[Usage Guide](https://dartworklabs.github.io/dartwork-mpl/usage_guide/index.html)** — Workflows and patterns
- **[Color System](https://dartworklabs.github.io/dartwork-mpl/color_system/index.html)** — Colors and colormaps reference
- **[API Reference](https://dartworklabs.github.io/dartwork-mpl/api/index.html)** — Function-level docs
- **[Example Gallery](https://dartworklabs.github.io/dartwork-mpl/examples_gallery/index.html)** — Interactive examples

<br/>

## 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

```shell
# 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`:

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

### Cursor

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

```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`](docs/integrations/mcp_server.md) (or the [hosted version](https://dartworklabs.github.io/dartwork-mpl/integrations/mcp_server.html)).

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

<br/>

## 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
```

<br/>

## Reporting Issues

Encountered a bug or have a feature request? Please open an issue through our [GitHub issue tracker](https://github.com/dartworklabs/dartwork-mpl/issues).
