API Reference

glyphx.plot

glyphx.plot(x=None, y=None, kind='line', data=None, legend='top-right', **kwargs)[source]

Unified high-level plotting function.

This is the quickest way to create a single chart. Specify kind plus x/y (or data for distribution charts) and GlyphX handles scaling, theming, rendering, and display automatically.

Parameters:
  • x (list or None) – X-axis values. Not required for pie, donut, hist, box, or heatmap.

  • y (list or None) – Y-axis values or raw data for distribution charts.

  • kind (str) – Chart type. One of "line", "bar", "scatter", "pie", "donut", "hist", "box", "heatmap".

  • data (list or None) – Explicit data array for hist / box / pie / donut (takes priority over y).

  • legend (str) – Legend position ("top-right", "top-left", etc.) or False to suppress.

  • **kwargs – Extra keyword arguments forwarded to the Series constructor (e.g. color, label, bins, linestyle) or to Figure (e.g. width, height, theme, xscale).

Returns:

The Figure object (auto-displayed unless auto_display=False).

Return type:

Figure

Examples

>>> plot([1, 2, 3], [4, 5, 6], kind="line", title="My Line")
>>> plot(y=[4, 5, 6], kind="bar")
>>> plot(data=[1, 3, 2, 2, 1, 4], kind="hist")

glyphx.plot3d

glyphx.plot3d(x=None, y=None, z=None, kind='scatter', data=None, title='', theme='default', auto_display=True, **kwargs)[source]

Unified 3D plotting function - the fast path to any 3D chart type.

Parameters:
  • x – Data arrays. For "surface" x and y are 1-D grid arrays and z is a 2-D matrix.

  • y – Data arrays. For "surface" x and y are 1-D grid arrays and z is a 2-D matrix.

  • z – Data arrays. For "surface" x and y are 1-D grid arrays and z is a 2-D matrix.

  • kind – "scatter", "surface", "line", "bar3d".

  • data – Alias for z (useful for surface: plot3d(data=Z_matrix))

  • title – Chart title.

  • theme – Theme name.

  • auto_display – Call .show() automatically.

  • **kwargs – Passed to the series constructor.

Returns:

Figure3D

Examples:

import numpy as np
from glyphx import plot3d

# 3D scatter
xs = np.random.randn(300)
plot3d(xs, np.random.randn(300), np.random.randn(300), kind="scatter")

# Surface
x = np.linspace(-3, 3, 40)
X, Y = np.meshgrid(x, x)
Z = np.sin(np.sqrt(X**2 + Y**2))
plot3d(x, x, Z, kind="surface", cmap="plasma", title="sin(r)")

Figure

class glyphx.Figure(width: int = 640, height: int = 480, padding: int = 50, title: str | None = None, theme: str | dict[str, Any] | None = None, rows: int = 1, cols: int = 1, auto_display: bool = True, legend: str | bool | None = 'outside-right', xscale: str = 'linear', yscale: str = 'linear', shared_x: bool = False)[source]

Bases: object

Central class for creating and rendering GlyphX visualizations.

Every mutating method returns self so calls can be chained:

fig = (
    Figure(width=900)
    .set_theme("dark")
    .set_title("Monthly Revenue")
    .add(LineSeries(months, revenue, label="Revenue"))
    .annotate("Peak", x="Oct", y=5400)
    .share("report.html")
)
Parameters:
  • width – Canvas width in pixels.

  • height – Canvas height in pixels.

  • padding – Inner margin between canvas edge and plot area.

  • title – Optional title rendered above all plots.

  • theme – Theme name (str) or custom theme dict.

  • rows – Number of subplot rows.

  • cols – Number of subplot columns.

  • auto_display – Auto-render when plot() or __repr__ is called.

  • legend – Legend position string, or False to suppress.

  • xscale – "linear" or "log".

  • yscale – "linear" or "log".

set_title(title: str) → Figure[source]

Set the figure title and return self for chaining.

set_theme(theme: str | dict[str, Any]) → Figure[source]

Apply a named theme or a custom dict and return self.

set_size(width: int, height: int) → Figure[source]

Resize the canvas and return self.

set_xlabel(label: str) → Figure[source]

Set the X-axis label and return self.

set_ylabel(label: str) → Figure[source]

Set the Y-axis label and return self.

aggregate_line(data=None, x=None, y=None, *, hue=None, estimator='mean', ci=95, n_boot=1000, n_std=1.0, band_alpha: float = 0.2, label: str | None = None, color: str | None = None, seed: int = 42) → Figure[source]

Plot the estimate of repeated measurements per x, with a CI band.

The equivalent of seaborn.lineplot(): hand it raw repeated-measures data – several y values per x, from several subjects, trials or runs – and it draws the mean per x with a bootstrapped confidence band, without a manual groupby first.

Parameters:
  • data – A DataFrame, or None to pass x/y as sequences.

  • x – Column name, or the x of each observation. Repeats are the point: every observation sharing an x forms one group.

  • y – Column name, or the observed value of each.

  • hue – Column to split into one line and band per group.

  • estimator – "mean", "median", "sum", "min", "max", "count", or a callable reducing an array to a scalar.

  • ci – Confidence level 0-100 for a bootstrap interval, "sd", "se", or None for the line alone.

  • n_boot – Bootstrap resamples when ci is a number.

  • n_std – Multiplier for the "sd" and "se" intervals.

  • band_alpha – Opacity of the band.

  • label – Series label. Defaults to the y column name.

  • color – Line colour. Defaults to the theme palette.

  • seed – Fixed, so redrawing the same data gives an identical band.

Returns:

self for chaining.

Example:

fig.aggregate_line(df, x="timepoint", y="score", hue="treatment")
add_controls(*, checkboxes: str | None = None, radio: str | None = None, search: str | None = None, title: str | None = None, reset: bool = True, labels: dict[str, str] | None = None, placeholder: str | None = None) → Figure[source]

Add filter controls beside the chart: checkboxes, radios, a search box.

Each control narrows what the chart shows, in the browser, with no server and no callback. Pass the name of a field and GlyphX reads the distinct values out of the data and builds one control per value – you do not enumerate them yourself.

A field is looked up wherever it lives: in a point’s meta, in its own data- attributes (percent on a pie, close on a candlestick), or as the series label via "series". Callers should not have to know which, since it differs per chart type.

Filters combine with AND, which is how a stack of controls reads: tick two regions and type a name, and you get that name within those regions. A running “Showing 12 of 40” sits underneath, announced to screen readers.

Parameters:
  • checkboxes – Field to build a checkbox per value from. All start ticked – a panel that hides the data on load looks broken.

  • radio – Field to build a radio group from. Gets an “All” option, or there is no way back to unfiltered.

  • search – Field a text box filters on, case-insensitive substring.

  • title – Heading for the panel.

  • reset – Include a “Show all” button. False to omit.

  • labels – Friendlier captions per control, keyed "checkboxes", "radio", "search". Defaults to the field name.

  • placeholder – Placeholder for the search box.

Returns:

self for chaining.

Only meaningful for .share() and .save() output, where the JavaScript is inlined.

Example:

fig.add(ScatterSeries(x, y, meta=records))
fig.add_controls(checkboxes="region", search="customer",
                 title="Filter")
add_detail_panel(fields: list[str] | None = None, *, title: str | None = None, empty: str | None = None) → Figure[source]

Show a panel that fills in with a point’s details when it is clicked.

The common case for selection events without writing any JavaScript. Pass meta=[...] to the series and the panel lists those values for whichever point is selected; click the same point again, or press Escape, and it goes back to its empty message.

Under the hood this is an ordinary listener on the public glyphx:select event, so it composes rather than competes: your own listeners still fire for the same click, and cross-filtering still applies.

Parameters:
  • fields – Metadata keys to show, in this order. "x", "y" and "label" are also accepted and fall back to the point’s own values. A key a given point lacks is skipped. Defaults to every key that point’s meta carries, or to x/y/series for a series plotted without metadata.

  • title – Heading for the panel.

  • empty – Text shown before anything is selected.

Returns:

self for chaining.

Only meaningful for .share() and .save() output, where the JavaScript is inlined.

Example:

fig.add(ScatterSeries(x, y, meta=records))
fig.add_detail_panel(["customer", "region"], title="Selected")
fig.share("chart.html")
enable_crossfilter(enabled: bool = True) → Figure[source]

Let clicks in this chart filter every other opted-in chart on the page.

Clicking a bar, point or slice dims everything in every participating chart that does not share its x value; clicking the same element again, or pressing Escape, clears the filter. The x value is the join key, since that is what data-x already carries on every drawn element.

Charts opt in individually, so a page can mix filtered charts with independent ones. The filtering runs entirely in the exported HTML – there is no server, no callback round-trip, and nothing leaves the page, which is what Dash or Streamlit are normally needed for.

Only meaningful for .share() and .save() output, where the JavaScript is inlined. A bare render_svg() string carries the marker but has no script to act on it.

Parameters:

enabled – False to opt this chart back out.

Returns:

self for chaining.

Example:

revenue = Figure().bar(months, revenue).enable_crossfilter()
costs   = Figure().bar(months, costs).enable_crossfilter()
SubplotGrid(1, 2).add(revenue, 0, 0).add(costs, 0, 1).save("d.html")
# clicking "Feb" in either chart dims every other month in both
set_y2label(label: str) → Figure[source]

Label the secondary (right-hand) Y axis, and return self.

Only drawn when the figure has series added with use_y2=True.

Example:

fig.add(LineSeries(x, price), )
fig.add(BarSeries(x, volume), use_y2=True)
fig.set_ylabel("Price ($)").set_y2label("Volume")
set_legend(position: str | bool | None) → Figure[source]

Set legend position (or False to hide) and return self.

add_axes(row: int = 0, col: int = 0) → Axes[source]

Create or retrieve the Axes at a grid position.

Parameters:
  • row (int) – Zero-based grid row.

  • col (int) – Zero-based grid column.

Returns:

The axes at that position, created on first access.

Return type:

Axes

Raises:

IndexError – If the position is outside the figure’s grid.

add(series: Any, use_y2: bool = False) → Figure[source]

Add a series to the figure.

Returns self so calls can be chained:

fig.add(LineSeries(...)).add(BarSeries(...)).show()
line(x, y, color=None, label=None, linestyle='solid', width=2, yerr=None, xerr=None, use_y2=False, **kwargs) → Figure[source]

Add a LineSeries. Returns self.

bar(x, y, color=None, label=None, bar_width=0.8, yerr=None, use_y2=False, **kwargs) → Figure[source]

Add a BarSeries. Returns self.

scatter(x, y, color=None, label=None, size=5, c=None, cmap='viridis', use_y2=False, **kwargs) → Figure[source]

Add a ScatterSeries. Returns self.

hist(data, bins=20, color=None, label=None, **kwargs) → Figure[source]

Add a HistogramSeries. Returns self.

box(data, categories=None, color=None, box_width=20, **kwargs) → Figure[source]

Add a BoxPlotSeries. Returns self.

heatmap(matrix, row_labels=None, col_labels=None, show_values=False, cmap=None, **kwargs) → Figure[source]

Add a HeatmapSeries. Returns self.

pie(values, labels=None, colors=None, **kwargs) → Figure[source]

Add a PieSeries. Returns self.

donut(values, labels=None, colors=None, **kwargs) → Figure[source]

Add a DonutSeries. Returns self.

area(x, y1, y2=0, color=None, alpha=0.25, line_width=1, label=None, **kwargs) → Figure[source]

Add a FillBetweenSeries. Returns self.

kde(data, filled=False, alpha=0.2, color=None, width=2, label=None, **kwargs) → Figure[source]

Add a KDESeries. Returns self.

ecdf(data, color=None, label=None, complementary=False, **kwargs) → Figure[source]

Add a ECDFSeries. Returns self.

raincloud(data, categories=None, seed=42, violin_width=40, **kwargs) → Figure[source]

Add a RaincloudSeries. Returns self.

candlestick(dates, open, high, low, close, label=None, **kwargs) → Figure[source]

Add a CandlestickSeries. Returns self.

waterfall(labels, values, show_values=True, **kwargs) → Figure[source]

Add a WaterfallSeries. Returns self.

treemap(labels, values, cmap='viridis', show_values=True, **kwargs) → Figure[source]

Add a TreemapSeries. Returns self.

bubble(x, y, size, color=None, c=None, cmap='viridis', alpha=0.65, min_radius=4, max_radius=40, labels=None, label=None, use_y2=False, **kwargs) → Figure[source]

Add a BubbleSeries. Returns self.

sunburst(labels, parents, values, cmap='viridis', **kwargs) → Figure[source]

Add a SunburstSeries. Returns self.

parallel_coords(data, axes, hue=None, cmap='viridis', alpha=0.45, **kwargs) → Figure[source]

Add a ParallelCoordinatesSeries. Returns self.

diverging_bar(categories, values, pos_color='#2563eb', neg_color='#dc2626', show_values=True, **kwargs) → Figure[source]

Add a DivergingBarSeries. Returns self.

stream(max_points=100, color=None, label=None, **kwargs) → Figure[source]

Add a StreamingSeries and return it.

Unlike other shorthand methods, this returns the series (not self) so callers can push data to it:

stream = fig.stream(max_points=100, label="Sensor")
stream.push(42.0)
axhspan(ymin: float, ymax: float, color: str = '#facc15', alpha: float = 0.2, label: str | None = None) → Figure[source]

Add a horizontal shaded band across the full chart width.

Equivalent to Matplotlib’s ax.axhspan(). Y values are in data space; the band is clipped to the plot area.

Parameters:
  • ymin – Lower Y bound (data units).

  • ymax – Upper Y bound (data units).

  • color – Fill color.

  • alpha – Fill opacity 0-1.

  • label – Optional legend label.

Returns:

self for chaining.

Example:

fig.axhspan(90, 110, color="#22c55e", alpha=0.15, label="Target range")
axvspan(xmin, xmax, color: str = '#a855f7', alpha: float = 0.2, label: str | None = None) → Figure[source]

Add a vertical shaded band across the full chart height.

Equivalent to Matplotlib’s ax.axvspan(). X values may be numeric data values or category label strings.

Parameters:
  • xmin – Left X bound (data units or category label).

  • xmax – Right X bound.

  • color – Fill color.

  • alpha – Fill opacity 0-1.

  • label – Optional legend label.

Returns:

self for chaining.

Example:

fig.axvspan("Jul", "Sep", color="#f59e0b", alpha=0.15, label="Q3")
set_xticks(ticks: list, labels: list | None = None) → Figure[source]

Set explicit X-axis tick positions (and optionally their labels).

Equivalent to Matplotlib’s ax.set_xticks() + ax.set_xticklabels().

Returns:

self for chaining.

Example:

fig.set_xticks([0, 25, 50, 75, 100])
fig.set_xticks([1, 6, 12], labels=["Jan", "Jun", "Dec"])
set_yticks(ticks: list, labels: list | None = None) → Figure[source]

Set explicit Y-axis tick positions (and optionally their labels).

Returns:

self for chaining.

Example:

fig.set_yticks([0, 500_000, 1_000_000], labels=["$0", "$500k", "$1M"])
set_tick_format(formatter) → Figure[source]

Apply a callable formatter to all numeric tick labels on both axes.

Equivalent to Matplotlib’s FuncFormatter.

Parameters:

formatter – Callable (value: float) -> str.

Returns:

self for chaining.

Example:

fig.set_tick_format(lambda v: f"${v:,.0f}")
fig.set_tick_format(lambda v: f"{v:.1%}")
inset_axes(x: float, y: float, width: float, height: float, *, theme=None, padding: float | None = None, background: str | None = None, show_grid: bool = True)[source]

Add a small panel drawn on top of the main plot area.

Useful for a zoomed detail view of a dense region, or an overview thumbnail alongside a zoomed main chart. Returns a fresh Axes with its own independent scales – add series to it with add_series(), exactly as with add_axes() for subplot grids.

Position and size are fractions of the figure canvas, not of the plot area, so inset_axes(0.6, 0.1, 0.35, 0.3) always lands in the top-right regardless of how padding changes.

Insets render after the main series and in the order added, so a later inset overlaps an earlier one. They are drawn over an opaque background by default so the parent’s grid lines do not show through.

Parameters:
  • x – Left edge, 0-1 fraction of figure width.

  • y – Top edge, 0-1 fraction of figure height.

  • width – Panel width, 0-1 fraction of figure width.

  • height – Panel height, 0-1 fraction of figure height.

  • theme – Theme name or dict. Defaults to the parent’s theme.

  • padding – Inner padding in px. Defaults to a value scaled to the panel size, since the figure default of 50 would consume most of a small inset.

  • background – Panel fill. Defaults to the theme background. Pass "none" for a transparent inset.

  • show_grid – Draw grid lines inside the panel.

Returns:

the inset’s axes.

Return type:

Axes

Raises:

ValueError – If the panel is not within the canvas, or has non-positive size.

Example:

fig = Figure().line(x, y)
inset = fig.inset_axes(0.6, 0.15, 0.35, 0.3)
inset.add_series(LineSeries(x[:20], y[:20]))
set_tick_wrap(enabled: bool = True) → Figure[source]

Wrap long X-axis tick labels onto a second line instead of rotating.

Parameters:

enabled – True to wrap, False to restore auto-rotation.

Returns:

self for chaining.

Example:

fig.bar(["Product Engineering", "Sales & Marketing"], [10, 20])
fig.set_tick_wrap()
set_minor_ticks(n: int = 4) → Figure[source]

Draw minor tick subdivisions between each pair of major ticks.

Parameters:

n – Number of minor ticks between major ticks.

Returns:

self for chaining.

Example:

fig.set_minor_ticks(4)
set_spine_visible(left: bool = True, right: bool = True, top: bool = False, bottom: bool = True) → Figure[source]

Control axis spine (border line) visibility.

Equivalent to Matplotlib’s ax.spines[...].set_visible().

Parameters:
  • left – Left (Y) spine.

  • right – Right (Y2) spine.

  • top – Top spine.

  • bottom – Bottom (X) spine.

Returns:

self for chaining.

Example:

fig.set_spine_visible(top=False, right=False)   # clean minimal look
text(x: float, y: float, s: str, color: str = '#333', font_size: int = 12, anchor: str = 'middle', transform: str = 'canvas') → Figure[source]

Add free-form text anywhere on the canvas.

Equivalent to Matplotlib’s fig.text() / ax.text().

Parameters:
  • x – X position. When transform='canvas' this is a fraction of canvas width (0-1). When transform='data' it is a data-space value.

  • y – Y position. Canvas fraction (0 = top, 1 = bottom) or data-space value depending on transform.

  • s – Text string. Use $...$ for math (rendered via MathJax when the chart is opened in a browser).

  • color – Font color.

  • font_size – Font size in points.

  • anchor – SVG text-anchor: "start", "middle", "end".

  • transform – "canvas" (0-1 fractions) or "data" (data coords).

Returns:

self for chaining.

Example:

fig.text(0.5, 0.02, "Source: World Bank", font_size=9, color="#888")
fig.text(0.5, 0.5, "$R^2 = 0.95$", font_size=14)
supxlabel(label: str, font_size: int = 13, color: str | None = None) → Figure[source]

Set a shared X-axis label below all subplots.

Equivalent to Matplotlib’s fig.supxlabel(). Useful when all subplots in a grid share the same X-axis meaning.

Parameters:
  • label – Label text.

  • font_size – Font size.

  • color – Text color (defaults to theme text color).

Returns:

self for chaining.

supylabel(label: str, font_size: int = 13, color: str | None = None) → Figure[source]

Set a shared Y-axis label beside all subplots.

Equivalent to Matplotlib’s fig.supylabel().

Parameters:
  • label – Label text.

  • font_size – Font size.

  • color – Text color (defaults to theme text color).

Returns:

self for chaining.

to_vega_lite(path: str | None = None, **kwargs) → dict[source]

Convert this figure to a Vega-Lite v5 specification.

The spec can be saved as a .vl.json file, embedded in Observable notebooks, or rendered with altair. No Python plotting library currently produces Vega-Lite output.

Parameters:

path – If given, write the spec to this JSON file.

Returns:

Vega-Lite v5 specification dict.

Example:

spec = fig.to_vega_lite()
fig.to_vega_lite("chart.vl.json")  # saves to file
regplot(data=None, x=None, y=None, x_vals=None, y_vals=None, **kwargs) → Figure[source]

Add a regression plot series to this figure. Returns self.

choropleth(geojson, data, key='name', cmap='viridis', **kwargs) → Figure[source]

Add a ChoroplethSeries. Returns self.

gantt(tasks: list, group_colors: dict | None = None, cmap: str = 'viridis', bar_height: int = 20, show_today: bool = True, **kwargs) → Figure[source]

Add a GanttSeries. Returns self.

stacked_bar(x: list, series: dict, normalize: bool = False, colors: list | None = None, bar_width: float = 0.75, **kwargs) → Figure[source]

Add a StackedBarSeries. Returns self.

bump(x: list, rankings: dict, colors: list | None = None, show_labels: bool = True, **kwargs) → Figure[source]

Add a BumpChartSeries. Returns self.

sparkline(data: list, color: str = '#2563eb', kind: str = 'line', fill: bool = True, label: str | None = None, **kwargs) → Figure[source]

Add a SparklineSeries. Returns self.

vline(x, color='#888', width=1, linestyle='dashed', label=None) → Figure[source]

Draw a vertical reference line at data coordinate x. Returns self.

hline(y, color='#888', width=1, linestyle='dashed', label=None) → Figure[source]

Draw a horizontal reference line at data coordinate y. Returns self.

copy() → Figure[source]

Return a deep copy of this figure.

Useful for creating small variations without re-building from scratch:

base = Figure().add(LineSeries(x, y))
dark = base.copy().set_theme("dark")
light = base.copy().set_theme("default")

Series, annotations, and settings are all duplicated.

annotate(text: str, x: float, y: float, color: str = '#333', font_size: int = 12, anchor: str = 'start', arrow: bool = False, ax_x: float | None = None, ax_y: float | None = None) → Figure[source]

Add a text annotation in data-space coordinates.

Returns self for chaining.

Parameters:
  • text – Label text.

  • x – Data-space X coordinate of the annotation point.

  • y – Data-space Y coordinate.

  • color – Text and arrow colour.

  • font_size – Label font size in points.

  • anchor – SVG text-anchor ("start", "middle", "end").

  • arrow – Draw a small leader line from text to point.

  • ax_x – Arrow tail X pixel offset (default −8).

  • ax_y – Arrow tail Y pixel offset (default −8).

to_alt_text() → str[source]

Generate a plain-English description of this figure for screen readers.

Returns:

A human-readable string suitable for aria-label or <desc>.

render_svg(viewbox: bool = False) → str[source]

Render the complete figure and return an SVG string.

The SVG includes: - role="img" and aria-labelledby on the root element - <title> and <desc> ARIA landmark children - tabindex="0" on every interactive data point

Returns:

Complete SVG document markup.

to_html_fragment(interactive: bool = True) → str[source]

Render an HTML fragment suitable for embedding in a page.

Unlike save() with an .html path, this returns a fragment with no <html> wrapper, so it can be dropped into a notebook output cell, a Jinja template, or a dashboard.

Parameters:

interactive (bool) – Attach tooltips and legend toggling.

Returns:

An HTML fragment containing the chart.

Return type:

str

show() → Figure[source]

Render and display the figure. Returns self for chaining.

render_responsive(dark_theme: str | None = None) → str[source]

Render an SVG that responds to the OS dark-mode preference.

The output uses CSS custom properties (--glyphx-bg, etc.). When the user switches dark mode, the chart recolours without any Python re-render – a capability none of the three competitors have.

Parameters:

dark_theme – GlyphX theme name for dark mode (default 'dark').

Returns:

Complete <svg> string with embedded CSS variable block.

Example:

svg = fig.render_responsive(dark_theme='dark')
fig.save('chart.svg')          # handles encoding and the XML declaration
# Open in a browser -- switches colours with the OS setting
save(filename: str = 'glyphx_output.svg', dpi: int = 96, backend: str | None = None) → Figure[source]

Save the rendered figure to disk.

.svg and .html need no extra packages. .png, .jpg, .webp, and .pdf use whichever rendering backend is installed (see glyphx.export); .pptx needs the pptx extra:

pip install "glyphx[export]"    # PNG/JPG/WEBP via resvg
pip install "glyphx[cairo]"     # adds PDF
pip install "glyphx[pptx]"      # PowerPoint
Parameters:
  • filename – Output path. Extension determines the format.

  • dpi – Output resolution for raster formats. Default 96; use 192 for retina or 300 for print. No effect on SVG, HTML, or PDF.

  • backend – Force a specific export backend (“resvg”, “cairosvg”, or “playwright”). Defaults to the best available.

Returns:

self for chaining.

Example:

fig.save("chart.png", dpi=192)   # crisp on retina displays
fig.save("chart.pdf")            # vector, for print
tight_layout() → Figure[source]

Auto-adjust padding to prevent label clipping and overlap.

For single-axis figures, delegates to tight_layout(). For subplot grids, applies constrained_layout() which aligns the left edges of all subplot cells so tick labels never overlap across rows.

Returns self for chaining.

constrained_layout() → Figure[source]

Align subplot cells so their plot areas share a common left edge.

Equivalent to Matplotlib’s constrained_layout=True. Computes the widest Y-tick label across all cells in each column, then sets a uniform left padding for all cells in that column so the actual data area (to the right of the Y-axis) is flush.

Returns self for chaining.

Example:

fig = Figure(rows=2, cols=2, width=900, height=600)
# ... add_axes and add_series ...
fig.constrained_layout()   # aligns all subplot left edges
add_stat_annotation(x1: Any, x2: Any, p_value: float = 0.05, label: str | None = None, style: str = 'stars', color: str = '#222', y_offset: float = 0.0) → Figure[source]

Add a significance bracket between two groups.

Draws *** / ** / * / ns above the bracket based on p_value. Works with both numeric and categorical X axes.

Parameters:
  • x1 – First group (label or numeric X value).

  • x2 – Second group.

  • p_value – Statistical p-value.

  • label – Override the auto-generated significance label.

  • style – "stars" or "numeric".

  • color – Bracket and text color.

  • y_offset – Extra upward shift in pixels (stack multiple brackets).

Returns:

self for chaining.

enable_crosshair() → Figure[source]

Enable the synchronized crosshair on the next share() / show() call.

The crosshair draws a vertical line across all GlyphX charts on the same HTML page and highlights the nearest data point in each.

Returns self.

share(filename: str | None = None, title: str | None = None) → str[source]

Generate a fully self-contained, shareable HTML document.

The output embeds all JavaScript inline – no CDN, no server, works offline. Pass filename to also write it to disk.

Returns:

Complete HTML document string.

plot() → Figure[source]

Shortcut for show() respecting auto_display. Returns self.

Figure3D

class glyphx.Figure3D(width: int = 900, height: int = 650, title: str = '', theme: str = 'default', azimuth: float = 45.0, elevation: float = 30.0, xlabel: str = 'X', ylabel: str = 'Y', zlabel: str = 'Z')[source]

Bases: object

3D chart canvas.

Renders to self-contained HTML with interactive Three.js WebGL, or falls back to an orthographic SVG for static export.

Parameters:
  • width – HTML canvas width ("100%" or pixel value).

  • height – HTML canvas height.

  • title – Chart title.

  • theme – Theme name (same as Figure).

  • azimuth – Initial camera azimuth in degrees (SVG and HTML).

  • elevation – Initial camera elevation in degrees (SVG only).

  • xlabel – X-axis label.

  • ylabel – Y-axis label.

  • zlabel – Z-axis label.

Example:

from glyphx import Figure3D
from glyphx.surface3d import Surface3DSeries
import numpy as np

x = np.linspace(-3, 3, 50)
y = np.linspace(-3, 3, 50)
X, Y = np.meshgrid(x, y)
Z = np.sin(np.sqrt(X**2 + Y**2))

fig = Figure3D(title="sin(r)", theme="dark")
fig.add(Surface3DSeries(x, y, Z, cmap="plasma"))
fig.show()
add(series: Any) → Figure3D[source]

Add a 3D series and return self for chaining.

scatter(x, y, z, color='#2563eb', c=None, cmap='viridis', size=5, label=None, alpha=0.85) → Figure3D[source]

Add a Scatter3DSeries. Returns self.

surface(x, y, z, cmap='viridis', alpha=0.9, wireframe=True) → Figure3D[source]

Add a Surface3DSeries. Returns self.

line3d(x, y, z, color='#dc2626', width=2, linestyle='solid', label=None) → Figure3D[source]

Add a Line3DSeries. Returns self.

bar3d(x, y, z, cmap='viridis', alpha=0.85, label=None) → Figure3D[source]

Add a Bar3DSeries. Returns self.

set_xlabel(label: str) → Figure3D[source]

Label the X axis and return self.

set_ylabel(label: str) → Figure3D[source]

Label the Y axis and return self.

set_zlabel(label: str) → Figure3D[source]

Label the Z axis and return self.

set_view(azimuth: float, elevation: float) → Figure3D[source]

Set the initial camera angle for SVG output.

render_svg() → str[source]

Render a static orthographic SVG projection.

render_html() → str[source]

Render a complete interactive HTML document with Three.js.

show() → Figure3D[source]

Render and display. Uses Jupyter if available, else browser.

save(filename: str = 'glyphx3d.html') → Figure3D[source]

Save the figure to disk.

.html gives the interactive Three.js WebGL viewer (default) .svg gives a static orthographic SVG

Returns self for chaining.

Axes

class glyphx.layout.Axes(width=600, height=400, padding=50, show_grid=True, theme=None, legend=None, xscale='linear', yscale='linear', precision=2)[source]

Bases: object

Manages axis scaling, tick rendering, and series layout within a plot.

Supports: - Dual Y-axes (primary and secondary) - Categorical X-axis labels - Linear and log-scale axes - Configurable tick counts and grid lines - Axis title / xlabel / ylabel labels

width

Plot area width in pixels.

Type:

int

height

Plot area height in pixels.

Type:

int

padding

Space from canvas edge to the plot area.

Type:

int

show_grid

Whether to render background grid lines.

Type:

bool

theme

Color and font styling dictionary.

Type:

dict

xscale

"linear" or "log".

Type:

str

yscale

"linear" or "log".

Type:

str

series

Series on the primary Y-axis.

Type:

list

y2_series

Series on the secondary Y-axis.

Type:

list

add(series, use_y2=False)[source]

Proxy for add_series; allows Figure/Axes to share call syntax.

add_series(series, use_y2=False)[source]

Register a series on the primary or secondary Y-axis.

Parameters:
  • series (BaseSeries) – Any series with .x and .y attributes.

  • use_y2 (bool) – If True, bind to the right-hand Y-axis.

axhspan(ymin: float, ymax: float, color: str = '#ffff00', alpha: float = 0.2, label: str | None = None) → Axes[source]

Add a horizontal shaded band spanning the full plot width.

The band is drawn in data-space Y coordinates. Values outside the current Y domain are clipped to the plot boundary.

Parameters:
  • ymin – Lower Y data value of the band.

  • ymax – Upper Y data value of the band.

  • color – Fill color.

  • alpha – Fill opacity 0–1.

  • label – Optional legend label.

Returns:

self for chaining.

Example:

ax.axhspan(90, 110, color="#22c55e", alpha=0.15, label="Normal range")
axis_metadata() → str[source]

The plot rectangle and data domains, as data- attributes.

Zooming rewrites the SVG’s viewBox, which crops the axis labels along with everything else – they are static text positioned for the original domain. Publishing the geometry lets zoom.js map the visible region back to data coordinates and redraw the ticks for whatever is actually on screen.

Returns:

Attribute string, or "" when there is no domain yet.

Return type:

str

axvspan(xmin, xmax, color: str = '#a855f7', alpha: float = 0.2, label: str | None = None) → Axes[source]

Add a vertical shaded band spanning the full plot height.

xmin / xmax may be numeric data values or category label strings (resolved to their numeric position).

Parameters:
  • xmin – Left X data value of the band.

  • xmax – Right X data value of the band.

  • color – Fill color.

  • alpha – Fill opacity 0–1.

  • label – Optional legend label.

Returns:

self for chaining.

Example:

ax.axvspan("Jul", "Sep", color="#f59e0b", alpha=0.15, label="Summer")
compute_domain(series_list)[source]

Compute (x_domain, y_domain) from a list of series.

Categorical string X-values are converted to numeric indices. The conversion is stored on the series as ._numeric_x so the original series.x is never mutated.

When multiple series each carry different categories (e.g. one bar per group from a groupby aggregation), all unique categories are merged into a single global ordering so each gets a distinct x position.

Parameters:

series_list (list) – Series objects with .x and .y.

Returns:

(x_domain, y_domain) each as (min, max) or

(None, None) if no valid data is found.

Return type:

tuple

finalize()[source]

Compute all scale functions after series have been registered.

Must be called before any rendering method.

render_axes()[source]

Render X, Y, and (if y2_series exist) Y2 axis lines plus labels.

Returns:

SVG elements for axes.

Return type:

str

render_grid(ticks=5)[source]

Render tick marks, grid lines, and numeric labels.

Categorical X-axes replace numeric labels with the original category names.

Parameters:

ticks (int) – Number of major ticks per axis.

Returns:

SVG elements for grid and tick labels.

Return type:

str

set_minor_ticks(n: int, length: float = 2.0) → Axes[source]

Draw n minor tick subdivisions between each pair of major ticks.

Parameters:
  • n – Number of minor ticks between major ticks (e.g. 4 gives 5 equal sub-intervals).

  • length – Minor tick length in pixels.

Returns:

self for chaining.

Example:

ax.set_minor_ticks(4)   # quarterly subdivisions on annual axis
set_spine_visible(left: bool = True, right: bool = True, top: bool = False, bottom: bool = True) → Axes[source]

Control which axis spines (border lines) are visible.

By default the top spine is hidden (matches Matplotlib’s ax.spines best-practice for clean scientific plots).

Parameters:
  • left – Show left (Y) spine.

  • right – Show right (Y2) spine.

  • top – Show top spine.

  • bottom – Show bottom (X) spine.

Returns:

self for chaining.

Example:

ax.set_spine_visible(top=False, right=False)  # clean minimal look
set_tick_format(formatter) → Axes[source]

Apply a callable formatter to all numeric tick labels.

The formatter receives a float and must return a string. It applies to both X and Y axes (use set_xticklabels / set_yticklabels to override one axis independently).

Parameters:

formatter – Callable (value: float) -> str.

Returns:

self for chaining.

Example:

ax.set_tick_format(lambda v: f"${v:,.0f}")
ax.set_tick_format(lambda v: f"{v:.1%}")
set_tick_length(length: float) → Axes[source]

Set the major tick mark length in pixels (default: 4).

set_tick_wrap(enabled: bool = True) → Axes[source]

Wrap long X-axis tick labels onto a second line instead of rotating.

Rotation is GlyphX’s automatic default once labels would overlap at horizontal angle (see _should_rotate_xlabels); this is an explicit alternative for when rotated text is harder to read than two short lines – category names and month/quarter labels are the common case. The two are mutually exclusive: enabling wrap suppresses auto-rotation for this axes.

Parameters:

enabled – True to wrap, False to restore the default (auto-rotate when labels would otherwise overlap).

Returns:

self for chaining.

Example:

ax.set_tick_wrap()   # "Product Engineering" wraps onto two lines
set_xticklabels(labels: list[str]) → Axes[source]

Override X-tick display strings without changing positions.

set_xticks(ticks: list, labels: list[str] | None = None) → Axes[source]

Set explicit X-axis tick positions.

Parameters:
  • ticks – List of data-space positions where ticks should appear.

  • labels – Optional list of strings to display instead of formatted values. Must be the same length as ticks.

Returns:

self for chaining.

Example:

ax.set_xticks([0, 25, 50, 75, 100])
ax.set_xticks([1, 6, 12], labels=["Jan", "Jun", "Dec"])
set_y2label(label: str) → Axes[source]

Label the secondary (right-hand) Y axis.

Rendered rotated on the right edge, mirroring ylabel. Only drawn when the axes actually has y2_series, so setting it on a single-axis chart is a harmless no-op.

Parameters:

label – Text for the right-hand axis.

Returns:

self for chaining.

set_yticklabels(labels: list[str]) → Axes[source]

Override Y-tick display strings without changing positions.

set_yticks(ticks: list, labels: list[str] | None = None) → Axes[source]

Set explicit Y-axis tick positions.

Parameters:
  • ticks – List of data-space positions.

  • labels – Optional display labels (same length as ticks).

Returns:

self for chaining.

Example:

ax.set_yticks([0, 1_000_000, 2_000_000], labels=["$0", "$1M", "$2M"])
tight_layout() → Axes[source]

Auto-adjust padding so tick labels, axis labels, and titles don’t clip or overlap.

Estimates pixel widths of the longest tick labels and increases self.padding accordingly. Also triggers auto-rotation of crowded X-axis labels.

Returns self for chaining.

layout.grid

glyphx.layout.grid(figures, rows=1, cols=1, gap=20)[source]

Arrange multiple Figure instances in a grid and return a single HTML page.

Parameters:
  • figures (list[Figure]) – GlyphX Figure objects to arrange.

  • rows (int) – Number of rows in the grid.

  • cols (int) – Number of columns.

  • gap (int) – Pixel margin around each subplot.

Returns:

Full HTML document with all SVGs embedded.

Return type:

str

SubplotGrid

class glyphx.figure.SubplotGrid(rows: int, cols: int)[source]

Bases: object

Standalone 2-D grid for laying out existing Figure objects into one page.

Example:

sg = SubplotGrid(2, 2)
sg.add(fig_revenue, 0, 0)
sg.add(fig_costs,   0, 1)
html = sg.render()
with open("dashboard.html", "w", encoding="utf-8") as fh:
    fh.write(html)
Parameters:
  • rows – Number of rows.

  • cols – Number of columns.

add(figure: Figure, row: int, col: int) → SubplotGrid[source]

Place a Figure at a grid position. Returns self.

add_axes(row: int, col: int, figure: Figure) → SubplotGrid[source]

Alias for add() kept for backward compatibility.

render(gap: int = 20) → str[source]

Render all figures into a self-contained HTML page.

Returns:

Full HTML document string.

save(filename: str = 'glyphx_dashboard.html', dpi: int = 96, backend: str | None = None) → SubplotGrid[source]

Save the grid to disk.

.html writes the same composite page render() produces. .pptx puts each figure on its own slide, in row-major order, titled from the figure’s own title if it set one – this is the multi-slide export the standalone SubplotGrid had no way to do before, since Figure.save() only ever knew about one figure. .svg, .png, .jpg and .pdf are not supported: those formats have no multi-page notion, and the grid’s cells sit in separate <svg> documents rather than one combined one, so there is no single image to rasterise. Save each Figure in the grid individually for those formats.

Parameters:
  • filename – Output path. Extension selects the format.

  • dpi – Forwarded to the PNG rasteriser that PPTX export uses internally. No effect on .html.

  • backend – Unused; accepted for signature parity with Figure.save().

Returns:

self for chaining.

Raises:

ValueError – For an unsupported extension.

Example:

sg = SubplotGrid(2, 2)
sg.add(revenue_fig, 0, 0).add(costs_fig, 0, 1)
sg.save("quarterly_review.pptx")   # one slide per figure

Core Series

class glyphx.series.BaseSeries(x, y=None, color=None, label=None, title=None)[source]

Bases: object

Base class for all GlyphX series.

x

X-axis values.

