Skip to content

User-Defined Charts (--extra-charts)

Append a fixed library of generic chart types to the scout visualize dashboard via a TOML config. The chart library is closed (eleven types); referring to research vocabulary in code is intentionally out of scope (FR-025).

Spec: specs/003-merge-compare-charts/contracts/cli-visualize-extra.md and extra-charts.schema.toml.

Terminology — user-facing prose calls this feature user-defined charts (matches the dashboard section heading and FR-023 wording). --extra-charts is reserved for the literal CLI flag, the filename extra_charts.md, and the loader module name _extra_charts_loader.py. Do not introduce a third synonym.

Synopsis

scout visualize <PROJECT> [--open] [--interpret] [--export-png] \
  [--extra-charts FILE.toml]

When --extra-charts is omitted, dashboard output is semantically equivalent to the prior version (FR-024 / SC-006).

TOML schema

The config has two top-level keys (closed set): defaults (optional) and chart (array of tables, one entry per user-defined chart). Any other top-level key is rejected.

[defaults]
font_family   = "Inter, sans-serif"        # optional
color_palette = ["#1f77b4", "#ff7f0e"]      # optional

[[chart]]
type             = "group_sentiment_bar"   # required
title            = "Negative rate by group" # required
group_column     = "type"                   # required for this type
group_order      = ["a", "b", "c"]          # optional; default = sorted unique
group_labels     = { a = "A label" }        # optional
sentiment_column = "sentiment_label"        # optional; default

Chart library

The eleven supported type tokens (any other → validation error):

type Required keys (besides type/title)
group_sentiment_bar group_column
group_sentiment_stacked group_column
dual_axis_grouped_bar group_column, count_metric, ratio_metric
grouped_negative_timeline timestamp_column, group_column (optional bin = day|week|month, default month)
diverging_phrase_bar left_filter ({column, value}), right_filter, phrases (table of name → regex)
quadrant_scatter x_axis ({column, label}), y_axis, group_by
tier_colored_bar category_column, tier_thresholds
topic_group_bubble topic_column, group_column
category_gradient_bar category_column, value_column
brand_evidence_card group_column, text_column
sentiment_crosscut_table slice_columns (list of column names)

Optional group_order / group_labels / tier_thresholds keys that reference values absent from the data emit a UserWarning and render only the present subset.

Validation behavior (FR-022)

The loader runs two passes before any chart renders:

  1. Structural pass — parse TOML, reject unknown top-level keys, reject unknown [defaults] keys.
  2. Per-entry pass — for each [[chart]]: confirm type is in the library, confirm every required key is present, confirm every *_column / *_axis.column / *_filter.column / slice_columns[] reference points at a column present in cleaned_data.parquet or topics.parquet.

All errors are collected and reported together; partial rendering is impossible.

Exit codes (additive — visualize codes preserved)

Code Meaning
0 Dashboard rendered successfully.
1 Project not found.
2 No data available.
4 Internal rendering error.
5 Plotly missing ([viz] install required).
6 --extra-charts config validation failed (NEW). Error message lists every offending entry.

Worked example

This is quickstart.md Recipe 3 reproduced verbatim. Build a paper_charts.toml like:

[defaults]
font_family = "Inter, sans-serif"

[[chart]]
type             = "group_sentiment_bar"
title            = "Negative-rate by autonomy type"
group_column     = "type"
group_order      = ["cs_baseline", "type_2", "type_3", "type_4"]
group_labels     = { cs_baseline = "CS baseline", type_2 = "Consultative", type_3 = "Delegated", type_4 = "Autonomous" }

[[chart]]
type         = "diverging_phrase_bar"
title        = "Concern phrases — CS baseline vs AIC"
left_filter  = { column = "is_cs_baseline", value = true }
right_filter = { column = "is_cs_baseline", value = false }
phrases      = { refund = "\\brefund\\b", talk_to_human = "\\btalk to a human\\b", consent = "\\bconsent\\b" }

Then run:

scout visualize my-project --extra-charts paper_charts.toml --open

The dashboard contains a "User-defined charts" section after the standard sections, with both Plotly figures rendered using the configured titles.

See also