PlotSmith for ML models
Project description
PlotSmith
PlotSmith is a layered plotting library for ML models with strict architectural boundaries. It provides clean, minimalist visualizations following best practices for analytical figures.
Features
- 4-Layer Architecture: Strict separation of concerns with clear boundaries
- Minimalist Styling: Clean, publication-ready plots with serif fonts and minimal clutter
- Type-Safe: Full type hints and immutable data structures
- Comprehensive: Time series, scatter plots, histograms, bar charts, heatmaps, residuals, and more
- ML-Focused: Built for model evaluation, backtesting, and analysis workflows
Installation
pip install plotsmith
Quick Start
import pandas as pd
import numpy as np
from plotsmith import plot_timeseries, plot_residuals, plot_heatmap
# Time series with confidence bands
data = pd.Series([1, 2, 3, 4, 5], index=pd.date_range('2020-01-01', periods=5))
lower = data - 0.5
upper = data + 0.5
fig, ax = plot_timeseries(
data,
bands={'95% CI': (lower, upper)},
title='Time Series with Confidence Bands'
)
# Residual analysis
actual = np.array([1, 2, 3, 4, 5])
predicted = np.array([1.1, 2.2, 2.9, 4.1, 4.8])
fig, ax = plot_residuals(actual, predicted, plot_type='scatter')
# Correlation heatmap
corr_matrix = df.corr()
fig, ax = plot_heatmap(corr_matrix, annotate=True, cmap='RdYlGn')
Architecture
PlotSmith follows a strict 4-layer architecture with clear boundaries:
Layer 1: Objects (plotsmith.objects)
Immutable dataclasses representing plot-ready data. No matplotlib imports.
SeriesView- Time series dataBandView- Confidence bandsScatterView- Scatter plot dataHistogramView- Histogram dataBarView- Bar chart dataHeatmapView- 2D heatmap dataFigureSpec- Figure styling specification
Layer 2: Primitives (plotsmith.primitives)
Drawing functions that accept only Layer 1 objects. All matplotlib calls here.
draw_series(),draw_scatter(),draw_histogram(),draw_bar(),draw_heatmap()minimal_axes()- Minimalist axes stylingtidy_axes()- SignalPlot-style axes cleanupstyle_line_plot(),style_scatter_plot(),style_bar_plot()event_line(),direct_label(),note(),accent_point()
Layer 3: Tasks (plotsmith.tasks)
Translate user intent into Layer 1 objects. Can import pandas/numpy, not matplotlib.
TimeseriesPlotTask- Convert Series/DataFrame to viewsBacktestPlotTask- Convert results table to scatter viewsHistogramPlotTask- Convert data to histogram viewsBarPlotTask- Convert data to bar viewsHeatmapPlotTask- Convert 2D data to heatmap viewsResidualsPlotTask- Convert actual/predicted to residual views
Layer 4: Workflows (plotsmith.workflows)
Public API entry points. Orchestrate tasks → primitives → save/show.
plot_timeseries()- Time series plottingplot_backtest()- Backtest results visualizationplot_histogram()- Histogram plotting (supports overlaid)plot_bar()- Bar chart plottingplot_heatmap()- Heatmap/correlation matrix plottingplot_residuals()- Residual analysis plotsplot_model_comparison()- Compare multiple model predictionsfigure()- Create styled figuresmall_multiples()- Create grid of small-multiple axes
Workflows
Time Series Plotting
from plotsmith import plot_timeseries
import pandas as pd
# Single series
data = pd.Series([1, 2, 3, 4, 5], index=pd.date_range('2020-01-01', periods=5))
fig, ax = plot_timeseries(data, title='My Time Series')
# Multiple series (DataFrame)
df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]},
index=pd.date_range('2020-01-01', periods=3))
fig, ax = plot_timeseries(df)
# With confidence bands
bands = {'CI': (lower_series, upper_series)}
fig, ax = plot_timeseries(data, bands=bands, save_path='output.png')
Residual Analysis
from plotsmith import plot_residuals
# Scatter plot (predicted vs actual)
fig, ax = plot_residuals(actual, predicted, plot_type='scatter', add_perfect_line=True)
# Time series (residuals over time)
fig, ax = plot_residuals(actual, predicted, x=dates, plot_type='series')
Model Comparison
from plotsmith import plot_model_comparison
models = {
'LSTM': lstm_predictions,
'XGBoost': xgb_predictions,
'SARIMA': sarima_predictions
}
fig, ax = plot_model_comparison(
actual_data,
models,
test_start_idx=100, # Optional: mark test period start
title='Model Comparison'
)
Heatmaps
from plotsmith import plot_heatmap
import pandas as pd
# Correlation matrix
corr = df.corr()
fig, ax = plot_heatmap(
corr,
annotate=True,
fmt='.2f',
cmap='RdYlGn',
vmin=-1,
vmax=1
)
# Any 2D array
data = np.random.rand(10, 10)
fig, ax = plot_heatmap(data, title='Custom Heatmap')
Histograms
from plotsmith import plot_histogram
# Single histogram
fig, ax = plot_histogram(data, bins=30, title='Distribution')
# Overlaid histograms
fig, ax = plot_histogram(
[normal_data, anomaly_data],
labels=['Normal', 'Anomalies'],
colors=['blue', 'red'],
alpha=0.7
)
Bar Charts
from plotsmith import plot_bar
categories = ['A', 'B', 'C', 'D']
values = [10, 20, 15, 25]
fig, ax = plot_bar(
categories,
values,
force_zero=True, # Honest scale
title='Bar Chart'
)
Backtest Results
from plotsmith import plot_backtest
results = pd.DataFrame({
'y_true': [1, 2, 3, 4, 5],
'y_pred': [1.1, 2.2, 2.9, 4.1, 4.8],
'fold_id': [0, 0, 1, 1, 2]
})
fig, ax = plot_backtest(results, fold_id_col='fold_id')
Styling Helpers
PlotSmith provides minimalist styling by default and includes helpers for customization:
from plotsmith import minimal_axes, tidy_axes, event_line, direct_label, ACCENT
fig, ax = plt.subplots()
minimal_axes(ax) # Minimalist styling (serif font, clean spines)
# or
tidy_axes(ax) # SignalPlot-style (gray spines, clean ticks)
# Add event markers
event_line(ax, x=2020, text='Policy Change', color=ACCENT)
# Direct labels
direct_label(ax, x=5, y=10, text='Peak', use_accent=True)
Examples
See examples/basic_timeseries.py for a complete example:
python examples/basic_timeseries.py
This generates examples/out/basic_timeseries.png with a time series plot including confidence bands.
Architecture Principles
- Strict Boundaries: Each layer can only import from layers below it
- Immutable Data: All view objects are frozen dataclasses
- Validation: Shape and alignment checks before drawing
- Separation of Concerns: Data representation (Layer 1) is separate from drawing (Layer 2)
- Type Safety: Full type hints throughout
Requirements
- Python 3.12+
- matplotlib >= 3.5.0
- numpy >= 1.20.0
- pandas >= 1.3.0
Development
# Install in development mode
pip install -e ".[dev]"
# Run tests
pytest
# Run with coverage
pytest --cov=plotsmith --cov-report=html
License
MIT License - see LICENSE file for details.
Contributing
See CONTRIBUTING.md for guidelines.
Citation
If you use PlotSmith in your research, please cite:
@software{plotsmith,
title={PlotSmith: A Layered Plotting Library for ML Models},
author={Jones, Kyle T.},
year={2025},
url={https://github.com/kylejones200/plotsmith}
}
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file plotsmith-0.1.5.tar.gz.
File metadata
- Download URL: plotsmith-0.1.5.tar.gz
- Upload date:
- Size: 25.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5854c45b26dbfb48477d75186551a0c1ed03b81e9b1d5d4e369a4d3024fdabf2
|
|
| MD5 |
37e475967fee1bf8d0efd890cd7ad35b
|
|
| BLAKE2b-256 |
f3c3f9119f4a3f13f2ce6f6d668354318297888388a7e18f33959a083e99dd6d
|
Provenance
The following attestation bundles were made for plotsmith-0.1.5.tar.gz:
Publisher:
release.yml on kylejones200/plotsmith
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
plotsmith-0.1.5.tar.gz -
Subject digest:
5854c45b26dbfb48477d75186551a0c1ed03b81e9b1d5d4e369a4d3024fdabf2 - Sigstore transparency entry: 810295650
- Sigstore integration time:
-
Permalink:
kylejones200/plotsmith@64192e80422e72325914edba22f99fdb9af3dcc1 -
Branch / Tag:
refs/tags/v0.1.5 - Owner: https://github.com/kylejones200
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@64192e80422e72325914edba22f99fdb9af3dcc1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file plotsmith-0.1.5-py3-none-any.whl.
File metadata
- Download URL: plotsmith-0.1.5-py3-none-any.whl
- Upload date:
- Size: 22.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
872bfb1618180083fab2348affcd8b304ac78b07ec37fd762f72e58090c612c0
|
|
| MD5 |
dc620cb365cb7c01cd91e7aacba1cc3d
|
|
| BLAKE2b-256 |
917b0c8455a84a0695fc8bfab8c459ab40e344f6d5688456f9edc7f2e8e422ea
|
Provenance
The following attestation bundles were made for plotsmith-0.1.5-py3-none-any.whl:
Publisher:
release.yml on kylejones200/plotsmith
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
plotsmith-0.1.5-py3-none-any.whl -
Subject digest:
872bfb1618180083fab2348affcd8b304ac78b07ec37fd762f72e58090c612c0 - Sigstore transparency entry: 810295660
- Sigstore integration time:
-
Permalink:
kylejones200/plotsmith@64192e80422e72325914edba22f99fdb9af3dcc1 -
Branch / Tag:
refs/tags/v0.1.5 - Owner: https://github.com/kylejones200
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@64192e80422e72325914edba22f99fdb9af3dcc1 -
Trigger Event:
push
-
Statement type: