Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Sera

One Rust engine. Three pillars. Zero glue code.

SeraPlot for visualization, SeraML for machine learning, SeraDFrame for dataframes — compiled into a single native binary, calling each other directly instead of serializing across library boundaries.

PyPI npm License

Why one engine instead of three libraries

Plotly, scikit-learn, and pandas are each excellent at what they do — and each is a separate library with its own object model. Connecting them means converting DataFrames to NumPy arrays to lists and back, at every boundary. Sera exists because that conversion cost is real, and because a chart, a trained model, and the table that fed both of them don't need to live in different worlds.

sp.kmeans() computes the clustering and renders the chart in the same Rust call — no round-trip through scikit-learn, no intermediate serialization. That is the whole design principle behind Sera: build once, natively, and let every pillar call the others directly.

PillarWhat it isWhere to go deeper
SeraPlotThe rendering engine — 61 2D chart families, 24 3D types, 2 map types, each with several variants. Self-contained HTML/SVG output, no JS bundle.Intro SeraPlot · Showcase
SeraMLA scikit-learn-shaped machine learning layer written in Rust — linear models, trees, ensembles (random forest, gradient boosting, AdaBoost), SVM, k-NN, Naive Bayes, PCA, clustering, anomaly detection, model selection, metrics, preprocessing. Plus a model registry, PowerBI/Tableau export, and GPU/distributed backends that scikit-learn itself doesn't ship.Machine Learning
SeraDFrameA native columnar dataframe, built for the same pipeline rather than adapted from one — no pandas dependency, no copy at the boundary when it feeds a chart or a model.SeraDFrame

How to develop well with Sera

The three pillars share the same conventions on purpose, so that switching between them costs nothing:

  • One call, one result. sp.bar(...), sp.linear_regression(...), df.groupby(...) all follow the same flat-function shape — no builder object to assemble first, no separate .fit() then .transform() unless the algorithm genuinely needs state across calls.
  • Aliases are free. Every function is reachable under several names (sp.bar / sp.bars / sp.bar_chart / sp.bar_unified) resolved through a shared alias registry — pick the name that reads best in your code, they compile to the same call.
  • Native output, always. A chart is real HTML/SVG, a model result is a real Python dict, a DataFrame column is real Rust-backed memory — never an opaque wrapper object you have to unwrap to get to the actual data.
  • The fastest path is the default path. Because computation happens in Rust before anything crosses into Python, the ergonomic way to write code and the fast way to write code are the same code.

The controller: one config call, every chart obeys it

Every pillar reads from the same global controller instead of repeating options per call. Set it once — font, palette, animation, locale — and every Chart built afterward inherits it automatically, with any single call still free to override a value locally.

import seraplot as sp

sp.config(
    font="Inter", font_size=13,
    palette="viridis", background="#0d1117",
    animation=True, animation_duration=420,
    crosshair=True, zoom=True, tooltip=True,
    locale="en-US", thousands_sep=",",
    responsive=True, export_button=True,
)

sp.bar("Revenue", labels, values)          # inherits every setting above
sp.bar("Revenue", labels, values, font_size=16)  # overrides just this one

sp.config() exposes 30+ knobs this way — typography, palette/background, gridlines and despine, text auto-formatting and rotation, bar corner radius, watermark, drop shadow, crosshair/zoom/tooltip behavior, locale-aware number formatting, responsive layout, export button visibility. sp.reset_config() reverts to defaults, sp.theme() swaps a whole preset in one call. See Chart Methods for the full controller reference and every chainable per-chart method, and Configuration for the config surface in depth.

Accessibility and browser support, actually checked

Not a claim — verified this way: axe-core runs against real Chromium for every chart family with zero serious/critical violations; text and non-text contrast is measured (relative luminance, not eyeballed) against WCAG AA; keyboard navigation (roving tabindex, arrow/Home/End) works on data points and legends; the whole catalog loads with zero console errors on real Chromium, Firefox, and WebKit engines, not just one.

Where to start

Pourquoi un seul moteur plutôt que trois bibliothèques

Plotly, scikit-learn et pandas sont chacun excellents dans leur domaine — et chacun est une bibliothèque séparée avec son propre modèle d'objets. Les connecter implique de convertir des DataFrames en tableaux NumPy puis en listes et inversement, à chaque frontière. Sera existe parce que ce coût de conversion est réel, et parce qu'un graphique, un modèle entraîné et la table qui a nourri les deux n'ont pas besoin de vivre dans des mondes différents.

sp.kmeans() calcule le clustering et rend le graphique dans le même appel Rust — aucun aller-retour vers scikit-learn, aucune sérialisation intermédiaire. C'est tout le principe de conception derrière Sera : construire une seule fois, nativement, et laisser chaque pilier appeler les autres directement.

PilierCe que c'estPour aller plus loin
SeraPlotLe moteur de rendu — 61 familles de graphiques 2D, 24 types 3D, 2 types de cartes, chacun avec plusieurs variantes. Sortie HTML/SVG autonome, sans bundle JS.Intro SeraPlot · Vitrine
SeraMLUne couche de machine learning façon scikit-learn écrite en Rust — modèles linéaires, arbres, ensembles (random forest, gradient boosting, AdaBoost), SVM, k-NN, Naive Bayes, PCA, clustering, détection d'anomalies, sélection de modèle, métriques, preprocessing. Plus un registre de modèles, un export PowerBI/Tableau, et des backends GPU/distribués que scikit-learn lui-même n'a pas.Machine Learning
SeraDFrameUn dataframe colonnaire natif, conçu pour le même pipeline plutôt qu'adapté depuis un autre — pas de dépendance pandas, pas de copie à la frontière quand il alimente un graphique ou un modèle.SeraDFrame

Comment bien développer avec Sera

Les trois piliers partagent les mêmes conventions volontairement, pour que passer de l'un à l'autre ne coûte rien :

  • Un appel, un résultat. sp.bar(...), sp.linear_regression(...), df.groupby(...) suivent tous la même forme de fonction à plat — pas d'objet builder à assembler d'abord, pas de .fit() puis .transform() séparés sauf si l'algorithme a réellement besoin d'état entre les appels.
  • Les alias sont gratuits. Chaque fonction est accessible sous plusieurs noms (sp.bar / sp.bars / sp.bar_chart / sp.bar_unified) résolus via un registre d'alias partagé — choisissez le nom qui se lit le mieux dans votre code, ils compilent vers le même appel.
  • Sortie native, toujours. Un graphique est du vrai HTML/SVG, un résultat de modèle est un vrai dict Python, une colonne de DataFrame est de la vraie mémoire portée par Rust — jamais un objet wrapper opaque qu'il faut déballer pour accéder à la donnée réelle.
  • Le chemin le plus ergonomique est le chemin le plus rapide. Parce que le calcul se fait en Rust avant de traverser vers Python, la façon la plus naturelle d'écrire du code et la façon la plus rapide sont le même code.

Le contrôleur : un appel de config, tous les graphiques obéissent

Chaque pilier lit depuis le même contrôleur global plutôt que de répéter les options à chaque appel. Configurez une fois — police, palette, animation, locale — et chaque Chart construit ensuite hérite automatiquement, tout en restant libre de surcharger une valeur localement.

import seraplot as sp

sp.config(
    font="Inter", font_size=13,
    palette="viridis", background="#0d1117",
    animation=True, animation_duration=420,
    crosshair=True, zoom=True, tooltip=True,
    locale="fr-FR", thousands_sep=" ",
    responsive=True, export_button=True,
)

sp.bar("Revenu", labels, values)                  # hérite de tous les réglages ci-dessus
sp.bar("Revenu", labels, values, font_size=16)     # surcharge juste celui-ci

sp.config() expose 30+ réglages de cette façon — typographie, palette/fond, gridlines et despine, formatage/rotation automatique du texte, rayon des coins de barre, watermark, ombre portée, comportement crosshair/zoom/tooltip, formatage numérique localisé, mise en page responsive, visibilité du bouton d'export. sp.reset_config() revient aux défauts, sp.theme() change tout un preset en un appel. Voir Méthodes des graphiques pour la référence complète du contrôleur et chaque méthode chainable par graphique, et Configuration pour la surface de config en détail.

Accessibilité et compatibilité navigateur, réellement vérifiées

Pas une affirmation — vérifié ainsi : axe-core s'exécute contre un vrai Chromium pour chaque famille de graphique, zéro violation serious/critical ; le contraste texte et non-texte est mesuré (luminance relative, pas à l'œil) contre WCAG AA ; la navigation clavier (tabindex flottant, flèches/Home/End) fonctionne sur les points de données et les légendes ; tout le catalogue charge sans erreur console sur de vrais moteurs Chromium, Firefox et WebKit, pas un seul.

Par où commencer

Installation

Requirements

  • Python 3.8+
  • pip 21+

SeraPlot ships as a compiled Rust extension (.pyd / .so) bundled in the wheel. There is no compiler required on the user side — the binary is pre-built for each platform.


Install

Standard Python package installer — works in any environment:

pip install seraplot
pip install seraplot
pip install --upgrade seraplot
💡For project isolation, always install inside a virtual environment: python -m venv .venv && .venv\Scripts\activate
⚡ Recommended — 10–100× faster than pip

uv is a next-generation Python package manager written in Rust — resolves and installs packages in milliseconds.

uv add seraplot
💡Run pip install uv once to install uv, then use uv add in any project.

Install from the conda-forge channel, or declare it in your environment file:

conda install -c conda-forge seraplot

Or add to environment.yml:

dependencies:
  - pip:
    - seraplot

Why the install is this simple

SeraPlot has zero required Python dependencies. The Rust extension is entirely self-contained — the HTML output embeds its own JavaScript inline and does not load anything from a CDN.

🌐 Works offline Charts render in air-gapped environments, emails, PDF exports via browser print — no CDN, no internet.
🔒 No conflicts Zero dependency on numpy, pandas, or scipy — nothing to conflict with your existing stack.
🚀 All platforms Pre-built wheels for Windows, Linux, and macOS. No compiler, no Rust toolchain needed.
🪶 Tiny footprint pip install plotly downloads ~15 MB. pip install seraplot downloads ~2 MB.

Prérequis

  • Python 3.8+
  • pip 21+

SeraPlot se distribue sous forme d'extension Rust compilée (.pyd / .so) incluse dans le wheel. Aucun compilateur n'est requis côté utilisateur — le binaire est pré-compilé pour chaque plateforme.


Installer

Gestionnaire de paquets Python standard — fonctionne dans tous les environnements :

pip install seraplot
pip install seraplot
pip install --upgrade seraplot
💡Pour isoler votre projet, installez toujours dans un environnement virtuel : python -m venv .venv && .venv\Scripts\activate
⚡ Recommandé — 10 à 100× plus rapide que pip

uv est un gestionnaire de paquets Python nouvelle génération écrit en Rust — résout et installe les paquets en quelques millisecondes.

uv add seraplot
💡Exécutez pip install uv une seule fois pour installer uv, puis utilisez uv add dans chaque projet.

Installez depuis le canal conda-forge, ou déclarez-le dans votre fichier d'environnement :

conda install -c conda-forge seraplot

Ou ajoutez dans environment.yml :

dependencies:
  - pip:
    - seraplot

Pourquoi l'installation est aussi simple

SeraPlot n'a aucune dépendance Python requise. L'extension Rust est entièrement autonome — le HTML embarque son propre JavaScript sans rien charger depuis un CDN.

🌐 Fonctionne hors ligne Les graphiques se génèrent en environnement isolé, dans les e-mails, en impression PDF — sans CDN ni internet.
🔒 Zéro conflit Aucune dépendance sur numpy, pandas ou scipy — rien qui puisse entrer en conflit avec votre stack.
🚀 Toutes plateformes Wheels pré-compilés pour Windows, Linux et macOS. Aucun compilateur, aucune toolchain Rust requise.
🪶 Empreinte minimale pip install plotly télécharge ~15 Mo. pip install seraplot télécharge ~2 Mo.

SeraPlot

Plot anything. Train anything. Ship anywhere.

A Rust-native engine for visualization, machine learning, and zero-friction delivery — 6,000× faster than Plotly, 200× smaller, zero dependencies.

PyPI npm License

Seraplot, More than a charting library

SeraPlot is a complete data toolkit written in Rust. The same engine powers your visualizations, your machine learning, and the way you ship results to other people.

PillarWhat you get
Plot57 chart types — 33 in 2D, 17 in 3D (WebGL), 2 maps. Built-in themes, palettes, animation, zoom, crosshair, export.
TrainScikit-learn-compatible ML in Rust — DBSCAN, K-Means, RandomForest, GradientBoosting, SVM, PCA, GridSearchCV, train/test split. 1.3× to 686× faster.
Stream & scaleLive updates, downsampling for millions of points, drift detection, AutoML, diff mode, facet grids.
ShipSelf-contained 21 KB HTML — no CDN, no backend, works offline, by email, in S3, in PDFs, in Notion, in air-gapped CI.
IntegratePython, JavaScript, TypeScript, Rust. Drop-in seraplot.matplotlib as plt migration. Pandas / NumPy native.
AuthorNative VS Code extension — live preview, gallery, theme studio, snippets, auto-detection of labels / values from your code.
Persist & exportSave to HTML, PNG, SVG, PDF, pickle. Re-load trained ML models. CSP-safe output.
Stay accessibleA11y-tagged SVG, semantic HTML, keyboard navigation, locale-aware number formatting.

One library replaces: matplotlib + plotly + dash + streamlit + seaborn + parts of scikit-learn — with one pip install and zero runtime dependencies.


Same chart — three libraries

import seraplot as sp
sp.bar("Revenue by Product", labels, values).save("chart.html")
import plotly.express as px
fig = px.bar(x=labels, y=values, title="Revenue by Product")
fig.update_layout(template="plotly_white")
fig.write_html("chart.html")
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(9, 5))
ax.bar(labels, values, color="#6366f1")
ax.set_title("Revenue by Product")
ax.set_ylabel("Revenue")
plt.tight_layout()
plt.savefig("chart.png")
SeraPlotPlotlyMatplotlib
Lines of code247
OutputHTMLHTMLPNG
File size21 KB4.7 MB~150 KB
Interactive
Dependencies06+3+
1-line migration

Why Seraplot?

As you’ve probably understood by now, Seraplot is a tool designed to be extremely customizable, while also being much faster and more resource-efficient than existing solutions. It also provides a wide range of helpful features, such as the Seraplot extension for VSCode, which allows you to generate plots or ML methods very quickly and live, between each save of your scripts.

In addition, Seraplot is available across multiple languages such as: JS/TS, C (C# & C++), Java, Rust, Python, R & Scala. The main goal is to be highly accessible: from one language to another, the commands remain the same for greater simplicity.

In summary, Seraplot is a much more practical and independent tool that enables the generation of 2D & 3D plots, while also aiming to provide machine learning-related methods that you will find throughout the documentation. More surprises await you, such as the ability to choose different themes, a chunk system in case of crashes to resume from the error point, and even multiple aliases to use the same method (e.g., sp.build_bar_chart / sp.bar_chart / sp.bar / sp.bars).


1000 charts. Measured.

Same code, same random data, same machine. Full HTML output timed.

import seraplot as sp
categories = ["Electronics", "Clothing", "Food", "Books", "Sports", "Toys", "Health", "Auto"]
data = [...]  # 1000 pre-generated lists
for i in range(1000):
    sp.bar(f"Report #{i+1}", categories, data[i]).html

1000 charts in 6 ms — 6 µs/chart

import plotly.graph_objects as go
categories = ["Electronics", "Clothing", "Food", "Books", "Sports", "Toys", "Health", "Auto"]
data = [...]  # same 1000 pre-generated lists
for i in range(1000):
    fig = go.Figure(data=[go.Bar(x=categories, y=data[i])])
    fig.update_layout(title=f"Report #{i+1}", template="plotly_dark")
    fig.to_html(full_html=True, include_plotlyjs="cdn")

1000 charts in 37,023 ms — 6,170× slower

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
categories = ["Electronics", "Clothing", "Food", "Books", "Sports", "Toys", "Health", "Auto"]
data = [...]  # same 1000 pre-generated lists
for i in range(1000):
    fig, ax = plt.subplots(figsize=(9, 5))
    ax.bar(categories, data[i])
    ax.set_title(f"Report #{i+1}")
    fig.savefig(f"chart_{i}.png")
    plt.close()

1000 charts in 60,352 ms — 10,058× slower

ScaleSeraPlotPlotlyMatplotlib
1,000 charts6 ms37 s60 s
10,000 charts~60 ms~6 min~10 min
100,000 charts~600 ms~1 h~1.7 h

Render core speed

Benchmark: Diabetes dataset (n=768, 40 runs). Rust render time — chart object creation, not full HTML serialization.

Pie
7,956×
Bar
6,488×
Lollipop
3,983×
Grouped Bar
3,596×
Candlestick
2,038×
Radar
1,498×
KDE
753×
ChartSeraPlotPlotly figurePlotly → HTMLMatplotlib
Pie4.272533,41615,085
Bar2.865818,16613,596
Grouped Bar5.055817,98117,445
Histogram12.42,49632,76237,973
Scatter17.03,91621,61514,141
Violin16.72,61621,34721,211
Box Plot18.42,32921,79915,590
KDE26.32,98119,80740,108
Radar11.896217,67920,942
Lollipop6.38,38225,0969,072
Candlestick8.81,47817,934N/A
Ridgeline88.8N/AN/AN/A

All times in µs.


Output file size

Plotly embeds its entire JavaScript bundle in every HTML file. SeraPlot only includes the JS needed for that specific chart type.

Pie
19 KB vs 4,733 KB — 246×
Bar
21 KB vs 4,733 KB — 225×
Scatter
39 KB vs 4,740 KB — 121×
Radar
23 KB vs 4,733 KB — 205×

Matplotlib outputs PNG/SVG/PDF (50-500 KB) — not interactive HTML.


What SeraPlot actually is

SeraPlot is not a wrapper around Plotly, Chart.js, or D3.

It is a Rust-native rendering engine that generates minimal HTML + JS per chart. A Pie chart gets Pie JS. A Bar chart gets Bar JS. Nothing else is bundled.

That's why the output is 20 KB instead of 4.7 MB.


One line migration

import seraplot.matplotlib as plt

Everything else stays the same. plt.bar(), plt.scatter(), plt.hist(), plt.show(), plt.savefig() — unchanged.


Deploy from an API

from fastapi import FastAPI
import seraplot as sp
app = FastAPI()
@app.get("/chart")
def revenue_chart():
    return sp.bar("Revenue", labels, values).html
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
import plotly.express as px
app = FastAPI()
@app.get("/chart", response_class=HTMLResponse)
def revenue_chart():
    fig = px.bar(x=labels, y=values, title="Revenue")
    return fig.to_html(full_html=True)
from fastapi import FastAPI
from fastapi.responses import FileResponse
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import tempfile
app = FastAPI()
@app.get("/chart")
def revenue_chart():
    fig, ax = plt.subplots(figsize=(9, 5))
    ax.bar(labels, values)
    ax.set_title("Revenue")
    path = tempfile.mktemp(suffix=".png")
    plt.savefig(path)
    plt.close()
    return FileResponse(path, media_type="image/png")

Plotly returns 4.7 MB per request. Matplotlib requires disk I/O and returns a static PNG. SeraPlot returns 21 KB of interactive HTML directly from RAM.


Everything SeraPlot does

  • 57 chart types — every 2D chart has a 3D WebGL variant
  • Drop-in matplotlib APIimport seraplot.matplotlib as plt
  • Pandas & NumPy native — pass DataFrames directly
  • 7 built-in themes — dark, light, scientific, apple, notion, minimal, neon
  • Global configsp.config() sets font, zoom, crosshair, animation across all charts
  • Zero dependencies — pure Rust renderer
  • 200× smaller files — no bundled JS runtime
  • Multi-language — Python, JavaScript/TypeScript (npm), Rust, R, Scala, C#, C++, Java
  • DBSCAN up to 600× faster than scikit-learn
  • Native Machine learning — some ml methods is include by default in this tool
  • Works everywhere — Python ≥ 3.8, any OS

Seraplot - Bien plus qu'une bibliothèque de graphiques

« Tout tracer. Tout entraîner. Partout déployer. »

SeraPlot est une boîte à outils data complète écrite en Rust. Le même moteur propulse vos visualisations, votre machine learning, et la façon dont vous livrez les résultats à vos collègues.

PilierCe que vous obtenez
Tracer57 types de graphiques — 33 en 2D, 17 en 3D (WebGL), 2 cartes. Thèmes intégrés, palettes, animations, zoom, crosshair, export.
EntraînerML compatible scikit-learn en Rust — DBSCAN, K-Means, RandomForest, GradientBoosting, SVM, PCA, GridSearchCV, train/test split. De 1,3× à 686× plus rapide.
Streamer & passer à l'échelleMises à jour en direct, downsampling pour des millions de points, détection de drift, AutoML, mode diff, grilles de facettes.
DéployerHTML autonome de 21 Ko — pas de CDN, pas de backend, fonctionne hors-ligne, par e-mail, sur S3, dans des PDF, dans Notion, en CI isolée.
IntégrerPython, JavaScript, TypeScript, Rust. Migration directe seraplot.matplotlib as plt. Pandas / NumPy nativement.
CoderExtension VS Code native — aperçu en direct, galerie, studio de thèmes, snippets, détection automatique des labels / values depuis votre code.
Persister & exporterExport HTML, PNG, SVG, PDF, pickle. Rechargement des modèles ML entraînés. Sortie compatible CSP.
Rester accessibleSVG balisé a11y, HTML sémantique, navigation clavier, formatage numérique localisé.

Une seule librairie remplace : matplotlib + plotly + dash + streamlit + seaborn + une partie de scikit-learn — avec un seul pip install et zéro dépendance d'exécution.


Même graphique — trois bibliothèques

import seraplot as sp
sp.bar("Chiffre d'affaires par produit", labels, values).save("chart.html")
import plotly.express as px
fig = px.bar(x=labels, y=values, title="Chiffre d'affaires par produit")
fig.update_layout(template="plotly_white")
fig.write_html("chart.html")
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(9, 5))
ax.bar(labels, values, color="#6366f1")
ax.set_title("Chiffre d'affaires par produit")
ax.set_ylabel("Chiffre d'affaires")
plt.tight_layout()
plt.savefig("chart.png")
SeraPlotPlotlyMatplotlib
Lignes de code247
SortieHTMLHTMLPNG
Taille fichier21 Ko4,7 Mo~150 Ko
Interactif
Dépendances06+3+
Migration 1 ligne

Pourquoi Seraplot ?

Comme vous l’aurez compris en arrivant jusqu’ici, Seraplot est un outil qui a pour objectif d’être extrêmement personnalisable, mais aussi beaucoup plus rapide et moins gourmand que ce qui existe déjà, en plus de proposer tout un panel d’aides, comme l’extension Seraplot dans VSCode, qui vous permettra de générer des plots ou des méthodes ML très rapidement et en live, entre chaque sauvegarde de vos scripts.

En plus de cela, Seraplot se voit distribué dans différents langages comme : JS/TS, C (C# & C++), Java, Rust, Python, R & Scala. L’objectif étant vraiment d’être ultra accessible : d’un langage à un autre, les commandes restent les mêmes pour plus de simplicité.

Pour résumer, Seraplot est un outil beaucoup plus pratique de ce qui existe déjà et complétement indépendant, en plus de compilé différente fonctionnalitée. En autre il permet la génération de plots 2D & 3D, mais aussi qui tend à proposer des méthodes liées au ML, que vous pourrez retrouver au cours de votre documentation. D’autres surprises vous attendent, que ce soit la possibilité de choisir différents thèmes, ou bien le système de chunks en cas de crash pour reprendre au point d’erreur, ou encore pour n'en citer que un dernier, le fait d’avoir différents alias pour utiliser une même méthode (ex : sp.build_bar_chart / sp.bar_chart / sp.bar / sp.bars).


1 000 graphiques. Mesurés.

Même code, mêmes données aléatoires, même machine. Sortie HTML complète chronométrée.

import seraplot as sp
categories = ["Électronique", "Vêtements", "Alimentation", "Livres", "Sport", "Jouets", "Santé", "Auto"]
data = [...]
for i in range(1000):
    sp.bar(f"Rapport #{i+1}", categories, data[i]).html

1 000 graphiques en 6 ms — 6 µs/graphique

import plotly.graph_objects as go
categories = ["Électronique", "Vêtements", "Alimentation", "Livres", "Sport", "Jouets", "Santé", "Auto"]
data = [...]
for i in range(1000):
    fig = go.Figure(data=[go.Bar(x=categories, y=data[i])])
    fig.update_layout(title=f"Rapport #{i+1}", template="plotly_dark")
    fig.to_html(full_html=True, include_plotlyjs="cdn")

1 000 graphiques en 37 023 ms — 6 170× plus lent

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
categories = ["Électronique", "Vêtements", "Alimentation", "Livres", "Sport", "Jouets", "Santé", "Auto"]
data = [...]
for i in range(1000):
    fig, ax = plt.subplots(figsize=(9, 5))
    ax.bar(categories, data[i])
    ax.set_title(f"Rapport #{i+1}")
    fig.savefig(f"chart_{i}.png")
    plt.close()

1 000 graphiques en 60 352 ms — 10 058× plus lent

ÉchelleSeraPlotPlotlyMatplotlib
1 000 graphiques6 ms37 s60 s
10 000 graphiques~60 ms~6 min~10 min
100 000 graphiques~600 ms~1 h~1,7 h

Vitesse du moteur de rendu

Benchmark : dataset Diabetes (n=768, 40 itérations). Temps de rendu Rust — création de l'objet graphique, pas la sérialisation HTML complète.

Camembert
7 956×
Barres
6 488×
Sucette
3 983×
Barres groupées
3 596×
Bougie
2 038×
Radar
1 498×
KDE
753×
GraphiqueSeraPlotPlotly figurePlotly → HTMLMatplotlib
Camembert4,272533 41615 085
Barres2,865818 16613 596
Barres groupées5,055817 98117 445
Histogramme12,42 49632 76237 973
Nuage de points17,03 91621 61514 141
Violon16,72 61621 34721 211
Boîte à moustaches18,42 32921 79915 590
KDE26,32 98119 80740 108
Radar11,896217 67920 942
Sucette6,38 38225 0969 072
Bougie8,81 47817 934N/A
Ridgeline88,8N/AN/AN/A

Toutes les valeurs en µs.


Taille des fichiers de sortie

Plotly embarque tout son bundle JavaScript dans chaque fichier HTML. SeraPlot n'inclut que le JS nécessaire au type de graphique spécifique.

Camembert
19 Ko vs 4 733 Ko — 246×
Barres
21 Ko vs 4 733 Ko — 225×
Nuage de points
39 Ko vs 4 740 Ko — 121×
Radar
23 Ko vs 4 733 Ko — 205×

Matplotlib produit du PNG/SVG/PDF (50–500 Ko) — pas du HTML interactif.


Ce qu'est réellement SeraPlot

SeraPlot n'est pas un wrapper autour de Plotly, Chart.js ou D3.

C'est un moteur de rendu natif Rust qui génère du HTML + JS minimal par graphique. chaque chart reçoit soit js dédiée. Rien d'autre n'est embarqué.

C'est pour ça que la sortie fait 20 Ko au lieu de 4,7 Mo.


Migration en une ligne

import seraplot.matplotlib as plt

Tout le reste reste identique. plt.bar(), plt.scatter(), plt.hist(), plt.show(), plt.savefig() — inchangés.


Déployer depuis une API

from fastapi import FastAPI
import seraplot as sp
app = FastAPI()
@app.get("/chart")
def revenue_chart():
    return sp.bar("Chiffre d'affaires", labels, values).html
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
import plotly.express as px
app = FastAPI()
@app.get("/chart", response_class=HTMLResponse)
def revenue_chart():
    fig = px.bar(x=labels, y=values, title="Chiffre d'affaires")
    return fig.to_html(full_html=True)
from fastapi import FastAPI
from fastapi.responses import FileResponse
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import tempfile
app = FastAPI()
@app.get("/chart")
def revenue_chart():
    fig, ax = plt.subplots(figsize=(9, 5))
    ax.bar(labels, values)
    ax.set_title("Chiffre d'affaires")
    path = tempfile.mktemp(suffix=".png")
    plt.savefig(path)
    plt.close()
    return FileResponse(path, media_type="image/png")

Plotly retourne 4,7 Mo par requête. Matplotlib nécessite des I/O disque et retourne un PNG statique. SeraPlot retourne 21 Ko de HTML interactif directement depuis la RAM.


Tout ce que SeraPlot fait

  • 57 types de graphiques — chaque graphique 2D a une variante 3D WebGL
  • API matplotlib drop-inimport seraplot.matplotlib as plt
  • Pandas & NumPy natifs — passez les DataFrames directement
  • 7 thèmes intégrés — dark, light, scientific, apple, notion, minimal, neon
  • Configuration globalesp.config() définit la police, le zoom, le réticule, l'animation pour tous les graphiques
  • Zéro dépendance — moteur de rendu Rust pur
  • Fichiers 200× plus petits — pas de runtime JS embarqué
  • Multi-langage — Python, JavaScript/TypeScript (npm), Rust, R, Scala, C#, C++, Java
  • DBSCAN jusqu'à 600× plus rapide que scikit-learn
  • Machine learning natif — Plusieurs methods ml, sont déjà existante dans le framework
  • Fonctionne partout — Python ≥ 3.8, tout OS

Showcase

Chart methods

Chart methods & global config

Every Chart object returned by SeraPlot supports the same fluent API. Set defaults once with sp.config() and tweak per chart with chainable methods. All methods return a new Chart, so chaining is always safe.

Fluent APIGlobal + per-chart override60+ chart typesDoc-as-code: every card below is generated from the Rust source

Set defaults once. Every chart created afterwards inherits this configuration automatically.

💾Persist aliases across sessions
sp.config.add_alias("bar", "barchart")
sp.config.add_alias("line", "linechart")
sp.config.save()  # writes to ~/.seraplot/config.json
import seraplot as sp  # aliases are auto-loaded from ~/.seraplot/config.json

Curated presets that combine palette, background and gridlines.

ThemeMood
"dark"High-contrast dark dashboard
"light"Soft pastel light backdrop
"scientific"Publication-style monochrome
"apple"Glassy iOS-inspired palette
"notion"Calm Notion-style neutrals
"minimal"Bare lines, no chrome
"neon"Vibrant cyberpunk neons
sp.config(theme=...)global
Apply a theme globally to all charts created after this call. Combine with any other config keys.
sp.config(theme="dark", gridlines=True, font="Inter")
chart = sp.bar("Sales", labels=["Q1","Q2","Q3"], values=[120,180,150])
chart.show()
Tip: Call sp.reset_theme() to return to the framework default at any point.
3

Chart methods

Generated from #[sera_doc] in the Rust source

Every card below is generated straight from the #[sera_doc(...)] annotation on the matching Rust method — name, parameters and description always match the actual implementation.

.html  propertyread-only
Read the full HTML payload as a string.
src = chart.html
len(chart) → intproperty
Returns the size of the HTML payload in bytes.
print(len(chart))
bool(chart) → boolproperty
True when the chart has rendered output.
if chart:
    chart.show()
5

Annotations (cross-chart)

SVG overlays inherited by every plot

annotations=[...] (kwarg)newglobal
Pass a list of annotation dicts to any chart builder. Coordinates default to fractional canvas space (0.0–1.0); set "frac": false to use raw pixels. Supported kind: "hline", "vline", "line", "arrow", "rect", "text".
chart = sp.line(
    "Sales", labels=months, values=sales,
    annotations=[
        {"kind":"hline", "y":0.5, "color":"#22c55e", "dash":"6 4", "text":"Target"},
        {"kind":"vline", "x":0.62, "color":"#f59e0b", "text":"Launch"},
        {"kind":"rect",  "x":0.05, "y":0.65, "x2":0.40, "y2":0.92,
                         "color":"#6366f1", "fill":"#6366f1", "opacity":0.10},
        {"kind":"arrow", "x":0.45, "y":0.30, "x2":0.85, "y2":0.18, "color":"#ef4444"},
        {"kind":"text",  "x":0.46, "y":0.28, "text":"Outlier", "color":"#ef4444"},
    ],
)
Annotation fields
Every annotation accepts the same shape:
FieldTypeDefaultDescription
kindstrrequiredhline / vline / line / arrow / rect / text
x, yfloat0.5Anchor point (frac of canvas if frac=True, pixels otherwise)
x2, y2float1.0End point for line / arrow / rect
colorstr"#ef4444"Stroke / text color (CSS)
fillstr"none"Fill color (rect only)
stroke_widthfloat1.5Stroke width
dashstr""SVG dash array, e.g. "6 4"
opacityfloat1.00.0 - 1.0
textstrNoneOptional label rendered next to the primitive
font_sizefloat11.0Label font size
fracbooltrueCoordinate space: fractional (0-1) or pixel
Tip: Annotations apply uniformly to every 2D and 3D chart through the apply_annotations() hook - no per-chart wiring required.
6

Composers (Grid + Slideshow)

Group charts into stories

sp.grid() alias: sp.build_grid

Compose any number of pre-built charts into a responsive CSS-grid, each chart isolated in its own iframe.

chartslist[Chart]Charts to arrange
colsint = 3Number of columns
gapint = 16Gap between cells in px
bg_colorstrGrid background
titlestr = ""Optional header title
cell_heightint | NoneOverride each cell height
bar  = sp.bar("Sales", labels=["Q1","Q2","Q3","Q4"], values=[120,180,150,210])
line = sp.line("Trend", labels=months, values=sales)
pie  = sp.pie("Mix", labels=["A","B","C"], values=[40,35,25])
sp.grid([bar, line, pie], cols=3, gap=14, title="Dashboard").show()
sp.build_slideshow() navigable HTML carousel

Build a navigable HTML carousel with prev / next buttons and an auto-advance progress bar — tell a story without a slide deck.

chartslist[Chart]Ordered slide list
interval_msint = 2500Auto-advance delay in ms
titlestr = ""Carousel title
widthint = 900Output width in px
heightint = 520Output height in px
slides = [sp.bar(f"Slide {i+1}", labels=["A","B"], values=[i, i+1]) for i in range(4)]
sp.build_slideshow(slides, interval_ms=2200, title="Quarterly Story").show()

Configuration

Two layers, and every page in this section names which one it documents:

  • Global, standalone functionssp.set_global_background(...), sp.theme(...), sp.config(...) — apply before charts are built and affect everything created afterward. See Chart Methods for the full generated list.
  • Chainable Chart methodschart.export_svg(path), chart.hover_json(payload), chart.downsample() — apply to one already-built chart and return a new Chart, the same way every other per-chart method chains.

Every code sample in this section is checked against a real build rather than written from memory — where a feature exists only on the JS/WASM side, or isn't wired up as a Python function yet, that is stated explicitly instead of shown as if it worked.

Deux couches, et chaque page de cette section précise laquelle elle documente :

  • Fonctions globales autonomessp.set_global_background(...), sp.theme(...), sp.config(...) — s'appliquent avant la construction des graphiques et affectent tout ce qui est créé ensuite. Voir Méthodes des graphiques pour la liste complète générée.
  • Méthodes chaînables sur Chartchart.export_svg(path), chart.hover_json(payload), chart.downsample() — s'appliquent à un chart déjà construit et retournent un nouveau Chart, comme toute autre méthode par graphique.

Chaque exemple de code de cette section est vérifié contre un vrai build plutôt qu'écrit de mémoire — quand une fonctionnalité n'existe que côté JS/WASM, ou n'est pas encore câblée comme fonction Python, c'est dit explicitement plutôt que présenté comme si ça fonctionnait.

Background Configuration

Functions

FunctionDescription
set_global_background(color)Sets a global background color applied to all charts created after the call.
reset_global_background()Clears the global background, reverting to each chart's own default.
ParameterTypeDescription
colorstrCSS color string (hex "#rrggbb", "rgb(...)", named color)

Example

import seraplot as sp

sp.set_global_background("#0f172a")

bar = sp.build_bar_chart("Revenue", labels=["A", "B"], values=[300, 200])
pie = sp.build_pie_chart("Share", labels=["A", "B"], values=[60, 40])

sp.reset_global_background()

sp.set_global_background(...) is equivalent to sp.config(background=...), and is overridden by sp.theme(name) if a theme is applied afterward — see Themes for the built-in background/palette/gridlines bundles.

Fonctions

FonctionDescription
set_global_background(color)Définit une couleur de fond globale appliquée à tous les graphiques créés après l'appel.
reset_global_background()Efface le fond global, revenant à la valeur par défaut de chaque graphique.
ParamètreTypeDescription
colorstrCouleur CSS (hex "#rrggbb", "rgb(...)", nom de couleur)

Exemple

import seraplot as sp

sp.set_global_background("#0f172a")

barre = sp.build_bar_chart("Revenus", labels=["A", "B"], values=[300, 200])
camembert = sp.build_pie_chart("Parts", labels=["A", "B"], values=[60, 40])

sp.reset_global_background()

sp.set_global_background(...) équivaut à sp.config(background=...), et est écrasé par sp.theme(name) si un thème est appliqué ensuite — voir Thèmes pour la liste des thèmes intégrés (fond + palette + quadrillage).

Palette & Colors

Overview

SeraPlot represents colors as 24-bit RGB integers (int) or CSS strings (str).

FormatExampleUsage
Hex integer0x6366f1color_hex, palette lists
CSS hex string"#6366f1"background, bg_color
CSS named color"navy"background, bg_color

Built-in Palettes

There is no standalone sp.PALETTE_* constant — the built-in color sets ship bundled inside a theme (background + palette + gridlines together). Call sp.theme(name) to apply one, or read Themes for the full list and every palette's exact hex values.

import seraplot as sp

print(sp.themes())
# ['dark', 'light', 'scientific', 'apple', 'notion', 'minimal', 'neon']

sp.theme("dark")
chart = sp.build_bar_chart("Revenue", labels=["A", "B", "C"], values=[100, 200, 150])
sp.reset_theme()

Pass any list of hex ints as the palette parameter to override the palette for a single chart, independent of the active theme:

chart = sp.build_bar_chart(
    "Revenue",
    labels=["A", "B", "C"],
    values=[100, 200, 150],
    palette=[0x6366f1, 0x22d3ee, 0xf43f5e],
)

Color Utility Reference

Parameter nameAcceptsDescription
color_hexintSingle element color
palettelist[int]Multi-element color list
backgroundstrChart canvas background
bg_colorstr3D canvas background
color_low / color_mid / color_highintMin/mid/max heatmap colors
color_up / color_downintRising/falling candle colors
color_pos / color_neg / color_totalintPositive/negative/total bar (waterfall)

Example

import seraplot as sp

chart = sp.build_heatmap(
    "Correlation",
    labels=["A", "B", "C"],
    col_labels=["A", "B", "C"],
    values=[1, 0.8, 0.2, 0.8, 1, 0.5, 0.2, 0.5, 1],
    color_low=0xfaf5ff,
    color_mid=0xa78bfa,
    color_high=0x4c1d95,
)

Aperçu

SeraPlot représente les couleurs sous forme d'entiers RGB 24 bits (int) ou de chaînes CSS (str).

FormatExempleUtilisation
Entier hex0x6366f1color_hex, listes palette
Chaîne CSS hex"#6366f1"background, bg_color
Nom CSS"navy"background, bg_color

Palettes intégrées

Il n'existe pas de constante sp.PALETTE_* autonome — les jeux de couleurs intégrés sont livrés à l'intérieur d'un thème (fond + palette + quadrillage ensemble). Appelez sp.theme(name) pour en appliquer un, ou consultez Thèmes pour la liste complète et les valeurs hex exactes de chaque palette.

import seraplot as sp

print(sp.themes())
# ['dark', 'light', 'scientific', 'apple', 'notion', 'minimal', 'neon']

sp.theme("dark")
chart = sp.build_bar_chart("Revenus", labels=["A", "B", "C"], values=[100, 200, 150])
sp.reset_theme()

Passez n'importe quelle liste d'entiers hex comme paramètre palette pour surcharger la palette d'un seul chart, indépendamment du thème actif :

chart = sp.build_bar_chart(
    "Revenus",
    labels=["A","B","C"],
    values=[100,200,150],
    palette=[0x6366f1, 0x22d3ee, 0xf43f5e],
)

Référence des paramètres de couleur

Nom du paramètreAccepteDescription
color_hexintCouleur d'un élément unique
palettelist[int]Liste de couleurs multi-éléments
backgroundstrFond du canevas HTML
bg_colorstrFond du canevas 3D
color_lowintCouleur valeur min (heatmaps, choroplèthes)
color_midintCouleur valeur médiane
color_highintCouleur valeur max
color_upintCouleur bougie montante
color_downintCouleur bougie descendante
color_posintBarre positive (cascade)
color_negintBarre négative (cascade)
color_totalintBarre totale (cascade)

Exemple

import seraplot as sp

chart = sp.build_heatmap(
    "Corrélation",
    labels=["A","B","C"],
    col_labels=["A","B","C"],
    values=[1, 0.8, 0.2, 0.8, 1, 0.5, 0.2, 0.5, 1],
    color_low=0xfaf5ff,
    color_mid=0xa78bfa,
    color_high=0x4c1d95,
)

Themes

API

FunctionDescription
sp.theme(name)Apply a built-in theme — sets background, palette, and gridlines globally
sp.reset_theme()Revert to defaults (no background, default palette, no gridlines)
sp.themes()Returns a list of all available theme names
import seraplot as sp

sp.theme("dark")
chart = sp.bar("Revenue", labels=["Q1", "Q2", "Q3"], values=[120, 145, 98])

sp.reset_theme()

All 7 themes

ThemeBackgroundGridlinesInspirationPrimary palette
"dark" #0f172aDeep space / Tailwind indigo
"light"transparentClean minimal
"scientific" #fafafaMatplotlib / D3 academic
"apple" #000000Apple dark mode (iOS/macOS)
"notion" #191919Notion editorial dark
"minimal"transparentMonochrome grayscale
"neon" #0a0a0aCyberpunk / retrowave

Full palette per theme

"dark"

[0x818CF8, 0xFB7185, 0x34D399, 0xFBBF24, 0xA78BFA,
 0x22D3EE, 0xF472B6, 0xA3E635, 0xF87171, 0x2DD4BF]

"light"

[0x636EFA, 0xEF553B, 0x00CC96, 0xAB63FA, 0xFFA15A,
 0x19D3F3, 0xFF6692, 0xB6E880, 0xFF97FF, 0xFECB52]

"scientific"

[0x1F77B4, 0xFF7F0E, 0x2CA02C, 0xD62728, 0x9467BD,
 0x8C564B, 0xE377C2, 0x7F7F7F, 0xBCBD22, 0x17BECF]

"apple"

[0x0A84FF, 0x30D158, 0xFF453A, 0xFFD60A, 0xBF5AF2,
 0x64D2FF, 0xFF9F0A, 0xFF375F, 0xAC8E68, 0x63E6E2]

"notion"

[0x529CCA, 0xD08B65, 0x6C9B7D, 0xCB7C7A, 0x9A6DD7,
 0x868686, 0xCCAA55, 0x75B5AA, 0xD477A8, 0x507AA6]

"minimal"

[0x374151, 0x6B7280, 0x9CA3AF, 0xD1D5DB, 0x111827,
 0x4B5563, 0x1F2937, 0xE5E7EB, 0x030712, 0x6B7280]

"neon"

[0x00FF87, 0xFF006E, 0x00B4D8, 0xFFBE0B, 0xE500A4,
 0x8338EC, 0x3A86FF, 0xFB5607, 0xFF006E, 0x06D6A0]

Examples

import seraplot as sp

sp.theme("dark")
sp.bar("Revenue", labels=["Q1", "Q2", "Q3", "Q4"], values=[120, 145, 98, 180]).show()

sp.theme("neon")
sp.scatter(title="Clusters", x=[1, 2, 3, 4, 5, 6], y=[2, 5, 3, 8, 7, 9]).show()

sp.theme("scientific")
sp.line(title="Population Growth", x_labels=["2020", "2021", "2022", "2023"], values=[100, 112, 121, 135]).show()

sp.reset_theme()
print(sp.themes())
# ['dark', 'light', 'scientific', 'apple', 'notion', 'minimal', 'neon']

Notes

  • sp.theme() sets the global background, palette, and gridlines. It is equivalent to calling sp.config(background=..., palette=..., gridlines=...) with the preset values.
  • Themes persist until sp.reset_theme() or sp.config() overrides them.
  • You can further override individual properties after calling a theme:
sp.theme("dark")
sp.config(font_size=16, border_radius=12)

API

FonctionDescription
sp.theme(name)Applique un thème intégré — définit le fond, la palette et le quadrillage globalement
sp.reset_theme()Revient aux valeurs par défaut (pas de fond, palette par défaut, pas de quadrillage)
sp.themes()Retourne la liste de tous les noms de thèmes disponibles
import seraplot as sp

sp.theme("dark")
graphique = sp.bar("Revenus", labels=["T1", "T2", "T3"], values=[120, 145, 98])

sp.reset_theme()

Les 7 thèmes disponibles

ThèmeFondQuadrillageInspirationPalette principale
"dark" #0f172aEspace profond / indigo Tailwind
"light"transparentÉpuré minimal
"scientific" #fafafaMatplotlib / D3 académique
"apple" #000000Mode sombre Apple (iOS/macOS)
"notion" #191919Notion éditorial sombre
"minimal"transparentNuances de gris monochrome
"neon" #0a0a0aCyberpunk / retrowave

Palettes complètes

"dark"

[0x818CF8, 0xFB7185, 0x34D399, 0xFBBF24, 0xA78BFA,
 0x22D3EE, 0xF472B6, 0xA3E635, 0xF87171, 0x2DD4BF]

"light"

[0x636EFA, 0xEF553B, 0x00CC96, 0xAB63FA, 0xFFA15A,
 0x19D3F3, 0xFF6692, 0xB6E880, 0xFF97FF, 0xFECB52]

"scientific"

[0x1F77B4, 0xFF7F0E, 0x2CA02C, 0xD62728, 0x9467BD,
 0x8C564B, 0xE377C2, 0x7F7F7F, 0xBCBD22, 0x17BECF]

"apple"

[0x0A84FF, 0x30D158, 0xFF453A, 0xFFD60A, 0xBF5AF2,
 0x64D2FF, 0xFF9F0A, 0xFF375F, 0xAC8E68, 0x63E6E2]

"notion"

[0x529CCA, 0xD08B65, 0x6C9B7D, 0xCB7C7A, 0x9A6DD7,
 0x868686, 0xCCAA55, 0x75B5AA, 0xD477A8, 0x507AA6]

"minimal"

[0x374151, 0x6B7280, 0x9CA3AF, 0xD1D5DB, 0x111827,
 0x4B5563, 0x1F2937, 0xE5E7EB, 0x030712, 0x6B7280]

"neon"

[0x00FF87, 0xFF006E, 0x00B4D8, 0xFFBE0B, 0xE500A4,
 0x8338EC, 0x3A86FF, 0xFB5607, 0xFF006E, 0x06D6A0]

Exemples

import seraplot as sp

sp.theme("dark")
sp.bar("Revenus", labels=["T1", "T2", "T3", "T4"], values=[120, 145, 98, 180]).show()

sp.theme("neon")
sp.scatter(title="Clusters", x=[1, 2, 3, 4, 5, 6], y=[2, 5, 3, 8, 7, 9]).show()

sp.theme("scientific")
sp.line(title="Croissance démographique", x_labels=["2020", "2021", "2022", "2023"], values=[100, 112, 121, 135]).show()

sp.reset_theme()
print(sp.themes())
# ['dark', 'light', 'scientific', 'apple', 'notion', 'minimal', 'neon']

Notes

  • sp.theme() définit le fond global, la palette et le quadrillage. C'est équivalent à sp.config(background=..., palette=..., gridlines=...) avec les valeurs du préréglage.
  • Les thèmes persistent jusqu'à sp.reset_theme() ou un appel sp.config() qui les écrase.
  • Vous pouvez continuer à surcharger des propriétés individuelles après avoir appliqué un thème :
sp.theme("dark")
sp.config(font_size=16, border_radius=12)

Custom Tooltips

Signature

chart.hover_json(slots_json: str) -> Chart

hover_json is a chainable Chart method — not a standalone sp. function. It takes a single JSON string and returns a new Chart with the tooltip override applied, the same chaining shape as every other Chart method (chart.subtitle(...).hover_json(...).show()).


Description

Overrides the tooltip content shown per data point, independent of the values actually plotted — useful when the label/value combination on the axes isn't the whole story (currency formatting, a delta vs. last period, a category not otherwise on the chart).


Example

import json
import seraplot as sp

chart = sp.bar(title="Revenus par produit", labels=["Alpha", "Beta", "Gamma"], values=[420, 380, 290])

hover_payload = json.dumps({
    "fields": ["Produit", "Revenu (€)", "Croissance"],
    "values": [
        ["Alpha", 420, "+12%"],
        ["Beta",  380, "+5%"],
        ["Gamma", 290, "-3%"],
    ],
})

chart = chart.hover_json(hover_payload)

Signature

chart.hover_json(slots_json: str) -> Chart

hover_json est une méthode chaînable sur Chart — pas une fonction sp. autonome. Elle prend une seule chaîne JSON et retourne un nouveau Chart avec l'override de tooltip appliqué, la même forme chaînable que toute autre méthode Chart (chart.subtitle(...).hover_json(...).show()).


Description

Remplace le contenu du tooltip affiché par point de donnée, indépendamment des valeurs réellement tracées — utile quand la combinaison label/valeur des axes ne raconte pas toute l'histoire (formatage monétaire, un delta vs la période précédente, une catégorie absente du graphique lui-même).


Exemple

import json
import seraplot as sp

chart = sp.bar(title="Revenus par produit", labels=["Alpha", "Beta", "Gamma"], values=[420, 380, 290])

hover_payload = json.dumps({
    "fields": ["Produit", "Revenu (€)", "Croissance"],
    "values": [
        ["Alpha", 420, "+12%"],
        ["Beta",  380, "+5%"],
        ["Gamma", 290, "-3%"],
    ],
})

chart = chart.hover_json(hover_payload)

Auto-Display (Jupyter)

Signature

sp.set_auto_display(enabled: bool) -> None

Description

Controls whether Chart objects are automatically rendered inline in Jupyter notebooks when they are the last expression of a cell.

StateBehavior
True (default)chart at end of cell → rendered immediately
FalseMust call display(chart) or chart.show() explicitly

Parameters

ParameterTypeDescription
enabledboolTrue to enable auto-display, False to disable

Examples

sp.set_auto_display(False)
charts = []
for name, values in datasets.items():
    charts.append(sp.build_bar_chart(name, labels=["A","B","C"], values=values))
for c in charts:
    c.show()

Signature

sp.set_auto_display(enabled: bool) -> None

Description

Contrôle si les objets Chart sont automatiquement rendus dans les cellules Jupyter.

ÉtatComportement
True (défaut)Le graphique en fin de cellule est rendu immédiatement
FalseIl faut appeler display(chart) ou chart.show() explicitement

Paramètres

ParamètreTypeDescription
enabledboolTrue pour activer, False pour désactiver

Exemples

sp.set_auto_display(False)
graphiques = []
for nom, valeurs in jeux_de_donnees.items():
    graphiques.append(sp.build_bar_chart(nom, labels=["A","B","C"], values=valeurs))
for g in graphiques:
    g.show()

Downsampling (LTTB)

Reduce massive datasets while preserving visual shape using the Largest-Triangle-Three-Buckets algorithm. A 10M-point scatter chart becomes 5K points indistinguishable to the eye.

Python

import seraplot as sp

chart = sp.scatter(title="Big scatter", x_values=big_x, y_values=big_y).downsample()

downsample is a chainable Chart method, not a standalone sp. function — there is no Python sp.lttb(); the algorithm is only registered on the JS/WASM side today (downsampleLttb, below).

JavaScript

import { downsampleLttb } from "seraplot";
const reduced = JSON.parse(downsampleLttb(JSON.stringify({ x, y, threshold: 5000 })));

Why LTTB?

MethodPreserves peaksSpeedVisual fidelity
Random sampleNoFastPoor
Every-NthMaybeFastOK
LTTBYesFastExcellent

Réduit les datasets massifs en préservant la forme visuelle avec l'algorithme Largest-Triangle-Three-Buckets. Un scatter de 10M points devient 5K points indistinguables à l'œil.

Python

import seraplot as sp

chart = sp.scatter(title="Grand scatter", x_values=big_x, y_values=big_y).downsample()

downsample est une méthode chaînable sur Chart, pas une fonction sp. autonome — il n'y a pas de sp.lttb() en Python ; l'algorithme n'est enregistré que côté JS/WASM aujourd'hui (downsampleLttb, ci-dessous).

JavaScript

import { downsampleLttb } from "seraplot";
const reduced = JSON.parse(downsampleLttb(JSON.stringify({ x, y, threshold: 5000 })));

Pourquoi LTTB ?

MéthodePréserve les picsVitesseFidélité visuelle
Échantillon aléatoireNonRapideMauvaise
Tous les NPeut-êtreRapideOK
LTTBOuiRapideExcellente

Live Streaming

LiveStream is a bounded ring-buffer accumulator that turns a series of (x, y) samples arriving over time into a continuously redrawn chart. Memory stays constant whatever the duration of the stream, since older samples are dropped past max_points.

What makes it smooth in a notebook: push() / extend() / clear() don't just re-render — they repaint the same Jupyter output cell in place via IPython's display_id mechanism (display() once, then update_display() on every following call). No new cells get appended, no scroll-jump, no clear-then-flash; the chart updates where it already is.


Constructor

sp.LiveStream(
    kind: str = "line",        # "line" or "scatter"
    title: str = "",
    max_points: int = 500,      # ring buffer size
    color_hex: int = 0x6366F1,
    width: int = 900,
    height: int = 420,
)
ParameterTypeDefaultDescription
kindstr"line"Chart kind. "line" or "scatter".
titlestr""Chart title rendered on every update.
max_pointsint500Maximum samples kept in the buffer. Older samples are dropped from the head.
color_hexint0x6366F1Series color as a 24-bit RGB integer.
widthint900Canvas width in pixels.
heightint420Canvas height in pixels.

Methods

MethodEffect
push(x, y)Append a single sample, then redraw in place.
extend(xs, ys)Append two lists in lock-step, then redraw in place.
clear()Empty the buffer, then redraw the (now empty) chart in place.
render() -> ChartRender the current buffer to a standalone Chart, without touching the live display.
n (getter)Current sample count.
html (getter)Current chart HTML as a string.

Every mutating call enforces the max_points cap by dropping the oldest samples first — so the buffer is always bounded.


Example: live IoT sensor dashboard in Jupyter

import seraplot as sp
import time, random

stream = sp.LiveStream(kind="line", title="Temperature sensor (°C)", max_points=60)

value = 21.0
for tick in range(300):
    value += random.uniform(-0.4, 0.4)
    stream.push(tick, value)
    time.sleep(0.05)

Run this in a single notebook cell: the chart appears once, then updates smoothly in place on every push() — no flicker, no new output cells.

See v2/examples/iot_live_dashboard.py for a fuller multi-sensor simulation.

LiveStream est un accumulateur à buffer circulaire borné qui transforme une série d'échantillons (x, y) arrivant dans le temps en un graphique redessiné en continu. La mémoire reste constante quelle que soit la durée du flux, puisque les échantillons les plus anciens sont supprimés au-delà de max_points.

Ce qui le rend fluide dans un notebook : push() / extend() / clear() ne font pas que re-rendre — ils repeignent la même cellule de sortie Jupyter sur place via le mécanisme display_id d'IPython (display() une fois, puis update_display() à chaque appel suivant). Aucune nouvelle cellule n'est ajoutée, pas de saut de défilement, pas de clear-puis-flash ; le graphique se met à jour là où il est déjà.


Constructeur

sp.LiveStream(
    kind: str = "line",        # "line" ou "scatter"
    title: str = "",
    max_points: int = 500,      # taille du buffer circulaire
    color_hex: int = 0x6366F1,
    width: int = 900,
    height: int = 420,
)
ParamètreTypeDéfautDescription
kindstr"line"Type de graphique. "line" ou "scatter".
titlestr""Titre rendu à chaque mise à jour.
max_pointsint500Nombre maximum d'échantillons gardés. Les plus anciens sont supprimés en tête.
color_hexint0x6366F1Couleur de la série en entier RGB 24 bits.
widthint900Largeur du canvas en pixels.
heightint420Hauteur du canvas en pixels.

Méthodes

MéthodeEffet
push(x, y)Ajoute un échantillon unique, puis redessine sur place.
extend(xs, ys)Ajoute deux listes en parallèle, puis redessine sur place.
clear()Vide le buffer, puis redessine le graphique (désormais vide) sur place.
render() -> ChartRend le buffer courant sous forme de Chart autonome, sans toucher à l'affichage live.
n (getter)Nombre d'échantillons courant.
html (getter)HTML courant du graphique sous forme de chaîne.

Chaque appel mutant applique la limite max_points en supprimant d'abord les échantillons les plus anciens — le buffer est donc toujours borné.


Exemple : tableau de bord IoT live dans Jupyter

import seraplot as sp
import time, random

stream = sp.LiveStream(kind="line", title="Capteur de température (°C)", max_points=60)

value = 21.0
for tick in range(300):
    value += random.uniform(-0.4, 0.4)
    stream.push(tick, value)
    time.sleep(0.05)

Exécute ceci dans une seule cellule de notebook : le graphique apparaît une fois, puis se met à jour de manière fluide sur place à chaque push() — sans scintillement, sans nouvelle cellule de sortie.

Voir v2/examples/iot_live_dashboard.py pour une simulation multi-capteurs plus complète.

Chart Diff

Compare two charts structurally — useful for visual CI / regression testing. Implemented natively in Rust (plot::utils::chart_diff).

chart_diff is currently wired for the WASM/JS build only — it is not yet exposed as a Python method (Chart.diff() does not exist). Documented here as-is rather than papered over with a Python example that would not run.

JavaScript / WASM

import { chartDiff } from "seraplot";

const result = JSON.parse(chartDiff(JSON.stringify({ a: htmlA, b: htmlB })));
console.log(result);

Returns:

{
  "ok": true,
  "identical": false,
  "size_a": 4521,
  "size_b": 4523,
  "common_prefix": 4400,
  "similarity": 0.97
}

a/b are compared on the <svg>...</svg> slice extracted from each chart's .html. common_prefix is the number of leading bytes the two SVGs share before the first difference; similarity is that shared length divided by the longer of the two.

Compare deux charts structurellement — utile pour les CI visuelles / tests de régression. Implémenté nativement en Rust (plot::utils::chart_diff).

chart_diff n'est aujourd'hui câblé que pour le build WASM/JS — pas encore exposé comme méthode Python (Chart.diff() n'existe pas). Documenté tel quel plutôt que masqué derrière un exemple Python qui ne s'exécuterait pas.

JavaScript / WASM

import { chartDiff } from "seraplot";

const result = JSON.parse(chartDiff(JSON.stringify({ a: htmlA, b: htmlB })));
console.log(result);

Retourne :

{
  "ok": true,
  "identical": false,
  "size_a": 4521,
  "size_b": 4523,
  "common_prefix": 4400,
  "similarity": 0.97
}

a/b sont comparés sur la tranche <svg>...</svg> extraite du .html de chaque chart. common_prefix est le nombre d'octets identiques au début des deux SVG avant la première différence ; similarity est cette longueur commune divisée par la plus longue des deux.

Drift Detection

Detect distribution shift between a reference dataset and a current one using the Kolmogorov-Smirnov two-sample test — implemented natively in Rust (plot::utils::drift_ks).

drift_ks is currently wired for the WASM/JS build only — it is not yet exposed as a Python function (sp.drift does not exist). Documented here as-is rather than papered over with a Python example that would not run.

JavaScript / WASM

import { driftKs } from "seraplot";

const r = JSON.parse(driftKs(JSON.stringify({ reference, current })));
console.log(r);

Returns:

{
  "ok": true,
  "ks_statistic": 0.18,
  "p_value": 0.003,
  "drift_detected": true,
  "n_reference": 1000,
  "n_current": 1000
}

drift_detected is true when p_value < 0.05.

Détecte un drift de distribution entre un dataset de référence et un dataset actuel via le test à deux échantillons de Kolmogorov-Smirnov — implémenté nativement en Rust (plot::utils::drift_ks).

drift_ks n'est aujourd'hui câblé que pour le build WASM/JS — pas encore exposé comme fonction Python (sp.drift n'existe pas). Documenté tel quel plutôt que masqué derrière un exemple Python qui ne s'exécuterait pas.

JavaScript / WASM

import { driftKs } from "seraplot";

const r = JSON.parse(driftKs(JSON.stringify({ reference, current })));
console.log(r);

Retourne :

{
  "ok": true,
  "ks_statistic": 0.18,
  "p_value": 0.003,
  "drift_detected": true,
  "n_reference": 1000,
  "n_current": 1000
}

drift_detected est true quand p_value < 0.05.

Export (SVG / PNG / HTML)

Export is exposed two ways: as Chart methods in Python (verified below against a real build), and as standalone for_each_fn!-registered functions callable from JavaScript / the C-FFI. The two are not a 1:1 mirror of each other today — chart_info is the one function that is genuinely callable from both sides.


chart.save(path) / chart.export_html(path)

Write the complete HTML of the chart to disk. The file is fully self-contained: it embeds the SVG, its scripts and styles. It can be opened in any browser, attached to an email, or served statically — no server, no CDN.

import seraplot as sp

chart = sp.bar(title="Revenue", labels=["Q1", "Q2"], values=[120, 180])
chart.save("revenue.html")

chart.export_svg(path)

Extracts the <svg>...</svg> block from the chart and writes it to path. Useful for embedding into a LaTeX / Word / Illustrator workflow, or post-processing the geometry (CSS overrides, masks, custom filters).

chart.export_svg("plot.svg")

chart.export_png(path)

Rasterizes the chart to PNG via cairosvg. Requires pip install cairosvg — raises a clear error naming the missing dependency if it is not installed, rather than failing silently.

chart.export_png("plot.png")

sp.chart_info(chart) -> str

Returns a JSON string with structural metadata about the rendered chart. Handy for logging, telemetry, or asserting chart complexity in unit tests.

import json

info = json.loads(sp.chart_info(chart))
print(info)
{"size": 25488, "paths": 0, "rects": 3, "circles": 0, "has_svg": true}

JavaScript

Only buildBarChart (and the equivalent build* function per chart family) and exportHtmlFile are registered on the JS/WASM side today — there is no JS equivalent of export_svg/export_png/chart_info yet.

import * as sp from "seraplot";

const chart = sp.buildBarChart(JSON.stringify({
  title: "Revenue",
  labels: ["Q1", "Q2"],
  values: [120, 180],
}));

exportHtmlFile exists but currently always fails at runtime — the crate targets wasm32-unknown-unknown, which has no filesystem access to back std::fs::write, in Node or the browser alike:

sp.exportHtmlFile(JSON.stringify({ html: chart, path: "out.html" }));
// => '{"ok":false,"error":"operation not supported on this platform"}'

Write the returned HTML string to disk on the JS side instead (fs.writeFileSync("out.html", chart) in Node, or a Blob download in the browser).

L'export est exposé de deux façons : comme méthodes sur Chart en Python (vérifié ci-dessous contre un vrai build), et comme fonctions autonomes enregistrées via for_each_fn!, appelables depuis JavaScript / le C-FFI. Les deux ne sont pas un miroir 1:1 aujourd'hui — chart_info est la seule fonction réellement appelable des deux côtés.


chart.save(path) / chart.export_html(path)

Écrit l'intégralité du HTML du chart sur disque. Le fichier est auto-suffisant : il embarque le SVG, ses scripts et ses styles. Il s'ouvre dans n'importe quel navigateur, peut être joint à un mail ou servi en statique — aucun serveur, aucun CDN.

import seraplot as sp

chart = sp.bar(title="Chiffre d'affaires", labels=["T1", "T2"], values=[120, 180])
chart.save("revenue.html")

chart.export_svg(path)

Extrait le bloc <svg>...</svg> du chart et l'écrit sous path. Utile pour l'intégrer dans un flux LaTeX / Word / Illustrator, ou post-traiter la géométrie (overrides CSS, masques, filtres custom).

chart.export_svg("plot.svg")

chart.export_png(path)

Rasterise le chart en PNG via cairosvg. Nécessite pip install cairosvg — lève une erreur claire nommant la dépendance manquante plutôt que d'échouer silencieusement.

chart.export_png("plot.png")

sp.chart_info(chart) -> str

Retourne une chaîne JSON contenant des métadonnées structurelles sur le chart rendu. Pratique pour le logging, la télémétrie ou pour tester la complexité d'un chart dans des tests unitaires.

import json

info = json.loads(sp.chart_info(chart))
print(info)
{"size": 25488, "paths": 0, "rects": 3, "circles": 0, "has_svg": true}

JavaScript

Seuls buildBarChart (et l'équivalent build* par famille de chart) et exportHtmlFile sont enregistrés côté JS/WASM aujourd'hui — pas encore d'équivalent JS pour export_svg/export_png/chart_info.

import * as sp from "seraplot";

const chart = sp.buildBarChart(JSON.stringify({
  title: "Chiffre d'affaires",
  labels: ["T1", "T2"],
  values: [120, 180],
}));

exportHtmlFile existe mais échoue toujours à l'exécution aujourd'hui — le crate cible wasm32-unknown-unknown, qui n'a aucun accès au système de fichiers pour appuyer std::fs::write, ni dans Node ni dans le navigateur :

sp.exportHtmlFile(JSON.stringify({ html: chart, path: "out.html" }));
// => '{"ok":false,"error":"operation not supported on this platform"}'

Écrivez plutôt la chaîne HTML retournée sur disque côté JS (fs.writeFileSync("out.html", chart) en Node, ou un téléchargement Blob dans le navigateur).

ML Model Persistence

sp.ml_save_model() / sp.ml_load_model() are real, verified functions backed by an in-process, name-versioned model registry — not a file-path envelope. Every save under the same name gets the next version automatically; load without a version returns the latest.


sp.ml_save_model(name, kind, payload, params, metrics, tags) -> dict

ArgumentTypeDescription
namestrRegistry key. Repeated saves under the same name auto-increment version.
kindstrFree-form model identifier (e.g. "knn_classifier", "kmeans").
payloadstrArbitrary JSON-serialized state — typically the dict a training call returned.
paramsdict[str, str]Hyperparameters, stored alongside for reference.
metricsdict[str, float]Training/eval metrics, stored alongside.
tagslist[str]Free-form labels for later filtering.

Returns {"name": ..., "version": ...}.

import json
import seraplot as sp

result = sp.knn_classifier(data=X_train, target=y_train, k=5)
saved = sp.ml_save_model(
    name="knn_v1", kind="knn_classifier",
    payload=json.dumps(result), params={"k": "5"}, metrics={}, tags=[],
)
print(saved)  # {'name': 'knn_v1', 'version': 1}

sp.ml_load_model(name, version=None) -> dict

Loads the latest save for name, or a specific version if given.

loaded = sp.ml_load_model(name="knn_v1")
# {'found': True, 'name': 'knn_v1', 'version': 1, 'kind': 'knn_classifier', 'payload': '...'}

restored = json.loads(loaded["payload"])

Missing name/version returns {"found": False} rather than raising.


End-to-end: train → save → reload

import json
import seraplot as sp

result = sp.knn_classifier(data=X_train, target=y_train, k=5)
sp.ml_save_model(
    name="knn_v1", kind="knn_classifier",
    payload=json.dumps(result), params={"k": "5"}, metrics={}, tags=[],
)

loaded = sp.ml_load_model(name="knn_v1")
restored = json.loads(loaded["payload"])
assert restored == result

Saving again under the same name bumps the version rather than overwriting:

sp.ml_save_model(name="knn_v1", kind="knn_classifier", payload=json.dumps(result), params={}, metrics={}, tags=[])
# {'name': 'knn_v1', 'version': 2}

sp.ml_load_model(name="knn_v1", version=1)  # the original save is still there

sp.ml_save_model() / sp.ml_load_model() sont des fonctions réelles et vérifiées, adossées à un registre de modèles en mémoire, indexé par nom et versionné — pas une enveloppe fichier. Chaque sauvegarde sous le même name obtient automatiquement la version suivante ; charger sans version retourne la dernière.


sp.ml_save_model(name, kind, payload, params, metrics, tags) -> dict

ArgumentTypeDescription
namestrClé du registre. Des sauvegardes répétées sous le même nom incrémentent version automatiquement.
kindstrIdentifiant libre du modèle (ex. "knn_classifier", "kmeans").
payloadstrÉtat sérialisé en JSON arbitraire — typiquement le dict retourné par un appel d'entraînement.
paramsdict[str, str]Hyperparamètres, stockés pour référence.
metricsdict[str, float]Métriques d'entraînement/évaluation, stockées pour référence.
tagslist[str]Labels libres pour un filtrage ultérieur.

Retourne {"name": ..., "version": ...}.

import json
import seraplot as sp

result = sp.knn_classifier(data=X_train, target=y_train, k=5)
saved = sp.ml_save_model(
    name="knn_v1", kind="knn_classifier",
    payload=json.dumps(result), params={"k": "5"}, metrics={}, tags=[],
)
print(saved)  # {'name': 'knn_v1', 'version': 1}

sp.ml_load_model(name, version=None) -> dict

Charge la dernière sauvegarde pour name, ou une version précise si fournie.

loaded = sp.ml_load_model(name="knn_v1")
# {'found': True, 'name': 'knn_v1', 'version': 1, 'kind': 'knn_classifier', 'payload': '...'}

restored = json.loads(loaded["payload"])

Un nom/version absent retourne {"found": False} plutôt que de lever une exception.


Bout-en-bout : entraînement → sauvegarde → recharge

import json
import seraplot as sp

result = sp.knn_classifier(data=X_train, target=y_train, k=5)
sp.ml_save_model(
    name="knn_v1", kind="knn_classifier",
    payload=json.dumps(result), params={"k": "5"}, metrics={}, tags=[],
)

loaded = sp.ml_load_model(name="knn_v1")
restored = json.loads(loaded["payload"])
assert restored == result

Sauvegarder à nouveau sous le même name incrémente la version plutôt que d'écraser :

sp.ml_save_model(name="knn_v1", kind="knn_classifier", payload=json.dumps(result), params={}, metrics={}, tags=[])
# {'name': 'knn_v1', 'version': 2}

sp.ml_load_model(name="knn_v1", version=1)  # la sauvegarde originale existe toujours

Pickle / Serialization

Chart objects are picklable via __getstate__ / __setstate__ — works with joblib, multiprocessing, Ray, Streamlit reruns.

Python

import seraplot as sp
import pickle

chart = sp.bar("Revenue", labels=["a", "b", "c"], values=[1, 2, 3])
blob = pickle.dumps(chart)

restored = pickle.loads(blob)
restored.save("restored.html")

Internally, only the HTML string is serialized — minimal payload, no transient state.

ML models

Trained models are a separate concern from Chart pickling — see ML Model Persistence for sp.ml_save_model() / sp.ml_load_model().

Les objets Chart sont sérialisables via __getstate__ / __setstate__ — compatible joblib, multiprocessing, Ray, reruns Streamlit.

Python

import seraplot as sp
import pickle

chart = sp.bar("Revenu", labels=["a", "b", "c"], values=[1, 2, 3])
blob = pickle.dumps(chart)

restored = pickle.loads(blob)
restored.save("restored.html")

En interne, seule la chaîne HTML est sérialisée — payload minimal, aucun état transitoire.

Modèles ML

Les modèles entraînés sont une préoccupation distincte du pickling de Chart — voir ML Model Persistence pour sp.ml_save_model() / sp.ml_load_model().

Accessibility (a11y)

Inject ARIA roles, <title> and <desc> into the chart SVG for screen readers and B2B compliance (WCAG 2.1).

Python

import seraplot as sp

chart = (
    sp.bar(labels=["EU","US","APAC"], values=[10,20,30])
      .a11y(title="Quarterly revenue by region",
            desc="Bar chart, EU 10M, US 20M, APAC 30M")
)

The resulting SVG includes role="group" (set by default so keyboard-navigable data points and legend buttons remain valid descendants — role="img" forbids focusable children per the SVG-AAM spec), plus aria-label, <title>, <desc> from .a11y() — recognized by NVDA, JAWS, VoiceOver.

Injecte les rôles ARIA, <title> et <desc> dans le SVG pour les lecteurs d'écran et la conformité B2B (WCAG 2.1).

Python

import seraplot as sp

chart = (
    sp.bar(labels=["EU","US","APAC"], values=[10,20,30])
      .a11y(title="Revenu trimestriel par région",
            desc="Bar chart, EU 10M, US 20M, APAC 30M")
)

Le SVG résultant inclut role="group" (posé par défaut pour que les points de données et boutons de légende navigables au clavier restent des descendants valides — role="img" interdit tout enfant focusable selon la spec SVG-AAM), plus aria-label, <title>, <desc> ajoutés par .a11y() — reconnus par NVDA, JAWS, VoiceOver.

CSP-safe Mode

Strict Content Security Policies block inline <script>. The csp_safe() method extracts JS into a <script type="application/json"> payload + a single nonce-able loader.

Python

import seraplot as sp

chart = sp.line(x_labels=["1", "2", "3", "4"], values=[10, 20, 15, 25]).csp_safe()

Apply your CSP script-src 'nonce-sp-nonce' and the chart still renders.

Les CSP strictes bloquent les <script> inline. La méthode csp_safe() extrait le JS dans un payload <script type="application/json"> + un loader unique compatible nonce.

Python

import seraplot as sp

chart = sp.line(x_labels=["1", "2", "3", "4"], values=[10, 20, 15, 25]).csp_safe()

Applique ta CSP script-src 'nonce-sp-nonce' et le chart se rend toujours.

2D Charts

SeraPlot provides 41 two-dimensional chart types, from basic bar and line charts to specialized plots like ridgeline, dumbbell, sankey, chord, dendrogram, venn, correlogram, hive, pulse, and orbita.

ChartFunction
Bar Chartbar()
Horizontal Barhbar()
Line Chartline()
Scatter Chartscatter()
Histogramhistogram()
Grouped Bargrouped_bar()
Stacked Barstacked_bar()
Heatmapheatmap()
Pie Chartpie()
Donut Chartdonut()
Box Plotboxplot()
Violin Chartviolin()
Slope Chartslope()
Sunburstsunburst()
Funnelfunnel()
Treemaptreemap()
Multi-line Chartmultiline()
Area Chartarea()
Waterfallwaterfall()
Bullet Chartbullet()
Word Cloudwordcloud()
Candlestickcandlestick()
Dumbbelldumbbell()
Bubblebubble()
Gaugegauge()
Parallel Coordinatesparallel()
Lollipoplollipop()
KDEkde()
Ridgelineridgeline()
Radarradar()
Sankeysankey()
Chord Diagramchord()
Circle Packingcircle_pack()
Arc Diagramarc_diagram()
Dendrogramdendrogram()
Venn Diagramvenn()
Correlogramcorrelogram()
Hive Plothive()
Pulse Chartpulse()
Orbita Chartorbita()

SeraPlot propose 41 types de graphiques 2D, des barres et courbes basiques aux graphiques spécialisés (ridgeline, haltère, sankey, corde, dendrogramme, venn, corrélogramme, ruche, pulse et orbita).

GraphiqueFonction
Graphique en barresbar()
Barres horizontaleshbar()
Courbeline()
Nuage de pointsscatter()
Histogrammehistogram()
Barres groupéesgrouped_bar()
Barres empiléesstacked_bar()
Heatmapheatmap()
Camembertpie()
Anneaudonut()
Boîte à moustachesboxplot()
Violonviolin()
Penteslope()
Sunburstsunburst()
Entonnoirfunnel()
Treemaptreemap()
Multi-courbesmultiline()
Airesarea()
Cascadewaterfall()
Bulletbullet()
Nuage de motswordcloud()
Bougiecandlestick()
Haltèredumbbell()
Bullesbubble()
Jaugegauge()
Coordonnées parallèlesparallel()
Sucettelollipop()
KDEkde()
Ridgelineridgeline()
Radarradar()
Sankeysankey()
Diagramme de cordechord()
Packing de cerclescircle_pack()
Diagramme d'arcarc_diagram()
Dendrogrammedendrogram()
Diagramme de Vennvenn()
Corrélogrammecorrelogram()
Graphe en ruchehive()
Pulse radialpulse()
Orbitaorbita()

Bar Charts

Signature

sp.bar(title, labels=None, values=None, *, variant="basic", series=None, series_names=None, theme="none", **kwargs) -> Chart

Aliases: sp.bar_chart(), sp.bars(), sp.bar_unified(), sp.bars_unified(), sp.bar_family().

Description

sp.bar() is the unified entry point for the SeraPlot bar-chart family. It renders standalone Rust-generated HTML/SVG charts. The variant keyword selects the renderer, and shared chart options are applied by the common chart pipeline.

The default renderer is a vertical categorical bar chart. The same API also covers every bar variant registered in Rust.

Variants

Data

labels are category labels for bar variants. Single-series variants use values. Multi-series variants use series, where each inner list is one series, and series_names supplies legend names.

When series is missing but series_names is provided, values is interpreted as a flattened matrix split by len(labels): the first category-length block is the first series, the next block is the second series, and so on.

Parameters

Themes

Returns

Chart object with an .html property and a .show() method.

Variant "basic"Aliases sp.bar sp.bars sp.bar_unifiedReturns Chart
Preview

Horizontal bars — better for long category names. Alias: "h".

Variant "horizontal" / "h"Aliases sp.bar + variant="h"Returns Chart
Preview

Multiple series side-by-side per category. Alias: "group".

Variant "grouped" / "group"Required series, series_namesReturns Chart
Preview

Series stacked vertically — shows part-to-whole within each category. Alias: "stack".

Variant "stacked" / "stack"Required series, series_namesReturns Chart
Preview

100% stacked bars — every column fills from 0 to 100%, showing each series as a share of the total. Alias: "rel".

Variant "relative" / "rel"Required series, series_namesNote each column normalised to 100%Returns Chart
Preview

Groups of stacked sub-bars per category. offset_groups assigns a stack-group name to each series.

Variant "grouped_stacked"Required series, offset_groupsReturns Chart
Preview

Variable-width stacked bars (mosaic plot). widths encodes one dimension, stacked segments encode share. Aliases: "mekko", "mosaic".

Variant "marimekko" / "mekko" / "mosaic"Required series, widthsReturns Chart
Preview

A bar made of repeated icons. Each icon represents units_per_icon units. Alias: "icon".

Variant "pictogram" / "icon"Required values, units_per_iconReturns Chart
Preview

Two-level hierarchical x axis. super_categories groups adjacent bars under a bracket label. Alias: "multi".

Variant "multicategory" / "multi"Required values, super_categoriesReturns Chart
Preview

Bars arranged radially around a center, length proportional to value. Pass show_values=True for a value at each bar's tip, gridlines=True for labeled concentric rings. Aliases: "circular_basic", "radial_bar", "polar_bar".

Variant "circular"Required labels, valuesOptional show_values, gridlinesReturns Chart
Preview

Circular bars split into groups via color_groups, with an extra gap between groups. Same show_values/gridlines options as circular. Aliases: "radial_grouped", "circular_groups".

Variant "circular_grouped"Required labels, values, color_groupsReturns Chart
Preview

Two horizontal bar sets mirrored left/right around a shared category axis, from the first two entries of series. Aliases: "pyramid", "age_pyramid".

Variant "population_pyramid"Required labels, series (≥ 2), series_namesReturns Chart
Preview

Horizontal bars extending left or right from a zero line, one color regardless of sign, value printed inside the bar (white) when it's wide enough or just outside otherwise. Aliases: "signed", "delta", "bidirectional". The value label is controlled by show_values (bool) like every other bar variant — it defaults to True here so existing charts keep their look, unlike other variants where it defaults to False.

Variant "diverging"Required labels, valuesReturns Chart
Preview

Bar + boxplot fusion: a semi-transparent bar up to each category's mean, with a real box (Q1/median/Q3, whiskers) overlaid on top showing the distribution behind that mean — pass series as one raw sample array per category (same shape as boxplot's grouped input) instead of single aggregate values. Aliases: "bar_box", "boxbar", "bar_boxplot".

Variant "distribution"Required labels, seriesReturns Chart
Preview

Line Charts

Signature

sp.line(title, labels=None, values=None, *, variant="basic", series=None, **kwargs) -> Chart

Description

sp.line() is the unified entry point for the entire line-chart family. The variant keyword selects the rendering strategy — every other argument is shared across variants.

Variants

Parameters


Returns

Chart — object with .html property and .show() method.


Single series connecting ordered data points.

Variant "basic"Aliases "basic"Returns Chart
Preview

Several series sharing the same x-axis. Pass series=[(name, values), ...].

Variant "multi"Aliases "multi" / "multiline" / "multiple"Returns Chart
Preview

Step (staircase) line — ideal for piecewise-constant data. Use step_shape to control corner direction.

Variant "stepped"Aliases "stepped" / "step" / "hv" / "vh"Returns Chart
Preview

Catmull-Rom smoothed curve. spline_tension (0–1) controls how tight the curve hugs the points.

Variant "spline"Aliases "spline" / "smooth" / "curved"Returns Chart
Preview

Area chart — fills the region under the line. fill_opacity controls transparency; stack_fill=True stacks multiple series.

Variant "filled"Aliases "filled" / "area" / "fill"Returns Chart
Preview

Small inline chart — no axes, perfect for dashboards. spark_cols arranges multiple series in a grid.

Variant "sparkline"Aliases "sparkline" / "spark" / "tiny"Returns Chart
Preview

Custom stroke pattern. dash_pattern="8,4" means 8px on, 4px off. Use "2,3" for dotted.

Variant "dashed"Aliases "dashed" / "dotted" / "styled"Returns Chart
Preview

Line plot with prominent markers. marker_size (px) controls dot size; show_points=True is implicit.

Variant "connected_scatter"Aliases "connected_scatter" / "markers" / "lines+markers"Returns Chart
Preview

Line breaks where values exceed gap_threshold. Useful for time series with missing samples.

Variant "gapped"Aliases "gapped" / "gaps" / "missing"Returns Chart
Preview

Area Chart

Signature

sp.area(title, x_labels=None, series=None, *, variant="basic", series_names=None, palette=None, **kwargs) -> Chart

Aliases: sp.area, sp.area_chart, sp.area_family, sp.area_unified, sp.build_area_chart

Description

sp.area() is the unified entry point for the entire area-chart family. The variant keyword selects the rendering strategy — every other argument keeps the same name across variants. Area charts fill the space between a line and the baseline, making the emphasis on cumulative magnitude rather than the line chart's point-to-point comparison. SeraPlot renders everything in pure Rust SVG with native multi-series overlay, stacking, 100%-normalized stacking, smooth splines, step interpolation and gradient fills.

Variants

Parameters


Returns

Chart — object with .html property and .show() method.


Variant "basic"Aliases basic / overlay / default / simpleReturns Chart

Each series drawn as an independent semi-transparent filled area from its own value down to the baseline - overlapping regions blend visually, useful to compare overlapping magnitudes directly.

Preview
Variant "stacked"Aliases stacked / stackReturns Chart

Series drawn on top of one another so the top boundary tracks the running total - reads both individual contribution and combined magnitude at once.

Preview
Variant "percent"Aliases percent / percent_stacked / normalized / stream100Returns Chart

100%-stacked area - every x position sums to 100%, showing the changing composition (share of total) instead of absolute magnitude.

Preview
Variant "spline"Aliases spline / smooth / curvedReturns Chart

Catmull-Rom smoothed boundary through every point instead of straight segments - a softer, more organic silhouette for trend-focused series.

Preview
Variant "step"Aliases step / stepped / stairsReturns Chart

Step-interpolated boundary - the fill jumps at each data point instead of interpolating, correct for values that hold constant between samples (inventory levels, active counts...).

Preview
Variant "gradient"Aliases gradient / glow / fadeReturns Chart

Smooth spline boundary filled with a vertical gradient fading from the series color to transparent at the baseline - a modern dashboard look.

Preview
Variant "ribbon"Aliases ribbon / outlined / bordered / ggplotReturns Chart

100%-stacked area with bold black borders around every band instead of colored ones - the ggplot2 geom_area look, ideal for many groups (works well beyond two) where the outline is what separates adjacent bands visually.

Preview
Variant "wave"Aliases wave / signed / oscillating / stackplotReturns Chart

True signed stacking - unlike stacked, negative values are never clamped to zero, so oscillating series (sin/cos-like data crossing above and below the baseline) stack correctly on both sides of zero. Matches matplotlib's stackplot() behavior for signed data.

Preview

Signature

sp.area(title, x_labels=None, series=None, *, variant="basic", series_names=None, palette=None, **kwargs) -> Chart

Alias : sp.area, sp.area_chart, sp.area_family, sp.area_unified, sp.build_area_chart

Description

sp.area() est le point d'entrée unifié de toute la famille des graphiques en aires. Le mot-clé variant sélectionne la stratégie de rendu — tous les autres arguments gardent le même nom d'une variante à l'autre. Les graphiques en aires remplissent l'espace entre une courbe et la ligne de base, mettant l'accent sur la magnitude cumulée plutôt que sur la comparaison point à point du graphique en ligne. SeraPlot rend tout en SVG Rust pur, avec superposition multi-séries native, empilement, empilement normalisé à 100%, courbes lissées, interpolation en escalier et remplissages en dégradé.

Variantes

Paramètres


Retour

Chart — objet exposant .html et .show().


Variante "basic"Alias basic / overlay / default / simpleRetour Chart

Chaque série dessinée comme une aire remplie semi-transparente indépendante depuis sa propre valeur jusqu'à la ligne de base - les zones qui se chevauchent se mélangent visuellement, utile pour comparer directement des magnitudes qui se recouvrent.

Aperçu
Variante "stacked"Alias stacked / stackRetour Chart

Séries dessinées les unes sur les autres pour que la frontière supérieure suive le total cumulé - lit à la fois la contribution individuelle et la magnitude combinée.

Aperçu
Variante "percent"Alias percent / percent_stacked / normalized / stream100Retour Chart

Aire empilée à 100% - chaque position x totalise 100%, montrant la composition changeante (part du total) plutôt que la magnitude absolue.

Aperçu
Variante "spline"Alias spline / smooth / curvedRetour Chart

Frontière lissée par Catmull-Rom passant par chaque point au lieu de segments droits - une silhouette plus douce et organique pour les séries orientées tendance.

Aperçu
Variante "step"Alias step / stepped / stairsRetour Chart

Frontière interpolée en escalier - le remplissage saute à chaque point de donnée au lieu d'interpoler, correct pour des valeurs constantes entre échantillons (niveaux de stock, compteurs actifs...).

Aperçu
Variante "gradient"Alias gradient / glow / fadeRetour Chart

Frontière lissée remplie d'un dégradé vertical s'estompant de la couleur de la série vers la transparence à la ligne de base - un look de tableau de bord moderne.

Aperçu
Variante "ribbon"Alias ribbon / outlined / bordered / ggplotRetour Chart

Aire empilée à 100% avec des bordures noires marquées autour de chaque bande au lieu de bordures colorées - le look geom_area de ggplot2, idéal pour de nombreux groupes (fonctionne bien au-delà de deux) où le contour est ce qui sépare visuellement les bandes adjacentes.

Aperçu
Variante "wave"Alias wave / signed / oscillating / stackplotRetour Chart

Empilement signé véritable - contrairement à stacked, les valeurs négatives ne sont jamais ramenées à zéro, si bien que des séries oscillantes (type sinus/cosinus traversant la ligne de base) s'empilent correctement des deux côtés de zéro. Reproduit le comportement de stackplot() de matplotlib pour des données signées.

Aperçu

Scatter Charts

Signature

sp.scatter(title, x_values, y_values, *, variant="basic", categories=None, labels=None, color_values=None, **kwargs) -> Chart

Description

sp.scatter() is the unified entry point for the entire scatter family. The variant keyword selects the rendering strategy — every other argument keeps the same name across variants. Scatter plots are the canonical way to display the joint distribution of two numeric variables; SeraPlot adds optional grouping, continuous color, distinct marker shapes, on-point labels and OLS regression — all in pure Rust SVG, thousands of times faster than Plotly.

Variants

Parameters


Returns

Chart — object with .html property and .show() method.


Variant "basic"Aliases basic / simple / defaultReturns Chart
Preview
Variant "categorical"Aliases categorical / grouped / categoryReturns Chart
Preview
Variant "symbols"Aliases symbols / shapes / markersReturns Chart
Preview
Variant "labeled"Aliases labeled / labels / textReturns Chart
Preview
Variant "regression"Aliases regression / trendline / fitReturns Chart
Preview
Variant "residual"Aliases residuals / residplotReturns Chart
Preview

Two independent categorical variables: categories drives color, categories2 drives marker shape - matching seaborn's "hue and style with different variables" example.

Variant "dual_style"Aliases dual_style / hue_style / two_wayReturns Chart
Preview

Points colored by a continuous numeric variable (color_values) interpolated between color_low and color_high, with a gradient legend bar - seaborn's numeric hue mapping.

Variant "continuous_hue"Aliases continuous_hue / numeric_hue / colormapReturns Chart
Preview

Splits the data into one small-multiple panel per unique categories value, all sharing the same x/y domain - a native equivalent of seaborn's relplot() faceting.

Variant "facet"Aliases facet / facets / small_multiples / relplotReturns Chart
Preview

Both marker radius and color are driven by the same continuous variable (color_values, scaled between min_size and max_size) with a combined size+color legend - seaborn's hue= and size= mapped to the same column, with sizes=(min, max).

Variant "sized"Aliases sized / size_scale / bubble_scatter / magnitude_sizeReturns Chart
Preview

Plots several numeric columns (series, named via series_names) against one shared x_values axis, one color per column with a legend - the native equivalent of calling seaborn.scatterplot(data=wide_dataframe) directly on a wide-form table.

Variant "wide_form"Aliases wide_form / wide / multi_series / columnsReturns Chart
Preview

Signature

sp.scatter(title, x_values, y_values, *, variant="basic", categories=None, labels=None, color_values=None, **kwargs) -> Chart

Description

sp.scatter() est le point d'entrée unifié de toute la famille scatter. Le mot-clé variant sélectionne la stratégie de rendu — tous les autres arguments gardent le même nom d'une variante à l'autre. Les nuages de points sont la façon canonique d'afficher la distribution conjointe de deux variables numériques ; SeraPlot ajoute groupement optionnel, couleur continue, formes de marqueurs distinctes, étiquettes sur les points et régression OLS — le tout en SVG Rust pur, des milliers de fois plus rapide que Plotly.

Variantes

Paramètres


Retour

Chart — objet exposant .html et .show().


Variant "basic"Aliases basic / simple / defaultReturns Chart
Preview
Variant "categorical"Aliases categorical / grouped / categoryReturns Chart
Preview
Variant "symbols"Aliases symbols / shapes / markersReturns Chart
Preview
Variant "labeled"Aliases labeled / labels / textReturns Chart
Preview
Variant "regression"Aliases regression / trendline / fitReturns Chart
Preview
Variante "residual"Alias residuals / residplotRetourne Chart
Aperçu

Deux variables catégorielles indépendantes : categories pilote la couleur, categories2 pilote la forme du marqueur - comme l'exemple seaborn "hue and style" avec des variables différentes.

Variante "dual_style"Alias dual_style / hue_style / two_wayRetourne Chart
Aperçu

Points colorés selon une variable numérique continue (color_values) interpolée entre color_low et color_high, avec une barre de légende en dégradé - le mapping de teinte numérique de seaborn.

Variante "continuous_hue"Alias continuous_hue / numeric_hue / colormapRetourne Chart
Aperçu

Sépare les données en un panneau petit-multiple par valeur unique de categories, tous partageant le même domaine x/y - un équivalent natif du facettage relplot() de seaborn.

Variante "facet"Alias facet / facets / small_multiples / relplotRetourne Chart
Aperçu

Le rayon du marqueur et sa couleur sont pilotés par la même variable continue (color_values, mise à l'échelle entre min_size et max_size) avec une légende combinée taille+couleur - l'équivalent de hue= et size= pointant sur la même colonne en seaborn, avec sizes=(min, max).

Variante "sized"Alias sized / size_scale / bubble_scatter / magnitude_sizeRetourne Chart
Aperçu

Trace plusieurs colonnes numériques (series, nommées via series_names) sur un même axe x_values partagé, une couleur par colonne avec une légende - l'équivalent natif d'appeler seaborn.scatterplot(data=wide_dataframe) directement sur un tableau au format large.

Variante "wide_form"Alias wide_form / wide / multi_series / columnsRetourne Chart
Aperçu

Bubble Charts

Signature

sp.bubble(title, x_values, y_values, sizes, *, variant="basic", categories=None, labels=None, color_values=None, **kwargs) -> Chart

Description

sp.bubble() is the unified entry point for the entire bubble-chart family. The variant keyword selects the rendering strategy — all other arguments remain consistent across variants. A bubble chart extends a 2D scatter plot with a third numeric dimension represented as bubble area (not radius), following best practices for perceptual accuracy.

Variants

Parameters


Returns

Chart — object with .html property and .show() method.



Variant "basic"Aliases basic / simpleReturns Chart
Preview
Variant "categorical" / "grouped"Aliases category / groupsReturns Chart
Preview
Variant "labeled" / "text"Aliases labels / annotatedReturns Chart
Preview
Variant "outlined" / "hollow"Aliases ring / openReturns Chart
Preview
Variant "negative" / "signed"Aliases divergingReturns Chart
Preview

A categorical bubble matrix: x_categories and y_categories place bubbles on a grid, each split into a left/right half-circle by a binary categories value, sized by sizes - a native version of matplotlib's MarkerStyle(fillstyle="left"/"right") split-marker bubble chart, plus a magenta size-scale legend column.

Variant "split"Required x_categories, y_categories, categories, sizesReturns Chart
Preview

Histogram Charts

Signature

sp.histogram(title, values, *, variant="basic", bins=0, overlay_values=None, color_groups=None, series_names=None, **kwargs) -> Chart

Description

sp.histogram() is the unified entry point for the entire histogram family. The variant keyword selects the rendering strategy — every other argument keeps the same name across variants. Histograms are the canonical way to visualize the distribution of a single numeric variable; SeraPlot adds horizontal layout, density normalization, cumulative distribution, stacked groups, A/B overlay and step outline — all in pure Rust SVG, thousands of times faster than Plotly.

Variants

Parameters

Themes

Pass theme= to restyle any variant above — themes are a cross-cutting rendering pass, not a separate variant, and apply the same way across every chart family.


Returns

Chart — object with .html property and .show() method.


Variant "basic"Aliases basic / simple / default / verticalReturns Chart
Preview
Variant "horizontal"Aliases horizontal / h / barh / hbarReturns Chart
Preview
Variant "normalized"Aliases normalized / probability / density / pdfReturns Chart
Preview
Variant "cumulative"Aliases cumulative / cdf / cumReturns Chart
Preview
Variant "stacked"Aliases stacked / stack / stack_byReturns Chart
Preview
Variant "overlay"Aliases overlay / overlapping / compare / abReturns Chart
Preview
Variant "step"Aliases step / outline / stairReturns Chart
Preview

Signature

sp.histogram(title, values, *, variant="basic", bins=0, overlay_values=None, color_groups=None, series_names=None, **kwargs) -> Chart

Description

sp.histogram() est le point d'entrée unifié de toute la famille histogramme. Le mot-clé variant sélectionne la stratégie de rendu — tous les autres arguments gardent le même nom d'une variante à l'autre. Les histogrammes sont la façon canonique de visualiser la distribution d'une variable numérique ; SeraPlot ajoute layout horizontal, normalisation densité, distribution cumulative, groupes empilés, superposition A/B et contour en escalier — le tout en SVG Rust pur, des milliers de fois plus rapide que Plotly.

Variantes

Paramètres

Thèmes

Passez theme= pour restyliser n'importe quelle variante ci-dessus — les thèmes sont une passe de rendu transversale, pas une variante séparée, et s'appliquent de la même façon sur toutes les familles de graphiques.


Retour

Chart — objet exposant .html et .show().


Variant "basic"Aliases basic / simple / default / verticalReturns Chart
Preview
Variant "horizontal"Aliases horizontal / h / barh / hbarReturns Chart
Preview
Variant "normalized"Aliases normalized / probability / density / pdfReturns Chart
Preview
Variant "cumulative"Aliases cumulative / cdf / cumReturns Chart
Preview
Variant "stacked"Aliases stacked / stack / stack_byReturns Chart
Preview
Variant "overlay"Aliases overlay / overlapping / compare / abReturns Chart
Preview
Variant "step"Aliases step / outline / stairReturns Chart
Preview

Heatmap

Signature

sp.heatmap(title, labels=None, values=None, *, variant="basic", col_labels=None, **kwargs) -> Chart

Description

sp.heatmap() is the unified entry point for the entire heatmap family. The variant keyword selects the rendering strategy — every other argument stays consistent across variants. Cell colors are computed in pure Rust, no NumPy required. The matrix is passed as a flat list of length len(labels) * len(col_labels) (row-major).

Variants

Parameters


Returns

Chart — object with .html property and .show() method.


Variant "basic"Required labels, col_labels, valuesReturns Chart
Preview
Variant "annotated"Required labels, col_labels, valuesReturns Chart
Preview
Variant "categorical"Required labels, col_labels, values, paletteReturns Chart
Preview
Variant "unequal" / "variable"Required labels, col_labels, values, widths, rangesReturns Chart
Preview
Variant "log" / "log_scale"Required labels, col_labels, valuesReturns Chart
Preview
Variant "discrete" / "binned"Required labels, col_labels, values, binsReturns Chart
Preview
Variant "correlation" / "corr"Required labels, col_labels, valuesReturns Chart
Preview
Variant "density" / "imshow"Required labels, col_labels, valuesReturns Chart
Preview
Variant "contour"Required labels, col_labels, valuesReturns Chart
Preview
Variant "temporal" / "calendar"Required labels, col_labels, valuesReturns Chart
Preview
Variant "cluster" / "clustermap" / "dendrogram"Required labels, col_labels, valuesReturns Chart

Rows and columns are reordered by average-linkage hierarchical clustering (Euclidean distance on each row/column vector) so similar rows/columns sit next to each other, and the merge tree is drawn as a real dendrogram in the left and top margins — seaborn's clustermap / structured_heatmap look, fully native.

Preview
Variant "bubble" / "punchcard"Required labels, col_labels, valuesReturns Chart
Preview
Variant "marginal" / "with_marginals"Required labels, col_labels, valuesReturns Chart
Preview
Variant "confusion" / "confusion_matrix"Required labels, col_labels, valuesReturns Chart
Preview
Variant "pivot" / "pivot_table"Required labels, col_labels, valuesReturns Chart
Preview
Variant "polar" / "wheel" / "clock" / "carbon_wheel"Required labels, col_labels, valuesReturns Chart
Preview

Pie Charts

Signature

sp.pie(title, labels=None, values=None, *, variant="basic", series=None, **kwargs) -> Chart

Description

sp.pie() is the unified entry point for the entire pie-chart family. The variant keyword selects the rendering strategy — all other arguments remain consistent across variants.

Variants

Parameters

Floating labels

Pass labeled=True to any variant built on the shared angle-sweep engine (basic, donut, exploded, kpi, pattern, semi) to replace the in-wedge percentage text with an outside callout: a thin connector line from the wedge edge to a label showing the percentage and the category name, colored to match its slice. This is the same style used by the reference "total breakdown" donut screenshots — it is not a separate variant, it is a display option any of those variants can turn on.

import seraplot as sp

c = sp.pie(
    labels=["Acquisition", "Conversion", "Retention", "Referral", "Other"],
    values=[42, 26, 16, 11, 5],
    variant="donut",
    center_text="27.3K",
    center_subtext="TOTAL",
    labeled=True,
)

Returns

Chart — object with .html property and .show() method.


Variant "basic" / "pie"Required labels, valuesReturns Chart
Preview
Variant "donut" / "ring" / "hole"Required labels, valuesReturns Chart
Preview
Variant "exploded" / "pulled" / "explode"Required labels, valuesReturns Chart
Preview
Variant "subplots" / "grid" / "facet" / "multi"Required labels, seriesReturns Chart
Preview
Variant "proportional" / "scaled" / "scalegroup"Required labels, seriesReturns Chart
Preview
Variant "semi" / "half_pie"Required labels, valuesReturns Chart
Preview
Variant "kpi" / "indicator"Required labels, valuesReturns Chart
Preview
Variant "nested" / "concentric"Required labels, values, secondary_valuesReturns Chart
Preview
Variant "pattern" / "hatched"Patterns "stripes", "dots", "diagonal", "cross"Returns Chart
Preview
Variant "waffle" / "square" / "pie_square"Required labels, valuesReturns Chart

The "square pie" — a 10x10 grid of 100 cells filled proportionally to each category's share (largest-remainder allocation, so the cell count always sums to exactly 100), with a color-matched legend. Easier to read precise percentages from than wedge angles.

Preview

Box Plot

Signature

sp.boxplot(title, labels=None, values=None, *, variant="basic", series=None, **kwargs) -> Chart

Description

sp.boxplot() is the unified entry point for the entire box-plot family. The variant keyword selects the rendering strategy — every other argument stays consistent across variants. Quartiles, 1.5×IQR whiskers and outliers are computed in pure Rust without NumPy or pandas.

Variants

Parameters


Returns

Chart — object with .html property and .show() method.


Variant "basic"Required labels, valuesReturns Chart
Preview
Variant "horizontal" / "hbox"Required labels, valuesReturns Chart
Preview
Variant "notched" / "ci"Required labels, valuesReturns Chart
Preview
Variant "grouped" / "side_by_side"Required labels, series, series_namesReturns Chart
Preview
Variant "points" / "all_points"Required labels, valuesReturns Chart
Preview
Variant "outliers" / "fliers"Required labels, valuesReturns Chart
Preview
Variant "strip" / "jitter"Required labels, valuesReturns Chart
Preview
Variant "swarm" / "beeswarm"Required labels, valuesReturns Chart
Preview
Variant "violin" / "density"Required labels, valuesReturns Chart
Preview
Variant "letter_value" / "boxen"Required labels, valuesOptional boxen_depth (2–7)Returns Chart
Preview

Violin Plot

Signature

sp.violin(title, labels=None, values=None, *, variant="box", **kwargs) -> Chart

Description

sp.violin() is the unified entry point for the entire violin-plot family. The variant keyword selects the rendering strategy — every other argument stays consistent across variants. The kernel-density estimation, quartiles and statistics are computed in pure Rust, no NumPy or pandas required.

Variants

Parameters


Returns

Chart — object with .html property and .show() method.


Variant "basic"Required labels, valuesReturns Chart
Preview
Variant "box" (default)Required labels, valuesReturns Chart
Preview
Variant "quartile"Required labels, valuesReturns Chart
Preview
Variant "mean"Required labels, valuesReturns Chart
Preview
Variant "points"Required labels, valuesReturns Chart
Preview
Variant "strip"Required labels, valuesReturns Chart

Raincloud layout - a translucent half-violin KDE silhouette on the left of each category paired with individual jittered points strictly on the right, so the density shape and the raw sample are both visible without ever overlapping.

Preview
Variant "horizontal"Required labels, valuesReturns Chart
Preview
Variant "split"Required labels, valuesReturns Chart
Preview
Variant "half"Required labels, valuesReturns Chart
Preview

KDE — Kernel Density Estimate

Signature

sp.kde(title, values=None, *, x=None, y=None, variant="basic", categories=None, bandwidth=0.0, filled=True, fill_opacity=50, bins=30, n_points=80, palette=None, **kwargs) -> Chart

Description

sp.kde() is the unified entry point for the entire Kernel Density Estimate family. The variant keyword selects the rendering strategy — every other argument keeps the same name across variants. KDE produces a smooth, continuous density estimate from a sample of points using a Gaussian kernel with Scott's rule for automatic bandwidth selection. SeraPlot renders the curves as pure Rust SVG, with native multi-series, normalization, CDF, rug, histogram overlay and gradient fills.

Variants

Parameters


Returns

Chart — object with .html property and .show() method.


Variant "basic"Aliases basic / filled / default / single / multiReturns Chart

Filled curve, single or multi-series.

Preview
Variant "outline"Aliases outline / line / stroke / compare / no_fillReturns Chart

Stroke-only curves for clean overlays.

Preview
Variant "stepped"Aliases stepped / step / stair / stairsReturns Chart

Stair-stepped density (rectangular look).

Preview
Variant "rug"Aliases rug / carpet / ticks / rugplotReturns Chart

KDE curve with rug ticks at sample positions.

Preview
Variant "histogram"Aliases histogram / hist / with_hist / kdehist / distplotReturns Chart

KDE curve overlaid on a normalized histogram.

Preview
Variant "normalized"Aliases normalized / pdf / norm / densityReturns Chart

Each series normalized so its area integrates to 1.

Preview
Variant "cumulative"Aliases cumulative / cdf / cumReturns Chart

Cumulative density (CDF) curve in [0, 1].

Preview
Variant "contour"Aliases contour / bivariate / kde2d / joint_density / smoothRequired x, yOptional categoriesReturns Chart

Bivariate (2D) kernel density estimate — a product-kernel Gaussian evaluated on a grid and rendered as a shaded density surface with the raw points overlaid. Pass categories to overlay one density surface per group, each in its own color with a legend.

Preview
Variant "levels"Aliases levels / bands / iso_bands / ring_contour / bandedRequired x, yOptional categoriesReturns Chart

Bivariate KDE quantized into discrete iso-density bands with a visible ring border at each band boundary — matches seaborn's kdeplot(x=, y=, hue=, fill=True) stepped-level look, as opposed to contour's continuous gradient.

Preview
Variant "stack"Aliases stack / stacked / layered_stackReturns Chart

Each group's density curve stacked on top of the previous one's (cumulative running total), all evaluated on one shared x-grid - matches seaborn's kdeplot(hue=, multiple="stack").

Preview
Variant "fill"Aliases fill / stack100 / percent_stack / filled_stackReturns Chart

100%-stacked density - at every x position the groups sum to 100%, showing the changing share of the total instead of absolute density - matches seaborn's kdeplot(hue=, multiple="fill").

Preview

Signature

sp.kde(title, values=None, *, x=None, y=None, variant="basic", categories=None, bandwidth=0.0, filled=True, fill_opacity=50, bins=30, n_points=80, palette=None, **kwargs) -> Chart

Description

sp.kde() est le point d'entrée unifié pour toute la famille KDE (Kernel Density Estimate). Le mot-clé variant sélectionne la stratégie de rendu — tous les autres arguments conservent le même nom d'une variante à l'autre. La KDE produit une estimation de densité continue lissée à partir d'un échantillon de points avec un noyau gaussien et la règle de Scott pour le choix automatique de la bande passante. SeraPlot rend les courbes en SVG Rust natif, avec multi-séries, normalisation, CDF, rug, histogramme superposé et remplissage en dégradé.

Variantes

Paramètres


Retour

Chart — objet avec propriété .html et méthode .show().


Variante "basic"Alias basic / filled / default / single / multiRetour Chart

Courbe pleine, mono ou multi-séries.

Aperçu
Variante "outline"Alias outline / line / stroke / compare / no_fillRetour Chart

Courbes en trait seul pour des superpositions épurées.

Aperçu
Variante "stepped"Alias stepped / step / stair / stairsRetour Chart

Densité en escalier (rendu rectangulaire).

Aperçu
Variante "rug"Alias rug / carpet / ticks / rugplotRetour Chart

Courbe KDE avec ticks rug aux positions des points.

Aperçu
Variante "histogram"Alias histogram / hist / with_hist / kdehist / distplotRetour Chart

Courbe KDE par-dessus un histogramme normalisé.

Aperçu
Variante "normalized"Alias normalized / pdf / norm / densityRetour Chart

Chaque série normalisée pour que son aire vaille 1.

Aperçu
Variante "cumulative"Alias cumulative / cdf / cumRetour Chart

Densité cumulée (CDF) dans [0, 1].

Aperçu
Variante "contour"Alias contour / bivariate / kde2d / joint_density / smoothRequis x, yOptionnel categoriesRetour Chart

Estimation de densité bivariée (2D) — un noyau gaussien produit évalué sur une grille et rendu comme une surface de densité ombrée, avec les points bruts superposés. Passez categories pour superposer une surface de densité par groupe, chacune dans sa propre couleur avec une légende.

Aperçu
Variante "levels"Alias levels / bands / iso_bands / ring_contour / bandedRequis x, yOptionnel categoriesRetour Chart

KDE bivariée quantifiée en bandes iso-densité discrètes avec une bordure visible à chaque frontière de bande — reproduit le rendu par niveaux de kdeplot(x=, y=, hue=, fill=True) de seaborn, par opposition au dégradé continu de contour.

Aperçu
Variante "stack"Alias stack / stacked / layered_stackRetour Chart

La courbe de densité de chaque groupe est empilée sur celle du précédent (total cumulé), toutes évaluées sur une même grille x partagée - reproduit kdeplot(hue=, multiple="stack") de seaborn.

Aperçu
Variante "fill"Alias fill / stack100 / percent_stack / filled_stackRetour Chart

Densité empilée à 100% - à chaque position x, les groupes totalisent 100%, montrant la part changeante du total plutôt que la densité absolue - reproduit kdeplot(hue=, multiple="fill") de seaborn.

Aperçu

Ridgeline — Joyplot / Stacked KDE

Signature

sp.ridgeline(title, categories, values, *, variant="basic", overlap=0.5, bandwidth=0.0, n_points=60, fill_opacity=56, palette=None, priority=None, **kwargs) -> Chart

Description

sp.ridgeline() is the unified entry point for the entire ridgeline family — also known as joyplot. The variant keyword selects the rendering strategy — every other argument keeps the same name across variants. A ridgeline plot stacks one KDE curve per category along a shared X axis with a controllable vertical overlap, making it ideal to compare distributions across many groups (years, regions, segments…). SeraPlot renders everything in pure Rust SVG, with quartile/mean overlays, rug ticks, gradient fills and a built-in viridis colormap. priority takes a list of row indices (in their displayed order) to draw last, on top of every other ridge - use it to force a specific distribution to visually climb over its neighbors regardless of its position in the stack.

Variants

Parameters


Returns

Chart — object with .html property and .show() method.


Variant "basic"Aliases basic / filled / default / single / multiReturns Chart

Stacked filled ridges (one per category) with white underlay.

Preview
Variant "lines"Aliases lines / outline / stroke / no_fillReturns Chart

Stroke-only ridges, no fill — clean outline view.

Preview
Variant "quartiles"Aliases quartiles / q / qrt / iqrReturns Chart

Marks Q1, median (solid), and Q3 vertical lines on each ridge.

Preview
Variant "mean"Aliases mean / average / avg / mean_dotReturns Chart

Dashed line + dot at the mean of each distribution.

Preview
Variant "rug"Aliases rug / ticks / carpet / rugplotReturns Chart

Filled ridge with rug ticks below the baseline at sample positions.

Preview
Variant "heatmap"Aliases heatmap / heat / rainbow / coloredReturns Chart

Auto viridis palette across ridges (or custom palette).

Preview
Variant "spaced"Aliases spaced / separated / no_overlap / splitReturns Chart

Forced low overlap — ridges are separated for clarity.

Preview

Signature

sp.ridgeline(title, categories, values, *, variant="basic", overlap=0.5, bandwidth=0.0, n_points=60, fill_opacity=56, palette=None, priority=None, **kwargs) -> Chart

Description

sp.ridgeline() est le point d'entrée unifié pour toute la famille ridgeline — aussi appelé joyplot. Le mot-clé variant sélectionne la stratégie de rendu — tous les autres arguments conservent le même nom d'une variante à l'autre. Un ridgeline empile une courbe KDE par catégorie sur un axe X partagé avec un recouvrement vertical réglable, idéal pour comparer des distributions à travers plusieurs groupes (années, régions, segments…). SeraPlot rend tout en SVG Rust natif, avec marqueurs quartiles/moyenne, ticks rug, dégradés et palette viridis intégrée. priority prend une liste d'index de lignes (dans leur ordre affiché) à dessiner en dernier, par-dessus toutes les autres crêtes - utile pour forcer une distribution donnée à visuellement monter sur ses voisines quelle que soit sa position dans l'empilement.

Variantes

Paramètres


Retour

Chart — objet avec propriété .html et méthode .show().


Variante "basic"Alias basic / filled / default / single / multiRetour Chart

Crêtes empilées remplies (une par catégorie) avec fond blanc.

Aperçu
Variante "lines"Alias lines / outline / stroke / no_fillRetour Chart

Crêtes en trait seul, sans remplissage — vue épurée.

Aperçu
Variante "quartiles"Alias quartiles / q / qrt / iqrRetour Chart

Trace les verticales Q1, médiane (pleine) et Q3 sur chaque crête.

Aperçu
Variante "mean"Alias mean / average / avg / mean_dotRetour Chart

Trait pointillé + point à la moyenne de chaque distribution.

Aperçu
Variante "rug"Alias rug / ticks / carpet / rugplotRetour Chart

Crête remplie avec ticks rug sous la ligne de base aux positions des points.

Aperçu
Variante "heatmap"Alias heatmap / heat / rainbow / coloredRetour Chart

Palette viridis automatique sur les crêtes (ou palette personnalisée).

Aperçu
Variante "spaced"Alias spaced / separated / no_overlap / splitRetour Chart

Recouvrement forcé bas — crêtes séparées pour la lisibilité.

Aperçu

Radar — Spider / Star Chart

Signature

sp.radar(title, axes, series, *, series_names=None, variant="basic", filled=True, fill_opacity=50, palette=None, **kwargs) -> Chart

Description

sp.radar() is the unified entry point for the entire radar / spider / star chart family. The variant keyword selects the rendering strategy — every other argument keeps the same name across variants. Radar charts are ideal for multivariate comparison across 3+ axes — performance profiles, KPIs, skill maps, scoring systems. SeraPlot draws everything in pure Rust SVG with concentric grid rings, axis lines, automatic ring tick labels, optional legend and per-series palette colors. The polar-bar variant turns the chart into a categorical polar histogram, the stacked variant builds a cumulative composition view.

Variants

Parameters


Returns

Chart — object with .html property and .show() method.

Variant "basic"Aliases basic / default / classicReturns Chart

Filled polygon per series with stroke and dot markers — the standard radar.

Preview
Variant "lines"Aliases lines / outline / stroke / no_fillReturns Chart

Stroke-only polygons, no fill — clean overlay for many series.

Preview
Variant "filled"Aliases filled / fill / solid / areaReturns Chart

Strong fill, no stroke, sorted back-to-front by total area for clarity.

Preview
Variant "markers"Aliases markers / dots / points / markerReturns Chart

Light stroke + bold outlined markers — emphasis on data points.

Preview
Variant "dashed"Aliases dashed / dash / dottedReturns Chart

Dashed outline polygons — useful for projections, targets, baselines.

Preview
Variant "stacked"Aliases stacked / stack / cumulativeReturns Chart

Cumulative stacking on each axis — visualizes part-of-whole composition.

Preview
Variant "polar_bar"Aliases polar_bar / polar / bar / radial_barReturns Chart

Radial bars per axis grouped by series — categorical polar histogram.

Preview

Signature

sp.radar(title, axes, series, *, series_names=None, variant="basic", filled=True, fill_opacity=50, palette=None, **kwargs) -> Chart

Description

sp.radar() est le point d'entrée unifié pour toute la famille radar / spider / star. Le mot-clé variant sélectionne la stratégie de rendu — tous les autres arguments conservent le même nom d'une variante à l'autre. Le radar est idéal pour comparer plusieurs séries sur 3 axes ou plus — profils de performance, KPI, cartographie de compétences, systèmes de notation. SeraPlot dessine tout en SVG Rust natif avec anneaux de grille concentriques, axes, labels automatiques de graduation, légende optionnelle et couleurs de palette par série. La variante polar_bar transforme le radar en histogramme polaire catégoriel, la variante stacked construit une vue de composition cumulative.

Variantes

Paramètres


Retour

Chart — objet avec propriété .html et méthode .show().


Variante "basic"Alias basic / default / classicRetour Chart

Polygone rempli par série avec contour et points — le radar standard.

Aperçu
Variante "lines"Alias lines / outline / stroke / no_fillRetour Chart

Polygones en trait seul, sans remplissage — overlay net pour plusieurs séries.

Aperçu
Variante "filled"Alias filled / fill / solid / areaRetour Chart

Remplissage fort sans contour, trié de l'arrière vers l'avant par aire totale.

Aperçu
Variante "markers"Alias markers / dots / points / markerRetour Chart

Trait léger + marqueurs détourés — accent sur les points de données.

Aperçu
Variante "dashed"Alias dashed / dash / dottedRetour Chart

Polygones à contour pointillé — utile pour projections, cibles, références.

Aperçu
Variante "stacked"Alias stacked / stack / cumulativeRetour Chart

Empilement cumulatif sur chaque axe — visualise une composition part/tout.

Aperçu
Variante "polar_bar"Alias polar_bar / polar / bar / radial_barRetour Chart

Barres radiales par axe groupées par série — histogramme polaire catégoriel.

Aperçu

Slope — Before / After Comparison Chart

Signature

sp.slope(title, labels, left, right, *, variant="basic", left_label="Before", right_label="After", palette=None, show_text=True, **kwargs) -> Chart

Description

sp.slope() renders the entire slope-chart family: two parallel value axes (left / right) with one connector per row. The variant keyword swaps the connector style without changing any other parameter. Slope charts excel at before/after comparisons, A/B test outcomes, ranking shifts, KPI changes between periods, and any pair-wise change across many entities.

Variants

Parameters

Returns

Chart — object with .html property and .show() method.


Tips

  • Use sort_order="asc" / "desc" to reorder rows by left value before drawing.
  • The "diverging" and "thick" variants encode magnitude visually — perfect for executive summaries.
  • For rank shifts (positions in a league), prefer "bumps" rather than "basic".
  • Combine palette= with "monochrome" to match brand colours per category.
Variant "basic"Aliases basic / default / direction / classicReturns Chart

Direction-coloured straight lines (green up, red down) with endpoint dots.

Preview
Variant "monochrome"Aliases monochrome / mono / uniform / single_colorReturns Chart

Uniform palette colour per row, no direction tint — ideal for categorical narratives.

Preview
Variant "highlighted"Aliases highlighted / highlight / top / moversReturns Chart

Top 3 movers (largest |Δ|) drawn in vivid colour, the rest dimmed in grey.

Preview
Variant "bumps"Aliases bumps / bumpchart / rank / rankingReturns Chart

Bump chart: y axis encodes the rank (1..n) at each side instead of the raw value.

Preview
Variant "curved"Aliases curved / curve / bezier / smoothReturns Chart

Cubic-Bezier S-curves between the two endpoints — smoother visual flow.

Preview
Variant "thick"Aliases thick / magnitude / weighted / weightReturns Chart

Stroke-width proportional to |right - left| — magnitude becomes the visual weight.

Preview
Variant "diverging"Aliases diverging / delta / change / centeredReturns Chart

Centered delta bars: positive bars grow right (green), negative grow left (red).

Preview
Variant "stepped"Aliases stepped / step / elbow / rectilinearReturns Chart

L-shape connector: horizontal then vertical then horizontal — rectilinear flow.

Preview

Signature

sp.slope(title, labels, left, right, *, variant="basic", left_label="Before", right_label="After", palette=None, show_text=True, **kwargs) -> Chart

Description

sp.slope() produit toute la famille des slope charts : deux axes de valeurs parallèles (gauche / droite) avec un connecteur par ligne. Le mot-clé variant permute le style du connecteur sans changer aucun autre paramètre. Idéal pour comparer avant/après, résultats A/B, changements de classement, KPI entre périodes, et toute évolution par paire sur de nombreuses entités.

Variantes

Paramètres

Retour

Chart — objet avec propriété .html et méthode .show().


Astuces

  • Utilisez sort_order="asc" / "desc" pour réordonner les lignes selon left avant le rendu.
  • Les variantes "diverging" et "thick" encodent visuellement la magnitude — parfaites pour un résumé exécutif.
  • Pour les changements de rang (positions dans un classement), préférez "bumps" à "basic".
  • Combinez palette= avec "monochrome" pour aligner les couleurs sur les catégories de marque.
Variant "basic"Aliases basic / default / direction / classicReturns Chart

Lignes droites colorées selon la direction (vert haut, rouge bas) avec points aux extrémités.

Preview
Variant "monochrome"Aliases monochrome / mono / uniform / single_colorReturns Chart

Couleur uniforme par ligne tirée de la palette, sans coloration directionnelle.

Preview
Variant "highlighted"Aliases highlighted / highlight / top / moversReturns Chart

Top 3 des plus grands Δ mis en avant en couleur vive, le reste estompé en gris.

Preview
Variant "bumps"Aliases bumps / bumpchart / rank / rankingReturns Chart

Bump chart : l’axe y encode le rang (1..n) à chaque côté plutôt que la valeur.

Preview
Variant "curved"Aliases curved / curve / bezier / smoothReturns Chart

Courbes de Bézier cubiques en S entre les deux extrémités — transition douce.

Preview
Variant "thick"Aliases thick / magnitude / weighted / weightReturns Chart

Épaisseur du trait proportionnelle à |droite - gauche| — la magnitude devient le poids visuel.

Preview
Variant "diverging"Aliases diverging / delta / change / centeredReturns Chart

Barres delta centrées : positives à droite (vert), négatives à gauche (rouge).

Preview
Variant "stepped"Aliases stepped / step / elbow / rectilinearReturns Chart

Connecteur en L : horizontal puis vertical puis horizontal — flux rectiligne.

Preview

Funnel — Conversion / Pipeline Chart

Signature

sp.funnel(title, labels, values, *, variant="basic", palette=None, show_text=True, **kwargs) -> Chart

Description

sp.funnel() renders the entire funnel-chart family: a stacked sequence of stages where each step’s width encodes a value. The variant keyword switches the geometry without changing any other parameter. Funnels are the standard for conversion analytics (visitors → signups → paid), recruiting pipelines, sales pipelines, process drop-off and any descending-cohort analysis.

Variants

Parameters

Returns

Chart — object with .html property and .show() method.


Tips

  • Sort stages descending before passing them in (or use sort_order="desc").
  • Use "conversion" when the audience cares about stage-to-stage retention rate.
  • The "pyramid" variant works best when values follow a steep decay.
  • For broad audiences, "chevron" reads as a sales pipeline more naturally than the trapezoid.
Variant "basic"Aliases basic / default / trapezoid / classicReturns Chart

Classic centered trapezoid pyramid — each step’s top width inherits the previous bottom width.

Preview
Variant "stepped"Aliases stepped / bar / rect / rectangleReturns Chart

Centered rectangles per stage (no diagonal slope), width ∝ value/max.

Preview
Variant "rounded"Aliases rounded / round / pill / smoothReturns Chart

Trapezoids with rounded outer corners — softer, pill-like aesthetic.

Preview
Variant "chevron"Aliases chevron / arrow / pipeline / pointerReturns Chart

Pentagon arrow shapes pointing right — sales-pipeline / process flow style.

Preview
Variant "pyramid"Aliases pyramid / triangle / cone / pointReturns Chart

Continuous pyramid: each level narrows progressively to a point at the bottom.

Preview
Variant "inverted"Aliases inverted / inverse / reverse / upside_downReturns Chart

Vertically flipped funnel — widest stage at the bottom (growth pyramid).

Preview
Variant "conversion"Aliases conversion / dropoff / rate / stepsReturns Chart

Basic trapezoid plus drop-off percentage between consecutive stages displayed in red.

Preview
Variant "compare"Aliases compare / multi / side_by_side / funnelsRequired seriesOptional series_names, category_series, text_infoReturns Chart

Several independent funnels side by side, each with its own stage count and its own scale - the native equivalent of composing multiple go.Funnel() traces in Plotly, without ever building a trace by hand. Pass series (one value list per funnel), series_names (funnel names) and category_series (one stage-label list per funnel, since funnels can have different stage counts). Automatically selected whenever series has more than one entry and category_series is given - use "grouped" instead when every group shares the same stages. text_info combines "value", "percent_initial", "percent_previous" and "percent_total" with +.

Preview
Variant "grouped"Aliases grouped / colored / by_color / shared_stagesRequired labels, seriesOptional series_names, text_infoReturns Chart

One funnel, several colored groups sharing the exact same stages - each stage's band splits into adjacent, touching segments (no gap) whose widths are proportional to each group's own value on one shared linear scale, so the combined shape tapers naturally like a single funnel. The native equivalent of px.funnel(df, x="number", y="stage", color="office") in Plotly - works with any number of groups, not just two. Auto-selected whenever series has more than one entry and category_series is not given.

Preview

Signature

sp.funnel(title, labels, values, *, variant="basic", palette=None, show_text=True, **kwargs) -> Chart

Description

sp.funnel() produit toute la famille des entonnoirs : une séquence d’étapes empilées dont la largeur encode une valeur. Le mot-clé variant permute la géométrie sans changer aucun autre paramètre. Standard pour l’analyse de conversion (visiteurs → inscrits → payants), pipelines de recrutement, pipelines commerciaux, fuites de processus et toute analyse de cohorte décroissante.

Variantes

Paramètres

Retour

Chart — objet avec propriété .html et méthode .show().


Astuces

  • Triez les étapes décroissantes avant de les passer (ou utilisez sort_order="desc").
  • Utilisez "conversion" quand l’audience s’intéresse au taux de rétention entre étapes.
  • La variante "pyramid" fonctionne mieux avec des valeurs en forte décroissance.
  • Pour un public large, "chevron" se lit plus naturellement comme un pipeline commercial qu’un trapèze.
Variant "basic"Aliases basic / default / trapezoid / classicReturns Chart

Pyramide trapézoïdale centrée classique — le haut de chaque étape hérite du bas de la précédente.

Preview
Variant "stepped"Aliases stepped / bar / rect / rectangleReturns Chart

Rectangles centrés par étape (sans pente diagonale), largeur ∝ valeur/max.

Preview
Variant "rounded"Aliases rounded / round / pill / smoothReturns Chart

Trapèzes avec coins arrondis — esthétique douce de type pilule.

Preview
Variant "chevron"Aliases chevron / arrow / pipeline / pointerReturns Chart

Pentagones en flèche pointant à droite — style pipeline commercial / processus.

Preview
Variant "pyramid"Aliases pyramid / triangle / cone / pointReturns Chart

Pyramide continue : chaque niveau se rétrécit progressivement jusqu’à une pointe.

Preview
Variant "inverted"Aliases inverted / inverse / reverse / upside_downReturns Chart

Entonnoir inversé verticalement — étape la plus large en bas (pyramide de croissance).

Preview
Variant "conversion"Aliases conversion / dropoff / rate / stepsReturns Chart

Trapèze de base avec le pourcentage de chute entre étapes affiché en rouge.

Preview
Variante "compare"Alias compare / multi / side_by_side / funnelsRequis seriesOptionnel series_names, category_series, text_infoRetour Chart

Plusieurs entonnoirs indépendants côte à côte, chacun avec son propre nombre d'étapes et sa propre échelle - l'équivalent natif de composer plusieurs traces go.Funnel() en Plotly, sans jamais construire de trace à la main. Passez series (une liste de valeurs par entonnoir), series_names (noms des entonnoirs) et category_series (une liste d'étiquettes d'étapes par entonnoir, puisque les entonnoirs peuvent avoir des nombres d'étapes différents). Sélectionné automatiquement dès que series a plus d'une entrée et que category_series est fourni - utilisez "grouped" quand tous les groupes partagent les mêmes étapes. text_info combine "value", "percent_initial", "percent_previous" et "percent_total" avec +.

Aperçu
Variante "grouped"Alias grouped / colored / by_color / shared_stagesRequis labels, seriesOptionnel series_names, text_infoRetour Chart

Un seul entonnoir, plusieurs groupes colorés partageant exactement les mêmes étapes - la bande de chaque étape se divise en segments adjacents et jointifs (sans espace) dont les largeurs sont proportionnelles à la valeur de chaque groupe sur une même échelle linéaire partagée, si bien que la forme combinée se rétrécit naturellement comme un seul entonnoir. L'équivalent natif de px.funnel(df, x="number", y="stage", color="office") en Plotly - fonctionne avec n'importe quel nombre de groupes, pas seulement deux. Sélectionné automatiquement dès que series a plus d'une entrée et que category_series n'est pas fourni.

Aperçu

Waterfall — Running-Total Bridge Chart

Signature

sp.waterfall(title, labels, values, *, variant="basic", show_text=True, **kwargs) -> Chart

Description

sp.waterfall() renders the entire waterfall-chart family: a sequence of bars where each step adds (positive) or subtracts (negative) from a running total. The variant keyword selects the geometry without touching any other parameter. Waterfalls are the standard for P&L bridges, variance analysis, cohort decomposition, fee/tax breakdowns and any "from A to B, what changed?" narrative.

Totals — set a value to 0 and use a label containing total, net, final, gross or ebitda to mark a subtotal bar; it is rendered with the totals color and anchored on the running sum.

Variants

Parameters

Returns

Chart — object with .html property and .show() method.


Variant "basic"Aliases basic / default / classic / barsReturns Chart

Classic running-sum bars with dashed connectors between consecutive steps.

Preview
Variant "stepped"Aliases stepped / step / staircase / stairsReturns Chart

Bars touch each other forming a continuous staircase, no connectors needed.

Preview
Variant "lollipop"Aliases lollipop / stick / popsicle / lollyReturns Chart

Stick + circle marker at the end of each step. Excellent ink-to-data ratio.

Preview
Variant "arrowed"Aliases arrowed / arrow / directional / tippedReturns Chart

Triangle on top (positives) or bottom (negatives) emphasizes direction at a glance.

Preview
Variant "delta"Aliases delta / percent / annotated / pctReturns Chart

Bars + signed percentage badge (Delta vs previous running total) above each step.

Preview
Variant "horizontal"Aliases horizontal / rows / sideways / hReturns Chart

Rotated 90 degrees: each step becomes a horizontal row stacking downward, anchored to the previous running total. Editorial layout for reports with long labels or vertical storytelling.

Preview

Signature

sp.waterfall(title, labels, values, *, variant="basic", show_text=True, **kwargs) -> Chart

Description

sp.waterfall() rassemble toute la famille des graphiques waterfall : une suite de barres ou chaque etape ajoute (positif) ou retranche (negatif) au cumul courant. Le mot-cle variant change la geometrie sans toucher aux autres parametres. Les waterfalls sont la reference pour les ponts de P&L, l analyse d ecarts, la decomposition de cohortes, le detail des frais/taxes et tout recit du type "de A vers B, qu est-ce qui a change ?".

Totaux — mettez la valeur a 0 et utilisez un libelle contenant total, net, final, gross ou ebitda pour marquer une barre de sous-total ; elle est rendue avec la couleur des totaux et ancree sur le cumul courant.

Variantes

Paramètres

Retour

Chart — objet avec une propriete .html et une methode .show().


Variant "basic"Aliases basic / default / classic / barsReturns Chart

Barres classiques a somme cumulee avec connecteurs pointilles entre etapes.

Preview
Variant "stepped"Aliases stepped / step / staircase / stairsReturns Chart

Barres jointives formant un escalier continu, sans connecteur.

Preview
Variant "lollipop"Aliases lollipop / stick / popsicle / lollyReturns Chart

Tige + cercle en fin de chaque etape. Excellent ratio encre/donnee.

Preview
Variant "arrowed"Aliases arrowed / arrow / directional / tippedReturns Chart

Triangle dessus (positifs) ou dessous (negatifs) pour souligner la direction en un coup d oeil.

Preview
Variant "delta"Aliases delta / percent / annotated / pctReturns Chart

Barres + badge de pourcentage signe (Delta vs cumul precedent) au-dessus de chaque etape.

Preview
Variante "horizontal"Aliases horizontal / rows / sideways / hRetour Chart

Waterfall pivote a 90 degres : les etapes deviennent des lignes empilees verticalement, chacune partant du cumul precedent. Layout editorial pour rapports avec libelles longs ou storytelling vertical.

Apercu

Sunburst — Hierarchical Ring Chart

Signature

sp.sunburst(title, labels, parents, values, *, variant="basic", palette=None, **kwargs) -> Chart

Description

sp.sunburst() is the unified entry point for the entire sunburst-chart family. A sunburst represents a hierarchy as concentric rings: the innermost ring is the root, each outer ring is a deeper level, and angular size encodes value. The variant keyword selects the visual style without changing any other parameter. Sunbursts are the standard for visualizing nested taxonomies (org charts, file systems, market segmentation, expense categories, phylogenetic trees) and outperform classic pie charts as soon as a real hierarchy exists.

Hierarchy encodinglabels lists every node, parents gives the parent label of each node ("" for a root). Leaf values are taken from values; internal node values are auto-rolled-up from descendants when set to 0.

Variants

Parameters

Returns

Chart — object with .html property and .show() method.


Variant "basic"Aliases basic / default / classic / ringReturns Chart

Classic concentric rings with depth-based opacity and white separators.

Preview
Variant "donut"Aliases donut / hole / ring_hole / donut_ringReturns Chart

Larger central hole with the formatted grand total displayed at the center.

Preview
Variant "outlined"Aliases outlined / outline / stroke / wireframeReturns Chart

Wireframe wedges: white fill + colored stroke that thins on deeper rings.

Preview
Variant "gapped"Aliases gapped / spaced / isolated / petalsReturns Chart

Angular and radial margins between every wedge for crisp petal-like separation.

Preview
Variant "depth_fade"Aliases depth_fade / fade / fading / depthReturns Chart

Standard palette but opacity decreases with depth, focusing the eye on top levels.

Preview
Variant "mono"Aliases mono / monochrome / single / uniformReturns Chart

Single-color rings differentiated only by depth-based opacity. Editorial look.

Preview
Variant "zoomable"Aliases zoomable / zoom / animated / interactive / drillReturns Chart

Click a ring segment to zoom into that branch, animating every other segment to its new angle/radius. Click the center to zoom back out.

Preview

Signature

sp.sunburst(title, labels, parents, values, *, variant="basic", palette=None, **kwargs) -> Chart

Description

sp.sunburst() est le point d entree unifie pour toute la famille des graphiques sunburst. Un sunburst represente une hierarchie sous forme d anneaux concentriques : l anneau interieur est la racine, chaque anneau exterieur est un niveau plus profond, et l angle code la valeur. Le mot-cle variant change le style sans toucher aux autres parametres. Les sunbursts sont la reference pour visualiser des taxonomies imbriquees (organigrammes, systemes de fichiers, segmentation marche, categories de depenses, arbres phylogenetiques) et surpassent le camembert des qu une vraie hierarchie existe.

Encodage de la hierarchielabels liste tous les noeuds, parents donne le libelle du parent de chaque noeud ("" pour une racine). Les valeurs des feuilles viennent de values ; les noeuds internes a 0 sont calcules automatiquement comme la somme de leurs descendants.

Variantes

Paramètres

Retour

Chart — objet avec une propriete .html et une methode .show().


Variant "basic"Aliases basic / default / classic / ringReturns Chart

Anneaux concentriques classiques avec opacite degressive selon la profondeur.

Preview
Variant "donut"Aliases donut / hole / ring_hole / donut_ringReturns Chart

Large trou central avec total general formate (k/M) au centre.

Preview
Variant "outlined"Aliases outlined / outline / stroke / wireframeReturns Chart

Quartiers en fil de fer : fond blanc + contour colore amincissant en profondeur.

Preview
Variant "gapped"Aliases gapped / spaced / isolated / petalsReturns Chart

Marges angulaires et radiales entre quartiers pour une separation nette en petales.

Preview
Variant "depth_fade"Aliases depth_fade / fade / fading / depthReturns Chart

Palette standard mais opacite decroissante en profondeur pour concentrer le regard.

Preview
Variant "mono"Aliases mono / monochrome / single / uniformReturns Chart

Anneaux monochromes differencies uniquement par opacite. Rendu editorial.

Preview
Variant "zoomable"Alias zoomable / zoom / animated / interactive / drillRetour Chart

Cliquer un segment zoome sur cette branche, en animant chaque autre segment vers son nouvel angle/rayon. Cliquer le centre pour dezoomer.

Preview

Treemap — Hierarchical Proportional Tiles

Signature

sp.treemap(title, labels, values, *, parents=None, variant="basic", palette=None, **kwargs) -> Chart

Description

sp.treemap() is the unified entry point for the entire treemap-chart family. A treemap divides a rectangle into proportional sub-rectangles whose area encodes value; when a parents list is given the layout becomes hierarchical (each parent gets its own block, leaves are squarified within). The variant keyword switches the visual style without touching the data. Treemaps are the standard for visualizing budgets, market cap, disk usage, portfolio weights, file systems and any 'whole = sum of parts' breakdown.

Hierarchical mode — pass parents (one parent label per leaf, can be empty string "" for a flat treemap). Internal totals are auto-computed from leaves. Sort leaves with the sort_order parameter ("desc" recommended).

Variants

Parameters

Returns

Chart — object with .html property and .show() method.


Variant "basic"Aliases basic / default / classic / filledReturns Chart

Classic squarified treemap with rounded corners and white separators between tiles.

Preview
Variant "flat"Aliases flat / mosaic / edge / tightReturns Chart

Edge-to-edge mosaic with no stroke and no rounding for a dense, magazine-style block.

Preview
Variant "outlined"Aliases outlined / outline / stroke / wireframeReturns Chart

Wireframe tiles: translucent fill with bold colored stroke and dark labels for print-ready look.

Preview
Variant "gapped"Aliases gapped / spaced / inset / separatedReturns Chart

Each tile inset with extra padding so the structure breathes; rounded corners and color fill.

Preview
Variant "nested"Aliases nested / grouped / parents / hierarchyReturns Chart

Draws parent group rectangles with header labels around their children, emphasising hierarchy.

Preview
Variant "heat"Aliases heat / heatmap / temperature / cold_warmReturns Chart

Color encodes value (cool blue -> hot red) instead of identity, turning the treemap into a heatmap.

Preview
Variant "mono"Aliases mono / monochrome / single / uniformReturns Chart

Single hue with opacity decreasing by rank; editorial, minimalist, perfect for slides.

Preview

Signature

sp.treemap(title, labels, values, *, parents=None, variant="basic", palette=None, **kwargs) -> Chart

Description

sp.treemap() est le point d entree unifie pour toute la famille treemap. Un treemap decoupe un rectangle en sous-rectangles proportionnels dont l aire code la valeur ; lorsqu une liste parents est fournie le rendu devient hierarchique (chaque parent recoit son propre bloc, les feuilles y sont squarifiees). Le mot-cle variant change le style sans toucher aux donnees. Les treemaps sont la reference pour visualiser budgets, capitalisations boursieres, occupation disque, poids de portefeuille, systemes de fichiers et toute decomposition 'tout = somme des parties'.

Mode hierarchique — passez parents (un libelle parent par feuille, chaine vide "" pour un treemap plat). Les totaux internes sont auto-calcules. Triez les feuilles avec sort_order ("desc" recommande).

Variantes

Paramètres

Retour

Chart — objet avec une propriete .html et une methode .show().


Variant "basic"Aliases basic / default / classic / filledReturns Chart

Treemap squarifie classique avec coins arrondis et separateurs blancs entre les tuiles.

Preview
Variant "flat"Aliases flat / mosaic / edge / tightReturns Chart

Mosaique bord-a-bord sans contour ni arrondi pour un bloc dense type magazine.

Preview
Variant "outlined"Aliases outlined / outline / stroke / wireframeReturns Chart

Tuiles en fil de fer : fond translucide, contour colore epais et libelles sombres, style imprimable.

Preview
Variant "gapped"Aliases gapped / spaced / inset / separatedReturns Chart

Chaque tuile en retrait avec marges supplementaires pour aerer la structure ; coins arrondis.

Preview
Variant "nested"Aliases nested / grouped / parents / hierarchyReturns Chart

Dessine les rectangles parents avec libelle d en-tete autour de leurs enfants, met en avant la hierarchie.

Preview
Variant "heat"Aliases heat / heatmap / temperature / cold_warmReturns Chart

La couleur code la valeur (bleu froid -> rouge chaud) au lieu de l identite, treemap en heatmap.

Preview
Variant "mono"Aliases mono / monochrome / single / uniformReturns Chart

Teinte unique avec opacite decroissante par rang ; minimaliste et editorial, ideal pour slides.

Preview

Candlestick — OHLC Time Series

Signature

sp.candlestick(title, labels, open, high, low, close, *, variant="basic", palette=None, **kwargs) -> Chart

Description

sp.candlestick() is the unified entry point for the entire candlestick-chart family. A candlestick chart shows OHLC (Open, High, Low, Close) bars over time and is the de facto standard for financial markets, crypto, commodities, energy spot prices and any time-series with intra-period spread. The variant keyword switches the visual style without touching the data — including derived views like Heikin-Ashi smoothing, close-only line, mountain area and high-low range bars.

Color convention — by default green = up (close >= open) and red = down. Override with palette=[up_color, down_color]. Bars are rendered left-to-right in input order; use sort_order="asc" to sort by close price.

Variants

Parameters

Returns

Chart — object with .html property and .show() method.


Variant "basic"Aliases basic / default / classic / filledReturns Chart

Classic OHLC candles: solid body, thin wick, green for up bars and red for down bars.

Preview
Variant "hollow"Aliases hollow / empty / japanese / white_upReturns Chart

Japanese-style hollow up candles (white fill + colored stroke) and filled down candles.

Preview
Variant "ohlc"Aliases ohlc / western / bar / tickReturns Chart

Western OHLC bars: vertical wick with left tick = open, right tick = close, no body.

Preview
Variant "heikin"Aliases heikin / heikin_ashi / ha / smoothedReturns Chart

Heikin-Ashi smoothed candles: filters market noise to highlight trends and reversals clearly.

Preview
Variant "outlined"Aliases outlined / outline / stroke / wireframeReturns Chart

Wireframe candles: translucent body with bold colored stroke; lighter visual footprint.

Preview
Variant "line"Aliases line / close / lineplot / trendReturns Chart

Close-price line chart with markers — same data, smoother trend reading without OHLC noise.

Preview
Variant "mountain"Aliases mountain / area / filled_area / shadeReturns Chart

Close-price area chart with vertical gradient under the line; great for hero / cover charts.

Preview
Variant "range"Aliases range / hl / highlow / spreadReturns Chart

High-low range bars only (no open/close), single color — pure volatility visualization.

Preview
Variant "volume"Aliases volume / crypto / with_volume / tradingReturns Chart

Candlestick + volume histogram fusion — the standard crypto/trading terminal layout. Candles fill the upper ~78% of the plot; a volume bar strip (colored by that period's up/down candle) fills the remaining band beneath, sharing the same x-axis. Pass a volume array alongside open/high/low/close.

Preview

Signature

sp.candlestick(title, labels, open, high, low, close, *, variant="basic", palette=None, **kwargs) -> Chart

Description

sp.candlestick() est le point d entree unifie pour toute la famille des chandeliers. Un graphique en chandeliers affiche des barres OHLC (Ouverture, Haut, Bas, Cloture) dans le temps et constitue le standard de fait pour les marches financiers, la crypto, les matieres premieres, le spot energie et toute serie temporelle avec spread intra-periode. Le mot-cle variant change le style sans toucher aux donnees — y compris des vues derivees comme le lissage Heikin-Ashi, la ligne de cloture, l aire mountain et les barres haut-bas.

Convention de couleur — par defaut vert = hausse (close >= open) et rouge = baisse. Surchargez avec palette=[couleur_hausse, couleur_baisse]. Les barres sont rendues de gauche a droite dans l ordre d entree ; sort_order="asc" pour trier par prix de cloture.

Variantes

Paramètres

Retour

Chart — objet avec une propriete .html et une methode .show().


Variant "basic"Aliases basic / default / classic / filledReturns Chart

Bougies OHLC classiques : corps plein, meche fine, vert pour hausse et rouge pour baisse.

Preview
Variant "hollow"Aliases hollow / empty / japanese / white_upReturns Chart

Style japonais : bougies haussieres creuses (fond blanc + contour colore) et baissieres pleines.

Preview
Variant "ohlc"Aliases ohlc / western / bar / tickReturns Chart

Barres OHLC americaines : meche verticale, tick gauche = ouverture, droit = cloture, sans corps.

Preview
Variant "heikin"Aliases heikin / heikin_ashi / ha / smoothedReturns Chart

Bougies Heikin-Ashi lissees : filtre le bruit pour mettre en evidence tendances et retournements.

Preview
Variant "outlined"Aliases outlined / outline / stroke / wireframeReturns Chart

Bougies en fil de fer : corps translucide avec contour colore epais ; rendu plus aere.

Preview
Variant "line"Aliases line / close / lineplot / trendReturns Chart

Ligne des prix de cloture avec marqueurs — meme donnee, lecture de tendance plus lisse.

Preview
Variant "mountain"Aliases mountain / area / filled_area / shadeReturns Chart

Aire des prix de cloture avec degrade vertical sous la courbe ; ideal pour visuel de couverture.

Preview
Variant "range"Aliases range / hl / highlow / spreadReturns Chart

Barres haut-bas uniquement (sans ouverture/cloture), une seule couleur — visualisation de la volatilite.

Preview
Variant "volume"Aliases volume / crypto / with_volume / tradingReturns Chart

Fusion chandelier + histogramme de volume — la mise en page standard des terminaux crypto/trading. Les chandeliers occupent les ~78% superieurs du graphique ; une bande de barres de volume (colorees selon la hausse/baisse de la periode) occupe le reste, partageant le meme axe x. Passez un tableau volume en plus de open/high/low/close.

Apercu

Dumbbell - Before / After Two-Point Comparison

Signature

sp.dumbbell(title, labels, start, end, *, variant="basic", series_name_start="Start", series_name_end="End", **kwargs) -> Chart

Description

sp.dumbbell() is the unified entry point for the dumbbell-chart family. Each row plots two values - typically a before and an after - linked by a connector, making it the chart of choice for change, gap or comparison-over-time analyses (salary equity, turnaround KPIs, A/B uplifts, etc.). The variant keyword switches the visual treatment without touching the data.

Variants

Parameters

Returns

Chart - object with .html property and .show() method.


Variant "basic"Aliases basic / default / classic / dotReturns Chart

Classic two-dot dumbbell with a gray connecting bar; the workhorse of before/after comparisons.

Preview
Variant "arrow"Aliases arrow / directional / delta_arrow / flowReturns Chart

Arrowhead points from start to end so direction of change is immediate.

Preview
Variant "delta"Aliases delta / change / diff / signedReturns Chart

Bar between dots is colored by sign (green up, red down) to encode direction and magnitude.

Preview
Variant "barbell"Aliases barbell / thick / weighted / editorialReturns Chart

Square weighted endpoints on a thick gray axis - editorial barbell look for slides.

Preview
Variant "glow"Aliases glow / halo / neon / softReturns Chart

Soft halo around endpoints with thin connector for a luminous, modern feel.

Preview
Variant "dotted"Aliases dotted / dashed / minimal / thinReturns Chart

Dashed connector with hollow ring markers - lightweight and airy.

Preview
Variant "ranked"Aliases ranked / ranking / ordered / numberedReturns Chart

Adds a numeric rank in front of every label - perfect for top-N comparisons.

Preview

Signature

sp.dumbbell(title, labels, start, end, *, variant="basic", series_name_start="Start", series_name_end="End", **kwargs) -> Chart

Description

sp.dumbbell() est le point d entree unique pour la famille dumbbell. Chaque ligne montre deux valeurs - typiquement avant/apres - reliees par un connecteur, ce qui en fait le choix naturel pour visualiser un changement, un ecart ou une evolution (equite salariale, KPIs de redressement, uplifts A/B, etc.). Le mot-cle variant change le style visuel sans toucher aux donnees.

Variantes

Paramètres

Retour

Chart - objet avec propriete .html et methode .show().


Variant "basic"Aliases basic / default / classic / dotReturns Chart

Dumbbell classique a deux points et barre grise - la base des comparaisons avant/apres.

Preview
Variant "arrow"Aliases arrow / directional / delta_arrow / flowReturns Chart

Une fleche pointe du depart vers l arrivee, la direction du changement est immediate.

Preview
Variant "delta"Aliases delta / change / diff / signedReturns Chart

La barre entre les points prend la couleur du signe (vert hausse, rouge baisse).

Preview
Variant "barbell"Aliases barbell / thick / weighted / editorialReturns Chart

Halteres carres sur un axe epais - look editorial pour presentations.

Preview
Variant "glow"Aliases glow / halo / neon / softReturns Chart

Halo doux autour des extremites avec connecteur fin - style lumineux et moderne.

Preview
Variant "dotted"Aliases dotted / dashed / minimal / thinReturns Chart

Connecteur en pointilles et marqueurs en anneaux - leger et aere.

Preview
Variant "ranked"Aliases ranked / ranking / ordered / numberedReturns Chart

Ajoute un rang numerique devant chaque label - ideal pour comparer un top-N.

Preview

Bullet - Compact KPI vs Target

Signature

sp.bullet(title, labels, values, *, targets=None, max_vals=None, ranges=None, comparisons=None, variant="basic", **kwargs) -> Chart

Description

sp.bullet() is the unified entry point for the bullet-chart family. Inspired by Edward Tufte, a bullet packs an actual value, a target, qualitative ranges and a scale into a single horizontal row - perfect for KPI dashboards where space is precious. The variant keyword switches the visual treatment (zones, traffic light, thermometer, progress pill, dot, ghost-bar comparison) without touching the data.

Variants

Parameters

Returns

Chart - object with .html property and .show() method.


Variant "basic"Aliases basic / default / classic / standardReturns Chart

Classic Tufte bullet: track + qualitative range + value bar + target tick.

Preview
Variant "stacked"Aliases stacked / stacked_ranges / zones / qualitativeReturns Chart

Three graduated qualitative bands (poor / satisfactory / good) drawn behind the value bar.

Preview
Variant "thermo"Aliases thermo / thermometer / vertical / columnReturns Chart

Vertical thermometer style with a bulb base - dramatic for KPIs in a row.

Preview
Variant "segmented"Aliases segmented / traffic / rag / zones_colorReturns Chart

Traffic-light segmented track (red / amber / green) for status dashboards.

Preview
Variant "minimal"Aliases minimal / sparkline / clean / nakedReturns Chart

Sparkline-thin pill bar with target tick only - ultra-clean inline indicator.

Preview
Variant "dot"Aliases dot / point / marker / pipReturns Chart

Single dot on a track instead of a bar - dot-plot variant of the bullet.

Preview
Variant "progress"Aliases progress / pill / bar / percentReturns Chart

Pill-shape gradient progress bar with a percentage label centered inside.

Preview
Variant "compare"Aliases compare / vs / ghost / priorReturns Chart

Adds a ghost bar (e.g. previous period via comparisons) behind the current value.

Preview

Signature

sp.bullet(title, labels, values, *, targets=None, max_vals=None, ranges=None, comparisons=None, variant="basic", **kwargs) -> Chart

Description

sp.bullet() est le point d entree unique pour la famille bullet. Inspire par Edward Tufte, le bullet condense valeur, cible, zones qualitatives et echelle dans une seule ligne horizontale - parfait pour des dashboards KPIs serres. Le mot-cle variant change l aspect (zones, feu tricolore, thermometre, pillule de progression, point, comparaison par barre fantome) sans toucher aux donnees.

Variantes

Paramètres

Retour

Chart - objet avec propriete .html et methode .show().


Variant "basic"Aliases basic / default / classic / standardReturns Chart

Bullet de Tufte classique : piste + zone qualitative + barre de valeur + tick de cible.

Preview
Variant "stacked"Aliases stacked / stacked_ranges / zones / qualitativeReturns Chart

Trois bandes qualitatives graduees (faible / correct / bon) derriere la barre de valeur.

Preview
Variant "thermo"Aliases thermo / thermometer / vertical / columnReturns Chart

Style thermometre vertical avec bulbe - tres parlant pour des KPIs alignes.

Preview
Variant "segmented"Aliases segmented / traffic / rag / zones_colorReturns Chart

Piste segmentee feu tricolore (rouge / orange / vert) pour tableaux de bord.

Preview
Variant "minimal"Aliases minimal / sparkline / clean / nakedReturns Chart

Barre pillule fine type sparkline avec uniquement le tick cible - indicateur inline epure.

Preview
Variant "dot"Aliases dot / point / marker / pipReturns Chart

Un seul point sur la piste au lieu d une barre - variante dot-plot du bullet.

Preview
Variant "progress"Aliases progress / pill / bar / percentReturns Chart

Barre de progression pillule en degrade avec pourcentage centre.

Preview
Variant "compare"Aliases compare / vs / ghost / priorReturns Chart

Ajoute une barre fantome (par ex. periode precedente via comparisons) derriere la valeur courante.

Preview

Gauge - Single-Value Arc Indicator

Signature

sp.gauge(title, *, value, min_val=0.0, max_val=100.0, label="", variant="basic", comparison=0.0, **kwargs) -> Chart

Description

sp.gauge() is the unified entry point for the gauge family. A gauge maps a single scalar to a colored arc with optional thresholds - perfect for status / health / utilization KPIs. The variant keyword switches the geometry (half, three-quarter, full ring), the embellishments (needle, ticks, glow) and the layering (single arc vs. concentric arcs for value-vs-target).

Variants

Parameters

Returns

Chart - object with .html property and .show() method.


Variant "basic"Aliases basic / default / half / classicReturns Chart

Half-circle gauge with needle and color thresholds - the speedometer everyone knows.

Preview
Variant "radial"Aliases radial / donut / ring / fullReturns Chart

Full-circle donut progress arc - elegant ring KPI for dashboards.

Preview
Variant "arc270"Aliases arc270 / three_quarter / arc / wideReturns Chart

270-degree arc - more arc length for finer reading than a half-circle.

Preview
Variant "sleek"Aliases sleek / minimal / clean / flatReturns Chart

No needle, no ticks - oversized value text on a clean colored arc.

Preview
Variant "tick"Aliases tick / tickmarks / scaled / rulerReturns Chart

Half-arc with ruler tick marks every 5% and major labels every 25%.

Preview
Variant "segmented"Aliases segmented / battery / signal / chunkedReturns Chart

Battery / signal-bar style with discrete chunks lighting up by threshold.

Preview
Variant "glow"Aliases glow / neon / halo / luminousReturns Chart

Neon glow effect on the active arc - dramatic dark dashboard look.

Preview
Variant "concentric"Aliases concentric / rings / target / dualReturns Chart

Two concentric arcs: outer = current, inner = comparison or target.

Preview

Signature

sp.gauge(title, *, value, min_val=0.0, max_val=100.0, label="", variant="basic", comparison=0.0, **kwargs) -> Chart

Description

sp.gauge() est le point d entree unique pour la famille jauge. Une jauge associe un scalaire unique a un arc colore avec des seuils optionnels - parfait pour des KPIs de statut / sante / utilisation. Le mot-cle variant change la geometrie (demi, trois-quart, anneau complet), les ornements (aiguille, ticks, glow) et la composition (arc simple ou arcs concentriques pour valeur-vs-cible).

Variantes

Paramètres

Retour

Chart - objet avec propriete .html et methode .show().


Variant "basic"Aliases basic / default / half / classicReturns Chart

Jauge demi-cercle avec aiguille et seuils colores - le compteur que tout le monde connait.

Preview
Variant "radial"Aliases radial / donut / ring / fullReturns Chart

Arc de progression circulaire complet - KPI elegant en anneau pour tableaux de bord.

Preview
Variant "arc270"Aliases arc270 / three_quarter / arc / wideReturns Chart

Arc de 270 degres - plus de longueur pour une lecture plus fine qu un demi-cercle.

Preview
Variant "sleek"Aliases sleek / minimal / clean / flatReturns Chart

Sans aiguille ni ticks - valeur en grand sur un arc colore epure.

Preview
Variant "tick"Aliases tick / tickmarks / scaled / rulerReturns Chart

Demi-arc avec graduations regle tous les 5% et labels majeurs tous les 25%.

Preview
Variant "segmented"Aliases segmented / battery / signal / chunkedReturns Chart

Style batterie / barre de reseau avec segments discrets s allumant par seuil.

Preview
Variant "glow"Aliases glow / neon / halo / luminousReturns Chart

Effet neon sur l arc actif - look dashboard sombre tres marquant.

Preview
Variant "concentric"Aliases concentric / rings / target / dualReturns Chart

Deux arcs concentriques : externe = courant, interne = comparaison ou cible.

Preview

Lollipop - Categorical Value Sticks

Signature

sp.lollipop(title, labels, values, *, variant="basic", color_groups=None, **kwargs) -> Chart

Description

sp.lollipop() is the unified entry point for the lollipop family. Each item becomes a thin stick capped by a dot - lighter ink than a bar chart for the same ranking, and the family includes circular, diverging and grouped editorial layouts (the Office variant reproduces the season-rating panel pattern). To spotlight a single point on any variant, chain the generic .highlight(index) method instead of picking a dedicated variant for it.

Variants

Parameters

Returns

Chart - object with .html property and .show() method.


Variant "basic"Aliases basic / default / classic / verticalReturns Chart

Vertical sticks topped with dots - the canonical lollipop for ranked categorical values.

Preview
Variant "cleveland"Aliases cleveland / horizontal / h / rowReturns Chart

Horizontal Cleveland dot plot - long labels read naturally and dots align cleanly along value axis.

Preview
Variant "diverging"Aliases diverging / div / signed / deltaReturns Chart

Sticks pivot around the mean: green points sit above, red points below - perfect for deviation analysis.

Preview
Variant "circular"Aliases circular / polar / radial / roundReturns Chart

Polar layout where each category is an angular spoke - eye-catching for small alphabets and dashboard tiles.

Preview
Variant "office"Aliases office / grouped / season / panelReturns Chart

Group-aware lollipops with per-group mean line and color band - inspired by The Office IMDb season chart.

Preview
Variant "conditional_color"Aliases conditional_color / conditional / threshold_colorReturns Chart

Horizontal sticks pivoting on zero, colored by sign alone (orange ≥ 0, sky blue < 0) - the seaborn-gallery "lollipop with conditional color" recipe.

Preview
Variant "trend"Aliases trend / colormap / arrow / annotatedReturns Chart

Sticks colored by a continuous diverging colormap (magnitude from zero), a smoothed moving-average trend line, and an arrow annotation on the most extreme point - matching the "lollipop with colormap and arrow" gallery recipe.

Preview

Signature

sp.lollipop(title, labels, values, *, variant="basic", color_groups=None, **kwargs) -> Chart

Description

sp.lollipop() est le point d entree unique pour la famille lollipop. Chaque item devient un baton fin termine par un point - moins d encre qu un bar chart pour le meme classement, et la famille couvre des layouts circulaires, divergents et editoriaux groupes (la variante Office reproduit le motif des saisons IMDb de The Office). Pour mettre en avant un seul point sur n'importe quelle variante, chainez la methode generique .highlight(index) plutot que de choisir une variante dediee.

Variantes

Paramètres

Retour

Chart - objet avec propriete .html et methode .show().


Variant "basic"Aliases basic / default / classic / verticalReturns Chart

Batons verticaux surmontes de points - le lollipop canonique pour valeurs categorielles classees.

Preview
Variant "cleveland"Aliases cleveland / horizontal / h / rowReturns Chart

Cleveland dot plot horizontal - les longs libelles se lisent naturellement, les points s alignent sur l axe des valeurs.

Preview
Variant "diverging"Aliases diverging / div / signed / deltaReturns Chart

Batons pivotent autour de la moyenne: vert au-dessus, rouge en-dessous - parfait pour les ecarts.

Preview
Variant "circular"Aliases circular / polar / radial / roundReturns Chart

Disposition polaire ou chaque categorie est un rayon - tres lisible pour petits jeux et dashboards.

Preview
Variant "office"Aliases office / grouped / season / panelReturns Chart

Lollipops groupes avec moyenne par groupe et bande de couleur - inspire du chart IMDb de The Office.

Preview
Variant "conditional_color"Aliases conditional_color / conditional / threshold_colorReturns Chart

Batons horizontaux pivotant sur zero, colores selon le seul signe (orange ≥ 0, bleu ciel < 0) - la recette "lollipop with conditional color" de la galerie seaborn.

Preview
Variant "trend"Aliases trend / colormap / arrow / annotatedReturns Chart

Batons colores par un degrade divergent continu (magnitude depuis zero), une courbe de tendance lissee, et une fleche d'annotation sur le point le plus extreme - la recette "lollipop with colormap and arrow".

Preview

Parallel Coordinates - Multivariate Profile Lines

Signature

sp.build_parallel(title, axes, series, *, variant="basic", **kwargs) -> Chart

Description

sp.build_parallel() renders a parallel-coordinates chart - one vertical axis per dimension, one polyline per row. Six variants cover the classical use cases: straight lines, smooth Bezier curves, categorical coloring, single-row highlight, density-blended overlay, and gradient coloring driven by any axis. Perfect for high-dimensional EDA, profile comparison, and class separability inspection.

Variants

Parameters

Returns

Chart - object with .html property and .show() method.


Variant "basic"Aliases basic / default / classic / linesReturns Chart

Straight polylines through every axis - the textbook parallel-coordinates chart.

Preview
Variant "smooth"Aliases smooth / curved / bezier / splineReturns Chart

Bezier-smoothed lines reduce visual clutter for dense datasets.

Preview
Variant "categorical"Aliases categorical / category / groups / coloredReturns Chart

One color per category - perfect for comparing classes side by side.

Preview
Variant "highlight"Aliases highlight / spotlight / focus / dimReturns Chart

Spotlights one series and dims the others - great for storytelling.

Preview
Variant "density"Aliases density / fade / translucent / alphaReturns Chart

Translucent lines reveal density bands inside thousands of profiles.

Preview
Variant "arc"Aliases arc / bezier_color / smooth_color / colored_bezierReturns Chart

Smooth cubic bezier curves with per-series gradient coloring. Reduces visual clutter compared to straight lines while preserving individual series identity.

Preview
Variant "ribbon"Aliases ribbon / flow / band / filled_bezierReturns Chart

Filled bezier bands between adjacent axes. Each series is rendered as a translucent ribbon + thin solid stroke, creating a flowing Sankey-lite effect.

Preview

Signature

sp.build_parallel(title, axes, series, *, variant="basic", **kwargs) -> Chart

Description

sp.build_parallel() rend un graphique parallel-coordinates - un axe vertical par dimension, une polyligne par ligne. Six variantes couvrent les cas classiques : lignes droites, courbes Bezier, couleur par categorie, mise en avant d une ligne, overlay de densite, et degrade pilote par un axe. Ideal pour l EDA haute-dimension, la comparaison de profils, et l inspection de separabilite de classes.

Variantes

Paramètres

Retour

Chart - objet avec propriete .html et methode .show().

Variant "basic"Aliases basic / default / classic / linesReturns Chart

Polylignes droites sur tous les axes - le parallel-coordinates canonique.

Preview
Variant "smooth"Aliases smooth / curved / bezier / splineReturns Chart

Lignes Bezier qui reduisent l encombrement visuel sur grands jeux.

Preview
Variant "categorical"Aliases categorical / category / groups / coloredReturns Chart

Une couleur par categorie - parfait pour comparer des classes.

Preview
Variant "highlight"Aliases highlight / spotlight / focus / dimReturns Chart

Met en avant une serie et estompe les autres - ideal pour storytelling.

Preview
Variant "density"Aliases density / fade / translucent / alphaReturns Chart

Lignes translucides revelent les bandes de densite sur des milliers de profils.

Preview
Variante "arc"Alias arc / bezier_color / smooth_color / colored_bezierRetourne Chart

Courbes de Bezier cubiques avec degrade de couleur par serie. Reduit l encombrement visuel par rapport aux lignes droites tout en preservant l identite de chaque serie.

Apercu
Variante "ribbon"Alias ribbon / flow / band / filled_bezierRetourne Chart

Bandes de Bezier remplies entre les axes adjacents. Chaque serie est rendue comme un ruban translucide + trait fin, creant un effet de flux style Sankey simplifie.

Apercu

Word Cloud - Six Rendering Architectures

Signature

sp.build_wordcloud(title, words, frequencies, *, variant="basic", shape="rect", **kwargs) -> Chart

Description

sp.build_wordcloud() packs weighted tokens into six rendering architectures. Basic is the canonical spiral packer driven by a parametric shape= mask (rect, circle, heart, bird, glasses, diamond, star). Bubble gives each word its own color-filled disc sized by frequency - a packed-bubble layout. Context is an InfraNodus-style text-network cloud: words positioned by a force-directed layout driven by co-occurrence edges so semantically close words cluster spatially, colored by community. Image accepts any binary pixel mask (logo, icon, photo). LabelMap draws a datamapplot-style clustered scatter with leader-line labels. Network renders a keyword co-occurrence graph with bezier-curved edges.

Shapes (for variant basic)

The basic variant accepts a shape= argument that selects the silhouette mask:

ShapeAliasesDescription
"rect"rect / rectangle / box / defaultRectangular Archimedean spiral - the textbook word cloud.
"circle"circle / round / disk / ballWords packed inside a perfect disc.
"heart"heart / love / valentineCardioid heart silhouette.
"bird"bird / twitter / tweet / iconComposite-disk stylised bird silhouette.
"glasses"glasses / sunglasses / shades / specsSunglasses silhouette (two ellipses + bridge).
"diamond"diamond / rhombus / lozengeRotated square / rhombus silhouette.
"star"star / starburst / 5-point5-pointed star silhouette.

Variants

Parameters

Returns

Chart - object with .html property and .show() method.


Variant "basic"Aliases basic / default / spiral / rect / shape / shapedReturns Chart

Spiral packing inside a parametric shape mask. Pick the silhouette via the `shape=` argument (rect, circle, heart, bird, glasses, diamond, star).

Preview
Variant "bubble"Aliases bubble / bubbles / packed / circles / packing / packReturns Chart

Each word gets a colored disc sized by frequency - a packed-bubble word cloud. Words float in labeled circles, no overlap.

Preview
Variant "context"Aliases context / semantic / infranodus / text_network / textnetwork / force / force_directedReturns Chart

Text-network word cloud (InfraNodus style): words positioned by force-directed layout based on co-occurrence edges, colored by semantic cluster - semantically close words appear spatially close.

Preview
Variant "image"Aliases image / img / mask / picture / photo / silhouetteReturns Chart

Words flow inside a custom binary image mask - upload any silhouette (logo, icon, photo) and the cloud takes its shape.

Preview
Variant "labelmap"Aliases labelmap / label_map / datamap / datamapplot / topic_map / scatter_labelsReturns Chart

Datamapplot-style topic map - clustered scatter of points colored per category, with cluster labels positioned via leader lines.

Preview
Variant "network"Aliases network / graph / keywords / co_occurrence / cooccurrence / knowledge_graphReturns Chart

Keyword co-occurrence graph - golden-angle node layout, bezier-curved edges, frequency-sized circles. Editorial style of academic keyword maps.

Preview
Variant "neuron"Aliases neuron / neural / brain / synapse / network_glow / nodesReturns Chart

Neural-network word cloud on a dark background. Words become glowing nodes; faint connecting edges link nearest neighbors, evoking a synaptic graph.

Preview
Variant "cosmos"Aliases cosmos / stars / galaxy / nebula / constellation / space / phyllotaxisReturns Chart

Words placed on a phyllotaxis (sunflower-seed) spiral on a starfield background, largest/most frequent words nearest the center — a constellation-like layout instead of a packed rectangle.

Preview

Signature

sp.build_wordcloud(title, words, frequencies, *, variant="basic", shape="rect", **kwargs) -> Chart

Description

sp.build_wordcloud() propose six architectures de rendu. Basic est le packer spirale canonique pilote par un masque shape= (rect, circle, heart, bird, glasses, diamond, star). Bubble donne a chaque mot un disque colore dimensionne par frequence - un layout bubble-packed. Context est un nuage texte-reseau style InfraNodus : mots positionnes par layout force-dirige base sur les aretes de co-occurrence, colores par communaute. Image accepte n importe quel masque binaire de pixels. LabelMap dessine un scatter clusterise style datamapplot avec etiquettes en lignes de rappel. Network rend un graphe de co-occurrence de mots-cles avec aretes bezier.

Formes (pour la variante `basic`)

La variante basic accepte un argument shape= :

FormeAliasDescription
"rect"rect / rectangle / box / defaultRectangular Archimedean spiral - the textbook word cloud.
"circle"circle / round / disk / ballWords packed inside a perfect disc.
"heart"heart / love / valentineCardioid heart silhouette.
"bird"bird / twitter / tweet / iconComposite-disk stylised bird silhouette.
"glasses"glasses / sunglasses / shades / specsSunglasses silhouette (two ellipses + bridge).
"diamond"diamond / rhombus / lozengeRotated square / rhombus silhouette.
"star"star / starburst / 5-point5-pointed star silhouette.

Variantes

Paramètres

Retour

Chart - objet avec propriete .html et methode .show().

Variant "basic"Aliases basic / default / spiral / rect / shape / shapedReturns Chart

Packing en spirale dans un masque parametrique. Choisissez la silhouette via l argument `shape=` (rect, circle, heart, bird, glasses, diamond, star).

Preview
Variant "bubble"Aliases bubble / bubbles / packed / circles / packing / packReturns Chart

Chaque mot obtient un disque colore dimensionne par frequence - un nuage de bulles pack. Les mots flottent dans des cercles etiquetes, sans chevauchement.

Preview
Variant "context"Aliases context / semantic / infranodus / text_network / textnetwork / force / force_directedReturns Chart

Nuage de mots texte-reseau (style InfraNodus) : mots positionnes par layout force-dirige base sur les aretes de co-occurrence, colores par cluster semantique - les mots proches semantiquement sont proches spatialement.

Preview
Variant "image"Aliases image / img / mask / picture / photo / silhouetteReturns Chart

Mots a l interieur d un masque binaire personnalise - uploadez n importe quelle silhouette et le nuage en prend la forme.

Preview
Variant "labelmap"Aliases labelmap / label_map / datamap / datamapplot / topic_map / scatter_labelsReturns Chart

Carte thematique style datamapplot - scatter de points clusterises colores par categorie, avec etiquettes de cluster positionnees via lignes de rappel.

Preview
Variant "network"Aliases network / graph / keywords / co_occurrence / cooccurrence / knowledge_graphReturns Chart

Graphe de co-occurrence de mots-cles - layout en angle d or, aretes courbes bezier, cercles dimensionnes par frequence. Style editorial des cartes de mots-cles academiques.

Preview
Variante "neuron"Alias neuron / neural / brain / synapse / network_glow / nodesRetourne Chart

Nuage de mots style reseau de neurones sur fond sombre. Les mots deviennent des noeuds lumineux relies par des aretes fines evoquant un graphe synaptique.

Apercu
Variante "cosmos"Alias cosmos / stars / galaxy / nebula / constellation / space / phyllotaxisRetourne Chart

Mots places sur une spirale de phyllotaxie (graines de tournesol) sur fond etoile, les mots les plus frequents pres du centre - une disposition en constellation plutot qu'un rectangle compact.

Apercu

Sankey Diagram

Signature

sp.sankey(title, labels, edges_i, edges_j, edges_w, *, variant="basic", **kwargs) -> Chart

Aliases: sp.sankey, sp.sankeys, sp.sankey_chart, sp.sankey_diagram, sp.flow_chart

Description

Sankey diagrams visualize flows between nodes. Node widths and link widths are proportional to flow volumes. Edges are defined by source indices (edges_i), target indices (edges_j), and weights (edges_w). Nodes are laid out in columns by BFS depth.

Variants

Data

labels (list[str]) — Node names. edges_i (list[int]) — Source node indices. edges_j (list[int]) — Target node indices. edges_w (list[float]) — Flow weights. width / height (int) — Chart dimensions.

Parameters

Themes

Returns

Chart — object with .html property and .show() method.

Standard bezier ribbon links

Variant "basic"Aliases basic / default / classicReturns Chart
Preview

Increased node spacing

Variant "gapped"Aliases gapped / spaced / separatedReturns Chart
Preview

Wider nodes and ribbons

Variant "ribbon"Aliases ribbon / wide / thickReturns Chart
Preview

Thin outline style

Variant "minimal"Aliases minimal / thin / outlineReturns Chart
Preview

Reorders nodes within each depth column by descending total throughput, so the dominant flows cluster together instead of sitting in input order — makes it easy to spot which nodes carry the most volume.

Variant "sorted"Aliases sorted / reordered / by_flow / ranked
Preview

Chord Diagram

Signature

sp.chord(title, labels, matrix, *, variant="basic", **kwargs) -> Chart

Aliases: sp.chord, sp.chord_chart, sp.chord_diagram

Description

Chord diagrams show relationships between entities using arcs and ribbons around a circle. The matrix is an N×N flow matrix where matrix[i][j] is the flow from node i to node j.

Variants

Data

labels (list[str]) — Node names. matrix (list[list[float]]) — N×N flow matrix. width / height (int) — Chart dimensions (default 700×700).

Parameters

Themes

Returns

Chart — object with .html property and .show() method.

Standard filled ribbons

Variant "basic"Aliases basic / default / classic
Preview

Wider ribbon links

Variant "ribbon"Aliases ribbon / wide
Preview

Arc-only (no filled ribbons)

Variant "arc"Aliases arc / outline
Preview

Single-color monochrome

Variant "mono"Aliases mono / single
Preview

Draws a small arrowhead on each ribbon pointing toward whichever side receives more — reads the matrix's row/column asymmetry directly off the diagram instead of just the ribbon's natural taper.

Variant "directed"Aliases directed / asymmetric / flow_direction / arrows
Preview

Circle Packing

Signature

sp.circle_pack(title, labels, parents, values, *, variant="basic", **kwargs) -> Chart

Aliases: sp.circle_pack, sp.circle_packing, sp.pack, sp.bubble_pack

Description

Circle packing represents hierarchical data as nested circles, where the area of each circle is proportional to its value. Parent–child relationships are defined by the parents list (empty string = root node).

Variants

Data

labels (list[str]) — Node names. parents (list[str]) — Parent name for each node ("" = root). values (list[float]) — Size of each leaf node. width / height (int) — Chart dimensions.

Parameters

Themes

Returns

Chart — object with .html property and .show() method.

Filled nested circles with depth-based opacity

Variant "basic"Aliases basic / default / nested
Preview

Single-level bubble layout (no nesting)

Variant "flat"Aliases flat / single
Preview

Stroke-only circles

Variant "outlined"Aliases outlined / stroke / border
Preview

Runs a real greedy circle-packing layout: each circle is placed tangent to the best pair of already-placed circles (falling back to a spiral search when no tangent placement fits), producing a genuinely nested, non-overlapping bubble cluster instead of the grid-like flat layout.

Variant "bubble"Aliases bubble / packed
Preview

Fills only the leaf circles with color and shrinks every container circle to a faint dashed outline — declutters the hierarchy chrome so attention goes straight to the actual data points instead of the grouping structure.

Variant "leaf_focus"Aliases leaf_focus / leaves / leaves_only / focus
Preview

Arc Diagram

Signature

sp.arc_diagram(title, labels, edges_i, edges_j, edges_w, *, variant="basic", **kwargs) -> Chart

Aliases: sp.arc_diagram, sp.arc_chart, sp.arc_plot, sp.arc_graph, sp.linear_network

Description

Arc diagrams place nodes on a horizontal axis and draw quadratic bezier arcs above (and optionally below) the axis to represent connections. They are particularly effective for showing sequential or ordered relationships.

Variants

Data

labels (list[str]) — Node names. edges_i (list[int]) — Source node indices. edges_j (list[int]) — Target node indices. edges_w (list[float]) — Edge weights. width / height (int) — Chart dimensions.

Parameters

Themes

Returns

Chart — object with .html property and .show() method.

Arcs above the axis

Variant "basic"Aliases basic / default / classic
Preview

Alternating arcs above and below

Variant "bilateral"Aliases bilateral / both / dual
Preview

Stroke width proportional to edge weight

Variant "weighted"Aliases weighted / width / value
Preview

Thin, low-opacity arcs with small strokeless nodes — strips away the visual weight so overlapping arcs stay legible in dense diagrams.

Variant "minimal"Aliases minimal / thin / clean
Preview

Draws a small arrowhead where each arc lands on its target node — turns the diagram into a proper directed graph, e.g. for dependency or citation edges where "which way" matters as much as "how much".

Variant "directed"Aliases directed / arrows / flow / dependency
Preview

Dendrogram

Signature

sp.dendrogram(title, labels, *, matrix=None, parents=None, clusters=3, variant="vertical", **kwargs) -> Chart

Aliases: sp.dendrogram, sp.dendro, sp.tree, sp.tree_diagram, sp.hierarchy, sp.hierarchical

Description

Dendrograms display hierarchical tree structures using right-angle elbow connectors (vertical/horizontal) or smooth bezier curves (elegant) or a radial circular layout. Pass matrix -- one row of numeric coordinates per label -- for a genuine average-linkage agglomerative clustering with real merge heights (matching hclust/scipy), including automatic coloring of the top clusters groups with the trunk above the cut shown in neutral gray. Without matrix, parents describes a plain hand-specified hierarchy (each entry names its parent's label, empty string for a root) with no real distance semantics.

Variants

Data

labels (list[str]) — Node names. parents (list[str]) — Parent name per node ("" = root). width / height (int) — Chart dimensions.

Parameters

Themes

Returns

Chart — object with .html property and .show() method.

Root at top, leaves at bottom (elbow connectors)

Variant "vertical"Aliases vertical / top / default / classic
Preview

Root at left, leaves at right

Variant "horizontal"Aliases horizontal / left / h
Preview

Circular radial tree layout

Variant "radial"Aliases radial / circular / polar
Preview

Tighter spacing, smaller font

Variant "compact"Aliases compact / dense / tight
Preview

Smooth cubic bezier curves

Variant "elegant"Aliases elegant / smooth / rounded
Preview

Connects parent to child with a single straight diagonal line — a third connector style alongside the right-angle elbows (vertical/horizontal) and smooth beziers (elegant).

Variant "triangular"Aliases triangular / diagonal / straight / angular
Preview

Venn Diagram

Signature

sp.venn(title, labels, values, *, variant="basic", **kwargs) -> Chart

Aliases: sp.venn, sp.venn_diagram, sp.euler, sp.set_diagram, sp.overlap

Description

Venn diagrams show set relationships using overlapping circles. Supply one value per set for circle sizes. The "euler" variant scales circle radii proportionally to the first N values.

Variants

Data

labels (list[str]) — Set names. values (list[float]) — Set sizes (first N entries used for Euler radii). width / height (int) — Chart dimensions.

Parameters

Themes

Returns

Chart — object with .html property and .show() method.

Semi-transparent overlapping circles

Variant "basic"Aliases basic / default / classic
Preview

Proportional circle areas (Euler diagram)

Variant "euler"Aliases euler / proportional / area
Preview

Fully opaque circles

Variant "filled"Aliases filled / solid / opaque
Preview

Forces every circle into its stroke-only outline form regardless of the configured fill opacity, for a clean contour-only read of the set overlaps.

Variant "minimal"Aliases minimal / outline / thin
Preview

Masks each circle down to the region that belongs to it alone and renders that region at full color, while shared/overlapping areas fade into the background — makes it obvious what's unique to each set versus what's shared.

Variant "exclusive"Aliases exclusive / unique / distinct
Preview

Correlogram

Signature

sp.correlogram(title, labels, matrix, *, variant="circle", **kwargs) -> Chart

Aliases: sp.correlogram, sp.corrplot, sp.correlation_matrix, sp.corr, sp.correlation_map

Description

A correlogram visualizes a correlation matrix as a grid. Each cell encodes the Pearson correlation coefficient (–1 to +1) using color (red = positive, blue = negative) and either circle area, square fill, or text. matrix is a nested N×N list — one inner list per row.

Variants

Data

labels (list[str]) — Variable names (length N). matrix (list[list[float]]) — N×N correlation matrix, one row per inner list. width / height (int) — Chart dimensions.

Every variant is really just a preset of three lower-level params you can mix freely on the base circle variant instead of picking a named one: cell_shape ("circle" | "square" | "ellipse" | "pie" | "number") controls how a single cell is drawn, cell_shape2 sets a second shape for the lower triangle when layout="mixed", and layout ("full" | "upper" | "lower" | "mixed") controls which half of the matrix gets filled — e.g. sp.correlogram(labels=..., matrix=..., cell_shape="ellipse", layout="upper").

Parameters

Themes

Returns

Chart — object with .html property and .show() method.

Variant "circle"Aliases circle / default / classic
Preview

Filled squares (standard heatmap)

Variant "heatmap"Aliases heatmap / heat / square
Preview

Numeric correlation values only

Variant "text"Aliases text / number / value
Preview

Circles + text overlay

Variant "mixed"Aliases mixed / combo / both
Preview

Each cell is an ellipse tilted "/" for positive correlation, "\" for negative, flattening toward a line as |r| approaches 1 and toward a circle as it approaches 0.

Variant "ellipse"Aliases ellipse / oval
Preview

Upper triangle as pie wedges (wedge angle = |r|, color = sign), lower triangle as flat colored squares, diagonal left blank - the classic mixed correlogram layout, unsorted.

Variant "pie_square"Aliases pie_square / pie / mixed_pie
Preview

Upper-triangle-only circles (lower triangle and diagonal left blank) with a color/value legend bar alongside instead of numeric labels on the cells.

Variant "circle_legend"Aliases circle_legend / legend / scale
Preview

Hive Plot

Signature

sp.hive(title, axes, labels, categories, values, edges_i, edges_j, edges_w, *, variant="basic", **kwargs) -> Chart

Aliases: sp.hive, sp.hive_plot, sp.hive_chart, sp.hive_graph, sp.radial_network

Description

Hive plots organize network nodes on radial axes by category. Each axis corresponds to one node group (axes). Node position along the axis is determined by values (0–1). Edges between nodes are drawn as straight or curved lines through the center.

Variants

Data

axes (list[str]) — Axis (group) names. labels (list[str]) — Node names. categories (list[str]) — Group assignment per node. values (list[float]) — Node position along axis (0–1). edges_i (list[int]) — Source node indices. edges_j (list[int]) — Target node indices. edges_w (list[float]) — Edge weights. width / height (int) — Chart dimensions.

Parameters

Themes

Returns

Chart — object with .html property and .show() method.

Straight edge lines

Variant "basic"Aliases basic / default / classic
Preview

Cubic bezier curves through center

Variant "curved"Aliases curved / smooth / bezier
Preview

Stroke width proportional to edge weight

Variant "weighted"Aliases weighted / width / value
Preview

Straight (uncurved), thin, low-opacity edges with small strokeless nodes — a decluttered reading of dense hive plots that trades the curved-edge chrome for raw connectivity.

Variant "minimal"Aliases minimal / thin / clean
Preview

Draws a small arrowhead where each edge lands on its target node — hive plots are frequently used for directed graphs (network traffic, citations), and this makes the direction readable at a glance instead of implied.

Variant "directed"Aliases directed / arrows / flow / dependency
Preview

Pulse Chart

Signature

sp.pulse(title, labels, values, *, variant="radial", **kwargs) -> Chart

Aliases: sp.pulse, sp.pulse_chart, sp.radial_bar, sp.clock_chart, sp.rhythm, sp.radial_rhythm

Description

The Pulse chart is an original SeraPlot chart type that maps temporal or cyclic data onto a radial clock-face layout. Each slice is a time period (hour, day, month…) and the bar height encodes the intensity value. The "wave" variant connects data points into a smooth radial polygon.

Variants

Data

labels (list[str]) — Period labels (e.g. days, hours). values (list[float]) — Intensity per period (any scale). width / height (int) — Chart dimensions (default 560×560).

Parameters

Themes

Returns

Chart — object with .html property and .show() method.

Clock-face arc bars per period

Variant "radial"Aliases radial / default / classic
Preview

Smooth closed radial polygon

Variant "wave"Aliases wave / sine / smooth
Preview

Radial scatter with connecting spokes

Variant "dot"Aliases dot / scatter / bubble
Preview

Extends every slice into a continuous, gap-free ring at full opacity with no stroke — reads as a solid dial rather than a set of separated arc bars.

Variant "filled"Aliases filled / area / solid
Preview

Stroke-only arc slices with no fill — the same radial clock-face layout, stripped down to outlines for a lighter, print-friendly look.

Variant "outlined"Aliases outlined / outline / stroke / clean
Preview

Orbita Chart

Signature

sp.orbita(title, series_names, labels, matrix, *, variant="classic", **kwargs) -> Chart

Aliases: sp.orbita, sp.orbit, sp.orbit_chart, sp.orbital, sp.multi_orbit, sp.concentric

Description

The Orbita chart is an original SeraPlot chart type that places multiple series on concentric ring orbits. Each series (orbit) maps categories to angular positions. The result is a planetary-system-style comparison across series and categories simultaneously, ideal for multi-period cross-category analysis.

matrix is a nested S×C list — one inner list per series (S = number of series, C = number of categories).

Variants

Data

series_names (list[str]) — One name per orbit (e.g. years). labels (list[str]) — Category names (angular positions). matrix (list[list[float]]) — S×C value matrix, one row per series. width / height (int) — Chart dimensions (default 580×580).

Parameters

Themes

Returns

Chart — object with .html property and .show() method.

Fixed-size dots on orbits

Variant "classic"Aliases classic / default / basic
Preview

Dot radius proportional to value

Variant "bubble"Aliases bubble / sized / area
Preview

Closed polygon trail connecting series dots

Variant "trail"Aliases trail / line / connected
Preview

Gaussian blur glow effect on dots

Variant "glow"Aliases glow / neon / light
Preview

Drops the dashed orbit rings and radial spoke lines, and shrinks each point to a small strokeless dot — a decluttered read focused purely on relative position.

Variant "minimal"Aliases minimal / thin / clean
Preview

Colors each point green or red depending on whether its value rose or fell versus the same category on the previous orbit — turns concentric orbits (e.g. one per year) into a trend view instead of a static snapshot.

Variant "delta"Aliases delta / change / trend / momentum
Preview

Event Plot — Discrete Event Ticks per Row

Signature

sp.eventplot(title, x_values, categories, *, variant="basic", **kwargs) -> Chart

Aliases: sp.eventplot, sp.event_plot, sp.raster_plot, sp.spike_plot, sp.build_eventplot

Description

sp.eventplot() draws a short vertical tick for every discrete event, one row per category — the standard chart for point-in-time occurrences without duration (neuron spike trains, log/error timestamps, user session starts). Unlike gantt(), events have no end time. Reuses x_values and the existing categories field on ChartArgs (the same grouping mechanism used by bubble()'s categorical variant) — no new parameter shape, rows are formed automatically from distinct category values in order of first appearance.

Variants

Data

x_values (list[float]) — Event positions. categories (list[str]) — Row assignment per event.

Parameters

Themes

Returns

Chart — object with .html property and .show() method.

Tick marks only, one color per row.

Variant "basic"Aliases basic / default / classic / ticks
Preview

Tick marks plus a smoothed density curve per row, computed with the same native kernel density estimator as [`kde()`](kde.md) (`scott_bw` bandwidth selection, Gaussian kernel) — a rug plot and a KDE in one chart.

Variant "density"Aliases density / kde / smoothed / rug
Preview

Draws a thin line connecting each row's events in chronological order, on top of the usual ticks — traces the sequence/trajectory through time, not just where events landed.

Variant "connected"Aliases connected / sequence / path / trajectory
Preview

Gantt — Project Timeline Chart

Signature

sp.gantt(title, labels, start, end, *, variant="basic", categories=None, color_values=None, **kwargs) -> Chart

Aliases: sp.gantt, sp.gantt_chart, sp.broken_barh, sp.timeline_chart, sp.project_timeline, sp.build_gantt

Description

sp.gantt() draws one horizontal bar per task spanning from start to end on a shared numeric timeline (day index, epoch, or any consistent unit — no date-typed axis required). Tasks are sorted like every other chart via sort_order, and rows can be grouped by an optional categories list (e.g. team or phase), which colors bars by category with an automatic legend instead of per-row palette rotation. Reuses the labels/start/end/categories fields already on ChartArgs (the same start/end pair used by dumbbell()) — no new parameter shape.

Variants

Data

labels (list[str]) — Task names. start (list[float]) — Task start (numeric timeline unit). end (list[float]) — Task end. categories (list[str]) — Optional group per task; colors bars by group with a legend. color_values (list[float]) — Completion fraction (0–1) per task, used by the "progress" variant.

Parameters

Themes

Returns

Chart — object with .html property and .show() method.

Flat colored bar per task.

Variant "basic"Aliases basic / default / classic / flat
Preview

Outlined bar with an inner fill proportional to `color_values` (0–1 completion fraction) and a `%` label.

Variant "progress"Aliases progress / percent / completion / filled
Preview

Renders zero-duration tasks (`start == end`) as a diamond marker instead of a degenerate bar — the standard way project-planning tools distinguish milestones from work items.

Variant "milestone"Aliases milestone / diamonds / checkpoints / markers
Preview

Hexbin — Hexagonal Density Binning

Signature

sp.hexbin(title, x_values, y_values, *, variant="basic", gridsize=20, colorscale=None, **kwargs) -> Chart

Aliases: sp.hexbin, sp.hexbins, sp.hexbin_chart, sp.hexagonal_binning, sp.build_hexbin

Description

sp.hexbin() bins a 2D scatter cloud into a regular hexagonal grid and colors each hexagon by point density (count), the standard alternative to a scatter plot once point overlap makes individual markers unreadable. Points are assigned to hexagon cells directly in pixel space using the true nearest-center rule (two candidate offset grids, closest wins), so cells tile without gaps or overlap regardless of the data's aspect ratio. Cell color reuses the same continuous colorscale engine as heatmap() and bubble(variant="gradient") — any of viridis / plasma / inferno / magma / cividis / turbo / rdbu / blues / reds / greens works via colorscale=.

Variants

Data

x_values (list[float]) — X coordinates. y_values (list[float]) — Y coordinates.

Parameters

Themes

Returns

Chart — object with .html property and .show() method.

Filled hexagons only, compact grid, right-side density legend.

Variant "basic"Aliases basic / default / classic / filled
Preview

White cell borders; count printed inside each hexagon once cells are large enough to fit text.

Variant "outlined"Aliases outlined / outline / stroke / labeled
Preview

Hexagons drawn at 72% size with a visible gap between neighbors — a "confetti" look instead of a solid tiled surface.

Variant "spaced"Aliases spaced / gapped / confetti
Preview

Dims every cell except the densest ~15% (full opacity, white outline, count label) — draws the eye straight to the hotspots instead of the full density gradient.

Variant "highlight"Aliases highlight / top / hotspot / peak
Preview

Bins below min_count are skipped entirely (left transparent) instead of drawn faint - a hard threshold rather than a dimmed gradient, matching R's hexbin(mincnt=).

Variant "mincnt"Aliases mincnt / threshold / sparse
Preview

Each cell's count is classed into an order-of-magnitude band (ones/tens/hundreds/thousands/10 thousands), colored and sized by band, with a smaller nested hexagon inside in the previous band's color - matching R hexbin's nested/centroid styles - plus a size+color legend.

Variant "nested"Aliases nested / magnitude / rings / centroids
Preview

Cell color is mapped on log(count + 1) instead of the raw count, matching matplotlib's hexbin(bins="log") — compresses the huge dynamic range that skewed point clouds produce so low-density cells stay visually distinguishable instead of collapsing near zero.

Variant "log_counts"Aliases log_counts / log / log_scale / logarithmic
Preview

Cell color encodes the average of a third variable (values=) inside each bin instead of the point count — the native equivalent of matplotlib's hexbin(C=..., reduce_C_function=numpy.mean), for when the quantity of interest isn't density itself.

Variant "weighted"Aliases weighted / mean / aggregate / reduce_mean
Preview

White dashed cell borders over a full continuous colorscale (defaults to magma) with no plot border — matches matplotlib's hexbin(edgecolor="white", linestyle="dotted", linewidth=1.5) styling exactly.

Variant "dotted"Aliases dotted / dashed / styled / magma
Preview

Adds 1D density strips above and to the right of the hexbin grid — a joint-plot style combination, showing the marginal distribution of each axis alongside the 2D density.

Variant "marginals"Aliases marginals / joint / with_histograms / density_marginals
Preview

Joint — Bivariate Panel + Marginals

Signature

sp.joint(title, x, y, *, variant="hexbin", marginal="histogram", panel_variant="", marginal_variant="", bins=24, colorscale=None, categories=None, **kwargs) -> Chart

Aliases: sp.joint, sp.jointplot, sp.joint_plot, sp.bivariate, sp.build_joint

Description

sp.joint() composes a bivariate main panel with top and right marginal strips — the SeraPlot equivalent of seaborn's jointplot() / JointGrid. variant= (the panel, "inside") and marginal= (the top/right strips, "outside") are independent, fully open choices — not a fixed enum. Each accepts the name of any registered SeraPlot family from services/plot/statistical/chart_registry.rs (currently ~50: hexbin, scatter, kde, histogram, bar, violin, boxplot, heatmap, orbita, splom, … the same inventory facet() dispatches through), and panel_variant= / marginal_variant= forward straight through as that family's own variant=, so hexbin's outlined/spaced/highlight styles, histogram's cumulative, etc. all work exactly as they do standalone.

sp.joint(x, y, variant="hexbin", marginal="kde")
sp.joint(x, y, variant="kde", marginal="histogram")
sp.joint(x, y, variant="scatter", marginal="bar")
sp.joint(x, y, variant="hexbin", panel_variant="outlined", marginal="kde")

Each region — panel, top strip, right strip — is a real, independently-rendered SeraPlot chart embedded in its own frame, calling the exact same native build_* function facet() uses for its cells; nothing is reimplemented. That also means regions are not pixel-aligned to a shared coordinate system the way a hand-tuned single-SVG composition would be — each chart keeps its own axes/padding — an inherent tradeoff for genuine "any family, any slot" freedom. Not every family produces something meaningful in every slot — that limitation belongs to the target family's own data shape, not to joint() itself. As a marginal, a family only ever receives the single axis of values being summarized (plus generic synthetic labels/categories/series/sizes/words so families expecting those shapes still degrade gracefully); families whose own data model is inherently 2D/matrix/hierarchical/paired — candlestick, chord, circle_pack, correlogram, dendrogram, dumbbell, gantt, hive, heatmap, icicle, orbita, parcats, radar, sankey, scatterternary, slope, splom, sunburst — render blank there, the same honest way orbita renders blank as a panel without a hierarchy.

For a true bivariate (2D) density surface — not just kde's own 1D curve — use variant="kde", panel_variant="contour": kde()'s contour variant fits a product-kernel Gaussian KDE jointly over x and y and shades a smooth density surface with the raw points overlaid, matching seaborn's smooth_bivariate_kde / joint_kde examples. Legacy preset names (layered_bivariate, joint_kde, kde_smooth, smooth_bivariate_kde, …) already resolve to exactly this.

The preset names from earlier releases (hexbin_marginal, joint_histogram / histogram2d, layered_bivariate, joint_kde, kde_smooth, multiple_bivariate_kde, marginal_ticks, regression_marginals) still work as variant= values and resolve to a real family under the hood (resolve_legacy_panel() in joint/variant.rs), so existing code keeps working. heat_scatter — seaborn's correlation matrix drawn as sized/colored scatter dots — isn't a joint/marginal plot at all; use heatmap(variant="bubble") directly.

Data

x (list[float]) — X coordinates. y (list[float]) — Y coordinates.

Parameters

Returns

Chart — object with .html property and .show() method.

The raw entry point — variant= is simply the panel family's own name, and any registered family can fill it.

Call sp.joint(x, y, variant="hexbin", marginal="histogram")
Preview

Hexagonal density panel with KDE curve marginals instead of the default histograms.

Call sp.joint(x, y, variant="hexbin", marginal="kde")
Preview

A 1D KDE panel with histogram marginals — mixing families freely, not just bivariate-native ones.

Call sp.joint(x, y, variant="kde", marginal="histogram")
Preview

Scatter panel with bar-chart marginals.

Call sp.joint(x, y, variant="scatter", marginal="bar")
Preview

panel_variant= forwards to the panel family's own variant — here hexbin's outlined cell style, combined with KDE marginals.

Call sp.joint(x, y, variant="hexbin", panel_variant="outlined", marginal="kde")
Preview

The pre-existing layered_bivariate preset name still resolves (to variant="kde", panel_variant="contour" under the hood — a genuine bivariate density surface, not a flat 1D curve) — old code keeps working, and now renders correctly.

Call sp.joint(x, y, variant="layered_bivariate")
Preview

Facet Grid — Small Multiples for Any Chart

Signature

sp.facet(family, *, variant=None, facet_by, title="", cols=3, cell_width=320, cell_height=280, **kwargs) -> Chart

Aliases: sp.facet, sp.facet_grid, sp.facetgrid, sp.small_multiples, sp.build_facet

Description

sp.facet() is not a chart family of its own — it is the framework's generic small-multiples mechanism, the SeraPlot equivalent of seaborn's FacetGrid. It takes the name of any existing 2D chart family (family=), splits every data array in the call by a facet_by group key, and calls that family's own builder once per group, laying the results out in a grid. Every current and future chart family gets faceting for free — there is no per-chart code, no separate variant enum, and no duplicated geometry: services/plot/statistical/facet/mod.rs dispatches straight to the target family's real build_* function (histogram::build_histogram, line::build_line, joint::build_joint, …), so any **kwargs valid for that family (colorscale=, bins=, variant=, …) is simply forwarded through unfiltered.

Only arguments whose array length matches facet_by get split; everything else (scalars like bins=, variant=, colorscale=) is copied to every cell unchanged. cols= sets the grid's column count, cell_width= / cell_height= size each panel.

Currently wired families: area, bar, boxplot, bubble, bullet, candlestick, dumbbell, eventplot, funnel, gantt, gauge, heatmap, hexbin, histogram, icicle, joint, kde, line, lollipop, parallel, pie, radar, ridgeline, scatter, slope, splom, stackplot, sunburst, treemap, violin, waterfall, wordcloud — see facet::dispatch() for the exact match table.

Data

Any array field accepted by the target family= (values, labels, x, y, …), plus facet_by (list[str]) — the group label for each row, same length as the arrays being split.

Recipes

Not every case needs its own SeraPlot demo — some seaborn gallery examples are already one call away from an existing chart page:

  • Multiple ECDFs (overlaid, not facetted) — histogram(variant="cumulative", color_groups=...) or kde(variant="cumulative", categories=...): seaborn overlays several ECDF lines in one panel via category grouping, which is the same color_groups= / categories= convention already used for stacking and multi-series density.
  • Pair grid (KDE diagonal, paired point plots, dot-plot matrix) — splom(variant="density") or splom(variant="basic"): SPLOM is SeraPlot's scatterplot-matrix family and already covers the pairwise-comparison layout these seaborn examples show.
  • Radial facetsfacet(family="bar", facet_by=...): SeraPlot doesn't have a native polar/rose histogram variant yet, so this reproduces the faceting technique with a regular bar chart per facet rather than a pixel-perfect polar match.
  • Facetted time series — same mechanism as the Faceted Lineplot recipe below; swap in a time-ordered labels= array.

One histogram panel per facet_by group — matches seaborn's faceted_histogram example.

Call facet(family="histogram", values=[...], facet_by=[...], cols=2)
Preview

One line panel per group — matches seaborn's faceted_lineplot / timeseries_facets examples (use a time-ordered labels= for the latter).

Call facet(family="line", labels=[...], values=[...], facet_by=[...], cols=3)
Preview

Faceting scales to any number of groups — matches seaborn's many_facets example.

Call facet(family="bar", labels=[...], values=[...], facet_by=[...], cols=3)
Preview

One KDE curve per condition — matches seaborn's multiple_conditional_kde example.

Call facet(family="kde", values=[...], facet_by=[...], cols=3)
Preview

Facets a bivariate joint(variant="histogram2d") panel by a third variable — matches seaborn's three_variable_histogram example, combining the facet mechanism with the [`joint`](joint.md) family's `histogram2d` alias.

Call facet(family="joint", variant="histogram2d", x=[...], y=[...], facet_by=[...], cols=2)
Preview

Icicle — Hierarchical Banded Chart

Signature

sp.icicle(title, labels, parents, values, *, variant="basic", palette=None, **kwargs) -> Chart

Aliases: sp.icicle, sp.icicles, sp.icicle_chart, sp.icicle_family, sp.build_icicle

Description

sp.icicle() renders a hierarchy as stacked bands: each depth level of the tree is one horizontal row, and the width of each node inside its row is proportional to its value. It is a rectangular alternative to sunburst() and shares the exact same input schema (labels / parents / values), so any dataset already used with sunburst() or treemap() works unchanged.

Hierarchy encodinglabels lists every node, parents gives the parent label of each node ("" for a root). Leaf values come from values; internal-node values at 0 are auto-rolled-up from descendants.

Variants

Data

labels (list[str]) — Node labels (one per row). parents (list[str]) — Parent label of each node ("" for roots). values (list[float]) — Leaf values; internal zeros are auto-rolled-up.

Parameters

Themes

Returns

Chart — object with .html property and .show() method.

Root row at the top, depth-based opacity, white separators between bands.

Variant "basic"Aliases basic / default / classic / layers
Preview

Rounded corners with a small gap between every node, both across and between rows.

Variant "gapped"Aliases gapped / spaced / isolated / padded
Preview

Root column on the left, depth grows rightward instead of downward.

Variant "horizontal"Aliases horizontal / h / sideways / left_to_right
Preview

The same hierarchy in polar coordinates instead of cartesian — depth becomes ring radius, horizontal span becomes angular span. The classic icicle/sunburst duality: identical data, identical layout math (`xspan`, `depth`), different coordinate system.

Variant "radial"Aliases radial / sunburst / polar / mandala
Preview

Colors every node by its value rank among its same-depth peers (indigo → red, lowest to highest) instead of by raw share of the grand total — makes cross-branch comparisons at a given level obvious even when one branch is much bigger than another.

Variant "rank"Aliases rank / percentile / peer_rank / standing
Preview

Parallel Categories — Categorical Flow Diagram

Signature

sp.parcats(title, axes, category_series, *, variant="basic", **kwargs) -> Chart

Aliases: sp.parcats, sp.parallel_categories, sp.parcats_chart, sp.parallel_categories_chart, sp.build_parcats

Description

sp.parcats() is the categorical counterpart to parallel(): instead of numeric axes with one polyline per row, each axis holds a set of discrete category values, and ribbons flow between adjacent axes with width proportional to how many rows share that pair of categories — the standard chart for tracing how categorical attributes co-occur across a dataset (e.g. gender → survival → class). Internally it builds a node for every distinct (axis, category) pair and an edge for every consecutive-axis transition, then reuses the exact same layered layout engine and bezier ribbon renderer as sankey() (sankey::common::compute_layout / sankey_link_path) — the two charts share their positioning math, not just their visual family.

Data shapecategory_series is a list of rows, each row a list of category values with one entry per axis (category_series[row][axis]), mirroring exactly the row-major shape already used by parallel(series=...).

Variants

Data

axes (list[str]) — Axis names, left to right. category_series (list[list[str]]) — One row per observation, one category value per axis.

Parameters

Themes

Returns

Chart — object with .html property and .show() method.

Flat semi-transparent ribbons colored by their source node.

Variant "basic"Aliases basic / default / classic / flat
Preview

Dims every ribbon except each node's single heaviest outgoing flow, which is boosted to full opacity with a thin white outline — traces the dominant path through the categories.

Variant "highlight"Aliases highlight / dominant / spotlight / focus_flow
Preview

Scatter Ternary — Three-Component Composition Plot

Signature

sp.scatterternary(title, x_values, y_values, z_values, *, variant="basic", x_label="A", y_label="B", z_label="C", **kwargs) -> Chart

Aliases: sp.scatterternary, sp.scatter_ternary, sp.ternary, sp.ternary_plot, sp.ternary_scatter, sp.build_scatter_ternary

Description

sp.scatterternary() plots three-component compositions (e.g. soil sand/silt/clay, alloy element fractions, poll shares) inside an equilateral triangle — the standard chart whenever three parts sum to a whole. Each point's three values are barycentric weights normalized internally (a+b+c need not equal 1 or 100, only their ratio matters), converted to Cartesian coordinates and rendered with a full gridline mesh (three families of lines at 20/40/60/80%, one parallel to each triangle side). Reuses the exact same x_values/y_values/z_values and x_label/y_label/z_label inputs already used by 3D scatter charts — no new parameter shape introduced.

Variants

Data

x_values (list[float]) — First component (A, top vertex). y_values (list[float]) — Second component (B, right vertex). z_values (list[float]) — Third component (C, left vertex). x_label (str) — Label for the top vertex. y_label (str) — Label for the right vertex. z_label (str) — Label for the left vertex. color_values (list[float]) — Continuous values for the "gradient" variant.

Parameters

Themes

Returns

Chart — object with .html property and .show() method.

Single palette color, semi-transparent markers.

Variant "basic"Aliases basic / default / classic / dots
Preview

Point radius scales with `color_values` (4.5× range between smallest and largest) instead of a fixed `point_size` — a fourth variable encoded as size on top of the three ternary axes.

Variant "bubble"Aliases bubble / sized / weighted / proportional
Preview

Same layout as basic, with each point's label printed beside it — useful once you need to identify specific observations, not just see the overall distribution.

Variant "labeled"Aliases labeled / labelled / annotated / named
Preview

SPLOM — Scatter Plot Matrix

Signature

sp.splom(title, axes, series, *, variant="basic", colorscale=None, **kwargs) -> Chart

Aliases: sp.splom, sp.scatter_matrix, sp.splom_chart, sp.pairplot, sp.scatterplot_matrix, sp.build_splom

Description

sp.splom() lays out every pairwise combination of a set of numeric dimensions as an M×M grid of small scatter plots in a single self-contained chart — the standard first look at a multivariate numeric dataset. It reuses exactly the same row-major data shape as parallel() (axes + series, one row per observation with one value per axis), so any dataset already wired up for parallel coordinates works unchanged. Diagonal cells show the axis name instead of a self-scatter.

Variants

Data

axes (list[str]) — Dimension names. series (list[list[float]]) — One row per observation, one value per dimension.

Parameters

Themes

Returns

Chart — object with .html property and .show() method.

Off-diagonal cells are plain scatter plots in a single palette color.

Variant "basic"Aliases basic / default / classic / dots
Preview

Each off-diagonal cell's background is tinted by the Pearson correlation coefficient between its two dimensions (via the same continuous colorscale engine as [`heatmap()`](heatmap.md)), with points overlaid in a neutral color — a heatmap and a SPLOM in one chart.

Variant "correlation"Aliases correlation / corr / heat / shaded
Preview

Every point drawn at 14% opacity with no stroke — overlapping points accumulate into darker regions, revealing density in datasets too large for solid dots to stay readable.

Variant "density"Aliases density / alpha / overplot / cloud
Preview

Adds a least-squares trend line to every off-diagonal panel — the classic pairplot-with-regression view for spotting linear relationships across every pair of variables at once.

Variant "regression"Aliases regression / trend / fit / lm
Preview

Stackplot — Stacked Area / Streamgraph

Signature

sp.stackplot(title, x_labels, series, *, variant="basic", series_names=None, **kwargs) -> Chart

Aliases: sp.stackplot, sp.stack_plot, sp.stacked_area, sp.build_stackplot

Description

sp.stackplot() draws multiple series as cumulatively stacked areas over a shared x-axis — reuses the exact same x_labels/series/series_names input shape as multiline(), so any dataset already used with multiline() works unchanged. Negative values are clamped to 0 before stacking (a stack has no meaningful negative contribution).

Variants

Data

x_labels (list[str]) — Shared x-axis point labels. series (list[list[float]]) — One list of values per series, same length as x_labels. series_names (list[str]) — Legend label per series.

Parameters

Themes

Returns

Chart — object with .html property and .show() method.

Traditional zero-baseline stacking, each series added on top of the previous one's cumulative total.

Variant "basic"Aliases basic / default / classic / stacked
Preview

Centered ("silhouette") baseline — at every x-point the stack is centered around zero (`baseline = -total/2`) instead of starting at zero, giving the flowing ThemeRiver look.

Variant "streamgraph"Aliases streamgraph / stream / silhouette / themeriver
Preview

100%-stacked — every series is divided by the x-point's total before stacking, so the top of the stack is always 1.0. Shows share of total over time instead of absolute magnitude.

Variant "normalized"Aliases normalized / percent / hundred_percent / share
Preview

Polar-wrapped stacking — each x-point becomes an angle around a circle instead of a position along an axis, and the cumulative bands grow outward as concentric rings from a small central hole. A genuinely different read on the same stacked data: total magnitude becomes an overall silhouette size, and each series' share becomes a colored band thickness at that angle.

Variant "radial"Aliases radial / polar / radar_stack / circular
Preview

Cartesian stacking rendered as smooth, glowing ribbons: quadratic-bezier-smoothed band edges, a top-to-bottom depth gradient per series, and a soft drop-shadow separating each layer — a more atmospheric, editorial look than the sharp-edged basic stack.

Variant "ribbon"Aliases ribbon / glow / smooth / flow
Preview

Plot Web — Force-Directed Bubble Network

Signature

sp.plot_web(title, x_values, y_values, *, variant="scatter", sizes=None, labels=None, groups=None, **kwargs) -> Chart

Aliases: sp.plot_web, sp.web_plot, sp.plotweb, sp.carbon_web, sp.web_chart, sp.flow_web

Description

sp.plot_web() places each data point as a sized bubble node and lets the two positional axes (x_values/y_values) drive layout instead of a fixed cartesian grid — the scatter variant reads them as literal coordinates on a light-trail canvas, the radial variant re-projects them onto concentric rings around a center point. Bubble radius scales between min_r and max_r from the sizes array (or a constant radius if omitted), and groups assigns a categorical color from palette per node.

Variants

Data

x_values (list[float]) — Horizontal position (scatter) or angle-driving value (radial). y_values (list[float]) — Vertical position (scatter) or radius-driving value (radial). sizes (list[float]) — Per-node value driving bubble radius between min_r and max_r. labels (list[str]) — Per-node hover label. groups (list[str]) — Per-node category, colored from palette.

Parameters

Themes

Returns

Chart — object with .html property and .show() method.

Nodes positioned directly from `x_values`/`y_values`, connecting light-trail background.

Variant "scatter"Aliases scatter / web / connected / default / flow
Preview

Nodes re-projected onto concentric rings, angle and radius derived from the same input coordinates.

Variant "radial"Aliases radial / solar / stellar / mandala / spider
Preview

3D Charts

SeraPlot provides 17 three-dimensional chart types rendered with full WebGL acceleration.

ChartFunction
Scatter 3Dscatter3d()
Bar 3Dbar3d()
Line 3Dline3d()
Radar 3Dradar3d()
Lollipop 3Dlollipop3d()
KDE 3Dkde3d()
Ridgeline 3Dridgeline3d()
Bubble 3Dbubble3d()
Pie 3Dpie3d()
Violin 3Dviolin3d()
Heatmap 3Dheatmap3d()
Candlestick 3Dcandlestick3d()
Dumbbell 3Ddumbbell3d()
Funnel 3Dfunnel3d()
Sunburst 3Dsunburst3d()
Stacked Bar 3Dstacked_bar3d()
Globe 3Dglobe3d()

SeraPlot propose 17 types de graphiques tridimensionnels rendus avec acc\u00e9l\u00e9ration WebGL compl\u00e8te.

GraphiqueFonction
Nuage de points 3Dscatter3d()
Barres 3Dbar3d()
Courbe 3Dline3d()
Radar 3Dradar3d()
Sucette 3Dlollipop3d()
KDE 3Dkde3d()
Ridgeline 3Dridgeline3d()
Bulles 3Dbubble3d()
Camembert 3Dpie3d()
Violon 3Dviolin3d()
Heatmap 3Dheatmap3d()
Bougie 3Dcandlestick3d()
Halt\u00e8re 3Ddumbbell3d()
Entonnoir 3Dfunnel3d()
Sunburst 3Dsunburst3d()
Barres empil\u00e9es 3Dstacked_bar3d()
Globe 3Dglobe3d()

Scatter Chart 3D

Signature

sp.scatter3d(title, x=None, y=None, z=None, *, color_hex=0x6366F1, palette=None, bg_color="#1a1a2e", width=900, height=600, x_label="", y_label="", z_label="", **kwargs) -> Chart

Aliases: sp.build_scatter3d_chart(), sp.scatter_3d(), sp.scatter3d_chart().

Description

sp.scatter3d() scatters individual points in 3D space, useful for clustering and outlier/regression dream methods.

Parameters

Returns

Chart object with an .html property and a .show() method.

Bar Chart 3D

Signature

sp.bar3d(title, x=None, y=None, z=None, *, color_hex=0x6366F1, palette=None, bg_color="#1a1a2e", width=900, height=600, x_label="", y_label="", z_label="", **kwargs) -> Chart

Aliases: sp.build_bar3d_chart(), sp.bar_3d(), sp.bar3d_chart(), sp.bar3d_family(), sp.bars3d().

Description

sp.bar3d() renders bars as extruded rectangular prisms on a WebGL-style canvas scene.

Parameters

Returns

Chart object with an .html property and a .show() method.

Line Chart 3D

Signature

sp.line3d(title, x=None, y=None, z=None, *, color_hex=0x6366F1, palette=None, bg_color="#1a1a2e", width=900, height=600, x_label="", y_label="", z_label="", **kwargs) -> Chart

Aliases: sp.build_line3d_chart(), sp.line_3d(), sp.line3d_chart(), sp.line3d_family(), sp.lines3d().

Description

sp.line3d() traces a connected line through points in 3D space.

Parameters

Returns

Chart object with an .html property and a .show() method.

Radar Chart 3D

Signature

sp.radar3d(title, axes=None, series=None, *, series_names=None, palette=None, bg_color="#1a1a2e", width=700, height=600, max_val=None, fill_opacity=0.25, ring_gap=1.0, **kwargs) -> Chart

Aliases: sp.build_radar3d_chart(), sp.radar_3d(), sp.radar3d_chart(), sp.radar3d_family().

Description

sp.radar3d() renders a 3D radar (spider) chart in a WebGL-like canvas scene. Each series becomes one ring of points around the shared axes, stacked along the depth axis instead of overlaid flat like the 2D radar.

Parameters

ring_gap controls the distance between series rings along the depth axis: 1.0 (default) keeps the original one-unit spacing per series, while lower values pull the rings closer together, down to 0.0 where every ring collapses onto the same plane.

Returns

Chart object with an .html property and a .show() method.

Lollipop Chart 3D

Signature

sp.lollipop3d(title, x=None, y=None, z=None, *, color_labels=None, x_label="", y_label="", z_label="", bg_color="#1a1a2e", width=900, height=560, **kwargs) -> Chart

Aliases: sp.build_lollipop3d_chart(), sp.lollipop_3d(), sp.lollipop3d_chart().

Description

sp.lollipop3d() renders a stick-and-ball lollipop marker for each point in 3D space.

Parameters

Returns

Chart object with an .html property and a .show() method.

KDE Chart 3D

Signature

sp.kde3d(title, categories=None, values=None, *, x_label="", y_label="", z_label="", bg_color="#1a1a2e", width=900, height=560, **kwargs) -> Chart

Aliases: sp.build_kde3d_chart(), sp.kde_3d(), sp.kde3d_chart(), sp.density3d().

Description

sp.kde3d() renders kernel-density estimate ridges as layered 3D surfaces, one per category.

Parameters

Returns

Chart object with an .html property and a .show() method.

Ridgeline Chart 3D

Signature

sp.ridgeline3d(title, categories=None, labels=None, values=None, *, x_label="", y_label="", z_label="", bg_color="#1a1a2e", width=900, height=560, **kwargs) -> Chart

Aliases: sp.build_ridgeline3d_chart(), sp.ridgeline_3d(), sp.ridgeline3d_chart(), sp.joy_plot3d().

Description

sp.ridgeline3d() renders overlapping density ridges as layered 3D surfaces.

Parameters

Returns

Chart object with an .html property and a .show() method.

Bubble Chart 3D

Signature

sp.bubble3d(title, x=None, y=None, z=None, sizes=None, *, palette=None, bg_color="#1a1a2e", width=900, height=600, x_label="", y_label="", z_label="", **kwargs) -> Chart

Aliases: sp.build_bubble3d_chart(), sp.bubble_3d().

Description

sp.bubble3d() scatters points in 3D space with marker size mapped to an extra value dimension.

Parameters

Returns

Chart object with an .html property and a .show() method.

Pie Chart 3D

Signature

sp.pie3d(title, labels=None, values=None, *, sort_order="none", bg_color="#1a1a2e", width=900, height=560, **kwargs) -> Chart

Aliases: sp.build_pie3d_chart(), sp.pie_3d(), sp.pie3d_chart(), sp.pie3d_family(), sp.pies3d().

Description

sp.pie3d() renders a pie chart as an extruded 3D disc with wedge depth.

Parameters

Returns

Chart object with an .html property and a .show() method.

Violin Chart 3D

Signature

sp.violin3d(title, categories=None, labels=None, values=None, *, x_label="", y_label="", z_label="", bg_color="#1a1a2e", width=900, height=560, **kwargs) -> Chart

Aliases: sp.build_violin3d_chart(), sp.violin_3d(), sp.violin3d_chart(), sp.violins3d().

Description

sp.violin3d() renders distribution violins as layered 3D surfaces, one per category.

Parameters

Returns

Chart object with an .html property and a .show() method.

Heatmap Chart 3D

Signature

sp.heatmap3d(title, labels=None, categories=None, matrix=None, *, x_labels=None, x_label="", y_label="", z_label="", bg_color="#1a1a2e", width=900, height=560, **kwargs) -> Chart

Aliases: sp.build_heatmap3d_chart(), sp.heatmap_3d(), sp.heatmap3d_chart(), sp.heatmaps3d().

Description

sp.heatmap3d() renders a value matrix as a grid of extruded 3D cells.

Parameters

Returns

Chart object with an .html property and a .show() method.

Candlestick Chart 3D

Signature

sp.candlestick3d(title, labels=None, open=None, high=None, low=None, close=None, *, x_label="Price", y_label="Bar", z_label="", bg_color="#1a1a2e", width=900, height=560, **kwargs) -> Chart

Aliases: sp.build_candlestick3d_chart(), sp.candlestick_3d(), sp.candlestick3d_chart(), sp.ohlc3d().

Description

sp.candlestick3d() renders OHLC candlesticks as 3D bars along a depth axis.

Parameters

Returns

Chart object with an .html property and a .show() method.

Dumbbell Chart 3D

Signature

sp.dumbbell3d(title, labels=None, start=None, end=None, *, y_label="", bg_color="#1a1a2e", width=900, height=560, **kwargs) -> Chart

Aliases: sp.build_dumbbell3d_chart(), sp.dumbbell_3d(), sp.dumbbell3d_chart().

Description

sp.dumbbell3d() connects a start and end value per category with a 3D dumbbell shape.

Parameters

Returns

Chart object with an .html property and a .show() method.

Funnel Chart 3D

Signature

sp.funnel3d(title, labels=None, values=None, *, sort_order="none", bg_color="#1a1a2e", width=900, height=560, **kwargs) -> Chart

Aliases: sp.build_funnel3d_chart(), sp.funnel_3d(), sp.funnel3d_chart().

Description

sp.funnel3d() renders a conversion funnel as stacked 3D frustum segments.

Parameters

Returns

Chart object with an .html property and a .show() method.

Sunburst Chart 3D

Signature

sp.sunburst3d(title, labels=None, parents=None, values=None, *, bg_color="#1a1a2e", width=900, height=560, **kwargs) -> Chart

Aliases: sp.build_sunburst3d_chart(), sp.sunburst_3d(), sp.sunburst3d_chart().

Description

sp.sunburst3d() renders a hierarchical sunburst as concentric 3D rings.

Parameters

Returns

Chart object with an .html property and a .show() method.

Stacked Bar Chart 3D

Signature

sp.stacked_bar3d(title, labels=None, series=None, *, x_label="", y_label="", z_label="", bg_color="#1a1a2e", width=900, height=560, **kwargs) -> Chart

Aliases: sp.build_stacked_bar3d_chart(), sp.stacked_bar_3d(), sp.stacked_bar3d_chart().

Description

sp.stacked_bar3d() stacks multiple series into segmented 3D bars.

Parameters

Returns

Chart object with an .html property and a .show() method.

Globe Chart 3D

Signature

sp.globe3d(title, lats=None, lons=None, values=None, *, project="orthographic", bg_color="#0a0a1a", width=900, height=600, **kwargs) -> Chart

Aliases: sp.build_globe3d_chart(), sp.globe_3d(), sp.globe3d_chart(), sp.globe().

Description

sp.globe3d() plots geo-located values as a heat-colored 3D globe.

Parameters

Returns

Chart object with an .html property and a .show() method.

Map Charts

SeraPlot provides geographic chart types for visualizing spatial data on world maps.

ChartFunction
Bubble Mapbubble_map()
Choroplethchoropleth()

SeraPlot propose des types de graphiques géographiques pour visualiser des données spatiales sur des cartes mondiales.

GraphiqueFonction
Carte à bullesbubble_map()
Choroplethchoropleth()

Bubble Map

Signature

sp.build_bubble_map(
    title: str,
    labels: list[str],
    values: list[float],
    *,
    latitudes: list[float] | None = None,
    longitudes: list[float] | None = None,
    iso_codes: list[str] | None = None,
    color_hex: int = 0x6366F1,
    palette: list[int] | None = None,
    width: int = 1000,
    height: int = 600,
    background: str | None = None,
    hover_json: str | None = None,
    bubble_opacity: float = 0.6,
    min_bubble_size: float = 5.0,
    max_bubble_size: float = 50.0,
) -> Chart

Aliases: sp.bubble_map


Description

World map with proportional bubbles at geographic coordinates. Use iso_codes for country-level data (the library resolves centroids automatically), or pass explicit latitudes / longitudes.


Parameters

ParameterTypeDefaultDescription
titlestrrequiredChart title
labelslist[str]requiredLocation names
valueslist[float]requiredBubble sizes
latitudeslist[float] | NoneNoneManual latitudes
longitudeslist[float] | NoneNoneManual longitudes
iso_codeslist[str] | NoneNoneISO-3166 alpha-3 country codes
color_hexint0x6366F1Bubble color
palettelist[int] | NoneNoneMulti-group palette
widthint1000Canvas width
heightint600Canvas height
bubble_opacityfloat0.6Bubble transparency (0–1)
min_bubble_sizefloat5.0Minimum bubble radius in pixels
max_bubble_sizefloat50.0Maximum bubble radius in pixels
hover_jsonstr | NoneNoneCustom hover JSON

Returns

Chart


Examples

GDP per country (ISO code lookup)

import seraplot as sp
chart = sp.build_bubble_map(
    "GDP by Country",
    labels=["USA", "CHN", "DEU", "JPN", "FRA"],
    values=[25500, 17700, 4400, 4200, 3100],
)
const sp = require('seraplot');
const chart = sp.build_bubble_map("GDP by Country",
["USA", "CHN", "DEU", "JPN", "FRA"],
{
    values: [25500, 17700, 4400, 4200, 3100]
})
import * as sp from 'seraplot';
const chart = sp.build_bubble_map("GDP by Country",
["USA", "CHN", "DEU", "JPN", "FRA"],
{
    values: [25500, 17700, 4400, 4200, 3100]
})
▶ Live Preview

Custom coordinates

import seraplot as sp

chart = sp.build_bubble_map(
    "City Populations",
    labels=["Paris", "Tokyo", "New York", "Lagos"],
    values=[11, 37, 20, 15],
    latitudes=[48.85, 35.68, 40.71, 6.52],
    longitudes=[2.35, 139.69, -74.01, 3.38],
)

Signature

sp.build_bubble_map(
    title: str,
    labels: list[str],
    values: list[float],
    *,
    latitudes: list[float] | None = None,
    longitudes: list[float] | None = None,
    iso_codes: list[str] | None = None,
    color_hex: int = 0x6366F1,
    palette: list[int] | None = None,
    width: int = 1000,
    height: int = 600,
    background: str | None = None,
    hover_json: str | None = None,
    bubble_opacity: float = 0.6,
    min_bubble_size: float = 5.0,
    max_bubble_size: float = 50.0,
) -> Chart

Aliases: sp.bubble_map


Description

Carte mondiale avec des bulles proportionnelles aux coordonnées géographiques. Utilisez iso_codes pour les données par pays (la bibliothèque résout les centroïdes automatiquement), ou passez des latitudes / longitudes explicites.


Paramètres

ParamètreTypeDéfautDescription
titlestrrequisTitre du graphique
labelslist[str]requisNoms des lieux
valueslist[float]requisTailles des bulles
latitudeslist[float] | NoneNoneLatitudes manuelles
longitudeslist[float] | NoneNoneLongitudes manuelles
iso_codeslist[str] | NoneNoneCodes ISO-3166 alpha-3 des pays
color_hexint0x6366F1Couleur des bulles
palettelist[int] | NoneNonePalette multi-groupes
widthint1000Largeur du canvas
heightint600Hauteur du canvas
bubble_opacityfloat0.6Transparence des bulles (0–1)
min_bubble_sizefloat5.0Rayon minimal des bulles en pixels
max_bubble_sizefloat50.0Rayon maximal des bulles en pixels
hover_jsonstr | NoneNoneJSON d'infobulle personnalisée

Retourne

Chart


Exemples

import seraplot as sp

chart = sp.build_bubble_map(
    "PIB par pays",
    labels=["USA", "CHN", "DEU", "JPN", "FRA"],
    values=[25500, 17700, 4400, 4200, 3100],
)
import seraplot as sp

chart = sp.build_bubble_map(
    "Populations urbaines",
    labels=["Paris", "Tokyo", "New York", "Lagos"],
    values=[11, 37, 20, 15],
    latitudes=[48.85, 35.68, 40.71, 6.52],
    longitudes=[2.35, 139.69, -74.01, 3.38],
)

Choropleth Map

Signature

sp.build_choropleth(
    title: str,
    labels: list[str],
    values: list[float],
    *,
    iso_codes: list[str] | None = None,
    color_low: int = 0,
    color_high: int = 0,
    palette: list[int] | None = None,
    width: int = 1000,
    height: int = 600,
    background: str | None = None,
    hover_json: str | None = None,
    show_legend: bool = True,
    null_color: int = 0xdddddd,
) -> Chart

Aliases: sp.choropleth


Description

Choropleth (filled map) — country or region polygons colored by a scalar value.

Countries without data receive the null_color. Provide iso_codes (ISO-3166 alpha-3) to match countries automatically.


Parameters

ParameterTypeDefaultDescription
titlestrrequiredChart title
labelslist[str]requiredCountry
valueslist[float]requiredValues to color by
iso_codeslist[str] | NoneNoneISO-3166 alpha-3 codes
color_lowintautoLow value color
color_highintautoHigh value color
null_colorint0xddddddColor for countries with no data
widthint1000Canvas width
heightint600Canvas height
show_legendboolTrueShow color scale legend
hover_jsonstr | NoneNoneCustom hover JSON

Returns

Chart


Examples

Unemployment rate choropleth

import seraplot as sp
chart = sp.build_choropleth(
    "Unemployment Rate by Country",
    labels=["FRA", "DEU", "ESP", "ITA", "PRT"],
    values=[7.1, 3.0, 11.8, 6.7, 6.2],
)
const sp = require('seraplot');
const chart = sp.build_choropleth("Unemployment Rate by Country",
["FRA", "DEU", "ESP", "ITA", "PRT"],
{
    values: [7.1, 3.0, 11.8, 6.7, 6.2]
})
import * as sp from 'seraplot';
const chart = sp.build_choropleth("Unemployment Rate by Country",
["FRA", "DEU", "ESP", "ITA", "PRT"],
{
    values: [7.1, 3.0, 11.8, 6.7, 6.2]
})
▶ Live Preview

Signature

sp.build_choropleth(
    title: str,
    labels: list[str],
    values: list[float],
    *,
    iso_codes: list[str] | None = None,
    color_low: int = 0,
    color_high: int = 0,
    palette: list[int] | None = None,
    width: int = 1000,
    height: int = 600,
    background: str | None = None,
    hover_json: str | None = None,
    show_legend: bool = True,
    null_color: int = 0xdddddd,
) -> Chart

Aliases: sp.choropleth


Description

Carte choro-plèthe — polygones de pays/régions colorés par une valeur scalaire. Les pays sans données reçoivent la null_color. Fournissez des iso_codes (ISO-3166 alpha-3) pour associer les pays automatiquement.


Paramètres

ParamètreTypeDéfautDescription
titlestrrequisTitre du graphique
labelslist[str]requisPays
valueslist[float]requisValeurs pour la colorisation
iso_codeslist[str] | NoneNoneCodes ISO-3166 alpha-3
color_lowintautoCouleur pour les valeurs basses
color_highintautoCouleur pour les valeurs hautes
null_colorint0xddddddCouleur des pays sans données
widthint1000Largeur du canvas
heightint600Hauteur du canvas
show_legendboolTrueAfficher l'échelle de couleur
hover_jsonstr | NoneNoneJSON d'infobulle personnalisée

Retourne

Chart


Exemples

import seraplot as sp

chart = sp.build_choropleth(
    "Taux de chômage par pays",
    labels=["FRA", "DEU", "ESP", "ITA", "PRT"],
    values=[7.1, 3.0, 11.8, 6.7, 6.2],
)

Canvas Composition

Canvas is SeraPlot's composition layer: a free-form surface where you place multiple independently-built Chart objects, images, shapes and text, wire them together, and export the whole thing as one Chart. It is the tool for building dashboards, annotated stories and multi-panel figures that a single chart function can't produce on its own.

import seraplot as sp

bar = sp.grouped_bar("", labels=[...], values=[...], series_names=[...])
cv = sp.canvas(1280, 800, "#0a0a0f")
bars_ref = cv.place(bar, 60, 60, 560, 420, name="revenue")
chart = cv.build()

Every placement/drawing method accepts an optional name keyword. A named element gets a data-sp-name="..." attribute in the rendered HTML, which is what makes it addressable by every other method below (nudge, resize, style, script, group, link, refill, dev-mode dragging, ...). Naming is free and has no runtime cost — name anything you might want to touch again.


Constructing a canvas

cv = sp.canvas(width: int, height: int, bg: str = "#0a0a0f")

Placing charts and images

MethodEffect
place(chart, x, y, w, h, rotation=0, opacity=1, clip="", group="", name="")Places a Chart on the canvas at (x, y) sized w×h. Returns a chart_ref (int) used by pin/connect/attach_*.
image(src, x, y, w, h, rotation=0, opacity=1, clip="", group="", name="")Places a PNG/JPEG/GIF/WebP/SVG image. src is a local file path (read and base64-embedded), a data: URI, or an http(s):// URL.
slot(name, x, y, w, h)Reserves a named region without placing anything yet.
fill(slot_name, chart, ...)Places a chart using a previously-declared slot's geometry.
grid(x, y, w, h, rows, cols, gap_x=0, gap_y=0)Declares a rows × cols grid of slots named cell_{row}_{col} and returns the list of names in row-major order — no manual coordinate math for dashboards.
refill(name, chart) -> boolReplaces a named, already-placed chart's content in place — same position, size, rotation, style. Use this (not place/fill again) whenever you're refreshing a panel with new data.

clip accepts "circle", "diamond", "hex", "tri", "pentagon" for non-rectangular chart/image framing.

Calling place/fill again with a name that's already taken by a placed chart updates that chart in place instead of stacking a duplicate — so fill(slot, new_chart, name="panel") is safe to call repeatedly.


Micro-tools: shared conventions

text, line, curve, connector, circle, ring, rect, polygon, path, arrow, annotate and gradient are the low-level drawing primitives everything else in Canvas (including voronoi(), below) is built from. They draw directly on the canvas SVG, and share two keywords:

  • layer="fg"|"bg""bg" renders under every place()d chart/image, "fg" (the default) renders on top. Use "bg" for backdrops, card panels and watermark-style decoration; "fg" for annotations, callouts and anything that should sit above the data.
  • name="" — makes the element addressable afterward by nudge, resize, style, script, group, link, and draggable in dev() mode. Naming is free; name anything you might want to touch again.

None of them require a Chart — a canvas full of nothing but these primitives is a valid way to hand-draw a diagram SeraPlot has no dedicated chart function for (see the closing example on this page).


Lines, curves & connectors

Four ways to draw between points — pick based on how many points and how rigid the shape between them needs to be.

line — straight segment

cv.line(x1, y1, x2, y2, color="#ffffff", width=1.5, dash="", opacity=1.0,
         cap="round", layer="fg", hover_group="", name="")
ParameterTypeDefaultDescription
x1, y1, x2, y2floatrequiredEndpoints, in canvas pixels
colorstr"#ffffff"Stroke color
widthfloat1.5Stroke width
dashstr""SVG stroke-dasharray, e.g. "6,4" for a dashed line
opacityfloat1.00–1
capstr"round"Line-end style: "round", "butt", or "square"
hover_groupstr""Adds an invisible wide hit-area alongside the (often thin) visible stroke, so the line reacts to hover as part of a link() group
namestr""Addressable name

The plain straight-line primitive — axes, dividers, guide lines, or one leg of a hand-built diagram.

curve — smooth line through N points

cv.curve(points, color="#ffffff", width=1.5, opacity=1.0, tension=1.0,
          fill="none", layer="fg", name="")
ParameterTypeDefaultDescription
pointslist[[x, y]]requiredThree or more waypoints the curve passes through
tensionfloat1.0Catmull-Rom tension: 0 collapses to straight segments between points, 1 is a standard smooth spline, higher values pull the curve into more pronounced bulges past each point
fillstr"none"Fills the area under the curve when set — a hand-drawn area-chart look
(color / width / opacity / layer / name — same as line)

Unlike connector (below), which always routes between exactly two points, curve interpolates through an arbitrary polyline of waypoints. Reach for it for hand-drawn trend lines, sparkline-style decoration, or free-form organic strokes that aren't tied to a Chart's own axes:

cv.curve([[40, 300], [140, 120], [260, 260], [400, 80]],
          color="#22c55e", width=3, tension=0.8, name="trend-doodle")

connector — S-curve between two points

cv.connector(x1, y1, x2, y2, color="#ffffff", width=1.5, opacity=1.0,
              bend=0.5, layer="fg", name="")
ParameterTypeDefaultDescription
bendfloat0.5Fraction along the dominant axis (whichever of dx/dy is larger) where the bezier control points sit — 0.5 gives a symmetric S-curve; values toward 0 or 1 skew the curve's midpoint toward one end
(others — same as line)

The "flowchart wire" primitive: one cubic bezier that always produces a clean S- or L-shaped route between two points, regardless of their relative position. Use it to link two place()d panels or two named elements without hand-computing control points — connect() (under Connecting two charts, below) draws the exact same curve, but reads its endpoints from registered pins instead of raw coordinates.

arrow — directional line with an arrowhead

cv.arrow(x1, y1, x2, y2, color="#ffffff", width=1.5, head_size=4.0,
          opacity=1.0, layer="fg", name="")
ParameterTypeDefaultDescription
head_sizefloat4.0Arrowhead size in px — the marker scales with this, not with width
(others — same as line)

A line with an SVG <marker> arrowhead baked onto its end, for pointing at something rather than just connecting two things.


Shapes

Five ways to fill or stroke a region, from most constrained to most free-form.

circle / ring

cv.circle(cx, cy, r, fill="none", stroke="#ffffff", stroke_width=1.5,
           opacity=1.0, layer="fg", hover_group="", name="")
cv.ring(cx, cy, inner_r, outer_r, fill="#ffffff", stroke="none",
         stroke_width=0.0, opacity=1.0, layer="fg", name="")

ring is a donut: the filled region strictly between inner_r and outer_r, built from two arcs combined with fill-rule="evenodd" rather than a solid <circle>. Use it for radial progress rings, avatar frames, or halo highlights — anywhere circle's solid disc would cover whatever sits underneath it.

rect

cv.rect(x, y, w, h, fill="none", stroke="#ffffff", stroke_width=1.5,
         rx=0.0, opacity=1.0, rotation=0.0, layer="fg", name="")

rx rounds the corners; rotation (degrees) spins the rect around its own center. The two together cover card backgrounds, chips/badges, and simple category-key swatches.

polygon

cv.polygon(points, fill="none", stroke="#ffffff", stroke_width=1.5,
            opacity=1.0, layer="fg", name="")

A closed shape through an arbitrary list[[x, y]] of vertices — the primitive voronoi() itself is built from (each cell it returns is one polygon() call under the hood). Use it directly for triangular/diamond markers, custom badge shapes, or any closed region rect/circle can't express.

path

cv.path(d, fill="none", stroke="#ffffff", stroke_width=1.5, opacity=1.0,
          layer="fg", name="")

The escape hatch: d is a raw SVG path-data string ("M ... L ... A ... Z") for shapes none of the other primitives cover — logos, icons, arcs with a specific sweep, or geometry computed by your own code. This is exactly how icicle()'s "radial" variant draws its annular sectors internally: hand-built M/A/L/Z strings, no separate arc primitive needed.


Text & annotations

text

cv.text(content, x, y, size=24.0, color="#ffffff", weight="normal",
          anchor="start", rotation=0.0, letter_spacing=0.0,
          font="sans-serif", opacity=1.0, layer="fg", name="")

anchor is the SVG text-anchor ("start", "middle", "end") relative to (x, y)"middle" centers a title over a panel, "end" right-aligns a value next to an axis.

annotate — leader-line label

cv.annotate(text, ax, ay, tx, ty, color="#ffffff", size=13.0,
             line_dash="", line_width=1.0, bg="", layer="fg", name="")
ParameterTypeDefaultDescription
ax, ayfloatrequiredThe point being annotated — where the leader line starts
tx, tyfloatrequiredWhere the text itself sits — where the leader line ends
textstrrequiredSupports \n for multi-line labels
line_dashstr""Dash pattern for the leader line, e.g. "4,3"
bgstr""Background color behind the text; ""/"none" draws no box

Unlike a plain text() + line() pair, annotate() auto-routes a clean two-segment elbow between (ax, ay) and (tx, ty) (picking the elbow point from whichever axis has the larger offset) and sizes its own background box to fit the text. The tool for "this specific point, labeled, with a callout line" — a bar's peak, a scatter outlier. annotate_at() (under Connecting two charts, below) is the pin-aware version of this same primitive, for labeling a point inside a place()d chart instead of a raw canvas coordinate.


Color: gradient

cv.gradient(id, from_color, to_color, x1=0.0, y1=0.0, x2=1.0, y2=0.0)

Registers an SVG linearGradient definition — x1/y1/x2/y2 live in the 0..1 objectBoundingBox space, so (0,0)→(1,0) is left-to-right and (0,0)→(0,1) is top-to-bottom. It draws nothing by itself; call it once, then reference fill=f"url(#{id})" on any subsequent rect/circle/ polygon/path:

cv.gradient("card-glow", "#6366f1", "#0a0a0f", x1=0, y1=0, x2=0, y2=1)
cv.rect(40, 40, 300, 200, fill="url(#card-glow)", rx=18, name="card")

Composing micro-tools: a radial dial

None of the primitives above need a Chart at all — a canvas built only from them is a fully valid way to hand-draw a widget SeraPlot has no dedicated chart function for. ring only ever draws a complete annulus, so a partial-sweep progress dial needs path with a hand-computed SVG arc — exactly the "escape hatch" role described above:

import math
import seraplot as sp

def arc_path(cx, cy, r, pct):
    start = -math.pi / 2
    end = start + 2 * math.pi * pct
    x1, y1 = cx + r * math.cos(start), cy + r * math.sin(start)
    x2, y2 = cx + r * math.cos(end), cy + r * math.sin(end)
    large_arc = 1 if pct > 0.5 else 0
    return f"M {x1:.2f},{y1:.2f} A {r},{r} 0 {large_arc},1 {x2:.2f},{y2:.2f}"

cv = sp.Canvas(300, 300, bg="#0a0a0f")
cv.gradient("dial-g", "#6366f1", "#22d3ee", x1=0, y1=0, x2=1, y2=1)
cv.ring(150, 150, 100, 112, fill="#1e293b", name="track")
cv.path(arc_path(150, 150, 106, 0.72), fill="none", stroke="url(#dial-g)",
         stroke_width=12, name="progress")
cv.text("72%", 150, 158, size=34, color="#f8fafc", weight="800",
          anchor="middle", name="pct-label")
chart = cv.build()

ring draws the static background track, path draws the live progress arc on top of it (stroked with the gradient defined a line earlier), and text centers the number — three primitives from three different sections above, one small self-contained gauge.

The hand-rolled arc_path above is exactly what arc/wedge below do internally — reach for them first; path stays the escape hatch for shapes neither one covers.


Radial drawing: arc, wedge, ribbon, polar

arc, wedge, ribbon, polar and radial_gradient share one angle convention: degrees, 0° at the top, increasing clockwise — the same convention pie/donut/gauge charts already use, so radial compositions read the same way.

MethodEffect
arc(cx, cy, r, start_deg, end_deg, color="#ffffff", width=1.5, opacity=1, cap="round", layer="fg", name="")A stroked circular arc — spokes, progress rings, radial tick marks.
wedge(cx, cy, r_inner, r_outer, start_deg, end_deg, fill="#ffffff", stroke="none", stroke_width=0, opacity=1, layer="fg", name="")A filled donut segment; r_inner=0 collapses it to a pie slice. The building block for radial bar charts — one wedge per bar, r_outer mapped to the value.
ribbon(cx, cy, r, a_start, a_end, b_start, b_end, fill="#ffffff", opacity=0.7, layer="fg", name="")A curved band connecting two arc spans on the same circle through its center — chord-diagram-style links between categories.
polar(cx, cy, r, deg) -> (x, y)Pure coordinate math, no drawing — converts a radial position to (x, y) so you can place any other primitive (text, circle, line, a placed Chart) at a computed angle instead of hand-deriving trig every time.
radial_gradient(id, from_color, to_color, cx=0.5, cy=0.5, r=0.5)A radial counterpart to gradient — reference it the same way, fill="url(#id)", for glows and center-out fades.
cv = sp.canvas(600, 600, "#0a0a12")
cx, cy = 300, 300
cv.radial_gradient("glow", "#312e81", "#0a0a12", r=0.75)
cv.circle(cx, cy, 260, fill="url(#glow)", name="glow-bg")

values = [8, 15, 6, 22, 11, 18, 4, 13]
n = len(values)
for i, v in enumerate(values):
    a0 = i * 360 / n + 2
    a1 = (i + 1) * 360 / n - 2
    cv.wedge(cx, cy, 60, 60 + v * 7, a0, a1,
             fill=f"hsl({i * 360 // n}, 70%, 60%)", name=f"bar-{i}")
    lx, ly = cv.polar(cx, cy, 60 + v * 7 + 16, (a0 + a1) / 2)
    cv.text(str(v), lx, ly, size=11, color="#f8fafc", anchor="middle", name=f"lbl-{i}")

cv.ribbon(cx, cy, 58, 10, 30, 190, 210, fill="#a78bfa", opacity=0.35, name="link-a")
chart = cv.build()

This is the same shape as the radial pieces at visualcinnamon.com — a center, a set of wedges swept around it, labels placed with polar, and ribbons crossing between spans. Nothing here is a dedicated "radial bar chart" type; it's the five primitives above composed by hand, the same way the rest of Canvas works — including mixing in a placed Chart at a polar-computed position if the story calls for it.


Three more shapes built from the same handful of primitives — no new API below this line, just polar, curve, wedge and connector combined differently each time.

A spiral — each point's radius grows with its index instead of staying fixed, the technique behind timeline-as-spiral pieces like Searching for Birds:

cx, cy = 300, 300
n = 60
cv = sp.canvas(600, 600, "#0a0a12")
pts = []
for i in range(n):
    deg = i * 12
    r = 20 + i * 4.2
    pts.append(list(cv.polar(cx, cy, r, deg)))
cv.curve(pts, color="#a78bfa", width=2, tension=0.8, name="spiral")
for i in range(0, n, 4):
    x, y = pts[i]
    cv.circle(x, y, 3 + (i / n) * 5, fill="#22d3ee", name=f"pt-{i}")
chart = cv.build()

A sunburst — two rings of wedge, the outer ring's spans computed from the inner ring's proportions instead of an even split, giving a hierarchical part-of-a-part-of-a-whole read:

cx, cy = 300, 300
cv = sp.canvas(600, 600, "#0a0a12")
groups = [("Frontend", 40), ("Backend", 35), ("Data", 25)]
subgroups = {
    "Frontend": [("React", 20), ("CSS", 12), ("A11y", 8)],
    "Backend": [("API", 18), ("Auth", 10), ("Jobs", 7)],
    "Data": [("ETL", 14), ("ML", 11)],
}

total = sum(v for _, v in groups)
cursor = 0.0
for name, v in groups:
    span = v / total * 360
    cv.wedge(cx, cy, 60, 130, cursor, cursor + span - 2, fill="#6366f1", name=f"inner-{name}")
    lx, ly = cv.polar(cx, cy, 95, cursor + span / 2)
    cv.text(name, lx, ly, size=11, color="#fff", anchor="middle", name=f"inner-lbl-{name}")

    sub_total = sum(sv for _, sv in subgroups[name])
    sub_cursor = cursor
    for sname, sv in subgroups[name]:
        sub_span = sv / sub_total * span
        cv.wedge(cx, cy, 135, 200, sub_cursor, sub_cursor + sub_span - 1,
                 fill="#22d3ee", opacity=0.85, name=f"outer-{sname}")
        lx, ly = cv.polar(cx, cy, 168, sub_cursor + sub_span / 2)
        cv.text(sname, lx, ly, size=9, color="#0a0a12", anchor="middle", name=f"outer-lbl-{sname}")
        sub_cursor += sub_span
    cursor += span
chart = cv.build()

A radial network — nodes placed on a circle with polar, random pairs joined with connector's bend for a soft curve instead of a straight chord; the same "relationships between things" story ribbon tells, drawn node-and-edge instead of band-and-arc:

import random

cx, cy = 300, 300
n = 14
cv = sp.canvas(600, 600, "#0a0a12")
cv.radial_gradient("net-glow", "#1e1b4b", "#0a0a12", r=0.85)
cv.circle(cx, cy, 280, fill="url(#net-glow)", name="bg")

nodes = [cv.polar(cx, cy, 220, i * 360 / n) for i in range(n)]

edges = set()
while len(edges) < 22:
    a, b = random.sample(range(n), 2)
    edges.add((min(a, b), max(a, b)))

for a, b in edges:
    ax, ay = nodes[a]
    bx, by = nodes[b]
    cv.connector(ax, ay, bx, by, color="#4c1d95", width=1, opacity=0.5, bend=0.15, name=f"edge-{a}-{b}")

for i, (x, y) in enumerate(nodes):
    cv.circle(x, y, 8, fill="#a78bfa", stroke="#0a0a12", stroke_width=2, name=f"node-{i}")
chart = cv.build()

Real-world composition: a RéciTAC-style network

RéciTAC (Nadieh Bremer) is a d3.js/Canvas network diagram organizing a research program's projects, people, and outcomes into a central cluster flanked by two semi-circles — researchers' disciplines on one side, activities/outputs on the other — with small donut rings around each project node encoding the disciplinary mix of everyone connected to it. None of that needs a dedicated "network chart" type: it's polar for every node position, wedge stacked into a per-node donut, connector for the edges, and link so hovering a project highlights its whole neighborhood — the same primitives from every section above, composed around one idea.

import seraplot as sp

DISCIPLINES = {"Climate": "#38bdf8", "Social": "#f472b6", "Engineering": "#a3e635", "Policy": "#fbbf24"}
RESEARCHERS = [("Amara", "Climate"), ("Lian", "Climate"), ("Devi", "Social"),
               ("Noah", "Social"), ("Jamal", "Engineering"), ("Elin", "Policy")]
ACTIVITIES = ["Workshops", "Sensors", "Policy Brief", "Dataset", "Exhibition"]
PROJECTS = [
    ("Coastal Lab", [0, 1, 3, 5], [0, 1]),
    ("Urban Heat", [1, 2, 4], [1, 3]),
    ("Youth Climate", [2, 3, 5], [2, 4]),
]

cx, cy = 450, 450
cv = sp.Canvas(900, 900)
cv.radial_gradient("bg", "#141b2e", "#05070d", cx=0.5, cy=0.46, r=0.75)
cv.rect(0, 0, 900, 900, fill="url(#bg)", layer="bg")

left = [cv.polar(cx, cy, 340, 210 + i * 25) for i in range(len(RESEARCHERS))]
right = [cv.polar(cx, cy, 340, 30 + i * 25) for i in range(len(ACTIVITIES))]
proj_pos = [cv.polar(cx, cy, 150, i * 360 / len(PROJECTS)) for i in range(len(PROJECTS))]

for i, (name, disc) in enumerate(RESEARCHERS):
    x, y = left[i]
    cv.circle(x, y, 8, fill=DISCIPLINES[disc], stroke="#0b0e18", stroke_width=2, name=f"res{i}")

for i, name in enumerate(ACTIVITIES):
    x, y = right[i]
    cv.rect(x - 6, y - 6, 12, 12, fill="#e2e8f0", rotation=45, name=f"act{i}")

for pi, (name, r_idx, a_idx) in enumerate(PROJECTS):
    px, py = proj_pos[pi]
    for ri in r_idx:
        rx, ry = left[ri]
        cv.connector(rx, ry, px, py, color=DISCIPLINES[RESEARCHERS[ri][1]], width=1.2, opacity=0.35, bend=0.2)
    for ai in a_idx:
        ax, ay = right[ai]
        cv.connector(px, py, ax, ay, color="#64748b", width=1, opacity=0.3, bend=0.2)

    counts = {}
    for ri in r_idx:
        counts[RESEARCHERS[ri][1]] = counts.get(RESEARCHERS[ri][1], 0) + 1
    start = 0.0
    for d, count in counts.items():
        end = start + count / len(r_idx) * 360
        cv.wedge(px, py, 34, 42, start, end, fill=DISCIPLINES[d])
        start = end
    cv.circle(px, py, 30, fill="#111827", stroke="#f8fafc", stroke_width=2, name=f"proj{pi}")
    cv.text(name, px, py + 4, size=11, color="#f8fafc", weight="600", anchor="middle")

    members = [f"proj{pi}"] + [f"res{ri}" for ri in r_idx] + [f"act{ai}" for ai in a_idx]
    cv.link(f"cluster{pi}", members)

chart = cv.build()

The dataset above is synthetic — the point is the composition pattern, not a literal port of Nadieh's real research-program data (which comes from a private Google Sheet). Everything scales with the data: add a discipline to the dict and every donut ring picks it up automatically; add a researcher to a project's list and a new connector + donut slice appear on the next build().


Composing real charts: a mission-control dashboard

place() embeds a full Chart — not just a primitive — inside a canvas, which means canvas composition isn't limited to hand-drawn shapes: real sp.line(), sp.bar(), sp.gauge(), sp.area() panels can sit framed, connected, and annotated by the exact same primitives used everywhere else on this page. The part that actually sells "dashboard" over "four charts in boxes" is the same trick as the RéciTAC network above: a shared center every panel connects to. One glowing hub, four color-matched spokes (connector + a circle anchor at each end), each spoke tinted to match the panel it comes from via the chart-level chainable methods (palette(), gridlines(), width()/height() — see Chart Methods) applied before place():

import seraplot as sp

W, H = 1500, 1000
HX, HY, HR = 750, 500, 76

cv = sp.Canvas(W, H)
cv.radial_gradient("dashBg", "#1a2140", "#04050a", cx=0.5, cy=0.5, r=0.9)
cv.rect(0, 0, W, H, fill="url(#dashBg)", layer="bg")
cv.radial_gradient("hubGlow", "#22d3ee", "#04050a", cx=0.5, cy=0.5, r=0.5)

cv.text("Mission Control", 48, 54, size=27, color="#f8fafc", weight="800")
cv.text("Every panel wired into one live hub — sp.Canvas place() + connectors + real SeraPlot charts",
         48, 80, size=13, color="#64748b")

PALETTE = [0x6366f1, 0x22d3ee, 0xf59e0b, 0xf472b6]
HEX = [f"#{c:06x}" for c in PALETTE]
PW, PH = 600, 300
PANELS = [("trend", 60, 150, HEX[0]), ("revenue", 840, 150, HEX[1]),
          ("health", 60, 590, HEX[2]), ("incidents", 840, 590, HEX[3])]

def panel_frame(x, y, w, h, color, name):
    cv.rect(x - 16, y - 16, w + 32, h + 32, fill="#0b1022", stroke="rgba(255,255,255,.06)",
            stroke_width=1, rx=18, layer="bg", name=name)
    cv.rect(x - 16, y - 16, w + 32, 4, fill=color, rx=2, layer="bg")

for name, x, y, color in PANELS:
    panel_frame(x, y, PW, PH, color, f"panel-{name}")

trend = sp.line(labels=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"],
                  values=[820, 932, 901, 934, 1290, 1330, 1320], title="Weekly Active Users",
                 ).width(PW).height(PH).palette(PALETTE).gridlines(False).background("#0b1022")

revenue = sp.bar(labels=["Core","Cloud","API","Mobile","Support"],
                   values=[420, 680, 310, 240, 150], title="Revenue by Segment",
                  ).width(PW).height(PH).palette(PALETTE).gridlines(False).background("#0b1022")

health = sp.gauge(value=87, title="System Health").width(PW).height(PH).background("#0b1022")

incidents = sp.area(labels=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"], values=[5, 3, 6, 2, 4, 1, 2],
                      title="Open Incidents",
                     ).width(PW).height(PH).palette([PALETTE[3]]).gridlines(False).background("#0b1022")

cv.place(trend, 60, 150, PW, PH, name="chart-trend")
cv.place(revenue, 840, 150, PW, PH, name="chart-revenue")
cv.place(health, 60, 590, PW, PH, name="chart-health")
cv.place(incidents, 840, 590, PW, PH, name="chart-incidents")

ANCHORS = {"trend": (660, 300), "revenue": (840, 300), "health": (660, 700), "incidents": (840, 700)}
for name, x, y, color in PANELS:
    ax, ay = ANCHORS[name]
    cv.connector(ax, ay, HX, HY, color=color, width=2, opacity=0.55, bend=0.28, name=f"spoke-{name}")
    cv.circle(ax, ay, 6, fill=color, stroke="#04050a", stroke_width=2, name=f"anchor-{name}")
    cv.circle(ax, ay, 11, fill="none", stroke=color, stroke_width=1, opacity=0.4)

cv.circle(HX, HY, HR + 34, fill="url(#hubGlow)", opacity=0.35)
cv.ring(HX, HY, HR + 18, HR + 22, fill="#22d3ee", opacity=0.25)
cv.ring(HX, HY, HR + 6, HR + 9, fill="#22d3ee", opacity=0.45)

start = 0.0
for name, _, _, color in PANELS:
    end = start + 90
    cv.wedge(HX, HY, HR - 10, HR - 4, start, end, fill=color, opacity=0.85)
    start = end

cv.circle(HX, HY, HR - 14, fill="#0b1022", stroke="#f8fafc", stroke_width=2)
cv.text("87", HX, HY - 4, size=40, color="#22d3ee", weight="800", anchor="middle")
cv.text("SYSTEM SCORE", HX, HY + 22, size=10, color="#64748b", anchor="middle", letter_spacing=1.5)

cv.link("hub-cluster", ["anchor-trend", "anchor-revenue", "anchor-health", "anchor-incidents"])

cv.annotate("Trending up 61% since Monday", 250, 320, 250, 500, color="#94a3b8", size=12,
             line_dash="4,3", bg="#0b1022")
cv.annotate("5 open, 2 critical", 1050, 660, 1150, 500, color="#94a3b8", size=12,
             line_dash="4,3", bg="#0b1022")

chart = cv.build()

The hub itself is a small radial gauge in disguise — four wedge slices (one per panel, in that panel's color) inside two ring pulse tracks, built from exactly the same primitives as the "Composing micro-tools" dial and the RéciTAC donut rings above. Reusing one visual language across every worked example on this page is the actual point: primitives don't know or care whether they're drawing a progress dial, a discipline ring, or a dashboard hub.

panel_frame() draws a rounded card plus a thin color-matched top border — that accent color is the same one used for that panel's spoke and palette(), so the eye connects "this line is orange" to "this panel is orange" to "this spoke is orange" without a legend. The one easy-to-miss detail behind all of it: any decoration meant to sit behind a placed chart (background fill, panel frames) needs layer="bg" explicitly — rect()'s default layer="fg" renders on top of placed charts by design (so connectors and callouts can cross over them), which will silently hide a panel's contents if the panel itself is drawn on the foreground layer.


Organic layouts: Voronoi

voronoi(sites, x, y, w, h, fills=None, stroke=..., stroke_width=..., opacity=...) computes a bounded Voronoi diagram — one cell per site, each cell the region closer to that site than to any other — and adds every cell to the canvas as a polygon() in one call, returning their element indices for later addressing (hover groups, derive(), etc.). This is the same organic, cell-based layout technique behind editorial data-journalism pieces like Nadieh Bremer's Highly Hazardous Pesticides — no off-the-shelf "voronoi chart type" needed, just the primitive.

import random
cv = sp.Canvas(900, 540)
sites = [[random.uniform(30, 870), random.uniform(30, 510)] for _ in range(22)]
palette = ["#6366f1", "#ec4899", "#22c55e", "#f59e0b", "#06b6d4", "#8b5cf6", "#ef4444"]
fills = [palette[i % len(palette)] for i in range(len(sites))]
cv.voronoi(sites, 0, 0, 900, 540, fills=fills, stroke="#0d1117", stroke_width=2, opacity=0.88)

Cell size follows site density automatically — cluster sites tightly to shrink their cells, useful for a treemap-like "one cell per record, colored by category, sized by local density" layout without a separate packing algorithm. Implemented natively (iterative half-plane clipping against every other site, no external geometry crate) rather than pulled in as a dependency.


Custom CSS / JS

MethodEffect
style(name, css)Injects [data-sp-name="name"]{ css } into the canvas's <style>. Pass name="" to inject a raw, unscoped CSS block (e.g. @keyframes).
script(js)Appends a raw <script>js</script> before </body> — full manual control for users who want to hand-write interactivity.

Groups and inter-plot linking

Two different mechanisms, both driven by element names:

group(group_name, member_names) / move_group(group_name, dx, dy) — moves several named elements together as a rigid unit. nudge(name, dx, dy) and resize(name, dw, dh) do the same for a single element. Pins registered on a chart before a move/resize are shifted along with it automatically.

link(group_name, member_names) -> int — ties elements across different panels into one hover group: hovering any linked element (a Chart, Rect, Text or Circle) glows/pulses all the others in the same group. Returns how many of the given names were actually linkable (Line, RawPath and other pure decoration types don't currently support it).

cv.link("story", ["revenue_chart", "trend_chart", "kpi_card"])

Connecting two charts (pins)

Pins are named anchor points registered inside a placed chart's coordinate space, in canvas pixel coordinates. connect()/annotate_at() read pins to draw a line or label between (or on top of) charts.

MethodEffect
pin(chart_ref, name, local_x, local_y)Registers a pin at a chart-local pixel coordinate.
pin_frac(chart_ref, name, fx, fy)Registers a pin at a fractional position (0..1) of the chart's native size.
`pin_xy(chart_ref, name) -> (x, y)None`
attach_bar(chart_ref, values, chart_w, chart_h, ...)Auto-registers bar:{i}:top/center/bottom/left/right pins by reading the actual rendered bar rectangles.
attach_scatter(chart_ref, x_vals, y_vals, labels, chart_w, chart_h, ...)Auto-registers point:{i} (and named) pins from the data's projected positions.
connect(from_ref, from_name, to_ref, to_name, ...)Draws a curved connector between two pins, possibly on two different charts.
annotate_at(chart_ref, pin_name, text, ...)Draws a leader-line label pointing at a pin.

Pins go stale when the geometry they were computed from changes. refill() on a chart clears its pins (so you don't silently connect to coordinates that belonged to the old content) — re-pin after refilling if you still need them. nudge/resize/move_group, on the other hand, do shift existing pins automatically, since the underlying content hasn't changed.


Reusable skeletons: template & derive

skeleton = base_canvas.template()   # strip Chart/Image elements, keep everything else
dashboard = skeleton.derive()       # deep-clone a fresh instance to fill in
dashboard.fill("main", my_chart, name="panel")

template() returns a canvas with all place()d charts and image()s removed but every decorative element (cards, gradients, titles, slots, groups, custom CSS/JS) intact — the reusable "class". derive() deep-clones any canvas (templated or not) into an independent instance — the "constructor call". Build your branded skeleton once, derive() + fill() it per dataset/variant instead of repeating layout code.


Persistence

MethodEffect
save(path)Serializes the full canvas state (elements, pins, groups, slots, custom CSS/JS) to JSON.
sp.canvas_load(path) -> CanvasRebuilds a canvas from a saved JSON file.
sp.canvas_save_named(cv, name) -> strSaves under ~/.seraplot/canvas/{name}.json and updates an index.json manifest.
sp.canvas_load_named(name) -> CanvasLoads back via that manifest.
to_json() -> strThe raw JSON string, if you want to manage storage yourself.

This is what lets a generated dashboard survive closing and reopening the app: cv.save(...) once, sp.canvas_load(...) next session reconstructs an identical canvas — positions, links, styling, everything.


Interactive dev mode

cv.dev()

Renders the canvas with a floating panel: drag any named element to move it, drag the corner handle on charts/images to resize them, hover shows the element's name and its linked group (if any). The panel's Copy Python button generates the equivalent cv.nudge(...)/cv.resize(...) calls; Download JSON exports the same deltas to a file that apply_deltas_json() can replay headlessly (cv.apply_deltas_json(open(path).read())) — the route from interactive tweaking to a reproducible script.

Canvas est la couche de composition de SeraPlot : une surface libre où l'on place plusieurs Chart construits indépendamment, des images, des formes et du texte, où on les relie entre eux, puis on exporte le tout comme un seul Chart. C'est l'outil pour construire des dashboards, des histoires annotées et des figures multi-panneaux qu'une seule fonction de chart ne peut pas produire seule.

import seraplot as sp

bar = sp.grouped_bar("", labels=[...], values=[...], series_names=[...])
cv = sp.canvas(1280, 800, "#0a0a0f")
bars_ref = cv.place(bar, 60, 60, 560, 420, name="revenue")
chart = cv.build()

Chaque méthode de placement/dessin accepte un mot-clé name optionnel. Un élément nommé reçoit un attribut data-sp-name="..." dans le HTML généré, ce qui le rend adressable par toutes les autres méthodes ci-dessous (nudge, resize, style, script, group, link, refill, le glisser-déposer du mode dev, ...). Nommer est gratuit et sans coût d'exécution — nommez tout ce que vous pourriez vouloir retoucher.


Créer un canvas

cv = sp.canvas(width: int, height: int, bg: str = "#0a0a0f")

Placer des charts et des images

MéthodeEffet
place(chart, x, y, w, h, rotation=0, opacity=1, clip="", group="", name="")Place un Chart sur le canvas à (x, y) de taille w×h. Renvoie un chart_ref (int) utilisé par pin/connect/attach_*.
image(src, x, y, w, h, rotation=0, opacity=1, clip="", group="", name="")Place une image PNG/JPEG/GIF/WebP/SVG. src est un chemin de fichier local (lu et encodé en base64), une URI data:, ou une URL http(s)://.
slot(name, x, y, w, h)Réserve une région nommée sans encore rien y placer.
fill(slot_name, chart, ...)Place un chart en utilisant la géométrie d'un slot déclaré au préalable.
grid(x, y, w, h, rows, cols, gap_x=0, gap_y=0)Déclare une grille rows × cols de slots nommés cell_{row}_{col} et renvoie la liste des noms en ordre ligne par ligne — plus de calcul de coordonnées à la main pour un dashboard.
refill(name, chart) -> boolRemplace le contenu d'un chart nommé et déjà placé, en conservant position, taille, rotation, style. À utiliser (au lieu de rappeler place/fill) chaque fois que vous rafraîchissez un panneau avec de nouvelles données.

clip accepte "circle", "diamond", "hex", "tri", "pentagon" pour un cadrage non rectangulaire du chart/de l'image.

Rappeler place/fill avec un nom déjà pris par un chart placé met à jour ce chart en place au lieu d'empiler un doublon — fill(slot, new_chart, name="panel") peut donc être rappelé sans risque.


Micro-outils : conventions communes

text, line, curve, connector, circle, ring, rect, polygon, path, arrow, annotate et gradient sont les primitives de dessin bas niveau à partir desquelles tout le reste de Canvas (y compris voronoi(), plus bas) est construit. Elles dessinent directement sur le SVG du canvas, et partagent deux mots-clés :

  • layer="fg"|"bg""bg" s'affiche sous chaque chart/image place()é, "fg" (par défaut) s'affiche au-dessus. Utilisez "bg" pour les fonds, panneaux-cartes et décorations façon filigrane ; "fg" pour les annotations, callouts et tout ce qui doit rester au-dessus des données.
  • name="" — rend l'élément adressable ensuite par nudge, resize, style, script, group, link, et déplaçable au glisser-déposer en mode dev(). Nommer est gratuit ; nommez tout ce que vous pourriez vouloir retoucher.

Aucune de ces primitives ne nécessite un Chart — un canvas ne contenant que ces primitives est une façon parfaitement valide de dessiner à la main un diagramme pour lequel SeraPlot n'a pas de fonction de chart dédiée (voir l'exemple de clôture de cette page).


Lignes, courbes & connecteurs

Quatre façons de dessiner entre des points — le choix dépend du nombre de points et de la rigidité voulue pour la forme qui les relie.

line — segment droit

cv.line(x1, y1, x2, y2, color="#ffffff", width=1.5, dash="", opacity=1.0,
         cap="round", layer="fg", hover_group="", name="")
ParamètreTypeDéfautDescription
x1, y1, x2, y2floatrequisExtrémités, en pixels canvas
colorstr"#ffffff"Couleur du trait
widthfloat1.5Épaisseur du trait
dashstr""stroke-dasharray SVG, ex. "6,4" pour un trait pointillé
opacityfloat1.00–1
capstr"round"Style d'extrémité : "round", "butt", ou "square"
hover_groupstr""Ajoute une zone de survol invisible plus large que le trait visible (souvent fin), pour que la ligne réagisse au survol en tant que membre d'un groupe link()
namestr""Nom adressable

La primitive ligne droite la plus simple — axes, séparateurs, lignes guides, ou un segment d'un diagramme construit à la main.

curve — ligne lissée passant par N points

cv.curve(points, color="#ffffff", width=1.5, opacity=1.0, tension=1.0,
          fill="none", layer="fg", name="")
ParamètreTypeDéfautDescription
pointslist[[x, y]]requisTrois points ou plus par lesquels la courbe passe
tensionfloat1.0Tension Catmull-Rom : 0 réduit la courbe à des segments droits entre les points, 1 donne une spline lissée standard, des valeurs plus hautes accentuent les bombements après chaque point
fillstr"none"Remplit la zone sous la courbe si défini — effet aire dessinée à la main
(color / width / opacity / layer / name — comme line)

Contrairement à connector (ci-dessous), qui relie toujours exactement deux points, curve interpole à travers une polyligne arbitraire de points de passage. À utiliser pour des lignes de tendance dessinées à la main, des décorations façon sparkline, ou des traits organiques libres non liés aux axes d'un Chart :

cv.curve([[40, 300], [140, 120], [260, 260], [400, 80]],
          color="#22c55e", width=3, tension=0.8, name="trend-doodle")

connector — courbe en S entre deux points

cv.connector(x1, y1, x2, y2, color="#ffffff", width=1.5, opacity=1.0,
              bend=0.5, layer="fg", name="")
ParamètreTypeDéfautDescription
bendfloat0.5Fraction, le long de l'axe dominant (celui de dx/dy le plus grand), où se placent les points de contrôle de la bézier — 0.5 donne une courbe en S symétrique ; des valeurs vers 0 ou 1 décalent le milieu de la courbe vers une extrémité
(autres — comme line)

La primitive « fil de flowchart » : une seule bézier cubique qui produit toujours un tracé propre en S ou en L entre deux points, quelle que soit leur position relative. À utiliser pour relier deux panneaux place()és ou deux éléments nommés sans calculer les points de contrôle à la main — connect() (sous Connecter deux charts, plus bas) trace exactement la même courbe, mais lit ses extrémités depuis des pins enregistrés plutôt que des coordonnées brutes.

arrow — ligne directionnelle avec pointe de flèche

cv.arrow(x1, y1, x2, y2, color="#ffffff", width=1.5, head_size=4.0,
          opacity=1.0, layer="fg", name="")
ParamètreTypeDéfautDescription
head_sizefloat4.0Taille de la pointe en px — le marqueur suit cette valeur, pas width
(autres — comme line)

Une line avec une pointe de flèche SVG (<marker>) ajoutée à son extrémité, pour pointer vers quelque chose plutôt que simplement relier deux points.


Formes

Cinq façons de remplir ou tracer une région, de la plus contrainte à la plus libre.

circle / ring

cv.circle(cx, cy, r, fill="none", stroke="#ffffff", stroke_width=1.5,
           opacity=1.0, layer="fg", hover_group="", name="")
cv.ring(cx, cy, inner_r, outer_r, fill="#ffffff", stroke="none",
         stroke_width=0.0, opacity=1.0, layer="fg", name="")

ring est un anneau (donut) : la région remplie strictement entre inner_r et outer_r, construite à partir de deux arcs combinés avec fill-rule="evenodd" plutôt qu'un <circle> plein. À utiliser pour des anneaux de progression radiale, des cadres d'avatar, ou des halos de mise en valeur — partout où le disque plein de circle masquerait ce qu'il y a en dessous.

rect

cv.rect(x, y, w, h, fill="none", stroke="#ffffff", stroke_width=1.5,
         rx=0.0, opacity=1.0, rotation=0.0, layer="fg", name="")

rx arrondit les coins ; rotation (en degrés) fait pivoter le rectangle autour de son propre centre. Les deux ensemble couvrent les fonds de carte, badges/puces, et échantillons de légende de catégorie.

polygon

cv.polygon(points, fill="none", stroke="#ffffff", stroke_width=1.5,
            opacity=1.0, layer="fg", name="")

Une forme fermée à travers une liste arbitraire list[[x, y]] de sommets — la primitive à partir de laquelle voronoi() elle-même est construite (chaque cellule qu'elle renvoie est un appel polygon() en coulisses). À utiliser directement pour des marqueurs triangulaires/en losange, des formes de badge personnalisées, ou toute région fermée que rect/circle ne peuvent pas exprimer.

path

cv.path(d, fill="none", stroke="#ffffff", stroke_width=1.5, opacity=1.0,
          layer="fg", name="")

L'échappatoire : d est une chaîne de données de chemin SVG brute ("M ... L ... A ... Z") pour les formes qu'aucune autre primitive ne couvre — logos, icônes, arcs avec un balayage spécifique, ou géométrie calculée par votre propre code. C'est exactement ainsi que la variante "radial" d'icicle() dessine ses secteurs annulaires en interne : des chaînes M/A/L/Z construites à la main, sans primitive d'arc séparée.


Texte & annotations

text

cv.text(content, x, y, size=24.0, color="#ffffff", weight="normal",
          anchor="start", rotation=0.0, letter_spacing=0.0,
          font="sans-serif", opacity=1.0, layer="fg", name="")

anchor est le text-anchor SVG ("start", "middle", "end") relatif à (x, y)"middle" centre un titre au-dessus d'un panneau, "end" aligne une valeur à droite le long d'un axe.

annotate — étiquette avec ligne de rappel

cv.annotate(text, ax, ay, tx, ty, color="#ffffff", size=13.0,
             line_dash="", line_width=1.0, bg="", layer="fg", name="")
ParamètreTypeDéfautDescription
ax, ayfloatrequisLe point annoté — où commence la ligne de rappel
tx, tyfloatrequisOù se trouve le texte lui-même — où finit la ligne de rappel
textstrrequisSupporte \n pour des étiquettes multi-lignes
line_dashstr""Motif de tirets pour la ligne de rappel, ex. "4,3"
bgstr""Couleur de fond derrière le texte ; ""/"none" ne dessine aucun cadre

Contrairement à une paire text() + line(), annotate() route automatiquement un coude propre en deux segments entre (ax, ay) et (tx, ty) (le point de coude choisi selon l'axe ayant le plus grand écart) et dimensionne son propre cadre de fond pour s'ajuster au texte. L'outil pour « ce point précis, étiqueté, avec une ligne d'appel » — le pic d'une barre, un point aberrant sur un scatter. annotate_at() (sous Connecter deux charts, plus bas) est la version « pin-aware » de cette même primitive, pour étiqueter un point à l'intérieur d'un chart place()é plutôt qu'une coordonnée canvas brute.


Couleur : gradient

cv.gradient(id, from_color, to_color, x1=0.0, y1=0.0, x2=1.0, y2=0.0)

Enregistre une définition linearGradient SVG — x1/y1/x2/y2 vivent dans l'espace objectBoundingBox 0..1, donc (0,0)→(1,0) va de gauche à droite et (0,0)→(0,1) de haut en bas. Ne dessine rien par elle-même ; appelez-la une fois, puis référencez fill=f"url(#{id})" sur n'importe quel rect/circle/polygon/path suivant :

cv.gradient("card-glow", "#6366f1", "#0a0a0f", x1=0, y1=0, x2=0, y2=1)
cv.rect(40, 40, 300, 200, fill="url(#card-glow)", rx=18, name="card")

Composer les micro-outils : un cadran radial

Aucune des primitives ci-dessus n'a besoin d'un Chart — un canvas construit uniquement à partir d'elles est une façon parfaitement valide de dessiner à la main un widget pour lequel SeraPlot n'a pas de fonction de chart dédiée. ring ne dessine jamais qu'un anneau complet, donc un cadran de progression à balayage partiel nécessite path avec un arc SVG calculé à la main — exactement le rôle d'« échappatoire » décrit plus haut :

import math
import seraplot as sp

def arc_path(cx, cy, r, pct):
    start = -math.pi / 2
    end = start + 2 * math.pi * pct
    x1, y1 = cx + r * math.cos(start), cy + r * math.sin(start)
    x2, y2 = cx + r * math.cos(end), cy + r * math.sin(end)
    large_arc = 1 if pct > 0.5 else 0
    return f"M {x1:.2f},{y1:.2f} A {r},{r} 0 {large_arc},1 {x2:.2f},{y2:.2f}"

cv = sp.Canvas(300, 300, bg="#0a0a0f")
cv.gradient("dial-g", "#6366f1", "#22d3ee", x1=0, y1=0, x2=1, y2=1)
cv.ring(150, 150, 100, 112, fill="#1e293b", name="track")
cv.path(arc_path(150, 150, 106, 0.72), fill="none", stroke="url(#dial-g)",
         stroke_width=12, name="progress")
cv.text("72%", 150, 158, size=34, color="#f8fafc", weight="800",
          anchor="middle", name="pct-label")
chart = cv.build()

ring dessine la piste de fond statique, path dessine par-dessus l'arc de progression réel (tracé avec le gradient défini juste avant), et text centre le nombre — trois primitives issues de trois sections différentes ci-dessus, une seule jauge autonome.

Le arc_path codé à la main ci-dessus, c'est exactement ce que font arc/wedge en interne — utilisez-les en premier ; path reste l'échappatoire pour les formes qu'aucun des deux ne couvre.


Dessin radial : arc, wedge, ribbon, polar

arc, wedge, ribbon, polar et radial_gradient partagent une convention d'angle : degrés, 0° en haut, croissant dans le sens horaire — la même convention que les charts pie/donut/gauge, pour que les compositions radiales se lisent de la même façon.

MéthodeEffet
arc(cx, cy, r, start_deg, end_deg, color="#ffffff", width=1.5, opacity=1, cap="round", layer="fg", name="")Un arc de cercle tracé — rayons, anneaux de progression, graduations radiales.
wedge(cx, cy, r_inner, r_outer, start_deg, end_deg, fill="#ffffff", stroke="none", stroke_width=0, opacity=1, layer="fg", name="")Un segment d'anneau rempli ; r_inner=0 le réduit à une part de camembert. La brique de base des barres radiales — une wedge par barre, r_outer mappé sur la valeur.
ribbon(cx, cy, r, a_start, a_end, b_start, b_end, fill="#ffffff", opacity=0.7, layer="fg", name="")Une bande courbe reliant deux plages d'arc sur le même cercle en passant par son centre — liens façon chord diagram entre catégories.
polar(cx, cy, r, deg) -> (x, y)Du calcul de coordonnées pur, sans dessin — convertit une position radiale en (x, y) pour placer n'importe quelle autre primitive (text, circle, line, un Chart placé) à un angle calculé, sans refaire la trigonométrie à la main.
radial_gradient(id, from_color, to_color, cx=0.5, cy=0.5, r=0.5)Le pendant radial de gradient — se référence pareil, fill="url(#id)", pour des lueurs et fondus centre-vers-bord.
cv = sp.canvas(600, 600, "#0a0a12")
cx, cy = 300, 300
cv.radial_gradient("glow", "#312e81", "#0a0a12", r=0.75)
cv.circle(cx, cy, 260, fill="url(#glow)", name="glow-bg")

values = [8, 15, 6, 22, 11, 18, 4, 13]
n = len(values)
for i, v in enumerate(values):
    a0 = i * 360 / n + 2
    a1 = (i + 1) * 360 / n - 2
    cv.wedge(cx, cy, 60, 60 + v * 7, a0, a1,
             fill=f"hsl({i * 360 // n}, 70%, 60%)", name=f"bar-{i}")
    lx, ly = cv.polar(cx, cy, 60 + v * 7 + 16, (a0 + a1) / 2)
    cv.text(str(v), lx, ly, size=11, color="#f8fafc", anchor="middle", name=f"lbl-{i}")

cv.ribbon(cx, cy, 58, 10, 30, 190, 210, fill="#a78bfa", opacity=0.35, name="link-a")
chart = cv.build()

C'est la même construction que les pièces radiales de visualcinnamon.com — un centre, des wedges disposées tout autour, des labels placés avec polar, et des ribbons qui traversent entre les plages. Rien ici n'est un type « radial bar chart » dédié ; ce sont les cinq primitives ci-dessus composées à la main, de la même façon que le reste de Canvas — y compris en mélangeant un Chart placé à une position calculée par polar si l'histoire le demande.


Galerie radiale : spirale, sunburst, réseau

Trois formes de plus construites à partir des mêmes primitives — aucune nouvelle API en dessous de cette ligne, juste polar, curve, wedge et connector combinés différemment à chaque fois.

Une spirale — le rayon de chaque point grandit avec son index au lieu de rester fixe, la technique derrière les pièces façon timeline-en-spirale comme Searching for Birds :

cx, cy = 300, 300
n = 60
cv = sp.canvas(600, 600, "#0a0a12")
pts = []
for i in range(n):
    deg = i * 12
    r = 20 + i * 4.2
    pts.append(list(cv.polar(cx, cy, r, deg)))
cv.curve(pts, color="#a78bfa", width=2, tension=0.8, name="spiral")
for i in range(0, n, 4):
    x, y = pts[i]
    cv.circle(x, y, 3 + (i / n) * 5, fill="#22d3ee", name=f"pt-{i}")
chart = cv.build()

Un sunburst — deux anneaux de wedge, les plages de l'anneau extérieur calculées à partir des proportions de l'anneau intérieur plutôt qu'un partage égal, pour une lecture hiérarchique « partie d'une partie d'un tout » :

cx, cy = 300, 300
cv = sp.canvas(600, 600, "#0a0a12")
groups = [("Frontend", 40), ("Backend", 35), ("Data", 25)]
subgroups = {
    "Frontend": [("React", 20), ("CSS", 12), ("A11y", 8)],
    "Backend": [("API", 18), ("Auth", 10), ("Jobs", 7)],
    "Data": [("ETL", 14), ("ML", 11)],
}

total = sum(v for _, v in groups)
cursor = 0.0
for name, v in groups:
    span = v / total * 360
    cv.wedge(cx, cy, 60, 130, cursor, cursor + span - 2, fill="#6366f1", name=f"inner-{name}")
    lx, ly = cv.polar(cx, cy, 95, cursor + span / 2)
    cv.text(name, lx, ly, size=11, color="#fff", anchor="middle", name=f"inner-lbl-{name}")

    sub_total = sum(sv for _, sv in subgroups[name])
    sub_cursor = cursor
    for sname, sv in subgroups[name]:
        sub_span = sv / sub_total * span
        cv.wedge(cx, cy, 135, 200, sub_cursor, sub_cursor + sub_span - 1,
                 fill="#22d3ee", opacity=0.85, name=f"outer-{sname}")
        lx, ly = cv.polar(cx, cy, 168, sub_cursor + sub_span / 2)
        cv.text(sname, lx, ly, size=9, color="#0a0a12", anchor="middle", name=f"outer-lbl-{sname}")
        sub_cursor += sub_span
    cursor += span
chart = cv.build()

Un réseau radial — des nœuds placés sur un cercle avec polar, des paires aléatoires reliées via le bend de connector pour une courbe douce plutôt qu'une corde droite ; la même histoire de « relations entre les choses » que raconte ribbon, dessinée nœuds-et-arêtes plutôt que bandes-et-arcs :

import random

cx, cy = 300, 300
n = 14
cv = sp.canvas(600, 600, "#0a0a12")
cv.radial_gradient("net-glow", "#1e1b4b", "#0a0a12", r=0.85)
cv.circle(cx, cy, 280, fill="url(#net-glow)", name="bg")

nodes = [cv.polar(cx, cy, 220, i * 360 / n) for i in range(n)]

edges = set()
while len(edges) < 22:
    a, b = random.sample(range(n), 2)
    edges.add((min(a, b), max(a, b)))

for a, b in edges:
    ax, ay = nodes[a]
    bx, by = nodes[b]
    cv.connector(ax, ay, bx, by, color="#4c1d95", width=1, opacity=0.5, bend=0.15, name=f"edge-{a}-{b}")

for i, (x, y) in enumerate(nodes):
    cv.circle(x, y, 8, fill="#a78bfa", stroke="#0a0a12", stroke_width=2, name=f"node-{i}")
chart = cv.build()

Composition réelle : un réseau façon RéciTAC

RéciTAC (Nadieh Bremer) est un diagramme réseau d3.js/Canvas qui organise les projets, les personnes et les résultats d'un programme de recherche en un cluster central flanqué de deux demi-cercles — les disciplines des chercheurs d'un côté, les activités/résultats de l'autre — avec de petits anneaux donut autour de chaque nœud projet encodant le mix disciplinaire de tous ceux qui y sont connectés. Rien de tout cela ne nécessite un type "graphique réseau" dédié : c'est polar pour chaque position de nœud, wedge empilés en un donut par nœud, connector pour les arêtes, et link pour que survoler un projet mette en valeur tout son voisinage — les mêmes primitives que dans chaque section ci-dessus, composées autour d'une seule idée.

import seraplot as sp

DISCIPLINES = {"Climate": "#38bdf8", "Social": "#f472b6", "Engineering": "#a3e635", "Policy": "#fbbf24"}
RESEARCHERS = [("Amara", "Climate"), ("Lian", "Climate"), ("Devi", "Social"),
               ("Noah", "Social"), ("Jamal", "Engineering"), ("Elin", "Policy")]
ACTIVITIES = ["Workshops", "Sensors", "Policy Brief", "Dataset", "Exhibition"]
PROJECTS = [
    ("Coastal Lab", [0, 1, 3, 5], [0, 1]),
    ("Urban Heat", [1, 2, 4], [1, 3]),
    ("Youth Climate", [2, 3, 5], [2, 4]),
]

cx, cy = 450, 450
cv = sp.Canvas(900, 900)
cv.radial_gradient("bg", "#141b2e", "#05070d", cx=0.5, cy=0.46, r=0.75)
cv.rect(0, 0, 900, 900, fill="url(#bg)", layer="bg")

left = [cv.polar(cx, cy, 340, 210 + i * 25) for i in range(len(RESEARCHERS))]
right = [cv.polar(cx, cy, 340, 30 + i * 25) for i in range(len(ACTIVITIES))]
proj_pos = [cv.polar(cx, cy, 150, i * 360 / len(PROJECTS)) for i in range(len(PROJECTS))]

for i, (name, disc) in enumerate(RESEARCHERS):
    x, y = left[i]
    cv.circle(x, y, 8, fill=DISCIPLINES[disc], stroke="#0b0e18", stroke_width=2, name=f"res{i}")

for i, name in enumerate(ACTIVITIES):
    x, y = right[i]
    cv.rect(x - 6, y - 6, 12, 12, fill="#e2e8f0", rotation=45, name=f"act{i}")

for pi, (name, r_idx, a_idx) in enumerate(PROJECTS):
    px, py = proj_pos[pi]
    for ri in r_idx:
        rx, ry = left[ri]
        cv.connector(rx, ry, px, py, color=DISCIPLINES[RESEARCHERS[ri][1]], width=1.2, opacity=0.35, bend=0.2)
    for ai in a_idx:
        ax, ay = right[ai]
        cv.connector(px, py, ax, ay, color="#64748b", width=1, opacity=0.3, bend=0.2)

    counts = {}
    for ri in r_idx:
        counts[RESEARCHERS[ri][1]] = counts.get(RESEARCHERS[ri][1], 0) + 1
    start = 0.0
    for d, count in counts.items():
        end = start + count / len(r_idx) * 360
        cv.wedge(px, py, 34, 42, start, end, fill=DISCIPLINES[d])
        start = end
    cv.circle(px, py, 30, fill="#111827", stroke="#f8fafc", stroke_width=2, name=f"proj{pi}")
    cv.text(name, px, py + 4, size=11, color="#f8fafc", weight="600", anchor="middle")

    members = [f"proj{pi}"] + [f"res{ri}" for ri in r_idx] + [f"act{ai}" for ai in a_idx]
    cv.link(f"cluster{pi}", members)

chart = cv.build()

Le jeu de données ci-dessus est synthétique — l'intérêt est le motif de composition, pas un portage littéral des vraies données du programme de recherche de Nadieh (issues d'une feuille Google Sheets privée). Tout s'adapte aux données : ajouter une discipline au dict et chaque anneau donut la prend en compte automatiquement ; ajouter un chercheur à la liste d'un projet et un nouveau connecteur + une nouvelle part de donut apparaissent au prochain build().


Composer de vrais charts : un tableau de bord mission-control

place() intègre un Chart complet — pas seulement une primitive — dans un canvas, ce qui signifie que la composition canvas ne se limite pas aux formes dessinées à la main : de vrais panneaux sp.line(), sp.bar(), sp.gauge(), sp.area() peuvent être encadrés, connectés et annotés par les mêmes primitives que partout ailleurs sur cette page. Ce qui fait vraiment la différence entre "tableau de bord" et "quatre charts dans des boîtes", c'est la même astuce que le réseau RéciTAC ci-dessus : un centre partagé auquel chaque panneau se connecte. Un hub lumineux, 4 rayons colorés (connector + une ancre circle à chaque bout), chaque rayon teinté pour correspondre à son panneau via les méthodes chainables de niveau chart (palette(), gridlines(), width()/height() — voir Méthodes de graphique) appliquées avant place() :

import seraplot as sp

W, H = 1500, 1000
HX, HY, HR = 750, 500, 76

cv = sp.Canvas(W, H)
cv.radial_gradient("dashBg", "#1a2140", "#04050a", cx=0.5, cy=0.5, r=0.9)
cv.rect(0, 0, W, H, fill="url(#dashBg)", layer="bg")
cv.radial_gradient("hubGlow", "#22d3ee", "#04050a", cx=0.5, cy=0.5, r=0.5)

cv.text("Mission Control", 48, 54, size=27, color="#f8fafc", weight="800")
cv.text("Chaque panneau relié à un seul hub vivant — sp.Canvas place() + connecteurs + de vrais charts SeraPlot",
         48, 80, size=13, color="#64748b")

PALETTE = [0x6366f1, 0x22d3ee, 0xf59e0b, 0xf472b6]
HEX = [f"#{c:06x}" for c in PALETTE]
PW, PH = 600, 300
PANELS = [("trend", 60, 150, HEX[0]), ("revenue", 840, 150, HEX[1]),
          ("health", 60, 590, HEX[2]), ("incidents", 840, 590, HEX[3])]

def panel_frame(x, y, w, h, color, name):
    cv.rect(x - 16, y - 16, w + 32, h + 32, fill="#0b1022", stroke="rgba(255,255,255,.06)",
            stroke_width=1, rx=18, layer="bg", name=name)
    cv.rect(x - 16, y - 16, w + 32, 4, fill=color, rx=2, layer="bg")

for name, x, y, color in PANELS:
    panel_frame(x, y, PW, PH, color, f"panel-{name}")

trend = sp.line(labels=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"],
                  values=[820, 932, 901, 934, 1290, 1330, 1320], title="Weekly Active Users",
                 ).width(PW).height(PH).palette(PALETTE).gridlines(False).background("#0b1022")

revenue = sp.bar(labels=["Core","Cloud","API","Mobile","Support"],
                   values=[420, 680, 310, 240, 150], title="Revenue by Segment",
                  ).width(PW).height(PH).palette(PALETTE).gridlines(False).background("#0b1022")

health = sp.gauge(value=87, title="System Health").width(PW).height(PH).background("#0b1022")

incidents = sp.area(labels=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"], values=[5, 3, 6, 2, 4, 1, 2],
                      title="Open Incidents",
                     ).width(PW).height(PH).palette([PALETTE[3]]).gridlines(False).background("#0b1022")

cv.place(trend, 60, 150, PW, PH, name="chart-trend")
cv.place(revenue, 840, 150, PW, PH, name="chart-revenue")
cv.place(health, 60, 590, PW, PH, name="chart-health")
cv.place(incidents, 840, 590, PW, PH, name="chart-incidents")

ANCHORS = {"trend": (660, 300), "revenue": (840, 300), "health": (660, 700), "incidents": (840, 700)}
for name, x, y, color in PANELS:
    ax, ay = ANCHORS[name]
    cv.connector(ax, ay, HX, HY, color=color, width=2, opacity=0.55, bend=0.28, name=f"spoke-{name}")
    cv.circle(ax, ay, 6, fill=color, stroke="#04050a", stroke_width=2, name=f"anchor-{name}")
    cv.circle(ax, ay, 11, fill="none", stroke=color, stroke_width=1, opacity=0.4)

cv.circle(HX, HY, HR + 34, fill="url(#hubGlow)", opacity=0.35)
cv.ring(HX, HY, HR + 18, HR + 22, fill="#22d3ee", opacity=0.25)
cv.ring(HX, HY, HR + 6, HR + 9, fill="#22d3ee", opacity=0.45)

start = 0.0
for name, _, _, color in PANELS:
    end = start + 90
    cv.wedge(HX, HY, HR - 10, HR - 4, start, end, fill=color, opacity=0.85)
    start = end

cv.circle(HX, HY, HR - 14, fill="#0b1022", stroke="#f8fafc", stroke_width=2)
cv.text("87", HX, HY - 4, size=40, color="#22d3ee", weight="800", anchor="middle")
cv.text("SYSTEM SCORE", HX, HY + 22, size=10, color="#64748b", anchor="middle", letter_spacing=1.5)

cv.link("hub-cluster", ["anchor-trend", "anchor-revenue", "anchor-health", "anchor-incidents"])

cv.annotate("Trending up 61% since Monday", 250, 320, 250, 500, color="#94a3b8", size=12,
             line_dash="4,3", bg="#0b1022")
cv.annotate("5 open, 2 critical", 1050, 660, 1150, 500, color="#94a3b8", size=12,
             line_dash="4,3", bg="#0b1022")

chart = cv.build()

Le hub lui-même est une petite jauge radiale déguisée — 4 parts de wedge (une par panneau, dans sa couleur) à l'intérieur de deux pistes ring pulsées, construites avec exactement les mêmes primitives que le cadran "Composer les micro-outils" et les anneaux donut RéciTAC ci-dessus. Réutiliser un seul langage visuel sur chaque exemple travaillé de cette page est tout l'intérêt : les primitives ne savent pas et ne se soucient pas de dessiner un cadran de progression, un anneau de discipline, ou un hub de tableau de bord.

panel_frame() dessine une carte arrondie plus une fine bordure supérieure teintée — cette couleur d'accent est la même utilisée pour le rayon de ce panneau et son palette(), pour que l'œil relie "cette ligne est orange" à "ce panneau est orange" à "ce rayon est orange" sans légende. Le détail facile à manquer derrière tout ça : toute décoration censée se trouver derrière un chart placé (fond, cadres de panneau) a besoin de layer="bg" explicitement — le layer="fg" par défaut de rect() se dessine au-dessus des charts placés par conception (pour que connecteurs et annotations puissent les traverser), ce qui masquera silencieusement le contenu d'un panneau si celui-ci est dessiné sur la couche de premier plan.


Mises en page organiques : Voronoi

voronoi(sites, x, y, w, h, fills=None, stroke=..., stroke_width=..., opacity=...) calcule un diagramme de Voronoi borné — une cellule par site, chaque cellule étant la région plus proche de ce site que de tout autre — et ajoute chaque cellule au canvas comme un polygon() en un seul appel, en renvoyant leurs indices d'éléments pour un adressage ultérieur (groupes de survol, derive(), etc.). C'est la même technique de mise en page organique par cellules derrière des pièces éditoriales de data-journalisme comme Highly Hazardous Pesticides de Nadieh Bremer — pas besoin d'un "type de chart voronoi" tout fait, juste la primitive.

import random
cv = sp.Canvas(900, 540)
sites = [[random.uniform(30, 870), random.uniform(30, 510)] for _ in range(22)]
palette = ["#6366f1", "#ec4899", "#22c55e", "#f59e0b", "#06b6d4", "#8b5cf6", "#ef4444"]
fills = [palette[i % len(palette)] for i in range(len(sites))]
cv.voronoi(sites, 0, 0, 900, 540, fills=fills, stroke="#0d1117", stroke_width=2, opacity=0.88)

La taille des cellules suit automatiquement la densité des sites — resserrer des sites rétrécit leurs cellules, utile pour une mise en page façon treemap ("une cellule par enregistrement, colorée par catégorie, dimensionnée par densité locale") sans algorithme de packing séparé. Implémenté nativement (découpage itératif par demi-plans contre chaque autre site, aucune dépendance de géométrie externe).


CSS / JS custom

MéthodeEffet
style(name, css)Injecte [data-sp-name="name"]{ css } dans le <style> du canvas. Passer name="" pour injecter un bloc CSS brut non scopé (ex. @keyframes).
script(js)Ajoute un <script>js</script> brut avant </body> — contrôle manuel complet pour qui veut écrire son interactivité à la main.

Groupes et liaison inter-plot

Deux mécanismes distincts, tous deux pilotés par les noms d'éléments :

group(group_name, member_names) / move_group(group_name, dx, dy) — déplace plusieurs éléments nommés ensemble comme un bloc rigide. nudge(name, dx, dy) et resize(name, dw, dh) font pareil pour un seul élément. Les pins enregistrés sur un chart avant un déplacement/redimensionnement sont automatiquement décalés avec lui.

link(group_name, member_names) -> int — relie des éléments à travers des panneaux différents en un seul groupe de survol : survoler n'importe quel élément lié (Chart, Rect, Text ou Circle) fait briller/pulser tous les autres du même groupe. Renvoie le nombre de noms effectivement liables (Line, RawPath et autres types purement décoratifs ne le supportent pas encore).

cv.link("story", ["revenue_chart", "trend_chart", "kpi_card"])

Connecter deux charts (pins)

Les pins sont des points d'ancrage nommés enregistrés dans l'espace de coordonnées d'un chart placé, en coordonnées pixel du canvas. connect()/annotate_at() lisent les pins pour tracer une ligne ou une étiquette entre (ou par-dessus) des charts.

MéthodeEffet
pin(chart_ref, name, local_x, local_y)Enregistre un pin à une coordonnée pixel locale au chart.
pin_frac(chart_ref, name, fx, fy)Enregistre un pin à une position fractionnaire (0..1) de la taille native du chart.
`pin_xy(chart_ref, name) -> (x, y)None`
attach_bar(chart_ref, values, chart_w, chart_h, ...)Enregistre automatiquement les pins bar:{i}:top/center/bottom/left/right en lisant les rectangles de barres réellement rendus.
attach_scatter(chart_ref, x_vals, y_vals, labels, chart_w, chart_h, ...)Enregistre automatiquement les pins point:{i} (et nommés) à partir des positions projetées des données.
connect(from_ref, from_name, to_ref, to_name, ...)Trace un connecteur courbe entre deux pins, éventuellement sur deux charts différents.
annotate_at(chart_ref, pin_name, text, ...)Trace une étiquette avec ligne de rappel pointant vers un pin.

Les pins deviennent obsolètes quand la géométrie qui les a produits change. refill() sur un chart efface ses pins (pour ne pas connecter silencieusement vers des coordonnées appartenant à l'ancien contenu) — re-pinnez après un refill si vous en avez encore besoin. nudge/resize/ move_group, en revanche, décalent bien les pins existants automatiquement, puisque le contenu sous-jacent n'a pas changé.


Squelettes réutilisables : template & derive

skeleton = base_canvas.template()   # retire les Chart/Image, garde le reste
dashboard = skeleton.derive()       # clone profond d'une instance prête à remplir
dashboard.fill("main", my_chart, name="panel")

template() renvoie un canvas dont tous les charts place()és et images image()ées sont retirés, mais où chaque élément décoratif (cartes, dégradés, titres, slots, groupes, CSS/JS custom) reste intact — la "classe" réutilisable. derive() clone en profondeur n'importe quel canvas (templatisé ou non) en une instance indépendante — "l'instanciation". Construisez votre squelette de marque une fois, puis derive() + fill() par jeu de données/variante au lieu de répéter le code de mise en page.


Persistance

MéthodeEffet
save(path)Sérialise tout l'état du canvas (éléments, pins, groupes, slots, CSS/JS custom) en JSON.
sp.canvas_load(path) -> CanvasReconstruit un canvas depuis un fichier JSON sauvegardé.
sp.canvas_save_named(cv, name) -> strSauvegarde sous ~/.seraplot/canvas/{name}.json et met à jour un manifeste index.json.
sp.canvas_load_named(name) -> CanvasRecharge via ce manifeste.
to_json() -> strLa chaîne JSON brute, pour gérer soi-même le stockage.

C'est ce qui permet à un dashboard généré de survivre à la fermeture et à la réouverture de l'application : cv.save(...) une fois, sp.canvas_load(...) à la session suivante reconstruit un canvas identique — positions, liens, style, tout.


Mode dev interactif

cv.dev()

Rend le canvas avec un panneau flottant : glissez n'importe quel élément nommé pour le déplacer, glissez la poignée en coin des charts/images pour les redimensionner, le survol affiche le nom de l'élément et son groupe lié (le cas échéant). Le bouton Copy Python du panneau génère les appels cv.nudge(...)/cv.resize(...) équivalents ; Download JSON exporte les mêmes deltas dans un fichier que apply_deltas_json() peut rejouer sans interface (cv.apply_deltas_json(open(path).read())) — le chemin entre ajustement interactif et script reproductible.

Web App (sp.App)

sp.App is a small, dependency-free reactive dashboard server built directly into the Rust core — no Flask, no Dash, no Node. .serve() spins up a Tokio-based HTTP + WebSocket server (hand-rolled HTTP/1.1 parsing and RFC 6455 framing, no external web framework) that pushes live UI updates to the browser whenever a registered callback re-runs.

import seraplot as sp

def on_change(period):
    values = {"7d": [12, 19, 15], "30d": [40, 55, 38]}[period]
    chart = sp.line("Sales", labels=["A", "B", "C"], values=values)
    return chart  # .html is extracted automatically

app = sp.App("Sales Dashboard")
app.dropdown("period", ["7d", "30d"], value="7d")
app.chart("out", sp.line("Sales", labels=["A", "B", "C"], values=[12, 19, 15]).html)
app.add_callback(inputs=["period"], output="out", handler=on_change)
app.serve(port=8787)

Open http://127.0.0.1:8787/ — changing the dropdown re-runs on_change server-side and pushes the new chart HTML into the page without a reload.

How it works

  1. App(title) creates a single-page app state with an implicit "/" page. .page(path, title=None) registers/switches to additional pages; every component call after it attaches to that page until the next .page().
  2. Component builders (dropdown, slider, button, text_input, checkbox, chart) render server-side HTML for that widget, register its initial value, and append it to the current page's layout. All of them return self, so calls chain.
  3. .add_callback(inputs, output, handler) wires a Python callable: whenever any component whose id is in inputs changes, handler is invoked with the current value of every input, typed to its componentfloat for a slider, bool for a checkbox, str for everything else — positionally, in the order given to inputs. Its return value becomes the new HTML for output — either a raw string, or any object exposing an .html attribute (a Chart works directly, no .html access needed on the caller's side).
  4. .interval(seconds, output, handler) wires a Python callable that fires on a server-side timer instead of a client event — no arguments, same return contract as a callback. .push(id, html) sets a component's HTML and broadcasts it to every connected browser immediately, from outside any callback (e.g. from a background thread). Both bypass the request/response cycle: they reach the browser over the same open WebSocket, unprompted.
  5. Each browser tab that opens /ws gets its own session — input values are tracked per connection, so two tabs moving the same-id slider don't clobber each other's callback inputs.
  6. .auth(username, password) gates every request (page loads and the /ws upgrade) behind HTTP Basic Auth; omit it and the app stays open.
  7. .serve(port=8787, host="127.0.0.1") blocks and starts the server. The browser opens a WebSocket to /ws; every input interaction sends {"type":"event","id":...,"value":...}, the server re-runs matching callbacks and pushes back {"type":"update","id":...,"html":...} — the same message an .interval() tick or a .push() call sends — and a ~15-line bootstrap script does document.getElementById(id).innerHTML = html — no virtual DOM, no client-side framework.

Component reference

MethodSignatureNotes
App(title="SeraPlot App")constructor
.page(path, title=None)(str, str | None)Creates the page on first call, switches the "current page" on every call
.dropdown(id, options, value=None)(str, list[str], str | None)Defaults to options[0] if value omitted
.slider(id, min, max, step=1.0, value=None)(str, float, float, float, float | None)Defaults to min if value omitted
.button(id, label)(str, str)Emits value "click" on press
.text_input(id, value="", placeholder="")(str, str, str)
.checkbox(id, label, checked=False)(str, str, bool)Emits "true"/"false"
.chart(id, html="")(str, str)Registers an output slot; typically seeded with a Chart.html and refreshed via a callback or .push()
.add_callback(inputs, output, handler)(list[str], str, Callable)handler receives one positional argument per entry in inputs, typed to its component (float/bool/str)
.interval(seconds, output, handler)(float, str, Callable)handler takes no arguments; fires on a repeating server-side timer, independent of any client event
.push(id, html)(str, str | Chart)Sets id's HTML and broadcasts it to every open connection immediately
.auth(username, password)(str, str)Gates every request behind HTTP Basic Auth
.serve(port=8787, host="127.0.0.1")(int, str)Blocking call

sp.App est un petit serveur de tableau de bord réactif, sans dépendance, intégré directement au cœur Rust — pas de Flask, pas de Dash, pas de Node. .serve() démarre un serveur HTTP + WebSocket basé sur Tokio (parsing HTTP/1.1 et trames RFC 6455 écrits à la main, sans framework web externe) qui pousse les mises à jour de l'interface vers le navigateur à chaque nouvelle exécution d'un callback enregistré.

import seraplot as sp

def on_change(period):
    values = {"7d": [12, 19, 15], "30d": [40, 55, 38]}[period]
    chart = sp.line("Ventes", labels=["A", "B", "C"], values=values)
    return chart  # .html est extrait automatiquement

app = sp.App("Tableau de bord Ventes")
app.dropdown("period", ["7d", "30d"], value="7d")
app.chart("out", sp.line("Ventes", labels=["A", "B", "C"], values=[12, 19, 15]).html)
app.add_callback(inputs=["period"], output="out", handler=on_change)
app.serve(port=8787)

Ouvrez http://127.0.0.1:8787/ — changer le menu déroulant relance on_change côté serveur et pousse le nouveau HTML du graphique dans la page sans rechargement.

Fonctionnement

  1. App(title) crée un état d'application avec une page implicite "/". .page(path, title=None) enregistre/bascule vers d'autres pages ; chaque appel de composant suivant s'attache à cette page jusqu'au .page() suivant.
  2. Les constructeurs de composants (dropdown, slider, button, text_input, checkbox, chart) génèrent le HTML côté serveur du widget, enregistrent sa valeur initiale et l'ajoutent à la mise en page de la page courante. Tous retournent self, donc les appels s'enchaînent.
  3. .add_callback(inputs, output, handler) relie un callable Python : dès qu'un composant dont l'id figure dans inputs change, handler est appelé avec la valeur courante de chaque input, typée selon son composantfloat pour un slider, bool pour une checkbox, str pour le reste — en positionnel, dans l'ordre de inputs. Sa valeur de retour devient le nouveau HTML de output — une chaîne brute, ou tout objet exposant un attribut .html (un Chart fonctionne directement, sans accès .html côté appelant).
  4. .interval(seconds, output, handler) relie un callable Python déclenché par un minuteur côté serveur plutôt qu'un événement client — sans argument, même contrat de retour qu'un callback. .push(id, html) fixe le HTML d'un composant et le diffuse immédiatement à toutes les connexions ouvertes, depuis l'extérieur de tout callback (par ex. depuis un thread d'arrière-plan). Les deux contournent le cycle requête/réponse : ils atteignent le navigateur sur le même WebSocket ouvert, sans sollicitation préalable.
  5. Chaque onglet de navigateur qui ouvre /ws obtient sa propre session — les valeurs des inputs sont suivies par connexion, donc deux onglets qui modifient un slider de même id ne s'écrasent pas mutuellement dans les callbacks.
  6. .auth(username, password) protège chaque requête (chargements de page et upgrade /ws) derrière une authentification HTTP Basic ; omise, l'application reste ouverte.
  7. .serve(port=8787, host="127.0.0.1") bloque et démarre le serveur. Le navigateur ouvre un WebSocket vers /ws ; chaque interaction envoie {"type":"event","id":...,"value":...}, le serveur relance les callbacks correspondants et repousse {"type":"update","id":...,"html":...} — le même message qu'envoie un tick .interval() ou un appel .push() — et un script d'amorçage d'une quinzaine de lignes fait document.getElementById(id).innerHTML = html — pas de DOM virtuel, pas de framework côté client.

Référence des composants

MéthodeSignatureRemarques
App(title="SeraPlot App")constructeur
.page(path, title=None)(str, str | None)Crée la page au premier appel, bascule la « page courante » à chaque appel
.dropdown(id, options, value=None)(str, list[str], str | None)Vaut options[0] par défaut si value omis
.slider(id, min, max, step=1.0, value=None)(str, float, float, float, float | None)Vaut min par défaut si value omis
.button(id, label)(str, str)Émet la valeur "click" au clic
.text_input(id, value="", placeholder="")(str, str, str)
.checkbox(id, label, checked=False)(str, str, bool)Émet "true"/"false"
.chart(id, html="")(str, str)Enregistre un emplacement de sortie ; généralement initialisé avec un Chart.html et rafraîchi via un callback ou .push()
.add_callback(inputs, output, handler)(list[str], str, Callable)handler reçoit un argument positionnel par entrée de inputs, typé selon son composant (float/bool/str)
.interval(seconds, output, handler)(float, str, Callable)handler ne prend aucun argument ; se déclenche sur un minuteur serveur répétitif, indépendant de tout événement client
.push(id, html)(str, str | Chart)Fixe le HTML de id et le diffuse à toutes les connexions ouvertes immédiatement
.auth(username, password)(str, str)Protège chaque requête derrière une authentification HTTP Basic
.serve(port=8787, host="127.0.0.1")(int, str)Appel bloquant

SeraML

Description

Machine learning API generated from Rust model and function decorators.

Registry

Description

API machine learning generee depuis les decorateurs Rust des modeles et fonctions.

Registre

Clustering

Description

Clustering functions registered in the ML bindings.

Description

Fonctions de clustering enregistrees dans les bindings ML.

K-Means

Description

K-Means fit-predict JSON API.

API Reference

Description

API JSON fit-predict K-Means.

Reference API

KMeans Class

Signature

model = sp.KMeans(
    k=3,
    max_iter=300,
    tol=1e-4,
    mini_batch=False,
    batch_size=1000,
    n_init=10,
)

model.fit(x: list[list[float]]) -> None
model.fit_predict(x: list[list[float]]) -> list[int]
model.predict(x: list[list[float]]) -> list[int]
model.transform(x: list[list[float]]) -> list[list[float]]

model.labels_     -> list[int]
model.centroids_  -> list[list[float]]
model.inertia_    -> float
model.n_iter_     -> int
model.n_clusters  -> int

Description

High-performance K-Means class for N-dimensional data with a scikit-learn-compatible API.


Constructor Parameters

ParameterTypeDefaultDescription
kint3Number of clusters
max_iterint300Maximum EM iterations
tolfloat1e-4Convergence tolerance on inertia delta
mini_batchboolFalseForce mini-batch mode
batch_sizeint1000Mini-batch sample size
n_initint10Number of times to run with different seeds (best inertia is kept)

Methods

fit(x)

Runs K-Means on the N-D data. Populates labels_, centroids_, and inertia_.

ArgumentTypeDescription
xlist[list[float]]Data matrix (rows = samples, cols = features)

fit_predict(x) -> list[int]

Equivalent to fit(x) then returning labels_.

predict(x) -> list[int]

Assign new samples to the nearest centroid (does not refit).

transform(x) -> list[list[float]]

Return Euclidean distance from each sample to each centroid (shape: n_samples × k).


Attributes

AttributeTypeDescription
labels_list[int]Cluster index per point (0-based)
centroids_list[list[float]]Final centroid coordinates (k × dims)
inertia_floatSum of squared distances to assigned centroids
n_iter_intNumber of iterations run
n_clustersintEffective number of clusters found
kintRequested k

Examples

Basic N-D clustering

import seraplot as sp
import random

random.seed(42)
centers = [(-2, -2, 0), (2, -2, 0), (0, 2, 1)]
data = [[cx + random.gauss(0, 0.4), cy + random.gauss(0, 0.4), cz + random.gauss(0, 0.3)]
        for cx, cy, cz in centers for _ in range(300)]

model = sp.KMeans(k=3)
labels = model.fit_predict(data)

print(f"Clusters: {model.n_clusters}")
print(f"Inertia: {model.inertia_:.2f}")
print(f"Centroids: {model.centroids_}")

Combine class + chart

import seraplot as sp
import random

random.seed(0)
pts = [(random.gauss(cx, 0.3), random.gauss(cy, 0.3))
       for cx, cy in [(0,0),(3,0),(1.5,2.5)] for _ in range(500)]
x, y = zip(*pts)

model = sp.KMeans(k=3)
labels = model.fit_predict([[xi, yi] for xi, yi in zip(x, y)])

# Build chart with known labels
chart = sp.kmeans(
    title="K-Means Result",
    x_values=list(x),
    y_values=list(y),
    k=3,
)
chart.show()
print(f"Inertia: {model.inertia_:.4f}")

Distance transform

import seraplot as sp

data = [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0], [0.0, 0.0]]

model = sp.KMeans(k=2)
model.fit(data)

distances = model.transform(data)
for i, row in enumerate(distances):
    print(f"Point {i}: distances to centroids = {[f'{d:.3f}' for d in row]}")

Algorithmic Functioning

K-Means minimises the total inertia — the sum of squared distances from each point to its assigned centroid:

$$J = \sum_{i=1}^{n} \|x_i - \mu_{c(x_i)}\|^2$$

K-Means++ initialisation

The first centroid $\mu_1$ is chosen uniformly at random. Each subsequent centroid $\mu_j$ is sampled with probability proportional to $D(x)^2$ — the squared distance to the nearest already-placed centroid. This reduces the expected inertia at convergence to $O(\log k)$ of optimal.

EM iterations

  1. Assignment: $c(x_i) = \underset{k}{\arg\min}\ |x_i - \mu_k|^2$
  2. Update: $\mu_k = \dfrac{1}{|C_k|}\displaystyle\sum_{x_i \in C_k} x_i$

Iterations run until inertia delta $< $ tol or max_iter is reached.

transform(x) returns the $n \times k$ matrix of Euclidean distances from each sample to each centroid, useful for soft-assignment and feature engineering.

Description

Classe K-Means haute performance pour données N-dimensionnelles, compatible avec l'API scikit-learn. Passe automatiquement en mode mini-batch pour n > 100 000.

Constructeur

ParamètreTypeDéfautDescription
kint3Nombre de clusters
max_iterint300Nombre maximum d'itérations
tolfloat1e-4Tolérance de convergence
mini_batchboolFalseForcer le mode mini-batch
batch_sizeint1000Taille du mini-batch

Méthodes

MéthodeDescription
fit(x)Ajuste le modèle
fit_predict(x)Ajuste et retourne les labels
predict(x)Prédit les clusters
transform(x)Distances aux centroïdes

Attributs

AttributDescription
labels_Labels par point
centroids_Coordonnées des centroïdes
inertia_Inertie finale
n_iter_Nombre d'itérations

Fonctionnement algorithmique

K-Means minimise l'inertie totale — la somme des carrés des distances de chaque point à son centroïde assigné :

$$J = \sum_{i=1}^{n} \|x_i - \mu_{c(x_i)}\|^2$$

Initialisation K-Means++

Le premier centroïde $\mu_1$ est choisi de façon uniforme aléatoire. Chaque centroïde suivant $\mu_j$ est échantillonné avec une probabilité proportionnelle à $D(x)^2$ — la distance au carré au centroïde le plus proche déjà placé. Cela réduit l'inertie attendue à la convergence à $O(\log k)$ de l'optimal.

Itérations EM

  1. Affectation : $c(x_i) = \underset{k}{\arg\min}\ |x_i - \mu_k|^2$
  2. Mise à jour : $\mu_k = \dfrac{1}{|C_k|}\displaystyle\sum_{x_i \in C_k} x_i$

Les itérations tournent jusqu'à ce que le delta d'inertie passe sous tol ou que max_iter soit atteint.

transform(x) retourne la matrice $n \times k$ des distances euclidiennes de chaque échantillon à chaque centroïde, utile pour l'affectation douce et l'ingénierie de caractéristiques.

DBSCAN

Description

DBSCAN fit-predict JSON API.

API Reference

Description

API JSON fit-predict DBSCAN.

Reference API

DBSCAN 3D Chart

Signature

sp.build_dbscan_chart_3d(
    title: str,
    x: list[float],
    y: list[float],
    z: list[float],
    *,
    eps: float = 0.5,
    min_samples: int = 5,
    width: int = 900,
    height: int = 600,
    x_label: str = "X",
    y_label: str = "Y",
    z_label: str = "Z",
    bg_color: str = "#1a1a2e",
    normalize: bool = False,
    palette: list[int] | None = None,
) -> Chart

Aliases: sp.dbscan3d


Description

DBSCAN clustering in 3D — rendered via GPU WebGL. Each cluster is assigned a distinct color; noise points are grey.


Parameters

ParameterTypeDefaultDescription
titlestrrequiredChart title
xlist[float]requiredX coordinates
ylist[float]requiredY coordinates
zlist[float]requiredZ coordinates
epsfloat0.5Neighborhood radius
min_samplesint5Core point threshold
widthint900Canvas width
heightint600Canvas height
x_labelstr"X"X-axis label
y_labelstr"Y"Y-axis label
z_labelstr"Z"Z-axis label
bg_colorstr"#1a1a2e"Background color
normalizeboolFalseNormalize XYZ to [0, 1]
palettelist[int] | NoneNoneCustom cluster colors

Returns

Chart


Examples

3D clusters

import seraplot as sp
import random
def blob3d(cx, cy, cz, n=200, s=0.4):
    return [(cx+random.gauss(0,s), cy+random.gauss(0,s), cz+random.gauss(0,s))
            for _ in range(n)]
pts = blob3d(0,0,0) + blob3d(5,5,5) + blob3d(10,0,5)
x, y, z = zip(*pts)
chart = sp.build_dbscan_chart_3d(
    "3D DBSCAN",
    x_values=list(x), y_values=list(y), z_values=list(z),
    eps=1.2,
    min_samples=5,
)
const sp = require('seraplot');
import random
def blob3d(cx, cy, cz, {n: 200, s: 0.4}):
    return [(cx+random.gauss(0,s), cy+random.gauss(0,s), cz+random.gauss(0,s))
            for _ in range(n)]
const pts = blob3d(0,0,0) + blob3d(5,5,5) + blob3d(10,0,5)
x, y, z = zip(*pts)
const chart = sp.build_dbscan_chart_3d("3D DBSCAN",
list(x),
list(y),
{
    z_values: list(z),
    eps: 1.2,
    min_samples: 5
})
import * as sp from 'seraplot';
import random
def blob3d(cx, cy, cz, {n: 200, s: 0.4}):
    return [(cx+random.gauss(0,s), cy+random.gauss(0,s), cz+random.gauss(0,s))
            for _ in range(n)]
const pts = blob3d(0,0,0) + blob3d(5,5,5) + blob3d(10,0,5)
x, y, z = zip(*pts)
const chart = sp.build_dbscan_chart_3d("3D DBSCAN",
list(x),
list(y),
{
    z_values: list(z),
    eps: 1.2,
    min_samples: 5
})
▶ Live Preview

Algorithmic Functioning

DBSCAN groups points that lie in dense regions and marks isolated points as noise. It requires no prior specification of the number of clusters.

For a point $p$, its $\epsilon$-neighbourhood is:

$$N_\epsilon(p) = \{q \in D : \|p - q\| \leq \epsilon\}$$
  • Core point: $|N_\epsilon(p)| \geq \text{min_samples}$
  • Border point: reachable from a core point but not itself a core point
  • Noise point: not reachable from any core point — assigned label $-1$

The 3D variant operates identically in $\mathbb{R}^3$ — the KD-tree extends to three dimensions with SIMD-accelerated Euclidean distance $|p - q| = \sqrt{\Delta x^2 + \Delta y^2 + \Delta z^2}$.

When normalize=True, each axis is scaled to $[0, 1]$ independently before clustering, so that the scale of $z$ does not distort $\epsilon$.


Description

Clustering DBSCAN en 3D — rendu via WebGL GPU. Chaque cluster est coloré distinctement ; les points bruit sont gris.

Paramètres

ParamètreTypeDéfautDescription
titlestrrequisTitre du graphique
xlist[float]requisCoordonnées X
ylist[float]requisCoordonnées Y
zlist[float]requisCoordonnées Z
epsfloat0.5Distance maximale de voisinage
min_samplesint5Minimum de points pour une région dense
normalizeboolFalseNormaliser les variables avant le clustering

Fonctionnement algorithmique

DBSCAN regroupe les points situés dans des régions denses et marque les points isolés comme du bruit. Il ne nécessite pas de spécifier le nombre de clusters à l'avance.

Pour un point $p$, son $\epsilon$-voisinage est :

$$N_\epsilon(p) = \{q \in D : \|p - q\| \leq \epsilon\}$$
  • Point cœur : $|N_\epsilon(p)| \geq \text{min_samples}$
  • Point frontière : accessible depuis un point cœur, mais pas lui-même un point cœur
  • Point bruit : non accessible depuis aucun point cœur — label $-1$

La variante 3D fonctionne identiquement dans $\mathbb{R}^3$ — le KD-tree s'étend à trois dimensions avec un calcul de distance euclidienne $|p - q| = \sqrt{\Delta x^2 + \Delta y^2 + \Delta z^2}$ accéléré par SIMD.

Avec normalize=True, chaque axe est normalisé dans $[0, 1]$ indépendamment avant le clustering, de façon à ce que l'échelle de $z$ ne distorde pas $\epsilon$.

DBSCAN Class

API Reference

model = sp.DBSCAN(eps=0.5, min_samples=5)

model.fit(X)                 -> None
model.fit_predict(X)         -> list[int]

model.labels_                -> list[int]
model.n_clusters_            -> int
model.n_noise_               -> int

Constructor Parameters

ParameterTypeDefaultDescription
epsfloat0.5Neighborhood radius threshold $\epsilon$
min_samplesint5Minimum points to form a dense core

Methods

MethodSignatureReturnsDescription
fit(X)fit(X: list[list[float]])NoneFit DBSCAN on N-dimensional data, populates labels_, n_clusters_, n_noise_
fit_predict(X)fit_predict(X: list[list[float]])list[int]Fit and return cluster labels (convenience wrapper)

Attributes

AttributeTypeDescription
labels_list[int]Cluster label per point (-1 = noise)
n_clusters_intNumber of identified clusters (noise not counted)
n_noise_intCount of noise points (label $-1$)

Example

import seraplot as sp
import numpy as np

data = np.random.randn(100, 3)

model = sp.DBSCAN(eps=0.8, min_samples=5)
labels = model.fit_predict(data.tolist())

print(f"Clusters: {model.n_clusters_}, Noise: {model.n_noise_}")
print(f"Labels shape: {len(labels)}")

x, y, z = data[:, 0].tolist(), data[:, 1].tolist(), data[:, 2].tolist()
color_groups = [str(lbl) for lbl in labels]

chart = sp.build_dbscan_chart_3d(
    f"DBSCAN ({model.n_clusters_} clusters)",
    x, y, z,
    eps=0.8, min_samples=5,
    color_groups=color_groups
)

Algorithmic Functioning

DBSCAN (Density-Based Spatial Clustering of Applications with Noise) groups points in dense regions and marks isolated points as noise.

Core concepts — for point $p$:

  • $\epsilon$-neighborhood: $N_\epsilon(p) = {q \in D : |p - q|_2 \leq \epsilon}$
  • Core point: $|N_\epsilon(p)| \geq \text{min_samples}$
  • Border point: not core, but within $\epsilon$ of a core point
  • Noise point: not reachable from any core point → label $-1$

Algorithm:

  1. For each unvisited point $p$:

    • If $p$ is core, start a new cluster via BFS (expand through density-connected neighbors)
    • Otherwise, mark as noise (or leave unvisited)
  2. Clusters are maximal sets of density-connected points.

Implementation:

SeraPlot uses KD-tree for $O(\log n)$ radius queries and parallel BFS with SIMD distance acceleration. n_clusters_ counts only true clusters; noise points are excluded.

Complexity: $O(n \log n)$ average time; $O(n^2)$ worst case.



Référence API

model = sp.DBSCAN(eps=0.5, min_samples=5)

model.fit(X)                 -> None
model.fit_predict(X)         -> list[int]

model.labels_                -> list[int]
model.n_clusters_            -> int
model.n_noise_               -> int

Paramètres du constructeur

ParamètreTypeDéfautDescription
epsfloat0.5Rayon de voisinage $\epsilon$
min_samplesint5Points min pour former un cœur

Méthodes

MéthodeSignatureRetourneDescription
fit(X)fit(X: list[list[float]])NoneAjuste DBSCAN, remplit labels_, n_clusters_, n_noise_
fit_predict(X)fit_predict(X: list[list[float]])list[int]Ajuste et retourne labels

Attributs

AttributTypeDescription
labels_list[int]Label de cluster par point (-1 = bruit)
n_clusters_intNombre de clusters (bruit non compté)
n_noise_intNombre de points bruit (label $-1$)

Exemple

import seraplot as sp
import numpy as np

data = np.random.randn(100, 3)

model = sp.DBSCAN(eps=0.8, min_samples=5)
labels = model.fit_predict(data.tolist())

print(f"Clusters: {model.n_clusters_}, Bruit: {model.n_noise_}")

x, y, z = data[:, 0].tolist(), data[:, 1].tolist(), data[:, 2].tolist()
color_groups = [str(lbl) for lbl in labels]

chart = sp.build_dbscan_chart_3d(
    f"DBSCAN ({model.n_clusters_} clusters)",
    x, y, z,
    eps=0.8, min_samples=5,
    color_groups=color_groups
)

Fonctionnement algorithmique

DBSCAN groupe les points dans les régions denses et marque les points isolés comme bruit.

Concepts clés — pour un point $p$:

  • $\epsilon$-voisinage: $N_\epsilon(p) = {q \in D : |p - q|_2 \leq \epsilon}$
  • Point cœur: $|N_\epsilon(p)| \geq \text{min_samples}$
  • Point frontière: non cœur, mais dans $\epsilon$ d'un point cœur
  • Point bruit: non accessible depuis aucun point cœur → label $-1$

Algorithme:

  1. Pour chaque point $p$ non visité:

    • Si $p$ est cœur, démarrer cluster via BFS
    • Sinon, marquer comme bruit
  2. Les clusters sont ensembles maximaux de points densément connexes.

Implémentation:

SeraPlot utilise KD-tree pour $O(\log n)$ requêtes de rayon et BFS parallèle avec accélération SIMD. n_clusters_ ne compte que vrais clusters; bruit exclu.

Complexité: $O(n \log n)$ en moyenne; $O(n^2)$ pire cas.



Linear Models

Description

Linear estimators and classifiers registered in the ML bindings.

Description

Estimateurs et classifieurs lineaires enregistres dans les bindings ML.

LinearRegression

Description

Ordinary Least Squares linear regression from the Rust ML implementation.

API Reference

Description

Regression lineaire OLS depuis l implementation ML Rust.

Reference API

Ridge / RidgeClassifier

Description

Ridge regression and ridge classifier APIs.

API Reference

Description

APIs Ridge regression et Ridge classifier.

Reference API

Lasso

Description

L1-regularized linear regression API.

API Reference

Description

API de regression lineaire regularisee L1.

Reference API

ElasticNet

Description

ElasticNet regression API.

API Reference

Description

API de regression ElasticNet.

Reference API

LogisticRegression

Description

Logistic regression classifier API.

API Reference

Description

API du classifieur de regression logistique.

Reference API

SGDClassifier / SGDRegressor

Description

Stochastic-gradient linear classifier and regressor APIs.

API Reference

Description

APIs classifieur et regresseur lineaires par gradient stochastique.

Reference API

Tree-Based Models

Description

Tree ensembles and CART-based models registered in the ML bindings.

Description

Ensembles d arbres et modeles bases CART enregistres dans les bindings ML.

DecisionTree

Description

Decision tree classifier and regressor APIs.

API Reference

Description

APIs arbre de decision classifieur et regresseur.

Reference API

RandomForest

Description

Random forest classifier and regressor APIs.

API Reference

Description

APIs random forest classifieur et regresseur.

Reference API

GradientBoosting

Description

Gradient boosting classifier and regressor APIs.

API Reference

Description

APIs gradient boosting classifieur et regresseur.

Reference API

AdaBoost

Description

AdaBoost classifier and regressor APIs.

API Reference

Description

APIs AdaBoost classifieur et regresseur.

Reference API

Neighbors

Description

Nearest-neighbor estimators registered in the ML bindings.

Description

Estimateurs par plus proches voisins enregistres dans les bindings ML.

KNN / NearestCentroid

Description

Nearest-neighbor classifier, regressor and centroid classifier APIs.

API Reference

Description

APIs classifieur, regresseur et centroide par voisins.

Reference API

Naive Bayes

Description

Naive Bayes estimators registered in the ML bindings.

Description

Estimateurs Naive Bayes enregistres dans les bindings ML.

Naive Bayes

Description

Gaussian, Multinomial and Bernoulli Naive Bayes APIs.

API Reference

Description

APIs Naive Bayes gaussien, multinomial et Bernoulli.

Reference API

SVM

Description

Linear SVM estimators registered in the ML bindings.

Description

Estimateurs SVM lineaires enregistres dans les bindings ML.

LinearSVC / LinearSVR

Description

Linear support-vector classifier and regressor APIs.

API Reference

Description

APIs SVM lineaire classifieur et regresseur.

Reference API

Preprocessing

Description

Preprocessing transformers registered in Rust.

Description

Transformers de preprocessing enregistres en Rust.

Preprocessing

Description

Scaler and transformer APIs exposed by the preprocessing bindings.

API Reference

Description

APIs scalers et transformers exposees par les bindings preprocessing.

Reference API

Advanced Preprocessing

API Reference

Signatures

imp  = sp.SimpleImputer(strategy="mean", fill_value=0.0)
poly = sp.PolynomialFeatures(degree=2, interaction_only=False, include_bias=True)
kbd  = sp.KBinsDiscretizer(n_bins=5, strategy="quantile")
pt   = sp.PowerTransformer(method="yeo-johnson")
qt   = sp.QuantileTransformer(n_quantiles=1000, output_distribution="uniform")

ohe  = sp.OneHotEncoder()
ord_ = sp.OrdinalEncoder()

est.fit(X)
Xt = est.transform(X)              -> ndarray
Xt = est.fit_transform(X)          -> ndarray

SimpleImputer

ParameterTypeDefaultDescription
strategystr"mean""mean", "median", "most_frequent", "constant"
fill_valuefloat0.0Value used when strategy is "constant"

Attribute: statistics_ : list[float] — fitted per-column value used to fill missing entries (NaN/±inf).

PolynomialFeatures

ParameterTypeDefaultDescription
degreeint2Maximum total degree
interaction_onlyboolFalseDrop pure powers (no $x_i^2$)
include_biasboolTruePrepend a column of ones

Attribute: n_features_out_ : int, powers_ : list[list[int]].

KBinsDiscretizer

ParameterTypeDefaultDescription
n_binsint5Bins per feature
strategystr"quantile""uniform" or "quantile"

Attribute: bin_edges_ : list[list[float]].

PowerTransformer

ParameterTypeDefaultDescription
methodstr"yeo-johnson""yeo-johnson" (any sign) or "box-cox" (positive only)

Attribute: lambdas_ : list[float]. Lambda is found by grid-searching $[-2, 2]$ and minimising variance after transform.

QuantileTransformer

ParameterTypeDefaultDescription
n_quantilesint1000Quantile knots
output_distributionstr"uniform""uniform" or "normal"

Attribute: quantiles_ : list[list[float]].

OneHotEncoder / OrdinalEncoder

fit / transform accept list[list[Any]] of strings or numbers; categories are deduced per column. Attribute: categories_ : list[list[Any]]. OneHotEncoder exposes n_features_out_.

Example — full preprocessing pipeline
import seraplot as sp
import numpy as np

rng = np.random.default_rng(0)
X = rng.normal(size=(500, 4))
X[10, 1] = np.nan
X[42, 3] = np.nan

imp  = sp.SimpleImputer(strategy="median")
poly = sp.PolynomialFeatures(degree=2, interaction_only=True, include_bias=False)
kbd  = sp.KBinsDiscretizer(n_bins=8, strategy="quantile")
pt   = sp.PowerTransformer(method="yeo-johnson")
qt   = sp.QuantileTransformer(n_quantiles=200, output_distribution="normal")

X1 = imp.fit_transform(X)
print("imputed   :", X1.shape, "stats:", imp.statistics_)
X2 = poly.fit_transform(X1)
print("poly      :", X2.shape, "n_out:", poly.n_features_out_)
X3 = kbd.fit_transform(X1)
print("discretised:", X3.shape)
X4 = pt.fit_transform(X1)
print("power     :", X4.shape, "lambdas:", pt.lambdas_)
X5 = qt.fit_transform(X1)
print("quantile  :", X5.shape, "mean ≈ 0:", X5.mean(0).round(2))
Example — categorical encoders
import seraplot as sp

rows = [["cat", "red"], ["dog", "red"], ["cat", "blue"], ["fish", "blue"]]

ohe = sp.OneHotEncoder()
print(ohe.fit_transform(rows))
print(ohe.categories_, ohe.n_features_out_)

oe = sp.OrdinalEncoder()
print(oe.fit_transform(rows))
print(oe.categories_)

Algorithmic Functioning

SimpleImputer

For each feature $j$, fit a statistic $\theta_j$ over the non-missing values ($\mathrm{NaN}$, $+\infty$, $-\infty$ are treated as missing):

$$\theta_j \in \{\mathrm{mean}_j,\; \mathrm{median}_j,\; \mathrm{mode}_j,\; \text{fill\_value}\}$$

transform replaces every missing entry with $\theta_j$.

PolynomialFeatures

Enumerates all monomials $\prod_j x_j^{a_j}$ with $\sum_j a_j \leq d$. With interaction_only=True, every $a_j \in {0, 1}$ (no pure powers). With include_bias=True, the constant 1 column is prepended.

KBinsDiscretizer

Computes per-feature bin edges:

  • uniform : $[\min, \max]$ split into $K$ equal-width intervals.
  • quantile : $[\min, q_{1/K}, q_{2/K}, \dots, \max]$ using sample quantiles.

transform returns the integer bin index in ${0, \dots, K-1}$.

PowerTransformer

Applies a parametric monotone transform to make data more Gaussian.

Yeo-Johnson (works with any sign):

$$\psi_\lambda(y) = \begin{cases} \frac{(y+1)^\lambda - 1}{\lambda} & \lambda \neq 0,\; y \geq 0 \\ \log(y+1) & \lambda = 0,\; y \geq 0 \\ -\frac{(-y+1)^{2-\lambda} - 1}{2-\lambda} & \lambda \neq 2,\; y < 0 \\ -\log(-y+1) & \lambda = 2,\; y < 0 \end{cases}$$

Box-Cox (requires $y > 0$):

$$\phi_\lambda(y) = \begin{cases} \frac{y^\lambda - 1}{\lambda} & \lambda \neq 0 \\ \log(y) & \lambda = 0 \end{cases}$$

$\lambda^*$ is selected per feature by a grid search over $[-2, 2]$ minimising the variance of the transformed feature.

QuantileTransformer

Maps each feature to a uniform $[0, 1]$ distribution via its empirical CDF, then optionally re-maps to $\mathcal{N}(0, 1)$ via the inverse normal CDF (Beasley–Springer–Moro approximation).

Categorical encoders

OneHotEncoder builds the union of observed categories per column and emits one indicator per category. OrdinalEncoder assigns each category an integer index in fit-time order.

Référence API

Signatures

imp  = sp.SimpleImputer(strategy="mean", fill_value=0.0)
poly = sp.PolynomialFeatures(degree=2, interaction_only=False, include_bias=True)
kbd  = sp.KBinsDiscretizer(n_bins=5, strategy="quantile")
pt   = sp.PowerTransformer(method="yeo-johnson")
qt   = sp.QuantileTransformer(n_quantiles=1000, output_distribution="uniform")

ohe  = sp.OneHotEncoder()
ord_ = sp.OrdinalEncoder()

est.fit(X)
Xt = est.transform(X)              -> ndarray
Xt = est.fit_transform(X)          -> ndarray

SimpleImputer

ParamètreTypeDéfautDescription
strategystr"mean""mean", "median", "most_frequent", "constant"
fill_valuefloat0.0Valeur utilisée si stratégie "constant"

Attribut : statistics_ : list[float] — valeur ajustée par colonne pour remplir les entrées manquantes (NaN/±inf).

PolynomialFeatures

ParamètreTypeDéfautDescription
degreeint2Degré total maximal
interaction_onlyboolFalseSupprime les puissances pures (pas de $x_i^2$)
include_biasboolTrueAjoute une colonne de uns en tête

Attribut : n_features_out_ : int, powers_ : list[list[int]].

KBinsDiscretizer

ParamètreTypeDéfautDescription
n_binsint5Nombre de classes par feature
strategystr"quantile""uniform" ou "quantile"

Attribut : bin_edges_ : list[list[float]].

PowerTransformer

ParamètreTypeDéfautDescription
methodstr"yeo-johnson""yeo-johnson" (tout signe) ou "box-cox" (positif)

Attribut : lambdas_ : list[float]. Lambda est trouvé par recherche sur grille $[-2, 2]$ minimisant la variance après transformation.

QuantileTransformer

ParamètreTypeDéfautDescription
n_quantilesint1000Nœuds de quantiles
output_distributionstr"uniform""uniform" ou "normal"

Attribut : quantiles_ : list[list[float]].

OneHotEncoder / OrdinalEncoder

fit / transform acceptent list[list[Any]] de chaînes ou de nombres ; les catégories sont déduites par colonne. Attribut : categories_ : list[list[Any]]. OneHotEncoder expose n_features_out_.

Exemple — pipeline complet
import seraplot as sp
import numpy as np

rng = np.random.default_rng(0)
X = rng.normal(size=(500, 4))
X[10, 1] = np.nan
X[42, 3] = np.nan

imp  = sp.SimpleImputer(strategy="median")
poly = sp.PolynomialFeatures(degree=2, interaction_only=True, include_bias=False)
kbd  = sp.KBinsDiscretizer(n_bins=8, strategy="quantile")
pt   = sp.PowerTransformer(method="yeo-johnson")
qt   = sp.QuantileTransformer(n_quantiles=200, output_distribution="normal")

X1 = imp.fit_transform(X)
print("imputé    :", X1.shape, "stats:", imp.statistics_)
X2 = poly.fit_transform(X1)
print("poly      :", X2.shape, "n_out:", poly.n_features_out_)
X3 = kbd.fit_transform(X1)
print("discrétisé:", X3.shape)
X4 = pt.fit_transform(X1)
print("power     :", X4.shape, "lambdas:", pt.lambdas_)
X5 = qt.fit_transform(X1)
print("quantile  :", X5.shape, "moy ≈ 0 :", X5.mean(0).round(2))
Exemple — encodeurs catégoriels
import seraplot as sp

rows = [["cat", "red"], ["dog", "red"], ["cat", "blue"], ["fish", "blue"]]

ohe = sp.OneHotEncoder()
print(ohe.fit_transform(rows))
print(ohe.categories_, ohe.n_features_out_)

oe = sp.OrdinalEncoder()
print(oe.fit_transform(rows))
print(oe.categories_)

Fonctionnement algorithmique

SimpleImputer

Pour chaque feature $j$, ajuste une statistique $\theta_j$ sur les valeurs non manquantes ($\mathrm{NaN}$, $+\infty$, $-\infty$ sont considérés comme manquants) :

$$\theta_j \in \{\mathrm{mean}_j,\; \mathrm{median}_j,\; \mathrm{mode}_j,\; \text{fill\_value}\}$$

transform remplace toute entrée manquante par $\theta_j$.

PolynomialFeatures

Énumère tous les monômes $\prod_j x_j^{a_j}$ avec $\sum_j a_j \leq d$. Avec interaction_only=True, chaque $a_j \in {0, 1}$ (pas de puissances pures). Avec include_bias=True, la colonne constante 1 est ajoutée en tête.

KBinsDiscretizer

Calcule les bornes de classes par feature :

  • uniform : $[\min, \max]$ découpé en $K$ intervalles équilarges.
  • quantile : $[\min, q_{1/K}, q_{2/K}, \dots, \max]$ via les quantiles empiriques.

transform renvoie l'index de classe entier dans ${0, \dots, K-1}$.

PowerTransformer

Applique une transformation monotone paramétrique pour rendre les données plus gaussiennes.

Yeo-Johnson (tout signe) :

$$\psi_\lambda(y) = \begin{cases} \frac{(y+1)^\lambda - 1}{\lambda} & \lambda \neq 0,\; y \geq 0 \\ \log(y+1) & \lambda = 0,\; y \geq 0 \\ -\frac{(-y+1)^{2-\lambda} - 1}{2-\lambda} & \lambda \neq 2,\; y < 0 \\ -\log(-y+1) & \lambda = 2,\; y < 0 \end{cases}$$

Box-Cox (requiert $y > 0$) :

$$\phi_\lambda(y) = \begin{cases} \frac{y^\lambda - 1}{\lambda} & \lambda \neq 0 \\ \log(y) & \lambda = 0 \end{cases}$$

$\lambda^*$ est sélectionné par feature via une recherche sur grille dans $[-2, 2]$ minimisant la variance de la feature transformée.

QuantileTransformer

Mappe chaque feature vers une distribution uniforme $[0, 1]$ via sa CDF empirique, puis optionnellement re-mappe vers $\mathcal{N}(0, 1)$ via la CDF normale inverse (approximation de Beasley–Springer–Moro).

Encodeurs catégoriels

OneHotEncoder construit l'union des catégories observées par colonne et émet un indicateur par catégorie. OrdinalEncoder attribue à chaque catégorie un index entier dans l'ordre du fit.

Decomposition

Description

Dimensionality-reduction models registered in Rust.

Description

Modeles de reduction de dimension enregistres en Rust.

PCA / TruncatedSVD

Description

Decomposition APIs exposed by the ML bindings.

API Reference

Description

APIs de decomposition exposees par les bindings ML.

Reference API

Model Selection

Description

Cross-validation, search and inspection utilities registered in ML.

Description

Utilitaires de validation croisee, recherche et inspection enregistres en ML.

GridSearchCV

Description

Grid-search cross-validation JSON API.

API Reference

Description

API JSON de recherche grille avec validation croisee.

Reference API

Cross-Validation

Description

K-Fold and cross-validation JSON APIs.

API Reference

Description

APIs JSON K-Fold et validation croisee.

Reference API

Permutation Importance

Description

Permutation importance JSON API.

API Reference

Description

API JSON permutation importance.

Reference API

IsolationForest

Description

Isolation Forest anomaly detection API.

API Reference

Description

API de detection d anomalies Isolation Forest.

Reference API

Model Registry

Description

Model persistence JSON APIs.

API Reference

Description

APIs JSON de persistance des modeles.

Reference API

PowerBI & Tableau Export

New in 2.4.34 Export

Export predictions and feature matrices directly to PowerBI Push dataset JSON or Tableau TDS/CSV — native format, no extra tooling. / Export les prédictions et matrices de features en JSON PowerBI ou TDS/CSV Tableau.

✓ PowerBI JSON ✓ Tableau TDS + CSV
PowerBI format Push dataset API compatible
Tableau format TDS + CSV data source + extract
Columns X + y + ŷ feature, target, pred
📊
export_powerbi

Returns a JSON string representing a PowerBI Push dataset. Paste into the PowerBI REST API or save to .json.

📋
export_tableau_tds

Returns a Tableau Data Source XML (.tds). Defines all columns — open in Tableau Desktop to connect instantly.

📁
export_tableau_csv

Returns a CSV string with a header row. Includes feature columns, optional target and optional predictions.

🔗
Combine with Registry

Export predictions from a registry-loaded model payload and share reproducible exports alongside versioned models.

Quick start
import seraplot as sp, numpy as np

X = np.random.randn(200, 3)
y = X[:, 0] * 2 + np.random.randn(200) * 0.1

model = sp.LinearRegression()
model.fit(X, y)
yhat = model.predict(X)

pbi_json = sp.export_powerbi(
    name   = "HousePrice",
    table  = "Predictions",
    X      = X,
    y      = list(y),
    y_pred = list(yhat),
)
with open("powerbi_dataset.json", "w") as f:
    f.write(pbi_json)

tds_xml = sp.export_tableau_tds(
    name   = "HousePrice",
    X      = X,
    y      = list(y),
    y_pred = list(yhat),
)
with open("house_price.tds", "w") as f:
    f.write(tds_xml)

csv_str = sp.export_tableau_csv(
    name   = "HousePrice",
    X      = X,
    y      = list(y),
    y_pred = list(yhat),
)
with open("house_price.csv", "w") as f:
    f.write(csv_str)

API Reference

export_powerbi
ParameterTypeDefaultDescription
namestrDataset name (appears in PowerBI)
tablestrTable name inside the dataset
Xlist[list[float]]Feature matrix, shape (n, p)
ylist[float] | NoneNoneTarget values (optional)
y_predlist[float] | NoneNonePredicted values (optional)
Returns → str — PowerBI Push dataset JSON
export_tableau_tds
ParameterTypeDefaultDescription
namestrData source name in Tableau
Xlist[list[float]]Feature matrix
ylist[float] | NoneNoneTarget values (optional)
y_predlist[float] | NoneNonePredicted values (optional)
Returns → str — Tableau TDS XML
export_tableau_csv
ParameterTypeDefaultDescription
namestrUsed as comment in header row
Xlist[list[float]]Feature matrix
ylist[float] | NoneNoneTarget values (optional)
y_predlist[float] | NoneNonePredicted values (optional)
Returns → str — CSV with header row (feat_0, feat_1, …, target, prediction)
ℹ️
Column names are auto-generated: feat_0feat_{p-1}, target, prediction. All functions return strings — write them to disk or POST them to the relevant API.

Référence API

export_powerbi
ParamètreTypeDéfautDescription
namestrNom du dataset (visible dans PowerBI)
tablestrNom de la table dans le dataset
Xlist[list[float]]Matrice de features, forme (n, p)
ylist[float] | NoneNoneValeurs cibles (optionnel)
y_predlist[float] | NoneNonePrédictions (optionnel)
Retourne → str — JSON Push dataset PowerBI
export_tableau_tds
ParamètreTypeDéfautDescription
namestrNom de la source de données dans Tableau
Xlist[list[float]]Matrice de features
ylist[float] | NoneNoneValeurs cibles (optionnel)
y_predlist[float] | NoneNonePrédictions (optionnel)
Retourne → str — XML Tableau TDS
export_tableau_csv
ParamètreTypeDéfautDescription
namestrUtilisé en commentaire dans la ligne d'en-tête
Xlist[list[float]]Matrice de features
ylist[float] | NoneNoneValeurs cibles (optionnel)
y_predlist[float] | NoneNonePrédictions (optionnel)
Retourne → str — CSV avec en-tête (feat_0, feat_1, …, target, prediction)
💡
Les colonnes sont nommées automatiquement : feat_0feat_{p-1}, target, prediction. Toutes les fonctions retournent des chaînes de caractères — écrivez-les sur disque ou envoyez-les à l'API concernée via HTTP POST.

GPU Backend

New in 2.4.34 GPU

Backend detection and selection for CUDA, Metal (Apple Silicon), ROCm and CPU. Auto-detection at runtime with zero configuration. / Détection et sélection du backend GPU/CPU — CUDA, Metal, ROCm détectés automatiquement.

✓ CUDA detected ✓ CPU always available
Backends 4 CPU · CUDA · Metal · ROCm
Detection Auto env-var + path probing
Config Zero no setup required
⚠️
EN — Current state: The default pip install seraplot wheel ships CPU-only and uses rayon multi-threading. Real GPU kernels are available through opt-in feature flags compiled from source: cargo build --features cuda, --features metal, --features rocm. The detection and selection API works in both builds.
FR — État actuel : La wheel par défaut pip install seraplot est CPU only avec multi-threading rayon. Les vrais kernels GPU sont disponibles via des feature flags opt-in compilés depuis les sources : cargo build --features cuda, --features metal, --features rocm. L'API de détection et sélection fonctionne dans les deux builds.
🔍
gpu_devices

List all detected devices with backend, name, memory and availability flag.

gpu_set_backend

Explicitly select a backend. Pass None for auto-selection (picks the first available non-CPU backend).

📍
gpu_active_backend

Returns the currently active backend name as a string.

🖥️
Detection logic

CUDA: CUDA_PATH / CUDA_HOME env vars. Metal: macOS target. ROCm: /opt/rocm path probe.

Quick start
import seraplot as sp

devices = sp.gpu_devices()
for d in devices:
    avail = "available" if d["available"] else "detected / unavailable"
    print(f"  [{d['backend']}] {d['name']}  {d['mem_mb']} MB  — {avail}")

active = sp.gpu_active_backend()
print(f"\nActive backend: {active}")

sp.gpu_set_backend("cpu")
print(f"Forced CPU: {sp.gpu_active_backend()}")

sp.gpu_set_backend(None)
print(f"Auto-select: {sp.gpu_active_backend()}")

API Reference

Functions
FunctionSignatureReturns
gpu_devices()list[dict]
gpu_set_backend(backend: str | None)str — active backend
gpu_active_backend()str
Device record schema
FieldTypeDescription
backendstr"cpu", "cuda", "metal", "rocm"
namestrHuman-readable device name
mem_mbintDevice memory in MB (0 for CPU)
availableboolTrue if the device can be used for computation
Backend string values for gpu_set_backend
ValuePlatformDetection method
"cpu"AllAlways available
"cuda"NVIDIA GPUCUDA_PATH or CUDA_HOME env var set
"metal"Apple Silicon / macOScfg!(target_os = "macos") at compile time
"rocm"AMD GPU / Linux/opt/rocm directory exists
NoneAuto-select: first non-CPU available backend
ℹ️
Setting a backend does not automatically enable GPU kernels in the current version. It records your preference so that when kernel dispatch ships in 2.5.x, your code is already correct and ready.

Référence API

Fonctions
FonctionSignatureRetourne
gpu_devices()list[dict]
gpu_set_backend(backend: str | None)str — backend actif
gpu_active_backend()str
Schéma d'un device
ChampTypeDescription
backendstr"cpu", "cuda", "metal", "rocm"
namestrNom lisible du périphérique
mem_mbintMémoire du périphérique en Mo (0 pour CPU)
availableboolTrue si le périphérique peut être utilisé
Valeurs de backend pour gpu_set_backend
ValeurPlateformeMéthode de détection
"cpu"ToutesToujours disponible
"cuda"GPU NVIDIAVariable d'env CUDA_PATH ou CUDA_HOME
"metal"Apple Silicon / macOScfg!(target_os = "macos") à la compilation
"rocm"GPU AMD / LinuxDossier /opt/rocm présent
NoneAuto : premier backend non-CPU disponible
ℹ️
Dans la version actuelle, définir un backend ne déclenche pas encore les kernels GPU. Cela enregistre votre préférence : quand le dispatch de kernels arrivera en 2.5.x, votre code sera déjà correct et prêt.

Distributed Training & Cloud Planner

New in 2.4.34 Distributed Cloud

Ray-style scatter/gather primitives backed by rayon + auto-scaling planner for datasets >1M rows. Zero infra, pure Python. / Primitives scatter/gather style Ray via rayon + planificateur auto-scaling pour jeux de données >1M lignes.

✓ WorkerPool ✓ cloud_plan
Max workers auto 0 = rayon thread count
Scatter / gather allreduce_mean / sum
Planner in_memory / chunked / streamed
🔀
WorkerPool

Create a pool, scatter rows into shards, train per shard in parallel, then allreduce results back.

📐
cloud_plan

Given n_rows × n_cols and a memory budget, produces the optimal strategy: in_memory, chunked or streamed.

📡
cloud_resources

Runtime snapshot: CPU threads, active backend, OS, architecture, registry path.

📂
cloud_count_rows

Streaming CSV row count — constant memory regardless of file size. Useful before calling cloud_plan.

Quick start — WorkerPool
import seraplot as sp, numpy as np

n_rows = 10_000
X = np.random.randn(n_rows, 5)
y = X[:, 0] * 2 + np.random.randn(n_rows) * 0.1

wp = sp.WorkerPool(n_workers=0)
print(f"Pool: {wp.n_workers} workers")

handle = wp.scatter(n_rows)
shards = wp.shards(handle)

coefs = []
for shard in shards:
    Xi = X[shard["start"]:shard["end"]]
    yi = y[shard["start"]:shard["end"]]
    model = sp.LinearRegression()
    model.fit(Xi, yi)
    coefs.append(model.coef_)

mean_coef = wp.allreduce_mean(coefs)
print(f"Aggregated coef: {mean_coef}")

wp.release(handle)
Quick start — Cloud planner
import seraplot as sp

plan = sp.cloud_plan(n_rows=5_000_000, n_cols=50, mem_budget_mb=4096)
print(f"Strategy    : {plan['strategy']}")
print(f"Workers     : {plan['recommended_workers']}")
print(f"Chunk rows  : {plan['recommended_chunk_rows']}")
print(f"Chunks      : {plan['n_chunks']}")
print(f"Est. seconds: {plan['estimated_seconds']:.1f}s")

resources = sp.cloud_resources()
print(f"\nCPU threads : {resources['cpu_threads']}")
print(f"Backend     : {resources['backend']}")
print(f"OS          : {resources['os']} / {resources['arch']}")

API Reference

WorkerPool
wp = sp.WorkerPool(n_workers=0)
Method / AttrSignatureReturnsDescription
n_workerspropertyintActual number of workers (resolved from n_workers=0 = rayon thread count)
scatter(n_rows) -> inthandlePartition n_rows rows into shards, return opaque handle
shards(handle) -> list[dict]list[dict]Get shard list for handle: [{"id":0,"start":0,"end":625}, …]
release(handle)NoneFree memory associated with the scatter handle
allreduce_mean(vecs: list[list[float]]) -> list[float]list[float]Element-wise mean across all vectors (same length)
allreduce_sum(vecs: list[list[float]]) -> list[float]list[float]Element-wise sum across all vectors
cloud_plan
ParameterTypeDefaultDescription
n_rowsintNumber of dataset rows
n_colsintNumber of feature columns
mem_budget_mbint2048Available RAM budget in MB
Returns → dict with keys: n_rows, n_cols, bytes_total, mem_budget_mb, recommended_workers, recommended_chunk_rows, n_chunks, estimated_seconds, strategy
cloud_resources
Returns → dictcpu_threads (int), backend (str), os (str), arch (str), registry_dir (str), tasks_dir (str)
cloud_count_rows
ParameterTypeDefaultDescription
pathstrPath to CSV file
chunk_rowsint100000Internal read buffer size
has_headerboolTrueSkip first line as header
delimiterstr","CSV delimiter
Returns → int — number of data rows (header excluded if has_header=True)
Strategy reference (cloud_plan)
StrategyConditionDescription
in_memoryDataset fits in budgetLoad all at once, use full parallel training
chunkedDataset > budget, <2× budget per chunkProcess in chunks, aggregate results per chunk
streamedDataset >> budgetStream rows one chunk at a time, online aggregation
ℹ️
Call cloud_count_rows(path) on your CSV file, then pass the result to cloud_plan to get the optimal strategy before loading any data into memory.

Référence API

WorkerPool
wp = sp.WorkerPool(n_workers=0)
Méthode / AttrSignatureRetourneDescription
n_workerspropriétéintNombre réel de workers (0 = nombre de threads rayon)
scatter(n_rows) -> inthandlePartitionne n_rows lignes en shards, retourne un handle opaque
shards(handle) -> list[dict]list[dict]Récupère les shards : [{"id":0,"start":0,"end":625}, …]
release(handle)NoneLibère la mémoire associée au handle scatter
allreduce_mean(vecs)list[float]Moyenne élément par élément sur tous les vecteurs
allreduce_sum(vecs)list[float]Somme élément par élément sur tous les vecteurs
cloud_plan
ParamètreTypeDéfautDescription
n_rowsintNombre de lignes du jeu de données
n_colsintNombre de colonnes de features
mem_budget_mbint2048Budget RAM disponible en Mo
Retourne → dict avec les clés : n_rows, n_cols, bytes_total, mem_budget_mb, recommended_workers, recommended_chunk_rows, n_chunks, estimated_seconds, strategy
cloud_resources
Retourne → dictcpu_threads (int), backend (str), os (str), arch (str), registry_dir (str), tasks_dir (str)
cloud_count_rows
ParamètreTypeDéfautDescription
pathstrChemin vers le fichier CSV
chunk_rowsint100000Taille du buffer de lecture interne
has_headerboolTrueIgnorer la première ligne (en-tête)
delimiterstr","Séparateur CSV
Retourne → int — nombre de lignes de données (en-tête exclu si has_header=True)
Référence des stratégies (cloud_plan)
StratégieConditionDescription
in_memoryDataset tient dans le budgetChargement complet, entraînement parallèle total
chunkedDataset > budget, <2× budget par chunkTraitement en chunks, agrégation des résultats
streamedDataset >> budgetStreaming ligne par ligne, agrégation en ligne
💡
Appelez cloud_count_rows(chemin) sur votre CSV, puis passez le résultat à cloud_plan pour obtenir la stratégie optimale avant de charger la moindre donnée en mémoire.

Metrics

Description

Metric score and curve JSON APIs.

API Reference

Description

APIs JSON de scores et courbes de metriques.

Reference API

Classification Metrics

API Reference

Signatures

sp.accuracy_score(y_true, y_pred)                                   -> float
sp.balanced_accuracy_score(y_true, y_pred)                          -> float
sp.precision_score(y_true, y_pred, average="binary", pos_label=1)   -> float
sp.recall_score(y_true, y_pred, average="binary", pos_label=1)      -> float
sp.f1_score(y_true, y_pred, average="binary", pos_label=1)          -> float
sp.fbeta_score(y_true, y_pred, beta=1.0, average="binary", pos_label=1) -> float
sp.jaccard_score(y_true, y_pred, pos_label=1)                       -> float
sp.matthews_corrcoef(y_true, y_pred)                                -> float
sp.cohen_kappa_score(y_true, y_pred)                                -> float
sp.hamming_loss(y_true, y_pred)                                     -> float
sp.zero_one_loss(y_true, y_pred)                                    -> float
sp.confusion_matrix(y_true, y_pred)                                 -> list[list[int]]
sp.classification_report(y_true, y_pred)                            -> str

sp.log_loss(y_true, y_proba, n_classes, eps=1e-15)                  -> float
sp.binary_log_loss(y_true, y_proba, eps=1e-15)                      -> float
sp.brier_score_loss(y_true, y_proba)                                -> float
sp.hinge_loss(y_true, decision)                                     -> float

sp.roc_curve(y_true, y_score, pos_label=1)                          -> (fpr, tpr, thresholds)
sp.roc_auc_score(y_true, y_score)                                   -> float
sp.precision_recall_curve(y_true, y_score, pos_label=1)             -> (precision, recall, thresholds)
sp.average_precision_score(y_true, y_score)                         -> float

Function summary

FunctionDomainOutputDescription
accuracy_scoreanyfloatFraction correct
balanced_accuracy_scoreanyfloatMean of per-class recall
precision_scorebinary / multiclassfloatTP / (TP+FP)
recall_scorebinary / multiclassfloatTP / (TP+FN)
f1_scorebinary / multiclassfloatHarmonic mean of P and R
fbeta_scorebinary / multiclassfloatF-beta with weight beta
jaccard_scorebinaryfloatIntersection over Union
matthews_corrcoefbinaryfloatPhi coefficient (range $[-1,1]$)
cohen_kappa_scoreanyfloatAgreement vs. chance
hamming_lossanyfloatFraction of wrong predictions
zero_one_lossanyfloat$1 - \text{accuracy}$
log_loss$K$-class probafloatCross-entropy
binary_log_lossbinary probafloatCross-entropy (binary)
brier_score_lossbinary probafloat$(\hat{p} - y)^2$ averaged
hinge_loss$\pm 1$ labelsfloat$\max(0, 1 - y \cdot s)$ averaged
roc_curvebinary score(fpr, tpr, thr)ROC points
roc_auc_scorebinary scorefloatArea under ROC
precision_recall_curvebinary score(p, r, thr)PR points
average_precision_scorebinary scorefloatArea under PR curve

average accepts "binary", "macro", "weighted".

Example — full classification report
import seraplot as sp
import numpy as np

rng = np.random.default_rng(0)
y_true = rng.integers(0, 2, size=200).tolist()
y_score = rng.uniform(size=200).tolist()
y_pred  = [1 if s >= 0.5 else 0 for s in y_score]

print("accuracy           :", sp.accuracy_score(y_true, y_pred))
print("balanced_accuracy  :", sp.balanced_accuracy_score(y_true, y_pred))
print("precision          :", sp.precision_score(y_true, y_pred))
print("recall             :", sp.recall_score(y_true, y_pred))
print("f1                 :", sp.f1_score(y_true, y_pred))
print("f2                 :", sp.fbeta_score(y_true, y_pred, beta=2.0))
print("matthews_corrcoef  :", sp.matthews_corrcoef(y_true, y_pred))
print("cohen_kappa        :", sp.cohen_kappa_score(y_true, y_pred))
print("jaccard            :", sp.jaccard_score(y_true, y_pred))
print("hamming_loss       :", sp.hamming_loss(y_true, y_pred))
print("zero_one_loss      :", sp.zero_one_loss(y_true, y_pred))

print("brier              :", sp.brier_score_loss(y_true, y_score))
print("binary_log_loss    :", sp.binary_log_loss(y_true, y_score))
print("roc_auc            :", sp.roc_auc_score(y_true, y_score))
print("average_precision  :", sp.average_precision_score(y_true, y_score))
Example — ROC and PR curves
import seraplot as sp

fpr, tpr, thr = sp.roc_curve(y_true, y_score, pos_label=1)
sp.line(fpr, tpr, title=f"ROC (AUC={sp.roc_auc_score(y_true, y_score):.3f})")

prec, rec, thr = sp.precision_recall_curve(y_true, y_score, pos_label=1)
sp.line(rec, prec, title=f"PR (AP={sp.average_precision_score(y_true, y_score):.3f})")

Algorithmic Functioning

Accuracy — fraction of correct predictions:

$$\text{Accuracy} = \frac{1}{n}\sum_{i=1}^n \mathbf{1}[\hat{y}_i = y_i]$$

Balanced accuracy — mean per-class recall, robust to class imbalance:

$$\text{BAcc} = \frac{1}{K}\sum_{k=1}^K \text{Recall}_k$$

Matthews correlation coefficient (binary) — uses all four cells of the confusion matrix:

$$\text{MCC} = \frac{TP \cdot TN - FP \cdot FN}{\sqrt{(TP+FP)(TP+FN)(TN+FP)(TN+FN)}}$$

Cohen's kappa — agreement adjusted for chance, with $p_o$ observed agreement and $p_e$ chance agreement:

$$\kappa = \frac{p_o - p_e}{1 - p_e}$$

F-beta generalises F1 by weighting recall $\beta$ times more than precision:

$$F_\beta = (1+\beta^2)\frac{P \cdot R}{\beta^2 P + R}$$

Jaccard score (binary) — intersection over union of positive predictions and labels:

$$J = \frac{|y \cap \hat{y}|}{|y \cup \hat{y}|}$$

Log loss (cross-entropy) for $K$ classes with predicted probabilities $p_{i,k}$:

$$\mathcal{L} = -\frac{1}{n}\sum_{i=1}^n \sum_{k=1}^K \mathbf{1}[y_i = k] \log p_{i,k}$$

Probabilities are clipped to $[\varepsilon, 1-\varepsilon]$ before the log to avoid $-\infty$.

Brier score — mean squared error between predicted probabilities and binary labels:

$$\text{Brier} = \frac{1}{n}\sum_{i=1}^n (\hat{p}_i - y_i)^2$$

Hinge loss (margin loss) with labels in ${-1, +1}$ and decision values $s_i$:

$$\text{Hinge} = \frac{1}{n}\sum_{i=1}^n \max(0,\; 1 - y_i s_i)$$

ROC curve / AUC — sweep all thresholds of $s_i$, plotting FPR vs. TPR; AUC is the area under that curve, equal to the probability that a random positive scores higher than a random negative.

Precision-Recall curve / Average Precision — same sweep, plotting Precision vs. Recall; AP is computed as the step-area:

$$\text{AP} = \sum_{k} (R_k - R_{k-1}) \cdot P_k$$

Référence API

Signatures

sp.accuracy_score(y_true, y_pred)                                   -> float
sp.balanced_accuracy_score(y_true, y_pred)                          -> float
sp.precision_score(y_true, y_pred, average="binary", pos_label=1)   -> float
sp.recall_score(y_true, y_pred, average="binary", pos_label=1)      -> float
sp.f1_score(y_true, y_pred, average="binary", pos_label=1)          -> float
sp.fbeta_score(y_true, y_pred, beta=1.0, average="binary", pos_label=1) -> float
sp.jaccard_score(y_true, y_pred, pos_label=1)                       -> float
sp.matthews_corrcoef(y_true, y_pred)                                -> float
sp.cohen_kappa_score(y_true, y_pred)                                -> float
sp.hamming_loss(y_true, y_pred)                                     -> float
sp.zero_one_loss(y_true, y_pred)                                    -> float
sp.confusion_matrix(y_true, y_pred)                                 -> list[list[int]]
sp.classification_report(y_true, y_pred)                            -> str

sp.log_loss(y_true, y_proba, n_classes, eps=1e-15)                  -> float
sp.binary_log_loss(y_true, y_proba, eps=1e-15)                      -> float
sp.brier_score_loss(y_true, y_proba)                                -> float
sp.hinge_loss(y_true, decision)                                     -> float

sp.roc_curve(y_true, y_score, pos_label=1)                          -> (fpr, tpr, thresholds)
sp.roc_auc_score(y_true, y_score)                                   -> float
sp.precision_recall_curve(y_true, y_score, pos_label=1)             -> (precision, recall, thresholds)
sp.average_precision_score(y_true, y_score)                         -> float

Résumé

FonctionDomaineSortieDescription
accuracy_scoretoutfloatFraction correcte
balanced_accuracy_scoretoutfloatMoyenne du rappel par classe
precision_scorebinaire / multiclassefloat$TP / (TP+FP)$
recall_scorebinaire / multiclassefloat$TP / (TP+FN)$
f1_scorebinaire / multiclassefloatMoyenne harmonique de P et R
fbeta_scorebinaire / multiclassefloatF-bêta avec poids beta
jaccard_scorebinairefloatIntersection sur union
matthews_corrcoefbinairefloatCoefficient phi (intervalle $[-1,1]$)
cohen_kappa_scoretoutfloatAccord corrigé du hasard
hamming_losstoutfloatFraction d'erreurs
zero_one_losstoutfloat$1 - \text{accuracy}$
log_lossproba $K$ classesfloatEntropie croisée
binary_log_lossproba binairefloatEntropie croisée (binaire)
brier_score_lossproba binairefloat$(\hat{p} - y)^2$ moyen
hinge_lossétiquettes $\pm 1$float$\max(0, 1 - y \cdot s)$ moyen
roc_curvescore binaire(fpr, tpr, thr)Points ROC
roc_auc_scorescore binairefloatAire sous ROC
precision_recall_curvescore binaire(p, r, thr)Points PR
average_precision_scorescore binairefloatAire sous courbe PR

average accepte "binary", "macro", "weighted".

Exemple — rapport de classification complet
import seraplot as sp
import numpy as np

rng = np.random.default_rng(0)
y_true = rng.integers(0, 2, size=200).tolist()
y_score = rng.uniform(size=200).tolist()
y_pred  = [1 if s >= 0.5 else 0 for s in y_score]

print("accuracy           :", sp.accuracy_score(y_true, y_pred))
print("balanced_accuracy  :", sp.balanced_accuracy_score(y_true, y_pred))
print("precision          :", sp.precision_score(y_true, y_pred))
print("recall             :", sp.recall_score(y_true, y_pred))
print("f1                 :", sp.f1_score(y_true, y_pred))
print("f2                 :", sp.fbeta_score(y_true, y_pred, beta=2.0))
print("matthews_corrcoef  :", sp.matthews_corrcoef(y_true, y_pred))
print("cohen_kappa        :", sp.cohen_kappa_score(y_true, y_pred))
print("jaccard            :", sp.jaccard_score(y_true, y_pred))
print("hamming_loss       :", sp.hamming_loss(y_true, y_pred))
print("zero_one_loss      :", sp.zero_one_loss(y_true, y_pred))

print("brier              :", sp.brier_score_loss(y_true, y_score))
print("binary_log_loss    :", sp.binary_log_loss(y_true, y_score))
print("roc_auc            :", sp.roc_auc_score(y_true, y_score))
print("average_precision  :", sp.average_precision_score(y_true, y_score))
Exemple — courbes ROC et PR
import seraplot as sp

fpr, tpr, thr = sp.roc_curve(y_true, y_score, pos_label=1)
sp.line(fpr, tpr, title=f"ROC (AUC={sp.roc_auc_score(y_true, y_score):.3f})")

prec, rec, thr = sp.precision_recall_curve(y_true, y_score, pos_label=1)
sp.line(rec, prec, title=f"PR (AP={sp.average_precision_score(y_true, y_score):.3f})")

Fonctionnement algorithmique

Précision (accuracy) — fraction des prédictions correctes :

$$\text{Accuracy} = \frac{1}{n}\sum_{i=1}^n \mathbf{1}[\hat{y}_i = y_i]$$

Précision équilibrée — moyenne du rappel par classe, robuste au déséquilibre :

$$\text{BAcc} = \frac{1}{K}\sum_{k=1}^K \text{Recall}_k$$

Coefficient de corrélation de Matthews (binaire) — utilise les quatre cases de la matrice de confusion :

$$\text{MCC} = \frac{TP \cdot TN - FP \cdot FN}{\sqrt{(TP+FP)(TP+FN)(TN+FP)(TN+FN)}}$$

Kappa de Cohen — accord corrigé du hasard, avec $p_o$ accord observé et $p_e$ accord aléatoire :

$$\kappa = \frac{p_o - p_e}{1 - p_e}$$

F-bêta généralise F1 en pondérant le rappel $\beta$ fois plus que la précision :

$$F_\beta = (1+\beta^2)\frac{P \cdot R}{\beta^2 P + R}$$

Score de Jaccard (binaire) — intersection sur union des positifs prédits et labellisés :

$$J = \frac{|y \cap \hat{y}|}{|y \cup \hat{y}|}$$

Log loss (entropie croisée) pour $K$ classes avec probabilités $p_{i,k}$ :

$$\mathcal{L} = -\frac{1}{n}\sum_{i=1}^n \sum_{k=1}^K \mathbf{1}[y_i = k] \log p_{i,k}$$

Les probabilités sont clampées à $[\varepsilon, 1-\varepsilon]$ avant le log pour éviter $-\infty$.

Score de Brier — erreur quadratique moyenne entre probabilités prédites et labels binaires :

$$\text{Brier} = \frac{1}{n}\sum_{i=1}^n (\hat{p}_i - y_i)^2$$

Hinge loss (perte de marge) avec labels dans ${-1, +1}$ et valeurs de décision $s_i$ :

$$\text{Hinge} = \frac{1}{n}\sum_{i=1}^n \max(0,\; 1 - y_i s_i)$$

Courbe ROC / AUC — balayage de tous les seuils de $s_i$, traçant FPR vs. TPR ; l'AUC est l'aire sous la courbe, égale à la probabilité qu'un positif aléatoire ait un score supérieur à celui d'un négatif aléatoire.

Courbe Précision-Rappel / Average Precision — même balayage, traçant Précision vs. Rappel ; AP est l'aire en escalier :

$$\text{AP} = \sum_{k} (R_k - R_{k-1}) \cdot P_k$$

Regression Metrics

API Reference

Signatures

sp.mean_squared_error(y_true, y_pred)                       -> float
sp.root_mean_squared_error(y_true, y_pred)                  -> float
sp.mean_absolute_error(y_true, y_pred)                      -> float
sp.median_absolute_error(y_true, y_pred)                    -> float
sp.r2_score(y_true, y_pred)                                 -> float
sp.explained_variance_score(y_true, y_pred)                 -> float
sp.max_error(y_true, y_pred)                                -> float
sp.mean_absolute_percentage_error(y_true, y_pred)           -> float
sp.mean_squared_log_error(y_true, y_pred)                   -> float
sp.root_mean_squared_log_error(y_true, y_pred)              -> float
sp.mean_pinball_loss(y_true, y_pred, alpha=0.5)             -> float
sp.d2_absolute_error_score(y_true, y_pred)                  -> float

Function summary

FunctionOutputDescription
mean_squared_errorfloatAverage squared error
root_mean_squared_errorfloat$\sqrt{\text{MSE}}$, in target units
mean_absolute_errorfloatAverage absolute error
median_absolute_errorfloatMedian of $
r2_scorefloatCoefficient of determination
explained_variance_scorefloatVariance ratio (allows bias)
max_errorfloatWorst residual
mean_absolute_percentage_errorfloatMAPE, scale-free
mean_squared_log_errorfloatMSE in log space, requires $y, \hat{y} \geq 0$
root_mean_squared_log_errorfloat$\sqrt{\text{MSLE}}$
mean_pinball_lossfloatQuantile loss (param alpha in $(0,1)$)
d2_absolute_error_scorefloat$R^2$ analogue using MAE
Example
import seraplot as sp

y_true = [3.0, -0.5, 2.0, 7.0, 5.0, 4.5]
y_pred = [2.5, 0.0, 2.1, 7.8, 4.7, 4.6]

print("MSE   :", sp.mean_squared_error(y_true, y_pred))
print("RMSE  :", sp.root_mean_squared_error(y_true, y_pred))
print("MAE   :", sp.mean_absolute_error(y_true, y_pred))
print("MedAE :", sp.median_absolute_error(y_true, y_pred))
print("R²    :", sp.r2_score(y_true, y_pred))
print("EVS   :", sp.explained_variance_score(y_true, y_pred))
print("MaxE  :", sp.max_error(y_true, y_pred))
print("MAPE  :", sp.mean_absolute_percentage_error(y_true, y_pred))
print("MSLE  :", sp.mean_squared_log_error([1,2,3], [1.1,2.1,3.1]))
print("Q90   :", sp.mean_pinball_loss(y_true, y_pred, alpha=0.9))
print("D²-AE :", sp.d2_absolute_error_score(y_true, y_pred))

Algorithmic Functioning

MSE / RMSE / MAE — pointwise error aggregates:

$$\text{MSE} = \frac{1}{n}\sum_i (y_i - \hat{y}_i)^2 \qquad \text{MAE} = \frac{1}{n}\sum_i |y_i - \hat{y}_i|$$

Median absolute error — robust to outliers:

$$\text{MedAE} = \mathrm{median}_i \, |y_i - \hat{y}_i|$$

MAPE — scale-free, undefined when $y_i = 0$:

$$\text{MAPE} = \frac{1}{n}\sum_i \left|\frac{y_i - \hat{y}_i}{y_i}\right|$$

MSLE — penalises under-prediction more than over-prediction; requires non-negative values:

$$\text{MSLE} = \frac{1}{n}\sum_i \big(\log(1+y_i) - \log(1+\hat{y}_i)\big)^2$$

Pinball loss — asymmetric quantile loss; minimised by the $\alpha$-quantile predictor:

$$L_\alpha = \frac{1}{n}\sum_i \big(\alpha \max(y_i - \hat{y}_i, 0) + (1-\alpha)\max(\hat{y}_i - y_i, 0)\big)$$

Explained variance allows for a constant bias:

$$\text{EVS} = 1 - \frac{\mathrm{Var}(y - \hat{y})}{\mathrm{Var}(y)}$$

$R^2$ vs. $D^2$-AE — both are "1 minus loss / loss-of-the-mean-predictor", but using MSE for $R^2$ and MAE for $D^2$-AE:

$$R^2 = 1 - \frac{\sum_i (y_i - \hat{y}_i)^2}{\sum_i (y_i - \bar{y})^2}, \qquad D^2_{\text{AE}} = 1 - \frac{\sum_i |y_i - \hat{y}_i|}{\sum_i |y_i - \tilde{y}|}$$

with $\tilde{y}$ the median.

Référence API

Signatures

sp.mean_squared_error(y_true, y_pred)                       -> float
sp.root_mean_squared_error(y_true, y_pred)                  -> float
sp.mean_absolute_error(y_true, y_pred)                      -> float
sp.median_absolute_error(y_true, y_pred)                    -> float
sp.r2_score(y_true, y_pred)                                 -> float
sp.explained_variance_score(y_true, y_pred)                 -> float
sp.max_error(y_true, y_pred)                                -> float
sp.mean_absolute_percentage_error(y_true, y_pred)           -> float
sp.mean_squared_log_error(y_true, y_pred)                   -> float
sp.root_mean_squared_log_error(y_true, y_pred)              -> float
sp.mean_pinball_loss(y_true, y_pred, alpha=0.5)             -> float
sp.d2_absolute_error_score(y_true, y_pred)                  -> float

Résumé

FonctionSortieDescription
mean_squared_errorfloatErreur quadratique moyenne
root_mean_squared_errorfloat$\sqrt{\text{MSE}}$, dans l'unité cible
mean_absolute_errorfloatErreur absolue moyenne
median_absolute_errorfloatMédiane de $
r2_scorefloatCoefficient de détermination
explained_variance_scorefloatRatio de variance (autorise un biais)
max_errorfloatPire résidu
mean_absolute_percentage_errorfloatMAPE, sans échelle
mean_squared_log_errorfloatMSE en espace log, requiert $y, \hat{y} \geq 0$
root_mean_squared_log_errorfloat$\sqrt{\text{MSLE}}$
mean_pinball_lossfloatPerte quantile (paramètre alpha dans $(0,1)$)
d2_absolute_error_scorefloatAnalogue de $R^2$ avec MAE
Exemple
import seraplot as sp

y_true = [3.0, -0.5, 2.0, 7.0, 5.0, 4.5]
y_pred = [2.5, 0.0, 2.1, 7.8, 4.7, 4.6]

print("MSE   :", sp.mean_squared_error(y_true, y_pred))
print("RMSE  :", sp.root_mean_squared_error(y_true, y_pred))
print("MAE   :", sp.mean_absolute_error(y_true, y_pred))
print("MedAE :", sp.median_absolute_error(y_true, y_pred))
print("R²    :", sp.r2_score(y_true, y_pred))
print("EVS   :", sp.explained_variance_score(y_true, y_pred))
print("MaxE  :", sp.max_error(y_true, y_pred))
print("MAPE  :", sp.mean_absolute_percentage_error(y_true, y_pred))
print("MSLE  :", sp.mean_squared_log_error([1,2,3], [1.1,2.1,3.1]))
print("Q90   :", sp.mean_pinball_loss(y_true, y_pred, alpha=0.9))
print("D²-AE :", sp.d2_absolute_error_score(y_true, y_pred))

Fonctionnement algorithmique

MSE / RMSE / MAE — agrégats d'erreur point par point :

$$\text{MSE} = \frac{1}{n}\sum_i (y_i - \hat{y}_i)^2 \qquad \text{MAE} = \frac{1}{n}\sum_i |y_i - \hat{y}_i|$$

Erreur absolue médiane — robuste aux outliers :

$$\text{MedAE} = \mathrm{median}_i \, |y_i - \hat{y}_i|$$

MAPE — sans échelle, indéfini quand $y_i = 0$ :

$$\text{MAPE} = \frac{1}{n}\sum_i \left|\frac{y_i - \hat{y}_i}{y_i}\right|$$

MSLE — pénalise davantage la sous-estimation que la sur-estimation ; requiert des valeurs positives :

$$\text{MSLE} = \frac{1}{n}\sum_i \big(\log(1+y_i) - \log(1+\hat{y}_i)\big)^2$$

Pinball loss — perte quantile asymétrique, minimisée par le prédicteur $\alpha$-quantile :

$$L_\alpha = \frac{1}{n}\sum_i \big(\alpha \max(y_i - \hat{y}_i, 0) + (1-\alpha)\max(\hat{y}_i - y_i, 0)\big)$$

Variance expliquée autorise un biais constant :

$$\text{EVS} = 1 - \frac{\mathrm{Var}(y - \hat{y})}{\mathrm{Var}(y)}$$

$R^2$ vs. $D^2$-AE — tous deux « 1 moins perte / perte du prédicteur moyen », mais utilisant MSE pour $R^2$ et MAE pour $D^2$-AE :

$$R^2 = 1 - \frac{\sum_i (y_i - \hat{y}_i)^2}{\sum_i (y_i - \bar{y})^2}, \qquad D^2_{\text{AE}} = 1 - \frac{\sum_i |y_i - \hat{y}_i|}{\sum_i |y_i - \tilde{y}|}$$

avec $\tilde{y}$ la médiane.

Clustering Metrics

API Reference

Signatures

sp.silhouette_score(X, labels)                          -> float
sp.davies_bouldin_score(X, labels)                      -> float
sp.calinski_harabasz_score(X, labels)                   -> float

sp.adjusted_rand_score(labels_true, labels_pred)        -> float
sp.normalized_mutual_info_score(labels_true, labels_pred) -> float
sp.fowlkes_mallows_score(labels_true, labels_pred)      -> float
sp.homogeneity_score(labels_true, labels_pred)          -> float
sp.completeness_score(labels_true, labels_pred)         -> float
sp.v_measure_score(labels_true, labels_pred)            -> float

Function summary

FunctionTypeRangeBestDescription
silhouette_scoreinternal$[-1, 1]$$\to 1$Mean silhouette over samples
davies_bouldin_scoreinternal$[0, \infty)$$\to 0$Mean cluster similarity ratio
calinski_harabasz_scoreinternal$[0, \infty)$$\to \infty$Variance ratio criterion
adjusted_rand_scoreexternal$[-1, 1]$$\to 1$Rand index adjusted for chance
normalized_mutual_info_scoreexternal$[0, 1]$$\to 1$MI normalised by mean entropy
fowlkes_mallows_scoreexternal$[0, 1]$$\to 1$Geometric mean of pairwise P/R
homogeneity_scoreexternal$[0, 1]$$\to 1$Each cluster contains one class
completeness_scoreexternal$[0, 1]$$\to 1$Each class lies in one cluster
v_measure_scoreexternal$[0, 1]$$\to 1$Harmonic mean of H and C

X is a 2D ndarray (n_samples, n_features) (the silhouette is parallelised with rayon).

Example
import seraplot as sp
import numpy as np

rng = np.random.default_rng(0)
X = np.vstack([
    rng.normal(loc=( 0,  0), scale=0.6, size=(100, 2)),
    rng.normal(loc=( 5,  5), scale=0.6, size=(100, 2)),
    rng.normal(loc=(-5,  5), scale=0.6, size=(100, 2)),
])
y_true = [0]*100 + [1]*100 + [2]*100

km = sp.KMeans(k=3, max_iter=100, tol=1e-4, mini_batch=False, batch_size=0, n_init=4)
labels = list(km.fit_predict(X))

print("silhouette        :", sp.silhouette_score(X, labels))
print("davies_bouldin    :", sp.davies_bouldin_score(X, labels))
print("calinski_harabasz :", sp.calinski_harabasz_score(X, labels))

print("ARI               :", sp.adjusted_rand_score(y_true, labels))
print("NMI               :", sp.normalized_mutual_info_score(y_true, labels))
print("FMI               :", sp.fowlkes_mallows_score(y_true, labels))
print("homogeneity       :", sp.homogeneity_score(y_true, labels))
print("completeness      :", sp.completeness_score(y_true, labels))
print("v_measure         :", sp.v_measure_score(y_true, labels))

Algorithmic Functioning

Silhouette — for each sample $i$, with $a_i$ the mean distance to the same-cluster points and $b_i$ the mean distance to the nearest other cluster:

$$s_i = \frac{b_i - a_i}{\max(a_i, b_i)}, \qquad S = \frac{1}{n}\sum_i s_i$$

Davies-Bouldin — for each cluster $k$ with intra-cluster dispersion $S_k$ and centroid distance $d_{kj}$:

$$\text{DB} = \frac{1}{K}\sum_k \max_{j \neq k} \frac{S_k + S_j}{d_{kj}}$$

Calinski-Harabasz — variance ratio between/within clusters, with $B$ between-cluster scatter and $W$ within-cluster scatter:

$$\text{CH} = \frac{\mathrm{tr}(B)}{\mathrm{tr}(W)} \cdot \frac{n - K}{K - 1}$$

Adjusted Rand Index — Rand index corrected for chance by subtracting the expected value:

$$\text{ARI} = \frac{\text{RI} - E[\text{RI}]}{\max(\text{RI}) - E[\text{RI}]}$$

NMI — normalised mutual information:

$$\text{NMI} = \frac{2 \cdot I(U; V)}{H(U) + H(V)}$$

Homogeneity / Completeness / V-measure — entropy-based duals:

$$h = 1 - \frac{H(C \mid K)}{H(C)}, \qquad c = 1 - \frac{H(K \mid C)}{H(K)}, \qquad V = \frac{2 h c}{h + c}$$

Fowlkes-Mallows — geometric mean of pairwise precision and recall computed from TP/FP/FN of the pair confusion matrix:

$$\text{FMI} = \sqrt{\frac{TP}{TP+FP} \cdot \frac{TP}{TP+FN}}$$

Référence API

Signatures

sp.silhouette_score(X, labels)                          -> float
sp.davies_bouldin_score(X, labels)                      -> float
sp.calinski_harabasz_score(X, labels)                   -> float

sp.adjusted_rand_score(labels_true, labels_pred)        -> float
sp.normalized_mutual_info_score(labels_true, labels_pred) -> float
sp.fowlkes_mallows_score(labels_true, labels_pred)      -> float
sp.homogeneity_score(labels_true, labels_pred)          -> float
sp.completeness_score(labels_true, labels_pred)         -> float
sp.v_measure_score(labels_true, labels_pred)            -> float

Résumé

FonctionTypePlageIdéalDescription
silhouette_scoreinterne$[-1, 1]$$\to 1$Silhouette moyenne
davies_bouldin_scoreinterne$[0, \infty)$$\to 0$Ratio de similarité moyen
calinski_harabasz_scoreinterne$[0, \infty)$$\to \infty$Critère de ratio de variance
adjusted_rand_scoreexterne$[-1, 1]$$\to 1$Index de Rand corrigé du hasard
normalized_mutual_info_scoreexterne$[0, 1]$$\to 1$MI normalisée par l'entropie
fowlkes_mallows_scoreexterne$[0, 1]$$\to 1$Moyenne géométrique de P/R par paires
homogeneity_scoreexterne$[0, 1]$$\to 1$Chaque cluster contient une classe
completeness_scoreexterne$[0, 1]$$\to 1$Chaque classe est dans un cluster
v_measure_scoreexterne$[0, 1]$$\to 1$Moyenne harmonique de H et C

X est un ndarray 2D (n_samples, n_features) (la silhouette est parallélisée avec rayon).

Exemple
import seraplot as sp
import numpy as np

rng = np.random.default_rng(0)
X = np.vstack([
    rng.normal(loc=( 0,  0), scale=0.6, size=(100, 2)),
    rng.normal(loc=( 5,  5), scale=0.6, size=(100, 2)),
    rng.normal(loc=(-5,  5), scale=0.6, size=(100, 2)),
])
y_true = [0]*100 + [1]*100 + [2]*100

km = sp.KMeans(k=3, max_iter=100, tol=1e-4, mini_batch=False, batch_size=0, n_init=4)
labels = list(km.fit_predict(X))

print("silhouette        :", sp.silhouette_score(X, labels))
print("davies_bouldin    :", sp.davies_bouldin_score(X, labels))
print("calinski_harabasz :", sp.calinski_harabasz_score(X, labels))

print("ARI               :", sp.adjusted_rand_score(y_true, labels))
print("NMI               :", sp.normalized_mutual_info_score(y_true, labels))
print("FMI               :", sp.fowlkes_mallows_score(y_true, labels))
print("homogeneity       :", sp.homogeneity_score(y_true, labels))
print("completeness      :", sp.completeness_score(y_true, labels))
print("v_measure         :", sp.v_measure_score(y_true, labels))

Fonctionnement algorithmique

Silhouette — pour chaque échantillon $i$, avec $a_i$ la distance moyenne aux points du même cluster et $b_i$ la distance moyenne au cluster voisin le plus proche :

$$s_i = \frac{b_i - a_i}{\max(a_i, b_i)}, \qquad S = \frac{1}{n}\sum_i s_i$$

Davies-Bouldin — pour chaque cluster $k$ avec dispersion intra $S_k$ et distance entre centroïdes $d_{kj}$ :

$$\text{DB} = \frac{1}{K}\sum_k \max_{j \neq k} \frac{S_k + S_j}{d_{kj}}$$

Calinski-Harabasz — ratio de variance inter/intra, avec $B$ dispersion inter-cluster et $W$ dispersion intra-cluster :

$$\text{CH} = \frac{\mathrm{tr}(B)}{\mathrm{tr}(W)} \cdot \frac{n - K}{K - 1}$$

Index de Rand ajusté — Rand corrigé en soustrayant la valeur attendue :

$$\text{ARI} = \frac{\text{RI} - E[\text{RI}]}{\max(\text{RI}) - E[\text{RI}]}$$

NMI — information mutuelle normalisée :

$$\text{NMI} = \frac{2 \cdot I(U; V)}{H(U) + H(V)}$$

Homogénéité / Complétude / V-mesure — duaux basés sur l'entropie :

$$h = 1 - \frac{H(C \mid K)}{H(C)}, \qquad c = 1 - \frac{H(K \mid C)}{H(K)}, \qquad V = \frac{2 h c}{h + c}$$

Fowlkes-Mallows — moyenne géométrique de la précision et du rappel par paires, calculées à partir de TP/FP/FN de la matrice de confusion par paires :

$$\text{FMI} = \sqrt{\frac{TP}{TP+FP} \cdot \frac{TP}{TP+FN}}$$

train_test_split / StratifiedKFold

API Reference

Signature

X_train, X_test, y_train, y_test = sp.train_test_split(
    X, y, test_size=0.2, random_state=None, stratify=False
)

kf = sp.StratifiedKFold(n_splits=5, shuffle=False, random_state=0)

for train_idx, test_idx in kf.split(X, y):
    X_train, X_test = X[train_idx], X[test_idx]
    y_train, y_test = y[train_idx], y[test_idx]
    ...

Parameters — train_test_split

ParameterTypeDefaultDescription
Xndarray (n, p)Feature matrix
ylist | ndarrayTarget vector
test_sizefloat0.2Fraction of samples to hold out
random_stateint | NoneNoneSeed for reproducibility
stratifyboolFalsePreserve class proportions in each split

Constructor parameters — StratifiedKFold

ParameterTypeDefaultDescription
n_splitsint5Number of folds $k$
shuffleboolFalseShuffle data before splitting
random_stateint | NoneNoneSeed for reproducibility

Returns — train_test_split

Return valueTypeDescription
X_trainndarrayTraining features
X_testndarrayTest features
y_trainlistTraining labels
y_testlistTest labels
Example
import seraplot as sp
import numpy as np

X = np.random.randn(500, 6)
y = (X[:, 0] + X[:, 1] > 0).astype(int)

X_train, X_test, y_train, y_test = sp.train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=True
)
print(f"Train: {len(y_train)}, Test: {len(y_test)}")

kf = sp.StratifiedKFold(n_splits=5, shuffle=True, random_state=0)
for fold, (tr, te) in enumerate(kf.split(X, y)):
    clf = sp.LogisticRegression()
    clf.fit(X[tr], np.array(y)[tr].tolist())
    print(f"Fold {fold}: {clf.score(X[te], np.array(y)[te].tolist()):.4f}")

Algorithmic Functioning


train_test_split

Non-stratified split — randomly shuffle indices and cut at position $\lfloor n \cdot (1 - \texttt{test_size})\rfloor$:

$$\text{train} = \sigma([0,n))[:n_{\text{tr}}], \qquad \text{test} = \sigma([0,n))[n_{\text{tr}}:]$$

where $\sigma$ is a random permutation seeded by random_state.

Stratified split — class proportions are preserved by splitting each class independently:

$$\forall k:\quad n_{\text{test},k} = \text{round}(n_k \cdot \texttt{test\_size})$$

then combining and shuffling all per-class test/train sets. This ensures that rare classes are not accidentally excluded from the test set.


StratifiedKFold

Splits the dataset into $k$ non-overlapping folds whilst preserving class distributions in each fold.

Algorithm:

1. For each class $c$, collect its indices $\mathcal{I}_c = {i : y_i = c}$.

2. Optionally shuffle $\mathcal{I}_c$ with random_state.

3. Divide $\mathcal{I}_c$ into $k$ roughly equal sub-arrays of size $\lfloor|\mathcal{I}_c|/k\rfloor$ or $\lceil|\mathcal{I}_c|/k\rceil$.

4. For fold $f \in {0,\ldots,k-1}$: the test set is $\bigcup_c \mathcal{I}_c[f]$ and the train set is its complement.

The $f$-th fold test error estimate $\hat{e}_f$ gives the cross-validated score:

$$\widehat{\text{CV}} = \frac{1}{k}\sum_{f=0}^{k-1} \hat{e}_f$$

This estimate has lower variance than a single train/test split, especially for small datasets.

Référence API

Signature

X_train, X_test, y_train, y_test = sp.train_test_split(
    X, y, test_size=0.2, random_state=None, stratify=False
)

kf = sp.StratifiedKFold(n_splits=5, shuffle=False, random_state=0)

for train_idx, test_idx in kf.split(X, y):
    X_train, X_test = X[train_idx], X[test_idx]
    y_train, y_test = y[train_idx], y[test_idx]
    ...

Paramètres — train_test_split

ParamètreTypeDéfautDescription
Xndarray (n, p)Matrice de features
ylist | ndarrayVecteur cible
test_sizefloat0.2Fraction des échantillons à mettre de côté
random_stateint | NoneNoneGraine pour la reproductibilité
stratifyboolFalsePréserver les proportions de classes dans chaque partition

Paramètres du constructeur — StratifiedKFold

ParamètreTypeDéfautDescription
n_splitsint5Nombre de plis $k$
shuffleboolTrueMélanger les données avant de diviser
random_stateint | NoneNoneGraine pour la reproductibilité

Valeurs de retour — train_test_split

Valeur de retourTypeDescription
X_trainndarrayFeatures d'entraînement
X_testndarrayFeatures de test
y_trainlistÉtiquettes d'entraînement
y_testlistÉtiquettes de test
Exemple
import seraplot as sp
import numpy as np

X = np.random.randn(500, 6)
y = (X[:, 0] + X[:, 1] > 0).astype(int)

X_train, X_test, y_train, y_test = sp.train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=True
)
print(f"Train : {len(y_train)}, Test : {len(y_test)}")

kf = sp.StratifiedKFold(n_splits=5, shuffle=True, random_state=0)
for pli, (tr, te) in enumerate(kf.split(X, y)):
    clf = sp.LogisticRegression()
    clf.fit(X[tr], np.array(y)[tr].tolist())
    print(f"Pli {pli} : {clf.score(X[te], np.array(y)[te].tolist()):.4f}")

Fonctionnement algorithmique


train_test_split

Division non stratifiée — mélange aléatoire des indices et coupe à la position $\lfloor n \cdot (1 - \texttt{test_size})\rfloor$ :

$$\text{train} = \sigma([0,n))[:n_{\text{tr}}], \qquad \text{test} = \sigma([0,n))[n_{\text{tr}}:]$$

où $\sigma$ est une permutation aléatoire initialisée par random_state.

Division stratifiée — les proportions de classes sont préservées en divisant chaque classe indépendamment :

$$\forall k:\quad n_{\text{test},k} = \text{round}(n_k \cdot \texttt{test\_size})$$

puis en combinant et mélangeant tous les ensembles test/train par classe. Cela garantit que les classes rares ne sont pas accidentellement exclues de l'ensemble de test.


StratifiedKFold

Divise le jeu de données en $k$ plis non-chevauchants tout en préservant les distributions de classes dans chaque pli.

Algorithme :

1. Pour chaque classe $c$, collecter ses indices $\mathcal{I}_c = {i : y_i = c}$.

2. Optionnellement mélanger $\mathcal{I}_c$ avec random_state.

3. Diviser $\mathcal{I}_c$ en $k$ sous-tableaux approximativement égaux de taille $\lfloor|\mathcal{I}_c|/k\rfloor$ ou $\lceil|\mathcal{I}_c|/k\rceil$.

4. Pour le pli $f \in {0,\ldots,k-1}$ : l'ensemble de test est $\bigcup_c \mathcal{I}_c[f]$ et l'ensemble d'entraînement est son complément.

L'estimation d'erreur du $f$-ième pli $\hat{e}_f$ donne le score de validation croisée :

$$\widehat{\text{VC}} = \frac{1}{k}\sum_{f=0}^{k-1} \hat{e}_f$$

Cette estimation a une variance plus faible qu'une seule division train/test, notamment pour les petits jeux de données.

SeraDFrame

SeraDFrame is a columnar, Rust-native dataframe — Vec<f64> / Vec<String> / Vec<bool> per column, no per-cell object boxing — covering the common pandas surface: relational joins, group-by/aggregate, sorting, filtering, dedup, describe/corr, and a builder pattern, plus native, lossless conversion to and from pandas.DataFrame so it drops into an existing pandas pipeline anywhere.

import seraplot as sp

df = sp.SeraDFrame.from_csv("events.csv")
by_region = df.groupby("region").agg({"cost": "sum", "latency_ms": "mean"})
top5 = by_region.sort_values("cost", ascending=False).head(5)

Every table below is generated at page load straight from the #[sera_doc(...)] attributes on each method in v2/src/data/dframe/ — not hand-maintained, so it cannot drift from what is actually implemented. SeraDFrame methods do not currently carry aliases the way chart functions do — one canonical name per method, matching the underlying pandas-shaped surface directly.

Construction & Interop

Reading & Attributes

Filtering & Masking

Shaping & Transform

Relational & Combine

GroupBy

Rolling & Expanding

Datetime

Stats & Reductions

String Methods

SeraDFrame est un dataframe colonnaire, natif Rust — Vec<f64> / Vec<String> / Vec<bool> par colonne, sans boxing objet par cellule — couvrant la surface pandas courante : jointures relationnelles, group-by/agrégation, tri, filtrage, dédoublonnage, describe/corr, un patron builder, plus une conversion native et sans perte vers et depuis pandas.DataFrame, pour s'insérer n'importe où dans un pipeline pandas existant.

import seraplot as sp

df = sp.SeraDFrame.from_csv("events.csv")
by_region = df.groupby("region").agg({"cost": "sum", "latency_ms": "mean"})
top5 = by_region.sort_values("cost", ascending=False).head(5)

Chaque tableau ci-dessous est généré au chargement de la page directement depuis les attributs #[sera_doc(...)] de chaque méthode dans v2/src/data/dframe/ — pas maintenu à la main, donc impossible de dériver de ce qui est réellement implémenté. Les méthodes SeraDFrame n'ont actuellement pas d'alias comme les fonctions de graphique — un seul nom canonique par méthode, reflétant directement la surface pandas sous-jacente.

Construction & Interopérabilité

Lecture & attributs

Filtrage & masques

Mise en forme & transformation

Relationnel & combinaison

GroupBy

Fenêtres glissantes

Dates & heures

Stats & réductions

Méthodes de chaînes

Table — Data Engineering

Table is a small, columnar data-shaping utility: relational joins, group-by/aggregate, pivots, rolling windows and filters, all in Rust, with no pandas dependency. Its purpose is narrow and deliberate — reshape one source of truth into the exact inputs each chart function expects, so several panels built from the same data stay consistent, instead of hand-rolling loops per chart.

import seraplot as sp

t = sp.Table({
    "region": ["North", "South", "North", "South"],
    "product": ["Core", "Core", "Cloud", "Cloud"],
    "revenue": [24.0, 18.0, 12.0, 9.0],
})

Columns are built from Python dict[str, list] — each value can be int, float, str or bool; mixed-type columns coerce to string on read.


Reading

MethodEffect
columns() -> list[str]Column names, in original order.
nrows (getter)Row count.
column(name) -> listRaw values (native Python types).
column_f64(name) -> list[float]Values coerced to float.
column_str(name) -> list[str]Values coerced to string.
to_records() -> list[dict]Row-oriented view, one dict per row.
head(n) -> TableFirst n rows.
select(names) -> TableA subset of columns.

Filtering & sorting

MethodEffect
filter_eq(col, value) -> TableRows where col == value.
filter_gt/lt/ge/le(col, value: float) -> TableNumeric comparison filters.
filter_in(col, values: list[str]) -> TableRows where col is one of values.
sort_by(col, desc=False) -> TableSorted copy.
top_n(col, n, desc=True) -> TableShortcut for sort_by(col, desc).head(n) — the "top 10" pattern.

Relational & ETL operations

MethodEffect
join(other, on, how="inner") -> TableJoins two tables on a key column. how="left" keeps unmatched left rows with zero-filled right columns. Colliding column names from other are prefixed right_.
concat(other) -> TableVertical union of two tables; missing columns on either side are zero/empty-filled.
with_column(name, op, left, right) -> TableAdds a computed column. op is "add"/"sub"/"mul"/"div". right is either another column's name or a constant.
groupby_agg(group_col, value_col, agg="sum") -> TableGroups by group_col, aggregates value_col. agg is "sum"/"mean"/"count"/"min"/"max"/"median".
pivot(index_col, columns_col, values_col, agg="sum") -> TableReshapes long data to wide: one row per index_col value, one column per unique columns_col value.

Time-series & stats prep

MethodEffect
rolling_mean(col, window) -> TableAdds {col}_rolling{window}, a trailing moving average.
cumsum(col) -> TableAdds {col}_cumsum, the running total.
pct_change(col) -> TableAdds {col}_pct_change, row-over-row percent change.
rank(col, desc=False) -> TableAdds {col}_rank, 1-based rank.
zscore(col) -> TableAdds {col}_zscore, (x - mean) / std.
describe() -> TableOne row per numeric column: count, mean, min, max, std.

Every transform returns a new Table (chainable, no mutation):

monthly = (
    sales.groupby_agg("month", "revenue", "sum")
         .sort_by("month")
         .rolling_mean("revenue", 3)
         .cumsum("revenue")
)

Feeding charts directly

gb = table.to_grouped_bar("month", "product", "revenue", "sum")
bar = sp.grouped_bar(
    "", labels=gb["category_labels"], values=gb["values"],
    series_names=gb["series_names"],
)

to_grouped_bar(index_col, columns_col, values_col, agg="sum") pivots and flattens in one call, returning a dict shaped exactly for sp.grouped_bar(labels=, values=, series_names=) — the most common table-to-chart handoff, done in one line instead of manual pivoting.

For any other chart, column_f64/column_str after a filter_*/sort_by/ groupby_agg chain gets you there just as directly.


Loading data

t = sp.Table.from_csv("sales.csv")

Columns are auto-typed: numeric if every value in the column parses as a float, string otherwise.

Table est un petit outil de mise en forme de données en colonnes : jointures relationnelles, group-by/agrégation, pivots, fenêtres glissantes et filtres, le tout en Rust, sans dépendance à pandas. Son rôle est étroit et délibéré — remodeler une source de vérité unique vers les entrées exactes qu'attend chaque fonction de chart, pour que plusieurs panneaux construits depuis les mêmes données restent cohérents, au lieu d'écrire des boucles à la main pour chacun.

import seraplot as sp

t = sp.Table({
    "region": ["North", "South", "North", "South"],
    "product": ["Core", "Core", "Cloud", "Cloud"],
    "revenue": [24.0, 18.0, 12.0, 9.0],
})

Les colonnes se construisent depuis un dict[str, list] Python — chaque valeur peut être int, float, str ou bool ; les colonnes de type mixte sont converties en chaîne à la lecture.


Lecture

MéthodeEffet
columns() -> list[str]Noms des colonnes, dans l'ordre d'origine.
nrows (getter)Nombre de lignes.
column(name) -> listValeurs brutes (types Python natifs).
column_f64(name) -> list[float]Valeurs converties en float.
column_str(name) -> list[str]Valeurs converties en chaîne.
to_records() -> list[dict]Vue orientée ligne, un dict par ligne.
head(n) -> TableLes n premières lignes.
select(names) -> TableUn sous-ensemble de colonnes.

Filtrage & tri

MéthodeEffet
filter_eq(col, value) -> TableLignes où col == value.
filter_gt/lt/ge/le(col, value: float) -> TableFiltres de comparaison numérique.
filter_in(col, values: list[str]) -> TableLignes où col fait partie de values.
sort_by(col, desc=False) -> TableCopie triée.
top_n(col, n, desc=True) -> TableRaccourci pour sort_by(col, desc).head(n) — le motif "top 10".

Opérations relationnelles & ETL

MéthodeEffet
join(other, on, how="inner") -> TableJoint deux tables sur une colonne clé. how="left" garde les lignes gauches sans correspondance avec des colonnes droites à zéro. Les noms de colonnes de other en collision sont préfixés right_.
concat(other) -> TableUnion verticale de deux tables ; les colonnes manquantes d'un côté sont remplies à zéro/vide.
with_column(name, op, left, right) -> TableAjoute une colonne calculée. op vaut "add"/"sub"/"mul"/"div". right est soit le nom d'une autre colonne, soit une constante.
groupby_agg(group_col, value_col, agg="sum") -> TableGroupe par group_col, agrège value_col. agg vaut "sum"/"mean"/"count"/"min"/"max"/"median".
pivot(index_col, columns_col, values_col, agg="sum") -> TablePasse du format long au format large : une ligne par valeur de index_col, une colonne par valeur unique de columns_col.

Prépa séries temporelles & stats

MéthodeEffet
rolling_mean(col, window) -> TableAjoute {col}_rolling{window}, une moyenne mobile arrière.
cumsum(col) -> TableAjoute {col}_cumsum, le total cumulé.
pct_change(col) -> TableAjoute {col}_pct_change, la variation en % ligne à ligne.
rank(col, desc=False) -> TableAjoute {col}_rank, le rang (base 1).
zscore(col) -> TableAjoute {col}_zscore, (x - moyenne) / écart-type.
describe() -> TableUne ligne par colonne numérique : count, mean, min, max, std.

Chaque transformation renvoie une nouvelle Table (chaînable, sans mutation) :

monthly = (
    sales.groupby_agg("month", "revenue", "sum")
         .sort_by("month")
         .rolling_mean("revenue", 3)
         .cumsum("revenue")
)

Alimenter directement les charts

gb = table.to_grouped_bar("month", "product", "revenue", "sum")
bar = sp.grouped_bar(
    "", labels=gb["category_labels"], values=gb["values"],
    series_names=gb["series_names"],
)

to_grouped_bar(index_col, columns_col, values_col, agg="sum") pivote et aplatit en un seul appel, renvoyant un dict au format exact pour sp.grouped_bar(labels=, values=, series_names=) — la passerelle table-vers-chart la plus courante, faite en une ligne plutôt qu'un pivot manuel.

Pour tout autre chart, column_f64/column_str après une chaîne filter_*/sort_by/groupby_agg y mène tout aussi directement.


Charger des données

t = sp.Table.from_csv("sales.csv")

Les colonnes sont typées automatiquement : numérique si chaque valeur de la colonne se parse en float, chaîne sinon.

VS Code Extension

SeraPlot Live Preview
Live Preview

Official SeraPlot extension for Visual Studio Code — live preview, theme studio, snippets and a chart gallery.

Marketplace: https://marketplace.visualstudio.com/items?itemName=feur25.seraplot-vscode


Install

From the command palette or terminal — no browser needed:

ext install feur25.seraplot-vscode

Or from the Extensions view Ctrl+Shift+X, search SeraPlot:

Open in VS Code Marketplace →
💡 The extension auto-detects your Python environment via seraplot.pythonPath. Works on Windows, macOS and Linux.

Download the .vsix from the GitHub releases page, then install via terminal:

code --install-extension seraplot-vscode-0.6.1.vsix

Or drag the .vsix file directly into the VS Code Extensions panel.

📦 Ideal for air-gapped environments, corporate proxies, or pinning a specific version without going through the Marketplace.

Commands

IDTitleDescription
seraplot.previewSeraPlot: Live PreviewRender every sp.Chart of the current Python file in a side panel and refresh on save
seraplot.themeStudioSeraPlot: Open Theme StudioPick a palette + background, copy the generated sp.set_global_background(...) snippet
seraplot.gallerySeraPlot: Open GalleryBrowse all chart families with thumbnails and one-click code samples

The Live Preview button also appears in the editor title bar for any .py file.


Snippets

PrefixDescription
seraplot-importimport seraplot as sp
seraplot-barMinimal bar chart
seraplot-scatterScatter chart
seraplot-dashboard2x2 grid layout
seraplot-automlsp.auto_classify(...) skeleton
seraplot-driftsp.drift_detect(...) skeleton

Settings

KeyDefaultDescription
seraplot.pythonPathpythonPython interpreter used to render previews
seraplot.autoReloadtrueRe-render on save

Set seraplot.pythonPath to your project venv, e.g. ${workspaceFolder}/.venv/Scripts/python.exe on Windows or ${workspaceFolder}/.venv/bin/python on macOS / Linux.


How the preview works

  1. The active .py file is executed via runpy.run_path in a child Python process using seraplot.pythonPath.
  2. Every sp.Chart instance found in the module globals is exported with sp.export_html(chart).
  3. The HTML is concatenated and rendered inside a VS Code Webview panel.
  4. With seraplot.autoReload = true the panel re-runs automatically when the file is saved.

The preview is sandboxed in a Webview — no network access, no eval. Charts are CSP-safe (see config/csp.md).


Source

Repository: https://github.com/feur25/seraplot — folder seraplot-vscode/.

License: MIT.

Extension officielle SeraPlot pour Visual Studio Code — aperçu en direct, theme studio, snippets et galerie de graphiques.

Marketplace : https://marketplace.visualstudio.com/items?itemName=feur25.seraplot-vscode


Installation

Depuis la palette de commandes ou un terminal — sans navigateur :

ext install feur25.seraplot-vscode

Ou depuis la vue Extensions Ctrl+Shift+X, cherchez SeraPlot :

Ouvrir dans le Marketplace VS Code →
💡 L'extension détecte automatiquement votre environnement Python via seraplot.pythonPath. Fonctionne sur Windows, macOS et Linux.

Téléchargez le .vsix depuis la page des releases GitHub, puis installez via le terminal :

code --install-extension seraplot-vscode-0.6.1.vsix

Ou glissez-déposez le fichier .vsix directement dans le panneau Extensions de VS Code.

📦 Idéal pour les environnements hors ligne, les proxys d'entreprise, ou pour figer une version spécifique sans passer par le Marketplace.

Commandes

IDTitreDescription
seraplot.previewSeraPlot: Live PreviewAffiche tous les sp.Chart du fichier Python courant dans un panneau et rafraîchit à la sauvegarde
seraplot.themeStudioSeraPlot: Open Theme StudioChoisir une palette + un fond, copier le snippet sp.set_global_background(...) généré
seraplot.gallerySeraPlot: Open GalleryParcourir toutes les familles de graphiques avec aperçus et exemples de code en un clic

Le bouton Live Preview apparaît également dans la barre de titre de l'éditeur pour tout fichier .py.


Snippets

PréfixeDescription
seraplot-importimport seraplot as sp
seraplot-barGraphique en barres minimal
seraplot-scatterNuage de points
seraplot-dashboardGrille 2×2
seraplot-automlSquelette sp.auto_classify(...)
seraplot-driftSquelette sp.drift_detect(...)

Paramètres

CléDéfautDescription
seraplot.pythonPathpythonInterpréteur Python utilisé pour les aperçus
seraplot.autoReloadtrueRe-rendu à chaque sauvegarde

Pointer seraplot.pythonPath vers le venv du projet, par exemple ${workspaceFolder}/.venv/Scripts/python.exe sous Windows ou ${workspaceFolder}/.venv/bin/python sous macOS / Linux.


Fonctionnement de l'aperçu

  1. Le fichier .py actif est exécuté via runpy.run_path dans un processus Python enfant utilisant seraplot.pythonPath.
  2. Chaque instance sp.Chart trouvée dans les globales du module est exportée avec sp.export_html(chart).
  3. Le HTML est concaténé et rendu dans un panneau Webview de VS Code.
  4. Avec seraplot.autoReload = true, le panneau se relance automatiquement à chaque sauvegarde du fichier.

L'aperçu est sandboxé dans un Webview — pas d'accès réseau, pas d'eval. Les graphiques sont CSP-safe (voir config/csp.md).


Code source

Dépôt : https://github.com/feur25/seraplot — dossier seraplot-vscode/.

Licence : MIT.

About & Support

👨‍💻

A solo project

SeraPlot is built entirely on my own, on top of a day job. I regularly rework the core of the framework to keep improving it — not because I'm the best at low-level optimisation, but because I care about delivering a complete solution that originally answered my own needs and hopefully answers yours too.

Ultra-performant Fully customisable Complete

Get in touch

✉️ Email only

If you'd like a specific mechanic, feature or chart type, don't hesitate to reach out — by email only. I can't promise I'll build everything, but I'll do as much as I can.

📧 feur09@gmail.com

Support the project

☕ Buy me a coffee

I work on SeraPlot for free, on top of my day job. If it saves you time, a donation is very welcome — but you absolutely don't need to donate to send me a feature request.

Donate via PayPal

Thanks for using Sera ✨

👨‍💻

Un projet en solo

SeraPlot est entièrement réalisé seul, en plus d'un travail à plein temps. Je retravaille régulièrement le corps du framework pour continuer à l'améliorer — pas parce que je suis le meilleur en optimisation bas-niveau, mais parce que je tiens à offrir une solution complète qui répondait au départ à mes propres besoins et qui répond, j'espère, aussi aux vôtres.

Ultra-performant Entièrement personnalisable Complet

Me contacter

✉️ Par mail uniquement

Si vous voulez une mécanique, une fonctionnalité ou un type de graphique particulier, n'hésitez pas — par mail exclusivement. Je ne dis pas que je serai en capacité de tout réaliser, mais je ferai le plus possible.

📧 feur09@gmail.com

Soutenir le projet

☕ Offrez-moi un café

Je travaille sur SeraPlot gratuitement, en plus de mon travail. Si cela vous fait gagner du temps, un don est le bienvenu — mais il n'y a aucun besoin de faire un don pour me faire une demande de fonctionnalité.

Soutenir via PayPal

Merci d'utiliser Sera ✨