Plots reference (mapi-plots)¶
mapi-plots has two parts. Each part has different dependencies:
| Install | Modules | Imports | Runs in |
|---|---|---|---|
mapi-plots |
mapi_plots.sanitize, mapi_plots.templates |
mapi-spec, jsonschema (JSON only) |
API server, runner, notebooks |
mapi-plots[recipes] |
mapi_plots.convert, mapi_plots.recipes, mapi_plots.packs, mapi_plots.examples |
+ altair, plotly, numpy, pandas, pyarrow, xarray | runner images, notebooks |
An import-linter contract makes sure that the sanitizer and the templates do not import
numpy, pandas, xarray, pyarrow, altair, plotly or mapi_sdk. import mapi_plots loads no
large modules, because the exports are lazy.
The PlotSpec envelope¶
The contract package mapi_spec.plots defines the envelope:
id: core.ppc_fan # [A-Za-z0-9_.-]{1,128}
title: Fit and forecast
kind: vega-lite # or plotly
spec: {...} # Vega-Lite JSON, or Plotly {data, layout, frames, config}
datasets: # referenced BY NAME only
fan: {kind: inline_arrow, data: <base64 Arrow IPC stream>, rows: 84}
big: {kind: data_ref, path: ui/plotdata/fan.arrow, format: arrow}
bindings: {x: "dim:time", y: "role:target", facet: "dim:geo"} # templates only
schema_version: v6.4.1
persona: both # guided | expert | both
caption_plain: "The line is the model's median estimate ..."
provenance: {recipe: core.ppc_fan@1.0.0, bundle_id: ..., generated_at: ...}
- Vega-Lite references data with
{"data": {"name": "fan"}}. - Plotly references a column with
{"$ref": "<dataset>.<column>"}in a data-array attribute. It also uses this reference inarrayOkattributes, for examplemarker.color. The part before the first.is the dataset. The remaining part is the column (trace0.marker.color→ datasettrace0, columnmarker.color). The JSON Schema of the reference ismapi_plots.sanitize.PLOTLY_REF_SCHEMA. It is also in the filemapi_plots/sanitize/schemas/plotly-ref.schema.json:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "urn:mapi:schema:plotly-dataset-ref:v1",
"type": "object",
"properties": {"$ref": {"type": "string",
"pattern": "^[A-Za-z_][A-Za-z0-9_\\-]{0,63}\\.[A-Za-z_][A-Za-z0-9_.\\-]{0,127}$"}},
"required": ["$ref"],
"additionalProperties": false
}
- The maximum size of each inline Arrow dataset is 2 MiB of base64. Recipes write datasets in a compact format (float32, int32, dictionary-encoded strings). Timestamps are UTC milliseconds.
Sanitizer¶
from mapi_plots.sanitize import sanitize_plot, check_plot, sanitize_spec, SanitizeLimits
result = sanitize_plot(doc) # PlotSpec | dict | JSON str | bytes
result.plot # validated, sanitized PlotSpec
result.changes # list[Issue] (severity info): HTML stripped, $schema pinned ...
issues = check_plot(doc) # errors + changes, never raises
spec, changes = sanitize_spec("plotly", figure_dict) # bare spec, no envelope
SanitizeError is a MapiError. err.issues lists all violations, up to max_issues. Each
violation has these items:
- An RFC 6901
pointer. - A
messagethat the platform wrote. - The rule, in
context["rule"]. - Text from the user, if there is some. This text is only in
untrusted_text.
err.rules is the set of rules that fired. The error code is the most severe code that is
present:
| Code | HTTP | Rules |
|---|---|---|
PLOT_UNSAFE |
422 | url_data, href, external_image, tile_map, proto_key, script_url, css_url, expression, format_type, config |
PAYLOAD_TOO_LARGE |
413 | too_large, too_deep, too_many_nodes, string_too_long, array_too_long |
SPEC_PARSE_ERROR |
400 | parse (JSON that is not valid, duplicate keys, NaN/Infinity) |
SCHEMA_INVALID |
422 | schema, envelope, dataset_ref, typed_array |
Changes use the rules html_stripped, schema_url and template_pruned. Changes are not
errors.
Limits¶
SanitizeLimits field |
Default |
|---|---|
max_document_bytes |
16 MiB (the full PlotSpec, with the inline Arrow data) |
max_spec_bytes |
2 MiB (the spec member) |
max_depth |
48 |
max_nodes |
200 000 |
max_string_bytes |
64 KiB (the envelope sets the limit for inline Arrow payloads) |
max_array_items |
100 000 |
max_expr_chars |
2 000 |
max_typed_array_bytes |
8 MiB |
max_issues |
50 |
Vega-Lite rules¶
$schemamust be an official Vega-Lite v5 or v6 URL, or not present. The sanitizer sets it to v6.4.1.- The spec must be valid against the vendored Vega-Lite v6.4.1 JSON Schema (draft-07, local
$refs only). - Do not use these items: a
urlkey at any location,href, and theimagemark.formatTypecan only benumber,timeorutc. Do not enableconfig.customFormatTypes. -
Expressions must use only Vega functions from the allow list. Expressions are:
expr,calculateandfilter/teststrings, and theirand/or/notcompositions.- Each
…Exprkey, for examplelabelExpr. - Filters in brackets in selection event streams.
The sanitizer rejects these items: method calls,
this/new, assignment, statements, template and regex literals, and\u/\xescapes. It also rejects non-ASCII characters outside strings, and computed member access with a key that is not a literal. It also rejects browser globals (window,document,fetch,globalThis…) andevent.view.
Plotly rules¶
- The top level has only
data,layout,framesandconfig. - The sanitizer does a check of trace types, attribute names and value types against a table.
This table comes from the official plotly.js 4.1.1
plot-schema.json. It has enumerations, flag lists, subplot ids, colour scales and info arrays. It also has subplot keys of thexaxis2type, and template keys of theannotationdefaultstype. - Unknown attributes are errors. In
layout.template, the sanitizer removes unknown attributes and tile-map sections, and reports them. - Data arrays are inline lists, dataset references or plotly.py typed arrays
(
{dtype: i1|u1|u1c|i2|u2|i4|u4|f4|f8, bdata, shape?}). The sanitizer does a check of the base64, length and shape of typed arrays. - The sanitizer rejects these items:
- Tile-map traces and subplots.
- Image sources that are not
data:image/(png|jpeg|gif|webp);base64. This rule also applies in the relayout arguments ofupdatemenus/sliders. url/href/topojsonURLkeys.- Network
configoptions.
- Strings can keep only
<b> <i> <br> <sub> <sup>. The sanitizer removes attributes and escapes a stray<.<extra>stays in hover templates.
Vendored schemas¶
| File | Source | Regenerate |
|---|---|---|
vega-lite-v6.4.1.json |
https://vega.github.io/schema/vega-lite/v6.4.1.json (byte-for-byte) |
scripts/vendor_schemas.py --download |
plotly-structure-v4.1.1.json |
made from plotly.js@v4.1.1/dist/plot-schema.json |
same |
VENDORED.json |
source URLs and SHA-256 digests (a unit test does a check of them) | same |
Templates (mapi_plots.templates)¶
resolve_bindings(bindings, schema, *, optional=()) -> dict[channel, BoundField | list[BoundField]]
apply_template(plot, schema, *, optional=(), title=None) -> PlotSpec
template_issues(plot, schema, *, optional=()) -> list[Issue]
| Binding | Resolves to | Vega-Lite type |
|---|---|---|
dim:<name> |
a dim of the schema | time → temporal, numeric → quantitative, ordered/index → ordinal, other → nominal |
role:<role> |
the one variable with that role (lists for tooltip) |
from the dtype |
var:<name> |
that variable | from the dtype |
coord:<name> |
a coordinate (dim or not) | from the dim, or nominal if it is not a dim |
stat:<name> |
a summary statistic column (mean, hdi_90_lower, q5 …) |
quantitative |
render_template(template, data, schema=None, *, group=None, value=None, optional=()) (extra
recipes) also makes the dataset from an xr.Dataset or a tree group. The default schema is
attrs["mapi_schema"]. If that is not available, the function infers the schema. It gets the
roles from the role attribute of each variable.
Recipes (mapi_plots.recipes)¶
get_recipe(id) -> Recipe # bundled recipes (core + packs)
standard_recipes() -> list[Recipe] # entry point mapi.plots: core
mapi_plots.packs.mmm.mmm_recipes() # entry point mapi.plots: mmm
mapi_plots.packs.ml.ml_recipes() # entry point mapi.plots: ml
mapi_plots.packs.sci.sci_recipes() # entry point mapi.plots: sci (Plotly)
mapi_plots.packs.net.net_recipes() # entry point mapi.plots: net (Plotly)
mapi_plots.packs.causal.causal_recipes() # entry point mapi.plots: causal (v0.13)
Recipe.render(data, **settings) -> PlotSpec # also Recipe(data, **settings)
Recipe.catalog_entry() -> PlotCatalogEntry # id, version, persona, required groups/representation
# what the runner calls for outputs.plots: never raises for a single bad plot
report = render_plots(tree, ["core.ppc_fan", "mmm.response_curves@^1"],
registry=None, options={"core.ppc_fan": {"facet": "market"}})
report.plots # sanitized PlotSpecs
report.issues # skipped plots: REF_UNRESOLVED / SCHEMA_INVALID / USER_CODE_ERROR
# (warnings) and PLOT_UNSAFE (error)
report.to_json() # plots.json sidecar body
To write your own recipe, use the decorator. The result works with Registry.register and
the mapi.plots entry-point group:
import altair as alt
from mapi_plots.recipes import Figure, RecipeSettings, named, recipe
class Settings(RecipeSettings):
var: str = "y_hat"
@recipe("acme.weekly_total", title="Weekly total", settings=Settings, persona="guided")
def weekly_total(inp, s: Settings) -> Figure:
ds = inp.require("summary")
frame = ds[s.var].sel(stat="mean").sum("market").to_dataframe().reset_index()
chart = alt.Chart(named("weekly")).mark_line().encode(x="date:T", y=f"{s.var}:Q")
return Figure(chart, {"weekly": frame}, caption=f"Total {s.var} per week.")
A recipe can also return a Plotly figure (plotly.graph_objects.Figure or a
{data, layout, frames} dict) in Figure.chart. Recipe.render then sends it through
from_plotly with the same title, caption, persona and provenance. The recipe can also give
its own DataFrames in Figure.datasets. The traces then refer to their columns with
{"$ref": "<dataset>.<column>"}. The function plotly_plot applies the inline-text rules to
the string columns of these DataFrames.
Settings shared by every recipe¶
title (override), width (480), height (180). The recipe rejects unknown settings.
Per-recipe settings¶
| Recipe | Settings (defaults) |
|---|---|
core.data_overview |
group, vars, along, facet, max_vars (8), max_levels (12), max_rows (20 000) |
core.prior_predictive |
var, num_draws (50), along, levels ([0.5, 0.9]) |
core.convergence |
var_names, max_parameters (40), max_traces (6), max_draws (400), max_elements (2 000), rhat_threshold (1.01), ess_per_chain (100), bins (20), table_rows (15) |
core.posterior_forest |
var_names, hdi_prob (0.94), inner_prob (0.5), point (median), max_rows (60) |
core.ppc |
var, observed_var, num_draws (50), bins (20), levels |
core.ppc_fan |
var, observed_var, along, facet, max_facets (12), levels ([0.5, 0.9]), point (median), split_at, columns (3), max_rows |
core.fit_vs_actual, core.residuals_over_time |
var, observed_var, along, facet, max_facets, point |
core.decomposition, mmm.decomposition |
vars, component (auto / channel), along, hdi_prob (0.9), max_components (20). core.decomposition skips a variable with the attr decomposition: exclude if vars does not name it. mmm.decomposition also has outcome (none: attrs.primary_outcome or the first level of an outcome dim). |
core.model_comparison |
ic (auto: precomputed table, else WAIC), var, model_dim (model) |
core.counterfactual |
var, along, hdi_prob (0.9), bins (30) |
core.decision_distribution |
var, candidate, hdi_prob, higher_is_better (true), max_candidates (12) |
core.pair |
var_names, max_params (5), max_draws (500), bins (20), width (520) |
core.ridge |
var, group (auto | posterior | predictions | posterior_predictive), dim, select, hdi_prob (0.94), max_levels (30), max_draws (4 000), points (100), overlap (1.6), descending (true) |
core.rank_matrix |
var, group, dim, select, descending (true: rank 1 is the largest value), max_items (30), max_draws (4 000), labels (auto | always | never) |
core.calibration |
var, observed_var, kind (auto | continuous | binary), prob (0.95), bins (10), n_sim (1 000), seed (0) |
core.state_sequence |
var, group (auto | hidden_states | regimes | posterior | predictions | posterior_predictive | summary | root), state_dim (auto: state, then regime), along, observed_var, select (none: the first level of each other dim), max_states (10), max_times (2 000), max_draws (4 000), width (640), height (140) |
core.roc_pr |
var, observed_var, positive (the larger target value), max_points (500, 20 to 5 000), classes (v0.14, multiclass: the classes to draw; default the 12 most frequent), width (320), height (280) |
core.confusion |
var, observed_var, positive, threshold (0.5, or auto: the largest TPR − FPR), normalize (none | true), width (260), height (240). Multiclass (v0.14): threshold and positive are not used. |
core.loss_curve |
var, group (auto | fit_history | metrics_history), along (step), smooth (none: a window of n / 50 steps), log_y (none: log when max / min > 50), max_points (2 000), width (560), height (220) |
core.loo_pit |
var (a log_likelihood variable), observed_var, prob (0.95), n_sim (1 000), seed (0), max_draws (2 000), k_threshold (0.7) |
core.energy |
bfmi_threshold (0.3), bins (40) |
core.prior_posterior |
var_names (none: every variable in the two groups), max_vars (12), max_cells (8), points (80, the points of each density), little (0.8, the overlap above which the caption says that the data adds little) |
mmm.response_curves |
var, channel, grid, spend_var (spend), current_var (current_spend), hdi_prob, facet |
mmm.marginal_cost |
the same as response curves, + metric (cost | roi), clip_quantile (0.98) |
mmm.budget_plans |
spend_var, outcome_var, plan, channel, reference, hdi_prob |
mmm.prior_beliefs |
channel (channel), height (26, the height of one channel row) |
mmm.roi |
hdi_prob (0.9), breakeven (1.0; none: no line), channel (channel) |
mmm.adstock |
hdi_prob (0.9), facet (false) |
mmm.waterfall |
hdi_prob (0.9), outcome (none: attrs.primary_outcome or the first level) |
mmm.spend_effect |
hdi_prob (0.9), channel (channel) |
mmm.lift_tests |
hdi_prob (0.9), z (1.96, the width of the error bar of a test in standard errors) |
mmm.effectiveness |
hdi_prob (0.9), only_varying (true) |
mmm.mediation |
hdi_prob (0.9) |
mmm.cross_effects |
hdi_prob (0.9) |
ml.feature_importance |
top (20), feature_dim (feature), source (auto | importance | coefficients) |
ml.training_curves (v0.15) |
keys (none: loss and accuracy or rmse, a maximum of 4 panels), label (split), x (step | epoch), smooth (none), log_y (none), max_points (2 000) |
ml.confusion_epochs (v0.15) |
epochs (none: the first, evenly spaced, the best and the last, a maximum of 6), normalize (true | none), max_classes (20; the others are "(other)") |
ml.misclassified (v0.15) |
max_items (24), columns (6). Plotly image traces with z pixel arrays (no source) |
sci.field_map |
var, group (auto | posterior | predictions | posterior_predictive), y, x, frame, select, stats ([mean, sd]; also median, z, q05, q95, draws), n_draws (3), max_draws (400), max_cells (40 000), max_frames (24), colormap, log, origin, aspect (equal | auto), columns (3), width (760), height (280, one row of panels) |
sci.vector_field |
the same as sci.field_map (no n_draws), + component, stats ([mean, sd]; also q05, q95), arrows (20) |
sci.profile_bands |
var, group, observed_var, along, by, select, levels ([0.5, 0.9]), point (median | mean), max_curves (12), max_draws (1 000), colormap (viridis), log (false), width (640), height (360) |
sci.ensemble |
var, group, observed_var, along, select, n_draws (40), levels ([0.9]), point (median | mean | none), max_draws (2 000), seed (0), log (false), width (640), height (320) |
sci.area_map |
var, group, observed, stats (observed, mean, sd, exceedance; also median), threshold (1 for a non-negative output, else 0), mark_above (0.95), log_scale (false), show_edges (false), select, colormap (viridis), classes (9), max_draws (2 000), max_vertices (40 000), columns (2), width (760), height (340, one row of panels) |
sci.phylogeny |
var, group, tip_dim, observed, interval (0.9), point (mean | median), max_tips (400), max_draws (2 000), labels (up to 80 tips), select, colormap (viridis), width (780), height (0: from the number of tips) |
sci.rose |
var, group, observed, angle_dim, units (radians | degrees | hours | days), period, bins (24), frame, select, interval (0.9), scale (auto | count | share), clockwise, max_draws (1 000), max_frames (24), width (560), height (520) |
sci.image_residuals |
the same as sci.field_map (no stats, n_draws), + observed_var, sigma (a variable or a number), sigma_kind (sd | variance | inverse_variance), columns (2), hist_height (200; 0: no histogram). group auto reads posterior_predictive, predictions, posterior |
sci.ppc_image_grid |
the same as sci.field_map (no stats), + observed_var, n_draws (5, at most 11), shuffle (false), seed (0). group auto reads posterior_predictive, predictions, posterior |
sci.swatches |
var, group, observed_var, channel (rgb), item, row (row), col (col), arrange (auto | list | map), prob, prob_as (border | opacity), select, n_draws (3), max_draws (400), max_items (60, list only), tile (20 px), columns (2), seed (0), width (640) |
sci.power_spectrum |
var, group, observed_var, error_var (default <observed>_sd), theory, along, x_coord, select, levels ([0.5, 0.9]), point (median | mean), max_draws (2 000), log_x, log_y (false), width (640), height (360) |
sci.point_pattern |
points (the point dim), x (x), y (y), sd_x (sd_x), sd_y (sd_y), radius (radius), group (auto | none | a variable), field (auto | none | a variable), field_stat (mean | median | sd), ellipses (auto), level (0.9), observed (true), select, max_points (20 000), max_ellipses (2 000), max_cells (40 000), colormap, origin, marker_size (6), width (640), height (560) |
net.graph |
var, node_dim, positions (auto | none | a variable), threshold (auto), signed (auto), directed (auto), group (auto | none | a variable), truth (auto | none | a variable), panels (both | graph | matrix), select, labels (auto), max_nodes (300), max_edges (2 000), seed (0), width (900), height (440) |
Extra core recipes¶
These recipes are in the core pack (mapi_plots.recipes.extras, classification, training and loo, Vega-Lite):
| Recipe | What it shows |
|---|---|
core.pair |
A corner plot of up to max_params scalar parameter elements. Below the diagonal: thinned draws of each pair. On the diagonal: a histogram of each parameter. Red points are divergent transitions (sample_stats.diverging). |
core.ridge |
One density for each level of dim, sorted by the mean, with a dot for the mean and a bar for the HDI. Each curve has the same peak height. |
core.rank_matrix |
P(rank = k) for each item, sorted by the expected rank, and the matrix of P(row above column). Input: draws (…, item). |
core.calibration |
Continuous targets: the PIT-ECDF difference with a simultaneous envelope (simulated). Targets with values 0 and 1: a reliability diagram with a binomial band for each bin and a histogram of the predicted probabilities. A point prediction (no draws, values from 0 to 1) uses the reliability diagram. A point prediction of a target that is not 0/1 gives an error, because the PIT check needs draws. |
core.state_sequence |
The observed series (points coloured by the most likely state) above the stacked state probabilities. Input: probabilities (…, state, time) with or without draws, a score summary with a stat dim (the plot uses mean), or integer state draws (chain, draw, time). The default variable is smoothed_prob, state_prob or filtered_prob. Without select, the plot fixes each other dim at its first level and the caption names that level. |
core.roc_pr |
Two panels: the ROC curve with the diagonal of a random guess, and the precision-recall curve with the base rate. The titles give the AUC and the average precision. With draws, the caption gives the 90% interval of the AUC (up to 500 draws). Multiclass (v0.14): one-vs-rest curves in a colour for each class, the macro AUC in the title, and the number of classes that are not drawn in the caption. |
core.confusion |
The 2 × 2 table of the actual class and the predicted class at the threshold, as counts or as the share of each actual class. The caption gives the accuracy, the precision, the recall, the specificity, the F1 score and the threshold. Multiclass (v0.14): a K × K table of the most probable class (a maximum of 30 classes; the other classes are (other)), with the accuracy and the macro F1. |
core.loss_curve |
The raw loss (light) and a rolling mean (dark) over the steps, one line for each level of an extra dim (at most 8). The caption gives the first and the last smoothed value and the change over the last 10% of the steps. |
core.loo_pit |
The LOO-PIT ECDF difference with a simultaneous envelope (when posterior_predictive and observed_data are present), and the PSIS Pareto k of each observation with lines at 0.5 and k_threshold. |
The recipes core.calibration, core.roc_pr and core.confusion share one input rule. They
look for the prediction in the posterior_predictive, predictions and draws groups (with
draws, or one probability for each cell), then in summary (stat mean, point or median). The
actual values come from observed_data or observed. The two arrays are aligned on their shared
cells, and cells with NaN are left out. For a binary target, the target must have two values.
The larger value is the positive class unless you set positive. The predictions must be from
0 to 1. From v0.14, core.roc_pr and core.confusion change to multiclass when the prediction
has a class dim (meaning: class_probability, the probabilities of the classes add up to 1)
or when the actual target has more than two values. The actual classes can be text or whole
numbers (3.0 is the class 3).
Marketing-mix recipes of v0.12¶
All of these recipes accept draws with a sample dim or with chain and draw dims. A
recipe that does not find its group or variable raises RecipeDataError. The runner then
skips only that plot.
| Recipe | Input | What it shows |
|---|---|---|
core.energy |
sample_stats.energy(chain, draw) |
The centred marginal energy and the energy transitions (two histograms), and the BFMI of each chain, mean(diff(E)²) / var(E). The caption names the chains below bfmi_threshold. |
core.prior_posterior |
variables with chain/draw dims in prior and in posterior |
A density of the prior and of the posterior for each parameter cell, ranked by |Δmean| / sd(prior). The caption gives the overlap of each panel. An overlap above little (0.8) means that the data adds little. |
mmm.roi |
response_curves: contribution at multiplier 1 divided by current_spend (other dims summed). marginal_cost.marginal_roi_total, else a central difference on the grid around 1 |
A forest of the ROI of each channel (median and HDI), the mROAS next to it, and a break-even line |
mmm.adstock |
adstock: weight(sample, channel, lag), optional mean_lag |
The weight of each lag with an HDI band, one line for each channel (or one panel with facet) |
mmm.waterfall |
contributions: channel_contribution and every other variable as a component |
The total of each component over the fit window as steps to the total result |
mmm.spend_effect |
response_curves: contribution at multiplier 1 for each draw and current_spend |
The share of spend and the share of effect of each channel side by side |
mmm.lift_tests |
the lift_tests group: observed(test), observed_sd(test), model(chain, draw, test) and the coords channel, estimand, start, end, geo |
Each test (value ± z standard errors) next to the model estimate (HDI) |
mmm.effectiveness |
effectiveness(sample, channel, time), time_varying(channel) |
The effect of one unit of spend in each period with an HDI band |
mmm.mediation |
mediation: direct(sample, channel), indirect(sample, channel, mediator) |
Stacked direct and indirect effects of each channel, with the share that the mediators carry |
mmm.cross_effects |
cross_effects: psi(sample, pair) and the coords source, target, kind |
A forest of each cross-effect with its kind |
Causal pack (causal.*) v0.13¶
The causal models (causal.impact, causal.synthetic_control, causal.did) write their
results to bundle groups that these recipes read. See
Causal models. All recipes accept draws
with a sample dim or with chain and draw dims. A recipe that does not find its group
raises RecipeDataError. The runner then skips only that plot. The recipes send medians and
intervals for each period to the sanitizer, not the draws.
| Recipe | Input | Settings | What it shows |
|---|---|---|---|
causal.impact |
impact: actual, counterfactual, effect, cumulative_effect, post |
hdi_prob (0.9), unit (none: the sum over the unit dim), panels (series, pointwise, cumulative) |
Three panels on one time axis: the actual values with the median and HDI band of the values without the change, the effect in each period, and the cumulative effect in the effect window. A rule marks the start (and the end). The caption gives the total effect with its interval, the relative effect and the probability that the effect is more than zero. |
causal.pre_fit |
impact (the cells before the start) |
hdi_prob (0.9), unit |
The actual values against the band of the model before the change, with the RMSE, the MAPE and the part of the actual values in the band. The caption flags a part below 80%. |
causal.donor_weights |
donor_weights: weight(sample, unit, donor) |
hdi_prob (0.9), top (15), unit (none: one panel for each treated unit up to 4, else the first unit) |
Horizontal bars of the mean weight of each donor with HDI rules, sorted. The other donors are summed as "other donors". |
causal.event_study |
event_study: coef(sample, event_time), att, attrs reference |
hdi_prob (0.9) |
A point and an HDI rule for each event time, a zero line and a dashed rule between -1 and 0. The reference period is marked. The caption gives the average effect after the change and tells if the coefficients before the change include zero. |
Scientific-model pack (sci.*)¶
The sci.* recipes make Plotly figures for models with gridded outputs, vector fields,
profiles and trajectories. They read draws (chain/draw or sample dims) from
posterior, predictions or posterior_predictive. They read the actual values from
observed_data.
| Recipe | What it shows |
|---|---|
sci.field_map |
One heatmap panel for each statistic of a gridded output. A slider and a Play button show one frame at a time. |
sci.vector_field |
The length of a vector as colours, arrows of the mean vector, and the sd of the length. |
sci.profile_bands |
The median and the 50% and 90% bands along along, one curve for each level of by, and the actual values. A slider shows one level with its bands. |
sci.ensemble |
Some draws as thin lines, the 90% band of all draws, the median and the actual values. |
sci.area_map |
A map of areas (polygons) coloured by the observed value, the mean, the sd and the probability that the value is above threshold. A cross marks each area where this probability is above mark_above. |
sci.phylogeny |
A tree of the tips (species) next to a strip with the estimate and its interval for each tip, and the observed values. |
sci.rose |
A polar chart of angles: a rose of the observed angles with the 90% range of simulated data in each sector, or a curve around the circle with its limits. |
sci.image_residuals |
The observed image, the model mean, the residual and the normalised residual (obs - mean) / sqrt(sd² + σ²), with a histogram of the normalised residuals against N(0, 1). |
sci.ppc_image_grid |
The observed image next to n_draws images from the model on one colour scale. With shuffle, the panels are in a random order and the caption names the real one. |
sci.swatches |
Squares in the colours of an sRGB output (…, item, rgb) in [0, 1]: observed, mean and some draws. A map when the item dim has row and col coords. |
sci.power_spectrum |
A binned spectrum (…, bin) against a coord such as ell: median, 50% and 90% bands, a theory curve and the observed values with error bars. |
sci.point_pattern |
One dot for each point (localisation, event) at its mean position, an error ellipse for each point, and an optional image or intensity field below the points. |
Data for the map, tree and polar recipes:
sci.area_mapreads the outlines of the areas fromring_x(area, vertex)andring_y(area, vertex). Fill the unused vertices with NaN. A NaN between points starts a new ring, for example an island. The first dim is the area dim. The optionaladjacency(area, area_)matrix (not zero for neighbours) gives the lines ofshow_edges. The recipe finds these variables inobserved_data,constant_data, ageometrygroup, the group of the output or the root. It draws the areas as filled shapes on axes with equal scales. It does not use a geographic projection or a base map. If the outlines have too many points, the recipe uses fewer points.- The Observed panel of
sci.area_mapreadsobserved, else the variable with the name of the output inobserved_data. If there is none, the recipe reads the variable that the attrmapi_observedof the output names. A model sets this attr when it keeps the observed value under a different name. For example,sci.areal_bym2keeps the raw SMR assmrfor its outputrr. sci.phylogenyreads the tree fromparent(node): the position of the parent node, or -1 for the root. The optional variables arebranch_length(node)(default 1),is_tip(node)(default: the nodes that are not a parent) andtip_label(node). The tips match the levels of the output by label. If there are no labels, tip k (in node order) is level k.sci.rosereads angles inunits. One turn is 2π radians, 360 degrees, 24 hours or 365.25 days, orperiod. If the output has an angle dim (angle_dim, or a dim calledangle,direction,hourand so on), the recipe draws a curve. Otherwise it counts the angles inbinssectors.
Notes on the image and spectrum recipes (mapi_plots.packs.sci_images):
sci.image_residualsandsci.ppc_image_gridneed the observed image inobserved_data, with the grid dims of the output. The recipe uses the variable with the same name, theobserved_varsetting or the only observed variable.- Draws from
posterior_predictivealready hold the noise of the data, sosci.image_residualsadds no σ to them. For a noise-free output (posteriororpredictions), it usessigmaor a variable namedsigma. - With
log,sci.image_residualsshows the observed, mean and residual panels as log10. It computes the normalised residual and its histogram in the data's units, because σ is in those units. sci.swatcheswrites the colours as#rrggbbtext in the dataset. The plot sandbox does not change these colours in dark mode, because they are data.- Colours that a recipe takes from a colour scale (the groups of
net.graphandsci.point_pattern, the classes ofsci.area_map, the curves ofsci.profile_bands) are also data. They do not change in dark mode, as a colour scale does not. All other colours come from the palette and have a dark variant.
Statistics of sci.field_map:
mean,median: the average value and the middle value of the draws.sd: the uncertainty. A high sd shows where the data do not fix the value.z: the mean divided by the sd. Values far from zero are clear.q05,q95: the limits of the 90% interval.draws:n_drawspossible fields from the model.
The grid dims come from the settings. If you do not set them, the recipe uses the grid of
the output (OutputDecl.grid). It reads the grid from the grid attribute of the variable
or from the model manifest in the bundle. The colormap, log and origin settings also
come from the grid when you do not set them. If the output has more dims than the plot
uses, use select to pick one level of each, for example select: {species: 0}.
The size of a field plot has limits:
- All the cells of a plot are in one dataset:
x,yand one column for each statistic and frame. The recipe keeps this dataset below the inline Arrow limit (2 MB). - If the field has too many cells, the recipe calculates the average of each block of k × k cells. A cell with no value (NaN) stays empty. The caption tells the block size.
- A field of 189 × 193 cells with six panels and one frame has its full resolution.
max_framessets the maximum number of frames. The slider shows frames at equal intervals.
sci.point_pattern reads the variables x and y with one value for each level of the
point dim. Draws give the posterior mean and an ellipse from the 2 × 2 covariance of the
draws. A score summary gives its point statistic and an ellipse from its sd. Plain values
use the sd_x and sd_y variables (or a radius variable, drawn as a circle) when they
exist. The ellipse holds the position with probability level. The field is a gridded
output (by default the first output with a grid), drawn below the points in the same units.
Network pack (net.*)¶
| Recipe | What it shows |
|---|---|
net.graph |
A node-link drawing of the links above threshold (line width shows the value, blue and red show the sign, arrows show the direction) and a heatmap of the full matrix. Dotted lines and open squares show the known or observed links. |
net.graph reads an edge variable with two node dims: the second dim has the name of the
first plus _, for example (node, node_) or (var, var_). The values can be draws (the
recipe uses the posterior mean), a score summary (its point statistic) or plain values. They
can be probabilities, weights or partial correlations.
positions: a variable(node, latent_dim), for example the latent positions of a latent space model. The recipe uses the posterior mean of the first two coordinates. Without it, the recipe calculates a layout from the mean weights (a spectral start and seeded Fruchterman–Reingold steps). The layout puts strongly linked nodes near each other.group: a variable with one value for each node (by defaultnode_grouporgroup). Categories get one colour each and a legend. Continuous values get a colour scale.truth: a known or observed adjacency(node, node_). By default the recipe uses one fromobserved_dataorconstant_data.threshold: by default 0.5 for values in [0, 1], else 10% of the largest absolute value. With draws, the tooltip at the middle of a link shows the share of draws above the threshold.
The plot sandbox shows the Plotly frames, sliders and updatemenus of these plots. In
dark mode, it changes the palette colours of the traces to their dark variants, the same as
for Vega-Lite. It also applies the theme to each polar subplot (barpolar, scatterpolar),
for example in sci.rose.
The convergence diagnostics are rank-normalised split R-hat and bulk/tail ESS (Vehtari et al. 2021). The package calculates them with numpy. Tests make sure that the values agree exactly with ArviZ.