Type:

list

y

Y-axis values (None for chart types that don’t use axes).

Type:

list

color

Primary color for this series.

Type:

str

label

Legend / tooltip label.

Type:

str | None

title

Per-series subtitle drawn above the chart area.

Type:

str | None

css_class

CSS class applied to interactive SVG elements.

Type:

str

class glyphx.series.LineSeries(x, y, color=None, label=None, legend=None, linestyle='solid', width=2, title=None, yerr=None, xerr=None, markers='auto', threshold=None)[source]

Bases: BaseSeries

Line chart series with optional error bars.

Parameters:
  • x (list) – X values.

  • y (list) – Y values.

  • color (str | None) – Line/point color.

  • label (str | None) – Legend label.

  • linestyle (str) – "solid", "dashed", "dotted", or "longdash".

  • width (int) – Stroke width in pixels.

  • title (str | None) – Chart subtitle.

  • yerr (list | None) – Symmetric Y error bar values (same length as y).

  • xerr (list | None) – Symmetric X error bar values (same length as x).

  • markers (bool | str) – Draw a hoverable circle per data point. "auto" (default) draws them only when the series has at most MARKER_LIMIT points, since one DOM node per point dominates document size and stalls the browser on dense series.

MARKER_LIMIT = 400

Above this many points, “auto” markers are suppressed. 400 is where Chrome started dropping frames for me on a 2019 laptop; it is a guess, not a measurement anyone should rely on.

to_svg(ax, use_y2=False)[source]

Draw the line, thinning the data first if it has more points than pixels.

An M4 pass preserves the per-column extremes, then LTTB thins what remains, so a million-point series renders in the time a few thousand would without losing spikes. What happened is recorded on last_downsample_info for anyone who needs to check.

class glyphx.series.BarSeries(x, y, color=None, label=None, legend=None, bar_width=0.8, title=None, yerr=None)[source]

Bases: BaseSeries

Bar chart series with optional error bars.

Parameters:
  • x – X-axis labels/values.

  • y – Bar heights.

  • color – Fill color.

  • label – Legend label.

  • bar_width (float) – Fraction of available slot width (0–1).

  • title – Per-series subtitle.

  • yerr – Symmetric Y error values.

to_svg(ax, use_y2=False)[source]

Draw the bars, taking their width from the axes’ own category spacing.

Width comes from scale_x(start + 1) - scale_x(start) rather than dividing the plot area by this series’ category count, so bars stay aligned when several series share an axes and cover different categories.

class glyphx.series.ScatterSeries(x, y, color=None, label=None, legend=None, size=5, marker='circle', title=None, c=None, cmap='viridis', sizes=None, style=None, style_order=None, threshold=None, meta=None)[source]

Bases: BaseSeries

Scatter plot with configurable marker type, size, and continuous color encoding.

Parameters:
  • marker (str) – "circle" or "square".

  • size (int) – Marker radius / half-width in pixels.

  • c (list | None) – Per-point values for color encoding. When set, each point’s color is determined by mapping this value through cmap. Overrides color.

  • cmap (str) – Colormap name (default: "viridis"). See list_colormaps() for options.

to_svg(ax, use_y2=False)[source]

Draw the points, voxel-thinning first when there are too many to see.

Thinning keeps one point per occupied grid cell and tracks which original rows survived, so tooltips still report the right underlying values.

class glyphx.series.HistogramSeries(data, bins=10, color=None, label=None, hue=None, hue_colors=None, cmap='viridis', alpha=0.65)[source]

Bases: BaseSeries

Frequency distribution histogram.

Parameters:
  • data (array-like) – Raw numeric values.

  • bins (int) – Number of histogram bins.

  • color – Bar fill color.

  • label – Legend label.

to_svg(ax, use_y2=False)[source]

Draw one bar per bin, splitting by hue when a hue column was given.

class glyphx.series.BoxPlotSeries(data, categories=None, color='#1f77b4', label=None, box_width=20, width=None, hue=None, hue_colors=None, cmap='viridis')[source]

Bases: BaseSeries

Box-and-whisker plot.

Supports a single array (one box) or a list of arrays (multiple boxes drawn at categorical X positions).

Parameters:
  • data (array-like or list of arrays) – Input data.

  • categories (list | None) – Category labels for multiple boxes.

  • color – Box fill color.

  • label – Legend / tooltip label.

  • box_width (int) – Pixel width of each box.

to_svg(ax, use_y2=False)[source]

Draw each box with its whiskers, median line, and any outlier points.

class glyphx.series.HeatmapSeries(matrix, cmap=None, row_labels=None, col_labels=None, show_values=False, *, vmin=None, vmax=None, center=None, **kwargs)[source]

Bases: BaseSeries

Heatmap for 2-D matrix data with a color-scale legend.

Parameters:
  • matrix (list[list[float]]) – 2-D data grid (rows × cols).

  • cmap (list[str] | None) – Ordered list of hex colors (low → high).

  • row_labels (list | None) – Row labels shown on the Y-axis.

  • col_labels (list | None) – Column labels shown on the X-axis.

  • show_values (bool) – Render numeric value inside each cell.

to_svg(ax, use_y2=False)[source]

Draw the cells, the colorbar, and the per-cell values if enabled.

class glyphx.series.PieSeries(values, labels=None, colors=None, title=None, label_position='outside', radius=None)[source]

Bases: BaseSeries

Pie chart series.

Parameters:
  • values (list) – Numeric slice sizes.

  • labels (list | None) – Label for each slice.

  • colors (list | None) – Color per slice (cycles if fewer than slices).

  • title (str | None) – Chart title rendered above the pie.

  • label_position (str) – "outside" (default) or "inside".

  • radius (float) – Explicit radius in pixels; auto-computed if None.

to_svg(ax=None)[source]

Draw the slices as arc paths, with labels placed inside or outside.

class glyphx.series.DonutSeries(values, labels=None, colors=None, show_labels=True, hover_animate=True, inner_radius_frac=0.5)[source]

Bases: BaseSeries

Donut (annular pie) chart series.

Parameters:
  • values (list) – Numeric slice sizes.

  • labels (list | None) – Label per slice; auto-generated if None.

  • colors (list | None) – Color per slice.

  • show_labels (bool) – Draw callout labels outside the ring.

  • hover_animate (bool) – Add glyphx-point class for CSS hover.

  • inner_radius_frac (float) – Hole radius as fraction of outer radius.

to_svg(ax=None)[source]

Draw the ring segments, plus the centre label if one is set.

Statistical Series

class glyphx.ecdf.ECDFSeries(data: list | ndarray, color: str | None = None, label: str | None = None, show_points: bool = False, point_radius: float = 3.0, line_width: float = 2.0, complementary: bool = False)[source]

Bases: BaseSeries

Empirical CDF rendered as a step function.

Parameters:
  • data – Raw observations (1-D array-like).

  • color – Line color.

  • label – Legend label.

  • show_points – Draw a circle at each step.

  • point_radius – Radius of step-point circles.

  • line_width – Stroke width of the step line.

  • complementary – If True, plot 1 − ECDF (survival function).

to_svg(ax: AxesLike, use_y2: bool = False) → str[source]

Render the ECDF step function as SVG.

class glyphx.raincloud.RaincloudSeries(data: list, categories: list[str] | None = None, colors: list[str] | None = None, jitter_width: float = 18.0, point_radius: float = 3.0, violin_width: float = 40.0, box_width: float = 10.0, seed: int = 42, label: str | None = None)[source]

Bases: object

Raincloud plot: jitter + half-violin + box for each category.

Parameters:
  • data – List of 1-D arrays, one per category.

  • categories – Category labels (same length as data).

  • colors – Per-category colors; cycles if fewer than categories.

  • jitter_width – Max horizontal pixel displacement of raw points.

  • point_radius – Radius of each jittered data point.

  • violin_width – Max pixel width of the half-violin.

  • box_width – Pixel width of the IQR box.

  • seed – Random seed for reproducible jitter.

  • label – Legend label for the series.

to_svg(ax: AxesLike, use_y2: bool = False) → str[source]

Draw each group as a half violin, a box, and its jittered points.

class glyphx.violin_plot.ViolinPlotSeries(data, positions=None, color='#1f77b4', width=50, show_median=True, show_box=True, label=None, hue=None, hue_colors=None, cmap='viridis', categories=None)[source]

Bases: object

Violin plot: a KDE-smoothed distribution mirrored on both sides of a centre line.

Requires no external dependencies beyond NumPy.

Parameters:
  • data (list of array-like) – One array per category.

  • positions (list | None) – X-axis positions for each violin.

  • color (str) – Fill/stroke color.

  • width (int) – Maximum pixel half-width of the violin body.

  • show_median (bool) – Draw a horizontal median marker.

  • show_box (bool) – Overlay a thin IQR box inside the violin.

  • label (str | None) – Legend label.

to_svg(ax, use_y2=False)[source]

Draw each violin as a mirrored density curve, with its inner box.

class glyphx.kde.KDESeries(data, n_points: int = 200, filled: bool = False, alpha: float = 0.2, color: str = '#1f77b4', width: int = 2, label: str | None = None, bw_method: str | float = 'silverman')[source]

Bases: BaseSeries

Smooth kernel density estimate curve (no scipy required).

Parameters:
  • data – 1-D array of raw observations.

  • n_points – Number of evaluation points along the curve (default 200).

  • filled – If True, shade the area under the curve.

  • alpha – Fill opacity when filled=True (default 0.20).

  • color – Line (and fill) color.

  • width – Line stroke width in pixels.

  • label – Legend label.

  • bw_method – Bandwidth: "silverman" (default) or a positive float multiplier applied to the Silverman estimate.

to_svg(ax: AxesLike, use_y2: bool = False) → str[source]

Draw the density curve, filled beneath if that was asked for.

class glyphx.fill_between.FillBetweenSeries(x, y1, y2, color: str = '#1f77b4', alpha: float = 0.25, line_width: int = 1, label: str | None = None, line_color: str | None = None)[source]

Bases: BaseSeries

Shaded area between two Y arrays (or between a line and a baseline).

Parameters:
  • x – X values (shared by both bounds).

  • y1 – Lower bound Y values, or the line when y2 is a scalar.

  • y2 – Upper bound Y values. Pass a scalar (e.g. 0) to shade between y1 and a horizontal baseline.

  • color – Fill and line color (default: "#1f77b4").

  • alpha – Fill opacity 0–1 (default: 0.25).

  • line_width – Width of the boundary lines in pixels. 0 hides them.

  • label – Legend label.

  • line_color – Color for boundary lines. Defaults to color.

to_svg(ax: AxesLike, use_y2: bool = False) → str[source]

Draw the band as one closed path: y1 forward, then y2 back.

class glyphx.stat_annotation.StatAnnotation(x1: Any, x2: Any, p_value: float = 0.05, label: str | None = None, style: str = 'stars', color: str = '#222', line_width: float = 1.5, tip_len: float = 8.0, y_offset: float = 0.0)[source]

Bases: object

Significance bracket drawn between two groups on a chart.

x1

First group label or numeric X value.

x2

Second group label or numeric X value.

p_value

The p-value for the test between the two groups.

label

Override text (defaults to significance stars).

style

"stars" or "numeric".

color

Line and text color.

line_width

Bracket stroke width.

tip_len

Vertical tick length at each bracket end.

y_offset

Extra upward pixel shift (stacks multiple brackets).

to_svg(ax: Any) → str[source]

Render the bracket into SVG.

Parameters:

ax – A finalised Axes instance.

Returns:

SVG markup string, or empty string if the axes have no scale.

glyphx.stat_annotation.pvalue_to_label(p: float, style: str = 'stars') → str[source]

Convert a p-value to a display label.

Parameters:
  • p – The p-value (0–1).

  • style – "stars" (default) or "numeric".

Returns:

"***", "**", "*", "ns" - or the formatted number.

Financial Series

class glyphx.candlestick.CandlestickSeries(dates: list, open: list[float], high: list[float], low: list[float], close: list[float], up_color: str = '#26a641', down_color: str = '#d73027', candle_width: float = 0.6, label: str | None = None)[source]

Bases: BaseSeries

OHLC candlestick chart.

Parameters:
  • dates – X-axis labels (e.g. date strings or numbers).

  • open – Opening prices.

  • high – High prices.

  • low – Low prices.

  • close – Closing prices.

  • up_color – Fill color when close ≥ open (bullish).

  • down_color – Fill color when close < open (bearish).

  • candle_width – Fraction of the available slot width (0–1).

  • label – Legend label.

to_svg(ax: AxesLike, use_y2: bool = False) → str[source]

Draw each candle: a high-low wick with the open-close body over it.

class glyphx.waterfall.WaterfallSeries(labels: list[str], values: list[float | None], up_color: str = '#2ca02c', down_color: str = '#d62728', total_color: str = '#1f77b4', bar_width: float = 0.6, connector: bool = True, show_values: bool = True, label: str | None = None)[source]

Bases: BaseSeries

Waterfall (bridge) chart.

Parameters:
  • labels – Category labels.

  • values – Deltas to add at each step. Pass None for the last bar to auto-compute the running total.

  • up_color – Fill for positive bars.

  • down_color – Fill for negative bars.

  • total_color – Fill for the auto-total bar.

  • bar_width – Fraction of slot width used by each bar (0–1).

  • connector – Draw dashed connector lines between bars.

  • show_values – Print the delta value above each bar.

  • label – Legend label.

