Interactive visualizations¶
ParleML MLI provides Plotly figures across archetypes, explanations, rules, evaluation, EDA, per-row decision support, anomaly detection, clustering, and forecasting.
In short
- Every plot helper returns a Plotly
go.Figure: hover, zoom, pan and toggle series. - Archetype, explanation and rule charts hang off the
ProfilingResult; EDA charts offresult.eda_. - Evaluation, per-case, anomaly, clustering and forecasting charts are functions in their own
modules, such as
parleml_mli.evaluation.plots. - Pass
save_path=...to write HTML, or a static image when Kaleido works. - A 2-D cluster or anomaly map is a display layout, not the space the model worked in.
They share one design:
- Interactive data charts — hover, zoom, pan and toggle series. Plot helpers
return a Plotly
go.Figure; some tree / SHAP views embed a rendered image inside that figure rather than making its contents interactive. - Consistently themed — one house theme (light/dark aware) across all figures.
- Embeddable & exportable — drop into a web app / notebook, or pass
save_path=...to write HTML or request a static image. The shared exporter uses CDN-hosted Plotly JavaScript for HTML. Static export needs a working Kaleido setup; if it fails, the exporter logs a warning and writes.htmlinstead. Check the actual output file.
Quickstart¶
Most figures hang directly off the ProfilingResult; explanation and EDA plots
live on the explanations_ / eda_ sub-results:
from parleml_mli import (
ProfilingConfig, ArchetypeConfig, RulesConfig, ExplanationsConfig,
PdpConfig, AleConfig, EDAConfig, fit_profiler,
)
result = fit_profiler(
model=clf, X=X_train, y=y_train, target_mask=(y_train == 1),
config=ProfilingConfig(
archetypes=ArchetypeConfig(n_bootstrap=20),
rules=RulesConfig(),
explanations=ExplanationsConfig(
pdp=PdpConfig(features=["age"]), ale=AleConfig(features=["age"]),
),
eda=EDAConfig(),
),
)
# This example assumes a non-constant numeric "age" column in X_train.
# Archetype / importance / rules figures — directly on the result:
result.plot_umap() # returns a go.Figure
result.plot_stability(save_path="stability.html") # save interactive HTML
result.plot_rules(save_path="rules.png") # or a static PNG
# Global explanations — on result (or result.explanations_):
result.plot_pdp("age")
result.explanations_.plot_ale("age")
# EDA figures — on result.eda_:
result.eda_.plot_correlation_matrix()
result.eda_.plot_variable("age")
Evaluation, anomaly, clustering, and forecasting figures are exposed as functions
in their respective modules (parleml_mli.evaluation.plots, parleml_mli.unsupervised.anomaly.plots,
parleml_mli.unsupervised.clustering.plots, parleml_mli.forecasting.plots) — see those sections
below.
Archetype & cohort profiling¶
| Chart | Shows |
|---|---|
plot_umap() / plot_umap_scores() |
2-D UMAP of the population, coloured by archetype or by model score |
plot_landscape() |
Python landscape helper requires attached narration with groups and archetype data. Studio's treemap can also show computed archetypes without narration (MLI in Studio). |
plot_sizes() |
Archetype sizes / coverage |
plot_scores() |
Model-score distribution per archetype |
plot_feature_heatmap() |
Archetype × feature signature heatmap (standardized) |
plot_stability() |
Bootstrap-stability of each archetype |
plot_prediction_scatter() |
Predicted vs. reference scatter, archetype-coloured |
plot_error_analysis() |
Per-archetype error breakdown |
Global explanations¶
| Chart | Shows |
|---|---|
plot_pdp(feature) |
Partial-dependence with an ICE band |
explanations_.plot_ale(feature) |
Accumulated Local Effects (correlation-robust) |
plot_permutation_importance() |
Permutation feature importance |
plot_shap_interactions() |
SHAP interaction strengths |
plot_psi() |
Class separation or monitoring drift, according to the recorded comparison basis |
plot_compacity() |
How few features explain each prediction |
plot_fairness(feature) |
Disparate-impact by group (AIR / ME / SMD) |
plot_error_tree() |
Error tree — the feature cohorts where the model is weakest |
Rules¶
| Chart | Shows |
|---|---|
plot_rules() |
Mined IF-THEN rules with recall / precision; the hover adds each rule's Test numbers and holds-up verdict when the rules were measured on held-out rows |
plot_rules_cumulative() |
Cumulative recall / precision (or coverage) of the rule portfolio as rules are added — the Test curve beside the Train one when measured |
plot_rules_feature_frequency() |
Which features drive the fired rules |
Model evaluation & calibration¶
Functions in parleml_mli.evaluation.plots, called on a split evaluation from
result.model_evaluation_.splits:
| Chart | Shows |
|---|---|
plot_confusion_matrix() / multiclass |
Confusion matrix |
plot_roc_curve() / plot_precision_recall_curve() |
ROC and PR curves |
plot_lift_chart() / plot_gains_chart() / plot_ks_chart() |
Lift, cumulative gains, and K-S |
plot_threshold_metrics() |
Metrics vs. decision threshold |
plot_score_distribution() |
Predicted-score histogram by class |
plot_reliability_diagram() |
Calibration (reliability) curve |
plot_business_value() |
Expected business value vs. threshold |
plot_actual_vs_predicted() / plot_residual_histogram() |
Regression fit and residuals |
EDA & data quality (Autoviz-style)¶
Called on result.eda_ (e.g. result.eda_.plot_correlation_matrix()):
| Chart | Shows |
|---|---|
plot_target_correlations() / plot_correlation_matrix() |
Feature↔target and feature↔feature correlation |
plot_correlation_graph() |
Correlation network |
plot_missingness() / plot_outliers() |
Missingness map and outlier detection |
plot_variable(feature) / plot_distribution_alerts() |
Univariate distributions with automatic alerts |
plot_transformation_recommendations() |
Suggested transforms (the current skewness when none is suggested) |
plot_category_variability_heatmap() |
Categorical × numeric variability |
plot_shape_radar() |
Per-feature distributional shape |
The row-level figures draw sampled rows of the dataset, so the result stores none
of their data; build them from the frame the EDA ran on with
parleml_mli.eda.render_autoviz_figure(kind, df, result=result.eda_):
kind |
Shows |
|---|---|
"correlated_scatter" |
The top over-correlated pairs (scatter, box or stacked bars by type) |
"category_boxplots" |
One categorical × numeric pair (cat_col= / num_col=); proportion bars for a binary numeric |
"biplot" |
PCA biplot |
"parallel_coordinates" |
Parallel coordinates of the top numeric features |
Per-row decision support¶
Functions in parleml_mli.local.plots, applied to a CaseExplanation from justify:
| Chart | Shows |
|---|---|
plot_ice_for_case() |
ICE curves for a single case |
plot_loco_for_case() |
Leave-one-covariate-out impact for a case |
plot_archetype_counterfactual() |
The nearest counterfactual toward another archetype |
Anomaly detection¶
Eighteen dedicated figures in parleml_mli.unsupervised.anomaly.plots, including score
distribution and score-vs-threshold, a top-K findings table and findings cards, an
anomaly map, per-feature contribution, detector comparison / agreement, quality
panel and radar, threshold sensitivity, a labeled ROC/PR view, a score time-series,
and the auto-mode ADEngine rationale.
plot_score_distribution() bins both series once, over all scores, so the two
overlaid histograms share their bins and compare bar for bar. The ADEngine rationale card
reports the router's shortlist weight as "Router rule weight (KB constant, 0–1)"
— it is the constant PyOD's hand-authored routing_rules.json writes against a
detector for a dataset of this shape, not a confidence measured on your data.
Clustering¶
Functions in parleml_mli.unsupervised.clustering.plots: plot_cluster_map(),
plot_cluster_sizes(), plot_cluster_profile_heatmap(), plot_auto_k_sweep(),
plot_quality_metrics(), and plot_silhouette().
plot_quality_metrics() draws silhouette, Davies–Bouldin and Calinski–Harabasz
in three separate panels with their own ranges and directions — the three are
incommensurable (silhouette ∈ [-1, 1], DB ∈ [0, ~5], CH unbounded and routinely
10²–10⁴), and on one shared axis CH sets the scale and the other two render as
zero. CH is a bare number rather than a bar because it has no reference scale.
Every negative clustering label is a rejection, not a cluster, and there are
three of them: -1 (density noise), -2 (the row held inf) and -3 (the row
held NaN). parleml_mli.unsupervised.analysis.cluster_legend_label() is the single
statement of how they are named on a chart; non_noise_mask() is the single
statement of how they are excluded from a computation.
The 2-D map is a third space¶
plot_cluster_map() and plot_anomaly_map() render parleml_ml4.unsupervised.Embedding2D
coordinates. That embedding is fitted for display after the fact and consumed by
no detector: the clustering algorithm worked in result.geometry_space, the
quality indices were computed on the fused feature matrix, and above
embedding_n_samples the layout itself is fitted on a subsample with every row
re-projected in (for UMAP, an approximate placement into a frozen layout).
Pass embedding_summary=pipeline.embedding.fit_summary so the chart can state the
method, the row counts and the fit regime in its subtitle:
fig = plot_cluster_map(
result,
coords=pipeline.embedding_coords,
embedding_summary=pipeline.embedding.fit_summary,
)
Omitting it is still honest — the subtitle then says the method was not recorded rather than guessing. Either way the subtitle disclaims the plane, because proximity here does not reflect feature-space similarity: UMAP and t-SNE preserve local neighbourhoods only, and gap widths, blob sizes and global layout mean nothing; PCA distances are real but only within two directions. Never tune a model from this picture — cross-check on the silhouette and the profile heatmap, which are computed in the feature space.
Forecasting¶
Functions in parleml_mli.forecasting.plots: forecast plots with prediction-interval
bands (plot_forecast_plot), residual diagnostics, a per-series model-selection
summary, coverage calibration, accuracy-by-horizon, and tree-backend SHAP
explanations.
plot_forecast_plot draws the deployed model per series (pass
show_candidates=True for the whole raced field), and the CV-derived diagnostics
— residual ACF/PACF and actual-vs-predicted — are computed per rolling-origin
window rather than over the stacked backtest table.
Feature importance and Shapley are tree-backend views. On a stats, foundation or
AutoGluon-TS run these surfaces render an explanation of why rather than
disappearing: plots.interpretability_note(result) is that copy, and
plots.BACKEND_INTERPRETABILITY is the single per-backend table behind it. Render
it — never use it to hide a tab, or the analyst cannot tell "not applicable to
this backend" from "this run failed".
Choosing which forecast model to explain¶
A tree-backend run can fit several model specs and pick a winner per series, so
every explain surface in parleml_mli.forecasting.tree_explain — native importance, SHAP
importance, the per-prediction waterfall, the per-horizon and per-series heatmaps,
and the tree diagrams — takes the same two selectors:
from parleml_mli.forecasting.tree_explain import plot_tree_shap_importance
# the model that won selection for this series
fig = plot_tree_shap_importance(pipeline, series="store_42")
# or pin a spec explicitly
fig = plot_tree_shap_importance(pipeline, alias="LGBM_lag24")
Resolution order is alias → the winner for series → the modal winner across
series (resolve_modal_winner, used when neither selector is given) → the first
fitted spec. Each figure states which rule applied in its subtitle, so a chart can
never quietly describe a model that lost selection. An alias that matches no
fitted spec raises SpecResolutionError rather than falling back — asking for a
specific model and getting a different one is exactly the failure this guards.
modal_winner_alias(pipeline) gives the deployed alias on its own, so a
provenance block can show a divergence between what shipped and what is being
explained instead of asserting they match.
The two halves are separate modules: parleml_mli.forecasting.tree_spec answers which
model and what data (resolve_spec, SpecChoice, training_matrix,
pipeline_uses_tree_backend) with no plotting, and parleml_mli.forecasting.tree_explain
is the figure surface built on it. Reach for tree_spec when you want the fitted
booster and its design matrix for your own analysis.
Supervised figures consume the profile's computed artifacts; forecasting and unsupervised figures consume their own ML4 results and may need additional frames or embedding coordinates. Check artifact presence and provenance before comparing charts from different models, splits or recomputations.
Next¶
- Global explanations: what each explanation chart is computed from.
- Consuming saved results: draw charts from a saved result.