Helper Utilities (dm.helpers)

General-purpose helpers for building consistent, high-quality visualizations. They cover the small ergonomic gaps that show up between matplotlib and a polished figure — data validation, color picking, label/legend formatting, quality checks, and figure I/O.

These helpers compose well with the rest of dartwork-mpl, but they also work as a standalone toolkit on top of plain matplotlib.

Note

Upgrading from an older alias? See the Migration Guide for the full list of renamed paths and one-shot migration scripts.

Overview

The helpers module is organized into specialized submodules:

  • data: Data validation and cleaning utilities

  • colors: Automatic color selection and management

  • labels: Legend placement and formatting

  • quality: Quality checks and chart suggestions

  • io: Figure creation and saving utilities

Main Module

General-purpose helper utilities for dartwork-mpl.

Composition helpers that sit above the low-level matplotlib and dartwork-mpl primitives. This module is organised into submodules:

  • data: data validation and cleaning.

  • colors: palette selection.

  • labels: axis-label / legend / value-annotation helpers.

  • quality: figure quality checks and chart-type suggestion.

dartwork_mpl.helpers.check_figure_quality(fig: Figure) → list[str][source]

Check figure for common quality issues.

Parameters:

fig (Figure) – Figure to check

Returns:

List of issues found

Return type:

list[str]

Examples

>>> issues = check_figure_quality(fig)
>>> if issues:
...     print("Quality issues found:")
...     for issue in issues:
...         print(f"  - {issue}")
dartwork_mpl.helpers.make_palette(n: int, kind: Literal['categorical', 'sequential', 'diverging'] = 'categorical', highlight: int | None = None) → list[str][source]

Return n curated dartwork color names for kind series.

Parameters:
  • n (int) – Number of series the palette must cover. Colors repeat if n exceeds the built-in list for kind.

  • kind ({"categorical", "sequential", "diverging"}) – Palette family. categorical returns distinct hues; sequential returns light→dark blues; diverging returns red↔blue through gray.

  • highlight (int | None) – If set, the series at this index becomes darker (oc.*7) and the rest become lighter (oc.*3) to emphasise it. Only effective for the categorical and (loosely) diverging palettes whose names contain a "5" middle shade.

Returns:

Length-n list of dartwork color names.

Return type:

list[str]

Examples

>>> make_palette(5)                           # 5 categorical series
>>> make_palette(3, kind="sequential")        # 3 sequential blues
>>> make_palette(4, highlight=0)              # emphasise series 0
dartwork_mpl.helpers.optimize_legend(ax: Axes, preferred_loc: str = 'best', max_cols: int = 3, outside: bool = False) → None[source]

Optimize legend placement and formatting.

Parameters:
  • ax (Axes) – Matplotlib axes

  • preferred_loc (str) – Preferred location if space permits

  • max_cols (int) – Maximum number of columns for legend

  • outside (bool) – Whether to place legend outside plot area

Examples

>>> optimize_legend(ax, preferred_loc="upper right")
>>> optimize_legend(ax, outside=True)
dartwork_mpl.helpers.suggest_chart_type(x_type: str, y_type: str | None, n_points: int, n_series: int = 1) → str[source]

Suggest appropriate chart type based on data characteristics.

Parameters:
  • x_type (str) – Type of x data: “continuous”, “categorical”, “temporal”

  • y_type (str | None) – Type of y data: “continuous”, “categorical”, “count”, None

  • n_points (int) – Number of data points

  • n_series (int) – Number of data series

Returns:

Suggested chart type

Return type:

str

Examples

>>> chart_type = suggest_chart_type("categorical", "continuous", 5, 1)
>>> print(chart_type)  # "bar"
dartwork_mpl.helpers.validate_data(x: Any, y: Any | None = None, require_same_length: bool = True, allow_nan: bool = False, min_points: int = 2) → tuple[ndarray[Any, Any], ndarray[Any, Any] | None][source]

Validate and clean input data for plotting.

Parameters:
  • x (Any) – X-axis data

  • y (Any | None) – Y-axis data (optional for histograms, etc.)

  • require_same_length (bool) – Whether x and y must have the same length

  • allow_nan (bool) – Whether to retain NaN/Inf values. The default filters them and aligned rows, which can close a missing-observation line gap. Use True for intentional gaps, with separate shape, alignment, infinity and domain checks; this option alone does not validate those properties.

  • min_points (int) – Minimum number of data points required

Returns:

Cleaned x and y arrays

Return type:

tuple[np.ndarray, np.ndarray | None]

Raises:

ValueError – If validation fails

Examples

>>> x, y = validate_data([1, 2, 3], [4, 5, 6])
>>> x_clean, _ = validate_data([1, 2, np.nan, 4], allow_nan=False)

