A next-gen Python plotting library with SVG-first rendering, interactivity, themes, and clean defaults
Project description
GlyphX
A next-generation Python visualization library — SVG-first, interactive, and designed to replace Matplotlib, Seaborn, and Plotly.
GlyphX renders crisp, interactive SVG charts that work everywhere — Jupyter notebooks, CLI pipelines, FastAPI servers, and static HTML files — with zero configuration and no plt.show() required.
Why GlyphX?
| Feature | GlyphX | Matplotlib | Seaborn | Plotly |
|---|---|---|---|---|
| Auto-display (no show()) | ✅ | ❌ | ❌ | ❌ |
| Method chaining API | ✅ | ❌ | ❌ | Partial |
DataFrame accessor (df.glyphx.*) |
✅ | ❌ | Partial | ❌ |
| Natural language chart generation | ✅ | ❌ | ❌ | ❌ |
| Linked interactive brushing | ✅ | ❌ | ❌ | ✅ (needs server) |
| Self-contained shareable HTML | ✅ | ❌ | ❌ | ❌ |
| Statistical significance brackets | ✅ | ❌ | ❌ | ❌ |
| ECDF plot | ✅ | ❌ | ✅ | ❌ |
| Raincloud plot | ✅ | ❌ | ❌ | ❌ |
| Perceptually-uniform colormaps | ✅ (9 built-in) | ✅ | ✅ | ✅ |
| Continuous color encoding in scatter | ✅ | ✅ | ✅ | ✅ |
| Candlestick / OHLC | ✅ | ❌ | ❌ | ✅ |
| Waterfall / bridge chart | ✅ | ❌ | ❌ | ✅ |
| Treemap (squarified) | ✅ | ❌ | ❌ | ✅ |
| Streaming / real-time series | ✅ (no server) | ❌ | ❌ | ✅ (needs server) |
| Synchronized crosshair | ✅ | ❌ | ❌ | ✅ (needs server) |
| PPTX export | ✅ | ❌ | ❌ | ❌ |
CLI tool (glyphx plot data.csv) |
✅ | ❌ | ❌ | ❌ |
| Full ARIA accessibility | ✅ | ❌ | ❌ | Partial |
| Full type annotations (py.typed) | ✅ | ❌ | ❌ | Partial |
| tight_layout() | ✅ (auto) | Manual | Auto | Auto |
Installation
pip install glyphx
# Optional extras
pip install "glyphx[pptx]" # PowerPoint export (python-pptx + cairosvg)
pip install "glyphx[export]" # PNG/JPG export (cairosvg)
pip install "glyphx[nlp]" # Natural language charts (anthropic)
pip install "glyphx[all]" # Everything
Quick Start
from glyphx import plot
# One-liner — auto-displays in Jupyter, opens browser in CLI
plot([1, 2, 3], [4, 5, 6], kind="line", title="My First Chart")
from glyphx import Figure
from glyphx.series import LineSeries, BarSeries
# Fluent method-chaining API
fig = (
Figure(width=800, height=500)
.set_title("Revenue vs Costs")
.set_theme("dark")
.set_xlabel("Month")
.set_ylabel("USD (thousands)")
.add(LineSeries(months, revenue, color="#60a5fa", label="Revenue"))
.add(LineSeries(months, costs, color="#f87171", label="Costs", linestyle="dashed"))
.set_legend("top-left")
.tight_layout()
)
fig.show() # display in Jupyter / browser
fig.save("chart.svg") # SVG
fig.save("chart.html") # interactive HTML
fig.save("chart.png") # raster (requires cairosvg)
fig.save("chart.pptx") # PowerPoint slide (requires glyphx[pptx])
fig.share("report.html") # self-contained, zero-CDN HTML
Core APIs
1 — Unified plot() Function
The fastest path to any chart type. Arguments mirror pandas' df.plot():
from glyphx import plot
plot([1,2,3], [4,5,6], kind="line", title="Line")
plot(["A","B","C"], [10,20,15], kind="bar", title="Bar")
plot([1,2,3], [4,5,6], kind="scatter", title="Scatter")
plot(data=[30,40,30], kind="pie", labels=["A","B","C"])
plot(data=[30,40,30], kind="donut", labels=["A","B","C"])
plot(data=raw_values, kind="hist", bins=20)
plot(data=raw_values, kind="box")
plot(data=matrix, kind="heatmap")
2 — Method-Chaining API
Every mutating method returns self. Build the entire chart in a single expression:
fig = (
Figure(width=720, height=460, theme="warm")
.set_title("Q3 Performance Dashboard")
.set_size(900, 520) # resize mid-chain
.set_xlabel("Month")
.set_ylabel("Revenue ($M)")
.set_legend("bottom-right")
.add(LineSeries(x, y, label="Revenue"))
.add(BarSeries(x, costs, label="Costs"), use_y2=True)
.annotate("Record High", x=10, y=5.4, arrow=True, color="#dc2626")
.add_stat_annotation("Jan", "Jun", p_value=0.001)
.tight_layout()
.share("dashboard.html")
)
3 — DataFrame Accessor
Import glyphx once and every pd.DataFrame gains a .glyphx accessor:
import pandas as pd
import glyphx # registers the accessor automatically
df = pd.read_csv("sales.csv")
# One-liner charts directly from column names
df.glyphx.line(x="date", y="revenue", title="Daily Revenue")
df.glyphx.bar( x="product", y="sales", title="Sales by Product")
df.glyphx.scatter(x="spend", y="revenue")
df.glyphx.hist(col="response_time", bins=20)
df.glyphx.box(col="score", groupby="region")
df.glyphx.pie(labels="category", values="share")
# Groupby aggregation in one call
df.glyphx.bar(groupby="region", y="revenue", agg="sum",
title="Revenue by Region")
# Full chain from the accessor
(df.glyphx
.bar(x="month", y="revenue", label="Revenue", auto_display=False)
.set_theme("dark")
.set_xlabel("Month")
.add_stat_annotation("Jan", "Jun", p_value=0.002)
.share("monthly_report.html"))
4 — Natural Language Charts
Describe a chart in plain English and GlyphX builds it automatically.
Requires pip install "glyphx[nlp]" and an ANTHROPIC_API_KEY.
from glyphx import from_prompt
import pandas as pd
df = pd.read_csv("sales.csv")
# GlyphX infers chart type, column mappings, grouping, theme, and title
fig = from_prompt("bar chart of total revenue by region, dark theme", df=df)
# Works without a DataFrame too — generates illustrative sample data
fig = from_prompt("scatter plot showing a strong positive correlation")
# Complex queries
fig = from_prompt(
"top 10 products by revenue this quarter, sorted descending",
df=df,
)
Interactivity
All charts rendered to HTML include:
| Interaction | How |
|---|---|
| Tooltips | Hover any data point |
| Zoom | Mouse wheel |
| Pan | Click + drag |
| Reset zoom | Double-click |
| Linked brushing | Shift + drag on any chart — filters all charts on the page |
| Keyboard navigation | Tab / Arrow keys move between data points |
| Legend toggle | Click a legend item to show/hide its series |
| Export | SVG / PNG buttons in the toolbar |
| Share | One-click copy of self-contained HTML to clipboard |
Linked Brushing
Hold Shift and drag on any chart. All charts on the same HTML page sharing the same X values highlight matching points and dim everything else. Press Escape to clear.
from glyphx import Figure
from glyphx.layout import grid
from glyphx.series import ScatterSeries, LineSeries
f1 = Figure().add(ScatterSeries(x, y1, label="Sales"))
f2 = Figure().add(LineSeries(x, y2, label="Revenue"))
# Both charts brush together
html = grid([f1, f2], rows=1, cols=2)
open("dashboard.html", "w").write(html)
Synchronized Crosshair
fig.enable_crosshair() # vertical line syncs across all charts on the page
fig.share("report.html")
Chart Types
Basic
from glyphx.series import (
LineSeries, BarSeries, ScatterSeries,
PieSeries, DonutSeries, HistogramSeries,
BoxPlotSeries, HeatmapSeries,
)
# Line — with error bars and linestyles
LineSeries(x, y,
color="#2563eb", label="Revenue",
linestyle="dashed", # solid | dashed | dotted | longdash
width=2,
yerr=error_values, # Y error bars with caps
xerr=error_values, # X error bars
)
# Bar — with error bars and groupby support
BarSeries(x, y,
color="#7c3aed", label="Units",
bar_width=0.7,
yerr=std_errors,
)
# Scatter — with continuous color encoding
ScatterSeries(x, y,
c=z_values, # per-point color values
cmap="viridis", # any of 9 built-in colormaps
size=6,
marker="circle", # circle | square
)
# Histogram
HistogramSeries(data, bins=20, color="#0891b2")
# Box plot — single or multi-group
BoxPlotSeries(data, categories=["A","B","C"], box_width=24)
BoxPlotSeries([group_a, group_b, group_c], categories=["A","B","C"])
# Heatmap — with colorbar, row/col labels, value overlay
HeatmapSeries(matrix,
row_labels=row_names,
col_labels=col_names,
show_values=True,
cmap=["#1e40af","#f0f0f0","#b91c1c"],
)
Statistical (better than Seaborn)
# ECDF — no bin-width choice needed
from glyphx.ecdf import ECDFSeries
ECDFSeries(data, label="Control", complementary=False)
# Raincloud — jitter + half-violin + box in one
from glyphx.raincloud import RaincloudSeries
RaincloudSeries(
data=[control, drug_a, drug_b],
categories=["Control","Drug A","Drug B"],
violin_width=35,
)
# Statistical significance brackets
fig.add_stat_annotation(
x1="Control", x2="Drug A",
p_value=0.001, # → "***"
style="stars", # stars | numeric
y_offset=0, # stack multiple brackets
)
# Violin plot
from glyphx.violin_plot import ViolinPlotSeries
ViolinPlotSeries(data=[grp_a, grp_b], show_median=True, show_box=True)
Financial (better than Plotly)
# Candlestick / OHLC
from glyphx.candlestick import CandlestickSeries
CandlestickSeries(
dates=["Mon","Tue","Wed"],
open= [150, 153, 149],
high= [155, 157, 153],
low= [148, 151, 146],
close=[153, 149, 155],
)
# Waterfall / bridge chart
from glyphx.waterfall import WaterfallSeries
WaterfallSeries(
labels=["Q2 Revenue","New Sales","Churn","Q3 Revenue"],
values=[8.2, 2.1, -0.6, None], # None = auto-compute total bar
show_values=True,
)
Hierarchical
# Treemap — squarified layout algorithm
from glyphx.treemap import TreemapSeries
TreemapSeries(
labels=["Cloud","AI","Mobile","Security","Data"],
values=[4200, 3100, 2800, 2100, 1900],
cmap="viridis",
)
Streaming / Real-Time
from glyphx.streaming import StreamingSeries
fig = Figure().set_title("Live Sensor Feed")
stream = StreamingSeries(max_points=100, color="#7c3aed", label="Sensor")
fig.add(stream)
# Push values one at a time
stream.push(42.0)
stream.push(43.8)
# Or batch
stream.push_many([41, 42, 43, 44, 45])
# Jupyter live mode — re-renders at target FPS
with stream.live(fig, fps=10) as s:
for reading in sensor_generator():
s.push(reading)
Advanced Layout
# Dual Y-axis
fig.add(LineSeries(x, prices, label="Price (left)"))
fig.add(BarSeries(x, volume, label="Volume (right)"), use_y2=True)
# Subplot grid
fig = Figure(rows=2, cols=2, width=1000, height=700)
ax1 = fig.add_axes(0, 0)
ax1.add_series(LineSeries(x, y))
ax2 = fig.add_axes(0, 1)
ax2.add_series(BarSeries(cats, vals))
# Auto tight layout — adjusts padding and rotates crowded labels
fig.tight_layout()
# Annotations with arrows
fig.annotate("Peak", x=10, y=5.4, arrow=True, color="#dc2626", font_size=12)
# Log scale
Figure(yscale="log")
Figure(xscale="log")
Colormaps
Nine perceptually-uniform colormaps, all colorblind-safe when used with the colorblind theme:
| Name | Type | Best for |
|---|---|---|
viridis |
Sequential | Default continuous encoding |
plasma |
Sequential | High-contrast continuous |
inferno |
Sequential | Print-safe dark backgrounds |
magma |
Sequential | Heatmaps and density |
cividis |
Sequential | Deuteranopia-safe |
coolwarm |
Diverging | Correlation matrices |
rdbu |
Diverging | Positive/negative values |
spectral |
Multi-hue | Categorical ranges |
greys |
Sequential | Monochrome export |
from glyphx.colormaps import (
apply_colormap, # single value → hex color
colormap_colors, # n evenly-spaced colors
list_colormaps, # all available names
)
# Single value
color = apply_colormap(0.75, "plasma") # "#eb5f34"
# N colors for a grouped bar chart
colors = colormap_colors("viridis", 6)
# Color-encode scatter points by a third variable
ScatterSeries(x, y, c=z_values, cmap="inferno")
Themes
Seven built-in themes, including the scientifically correct Okabe-Ito colorblind palette:
Figure(theme="default") # clean white background
Figure(theme="dark") # dark charcoal background
Figure(theme="colorblind") # Okabe-Ito palette — safe for all types
Figure(theme="pastel") # soft, presentation-friendly
Figure(theme="warm") # earthy tones, Georgia serif font
Figure(theme="ocean") # blue palette, light blue background
Figure(theme="monochrome") # grayscale, print-safe
# Custom theme
Figure(theme={
"colors": ["#ff6b6b", "#4ecdc4", "#45b7d1"],
"background": "#1a1a2e",
"text_color": "#eee",
"axis_color": "#555",
"grid_color": "#333",
"font": "Roboto, sans-serif",
})
Export Options
fig.save("chart.svg") # vector SVG
fig.save("chart.html") # interactive HTML with tooltips, zoom, export buttons
fig.save("chart.png") # raster PNG (requires: pip install cairosvg)
fig.save("chart.jpg") # raster JPG (requires: pip install cairosvg)
fig.save("chart.pptx") # PowerPoint (requires: pip install "glyphx[pptx]")
# Self-contained HTML — zero external dependencies, works offline
html = fig.share() # returns HTML string
html = fig.share("report.html") # also writes to disk
html = fig.share(title="Q3 Report") # custom <title>
Shareable HTML
fig.share() generates a single .html file with all JavaScript inlined. No CDN links, no server, no external files. Open it from a USB stick, email it, embed it in Confluence, paste it in Notion — it works everywhere.
CLI Tool
Plot any CSV, JSON, or Excel file from the terminal:
# Basic usage
glyphx plot sales.csv --x month --y revenue --kind bar -o chart.html
# All options
glyphx plot data.csv \
--x date \
--y revenue \
--kind line \
--groupby region \
--agg sum \
--theme dark \
--title "Monthly Revenue" \
--xlabel "Date" \
--ylabel "Revenue ($M)" \
--width 900 \
--height 500 \
--no-legend \
-o report.html \
--open # auto-open in browser
# Chart type suggestions for any dataset
glyphx suggest data.csv
# Version
glyphx version
Supported input formats: .csv .tsv .json .jsonl .xlsx .xls
Supported output formats: .svg .html .png .jpg .pptx
Accessibility
Every chart GlyphX renders meets WCAG 2.1 AA standards out of the box:
role="img"andaria-labelledbyon every<svg>root element<title>and<desc>landmark elements with auto-generated descriptionstabindex="0"androle="graphics-symbol"on every interactive data pointTab/Arrowkey navigation between data pointsEnter/Spaceto trigger tooltips from keyboardEscapeto dismiss and blurfocusable="false"prevents SVG from stealing keyboard focus
# Auto-generated plain-English description for screen readers
alt = fig.to_alt_text()
# → 'Line chart titled "Monthly Revenue". X axis: Month. Y axis: USD.
# Series "Revenue": 12 data points. Ranges from 98 (Mar) to 300 (Dec).'
Type Annotations
GlyphX is fully typed (py.typed PEP 561 marker included). Works with mypy, pyright, and any IDE with type checking:
from glyphx import Figure
from glyphx.series import LineSeries
fig: Figure = Figure(width=640, height=480)
s: LineSeries = LineSeries([1, 2, 3], [4, 5, 6], label="Revenue")
fig.add(s).set_title("Typed Chart").show()
Comparison with Matplotlib
Line Chart
# Matplotlib
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(months, revenue, color="blue", label="Revenue")
ax.plot(months, costs, color="red", label="Costs", linestyle="--")
ax.set_title("Revenue vs Costs")
ax.set_xlabel("Month")
ax.set_ylabel("USD")
ax.legend(loc="upper left")
plt.tight_layout()
plt.show()
# GlyphX — chains, shares, no plt.show()
(Figure()
.set_title("Revenue vs Costs")
.set_xlabel("Month").set_ylabel("USD")
.add(LineSeries(months, revenue, color="#2563eb", label="Revenue"))
.add(LineSeries(months, costs, color="#dc2626", label="Costs", linestyle="dashed"))
.set_legend("top-left")
.tight_layout()
.share("report.html"))
Subplot Grid
# Matplotlib
import matplotlib.pyplot as plt
fig, axs = plt.subplots(2, 2, figsize=(10, 8))
axs[0,0].plot([1,2,3], [4,5,6])
axs[0,1].bar(["A","B","C"], [5,3,7])
axs[1,0].scatter([1,2,3], [4,5,6])
axs[1,1].pie([30,45,25], labels=["A","B","C"])
plt.tight_layout()
plt.show()
# GlyphX
from glyphx import Figure
from glyphx.series import LineSeries, BarSeries, ScatterSeries, PieSeries
fig = Figure(rows=2, cols=2, width=900, height=640)
fig.add_axes(0,0).add_series(LineSeries([1,2,3],[4,5,6]))
fig.add_axes(0,1).add_series(BarSeries(["A","B","C"],[5,3,7]))
fig.add_axes(1,0).add_series(ScatterSeries([1,2,3],[4,5,6]))
fig.add_axes(1,1).add_series(PieSeries([30,45,25],labels=["A","B","C"]))
fig.show()
Comparison with Seaborn
Statistical Significance
# Seaborn — requires separate statannotations package
import seaborn as sns
from statannotations.Annotator import Annotator
ax = sns.barplot(data=df, x="group", y="score")
annotator = Annotator(ax, [("Control","Drug A")], data=df, x="group", y="score")
annotator.configure(test="t-test_ind", text_format="star")
annotator.apply_and_annotate()
# GlyphX — built-in, no extra package
(Figure()
.add(BarSeries(["Control","Drug A","Drug B"], means, yerr=errors))
.add_stat_annotation("Control", "Drug A", p_value=0.001)
.add_stat_annotation("Control", "Drug B", p_value=0.031, y_offset=30)
.show())
Raincloud Plot
# Seaborn — no native raincloud, requires ptitprince or manual assembly
import ptitprince as pt
pt.RainCloud(x="group", y="score", data=df, ax=ax)
# GlyphX — one series, built-in
from glyphx.raincloud import RaincloudSeries
Figure().add(RaincloudSeries(
data=[control, drug_a, drug_b],
categories=["Control","Drug A","Drug B"],
)).show()
Comparison with Plotly
Shareable Output
# Plotly — CDN dependency in exported HTML
import plotly.express as px
fig = px.line(df, x="month", y="revenue")
fig.write_html("chart.html") # loads plotly.js from CDN — breaks offline
# GlyphX — truly self-contained
fig.share("chart.html") # all JS inlined, works with no internet connection
Streaming — No Server Required
# Plotly — requires Dash + a running server
import dash
app = dash.Dash(__name__)
# ... 50+ lines of Dash boilerplate ...
app.run_server()
# GlyphX — works in a single Jupyter cell
from glyphx.streaming import StreamingSeries
stream = StreamingSeries(max_points=100)
fig = Figure().add(stream)
with stream.live(fig, fps=10) as s:
for reading in sensor.stream():
s.push(reading)
Full Feature Reference
Figure
| Method | Returns | Description |
|---|---|---|
Figure(width, height, theme, rows, cols, legend, xscale, yscale) |
Figure |
Create a figure |
.add(series, use_y2=False) |
Figure |
Add a series |
.set_title(text) |
Figure |
Set chart title |
.set_theme(name_or_dict) |
Figure |
Apply a theme |
.set_size(width, height) |
Figure |
Resize canvas |
.set_xlabel(text) |
Figure |
X-axis label |
.set_ylabel(text) |
Figure |
Y-axis label |
.set_legend(position) |
Figure |
Legend position or False |
.add_axes(row, col) |
Axes |
Subplot grid cell |
.annotate(text, x, y, ...) |
Figure |
Add text annotation |
.add_stat_annotation(x1, x2, p_value, ...) |
Figure |
Significance bracket |
.tight_layout() |
Figure |
Auto-adjust padding |
.enable_crosshair() |
Figure |
Synchronized crosshair |
.to_alt_text() |
str |
Screen-reader description |
.show() |
Figure |
Display (Jupyter / browser) |
.save(filename) |
Figure |
Save SVG/HTML/PNG/JPG/PPTX |
.share(filename, title) |
str |
Self-contained HTML |
.render_svg() |
str |
Raw SVG string |
DataFrame Accessor (df.glyphx.*)
| Method | Description |
|---|---|
.line(x, y, ...) |
Line chart |
.bar(x, y, groupby, agg, ...) |
Bar chart with optional groupby |
.scatter(x, y, ...) |
Scatter plot |
.hist(col, bins, ...) |
Histogram |
.box(col, groupby, ...) |
Box plot |
.pie(labels, values, ...) |
Pie chart |
.donut(labels, values, ...) |
Donut chart |
.heatmap(...) |
Heatmap from numeric columns |
.plot(kind, x, y, ...) |
Unified dispatcher |
All accessor methods return Figure for chaining.
CLI (glyphx)
| Command | Description |
|---|---|
glyphx plot <file> [options] |
Render a chart from a data file |
glyphx suggest <file> |
Recommend chart types for a dataset |
glyphx version |
Print version and exit |
Colormaps
viridis plasma inferno magma cividis coolwarm rdbu spectral greys
from glyphx.colormaps import apply_colormap, colormap_colors, list_colormaps
Themes
default dark colorblind pastel warm ocean monochrome
Running the Examples
git clone https://github.com/kjkoeller/glyphx
cd glyphx
pip install -e .
python examples.py # generates ./glyphx_output/ with 34 HTML files
OPEN=1 python examples.py # same, auto-opens each chart in browser
License
MIT License — © 2025 Kyle Koeller and GlyphX contributors
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 glyphx-2.0.1.tar.gz.
File metadata
- Download URL: glyphx-2.0.1.tar.gz
- Upload date:
- Size: 422.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e1e622528a37a1bed595e2388538a17562e85448d18306cb2969f1c0f163e67c
|
|
| MD5 |
c6b120390cc972ebe30d79d1c6c13a40
|
|
| BLAKE2b-256 |
459e0609168ba94685046ea9c37ec5637977e802d2b0cd4c5fa215138dcd2da3
|
File details
Details for the file glyphx-2.0.1-py3-none-any.whl.
File metadata
- Download URL: glyphx-2.0.1-py3-none-any.whl
- Upload date:
- Size: 94.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c66ae5e1957b878448594d94d3b28487caccb5b42277f8ec1ee8eb055a83a16
|
|
| MD5 |
c5882d77dddf4201533ec47251212230
|
|
| BLAKE2b-256 |
6f5d4b14edc3d0bff46a193ef1c17065b27c73d6f0a83b0d68cb39c3ea421a09
|