to_svg(ax: AxesLike, use_y2: bool = False) → str[source]

Draw each step as a floating bar between its start and end totals.

Hierarchical Series

class glyphx.treemap.TreemapSeries(labels: list[str], values: list[float], colors: list[str] | None = None, cmap: str = 'viridis', padding: float = 2.0, show_values: bool = True, min_font: int = 9, label: str | None = None)[source]

Bases: object

Squarified treemap.

Parameters:
  • labels – Category labels.

  • values – Numeric values (determines rectangle area).

  • colors – Per-label colors; if None, uses cmap.

  • cmap – Colormap name used when colors is not supplied.

  • padding – Gap between rectangles in pixels.

  • show_values – Overlay the numeric value in each rectangle.

  • min_font – Minimum font size; hides label if rect too small.

  • label – Legend label (unused but kept for API consistency).

to_svg(ax: AxesLike = None) → str[source]

Render the treemap into SVG rectangles.

class glyphx.sunburst.SunburstSeries(labels: list[str], parents: list[str], values: list[float], colors: list[str] | None = None, cmap: str = 'viridis', inner_radius: float = 40.0, ring_width: float = 60.0, padding_angle: float = 1.0, show_labels: bool = True, min_label_arc: float = 14.0, label: str | None = None)[source]

Bases: object

Multi-ring sunburst chart.

The root node (parent == "") is drawn as the centre circle. Each subsequent ring represents one level of the hierarchy.

Parameters:
  • labels – Node labels (unique identifiers).

  • parents – Parent label for each node. Root node has "".

  • values – Numeric value for each leaf node. Internal nodes can be 0 - their size is auto-summed from children.

  • colors – Per-label hex colors. If None, cmap is used.

  • cmap – Colormap for auto-coloring (default "viridis").

  • inner_radius – Inner radius of the first ring (default 40 px).

  • ring_width – Width of each ring in pixels (default 60).

  • padding_angle – Gap between segments in degrees (default 1.0).

  • show_labels – Render text inside each segment.

  • min_label_arc – Minimum arc length in px to show a label.

  • label – Legend label (unused but kept for API consistency).

to_svg(ax: AxesLike = None) → str[source]

Draw each ring outward from the root, one arc per node.

Streaming

class glyphx.streaming.StreamingSeries(max_points: int = 100, color: str | None = None, label: str | None = None, line_width: float = 2.0, show_points: bool = False)[source]

Bases: BaseSeries

Sliding-window line series for real-time / streaming data.

Parameters:
  • max_points – Maximum number of data points kept in the window.

  • color – Line color.

  • label – Legend label.

  • line_width – Stroke width.

  • show_points – Draw a dot at each data point.

live(fig: object, fps: float = 10.0) → _LiveContext[source]

Context manager for live display in Jupyter.

Usage:

with stream.live(fig, fps=10) as s:
    for value in sensor_generator():
        s.push(value)
Parameters:
  • fig – The Figure containing this series.

  • fps – Target frames per second (throttles re-renders).

Returns:

Context manager that yields self.

push(value: float) → StreamingSeries[source]

Append a new value to the stream.

Updates self.x and self.y so the parent Figure re-renders correctly on the next fig.render_svg() call.

Returns self for chaining:

stream.push(42.0).push(43.5)
Parameters:

value – New data value.

push_many(values: list[float] | ndarray) → StreamingSeries[source]

Push multiple values at once. Returns self.

reset() → StreamingSeries[source]

Clear the buffer and reset the tick counter. Returns self.

to_svg(ax: AxesLike, use_y2: bool = False) → str[source]

Draw the current buffer contents as a line.

Advanced 2-D Series

class glyphx.bubble.BubbleSeries(x, y, size, color: str | None = None, c=None, cmap: str = 'viridis', alpha: float = 0.65, min_radius: float = 4.0, max_radius: float = 40.0, labels: list | None = None, label: str | None = None, stroke: str = '#ffffff', stroke_width: float = 0.8, title: str | None = None)[source]

Bases: BaseSeries

Scatter plot with circle area encoding a fourth variable.

Unlike ScatterSeries(size=fixed_int), this accepts a per-point size array and scales radii so the smallest bubble is always min_radius pixels and the largest is max_radius pixels.

Parameters:
  • x – X-axis values.

  • y – Y-axis values.

  • size – Per-point numeric values mapped to bubble area. Can also be a fixed scalar to get uniform-sized bubbles without the colormap overhead.

  • color – Flat fill color, or None when c= is used.

  • c – Per-point values for color encoding (colormap).

  • cmap – Colormap name (default "viridis").

  • alpha – Fill opacity 0–1 (default 0.65).

  • min_radius – Pixel radius of the smallest bubble (default 4).

  • max_radius – Pixel radius of the largest bubble (default 40).

  • labels – Per-point tooltip labels (list of str).

  • label – Legend label for the series.

  • stroke – Bubble outline color (default "#fff").

  • stroke_width – Bubble outline width in pixels (default 0.8).

to_svg(ax: AxesLike, use_y2: bool = False) → str[source]

Draw one circle per point, radius from sizes and fill from c.

class glyphx.parallel_coords.ParallelCoordinatesSeries(data, axes: list[str], hue: list | None = None, cmap: str = 'viridis', colors: dict | list | None = None, alpha: float = 0.45, line_width: float = 1.2, show_axes: bool = True, label: str | None = None)[source]

Bases: object

Parallel coordinates plot for high-dimensional data.

Parameters:
  • data – 2-D array-like (rows × variables).

  • axes – Column / variable names (length must match data columns).

  • hue – Per-row group labels for color coding. When provided, each unique value gets a distinct color from the theme or cmap. Pass a numeric array to use a continuous colormap instead.

  • cmap – Colormap name used when hue holds numeric values, or when colors is not supplied (default "viridis").

  • colors – Explicit hex color per unique hue group (dict or list).

  • alpha – Line opacity 0–1 (default 0.45). Lower values help with overplotting.

  • line_width – Stroke width (default 1.2).

  • show_axes – Draw vertical axis lines and tick labels (default True).

  • label – Legend label (unused but kept for API consistency).

to_svg(ax: AxesLike = None) → str[source]

Draw one polyline per row, crossing every vertical axis.

class glyphx.diverging_bar.DivergingBarSeries(categories: list[str], values: list[float], pos_color: str = '#2563eb', neg_color: str = '#dc2626', bar_height: float = 0.65, show_values: bool = True, zero_line: bool = True, label: str | None = None)[source]

Bases: object

Horizontal diverging bar chart.

Parameters:
  • categories – Category labels (one per bar, rendered on Y axis).

  • values – Numeric values. Positive → right; negative → left.

  • pos_color – Fill color for positive bars (default blue).

  • neg_color – Fill color for negative bars (default red).

  • bar_height – Fraction of available row height used by each bar (0–1).

  • show_values – Render the numeric value at the end of each bar.

  • zero_line – Draw a vertical reference line at zero.

  • label – Legend label.

to_svg(ax: AxesLike = None) → str[source]

Draw bars left or right of a centre line, by sign.

class glyphx.grouped_bar.GroupedBarSeries(groups: list, categories: list, values: list[list[float]], group_colors: list[str] | None = None, bar_width: float = 0.8, label: str | None = None)[source]

Bases: BaseSeries

Grouped bar chart: for each category on the X-axis, draws one bar per group side-by-side, each with a distinct color.

Parameters:
  • groups – Category labels shown on the X-axis (outer grouping).

  • categories – Series / group names (inner grouping - one bar per name).

  • values – 2-D list values[group_i][cat_j].

  • group_colors – Color per category (inner group). Auto-assigned if None.

  • bar_width – Fraction of the available slot used by all bars together (0–1).

  • label – Legend label (unused; individual category labels shown instead).

to_svg(ax: AxesLike, use_y2: bool = False) → str[source]

Draw the groups side by side, splitting each category slot between them.

class glyphx.swarm_plot.SwarmPlotSeries(data, categories=None, color='#1f77b4', size=4, jitter=6, label=None)[source]

Bases: BaseSeries

Categorical scatter that offsets overlapping points sideways.

Parameters:
  • data (list[list]) – One list of observations per category.

  • categories (list | None) – Category labels, one per inner list.

  • color (str) – Point fill colour.

  • size (int) – Point radius in pixels.

  • jitter (int) – Horizontal spacing between collided points.

  • label (str | None) – Legend label.

to_svg(ax, use_y2=False) → str[source]

Draw each point, nudged sideways until it clears its neighbours.

class glyphx.count_plot.CountPlotSeries(data, order=None, color='#1f77b4', bar_width=0.8, label=None)[source]

Bases: BaseSeries

Bar chart of how often each category appears.

Counts the values itself, so it takes the raw column rather than pre-aggregated totals.

to_svg(ax, use_y2=False) → str[source]

Draw one bar per category, sized by its count.

zero_anchored = True

Bar chart of how often each category occurs.

Parameters:
  • data (list) – Raw observations; one entry per occurrence.

  • order (list | None) – Explicit category order. Defaults to sorted unique.

  • color (str) – Bar fill colour.

  • bar_width (float) – Fraction of the category slot the bar occupies.

  • label (str | None) – Legend label.

3-D Series

class glyphx.scatter3d.Scatter3DSeries(x, y, z, color: str = '#2563eb', c: list | None = None, cmap: str = 'viridis', size: float = 5.0, label: str | None = None, alpha: float = 0.85)[source]

Bases: object

3D scatter plot.

Parameters:
  • x – Data coordinates (same length).

  • y – Data coordinates (same length).

  • z – Data coordinates (same length).

  • color – Flat hex fill color when c is not used.

  • c – Per-point numeric values for colormap encoding.

  • cmap – Colormap name (default "viridis").

  • size – Marker size in pixels / Three.js units.

  • label – Legend / tooltip label.

  • alpha – Point opacity 0–1.

to_svg(cam: Camera3D, x_range: tuple, y_range: tuple, z_range: tuple) → str[source]

Render as SVG circles with 3D voxel thinning for large datasets.

to_threejs_data() → dict[source]

Serialise series data for the Three.js HTML renderer.

class glyphx.surface3d.Surface3DSeries(x, y, z, cmap: str = 'viridis', alpha: float = 0.9, wireframe: bool = True, wire_color: str = '#ffffff44', label: str | None = None)[source]

Bases: object

3D surface plot - z = f(x, y) over a regular grid.

Parameters:
  • x – 1-D X grid values (length N).

  • y – 1-D Y grid values (length M).

  • z – 2-D Z matrix, shape (M, N). z[j][i] is the height at (x[i], y[j]).

  • cmap – Colormap name (default "viridis").

  • alpha – Surface opacity 0–1.

  • wireframe – If True, draw grid lines over the surface.

  • wire_color – Color of wireframe lines.

  • label – Legend / tooltip label.

to_svg(cam: Camera3D, x_range, y_range, z_range) → str[source]

Render each grid quad as a coloured SVG polygon.

Quads are sorted back-to-front by their average projected depth.

to_threejs_data() → dict[source]

Export the mesh as plain dicts for the Three.js renderer.

class glyphx.line3d.Line3DSeries(x, y, z, color: str = '#dc2626', width: float = 2.0, linestyle: str = 'solid', label: str | None = None)[source]

Bases: object

3D line chart - a connected polyline through 3D coordinates.

Parameters:
  • x – Path coordinates (same length, connected in order).

  • y – Path coordinates (same length, connected in order).

  • z – Path coordinates (same length, connected in order).

  • color – Line color.

  • width – Stroke width in pixels.

  • linestyle – "solid", "dashed", "dotted".

  • label – Legend label.

to_svg(cam: Camera3D, x_range, y_range, z_range) → str[source]

Project the path to screen space and draw it, thinning first if needed.

LTTB runs on the projected screen coordinates rather than the raw data, so the points kept are the ones that matter from this camera angle.

to_threejs_data() → dict[source]

Export the path as plain dicts for the Three.js renderer.

class glyphx.bar3d.Bar3DSeries(x, y, z, dx: float | None = None, dy: float | None = None, cmap: str = 'viridis', alpha: float = 0.85, label: str | None = None)[source]

Bases: object

3D bar chart - one rectangular bar per (x, y) grid cell, height = z.

Parameters:
  • x – 1-D X positions (bar centres).

  • y – 1-D Y positions (bar centres).

  • z – 2-D Z matrix (heights), shape (len(y), len(x)), or 1-D if x and y are already paired point arrays.

  • dx – Bar width along X (default: auto from grid spacing).

  • dy – Bar depth along Y (default: auto from grid spacing).

  • cmap – Colormap name for bar colours (mapped by height).

  • alpha – Bar opacity.

  • label – Legend label.

to_svg(cam: Camera3D, x_range, y_range, z_range) → str[source]

Project every bar to screen space and draw it back to front.

Bars are sorted by camera depth before drawing, because SVG has no z-buffer: whatever is painted last ends up on top, so far bars have to go down first or near ones get hidden behind them.

to_threejs_data() → dict[source]

Export the bars as plain dicts for the Three.js renderer to consume.

class glyphx.contour.ContourSeries(x, y, z, levels: int | list[float] = 10, cmap: str = 'viridis', filled: bool = True, lines: bool = True, line_color: str = '#ffffff88', line_width: float = 0.8, alpha: float = 0.85, label: str | None = None)[source]

