"""Linked dashboard: file-level scatter + brush-filtered category aggregates."""
cat_color = alt.Color("category:N",
scale=alt.Scale(domain=_cat_domain, range=_cat_range),
legend=alt.Legend(title="Category", orient="bottom", columns=4))
brush = alt.selection_interval(encodings=["x", "y"])
legend_sel = alt.selection_point(fields=["category"], bind="legend")
scatter = (
alt.Chart(alt_df).mark_circle(opacity=0.7).encode(
x=alt.X("mood_marker_pct:Q",
title="Imperative-marker density (% of file tokens)"),
y=alt.Y("just_ratio:Q", title="Justification ratio (reasons / imperative)"),
size=alt.Size("n_tokens:Q",
title="tokens",
scale=alt.Scale(range=[20, 600])),
color=cat_color,
opacity=alt.condition(legend_sel, alt.value(0.85), alt.value(0.07)),
tooltip=[
alt.Tooltip("name:N", title="Name"),
alt.Tooltip("description:N", title="Description"),
alt.Tooltip("ccVersion:N", title="ccVersion"),
alt.Tooltip("path:N", title="File"),
alt.Tooltip("category:N"),
alt.Tooltip("n_tokens:Q", format=","),
alt.Tooltip("imperative_sent_pct:Q", title="imperative % of sents", format=".1f"),
alt.Tooltip("mood_marker_pct:Q", title="imp markers %", format=".2f"),
alt.Tooltip("just_ratio:Q", title="justification ratio", format=".2f"),
alt.Tooltip("hard_prohibitions_pct:Q", title="hard_proh %", format=".2f"),
alt.Tooltip("caps_imp_pct:Q", title="CAPS imp %", format=".2f"),
alt.Tooltip("dominant_stance:N"),
alt.Tooltip("dominant_register:N"),
alt.Tooltip("dominant:N", title="dominant sentence-register"),
]).add_params(brush, legend_sel).properties(width=470, height=420,
title="Per-file: imperative density vs justification ratio (brush to filter →)")
)
metrics = [
("hard_prohibitions_pct", "Hard prohibitions %"),
("caps_imp_pct", "CAPS imperative %"),
("all_caps_pct", "ALL CAPS %"),
]
linked_bars = []
for col, title in metrics:
bar = (
alt.Chart(alt_df).mark_bar().encode(
x=alt.X(f"mean({col}):Q", title=f"{title} (of file tokens)"),
y=alt.Y("category:N", sort="-x", title=None),
color=cat_color,
tooltip=[
alt.Tooltip("category:N"),
alt.Tooltip(f"mean({col}):Q", title=f"mean {title}", format=".3f"),
alt.Tooltip("count:Q", title="files in selection"),
]).transform_filter(brush).properties(width=260, height=130, title=f"{title} (mean, in selection)")
)
linked_bars.append(bar)
dashboard = scatter | alt.vconcat(*linked_bars)
save_chart(dashboard, "20-per-file-dashboard")