Skip to main content

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.

PyPI version Python Documentation License: MIT

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" and aria-labelledby on every <svg> root element
  • <title> and <desc> landmark elements with auto-generated descriptions
  • tabindex="0" and role="graphics-symbol" on every interactive data point
  • Tab / Arrow key navigation between data points
  • Enter / Space to trigger tooltips from keyboard
  • Escape to dismiss and blur
  • focusable="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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

glyphx-2.0.0.tar.gz (421.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

glyphx-2.0.0-py3-none-any.whl (94.1 kB view details)

Uploaded Python 3

File details

Details for the file glyphx-2.0.0.tar.gz.

File metadata

  • Download URL: glyphx-2.0.0.tar.gz
  • Upload date:
  • Size: 421.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for glyphx-2.0.0.tar.gz
Algorithm Hash digest
SHA256 848c34a2111479b4a209f090dc6b59b2f6d84fbca3b7fd53da3fcde4ae038571
MD5 ef1a0a07842f065badd520537e7f4ef0
BLAKE2b-256 23630e71f7169582b7d6e538e8d7d8f67b336bf746acb7c72e71f4e0ecf9ba29

See more details on using hashes here.

File details

Details for the file glyphx-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: glyphx-2.0.0-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

Hashes for glyphx-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0a42afaf917ad6db3d72f8d80f92bbad210ea75222d1149f2b2b3f29327895e7
MD5 3316ae7d63bd74bdf2757311e87d7784
BLAKE2b-256 943ed57b1456a8efac3d24972115911b6c7c23f1bd9cc0bf0b4cae0346dcd7cb

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page