recon_gen.common.tree.visuals
Typed Visual subtypes — one per visual kind in active use.
L.1.1 catalog: KPI ×29, Table ×22, BarChart ×13, Sankey ×2 across
the three apps. Each subtype owns its field-well shape and emits the
corresponding models.py Visual instance.
Classes
|
Bar chart visual — one bar per distinct |
|
Force-directed network visual — HTMX-dialect only (X.2 spike capability test for X.4). |
|
KPI visual — single number per |
|
BK.9 — sign-aware (▲ inflow / ▼ outflow) state indicator for a KPI's primary value. |
|
CF.X-infra — 3-band threshold indicator on a KPI's primary value. |
|
BK.2 — binary healthy-when-zero state indicator for a KPI's primary value. |
|
Line chart visual — one line per distinct |
|
Sankey diagram visual — flows from |
|
Table visual — two field-well shapes: |
|
Structural type for tree-level visual nodes. |
- class recon_gen.common.tree.visuals.BarChart(title, subtitle, category=<factory>, values=<factory>, colors=<factory>, orientation=None, bars_arrangement=None, category_label=None, value_label=None, color_label=None, sort_by=None, actions=<factory>, log_scale=False, visual_id=AUTO)[source]
Bases:
objectBar chart visual — one bar per distinct
category, height byvalues.Field-well shape:
Category=[Dim, ...]+Values=[Measure, ...].orientation("VERTICAL"or"HORIZONTAL") andbars_arrangement("CLUSTERED"/"STACKED"/"STACKED_PERCENT") pass through to the underlyingBarChartConfiguration.sort_byis a(field_id, direction)tuple — direction"ASC"or"DESC"— and emits aCategorySortentry. All three default toNoneso the QuickSight defaults apply when not specified.visual_idis optional (L.1.8.5 auto-ID).- Parameters:
title (str)
subtitle (str)
category (list[Dim])
values (list[Measure])
colors (list[Dim])
orientation (Literal['HORIZONTAL', 'VERTICAL'] | None)
bars_arrangement (Literal['CLUSTERED', 'STACKED', 'STACKED_PERCENT'] | None)
category_label (str | None)
value_label (str | None)
color_label (str | None)
sort_by (tuple[Dim | Measure | str, Literal['ASC', 'DESC']] | None)
actions (list[Drill | SameSheetFilter])
log_scale (bool)
visual_id (VisualId | Literal[_AutoSentinel.AUTO])
- actions: list[Drill | SameSheetFilter]
- bars_arrangement: Literal['CLUSTERED', 'STACKED', 'STACKED_PERCENT'] | None = None
- category_label: str | None = None
- color_label: str | None = None
- property element_id: str
- property element_type: Literal['VISUAL', 'FILTER_CONTROL', 'PARAMETER_CONTROL', 'TEXT_BOX', 'IMAGE']
- log_scale: bool = False
- orientation: Literal['HORIZONTAL', 'VERTICAL'] | None = None
- subtitle: str
- title: str
- value_label: str | None = None
- visual_id: VisualId | Literal[_AutoSentinel.AUTO] = 'auto'
- class recon_gen.common.tree.visuals.ForceGraph(title, subtitle, actions=<factory>, visual_id=AUTO)[source]
Bases:
objectForce-directed network visual — HTMX-dialect only (X.2 spike capability test for X.4).
QuickSight’s standard visual library doesn’t include a force layout (only hierarchical
SankeyDiagramVisual), so this primitive exists to prove the L1 tree primitives can host a visual kind that no QS dialect emit knows how to render. The HTMX renderer’s bootstrap dispatches torenderForceGraphvia d3-force;emit()raises because the QS pipeline intentionally has no path for this kind.Phase.1 design call: either keep this HTMX-only or wire a custom-visual emitter for QS. The capability test is the artifact; the layering decision is downstream.
No field-well slots — the visual’s data shape (nodes + links) flows through the data fetcher directly, not through QS field wells.
visual_idis optional (L.1.8.5 auto-ID).- Parameters:
title (str)
subtitle (str)
actions (list[Drill | SameSheetFilter])
visual_id (VisualId | Literal[_AutoSentinel.AUTO])
- actions: list[Drill | SameSheetFilter]
- property element_id: str
- property element_type: Literal['VISUAL', 'FILTER_CONTROL', 'PARAMETER_CONTROL', 'TEXT_BOX', 'IMAGE']
- subtitle: str
- title: str
- visual_id: VisualId | Literal[_AutoSentinel.AUTO] = 'auto'
- class recon_gen.common.tree.visuals.KPI(title, subtitle, values=<factory>, value_zero_indicator=None, value_sign_indicator=None, value_threshold_banding=None, visual_id=AUTO)[source]
Bases:
objectKPI visual — single number per
valuesentry, no grouping.Field-well shape:
Values=[Measure, ...]. Most KPIs use one measure; multiple are allowed and render as side-by-side numbers.value_zero_indicator(BK.2) — optional binary check/X+color state on the primary value. SeeKPIValueZeroIndicator. Only fires on single-value KPIs (multi-value KPIs would need per-value indicators; not currently supported).visual_idis optional (L.1.8.5 auto-ID). When omitted, the App’s tree walker assignsv-kpi-s{sheet_idx}-{visual_idx}at emit time. Pass an explicitVisualId(...)to override.- Parameters:
title (str)
subtitle (str)
values (list[Measure])
value_zero_indicator (KPIValueZeroIndicator | None)
value_sign_indicator (KPIValueSignIndicator | None)
value_threshold_banding (KPIValueThresholdBanding | None)
visual_id (VisualId | Literal[_AutoSentinel.AUTO])
- calc_fields()[source]
CalcFields this visual references via its field-well leaves.
- Return type:
set[CalcField]
- property element_id: str
- property element_type: Literal['VISUAL', 'FILTER_CONTROL', 'PARAMETER_CONTROL', 'TEXT_BOX', 'IMAGE']
- subtitle: str
- title: str
- value_sign_indicator: KPIValueSignIndicator | None = None
- value_threshold_banding: KPIValueThresholdBanding | None = None
- value_zero_indicator: KPIValueZeroIndicator | None = None
- visual_id: VisualId | Literal[_AutoSentinel.AUTO] = 'auto'
- class recon_gen.common.tree.visuals.KPIValueSignIndicator(inflow_is_healthy=True)[source]
Bases:
objectBK.9 — sign-aware (▲ inflow / ▼ outflow) state indicator for a KPI’s primary value. Renders ARROW_UP in green when the aggregated value is non-negative, ARROW_DOWN in red when it’s negative.
Accessibility: icon is the load-bearing channel (▲ vs ▼ is distinguishable to all viewers regardless of color perception); color rides along as a parallel signal.
Same QS wire shape as
KPIValueZeroIndicator(see for the three layered gotchas around hex case + expression DSL); the semantic differs — sign of the aggregated value, not zero-vs- not-zero. Currently used on Exec “Net Money Moved” (signed flow).- Parameters:
inflow_is_healthy (bool)
- inflow_is_healthy: bool = True
- class recon_gen.common.tree.visuals.KPIValueThresholdBanding(amber_at, red_at)[source]
Bases:
objectCF.X-infra — 3-band threshold indicator on a KPI’s primary value. Renders
CHECKMARK(green) when the aggregated value is belowamber_at,EXCLAMATION_CIRCLE(amber) betweenamber_atandred_at, andX(red) at or abovered_at.Accessibility (per BK.2 convention): ICON is the load-bearing channel — colorblind users see distinct ✓ / ⚠ / ✗ glyphs. Color rides along as parallel signal.
Use this on count-style KPIs where the operator wants a glance- readable “is anything wrong, anywhere?” tripwire. Bound Measure kind must be sum / max / min / average — count / distinct_count are blocked at the emit boundary (use a sum-of-1s shape in the dataset SQL and
kind='sum'instead).Wire shape: - QS: emits
KPIVisual.ConditionalFormattingwith threeConditionalFormattingOptionsentries ordered RED → AMBER → GREEN (most-restrictive-first); QS picks the first matching expression at render time.App2: the data-fetcher reads the primary value and emits
state_icon(Unicode glyph) +state_color(semantic keyword —success/warning/danger) on eachvaluesentry.bootstrap.js::renderKPIprepends the glyph + applies the color class.
First consumer: CF.2 Exec program-health rollup (amber_at=1, red_at=20).
- Parameters:
amber_at (int)
red_at (int)
- amber_at: int
- red_at: int
- class recon_gen.common.tree.visuals.KPIValueZeroIndicator(healthy_when_zero=True)[source]
Bases:
objectBK.2 — binary healthy-when-zero state indicator for a KPI’s primary value. Renders a CHECKMARK in green when the aggregated value equals zero, an X in red otherwise.
Accessibility (per user 2026-05-29 — colorblind users in the loop): the ICON is the load-bearing channel. Color is a parallel signal for users who can read it, but the icon alone fully communicates healthy/broken state to red/green-colorblind viewers.
Wire shape: - QS: emits
KPIVisual.ConditionalFormattingwith twoConditionalFormattingOptionsentries, each carrying aPrimaryValue.Icon.CustomConditionblock — the first matcheszero, the second matchesnon-zero. QS evaluates the expression at render time against the displayed primary value.App2: the data-fetcher reads the primary value and emits
state_icon(Unicode glyph) +state_color(semantic keyword) on eachvaluesentry.bootstrap.js::renderKPIprepends the glyph + applies the color class.
The TWO renderers see different payloads but render the semantically-equivalent shape — same icon glyph, same color intent — so the operator gets the same signal on either surface.
- Parameters:
healthy_when_zero (bool)
- healthy_when_zero: bool = True
- class recon_gen.common.tree.visuals.LineChart(title, subtitle, category=<factory>, values=<factory>, colors=<factory>, chart_type=None, category_label=None, value_label=None, sort_by=None, actions=<factory>, visual_id=AUTO)[source]
Bases:
objectLine chart visual — one line per distinct
colorsvalue, plotted acrosscategory(x-axis) with height byvalues(y-axis).Field-well shape:
Category=[Dim, ...]+Values=[Measure, ...]+Colors=[Dim, ...].chart_typeselectsLINE(default),AREA, orSTACKED_AREA.sort_byis a(field_id, direction)tuple — direction"ASC"or"DESC"— and emits aCategorySortentry. All optional fields default toNoneso the QuickSight defaults apply when not specified.visual_idis optional (L.1.8.5 auto-ID).- Parameters:
title (str)
subtitle (str)
category (list[Dim])
values (list[Measure])
colors (list[Dim])
chart_type (Literal['LINE', 'AREA', 'STACKED_AREA'] | None)
category_label (str | None)
value_label (str | None)
sort_by (tuple[Dim | Measure | str, Literal['ASC', 'DESC']] | None)
actions (list[Drill | SameSheetFilter])
visual_id (VisualId | Literal[_AutoSentinel.AUTO])
- actions: list[Drill | SameSheetFilter]
- category_label: str | None = None
- chart_type: Literal['LINE', 'AREA', 'STACKED_AREA'] | None = None
- property element_id: str
- property element_type: Literal['VISUAL', 'FILTER_CONTROL', 'PARAMETER_CONTROL', 'TEXT_BOX', 'IMAGE']
- subtitle: str
- title: str
- value_label: str | None = None
- visual_id: VisualId | Literal[_AutoSentinel.AUTO] = 'auto'
- class recon_gen.common.tree.visuals.Sankey(title, subtitle, source=None, target=None, weight=None, items_limit=None, actions=<factory>, visual_id=AUTO)[source]
Bases:
objectSankey diagram visual — flows from
sourcenodes totargetnodes, ribbon thickness byweight.Field-well shape: each of
source/target/weightis a singleDim/Measure(the underlying model expects lists, but every usage today has exactly one entry; emit wraps).items_limitcaps the number of source / destination nodes rendered (matches theItemsLimitshape on the underlying sort configuration).OtherCategoriesdefaults to"INCLUDE"so capped flows roll into a “(others)” bucket rather than being dropped silently.visual_idis optional (L.1.8.5 auto-ID).- Parameters:
title (str)
subtitle (str)
source (Dim | None)
target (Dim | None)
weight (Measure | None)
items_limit (int | None)
actions (list[Drill | SameSheetFilter])
visual_id (VisualId | Literal[_AutoSentinel.AUTO])
- actions: list[Drill | SameSheetFilter]
- property element_id: str
- property element_type: Literal['VISUAL', 'FILTER_CONTROL', 'PARAMETER_CONTROL', 'TEXT_BOX', 'IMAGE']
- items_limit: int | None = None
- subtitle: str
- title: str
- visual_id: VisualId | Literal[_AutoSentinel.AUTO] = 'auto'
- class recon_gen.common.tree.visuals.Table(title, subtitle, group_by=<factory>, values=<factory>, columns=<factory>, sort_by=None, actions=<factory>, conditional_formatting=None, visual_id=AUTO)[source]
Bases:
objectTable visual — two field-well shapes:
Aggregated (default):
group_by=[Dim, ...]+values=[Measure, ...]. One row per distinctgroup_bycombination, aggregated byvalues. EmitsTableAggregatedFieldWells.Unaggregated: pass
columns=[Dim, ...](and leavegroup_by/valuesempty). Each cell shows the raw column value — no aggregation, one row per source row. EmitsTableUnaggregatedFieldWells. Use this for detail/drill-source tables (AR Balances, AR Daily Statement transaction list).
Optional
sort_byis a(field_ref, direction)tuple — direction is"ASC"or"DESC".Optional
conditional_formattingpasses through to the model’s raw dict (seecommon/clickability.pyfor the standard accent-text and tint-background helpers).visual_idis optional (L.1.8.5 auto-ID).- Parameters:
title (str)
subtitle (str)
group_by (list[Dim])
values (list[Measure])
columns (list[Dim])
sort_by (tuple[Dim | Measure | str, Literal['ASC', 'DESC']] | list[tuple[~recon_gen.common.tree.fields.Dim | ~recon_gen.common.tree.fields.Measure | str, ~typing.Literal['ASC', 'DESC']]] | None)
actions (list[Drill | SameSheetFilter])
conditional_formatting (list[CellAccentText | CellAccentMenu] | None)
visual_id (VisualId | Literal[_AutoSentinel.AUTO])
- actions: list[Drill | SameSheetFilter]
- conditional_formatting: list[CellAccentText | CellAccentMenu] | None = None
- property element_id: str
- property element_type: Literal['VISUAL', 'FILTER_CONTROL', 'PARAMETER_CONTROL', 'TEXT_BOX', 'IMAGE']
- sort_by: tuple[Dim | Measure | str, Literal['ASC', 'DESC']] | list[tuple[Dim | Measure | str, Literal['ASC', 'DESC']]] | None = None
- subtitle: str
- title: str
- visual_id: VisualId | Literal[_AutoSentinel.AUTO] = 'auto'
- class recon_gen.common.tree.visuals.VisualLike(*args, **kwargs)[source]
Bases:
ProtocolStructural type for tree-level visual nodes.
Typed subtypes (
KPI/Table/BarChart/Sankey) satisfy this Protocol — duck-typed so subtypes don’t have to inherit from a base class. Subtypes contribute to the L.1.7 dependency-graph walk viadatasets()/calc_fields().All visual nodes also satisfy
LayoutNode(instructure.py) viaelement_id+element_typeso they can be placed in a sheet’s grid layout (sheet.layout.row(...).add_<kind>(...)).visual_idisVisualId | AutoResolved— typed subtypes default toAUTOandApp.resolve_auto_idsreplaces it with the derived id before emit. The walker / emit assert viaisinstancenarrowing.- visual_id: VisualId | Literal[_AutoSentinel.AUTO]