Hi Plotly community!
Just wanted to highlight this cool plotlyml project 
- GitHub: GitHub - samibahig/plotlyml: ML Monitoring Visualization Primitives for Plotly β Distribution Drift, Model Disagreement, Quantile Evolution Β· GitHub
- Live demo on Plotly Cloud : https://plotlyml-visual-primitaves-for-ml.plotly.app/
This library provides three new high-level functions for plotly that address a real gap in the ML observability and data science space. These are general-purpose visualization primitives β not domain-specific β that fill gaps common in production ML workflows.
1. distribution_drift(reference, current, ...)
What it does: Compares two distributions (e.g. training vs. live inference data) with overlapping normalized histograms and a scalar KL-divergence annotation. When drift exceeds a configurable threshold, the current distribution is highlighted in a warning color.
fig = distribution_drift(
reference, # array-like: baseline samples
current, # array-like: current samples
bins=50,
divergence_threshold=0.1,
reference_name="Reference",
current_name="Current",
title=None,
template=None,
)
Gap it fills: px.histogram with barmode="overlay" gets you close, but thereβs no built-in divergence scoring, threshold annotation, or drift-aware color logic. This is a one-liner for a very common ML monitoring pattern.
2. model_disagreement(x, y, predictions, ...)
What it does: Scatter plot of samples in a 2-D reduced feature space (UMAP/t-SNE/PCA), colored by ensemble variance. Samples above a disagreement threshold are fully opaque; others are dimmed. Includes a marginal histogram of variance scores.
fig = model_disagreement(
x, # dim 1 of reduced space (per sample)
y, # dim 2 of reduced space
predictions, # shape (n_samples, n_models) β ensemble preds
threshold=0.05,
colorscale="Viridis",
title=None,
template=None,
)
Gap it fills: px.scatter with color= handles the spatial encoding, but computing ensemble variance, dimming low-uncertainty samples, and combining with a marginal histogram requires significant boilerplate. This surfaces a critical active-learning and model-audit pattern as a single call.
3. quantile_evolution(timestamps, p50, *, p10, p90, p25, p75, ...)
What it does: Layered ribbon/band chart tracking P10βP90 and P25βP75 bands with P50 as a bold center line, over time or cohorts. Automatically annotates timestamps where the spread exceeds a volatility threshold.
fig = .quantile_evolution(
timestamps, # x-axis: ISO strings, labels, or numbers
p50=median_values, # required: median (center line)
p10=p10_values, # optional: outer lower band
p90=p90_values, # optional: outer upper band
p25=p25_values, # optional: IQR lower bound
p75=p75_values, # optional: IQR upper bound
mean=mean_values,
show_mean=False,
volatility_multiplier=1.5,
title=None,
template=None,
)
Gap it fills: Building fill-between ribbon plots requires chaining 5+ go.Scatter traces with careful fill="tonexty" sequencing. This is error-prone and undiscoverable. A single px call makes this pattern accessible to the full data science audience.