Bases: BaseSeries

2D filled contour plot - iso-lines and/or filled bands.

Parameters:
  • x – 1-D X grid values (length N).

  • y – 1-D Y grid values (length M).

  • z – 2-D Z matrix, shape (M, N).

  • levels – Number of contour levels, or an explicit list of Z values.

  • cmap – Colormap for fill bands.

  • filled – Draw filled colour bands between levels.

  • lines – Draw contour lines at each level.

  • line_color – Color for contour lines when not filled.

  • line_width – Contour line stroke width.

  • alpha – Fill opacity.

  • label – Legend label.

to_svg(ax: AxesLike, use_y2: bool = False) → str[source]

Render filled contour bands using linear interpolation.

Downsampling

GlyphX data downsampling utilities.

SVG performance degrades visibly above ~5 000 points. GlyphX automatically downsamples before SVG generation using a suite of algorithms chosen per series type.

Algorithm summary:

2-D line series   : Two-stage pipeline, M4 then LTTB.
2-D scatter series: 2-D voxel grid thinning.
3-D line series   : LTTB on vectorised camera-projected screen coords,
                    result cached in a WeakKeyDictionary keyed on camera
                    state + data fingerprint.
3-D scatter series: 3-D voxel grid thinning.
3-D surface series: Per-axis grid decimation + sub-pixel face culling.

Performance notes – all hot paths are fully vectorised with NumPy:

LTTB   : triangle-area computation uses slice broadcasting per bucket;
         no Python loop inside the bucket scan.
M4     : column assignment via np.digitize; min/max/first/last per
         column via np.minimum.reduceat / np.maximum.reduceat after a
         single argsort by column - no per-column Python list.
Voxel  : nearest-centroid selection via np.minimum.reduceat after
         sorting by cell_id - avoids a full argsort on distance.

Global kill-switch

Call glyphx.downsample.disable() to turn off all downsampling. The flag lives in a threading.local so threads are independent.

Per-series control

Pass threshold=N to LineSeries or ScatterSeries, or set series.threshold afterwards, to override AUTO_THRESHOLD.

Downsampling metadata

After rendering each series exposes series.last_downsample_info - a dict with keys algorithm, original_n, thinned_n.

glyphx.downsample.cull_faces(faces: list[tuple], min_area: float = 0.5) → list[tuple][source]

Remove projected quad faces whose screen area is below min_area px^2.

Fully vectorised NumPy shoelace computation.

glyphx.downsample.decimate_grid(x_1d: list | ndarray, y_1d: list | ndarray, z_mat: list[list[float]] | ndarray, max_faces: int = 5000) → tuple[ndarray, ndarray, ndarray][source]

Reduce a regular Surface3D grid by subsampling rows and columns.

Uses independent per-axis step sizes proportional to grid aspect ratio.

Raises:

ValueError – If z_mat shape does not match (len(y_1d), len(x_1d)).

glyphx.downsample.disable() → None[source]

Disable all automatic downsampling on the current thread.

glyphx.downsample.enable() → None[source]

Re-enable automatic downsampling on the current thread.

glyphx.downsample.is_enabled() → bool[source]

Return True if downsampling is active on this thread.

glyphx.downsample.lttb(x: list | ndarray, y: list | ndarray, threshold: int) → tuple[ndarray, ndarray][source]

Largest-Triangle-Three-Buckets downsampling (Steinarsson 2013).

The per-bucket triangle-area scan is vectorised: for each bucket the areas of all candidate points are computed as a NumPy slice expression and np.argmax selects the winner - no Python loop inside the bucket.

Parameters:
  • x – X values (1-D, numeric).

  • y – Y values (1-D, numeric, same length as x).

  • threshold – Maximum number of output points (>= 3).

Returns:

(x_down, y_down) – NumPy arrays of length <= threshold.

Raises:

ValueError – If lengths differ or threshold < 3.

glyphx.downsample.lttb_3d(x: list | np.ndarray, y: list | np.ndarray, z: list | np.ndarray, cam: Camera3D, threshold: int = 5000) → tuple[np.ndarray, np.ndarray, np.ndarray][source]

LTTB for a 3-D polyline in screen space.

Projects via vectorised NumPy transform, then runs the vectorised LTTB inner loop on screen coordinates. Result cached in a WeakKeyDictionary keyed on (camera-state, data-fingerprint).

Respects the thread-local kill-switch.

Raises:

ValueError – If x, y, z have different lengths.

glyphx.downsample.m4(x: list | ndarray, y: list | ndarray, pixel_width: int) → tuple[ndarray, ndarray][source]

M4 downsampling (Jugel et al. 2014).

Fully vectorised: column assignment uses np.digitize; per-column first/last/min/max are found with np.minimum.reduceat and np.maximum.reduceat after a single argsort by column - no per-column Python list or loop.

Requires monotone X values. Non-monotone input is auto-sorted with a UserWarning.

Parameters:
  • x – X values (1-D, numeric, monotone).

  • y – Y values (1-D, numeric, same length as x).

  • pixel_width – Canvas width in pixels.

Returns:

(x_down, y_down) – NumPy arrays.

glyphx.downsample.maybe_downsample(x: list | ndarray, y: list | ndarray, threshold: int = 5000) → tuple[list | ndarray, list | ndarray][source]

Backward-compatible wrapper: LTTB only, no pixel width, no M4.

Deprecated since version Use: maybe_downsample_line instead.

glyphx.downsample.maybe_downsample_line(x: list | ndarray, y: list | ndarray, pixel_width: int = 800, threshold: int = 5000, m4_threshold: int = 50000) → tuple[ndarray | list, ndarray | list][source]

Two-stage downsampling pipeline for ordered 2-D line data.

Stage 1 – M4 : if n > m4_threshold, reduce via M4. Stage 2 – LTTB: if still > threshold, apply LTTB.

Respects the thread-local kill-switch.

glyphx.downsample.voxel_thin_2d(x: list | ndarray, y: list | ndarray, c: list | ndarray | None = None, max_points: int = 5000) → tuple[ndarray, ndarray, ndarray | None][source]

2-D voxel grid thinning for unordered scatter data.

For each occupied grid cell keeps the point nearest to the cell centroid. Uses np.minimum.reduceat after sorting by cell_id to find the nearest point per cell without a full distance argsort, reducing the dominant cost from O(n log n) to O(n log n) sort by cell + O(n) scan.

The dtype of c is preserved in the output.

Respects the thread-local kill-switch.

Parameters:
  • x – Coordinates (1-D, same length).

  • y – Coordinates (1-D, same length).

  • c – Optional per-point values (threaded through).

  • max_points – Target maximum output points.

Returns:

(x_thin, y_thin, c_thin)

Raises:

ValueError – If x and y have different lengths.

glyphx.downsample.voxel_thin_3d(x: list | ndarray, y: list | ndarray, z: list | ndarray, colors: list | None = None, max_points: int = 5000) → tuple[ndarray, ndarray, ndarray, list | None][source]

3-D voxel grid thinning for unordered scatter data.

Uses np.minimum.reduceat after sorting by cell_id to find the nearest-centroid point per voxel without a full distance argsort.

Respects the thread-local kill-switch.

Raises:

ValueError – If x, y, z have different lengths.

Note

maybe_downsample() is deprecated; use maybe_downsample_line() instead.

DataFrame Accessor

class glyphx.accessor.GlyphXAccessor(df: DataFrame)[source]

Bases: object

Pandas DataFrame accessor that exposes the full GlyphX plotting API.

Registered automatically when glyphx is imported. Access via df.glyphx.<method>(...).

All methods return a Figure so results can be further customised via method chaining.

bar(x: str | None = None, y: str | None = None, color: str | None = None, label: str | None = None, yerr: str | None = None, groupby: str | None = None, hue: str | None = None, agg: str = 'sum', **kwargs: Any)[source]

Create a bar chart from DataFrame columns.

Pass groupby or hue to create one series per unique group, each colored automatically from the theme palette. hue splits by a column while keeping x/y semantics; groupby aggregates.

Returns:

Figure

box(col: str | None = None, groupby: str | None = None, color: str | None = None, **kwargs: Any)[source]

Create a box plot. Pass groupby for multi-box comparison. Returns Figure.

donut(labels: str | None = None, values: str | None = None, **kwargs: Any)[source]

Create a donut chart. Returns Figure.

heatmap(**kwargs: Any)[source]

Create a heatmap from the DataFrame’s numeric values.

The entire numeric portion of the DataFrame is treated as a 2-D matrix. Column names become column labels; index values become row labels.

Returns:

Figure

hist(col: str | None = None, bins: int = 10, color: str | None = None, label: str | None = None, **kwargs: Any)[source]

Create a histogram of a numeric column. Returns Figure.

line(x: str | None = None, y: str | None = None, color: str | None = None, label: str | None = None, linestyle: str = 'solid', yerr: str | None = None, **kwargs: Any)[source]

Create a line chart from DataFrame columns.

Parameters:
  • x – Column name for X axis.

  • y – Column name for Y axis.

  • yerr – Column name for Y error bars (optional).

  • label – Legend label; defaults to the y column name.

Returns:

Figure - fully chainable.

pie(labels: str | None = None, values: str | None = None, **kwargs: Any)[source]

Create a pie chart. Returns Figure.

plot(kind: str = 'line', x: str | None = None, y: str | None = None, **kwargs: Any)[source]

Unified entry point - mirrors glyphx.plot() but operates on the DataFrame’s columns.

Parameters:
  • kind – Chart type (same values as glyphx.plot()).

  • x – Column name for X axis (used for line/bar/scatter).

  • y – Column name for Y axis (used for line/bar/scatter).

Returns:

Figure

scatter(x: str | None = None, y: str | None = None, color: str | None = None, label: str | None = None, size: int = 5, marker: str = 'circle', **kwargs: Any)[source]

Create a scatter plot from DataFrame columns. Returns Figure.

stacked_bar(x: str, y: str, stack: str, normalize: bool = False, bar_width: float = 0.75, **kwargs: Any)[source]

Stacked bar chart from a long-format DataFrame.

Pivots stack into one sub-series per distinct value, summing y within each (x, stack) pair.

Negative values are supported: positive segments stack upward from zero and negative segments stack downward, so a category holding a mix shows both without the two cancelling out.

Parameters:
  • x (str) – Column holding the category for each bar.

  • y (str) – Column holding the numeric value.

  • stack (str) – Column whose distinct values become stack segments.

  • normalize (bool) – Scale each bar to 100%. Shares are computed from absolute values, so a bar holding +5 and -5 shows +50% and -50% rather than dividing by a zero total.

  • bar_width (float) – Fraction of the slot each bar fills.

Returns:

The rendered figure.

Return type:

Figure

Example:

df.glyphx.stacked_bar(x="quarter", y="revenue", stack="segment")

Colormaps

glyphx.colormaps.apply_colormap(value: float, cmap: str | list[str] = 'viridis') → str[source]

Map a scalar in [0, 1] to a hex color string.

Parameters:
  • value – Normalised value between 0 and 1.

  • cmap – Colormap name or a custom list of hex stops.

Returns:

Hex color string (e.g. "#3b528b").

glyphx.colormaps.colormap_colors(cmap: str, n: int) → list[str][source]

Sample n evenly-spaced colors from a colormap.

Parameters:
  • cmap – Colormap name.

  • n – Number of colors to return.

Returns:

List of hex color strings.

glyphx.colormaps.list_colormaps() → list[str][source]

Return names of all built-in colormaps.

glyphx.colormaps.get_colormap(name: str) → list[str][source]

Return the hex color stops for a named colormap.

Parameters:

name – Colormap name (case-insensitive).

Raises:

ValueError – If the name is not recognised.

glyphx.colormaps.render_colorbar_svg(cmap: str | list[str], vmin: float, vmax: float, x: float, y: float, width: float, height: float, font: str = 'sans-serif', text_color: str = '#000', steps: int = 24) → str[source]

Generate an SVG colorbar strip with min/max labels.

Parameters:
  • cmap – Colormap name or stops list.

  • vmin – Data range.

  • vmax – Data range.

  • x – Top-left corner of the bar in SVG units.

  • y – Top-left corner of the bar in SVG units.

  • width – Width of the color strip.

  • height – Height of the color strip.

  • font – Font family for labels.

  • text_color – Label fill color.

  • steps – Number of gradient rectangles.

Returns:

SVG markup string.

Accessibility

glyphx.a11y.generate_alt_text(fig: Figure) → str[source]

Generate a plain-English description of a Figure for screen readers.

The description covers chart type, title, axis labels, series count, data ranges, and notable values (min / max).

Parameters:

fig – A GlyphX Figure instance.

Returns:

A human-readable string suitable for aria-label or <desc>.

glyphx.a11y.inject_aria(svg: str, title: str, desc: str, chart_id: str) → str[source]

Inject ARIA attributes and landmark elements into a rendered SVG string.

Changes made:

  • Adds role="img" and aria-labelledby to the root <svg> (only if not already present)

  • Injects <title> and <desc> as the first children of the SVG

  • Adds tabindex="0" and role="graphics-symbol" to every .glyphx-point element for keyboard navigation

Parameters:
  • svg – Raw SVG string from Figure.render_svg().

  • title – Short label (goes in <title>).

  • desc – Longer description (goes in <desc>).

  • chart_id – Unique chart ID already present on the <svg> element.