Data Validation

Utilities for validating and cleaning data before plotting.

Data validation and cleaning utilities for dartwork-mpl agents.

This module provides functions for validating and cleaning data before plotting.

dartwork_mpl.helpers.data.validate_data(x: Any, y: Any | None = None, require_same_length: bool = True, allow_nan: bool = False, min_points: int = 2) → tuple[ndarray[Any, Any], ndarray[Any, Any] | None][source]

Validate and clean input data for plotting.

Parameters:
  • x (Any) – X-axis data

  • y (Any | None) – Y-axis data (optional for histograms, etc.)

  • require_same_length (bool) – Whether x and y must have the same length

  • allow_nan (bool) – Whether to retain NaN/Inf values. The default filters them and aligned rows, which can close a missing-observation line gap. Use True for intentional gaps, with separate shape, alignment, infinity and domain checks; this option alone does not validate those properties.

  • min_points (int) – Minimum number of data points required

Returns:

Cleaned x and y arrays

Return type:

tuple[np.ndarray, np.ndarray | None]

Raises:

ValueError – If validation fails

Examples

>>> x, y = validate_data([1, 2, 3], [4, 5, 6])
>>> x_clean, _ = validate_data([1, 2, np.nan, 4], allow_nan=False)

Example:

import dartwork_mpl as dm
import numpy as np

# Validate data before plotting
x = np.array([1, 2, np.nan, 4, 5])
y = np.array([2, 4, 6, 8, 10])

x_clean, y_clean = dm.helpers.data.validate_data(
    x, y,
    require_same_length=True,
    allow_nan=False,
    min_points=3
)

Palette Lookup

Curated dartwork palette sized to the data series count and kind.

Curated palette lookup for dartwork-mpl.

make_palette returns a list of dartwork color names sized to the requested series count and palette kind. The four built-in lists (categorical, sequential blue at two cardinalities, diverging red-blue at two cardinalities) are the dartwork-mpl recommended series colors; they live inside this function so the project’s palette curation stays centralised.

