flowmpl
Matplotlib design system and flow diagram renderer for analytical publications.
Built for research notebooks that combine data visualization with process flow diagrams — the kind of work where you need both a consistent visual language across charts and clean auto-routed arrows between labeled boxes.
Install
pip install flowmpl # core: matplotlib + numpy only
pip install flowmpl[charts] # + pandas (annotated_series, stacked_bar, etc.)
pip install flowmpl[maps] # + geopandas + requests (us_scatter_map)
pip install flowmpl[all] # everything
Quick Start
from flowmpl import COLORS, FONTS, flow_diagram
fig = flow_diagram(
nodes={
"a": ("Announce", 1.0, 1.0, COLORS["accent"], "#ffffff"),
"b": ("Permit", 3.0, 1.0, COLORS["neutral"], COLORS["text_dark"]),
"c": ("Build", 5.0, 1.0, COLORS["positive"], "#ffffff"),
},
edges=[
{"src": "a", "dst": "b", "label": "12–18 mo"},
{"src": "b", "dst": "c", "label": "24–36 mo"},
],
title="From announcement to operation",
)
fig.savefig("pipeline.png", dpi=150, bbox_inches="tight")
Design System
flowmpl ships a complete design system extracted from a production research project:
| Token | Description |
|---|---|
COLORS |
Semantic roles: accent, positive, negative, neutral, muted, reference, background, text_dark, text_light |
CONTEXT |
SWD gray — use for non-focus elements in gray+accent charts |
FONTS |
Font sizes for titles, labels, annotations, legends, captions |
FIGSIZE |
Named figure sizes: standard, wide, tall, map |
CATEGORICAL |
8-color Paul Tol colorblind-safe palette |
FUEL_COLORS |
Energy generation types: solar, wind, battery, gas_cc, gas_ct, nuclear, hydro, coal… |
COMPANY_COLORS |
Hyperscaler tickers: MSFT, AMZN, GOOGL, META, NVDA, ORCL, AAPL, TSLA |
Chart Functions
All functions return matplotlib.Figure objects.
from flowmpl import (
annotated_series, # time series with annotations + fill
multi_panel, # multi-subplot from a single DataFrame
stacked_bar, # stacked bar for categorical breakdowns
waterfall_chart, # cost allocation / flow breakdowns
horizontal_bar_ranking, # ranked horizontal bars with highlights
)
Helpers
from flowmpl import (
focus_colors, # SWD gray+accent pattern: focus items colored, rest gray
legend_below, # place legend below axes (works with bbox_inches='tight')
annotate_point, # annotate a data point with arrow + text
reference_line, # labeled horizontal or vertical reference line
chart_title, # subtle left-aligned insight title (for standalone PNGs)
)
focus_colors() example
colors = focus_colors(
["MSFT", "AMZN", "GOOGL", "META"],
focus="AMZN",
color_map=COMPANY_COLORS,
)
# → ['#c0c0c0', '#ff9900', '#c0c0c0', '#c0c0c0']
Flow Diagram
flow_diagram() renders labeled boxes connected by auto-routed arrows. It handles:
- Auto-routing: chooses straight or elbow connections based on source/destination geometry
- Face overrides: explicit
exit/entrykeys bypass the heuristic for complex layouts - Auto-spacing: adjusts vertical spacing to prevent label overlap
- Face spreading: distributes multiple edges from the same face to avoid overlaps
Node format
nodes = {
"key": (label, cx, cy, fill_color, text_color),
}
cx,cy: center coordinates in abstract units (the renderer scales to fit)- Sizes auto-scaled; override with
node_width/node_heightparams
Edge format
edges = [
{"src": "a", "dst": "b"}, # basic
{"src": "a", "dst": "b", "label": "2 years"}, # with label
{"src": "a", "dst": "b", "dashed": True}, # dashed line
{"src": "a", "dst": "b", "color": "#888"}, # custom color
{"src": "a", "dst": "b", "exit": "top", "entry": "left"}, # face override
{"src": "a", "dst": "b", "exit": "bottom", "entry": "left"}, # force exit face
]
Routing heuristic
The auto-router uses the vector between node centers:
| Condition | Route style |
|---|---|
|vy| < 0.25 \* |vx| |
Near-horizontal — straight line |
|vx| < 0.25 \* |vy| |
Near-vertical — straight line |
|vy| < 0.75 \* |vx| |
Primarily-horizontal — exit top/bottom, enter side |
| else | Primarily-vertical — exit side, enter top/bottom |
Use explicit exit/entry overrides when the heuristic produces overlapping arrows
from the same face (e.g., a root node with multiple connections at different angles).
T-layout example (face overrides)
fig = flow_diagram(
nodes={
"r": ("Root", 1.0, 1.5, COLORS["accent"], "#ffffff"),
"a": ("Top", 4.5, 3.0, COLORS["positive"], "#ffffff"),
"m": ("Middle", 4.5, 1.5, COLORS["neutral"], COLORS["text_dark"]),
"b": ("Bottom", 4.5, 0.0, CONTEXT, COLORS["text_dark"]),
},
edges=[
{"src": "r", "dst": "a", "exit": "top", "entry": "left"},
{"src": "r", "dst": "m"}, # straight, no override needed
{"src": "r", "dst": "b", "exit": "bottom", "entry": "left"},
],
title="Three destinations from one source",
)
Without the face overrides, all three arrows would exit from r's right face and overlap.
With exit="top" and exit="bottom", each arrow leaves from a different face.
Map
from flowmpl import us_scatter_map
import matplotlib.patches as mpatches
fig = us_scatter_map(
lats=[37.7, 40.7, 41.8],
lons=[-122.4, -74.0, -87.6],
colors=["#e74c3c", "#3498db", "#2ecc71"],
sizes=[100, 150, 80],
title="Three cities",
legend_handles=[
mpatches.Patch(color="#e74c3c", label="San Francisco"),
mpatches.Patch(color="#3498db", label="New York"),
mpatches.Patch(color="#2ecc71", label="Chicago"),
],
)
State boundary shapefiles are downloaded from the US Census Bureau on first use and cached in the package directory.
License
MIT
Metadata
Release files for flowmpl 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| flowmpl-0.3.1.tar.gz | 14.9 MB | Without provenance | Details for flowmpl-0.3.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| flowmpl-0.3.1-py3-none-any.whl | Python 3 | none | any | Details for flowmpl-0.3.1-py3-none-any.whl |
Total release size: 15.1 MB
Release files / flowmpl-0.3.1.tar.gz
| Download URL | flowmpl-0.3.1.tar.gz |
|---|---|
| Size | 14.9 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b13a421a8be91b149ca6f70cf420dbb042e16054f94b6d6849f4aa022f41b333
|
|
BLAKE2b-256 checksum How to use checksums |
035dedcf0c0b3f8961072a3a09df8f3fb66cb6ebc842ed29eae9df9144cdfa6a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.8.0
|
Release files / flowmpl-0.3.1-py3-none-any.whl
| Download URL | flowmpl-0.3.1-py3-none-any.whl |
|---|---|
| Size | 233.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b11ec798acdaceafb3825051deddde701c6a521e6ad093aa99ee30356d29811d
|
|
BLAKE2b-256 checksum How to use checksums |
e6d201b8afa0381def1d0188667cffa44aa6a9ca222e9cff947d8ddf8a1ba2b7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.8.0
|
Security for flowmpl 0.3.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.