recon_gen.common.tree.structure
Structural tree types — GridSlot / Sheet / Analysis /
Dashboard / App.
The skeleton the rest of the tree hangs off. Authors construct an
App, attach an Analysis (which holds the sheet tree),
optionally attach a Dashboard, and call app.emit_analysis()
/ app.emit_dashboard() to get the models.py instances ready
for deploy.
Classes
|
One explicit-position slot. |
|
Tree node for the Analysis-level structure. |
|
Top-level tree node — coordinates an Analysis + Dashboard plus the deploy-time context (theme, dataset arns, permissions) drawn from the Config. |
|
Tree node for a Dashboard. |
|
One placement in a sheet's grid layout. |
|
Anything placeable in a sheet's grid layout. |
|
One horizontal band in a Sheet's grid layout. |
|
Tree node for one sheet on an Analysis / Dashboard. |
|
Layout namespace on a Sheet — manages rows + absolute placements. |
- class recon_gen.common.tree.structure.AbsoluteSlot(sheet, col_span, row_span, col_index, row_index)[source]
Bases:
objectOne explicit-position slot. Use for layouts that don’t fit the row pattern — overlapping visuals, asymmetric grids, off-grid positioning. One-shot: construct via
sheet.layout.absolute( col_index=, row_index=, col_span=, row_span=)then chain a singleadd_<kind>(...)to fill it. Re-using an AbsoluteSlot for multiple visuals would emit duplicate slot positions and isn’t supported.- Parameters:
sheet (Sheet)
col_span (int)
row_span (int)
col_index (int)
row_index (int | None)
- add_bar_chart(*, title, category=None, values=None, subtitle, orientation=None, bars_arrangement=None, sort_by=None, actions=None, log_scale=False, visual_id=AUTO)[source]
- Return type:
- Parameters:
title (str)
category (list[Dim] | None)
values (list[Measure] | None)
subtitle (str)
orientation (Literal['HORIZONTAL', 'VERTICAL'] | None)
bars_arrangement (Literal['CLUSTERED', 'STACKED', 'STACKED_PERCENT'] | None)
sort_by (tuple[Dim | Measure | str, Literal['ASC', 'DESC']] | None)
actions (list[Drill | SameSheetFilter] | None)
log_scale (bool)
visual_id (VisualId | Literal[_AutoSentinel.AUTO])
- add_kpi(*, title, values=None, subtitle, value_zero_indicator=None, value_sign_indicator=None, visual_id=AUTO)[source]
- Return type:
- Parameters:
title (str)
values (list[Measure] | None)
subtitle (str)
value_zero_indicator (KPIValueZeroIndicator | None)
value_sign_indicator (KPIValueSignIndicator | None)
visual_id (VisualId | Literal[_AutoSentinel.AUTO])
- add_line_chart(*, title, category=None, values=None, colors=None, subtitle, chart_type=None, category_label=None, value_label=None, sort_by=None, actions=None, visual_id=AUTO)[source]
- Return type:
- Parameters:
title (str)
category (list[Dim] | None)
values (list[Measure] | None)
colors (list[Dim] | None)
subtitle (str)
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] | None)
visual_id (VisualId | Literal[_AutoSentinel.AUTO])
- add_sankey(*, title, source, target, weight, subtitle, items_limit=None, actions=None, visual_id=AUTO)[source]
- add_table(*, title, group_by=None, values=None, columns=None, subtitle, sort_by=None, actions=None, conditional_formatting=None, visual_id=AUTO)[source]
- Return type:
- Parameters:
title (str)
group_by (list[Dim] | None)
values (list[Measure] | None)
columns (list[Dim] | None)
subtitle (str)
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] | None)
conditional_formatting (list[CellAccentText | CellAccentMenu] | None)
visual_id (VisualId | Literal[_AutoSentinel.AUTO])
- col_index: int
- col_span: int
- row_index: int | None
- row_span: int
- class recon_gen.common.tree.structure.Analysis(analysis_id_suffix, name, sheets=<factory>, parameters=<factory>, filter_groups=<factory>, calc_fields=<factory>)[source]
Bases:
objectTree node for the Analysis-level structure.
analysis_id_suffixis the part the App’scfg.prefixed()will prepend to (e.g."investigation-analysis"becomes"qs-gen-investigation-analysis"). Keeping the suffix on the tree node keeps the per-app naming under the tree’s control while leaving the global resource-prefix in the Config.emit_definition()returns themodels.AnalysisDefinition— the App combines this with metadata (AwsAccountId,ThemeArn,Permissions, dataset declarations) to produce the fullmodels.Analysisready for deploy.- Parameters:
analysis_id_suffix (str)
name (str)
sheets (list[Sheet])
parameters (list[ParameterDeclLike])
filter_groups (list[FilterGroup])
calc_fields (list[CalcField])
- add_calc_field(calc)[source]
Register a calculated field on this analysis.
Construction-time check: calc field names are unique within the analysis. Two calc fields sharing a Name silently let one win at deploy time — same shadow-bug class as parameters / filter groups / datasets.
- add_filter_group(fg)[source]
Register a filter group on this analysis.
Construction-time check: explicit filter group IDs are unique. (Auto-IDs are unique by construction — assigned from the index in the analysis’s filter_groups list — so the check only applies when callers passed an explicit id.)
- Return type:
- Parameters:
fg (FilterGroup)
- add_parameter(param)[source]
Declare a parameter on this analysis.
Construction-time check: parameter names are unique within the analysis. Catches the silent shadow bug where two declarations share a Name and only one wins at deploy time. Generic over the concrete subtype so the returned ref keeps its type (
StringParam/IntegerParam/DateTimeParam) (PEP 695).- Return type:
TypeVar(T, bound=ParameterDeclLike)- Parameters:
param (T)
- analysis_id_suffix: str
- calc_fields_referenced()[source]
Walk the analysis tree and return every CalcField referenced by any visual or filter group. Distinct from
self.calc_fields(the registry): this returns only the calc fields actually used.Catches “calc field declared but never used” (registered but not in this set) and “calc field used but not declared” (in this set but not in the registry — App._validate_calc_field_ references raises on emit).
- Return type:
set[CalcField]
- datasets()[source]
Walk the analysis tree and return every Dataset referenced by any visual, filter group, or registered calc field. Used by App.dataset_dependencies to derive the precise refresh set.
Visuals using the spike-shape
VisualNodefactory wrapper don’t expose their dataset refs (the factory hides them). Typed Visual subtypes (KPI/Table/BarChart/Sankey) all exposedatasets()and contribute. The spike-shape gap closes once apps port to typed subtypes (L.2/L.3/L.4).Registered CalcFields contribute too — their
Datasetref becomes a dep even if no visual directly references the underlying columns.- Return type:
set[Dataset]
- filter_groups: list[FilterGroup]
- find_calc_field(*, name)[source]
Look up a single calc field by name.
- Return type:
- Parameters:
name (str)
- find_filter_group(*, filter_group_id=None)[source]
Look up a single filter group by id (auto or explicit).
- Return type:
- Parameters:
filter_group_id (FilterGroupId | str | None)
- find_parameter(*, name)[source]
Look up a single parameter declaration by name.
- Return type:
- Parameters:
name (str)
- find_sheet(*, name=None, sheet_id=None)[source]
Look up a single sheet on this analysis by name or sheet id.
Raises on no-match or multi-match. Sheet IDs stay explicit (URL-facing per the L.1.8.5 mixed scheme) so passing
sheet_id=is the most robust lookup;name=is the next-best for tests that don’t want to hardcode IDs.- Return type:
- Parameters:
name (str | None)
sheet_id (SheetId | str | None)
- name: str
- parameters: list[ParameterDeclLike]
- class recon_gen.common.tree.structure.App(name, cfg, analysis=None, dashboard=None, datasets=<factory>, allow_bare_strings=False)[source]
Bases:
objectTop-level tree node — coordinates an Analysis + Dashboard plus the deploy-time context (theme, dataset arns, permissions) drawn from the Config.
Authors construct an App, attach the Analysis (which holds the sheet tree), optionally attach the Dashboard (most apps do — they publish what they author), and call
emit_analysis()/emit_dashboard()to get themodels.pyinstances ready for deploy.Datasets are registered on the App via
add_dataset()and referenced from visuals / filters by object ref. At emit time the App walks the tree’sdataset_dependencies()and includes only the datasets actually used in the emittedDataSetIdentifierDeclarations— selective by construction. Validation: if a visual or filter references a Dataset that isn’t registered on the App,emit_analysisraises with the offending identifiers.- Parameters:
- add_dataset(dataset)[source]
Register a Dataset on the App.
Construction-time check: dataset identifiers are unique within the app. Catches the silent shadow bug where two registrations share an identifier and only one wins at deploy.
- allow_bare_strings: bool = False
- create_dashboard(*, dashboard_id_suffix, name)[source]
Construct + register a Dashboard against the App’s already-set Analysis.
The App owns the Analysis already; this shortcut prevents the analysis-mismatch bug class by construction — there’s no opening to pass a different Analysis.
- Return type:
- Parameters:
dashboard_id_suffix (str)
name (str)
- dataset_dependencies()[source]
The set of Datasets referenced anywhere in the App’s tree.
Walks the Analysis (sheets → visuals + filter_groups). Each typed Visual subtype + typed Filter wrapper exposes its own
datasets()set; the App unions them.- Return type:
set[Dataset]
Deployment side effect. This set drives: - selective deploy (only re-create / refresh the datasets
downstream of an actual change),
matview REFRESH ordering (REFRESH only the matviews backing datasets that the changed deploy surface depends on).
Returns an empty set when the App has no Analysis.
- find_sheet(*, name=None, sheet_id=None)[source]
Convenience pass-through to
app.analysis.find_sheet(...).- Return type:
- Parameters:
name (str | None)
sheet_id (SheetId | str | None)
- name: str
- resolve_auto_ids()[source]
Walk the tree and assign auto-IDs to nodes that left their IDs unset. Called from emit_analysis / emit_dashboard before any validation or emission, and exposed publicly so non-QS renderers (HTML, future X.4 editor) can resolve IDs without going through the full QS emit path.
Idempotent — re-runs are no-ops once IDs are filled in.
Mixed scheme (L.1.8.5 + L.1.16): URL-facing IDs (
SheetId,ParameterName) and analyst-facing identifiers (Datasetidentifier) stay explicit. Internal IDs the analyst never types — visual_id, filter_id, control_id, action_id, field_id, calc-field name — get tree-position-derived defaults when omitted.Auto-ID formats: - Visual:
v-{kind}-s{sheet_idx}-{visual_idx}- FilterGroup:fg-{idx}— analysis-scoped - Filter:f-{kind}-fg{fg_idx}-{filt_idx}- ParameterControl:pc-{kind}-s{sheet_idx}-{ctrl_idx}- FilterControl:fc-{kind}-s{sheet_idx}-{ctrl_idx}- Drill action:act-s{sheet_idx}-v{visual_idx}-{action_idx}- Field-well leaf (Dim/Measure): ``f-{visual_kind}-s{sheet_idx}-v{visual_idx}-{role}{slot_idx}`` where role tags the field well slot (
ggroup_by,vvalues,ccategory,ssource,ttarget,wweight)CalcField:
calc-{idx}— analysis-scoped
Same-sheet drills also get their target_sheet back-filled here (Drill.target_sheet=AUTO means “the sheet that owns me”).
- Return type:
None
- class recon_gen.common.tree.structure.Dashboard(dashboard_id_suffix, name, analysis)[source]
Bases:
objectTree node for a Dashboard.
Carries an object reference to the
Analysiswhose definition this Dashboard publishes.dashboard_id_suffixfollows the same pattern asAnalysis.analysis_id_suffix— App’scfg.prefixed()prepends the project resource prefix.analysisis the SAME tree node the App owns; the Dashboard re-emits the same definition the Analysis produces, which matches the existingbuild_dashboard(cfg)pattern in the per-app builders.- Parameters:
dashboard_id_suffix (str)
name (str)
analysis (Analysis)
- dashboard_id_suffix: str
- name: str
- class recon_gen.common.tree.structure.GridSlot(element, col_span, row_span, col_index, row_index=None)[source]
Bases:
objectOne placement in a sheet’s grid layout.
Holds an OBJECT reference to the placed
LayoutNode. The element id and element type are read off the node at emit time — the slot is agnostic about whether it carries a visual or a text box.- Parameters:
element (LayoutNode)
col_span (int)
row_span (int)
col_index (int)
row_index (int | None)
- col_index: int
- col_span: int
- element: LayoutNode
- row_index: int | None = None
- row_span: int
- class recon_gen.common.tree.structure.LayoutNode(*args, **kwargs)[source]
Bases:
ProtocolAnything placeable in a sheet’s grid layout.
Both typed visual subtypes (
KPI/Table/BarChart/Sankey) and the typedTextBoxwrapper satisfy this Protocol. Each exposeselement_id(the layout slot’sElementId) andelement_type("VISUAL"or"TEXT_BOX") — the slot reads them off the node at emit time.The Protocol means
Sheet.place(node, ...)accepts both visuals and text boxes uniformly; QuickSight’s two-list split (Visuals vs TextBoxes inSheetDefinition) stays an emit-time concern that callers never see.- property element_id: str
- property element_type: Literal['VISUAL', 'FILTER_CONTROL', 'PARAMETER_CONTROL', 'TEXT_BOX', 'IMAGE']
- class recon_gen.common.tree.structure.Row(sheet, height, row_index)[source]
Bases:
objectOne horizontal band in a Sheet’s grid layout.
Tracks the column cursor as visuals + text boxes are added; refuses widths that overflow the 36-column grid.
heightbecomes every visual’srow_span; the column cursor advances by each visual’swidth(col_span). A new row fromsheet.layout.row()lands below the previous row — the SheetLayout tracks the vertical cursor.- Parameters:
sheet (Sheet)
height (int)
row_index (int)
- add_bar_chart(*, width, title, category=None, values=None, colors=None, subtitle, orientation=None, bars_arrangement=None, category_label=None, value_label=None, color_label=None, sort_by=None, actions=None, log_scale=False, visual_id=AUTO)[source]
Construct + register + place a BarChart in this row.
- Return type:
- Parameters:
width (int)
title (str)
category (list[Dim] | None)
values (list[Measure] | None)
colors (list[Dim] | None)
subtitle (str)
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] | None)
log_scale (bool)
visual_id (VisualId | Literal[_AutoSentinel.AUTO])
- add_kpi(*, width, title, values=None, subtitle, value_zero_indicator=None, value_sign_indicator=None, visual_id=AUTO)[source]
Construct + register + place a KPI in this row.
- Return type:
- Parameters:
width (int)
title (str)
values (list[Measure] | None)
subtitle (str)
value_zero_indicator (KPIValueZeroIndicator | None)
value_sign_indicator (KPIValueSignIndicator | None)
visual_id (VisualId | Literal[_AutoSentinel.AUTO])
- add_line_chart(*, width, title, category=None, values=None, colors=None, subtitle, chart_type=None, category_label=None, value_label=None, sort_by=None, actions=None, visual_id=AUTO)[source]
Construct + register + place a LineChart in this row.
- Return type:
- Parameters:
width (int)
title (str)
category (list[Dim] | None)
values (list[Measure] | None)
colors (list[Dim] | None)
subtitle (str)
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] | None)
visual_id (VisualId | Literal[_AutoSentinel.AUTO])
- add_sankey(*, width, title, source, target, weight, subtitle, items_limit=None, actions=None, visual_id=AUTO)[source]
Construct + register + place a Sankey in this row.
- add_table(*, width, title, group_by=None, values=None, columns=None, subtitle, sort_by=None, actions=None, conditional_formatting=None, visual_id=AUTO)[source]
Construct + register + place a Table in this row.
Aggregated mode: pass
group_by+values. Unaggregated mode (raw column display): passcolumns. The two modes are mutually exclusive (Table.__post_init__ enforces this).- Return type:
- Parameters:
width (int)
title (str)
group_by (list[Dim] | None)
values (list[Measure] | None)
columns (list[Dim] | None)
subtitle (str)
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] | None)
conditional_formatting (list[CellAccentText | CellAccentMenu] | None)
visual_id (VisualId | Literal[_AutoSentinel.AUTO])
- add_text_box(text_box, *, width)[source]
Register + place a pre-constructed TextBox in this row.
TextBox content is verbose XML (built via
common/rich_text), so the analyst constructs the TextBox separately and passes it here. Uniqueness is by object identity — placing the same TextBox in two rows is a programmer error caught by the row- cursor advance (you’d be calling _consume twice).
- height: int
- row_index: int
- class recon_gen.common.tree.structure.Sheet(sheet_id, name, title, description, visuals=<factory>, parameter_controls=<factory>, filter_controls=<factory>, text_boxes=<factory>, grid_slots=<factory>)[source]
Bases:
objectTree node for one sheet on an Analysis / Dashboard.
Sheet has four concerns:
Metadata —
sheet_id,name,title,descriptionset at construction.Layout — visuals + text boxes placed in a grid. Accessed via
sheet.layout:sheet.layout.row(height=...).add_kpi(width=, title=, values=, ...)for sequential rows, orsheet.layout. absolute(col_index=, row_index=, col_span=, row_span=).add_*(...)for explicit positioning. The layout’s row tracks the column cursor so call sites don’t computecol_indexarithmetic by hand.Controls — parameter / filter controls live above/aside the canvas (NOT in the grid). Added directly on Sheet via
sheet.add_parameter_dropdown(...)/add_parameter_slider/add_parameter_datetime_picker/add_filter_dropdown/add_filter_slider/add_filter_datetime_picker/add_filter_cross_sheet— one shortcut per control kind.Scope wiring —
sheet.scope(filter_group, [v1, v2])scopes a filter group to specific visuals on this sheet.
emit()returns theSheetDefinitionready to drop intoAnalysisDefinition.Sheets.- Parameters:
sheet_id (SheetId)
name (str)
title (str)
description (str)
visuals (list[VisualLike])
parameter_controls (list[ParameterControlLike])
filter_controls (list[FilterControlLike])
text_boxes (list[TextBox])
grid_slots (list[GridSlot])
- add_filter_cross_sheet(*, filter, control_id=AUTO)[source]
Construct + register a cross-sheet filter control on this sheet.
- Return type:
- Parameters:
filter (FilterLike)
control_id (str | Literal[_AutoSentinel.AUTO])
- add_filter_datetime_picker(*, filter, title, type='DATE_RANGE', control_id=AUTO)[source]
Construct + register a filter datetime picker control.
- Return type:
- Parameters:
filter (FilterLike)
title (str)
type (Literal['SINGLE_VALUED', 'DATE_RANGE'])
control_id (str | Literal[_AutoSentinel.AUTO])
- add_filter_dropdown(*, filter, title, type='MULTI_SELECT', selectable_values=None, control_id=AUTO)[source]
Construct + register a filter dropdown control on this sheet.
- Return type:
- Parameters:
filter (FilterLike)
title (str)
type (Literal['SINGLE_SELECT', 'MULTI_SELECT'])
selectable_values (StaticValues | LinkedValues | None)
control_id (str | Literal[_AutoSentinel.AUTO])
- add_filter_slider(*, filter, title, minimum_value, maximum_value, step_size, type='RANGE', control_id=AUTO)[source]
Construct + register a filter slider control on this sheet.
- Return type:
- Parameters:
filter (FilterLike)
title (str)
minimum_value (float)
maximum_value (float)
step_size (float)
type (Literal['SINGLE_POINT', 'RANGE'])
control_id (str | Literal[_AutoSentinel.AUTO])
- add_parameter_datetime_picker(*, parameter, title, control_id=AUTO)[source]
Construct + register a parameter datetime picker control.
- Return type:
- Parameters:
parameter (ParameterDeclLike)
title (str)
control_id (str | Literal[_AutoSentinel.AUTO])
- add_parameter_dropdown(*, parameter, title, selectable_values, type='SINGLE_SELECT', hidden_select_all=False, cascade_source=None, cascade_match_column=None, control_id=AUTO)[source]
Construct + register a parameter dropdown control on this sheet.
selectable_valuesis required: a parameter dropdown without a source list (StaticValues / LinkedValues) shows only the QuickSight empty-state “All” placeholder, so the user can’t actually pick a value — the bound parameter stays unset and any CategoryFilter using it matches nothing. Caught the L1 Daily Statement account-dropdown footgun (v8.3.3 hotfix); the type makes it unrepresentable going forward.- Return type:
- Parameters:
parameter (ParameterDeclLike)
title (str)
selectable_values (StaticValues | LinkedValues)
type (Literal['SINGLE_SELECT', 'MULTI_SELECT'])
hidden_select_all (bool)
cascade_source (ParameterDropdown | None)
cascade_match_column (Column | None)
control_id (str | Literal[_AutoSentinel.AUTO])
- add_parameter_slider(*, parameter, title, minimum_value, maximum_value, step_size, control_id=AUTO)[source]
Construct + register a parameter slider control on this sheet.
- Return type:
- Parameters:
parameter (ParameterDeclLike)
title (str)
minimum_value (float)
maximum_value (float)
step_size (float)
control_id (str | Literal[_AutoSentinel.AUTO])
- add_parameter_text_field(*, parameter, title, control_id=AUTO)[source]
Construct + register a free-text parameter input control.
Use when the parameter’s option universe is unbounded / unknown at deploy time, or when LinkedValues / StaticValues paths fail (X.1.b L2FT cascade Value dropdown hit
Sample values not foundfrom QS’s lazy sample-values fetch on cold per-CI-run dashboards). Text input has no equivalent fetch path.- Return type:
- Parameters:
parameter (ParameterDeclLike)
title (str)
control_id (str | Literal[_AutoSentinel.AUTO])
- description: str
- filter_controls: list[FilterControlLike]
- find_visual(*, title=None, title_contains=None, visual_id=None)[source]
Look up a single visual on this sheet by title / partial title / visual id.
Designed for e2e + introspection: pass any of the three lookup keys and get the matching node back. Raises if no match or multiple matches — the API forces unambiguity at the call site so tests can rely on the result.
Auto-IDs (L.1.8.5) make this the right way to find a visual from outside the tree — IDs are not stable under tree restructuring, but titles + structural position are.
- Return type:
- Parameters:
title (str | None)
title_contains (str | None)
visual_id (VisualId | str | None)
- property layout: SheetLayout
L.1.21 — Layout namespace for grid placement.
Visuals + text boxes are added through the layout (one of:
sheet.layout.row(height=...).add_kpi(width=..., ...)orsheet.layout.absolute(col_index=..., row_index=..., col_span=..., row_span=...).add_kpi(...)). The Sheet itself coordinates four concerns; layout is one of them, factored out so the call sites for “place a visual” don’t crowd against “register a control” or “scope a filter group”.Lazily constructed; the same SheetLayout instance returns on subsequent accesses so the row cursor advances across calls.
- name: str
- parameter_controls: list[ParameterControlLike]
- scope(fg, visuals)[source]
L.1.21 — scope a filter group to specific visuals on this sheet.
Reads more naturally than
fg.scope_visuals(sheet, visuals)since the sheet is the contextual subject. Runtime check stays — Python’s type system can’t track whichSheetinstance a visual was registered on without dependent types.- Return type:
- Parameters:
fg (FilterGroup)
visuals (list[VisualLike])
- sheet_id: SheetId
- title: str
- visuals: list[VisualLike]
- class recon_gen.common.tree.structure.SheetLayout(sheet)[source]
Bases:
objectLayout namespace on a Sheet — manages rows + absolute placements.
Tracks a vertical row cursor: each
row(height=H)opens a new row at the current cursor and advances it byHfor the next row. Absolute placements don’t advance the cursor (they’re independent of row flow).- Parameters:
sheet (Sheet)
- absolute(*, col_index, row_index=None, col_span, row_span)[source]
Open an explicit-position slot. Doesn’t advance the row cursor — absolute placements are independent of row flow.
- Return type:
- Parameters:
col_index (int)
row_index (int | None)
col_span (int)
row_span (int)