Renamed from auto_select_colors in 0.5 (#156 Round 5):

  • auto_ prefix collided with auto_layout (measure-and-adjust).

  • select_colors was a strong verb for what is structurally a list slice.

  • Model B discrete family lookup now lives in dm.colors(..., n=...) and cycle application in dm.set_colors(...).

dartwork_mpl.helpers.colors.make_palette(n: int, kind: Literal['categorical', 'sequential', 'diverging'] = 'categorical', highlight: int | None = None) → list[str][source]

Return n curated dartwork color names for kind series.

Parameters:
  • n (int) – Number of series the palette must cover. Colors repeat if n exceeds the built-in list for kind.

  • kind ({"categorical", "sequential", "diverging"}) – Palette family. categorical returns distinct hues; sequential returns light→dark blues; diverging returns red↔blue through gray.

  • highlight (int | None) – If set, the series at this index becomes darker (oc.*7) and the rest become lighter (oc.*3) to emphasise it. Only effective for the categorical and (loosely) diverging palettes whose names contain a "5" middle shade.

Returns:

Length-n list of dartwork color names.

Return type:

list[str]

Examples

>>> make_palette(5)                           # 5 categorical series
>>> make_palette(3, kind="sequential")        # 3 sequential blues
>>> make_palette(4, highlight=0)              # emphasise series 0

Example:

import dartwork_mpl as dm

# Curated palette for 5 categorical series, item 0 highlighted.
colors = dm.make_palette(5, kind="categorical", highlight=0)

# Plot with the palette
for i, color in enumerate(colors):
    ax.plot(x, data[i], color=color, label=f"Series {i+1}")

Label and Legend Helpers

Functions for placing and formatting legends. Axis labels use matplotlib’s native ax.set_xlabel / ax.set_ylabel calls; value annotations use ax.text or ax.bar_label directly.

Label and legend helpers.

Higher-level composition helpers for legend placement. Renamed from helpers.formatting to avoid the name clash with the top-level dartwork_mpl.formatting module (which houses the format_axis_* tick formatters).

For axis labels, use ax.set_xlabel / ax.set_ylabel directly. For per-point value annotations, use an ax.text loop inline.

dartwork_mpl.helpers.labels.optimize_legend(ax: Axes, preferred_loc: str = 'best', max_cols: int = 3, outside: bool = False) → None[source]

Optimize legend placement and formatting.

Parameters:
  • ax (Axes) – Matplotlib axes

  • preferred_loc (str) – Preferred location if space permits

  • max_cols (int) – Maximum number of columns for legend

  • outside (bool) – Whether to place legend outside plot area

Examples

>>> optimize_legend(ax, preferred_loc="upper right")
>>> optimize_legend(ax, outside=True)

Example:

import dartwork_mpl as dm
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.plot(x, y)

ax.set_xlabel("Time", fontsize=dm.fs(0))
ax.set_ylabel("Value", fontsize=dm.fs(0))

# Optimize legend placement
dm.helpers.labels.optimize_legend(
    ax,
    preferred_loc="best",
    outside=False,
)

Quality Checks

Functions for checking figure quality and suggesting improvements.

Quality checks and chart type suggestions for dartwork-mpl agents.

This module provides functions for checking figure quality and suggesting appropriate chart types based on data characteristics.

Minimum DPI dartwork recommends for raster output. The one source for this check’s threshold and advice text and for the high_dpi requirement of validate_fixes.check_agent_requirements (they once drifted to 150 vs 200).

dartwork_mpl.helpers.quality.check_figure_quality(fig: Figure) → list[str][source]

Check figure for common quality issues.

Parameters:

fig (Figure) – Figure to check

Returns:

List of issues found

Return type:

list[str]

Examples

>>> issues = check_figure_quality(fig)
>>> if issues:
...     print("Quality issues found:")
...     for issue in issues:
...         print(f"  - {issue}")
dartwork_mpl.helpers.quality.suggest_chart_type(x_type: str, y_type: str | None, n_points: int, n_series: int = 1) → str[source]

Suggest appropriate chart type based on data characteristics.

Parameters:
  • x_type (str) – Type of x data: “continuous”, “categorical”, “temporal”

  • y_type (str | None) – Type of y data: “continuous”, “categorical”, “count”, None

  • n_points (int) – Number of data points

  • n_series (int) – Number of data series

Returns:

Suggested chart type

Return type:

str

Examples

>>> chart_type = suggest_chart_type("categorical", "continuous", 5, 1)
>>> print(chart_type)  # "bar"

Example:

import dartwork_mpl as dm

# Check figure quality
issues = dm.helpers.quality.check_figure_quality(fig)
if issues:
    print("Quality issues found:")
    for issue in issues:
        print(f"  - {issue}")

# Get chart type suggestions
suggested_type = dm.helpers.quality.suggest_chart_type(
    x_type="continuous",
    y_type="continuous",
    n_points=len(x),
    n_series=1,
)
print(f"Suggested chart type: {suggested_type}")

I/O Utilities

Note

The dartwork_mpl.helpers.io submodule was retired in 0.4. The single remaining entry point for multi-format saves is dm.save_formats (canonical) — pick the file types you want and the function handles the rest.

dm.save_formats is the canonical multi-format save helper (see Save & Export for its signature).

Example:

import matplotlib.pyplot as plt
import dartwork_mpl as dm

dm.style.use("scientific")
fig, ax = plt.subplots(figsize=dm.figsize("13cm", "standard"))
ax.plot(x, y)
dm.simple_layout(fig)

# Save in multiple formats at once
dm.save_formats(fig, "output", formats=("png", "pdf", "svg"))

End-to-end Example: Automated Visualization

The helpers module composes naturally with the rest of dartwork-mpl when you want a single function to take raw data and return a finished, quality-checked figure — useful for batch reporting, automated dashboards, or letting an LLM agent produce charts without hand-tuning every call.

import matplotlib.pyplot as plt
import dartwork_mpl as dm

def automated_visualization(data, chart_type=None):
    """Take raw ``{'x': ..., 'y': ...}`` data and return a polished figure."""

    # 1. Validate input data
    x, y = dm.helpers.data.validate_data(data["x"], data["y"])

    # 2. Suggest a chart type if not specified
    if chart_type is None:
        chart_type = dm.helpers.quality.suggest_chart_type(
            x_type="continuous",
            y_type="continuous",
            n_points=len(x),
            n_series=1,
        )

    # 3. Create the figure with an appropriate style
    dm.style.use("scientific" if chart_type == "scatter" else "web")
    fig, ax = plt.subplots(figsize=dm.figsize("13cm", "standard"))

    # 4. Pick a curated palette
    colors = dm.make_palette(
        1,
        kind="sequential" if chart_type == "line" else "categorical",
    )

    # 5. Render
    if chart_type == "line":
        ax.plot(x, y, color=colors[0])
    elif chart_type == "scatter":
        ax.scatter(x, y, color=colors[0])

    # 6. Format and quality-check
    ax.set_xlabel("X", fontsize=dm.fs(0))
    ax.set_ylabel("Y", fontsize=dm.fs(0))
    dm.helpers.labels.optimize_legend(ax)
    issues = dm.helpers.quality.check_figure_quality(fig)

    return fig, issues

See Also