Returns:

The accessibility-enhanced SVG string.

Themes

glyphx.themes.themes = {'colorblind': {'axis_color': '#000000', 'background': '#ffffff', 'colors': ['#E69F00', '#56B4E9', '#009E73', '#F0E442', '#0072B2', '#D55E00', '#CC79A7', '#000000'], 'font': 'sans-serif', 'grid_color': '#bbbbbb', 'text_color': '#000000'}, 'dark': {'axis_color': '#cccccc', 'background': '#1e1e1e', 'colors': ['#8ecae6', '#ffb703', '#219ebc', '#fb8500', '#d62828', '#a8dadc', '#f4a261', '#e9c46a'], 'font': 'sans-serif', 'grid_color': '#444444', 'text_color': '#ffffff'}, 'default': {'axis_color': '#333', 'background': '#ffffff', 'colors': ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f'], 'font': 'sans-serif', 'grid_color': '#ddd', 'text_color': '#000000'}, 'monochrome': {'axis_color': '#111111', 'background': '#ffffff', 'colors': ['#111111', '#333333', '#555555', '#777777', '#999999', '#bbbbbb', '#dddddd'], 'font': 'sans-serif', 'grid_color': '#cccccc', 'text_color': '#000000'}, 'ocean': {'axis_color': '#023e8a', 'background': '#f0f8ff', 'colors': ['#03045e', '#0077b6', '#00b4d8', '#90e0ef', '#caf0f8', '#48cae4', '#023e8a', '#0096c7'], 'font': 'sans-serif', 'grid_color': '#caf0f8', 'text_color': '#03045e'}, 'pastel': {'axis_color': '#444444', 'background': '#f9f9f9', 'colors': ['#aec7e8', '#ffbb78', '#98df8a', '#ff9896', '#c5b0d5', '#c49c94', '#f7b6d2', '#c7c7c7'], 'font': 'sans-serif', 'grid_color': '#cccccc', 'text_color': '#222222'}, 'warm': {'axis_color': '#5c3317', 'background': '#fff8f0', 'colors': ['#e63946', '#f4a261', '#e9c46a', '#2a9d8f', '#264653', '#a8dadc', '#457b9d', '#1d3557'], 'font': 'Georgia, serif', 'grid_color': '#f0d9c8', 'text_color': '#3e1f00'}}

Mapping of theme name to theme definition. Each value is a dict with the keys listed above; pass a name to Figure(theme=...) or set_theme().

glyphx.themes.register_theme(name: str, base: str = 'default', **overrides) → dict[source]

Register a named theme so it can be used anywhere a name is accepted.

Custom themes work with Figure(theme=...), df.glyphx.*, facet_plot, clustermap, Figure3D and the CLI – all of which take a theme name, which previously meant a custom palette could only be used by passing a dict to Figure.set_theme() and nowhere else.

Parameters:
  • name – Name to register under. Must not collide with a built-in.

  • base – Existing theme to inherit unspecified keys from.

  • **overrides – Any of colors, axis_color, grid_color, font, background, text_color.

Returns:

The fully resolved theme, also stored in the registry.

Return type:

dict

Raises:

ValueError – On a built-in name, an unknown base, an unknown key, or a malformed colors value.

Example:

from glyphx import Figure, register_theme

register_theme(
    "acme",
    base="dark",
    colors=["#e6194b", "#3cb44b", "#4363d8"],
    font="Inter, sans-serif",
)
Figure(theme="acme").line(x, y).show()
glyphx.themes.unregister_theme(name: str) → None[source]

Remove a custom theme. Built-ins cannot be removed.

Raises:
glyphx.themes.get_theme(spec=None) → dict[source]

Resolve a theme name or dict into a complete theme dictionary.

Parameters:

spec – A registered theme name, a partial theme dict (missing keys are filled from "default"), or None for the default.

Returns:

A theme with every key in THEME_KEYS populated.

Return type:

dict

Raises:

ValueError – If the name is not registered, or the dict is malformed. Previously an unknown name fell back to "default" silently, so a typo like theme="darkk" rendered a light chart with no indication anything was wrong.

glyphx.themes.list_themes() → list[str][source]

Names of every registered theme, built-in and custom.

Returns:

Sorted theme names.

Return type:

list[str]

Example:

>>> from glyphx import list_themes
>>> "dark" in list_themes()
True

Tick label wrapping

glyphx.utils.wrap_tick_label(label, max_chars, max_lines: int = 2) → list[source]

Word-wrap a tick label to at most max_lines lines of roughly max_chars characters each.

Character-count based, like every other width estimate in this codebase – SVG text has no font-metrics API to query, so Axes._should_rotate_xlabels uses the same kind of estimate for its rotate-vs-not decision. This is the wrap alternative: a label too long to fit at the current tick spacing goes to two lines instead of forcing every label on the axis to rotate.

A single word longer than max_chars is hard-split rather than left to overflow one line. If content remains after max_lines, the last line is truncated with an ellipsis rather than silently dropped.

Parameters:
  • label – Text to wrap. Non-strings are stringified first.

  • max_chars – Approximate character budget per line.

  • max_lines – Maximum lines to return.

Returns:

One or more lines, never more than max_lines.

Return type:

list[str]

Available theme names: "default", "dark", "colorblind", "pastel", "warm", "ocean", "monochrome"

Utilities

glyphx.utils.normalize(data)[source]

Normalize a numeric array to the [0, 1] range.

Parameters:

data (array-like) – List or NumPy array of values.

Returns:

Values scaled to [0, 1].

Return type:

np.ndarray

Raises:

ValueError – If all values are equal (zero-width range).

glyphx.utils.svg_escape(text)[source]

Escape a string so it is safe inside SVG text or an attribute.

glyphx.utils.wrap_svg_canvas(svg_content: str, width: int = 640, height: int = 480, has_math: bool = False, crossfilter: bool = False, axis_metadata: str = '') → str[source]

Wrap raw SVG elements in a full <svg> root element.

The chart id is a hash of the SVG content and canvas size, so the same figure always renders byte-identical output. A UUID would be equally collision-resistant, but it made every render differ from the last – which defeats caching, makes diffs unreadable, and rules out golden-file tests. Distinct charts still get distinct ids because distinct content hashes differently.

Parameters:
  • svg_content (str) – Inner SVG markup.

  • width (int) – Canvas width in pixels.

  • height (int) – Canvas height in pixels.

  • has_math (bool) – When True, embeds a MathJax data attribute so wrap_svg_with_template injects the CDN script.

  • crossfilter (bool) – When True, marks the root so crossfilter.js includes this chart. Charts without the marker are left alone, so one page can mix filtered and independent charts.

Returns:

Complete SVG document string.

Return type:

str

glyphx.utils.make_shareable_html(svg_string: str, title: str = 'GlyphX Chart') → str[source]

Build a fully self-contained HTML document with all JavaScript inlined.

The output has zero external dependencies and renders correctly in: - Email clients (tested in Gmail, Outlook web) - Confluence / Notion embeds - GitHub Pages / static hosts - Air-gapped / offline environments

Parameters:
  • svg_string (str) – Raw SVG markup.

  • title (str) – <title> tag value.

Returns:

Complete, standalone HTML document string.

Return type:

str

glyphx.utils.write_svg_file(svg_string: str, filename: str, **kwargs)[source]

Save a chart to file.

.svg and .html are written directly. .png, .jpg, .webp, and .pdf are delegated to glyphx.export, which picks whichever rendering backend is installed.

Parameters:
  • svg_string (str) – Raw SVG content.

  • filename (str) – Output path. Extension determines format.

  • **kwargs – dpi (int) and backend (str) are forwarded to the raster/PDF backends.

Raises:

RuntimeError – If no backend can produce the requested format.

Projection (3-D)

class glyphx.projection3d.Camera3D(azimuth: float = 45.0, elevation: float = 30.0, cx: float = 0.0, cy: float = 0.0, scale: float = 1.0)[source]

Bases: object

Orthographic camera for projecting 3D data to 2D SVG.

Angles follow the geographic convention:
azimuth - rotation around the vertical (Z) axis, degrees.

0° = looking from +Y; 90° = looking from +X.

elevation - tilt above the horizontal plane, degrees.

0° = side view; 90° = top-down.

The right-hand coordinate system uses:

X → right, Y → into screen (depth), Z → up.

project(x: float, y: float, z: float) → Projected[source]

Project a normalised 3D point to 2D screen coordinates.

project_all(xs: list[float], ys: list[float], zs: list[float]) → list[Projected][source]

Project a batch of points.

glyphx.projection3d.normalize(values: list[float]) → tuple[list[float], float, float][source]

Return (normalised_to_minus1_plus1, min_val, max_val).

Additional Chart Types (v1.6+)

class glyphx.gantt.GanttSeries(tasks: list[dict[str, Any]], group_colors: dict[str, str] | None = None, cmap: str = 'viridis', bar_height: int = 20, row_padding: int = 6, show_today: bool = True, today_color: str = '#ef4444', show_grid: bool = True, label: str | None = None)[source]

Bases: BaseSeries

Gantt / project timeline chart.

Each task is one horizontal bar spanning from start to end. Milestones (single-day events with "milestone": True) are rendered as diamond markers instead of bars.

Parameters:
  • tasks –

    List of task dicts, each with keys:

    • "task" (str) – display label

    • "start" (date|str) – bar left edge

    • "end" (date|str) – bar right edge

    • "group" (str, optional) – colour group

    • "milestone" (bool, optional) – diamond marker

    • "tooltip" (str, optional) – custom tooltip text

    • "progress" (float 0-1, optional) – fill fraction

  • group_colors – {group_name: hex_color} mapping. Auto-assigned from cmap if not provided.

  • cmap – Colormap for auto-assigned group colours.

  • bar_height – Pixel height of each task bar (default 18).

  • row_padding – Pixel gap between task rows (default 6).

  • show_today – Draw a vertical line at today’s date.

  • today_color – Color of the today marker.

  • show_grid – Draw vertical date-grid lines.

  • label – Series legend label.

to_svg(ax: AxesLike, use_y2: bool = False) → str[source]

Draw one horizontal bar per task, positioned by its start and end dates.

class glyphx.stacked_bar.StackedBarSeries(x: list, series: dict[str, list[float]], colors: list[str] | None = None, normalize: bool = False, bar_width: float = 0.75, label: str | None = None)[source]

Bases: BaseSeries

Bars split into stacked segments, optionally normalised to 100%.

Each key in stacks becomes one segment layer across every category, drawn bottom-up in insertion order.

to_svg(ax: AxesLike, use_y2: bool = False) → str[source]

Draw each category’s bar as a run of segments stacked from the baseline.

zero_anchored = True

Stacked bar chart - multiple series stacked vertically per category.

Parameters:
  • x – Category labels for the X-axis.

  • series – {label: [values]} mapping. Order determines stack order (first key is at the bottom).

  • colors – Per-series hex colors. Falls back to the active theme palette.

  • normalize – If True, bars are normalized to 100% (proportional stacking).

  • bar_width – Fraction of the available slot width per bar (0–1).

  • label – Legend label (not used; each sub-series has its own label).

class glyphx.bump_chart.BumpChartSeries(x: list, rankings: dict[str, list[int]], colors: list[str] | None = None, line_width: float = 3.0, dot_radius: float = 6.0, show_labels: bool = True, label: str | None = None)[source]

Bases: object

Rank-over-time chart drawn with smooth Bézier curves.

Lower rank number = higher position (rank 1 is at the top).

Parameters:
  • x – Time-axis labels (columns).

  • rankings – {series_name: [rank_at_each_x]} mapping.

  • colors – Per-series colors. Auto-assigned if None.

  • line_width – Stroke width of each ribbon.

  • dot_radius – Radius of the rank-position dots.

  • show_labels – Draw series name at leftmost and rightmost position.

  • label – Legend label (unused; individual series labeled directly).

to_svg(ax: AxesLike = None) → str[source]

Draw one line per entity across the periods, ranked top to bottom.

class glyphx.sparkline.SparklineSeries(data: list[float], color: str = '#2563eb', kind: str = 'line', fill: bool = True, fill_alpha: float = 0.18, line_width: float = 1.5, show_last_dot: bool = True, label: str | None = None)[source]

Bases: BaseSeries

Lightweight sparkline series. Designed for very small canvases (width ≤ 200, height ≤ 60). Omits axis lines, grid, and labels.

Parameters:
  • data – Numeric values.

  • color – Line color.

  • kind – "line" or "bar".

  • fill – Shade area under the line.

  • fill_alpha – Fill opacity.

  • line_width – Stroke width.

  • show_last_dot – Highlight the final data point.

  • label – Legend label.

to_svg(ax: AxesLike, use_y2: bool = False) → str[source]

Draw the sparkline, plus any min/max/last markers that were enabled.

glyphx.sparkline.sparkline_svg(data: list[float], width: int = 80, height: int = 28, color: str = '#2563eb', kind: str = 'line', line_width: float = 1.5, fill: bool = True, fill_alpha: float = 0.18, show_last_dot: bool = True, padding: int = 2) → str[source]

Render a compact sparkline and return raw SVG markup.

Parameters:
  • data – Numeric values to plot.

  • width – Pixel width of the sparkline.

  • height – Pixel height.

  • color – Line / bar fill color.

  • kind – "line" or "bar".

  • line_width – Stroke width for line sparklines.

  • fill – Shade area under the line.

  • fill_alpha – Fill opacity (0–1).

  • show_last_dot – Mark the last data point with a circle.

  • padding – Pixel margin around the chart area.

Returns:

Complete <svg> element as a string.

FacetGrid

class glyphx.facet_grid.FacetGrid(data, col: str | None = None, row: str | None = None, hue: str | None = None, height: int = 300, aspect: float = 1.4, col_wrap: int | None = None, theme: str = 'default', sharex: bool = True, sharey: bool = True, col_order: list | None = None, row_order: list | None = None, hue_order: list | None = None, palette: list | None = None)[source]

Bases: object

Small-multiples grid.

Parameters:
  • data – Source DataFrame.

  • col – Column name to facet along the X axis.

  • row – Column name to facet along the Y axis (optional).

  • hue – Column name for color-coding within each cell (optional).

  • height – Pixel height of each cell.

  • aspect – Width/height ratio of each cell.

  • col_wrap – Wrap into a new row after this many columns.

  • theme – GlyphX theme name.

  • sharex – Share X-axis scale across all cells.

  • sharey – Share Y-axis scale across all cells.

  • col_order – Explicit ordering of column facets.

  • row_order – Explicit ordering of row facets.

  • hue_order – Explicit ordering of hue groups.

  • palette – Color palette for hue groups (list of hex strings).

map(kind: str, x: str | None = None, y: str | None = None, **kwargs) → FacetGrid[source]

Apply a chart type to each facet cell.

Parameters:
  • kind – Chart kind ("scatter", "line", "bar", "hist", "kde", "box", "violin").

  • x – X-axis column name.

  • y – Y-axis column name (not needed for "hist"/"kde").

  • **kwargs – Passed to the series constructor.

Returns:

self for chaining.

Example:

g = FacetGrid(df, col="species", hue="island")
g.map("scatter", x="bill_length", y="flipper_length")
g.map("hist", x="body_mass")
render_svg() → str[source]

Composite all cell figures into a single SVG grid.

show() → FacetGrid[source]

Display in Jupyter or open in browser.

save(path: str) → FacetGrid[source]

Save the composite SVG to a file.

Regression Plot

glyphx.regplot.regplot(data, x: str | None = None, y: str | None = None, x_vals: list | None = None, y_vals: list | None = None, order: int = 1, lowess: bool = False, logistic: bool = False, ci: int = 95, n_boot: int = 100, scatter_kw: dict | None = None, line_kw: dict | None = None, color: str = '#2563eb', alpha: float = 0.2, title: str = '', theme: str = 'default', auto_display: bool = False) → Figure[source]

Regression plot: scatter + fitted curve + optional CI band.

Supports OLS, polynomial, logistic, and LOWESS regression, all in pure NumPy. Seaborn’s regplot requires statsmodels for some modes; GlyphX has zero extra dependencies.

Parameters:
  • data – DataFrame (use with x= and y= column names) or None (use x_vals/y_vals directly).

  • x – Column names when data is a DataFrame.

  • y – Column names when data is a DataFrame.

  • x_vals – Raw numeric arrays when data is None.

  • y_vals – Raw numeric arrays when data is None.

  • order – Polynomial degree (1 = linear, 2 = quadratic, etc.)

  • lowess – Use LOWESS instead of polynomial.

  • logistic – Fit logistic curve (binary Y assumed).

  • ci – Confidence interval level (0-100). 0 disables CI band.

  • n_boot – Bootstrap samples for the CI band.

  • scatter_kw – Extra kwargs for ScatterSeries.

  • line_kw – Extra kwargs for LineSeries.

  • color – Shared colour for scatter and fit line.

  • alpha – CI band fill opacity.

  • title – Chart title.

  • theme – GlyphX theme name.

  • auto_display – Open immediately after creation.

Returns:

Figure ready to .show() or .save().

Examples:

from glyphx.regplot import regplot

# OLS
regplot(df, x="height", y="weight")

# Quadratic
regplot(df, x="age", y="income", order=2, color="#dc2626")

# LOWESS
regplot(df, x="gdp", y="life_exp", lowess=True)

# Logistic (binary outcome)
regplot(df, x="dose", y="response", logistic=True)

# No data frame
import numpy as np
x = np.random.randn(200)
y = 2*x + np.random.randn(200)
regplot(None, x_vals=x, y_vals=y, title="Correlation")

Choropleth Map

class glyphx.choropleth.ChoroplethSeries(geojson: dict | list, data: dict[str, float], key: str = 'name', cmap: str = 'viridis', missing_color: str = '#e0e0e0', stroke: str = '#ffffff', stroke_width: float = 0.4, alpha: float = 0.9, label: str | None = None, title: str | None = None)[source]

Bases: object

SVG-path choropleth map from GeoJSON.

No tiles, no CDN – renders as pure SVG paths projected via Mercator.

Parameters:
  • geojson – GeoJSON FeatureCollection dict ({"type":"FeatureCollection", "features":[...]}) or a list of feature dicts.

  • data – {feature_key: numeric_value} mapping.

  • key – GeoJSON feature property name that matches data keys.

  • cmap – Colormap name.

  • missing_color – Fill color for features with no matching data entry.

  • stroke – Border stroke color.

  • stroke_width – Border stroke width.

  • alpha – Fill opacity.

  • label – Legend / tooltip label.

  • title – Chart title (forwarded to Figure).

to_svg(ax: AxesLike = None) → str[source]

Project every feature to screen space and emit it as an SVG path.

Clustermap

glyphx.clustermap.clustermap(data, row_labels: list[str] | None = None, col_labels: list[str] | None = None, cmap: str = 'viridis', row_cluster: bool = True, col_cluster: bool = True, standard_scale: str | None = None, z_score: str | None = None, show_values: bool = False, figsize: tuple[int, int] = (720, 640), title: str = '', dendrogram_ratio: float = 0.15, line_color: str = '#555', theme: str = 'default') → Figure[source]

Hierarchically clustered heatmap with row and column dendrograms.

Equivalent to seaborn.clustermap() but implemented in pure NumPy – no scipy, no matplotlib required.

Parameters:
  • data – 2-D numeric array or pandas DataFrame.

  • row_labels – Labels for rows (inferred from DataFrame index if None).

  • col_labels – Labels for columns (inferred from DataFrame columns if None).

  • cmap – Colormap name (default "viridis").

  • row_cluster – Cluster and reorder rows (default True).

  • col_cluster – Cluster and reorder columns (default True).

  • standard_scale – "row" or "col" – scale each row/column to [0,1].

  • z_score – "row" or "col" – z-score normalise each row/column.

  • show_values – Overlay the numeric value in each cell.

  • figsize – (width, height) in pixels.

  • title – Chart title.

  • dendrogram_ratio – Fraction of figure width/height used by dendrograms.

  • line_color – Dendrogram line colour.

  • theme – GlyphX theme name.

Returns:

Figure containing the clustered heatmap and dendrograms rendered as SVG.

Example:

import pandas as pd
from glyphx.clustermap import clustermap

df = pd.read_csv("gene_expression.csv", index_col=0)
fig = clustermap(df, cmap="coolwarm", z_score="row",
                 title="Gene Expression Heatmap")
fig.show()
fig.save("clustermap.html")

Vega-Lite Export

glyphx.vega_lite.to_vega_lite(fig, width: int | None = None, height: int | None = None) → dict[str, Any][source]

Convert a Figure to a Vega-Lite v5 specification dict.

The resulting specification can be:

  • Saved as a .vl.json file and opened in the Vega editor

  • Embedded in Observable notebooks

  • Rendered with altair (alt.Chart.from_dict(spec))

  • Shared as a portable, renderer-agnostic chart format

Parameters:
  • fig – GlyphX Figure instance.

  • width – Override canvas width (defaults to fig.width).

  • height – Override canvas height (defaults to fig.height).

Returns:

Vega-Lite v5 specification as a nested dict.

Example:

from glyphx import Figure
from glyphx.series import LineSeries
from glyphx.vega_lite import to_vega_lite
import json

fig = Figure().add(LineSeries(months, revenue, label="Revenue"))
spec = to_vega_lite(fig)
print(json.dumps(spec, indent=2))
glyphx.vega_lite.save_vega_lite(fig, path: str | Path, **kwargs) → None[source]

Serialize a figure’s Vega-Lite spec to a JSON file.

Parameters:
  • fig – GlyphX Figure.

  • path – Output path (conventionally .vl.json).

Example:

from glyphx.vega_lite import save_vega_lite
save_vega_lite(fig, "chart.vl.json")

Aggregation

Collapsing repeated measurements per x into an estimate and an interval, which is what glyphx.Figure.aggregate_line() draws.

glyphx.aggregate.aggregate(x_values, y_values, *, estimator='mean', ci=95, n_boot=1000, n_std=1.0, seed=42)[source]

Collapse repeated y values per x into an estimate and an interval.

Parameters:
  • x_values – The x of each observation. Repeats are the point: every observation sharing an x forms one group.

  • y_values – The observed value for each.

  • estimator – "mean", "median", "sum", "min", "max", "count", or any callable reducing an array to a scalar.

  • ci – Confidence level 0-100 for a bootstrap interval, "sd" for one standard deviation, "se" for standard error, or None for no interval at all.

  • n_boot – Bootstrap resamples when ci is a number.

  • n_std – Multiplier for the "sd" and "se" intervals.

  • seed – Fixed so a chart redrawn from the same data is identical – a band that shifted slightly on every render would make figures irreproducible.

Returns:

(xs, centre, lower, upper), sorted by x. lower and upper are None when ci is None.

Return type:

tuple

Raises:

ValueError – If the two inputs differ in length, or the estimator or ci is not recognised.

Math in labels

glyphx.mathtext.render(text: str) → str[source]

Render a label, converting any $...$ spans to SVG markup.

Text outside the math spans is escaped and left alone, so mixed labels such as "Energy $E = mc^2$ over time" work.

Parameters:

text (str) – The label.

Returns:

Markup safe to place inside an SVG <text> element.

Return type:

str

glyphx.mathtext.to_plain_text(text: str) → str[source]

Convert a label to a spoken form for alt text and ARIA descriptions.

Markup is useless to a screen reader, so $\sigma_{x}$ becomes σ_x rather than a pile of tspans.

Parameters:

text (str) – The label.

Returns:

Plain text with commands resolved to characters.

Return type:

str

glyphx.mathtext.contains_math(text: object) → bool[source]

True if text has a $...$ span in it.

glyphx.mathtext.estimate_width(text: str, font_size: float) → float[source]

Approximate the rendered width of a label in pixels.

Layout code sizes gutters and legends before anything is drawn, and a math label’s width is not its character count – scripts are smaller and commands collapse to one glyph.

Parameters:
  • text (str) – The label.

  • font_size (float) – Font size in pixels.

Returns:

Estimated width in pixels.

Return type:

float

Export backends

glyphx.export.render_to_file(svg: str, path: str, dpi: int = 96, backend: str | None = None) → str[source]

Rasterise svg to path, choosing an available backend.

Parameters:
  • svg (str) – The SVG document to convert.

  • path (str) – Output path; its extension selects the format.

  • dpi (int) – Target resolution. 96 is CSS-pixel scale; 192 is retina, 300 is print.

  • backend (str | None) – Force a specific backend by name. Defaults to the best available one for the format.

Returns:

The backend that produced the file.

Return type:

str

Raises:

ExportError – If the format is unsupported, or no backend can write it.

glyphx.export.available_backends() → list[str][source]

Return the export backends installed in this environment.

Returns:

Backend names, best first. Empty if none are installed.

Return type:

list[str]

PDF writer

The pure-Python PDF backend. It needs nothing beyond the standard library, which is why .pdf works in a bare virtualenv or CI container with no system libraries and no browser.

glyphx.pdf_writer.svg_to_pdf(svg: str, path: str) → None[source]

Write svg to path as a vector PDF, using only the standard library.

Parameters:
  • svg – An SVG document.

  • path – Destination .pdf file.

Raises:

UnsupportedSVGError – For SVG features with no faithful PDF equivalent here – gradients, clipping, filters, embedded images. Raised rather than dropped, so the output is never quietly missing part of the chart.

class glyphx.pdf_writer.UnsupportedSVGError[source]

Bases: ValueError

Raised for SVG this converter cannot faithfully reproduce.

Preferred over dropping the element: a PDF that silently lost a gradient or a clipped region looks complete while being wrong, and the caller has no way to notice.

pandas backend

Registered under the pandas_plotting_backends entry point, so pd.options.plotting.backend = "glyphx" resolves here. Not called directly – see glyphx.Figure.line() and the accessor below for GlyphX’s own APIs.

glyphx.pandas_backend.plot(data, x=None, y=None, kind: str = 'line', **kwargs: Any)[source]

Entry point pandas calls for df.plot() / series.plot() and the df.plot.line()-style accessors, once pd.options.plotting.backend = "glyphx" is set.

Not meant to be called directly – see line() and friends, or the DataFrame accessor at glyphx.accessor, for GlyphX’s own plotting APIs.

Returns:

ready to .show(), .share() or .save(). Also displays automatically in a notebook, the same as any other GlyphX figure – matplotlib’s backend returns an Axes instead, which is the one difference a caller migrating existing code will notice in the return value.

Return type:

Figure