Skip to content

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 off result.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 .html instead. 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