Reporting

Output generation: charts, PDFs, PowerPoint, hex cartograms, 3D maps, branded multi-client reports.

Reporting utilities — lazy-loaded.

Comprehensive PDF and PowerPoint report generation with client branding. All submodules load on first attribute access via PEP 562 __getattr__.

class siege_utilities.reporting.TitlePageTemplate[source]

Bases: object

Professional title page generator for siege utilities reports

__init__(canvas_obj, page_size=None)[source]
Parameters:
  • canvas_obj (canvas.Canvas)

  • page_size (tuple)

create_title_page(title, subtitle='', report_period='', prepared_by='', client_name='', additional_info=None)[source]

Create a professional title page.

Parameters:
  • title (str) – Main report title

  • subtitle (str) – Report subtitle

  • report_period (str) – Date range or period

  • prepared_by (str) – Who prepared the report

  • client_name (str) – Client name (overrides brand config)

  • additional_info (Dict[str, str]) – Additional information to display

Return type:

None

siege_utilities.reporting.create_title_page(canvas_obj, title, subtitle='', report_period='', prepared_by='', client_name='', additional_info=None, page_size=None)[source]

Convenience function to create a title page.

Parameters:
  • canvas_obj (canvas.Canvas) – ReportLab canvas object

  • title (str) – Main report title

  • subtitle (str) – Report subtitle

  • report_period (str) – Date range or period

  • prepared_by (str) – Who prepared the report

  • client_name (str) – Client name

  • additional_info (Dict[str, str]) – Additional information to display

  • page_size (tuple) – Page size tuple (default: letter)

Return type:

None

class siege_utilities.reporting.TableOfContentsTemplate[source]

Bases: object

Professional table of contents generator for siege utilities reports

__init__(canvas_obj, page_size=None)[source]
Parameters:
  • canvas_obj (canvas.Canvas)

  • page_size (tuple)

create_table_of_contents(sections, title='Table of Contents', page_number=2)[source]

Create a professional table of contents page.

Parameters:
  • sections (List[Dict[str, Any]]) – List of section dictionaries with ‘title’, ‘page’, and optional ‘subsections’

  • title (str) – TOC title (default: “Table of Contents”)

  • page_number (int) – Current page number

Return type:

None

Section format:
{

‘title’: ‘Executive Summary’, ‘page’: 3, ‘subsections’: [ # Optional

{‘title’: ‘Key Findings’, ‘page’: 3}, {‘title’: ‘Recommendations’, ‘page’: 4}

]

}

siege_utilities.reporting.create_table_of_contents(canvas_obj, sections, title='Table of Contents', page_number=2, page_size=None)[source]

Convenience function to create a table of contents page.

Parameters:
  • canvas_obj (canvas.Canvas) – ReportLab canvas object

  • sections (List[Dict[str, Any]]) – List of section dictionaries with ‘title’, ‘page’, and optional ‘subsections’

  • title (str) – TOC title

  • page_number (int) – Current page number

  • page_size (tuple) – Page size tuple

Return type:

None

siege_utilities.reporting.generate_sections_from_report_structure(report_structure)[source]

Generate TOC sections from a report structure dictionary.

Parameters:

report_structure (Dict[str, Any]) – Dictionary defining report structure

Returns:

List of section dictionaries for TOC

Return type:

List[Dict[str, Any]]

class siege_utilities.reporting.ContentPageTemplate[source]

Bases: object

Professional content page generator for siege utilities reports

__init__(canvas_obj, page_size=None)[source]
Parameters:
  • canvas_obj (canvas.Canvas)

  • page_size (tuple)

start_page(page_title, page_number, section_name='')[source]

Start a new content page with header and setup.

Parameters:
  • page_title (str) – Title for this page

  • page_number (int) – Current page number

  • section_name (str) – Optional section name for header

Return type:

None

add_section_title(title, font_size=16)[source]

Add a section title to the page

Parameters:
Return type:

None

add_paragraph(text, font_size=11, text_color=None, line_spacing=1.2)[source]

Add a paragraph of text to the page

Parameters:
Return type:

None

add_table(data, headers=None, table_title='', sort_by=None, sort_order='asc')[source]

Add a table to the page.

Parameters:
  • data (List[List[str]]) – Row data (list of lists).

  • headers (List[str]) – Column headers.

  • table_title (str) – Optional title above the table.

  • sort_by – Column index (int) or header name (str) to sort by. None preserves existing order.

  • sort_order (str) – 'asc' or 'desc'.

Return type:

None

add_bullet_list(items, bullet_char='•')[source]

Add a bullet list to the page

Parameters:
Return type:

None

add_spacing(points=20)[source]

Add vertical spacing

Parameters:

points (float)

Return type:

None

get_remaining_space()[source]

Get remaining space on current page

Return type:

float

finish_page()[source]

Finish the current page by drawing footer

Return type:

None

siege_utilities.reporting.create_content_page(canvas_obj, page_title, page_number, content_sections, section_name='', page_size=None)[source]

Convenience function to create a complete content page.

Parameters:
  • canvas_obj (canvas.Canvas) – ReportLab canvas object

  • page_title (str) – Title for this page

  • page_number (int) – Current page number

  • content_sections (List[Dict[str, Any]]) – List of content sections to add

  • section_name (str) – Optional section name for header

  • page_size (tuple) – Page size tuple

Return type:

None

Content sections format:
[

{‘type’: ‘title’, ‘text’: ‘Section Title’}, {‘type’: ‘paragraph’, ‘text’: ‘Paragraph text…’}, {‘type’: ‘table’, ‘data’: [[…]], ‘headers’: […], ‘title’: ‘Table Title’}, {‘type’: ‘bullets’, ‘items’: [‘Item 1’, ‘Item 2’]}, {‘type’: ‘spacing’, ‘points’: 20}

]

class siege_utilities.reporting.ChartGenerator[source]

Bases: BaseChartEngine, BarChartMixin, MapChartMixin, StatsChartMixin, CompositeChartMixin

Generates charts and visualizations for reports using matplotlib, seaborn, plotly, and folium. Supports pandas DataFrames, Spark DataFrames, and various data sources.

All chart methods are provided by engine mixins:

  • BaseChartEngine__init__, scaling, placeholder, save/convert helpers

  • BarChartMixin — bar, line, pie, proportional text bar charts

  • MapChartMixin — choropleth, marker, 3D, heatmap-map, cluster, flow, bivariate maps

  • StatsChartMixin — statistical heatmap, scatter plot, text heatmap

  • CompositeChartMixin — convergence diagram, dashboard, summary charts, subplots

class siege_utilities.reporting.ChartTypeRegistry[source]

Bases: object

Registry for chart types and their implementations. Provides easy extension and customization of chart types.

__init__()[source]

Initialize the chart type registry.

register_chart_type(chart_type)[source]

Register a new chart type.

Parameters:

chart_type (ChartType) – ChartType object to register

get_chart_type(chart_type_name)[source]

Get a chart type by name.

Parameters:

chart_type_name (str) – Name of the chart type

Returns:

ChartType object or None if not found

Return type:

ChartType | None

list_chart_types(category=None)[source]

List available chart types.

Parameters:

category (str | None) – Filter by category

Returns:

List of chart type names

Return type:

List[str]

get_chart_categories()[source]

Get list of available chart categories.

Return type:

List[str]

create_chart(chart_type_name, **kwargs)[source]

Create a chart using the specified chart type.

Parameters:
  • chart_type_name (str) – Name of the chart type (must exist in the registry).

  • **kwargs – Parameters for the chart; must include every entry in the chart type’s required_parameters.

Return type:

matplotlib.figure.Figure

Raises:
add_chart_creator(chart_type_name, create_function)[source]

Add or update the create function for a chart type.

Parameters:
  • chart_type_name (str) – Name of the chart type

  • create_function (Callable) – Function to create the chart

validate_chart_parameters(chart_type_name, **kwargs)[source]

Validate parameters for a chart type without creating the chart.

Parameters:
  • chart_type_name (str)

  • **kwargs – Chart parameters to validate against the chart type’s required_parameters. If the chart type defines a custom validate_function, all kwargs are forwarded to it.

Returns:

True iff required params present AND any custom validate_function returns truthy.

Return type:

bool

Raises:
  • UnknownChartTypeError – If chart_type_name isn’t registered. (Legitimately-missing validation returns False; unknown chart type is a caller error.)

  • ChartParameterError – If the custom validate function raised.

get_chart_help(chart_type_name)[source]

Get help information for a chart type.

Parameters:

chart_type_name (str) – Name of the chart type

Returns:

Dictionary with help information

Return type:

Dict[str, Any]

export_chart_type_config(chart_type_name, output_path)[source]

Export chart type configuration to a file.

Parameters:
  • chart_type_name (str) – Name of the chart type to export

  • output_path (str) – Path to export the configuration

siege_utilities.reporting.create_bar_chart(data, x_column=None, y_column=None, title='', width=800, height=600, **kwargs)[source]

Standalone function to create a bar chart.

Parameters:
  • data (pd.DataFrame | Dict[str, Any]) – DataFrame or data dictionary

  • x_column (str | None) – Column name for x-axis

  • y_column (str | None) – Column name for y-axis

  • title (str) – Chart title

  • width (int) – Chart width in pixels

  • height (int) – Chart height in pixels

  • **kwargs – Additional chart parameters

Returns:

Chart configuration dictionary or None if error

Return type:

Dict[str, Any] | None

siege_utilities.reporting.create_line_chart(data, x_column=None, y_column=None, title='', width=800, height=600, **kwargs)[source]

Standalone function to create a line chart.

Parameters:
  • data (pd.DataFrame | Dict[str, Any]) – DataFrame or data dictionary

  • x_column (str | None) – Column name for x-axis

  • y_column (str | None) – Column name for y-axis

  • title (str) – Chart title

  • width (int) – Chart width in pixels

  • height (int) – Chart height in pixels

  • **kwargs – Additional chart parameters

Returns:

Chart configuration dictionary or None if error

Return type:

Dict[str, Any] | None

siege_utilities.reporting.create_scatter_plot(data, x_column=None, y_column=None, title='', width=800, height=600, **kwargs)[source]

Standalone function to create a scatter plot.

Parameters:
  • data (pd.DataFrame | Dict[str, Any]) – DataFrame or data dictionary

  • x_column (str | None) – Column name for x-axis

  • y_column (str | None) – Column name for y-axis

  • title (str) – Chart title

  • width (int) – Chart width in pixels

  • height (int) – Chart height in pixels

  • **kwargs – Additional chart parameters

Returns:

Chart configuration dictionary or None if error

Return type:

Dict[str, Any] | None

siege_utilities.reporting.create_pie_chart(data, label_column=None, value_column=None, title='', width=800, height=600, **kwargs)[source]

Standalone function to create a pie chart.

Parameters:
  • data (pd.DataFrame | Dict[str, Any]) – DataFrame or data dictionary

  • label_column (str | None) – Column name for labels

  • value_column (str | None) – Column name for values

  • title (str) – Chart title

  • width (int) – Chart width in pixels

  • height (int) – Chart height in pixels

  • **kwargs – Additional chart parameters

Returns:

Chart configuration dictionary or None if error

Return type:

Dict[str, Any] | None

siege_utilities.reporting.create_heatmap(data, x_column=None, y_column=None, value_column=None, title='', width=8.0, height=6.0, **kwargs)[source]

Standalone function to create a heatmap.

Parameters:
  • data (pd.DataFrame | Dict[str, Any]) – DataFrame or dictionary with data

  • x_column (str) – Column name for X-axis

  • y_column (str) – Column name for Y-axis

  • value_column (str) – Column name for values

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

  • **kwargs – Additional arguments to pass to create_heatmap

Returns:

PIL Image object or None if error

Return type:

Image | None

siege_utilities.reporting.create_choropleth_map(data, location_column=None, value_column=None, title='', width=8.0, height=6.0, map_type='world', **kwargs)[source]

Standalone function to create a choropleth map.

Parameters:
  • data (pd.DataFrame | Dict[str, Any]) – DataFrame or dictionary with data

  • location_column (str) – Column name for locations (country codes, state names, etc.)

  • value_column (str) – Column name for values to color by

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

  • map_type (str) – Type of map (“world”, “usa”, “europe”, etc.)

  • **kwargs – Additional arguments

Returns:

PIL Image object or None if error

Return type:

Image | None

siege_utilities.reporting.create_bivariate_choropleth(data, x_column=None, y_column=None, geoid_column='geoid', title='Bivariate Choropleth Map', width=12.0, height=8.0, **kwargs)[source]

Standalone function to create a bivariate choropleth map.

Parameters:
  • data (pd.DataFrame | Dict[str, Any]) – DataFrame or dictionary with data

  • x_column (str) – Column name for X-axis variable

  • y_column (str) – Column name for Y-axis variable

  • geoid_column (str) – Column name for geographic identifiers

  • title (str) – Map title

  • width (float) – Map width in inches

  • height (float) – Map height in inches

  • **kwargs – Additional arguments

Returns:

PIL Image object or None if error

Return type:

Image | None

siege_utilities.reporting.create_marker_map(data, latitude_column=None, longitude_column=None, value_column=None, label_column=None, title='', width=10.0, height=8.0, map_style='open-street-map', zoom_level=10, **kwargs)[source]

Standalone function to create a marker map.

Parameters:
  • data (pd.DataFrame | Dict[str, Any]) – DataFrame or dictionary with data

  • latitude_column (str) – Column name for latitude values

  • longitude_column (str) – Column name for longitude values

  • value_column (str) – Column name for values (optional)

  • label_column (str) – Column name for labels (optional)

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

  • map_style (str) – Map style

  • zoom_level (int) – Initial zoom level

  • **kwargs – Additional arguments

Returns:

PIL Image object or None if error

Return type:

Image | None

siege_utilities.reporting.create_flow_map(data, origin_lat_column=None, origin_lon_column=None, dest_lat_column=None, dest_lon_column=None, flow_value_column=None, title='', width=12.0, height=10.0, **kwargs)[source]

Standalone function to create a flow map.

Parameters:
  • data (pd.DataFrame | Dict[str, Any]) – DataFrame or dictionary with data

  • origin_lat_column (str) – Column name for origin latitude

  • origin_lon_column (str) – Column name for origin longitude

  • dest_lat_column (str) – Column name for destination latitude

  • dest_lon_column (str) – Column name for destination longitude

  • flow_value_column (str) – Column name for flow values (optional)

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

  • **kwargs – Additional arguments

Returns:

PIL Image object or None if error

Return type:

Image | None

siege_utilities.reporting.create_convergence_diagram(sources, hub_label='Unified Hub', outputs=None, title='Convergence Diagram', width=10.0, height=6.0, **kwargs)[source]

Standalone function to create a convergence diagram.

Parameters:
  • sources (List[Dict[str, Any]]) – Source node dicts with keys label (required), color (optional), and an optional magnitude key.

  • hub_label (str) – Center node label.

  • outputs (List[Dict[str, Any]] | None) – Optional output node dicts (same schema as sources).

  • title (str) – Diagram title.

  • width (float) – Figure width in inches.

  • height (float) – Figure height in inches.

  • **kwargs – Forwarded to CompositeChartMixin.create_convergence_diagram(). Accepts arrow_style ('curved', 'radial', or 'orthogonal'), arrow_count, arrow_color, show_magnitudes, and magnitude_key.

Returns:

ReportLab Image object or None if error.

Return type:

None

siege_utilities.reporting.create_dashboard(charts, layout='2x2', width=12.0, height=8.0, **kwargs)[source]

Standalone function to create a dashboard with multiple charts.

Parameters:
  • charts (list) – List of chart configurations

  • layout (str) – Layout string (e.g., “2x2”, “3x1”)

  • width (float) – Total dashboard width in inches

  • height (float) – Total dashboard height in inches

  • **kwargs – Additional arguments

Returns:

PIL Image object or None if error

Return type:

None

siege_utilities.reporting.create_dataframe_summary_charts(df, title='', width=8.0, height=6.0, **kwargs)[source]

Standalone function to create summary charts from a DataFrame.

Parameters:
  • df (pd.DataFrame) – Pandas DataFrame

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

  • **kwargs – Additional arguments

Returns:

PIL Image object or None if error

Return type:

Image | None

siege_utilities.reporting.generate_chart_from_dataframe(df, chart_type='bar', x_column=None, y_columns=None, title='', width=6.0, height=4.0, **kwargs)[source]

Standalone function to generate a chart from a DataFrame.

Parameters:
  • df (pd.DataFrame) – Pandas DataFrame

  • chart_type (str) – Type of chart to create

  • x_column (str) – Column to use for X-axis labels

  • y_columns (list) – Columns to plot

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

  • **kwargs – Additional arguments

Returns:

PIL Image object or None if error

Return type:

Image | None

class siege_utilities.reporting.ClientBrandingManager[source]

Bases: object

Manages client branding configurations for reports. Handles logos, colors, fonts, and styling preferences.

__init__(config_dir=None)[source]

Initialize the branding manager.

Parameters:

config_dir (Path | None) – Directory containing branding configuration files

create_client_branding(client_name, branding_config)[source]

Create a new client branding configuration.

Parameters:
  • client_name (str) – Name of the client

  • branding_config (Dict[str, Any]) – Branding configuration dictionary

Returns:

Path to the created configuration file

Return type:

Path

get_client_branding(client_name)[source]

Get branding configuration for a specific client.

Parameters:

client_name (str) – Name of the client

Returns:

Branding configuration dictionary.

Raises:
Return type:

Dict[str, Any]

update_client_branding(client_name, updates)[source]

Update an existing client branding configuration.

Parameters:
  • client_name (str) – Name of the client

  • updates (Dict[str, Any]) – Dictionary of updates to apply

Raises:
Return type:

None

list_clients()[source]

List all available client branding configurations.

Returns:

List of client names

Return type:

List[str]

delete_client_branding(client_name)[source]

Delete a client branding configuration.

Parameters:

client_name (str) – Name of the client to delete

Raises:
Return type:

None

create_branding_from_template(client_name, template_name, customizations=None)[source]

Create client branding from a predefined template.

Parameters:
  • client_name (str) – Name of the new client

  • template_name (str) – Name of the template to use

  • customizations (Dict[str, Any] | None) – Optional customizations to apply

Returns:

Path to the created configuration file

Return type:

Path

validate_branding_config(branding_config)[source]

Validate a branding configuration.

Parameters:

branding_config (Dict[str, Any]) – Branding configuration to validate

Returns:

List of validation errors (empty if valid)

Return type:

List[str]

export_branding_config(client_name, export_path)[source]

Export a client branding configuration to a file.

Parameters:
  • client_name (str) – Name of the client

  • export_path (Path) – Path where to export the configuration

Raises:
Return type:

None

import_branding_config(import_path, client_name=None)[source]

Import a branding configuration from a file.

Parameters:
  • import_path (Path) – Path to the configuration file

  • client_name (str | None) – Name for the client (if not specified in config)

Raises:
Return type:

None

get_branding_summary(client_name)[source]

Get a summary of a client’s branding configuration.

Parameters:

client_name (str) – Name of the client

Returns:

Dictionary containing branding summary

Return type:

Dict[str, Any]

siege_utilities.reporting.decode_rl_image(rl_img)[source]

Decode a ReportLab Image’s base64 data URI to raw PNG bytes.

Parameters:

rl_img – A ReportLab Image object (or any object with a filename attribute).

Returns:

Raw PNG bytes, or None if the object is not a base64 data URI image.

Return type:

bytes | None

siege_utilities.reporting.show_rl_image(rl_img)[source]

Display a ReportLab Image in a Jupyter notebook.

Decodes the base64 data URI embedded in the ReportLab Image and returns an IPython Image object suitable for inline display.

Parameters:

rl_img – A ReportLab Image object returned by ChartGenerator.

Returns:

An IPython.display.Image for notebook rendering, or the original object if it is not a base64 data URI image.

siege_utilities.reporting.save_rl_image(rl_img, path)[source]

Save a ReportLab Image (base64 data URI) to a PNG file.

Parameters:
  • rl_img – A ReportLab Image object returned by ChartGenerator.

  • path (str | Path) – Destination file path.

Returns:

The resolved Path object (unchanged if the image could not be decoded).

Return type:

Path

class siege_utilities.reporting.Argument[source]

Bases: object

Atomic report unit: headline → narrative → table → visualization(s).

layout is auto-resolved in __post_init__:
  • map_figure present → “full_width” (stacked: title / table / figure)

  • map_figure absent → “side_by_side” (title top, table left, figure right)

headline: str
narrative: str
table: Any
table_type: TableType
chart: Any | None = None
map_figure: Any | None = None
layout: str = 'auto'
base_note: str | None = None
source_note: str | None = None
tags: List[str]
__init__(headline, narrative, table, table_type, chart=None, map_figure=None, layout='auto', base_note=None, source_note=None, tags=<factory>)
Parameters:
Return type:

None

class siege_utilities.reporting.TableType[source]

Bases: Enum

SINGLE_RESPONSE = 'single_response'
MULTIPLE_RESPONSE = 'multiple_response'
CROSS_TAB = 'cross_tab'
LONGITUDINAL = 'longitudinal'
RANKING = 'ranking'
MEAN_SCALE = 'mean_scale'
BANNER = 'banner'
class siege_utilities.reporting.Algorithm[source]

Bases: str, Enum

Placement-algorithm choices for hex_tile_layout().

GREEDY = 'greedy'

Sort by area, place in nearest unoccupied hex. < 100 ms typical.

HUNGARIAN = 'hungarian'

Optimal centroid-distance assignment (no topology term).

ANNEALING = 'annealing'

Centroid + topology weighted; SA refinement of an initial layout.

FORCE_DIRECTED = 'force_directed'

Reserved — not implemented in v1.

ILP = 'ilp'

Reserved — not implemented in v1.

__new__(value)
class siege_utilities.reporting.Sizing[source]

Bases: str, Enum

Sizing-mode choices for hex_tile_map().

EQUAL = 'equal'

Every hex same size; values map to colour only.

VALUE_PROPORTIONAL = 'value_proportional'

Hex area proportional to value.

VALUE_SQRT = 'value_sqrt'

Hex side proportional to √value (perception-correct).

__new__(value)
siege_utilities.reporting.hex_tile_layout(source, *, code_col='code', algorithm=Algorithm.ANNEALING, components='auto', component_gap=1, hex_size=1.0, seed=None)[source]

Build a hex tile layout.

Parameters:
  • source (Union[str, 'gpd.GeoDataFrame']) – Either a registered/builtin layout name, or a GeoDataFrame of polygons to place algorithmically.

  • code_col (str) – Column name on the GeoDataFrame containing the polygon identifier (e.g. state abbreviation, FIPS code). Ignored when source is a string layout name.

  • algorithm (Union[Algorithm, str]) – One of Algorithm (or its string value). Ignored when source is a registered layout name.

  • components (Optional[Union[str, list[list[str]]]]) – "auto" (default) splits the input into connected components by polygon adjacency and lays each out independently with component_gap empty cells between them. "single" forces everything into one component. A pre-computed list[list[code]] lets the caller specify groups explicitly.

  • component_gap (int) – Number of empty hex cells between neighbouring components in the final output.

  • hex_size (float) – Cell circumradius in CRS units used for the output geometry. 1.0 is fine for visualization; choose a smaller value if you plan to overlay the cartogram on a real map.

  • seed (Optional[int]) – Random seed for the annealing algorithm; ignored otherwise.

Returns:

GeoDataFrame[geometry, code, q, r] — one hexagon per polygon, with axial coords on each row for downstream tooling.

Return type:

gpd.GeoDataFrame

siege_utilities.reporting.hex_tile_map(values, layout, *, sizing=Sizing.EQUAL, cmap='viridis', code_col='code', label_col='code', title=None, figsize=(10.0, 7.0), edge_color='#888', missing_color='#eeeeee')[source]

Render a hex cartogram.

Parameters:
  • values (pd.Series) – Values to encode, indexed by polygon code (matching the code_col of layout). Codes present in the layout but absent from values render in missing_color.

  • layout (gpd.GeoDataFrame) – GeoDataFrame from hex_tile_layout() — needs at minimum code, q, r columns.

  • sizing (Union[Sizing, str]) – One of Sizing (or its string value). EQUAL uses the layout’s geometry as-is; the proportional modes scale per-hex around the cell center.

  • cmap (str) – matplotlib colour map name.

  • code_col (str) – Name of the code column on layout.

  • label_col (Optional[str]) – Column to write inside each hex (typically the code). Pass None to omit labels.

  • missing_color (str) – Standard mpl knobs.

  • title (Optional[str])

  • figsize (tuple[float, float])

  • edge_color (str)

  • missing_color

Return type:

matplotlib.figure.Figure

siege_utilities.reporting.register_layout(name, mapping)[source]

Register a hand-positioned layout under name.

The mapping must be {code: (q, r)} with no duplicate (q, r) pairs. Use any reproducible code convention ("AL", "01", "al-cd-7"); hex_tile_layout() will join your data on whichever column you provide via code_col.

Parameters:
Return type:

None

class siege_utilities.reporting.IDMLExporter[source]

Bases: object

Build an IDML file programmatically.

Parameters:
  • template_path (str or Path, optional) – Path to an existing .idml template. If provided and simpleidml is installed the template is loaded for modification. Otherwise the exporter builds the IDML structure from scratch.

  • page_width (float) – Page width in points (default 612 = US Letter).

  • page_height (float) – Page height in points (default 792 = US Letter).

__init__(template_path=None, page_width=612.0, page_height=792.0)[source]
Parameters:
  • template_path (str | None)

  • page_width (float)

  • page_height (float)

Return type:

None

add_text_frame(text, style_name='NormalParagraphStyle', x=72.0, y=72.0, width=468.0, height=36.0)[source]

Add a text frame to the document.

Parameters:
  • text (str) – Content of the text frame.

  • style_name (str) – InDesign paragraph style name.

  • x (float) – Top-left position in points.

  • y (float) – Top-left position in points.

  • width (float) – Dimensions in points.

  • height (float) – Dimensions in points.

Return type:

None

add_image_frame(image_path, x=72.0, y=72.0, width=200.0, height=200.0)[source]

Add an image placeholder frame.

Parameters:
  • image_path (str) – Path to the image file (stored as a link reference).

  • x (float) – Top-left position in points.

  • y (float) – Top-left position in points.

  • width (float) – Dimensions in points.

  • height (float) – Dimensions in points.

Return type:

None

add_table(headers, rows, x=72.0, y=72.0, width=468.0, height=200.0)[source]

Add a table as a text frame with tab-separated content.

Parameters:
  • headers (list[str]) – Column headers.

  • rows (list[list[str]]) – Row data — each inner list is one row.

  • x (float) – Top-left position in points.

  • y (float) – Top-left position in points.

  • width (float) – Dimensions in points.

  • height (float) – Dimensions in points.

Return type:

None

replace_placeholder(placeholder, content)[source]

Register a template placeholder substitution.

When save() is called every occurrence of placeholder in story XML content is replaced with content.

Parameters:
  • placeholder (str)

  • content (str)

Return type:

None

save(output_path)[source]

Write the IDML file to output_path.

Returns the resolved output path.

Parameters:

output_path (str)

Return type:

str

siege_utilities.reporting.export_report_idml(ga_data, output_path, template_path=None, title='Google Analytics Report')[source]

Export a GA-data report as an IDML file.

Accepts the same ga_data dict produced by generate_sample_ga_data() / fetch_real_ga4_data() and writes an IDML file that Adobe InDesign can open.

Parameters:
  • ga_data (dict) – Google Analytics data dictionary (totals, traffic_sources, top_pages, devices, etc.).

  • output_path (str) – Destination file path for the .idml output.

  • template_path (str, optional) – Path to an IDML template with placeholders.

  • title (str) – Report title.

Returns:

The resolved output file path.

Return type:

str

class siege_utilities.reporting.ThreeDMapRenderer[source]

Bases: object

High-level helper for creating pydeck 3D map visualisations.

Parameters:
  • mapbox_token (str | None) – Mapbox API key. Falls back to the MAPBOX_ACCESS_TOKEN env-var that pydeck reads automatically when None.

  • map_style (str) – One of "dark", "light", "satellite", "streets", "outdoors" or a full mapbox:// URL.

__init__(mapbox_token=None, map_style='dark')[source]
Parameters:
  • mapbox_token (str | None)

  • map_style (str)

create_hexagon_layer(df, lat_col='latitude', lon_col='longitude', value_col=None, radius=1000, elevation_scale=100, color_range=None, auto_highlight=True, extruded=True, coverage=0.8, zoom=10.0, pitch=45.0)[source]

Create a 3D hexagonal-bin aggregation layer.

Parameters:
  • df (pandas.DataFrame) – Must contain lat_col and lon_col columns.

  • value_col (str | None) – Column whose values are summed per hex. When None the layer counts the number of points (default pydeck behaviour).

  • radius (int) – Hexagon radius in metres.

  • elevation_scale (int) – Multiplier applied to the aggregated elevation value.

  • lat_col (str)

  • lon_col (str)

  • color_range (List[List[int]] | None)

  • auto_highlight (bool)

  • extruded (bool)

  • coverage (float)

  • zoom (float)

  • pitch (float)

Return type:

pdk.Deck

create_column_layer(df, lat_col='latitude', lon_col='longitude', value_col='value', radius=500, elevation_scale=1, color=None, auto_highlight=True, zoom=10.0, pitch=45.0)[source]

Create a 3D column layer at point locations.

Each row produces a column whose height is proportional to value_col multiplied by elevation_scale.

Parameters:
  • color (list[int] | None) – RGBA colour list, e.g. [255, 140, 0, 200]. Defaults to orange.

  • df (pd.DataFrame)

  • lat_col (str)

  • lon_col (str)

  • value_col (str)

  • radius (int)

  • elevation_scale (int)

  • auto_highlight (bool)

  • zoom (float)

  • pitch (float)

Return type:

pdk.Deck

create_choropleth_3d(gdf, value_col='value', elevation_scale=100, fill_color=None, line_color=None, opacity=0.8, zoom=10.0, pitch=45.0)[source]

Create an extruded polygon (choropleth) layer from a GeoDataFrame.

The polygons are extruded by value_col multiplied by elevation_scale, giving a 3D bar-on-map effect.

Parameters:
  • gdf (geopandas.GeoDataFrame) – Must have a geometry column of Polygon / MultiPolygon.

  • fill_color (str | None) – A deck.gl JS expression for getFillColor. Defaults to an orange-to-red colour ramp based on value_col.

  • value_col (str)

  • elevation_scale (int)

  • line_color (List[int] | None)

  • opacity (float)

  • zoom (float)

  • pitch (float)

Return type:

pdk.Deck

render_to_html(deck, output_path)[source]

Save a Deck to a standalone HTML file.

Returns the resolved Path of the written file.

Parameters:
  • deck (pdk.Deck)

  • output_path (str | Path)

Return type:

Path

static render_in_notebook(deck)[source]

Display the Deck in a Jupyter / Databricks notebook.

Simply returns the deck object so that Jupyter’s _repr_html_ protocol renders it inline.

Parameters:

deck (pdk.Deck)

siege_utilities.reporting.create_3d_hexbin(df, lat_col='latitude', lon_col='longitude', **kwargs)[source]

Convenience wrapper — create a hexagonal-bin 3D map.

Accepts all keyword arguments supported by ThreeDMapRenderer.create_hexagon_layer().

Parameters:
  • df (pd.DataFrame)

  • lat_col (str)

  • lon_col (str)

Return type:

pdk.Deck

siege_utilities.reporting.create_3d_columns(df, lat_col='latitude', lon_col='longitude', value_col='value', **kwargs)[source]

Convenience wrapper — create a column 3D map.

Accepts all keyword arguments supported by ThreeDMapRenderer.create_column_layer().

Parameters:
  • df (pd.DataFrame)

  • lat_col (str)

  • lon_col (str)

  • value_col (str)

Return type:

pdk.Deck

siege_utilities.reporting.sort_table_data(table_data, sort_by=None, sort_order='asc', has_header=True)[source]

Sort table rows by a column.

Parameters:
  • table_data (List[List]) – Table as list of lists. First row may be headers.

  • sort_by (int | str | None) – Column index (int) or header name (str) to sort by. None preserves existing order.

  • sort_order (str) – 'asc' or 'desc'.

  • has_header (bool) – Whether the first row is a header row.

Returns:

A new list with rows sorted. The header row (if present) stays first.

Raises:
  • ValueError – If sort_order is not 'asc' or 'desc', or sort_by names a column not found in the header.

  • IndexError – If sort_by is an int outside the column range.

Return type:

List[List]

siege_utilities.reporting.get_report_output_directory(client_code=None)[source]

Get the appropriate output directory for reports based on profile system.

Parameters:

client_code (str)

Return type:

Path

siege_utilities.reporting.create_report_generator(client_name, client_code=None)[source]

Create a ReportGenerator with profile-based output directory.

Parameters:
  • client_name (str)

  • client_code (str)

siege_utilities.reporting.create_powerpoint_generator(client_name, client_code=None)[source]

Create a PowerPointGenerator with profile-based output directory.

Parameters:
  • client_name (str)

  • client_code (str)

siege_utilities.reporting.export_branding_config(client_name, export_path)[source]

Export client branding configuration to a file.

Parameters:
  • client_name (str) – Name of the client whose branding should be exported.

  • export_path (str) – Destination path for the export.

Raises:

ReportingConfigError – On any failure — OS error writing the file, missing client, etc.

Return type:

None

siege_utilities.reporting.import_branding_config(import_path, client_name=None)[source]

Import client branding configuration from a file.

Parameters:
  • import_path (str) – Source file to read branding from.

  • client_name (str, optional) – Client to associate with the imported branding. When omitted, the implementation picks a name from the file.

Raises:

ReportingConfigError – On any failure — file missing, parse error, client collision.

Return type:

None

siege_utilities.reporting.export_chart_type_config(chart_type_name, output_path)[source]

Export chart type configuration to a file.

Parameters:
  • chart_type_name (str) – Name of the chart type (must exist in the registry).

  • output_path (str) – Destination file path.

Returns:

True on success.

Return type:

bool

Raises:

ReportingConfigError – On any failure — unknown chart type, OS error writing.

exception siege_utilities.reporting.ReportingConfigError[source]

Bases: RuntimeError

Raised when a reporting configuration export / import cannot complete.

Charts and Visualization

Chart generation utilities for siege_utilities reporting system. Supports multiple chart types, maps, and data sources including pandas and Spark DataFrames.

class siege_utilities.reporting.chart_generator.ChartGenerator[source]

Bases: BaseChartEngine, BarChartMixin, MapChartMixin, StatsChartMixin, CompositeChartMixin

Generates charts and visualizations for reports using matplotlib, seaborn, plotly, and folium. Supports pandas DataFrames, Spark DataFrames, and various data sources.

All chart methods are provided by engine mixins:

  • BaseChartEngine__init__, scaling, placeholder, save/convert helpers

  • BarChartMixin — bar, line, pie, proportional text bar charts

  • MapChartMixin — choropleth, marker, 3D, heatmap-map, cluster, flow, bivariate maps

  • StatsChartMixin — statistical heatmap, scatter plot, text heatmap

  • CompositeChartMixin — convergence diagram, dashboard, summary charts, subplots

siege_utilities.reporting.chart_generator.create_bar_chart(data, x_column=None, y_column=None, title='', width=800, height=600, **kwargs)[source]

Standalone function to create a bar chart.

Parameters:
  • data (pd.DataFrame | Dict[str, Any]) – DataFrame or data dictionary

  • x_column (str | None) – Column name for x-axis

  • y_column (str | None) – Column name for y-axis

  • title (str) – Chart title

  • width (int) – Chart width in pixels

  • height (int) – Chart height in pixels

  • **kwargs – Additional chart parameters

Returns:

Chart configuration dictionary or None if error

Return type:

Dict[str, Any] | None

siege_utilities.reporting.chart_generator.create_bivariate_choropleth(data, x_column=None, y_column=None, geoid_column='geoid', title='Bivariate Choropleth Map', width=12.0, height=8.0, **kwargs)[source]

Standalone function to create a bivariate choropleth map.

Parameters:
  • data (pd.DataFrame | Dict[str, Any]) – DataFrame or dictionary with data

  • x_column (str) – Column name for X-axis variable

  • y_column (str) – Column name for Y-axis variable

  • geoid_column (str) – Column name for geographic identifiers

  • title (str) – Map title

  • width (float) – Map width in inches

  • height (float) – Map height in inches

  • **kwargs – Additional arguments

Returns:

PIL Image object or None if error

Return type:

Image | None

siege_utilities.reporting.chart_generator.create_choropleth_map(data, location_column=None, value_column=None, title='', width=8.0, height=6.0, map_type='world', **kwargs)[source]

Standalone function to create a choropleth map.

Parameters:
  • data (pd.DataFrame | Dict[str, Any]) – DataFrame or dictionary with data

  • location_column (str) – Column name for locations (country codes, state names, etc.)

  • value_column (str) – Column name for values to color by

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

  • map_type (str) – Type of map (“world”, “usa”, “europe”, etc.)

  • **kwargs – Additional arguments

Returns:

PIL Image object or None if error

Return type:

Image | None

siege_utilities.reporting.chart_generator.create_convergence_diagram(sources, hub_label='Unified Hub', outputs=None, title='Convergence Diagram', width=10.0, height=6.0, **kwargs)[source]

Standalone function to create a convergence diagram.

Parameters:
  • sources (List[Dict[str, Any]]) – Source node dicts with keys label (required), color (optional), and an optional magnitude key.

  • hub_label (str) – Center node label.

  • outputs (List[Dict[str, Any]] | None) – Optional output node dicts (same schema as sources).

  • title (str) – Diagram title.

  • width (float) – Figure width in inches.

  • height (float) – Figure height in inches.

  • **kwargs – Forwarded to CompositeChartMixin.create_convergence_diagram(). Accepts arrow_style ('curved', 'radial', or 'orthogonal'), arrow_count, arrow_color, show_magnitudes, and magnitude_key.

Returns:

ReportLab Image object or None if error.

Return type:

None

siege_utilities.reporting.chart_generator.create_dashboard(charts, layout='2x2', width=12.0, height=8.0, **kwargs)[source]

Standalone function to create a dashboard with multiple charts.

Parameters:
  • charts (list) – List of chart configurations

  • layout (str) – Layout string (e.g., “2x2”, “3x1”)

  • width (float) – Total dashboard width in inches

  • height (float) – Total dashboard height in inches

  • **kwargs – Additional arguments

Returns:

PIL Image object or None if error

Return type:

None

siege_utilities.reporting.chart_generator.create_dataframe_summary_charts(df, title='', width=8.0, height=6.0, **kwargs)[source]

Standalone function to create summary charts from a DataFrame.

Parameters:
  • df (pd.DataFrame) – Pandas DataFrame

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

  • **kwargs – Additional arguments

Returns:

PIL Image object or None if error

Return type:

Image | None

siege_utilities.reporting.chart_generator.create_flow_map(data, origin_lat_column=None, origin_lon_column=None, dest_lat_column=None, dest_lon_column=None, flow_value_column=None, title='', width=12.0, height=10.0, **kwargs)[source]

Standalone function to create a flow map.

Parameters:
  • data (pd.DataFrame | Dict[str, Any]) – DataFrame or dictionary with data

  • origin_lat_column (str) – Column name for origin latitude

  • origin_lon_column (str) – Column name for origin longitude

  • dest_lat_column (str) – Column name for destination latitude

  • dest_lon_column (str) – Column name for destination longitude

  • flow_value_column (str) – Column name for flow values (optional)

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

  • **kwargs – Additional arguments

Returns:

PIL Image object or None if error

Return type:

Image | None

siege_utilities.reporting.chart_generator.create_heatmap(data, x_column=None, y_column=None, value_column=None, title='', width=8.0, height=6.0, **kwargs)[source]

Standalone function to create a heatmap.

Parameters:
  • data (pd.DataFrame | Dict[str, Any]) – DataFrame or dictionary with data

  • x_column (str) – Column name for X-axis

  • y_column (str) – Column name for Y-axis

  • value_column (str) – Column name for values

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

  • **kwargs – Additional arguments to pass to create_heatmap

Returns:

PIL Image object or None if error

Return type:

Image | None

siege_utilities.reporting.chart_generator.create_line_chart(data, x_column=None, y_column=None, title='', width=800, height=600, **kwargs)[source]

Standalone function to create a line chart.

Parameters:
  • data (pd.DataFrame | Dict[str, Any]) – DataFrame or data dictionary

  • x_column (str | None) – Column name for x-axis

  • y_column (str | None) – Column name for y-axis

  • title (str) – Chart title

  • width (int) – Chart width in pixels

  • height (int) – Chart height in pixels

  • **kwargs – Additional chart parameters

Returns:

Chart configuration dictionary or None if error

Return type:

Dict[str, Any] | None

siege_utilities.reporting.chart_generator.create_marker_map(data, latitude_column=None, longitude_column=None, value_column=None, label_column=None, title='', width=10.0, height=8.0, map_style='open-street-map', zoom_level=10, **kwargs)[source]

Standalone function to create a marker map.

Parameters:
  • data (pd.DataFrame | Dict[str, Any]) – DataFrame or dictionary with data

  • latitude_column (str) – Column name for latitude values

  • longitude_column (str) – Column name for longitude values

  • value_column (str) – Column name for values (optional)

  • label_column (str) – Column name for labels (optional)

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

  • map_style (str) – Map style

  • zoom_level (int) – Initial zoom level

  • **kwargs – Additional arguments

Returns:

PIL Image object or None if error

Return type:

Image | None

siege_utilities.reporting.chart_generator.create_pie_chart(data, label_column=None, value_column=None, title='', width=800, height=600, **kwargs)[source]

Standalone function to create a pie chart.

Parameters:
  • data (pd.DataFrame | Dict[str, Any]) – DataFrame or data dictionary

  • label_column (str | None) – Column name for labels

  • value_column (str | None) – Column name for values

  • title (str) – Chart title

  • width (int) – Chart width in pixels

  • height (int) – Chart height in pixels

  • **kwargs – Additional chart parameters

Returns:

Chart configuration dictionary or None if error

Return type:

Dict[str, Any] | None

siege_utilities.reporting.chart_generator.create_scatter_plot(data, x_column=None, y_column=None, title='', width=800, height=600, **kwargs)[source]

Standalone function to create a scatter plot.

Parameters:
  • data (pd.DataFrame | Dict[str, Any]) – DataFrame or data dictionary

  • x_column (str | None) – Column name for x-axis

  • y_column (str | None) – Column name for y-axis

  • title (str) – Chart title

  • width (int) – Chart width in pixels

  • height (int) – Chart height in pixels

  • **kwargs – Additional chart parameters

Returns:

Chart configuration dictionary or None if error

Return type:

Dict[str, Any] | None

siege_utilities.reporting.chart_generator.generate_chart_from_dataframe(df, chart_type='bar', x_column=None, y_columns=None, title='', width=6.0, height=4.0, **kwargs)[source]

Standalone function to generate a chart from a DataFrame.

Parameters:
  • df (pd.DataFrame) – Pandas DataFrame

  • chart_type (str) – Type of chart to create

  • x_column (str) – Column to use for X-axis labels

  • y_columns (list) – Columns to plot

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

  • **kwargs – Additional arguments

Returns:

PIL Image object or None if error

Return type:

Image | None

Extensible chart type system for siege_utilities. Provides base chart types and easy extension capabilities.

exception siege_utilities.reporting.chart_types.ChartCreationError[source]

Bases: RuntimeError

Raised when the underlying create function fails to produce a Figure.

exception siege_utilities.reporting.chart_types.ChartParameterError[source]

Bases: ValueError

Raised when required parameters are missing or invalid.

class siege_utilities.reporting.chart_types.ChartType[source]

Bases: object

Base chart type configuration.

name: str
category: str
description: str = ''
required_parameters: List[str]
optional_parameters: Dict[str, Any]
supports_interactive: bool = False
supports_3d: bool = False
supports_animation: bool = False
default_width: float = 10.0
default_height: float = 8.0
default_dpi: int = 300
custom_options: Dict[str, Any]
create_function: Callable | None = None
validate_function: Callable | None = None
customize_function: Callable | None = None
__init__(name, category, description='', required_parameters=<factory>, optional_parameters=<factory>, supports_interactive=False, supports_3d=False, supports_animation=False, default_width=10.0, default_height=8.0, default_dpi=300, custom_options=<factory>, create_function=None, validate_function=None, customize_function=None)
Parameters:
Return type:

None

class siege_utilities.reporting.chart_types.ChartTypeRegistry[source]

Bases: object

Registry for chart types and their implementations. Provides easy extension and customization of chart types.

__init__()[source]

Initialize the chart type registry.

chart_types: Dict[str, ChartType]
register_chart_type(chart_type)[source]

Register a new chart type.

Parameters:

chart_type (ChartType) – ChartType object to register

get_chart_type(chart_type_name)[source]

Get a chart type by name.

Parameters:

chart_type_name (str) – Name of the chart type

Returns:

ChartType object or None if not found

Return type:

ChartType | None

list_chart_types(category=None)[source]

List available chart types.

Parameters:

category (str | None) – Filter by category

Returns:

List of chart type names

Return type:

List[str]

get_chart_categories()[source]

Get list of available chart categories.

Return type:

List[str]

create_chart(chart_type_name, **kwargs)[source]

Create a chart using the specified chart type.

Parameters:
  • chart_type_name (str) – Name of the chart type (must exist in the registry).

  • **kwargs – Parameters for the chart; must include every entry in the chart type’s required_parameters.

Return type:

matplotlib.figure.Figure

Raises:
add_chart_creator(chart_type_name, create_function)[source]

Add or update the create function for a chart type.

Parameters:
  • chart_type_name (str) – Name of the chart type

  • create_function (Callable) – Function to create the chart

validate_chart_parameters(chart_type_name, **kwargs)[source]

Validate parameters for a chart type without creating the chart.

Parameters:
  • chart_type_name (str)

  • **kwargs – Chart parameters to validate against the chart type’s required_parameters. If the chart type defines a custom validate_function, all kwargs are forwarded to it.

Returns:

True iff required params present AND any custom validate_function returns truthy.

Return type:

bool

Raises:
  • UnknownChartTypeError – If chart_type_name isn’t registered. (Legitimately-missing validation returns False; unknown chart type is a caller error.)

  • ChartParameterError – If the custom validate function raised.

get_chart_help(chart_type_name)[source]

Get help information for a chart type.

Parameters:

chart_type_name (str) – Name of the chart type

Returns:

Dictionary with help information

Return type:

Dict[str, Any]

export_chart_type_config(chart_type_name, output_path)[source]

Export chart type configuration to a file.

Parameters:
  • chart_type_name (str) – Name of the chart type to export

  • output_path (str) – Path to export the configuration

exception siege_utilities.reporting.chart_types.UnknownChartTypeError[source]

Bases: LookupError

Raised when a chart type name is not in the registry.

siege_utilities.reporting.chart_types.create_chart(chart_type_name, **kwargs)[source]

Create a chart using the specified chart type.

Parameters:
  • chart_type_name (str) – Name of a registered chart type.

  • **kwargs – Forwarded to the chart type’s create function. Must include all of the chart type’s required_parameters. Optional parameters are filled from the chart type’s defaults. See ChartTypeRegistry.create_chart() for details.

Return type:

Optional[Figure]

siege_utilities.reporting.chart_types.get_chart_registry()[source]

Get or create the global chart type registry.

Return type:

ChartTypeRegistry

siege_utilities.reporting.chart_types.register_chart_type(chart_type)[source]

Register a new chart type.

Parameters:

chart_type (ChartType)

Rendering helpers for WaveSet longitudinal output.

Takes a LONGITUDINAL Chain (typically from compare_chain()) and produces matplotlib figures:

  • trend_chart() — line chart of each category across waves

  • heatmap() — category × wave heatmap of percents or counts

exception siege_utilities.reporting.wave_charts.WaveChartError[source]

Bases: ValueError

Raised when a WaveSet chart cannot be rendered from the given Chain.

siege_utilities.reporting.wave_charts.heatmap(chain, *, title=None, figsize=(10, 6), cmap='RdYlBu_r', annotate=True)[source]

Category × wave heatmap.

Parameters:
  • chain (Chain) – A LONGITUDINAL Chain.

  • title (Optional[str]) – Optional plot title.

  • figsize (tuple) – Matplotlib figure size.

  • cmap (str) – Matplotlib colormap name.

  • annotate (bool) – If True, write the numeric value in each cell.

siege_utilities.reporting.wave_charts.trend_chart(chain, *, title=None, ylabel='%', figsize=(10, 6), marker='o')[source]

Line chart of each row category across waves.

Parameters:
  • chain (Chain) – A LONGITUDINAL Chain. Each wave is a column; each row_var value becomes one line.

  • title (Optional[str]) – Optional plot title; defaults to f"{chain.row_var} over time".

  • ylabel (str) – Y-axis label; default “%”.

  • figsize (tuple) – Matplotlib figure size tuple.

  • marker (str) – Matplotlib marker style for data points.

Legend management utilities for siege_utilities reporting system. Provides comprehensive legend generation and management for charts, tables, and visualizations.

class siege_utilities.reporting.legend_manager.ColorScheme[source]

Bases: Enum

Enumeration of color schemes for legends

BLUE = 'blue'
GREEN = 'green'
RED = 'red'
PURPLE = 'purple'
ORANGE = 'orange'
GRAY = 'gray'
class siege_utilities.reporting.legend_manager.LegendManager[source]

Bases: object

Comprehensive legend management system for charts, tables, and visualizations. Provides consistent legend generation across all siege_utilities components.

__init__(branding_config=None)[source]

Initialize the legend manager.

Parameters:

branding_config (Dict[str, Any] | None) – Branding configuration for colors and styling

get_color_for_intensity(intensity, color_scheme=ColorScheme.BLUE)[source]

Get color for a given intensity (0-1) using specified color scheme.

Parameters:
  • intensity (float) – Intensity value between 0 and 1

  • color_scheme (ColorScheme) – Color scheme to use

Returns:

Hex color string

Return type:

str

create_heatmap_legend_table(min_value, max_value, value_name='Value', color_scheme=ColorScheme.BLUE, levels=5)[source]

Create a heatmap legend table for ReportLab.

Parameters:
  • min_value (float) – Minimum value in the data

  • max_value (float) – Maximum value in the data

  • value_name (str) – Name of the value being visualized

  • color_scheme (ColorScheme) – Color scheme to use

  • levels (int) – Number of intensity levels (default 5)

Returns:

ReportLab Table object

Return type:

reportlab.platypus.Table | None

create_matplotlib_legend(ax, labels, title='Legend', position=LegendPosition.BEST, **kwargs)[source]

Create a matplotlib legend with enhanced styling.

Parameters:
  • ax – Matplotlib axes object

  • labels (List[str]) – List of legend labels

  • title (str) – Legend title

  • position (LegendPosition) – Legend position

  • **kwargs – Additional legend parameters

Return type:

None

create_legend_for_series(ax, series_data, title='Legend', position=LegendPosition.BEST)[source]

Create a legend for multiple data series.

Parameters:
  • ax – Matplotlib axes object

  • series_data (Dict[str, Any]) – Dictionary mapping series names to their data/colors

  • title (str) – Legend title

  • position (LegendPosition) – Legend position

Return type:

None

create_heatmap_legend_elements(min_value, max_value, color_scheme=ColorScheme.BLUE, levels=5)[source]

Create matplotlib legend elements for heatmap visualization.

Parameters:
  • min_value (float) – Minimum value in the data

  • max_value (float) – Maximum value in the data

  • color_scheme (ColorScheme) – Color scheme to use

  • levels (int) – Number of intensity levels

Returns:

List of matplotlib Patch objects for legend

Return type:

List[matplotlib.patches.Patch]

add_heatmap_legend_to_plot(ax, min_value, max_value, color_scheme=ColorScheme.BLUE, position=LegendPosition.RIGHT, title='Intensity')[source]

Add a heatmap legend directly to a matplotlib plot.

Parameters:
  • ax – Matplotlib axes object

  • min_value (float) – Minimum value in the data

  • max_value (float) – Maximum value in the data

  • color_scheme (ColorScheme) – Color scheme to use

  • position (LegendPosition) – Legend position

  • title (str) – Legend title

Return type:

None

get_legend_position_for_chart_type(chart_type, data_size)[source]

Get optimal legend position based on chart type and data size.

Parameters:
  • chart_type (str) – Type of chart (‘bar’, ‘line’, ‘pie’, ‘scatter’, etc.)

  • data_size (int) – Number of data series or categories

Returns:

Recommended LegendPosition

Return type:

LegendPosition

should_show_legend(chart_type, data_size, series_count=1)[source]

Determine if a legend should be shown based on chart characteristics.

Parameters:
  • chart_type (str) – Type of chart

  • data_size (int) – Number of data points

  • series_count (int) – Number of data series

Returns:

True if legend should be shown

Return type:

bool

class siege_utilities.reporting.legend_manager.LegendPosition[source]

Bases: Enum

Enumeration of legend positions

BEST = 'best'
OUTSIDE = 'outside'
BOTTOM = 'bottom'
TOP = 'top'
LEFT = 'left'
RIGHT = 'right'
CENTER = 'center'
siege_utilities.reporting.legend_manager.create_heatmap_legend_table(min_value, max_value, value_name='Value', color_scheme='blue')[source]

Convenience function to create a heatmap legend table.

Parameters:
  • min_value (float) – Minimum value in the data

  • max_value (float) – Maximum value in the data

  • value_name (str) – Name of the value being visualized

  • color_scheme (str) – Color scheme name (‘blue’, ‘green’, ‘red’, etc.)

Returns:

ReportLab Table object or None

Return type:

reportlab.platypus.Table | None

siege_utilities.reporting.legend_manager.get_optimal_legend_position(chart_type, data_size)[source]

Convenience function to get optimal legend position.

Parameters:
  • chart_type (str) – Type of chart

  • data_size (int) – Number of data series

Returns:

Legend position string

Return type:

str

Utilities for working with ReportLab Image objects containing base64 data URIs.

ChartGenerator methods return ReportLab Image objects whose filename attribute is a base64 data URI (e.g. data:image/png;base64,...). These helpers decode, display, and persist those images.

siege_utilities.reporting.image_utils.decode_rl_image(rl_img)[source]

Decode a ReportLab Image’s base64 data URI to raw PNG bytes.

Parameters:

rl_img – A ReportLab Image object (or any object with a filename attribute).

Returns:

Raw PNG bytes, or None if the object is not a base64 data URI image.

Return type:

bytes | None

siege_utilities.reporting.image_utils.show_rl_image(rl_img)[source]

Display a ReportLab Image in a Jupyter notebook.

Decodes the base64 data URI embedded in the ReportLab Image and returns an IPython Image object suitable for inline display.

Parameters:

rl_img – A ReportLab Image object returned by ChartGenerator.

Returns:

An IPython.display.Image for notebook rendering, or the original object if it is not a base64 data URI image.

siege_utilities.reporting.image_utils.save_rl_image(rl_img, path)[source]

Save a ReportLab Image (base64 data URI) to a PNG file.

Parameters:
  • rl_img – A ReportLab Image object returned by ChartGenerator.

  • path (str | Path) – Destination file path.

Returns:

The resolved Path object (unchanged if the image could not be decoded).

Return type:

Path

Chart Engines

Engine mixins for the ChartGenerator class.

Each mixin defines a subset of chart-generation methods. At runtime they are combined via multiple inheritance into the unified ChartGenerator class defined in chart_generator.py.

class siege_utilities.reporting.engines.BaseChartEngine[source]

Bases: object

Core infrastructure: init, colors, styling, scaling, save helpers.

__init__(branding_config=None, output_dir=None, max_chart_width=None, max_chart_height=None)[source]

Initialize the chart generator.

Parameters:
  • branding_config (Dict[str, Any] | None) – Branding configuration for chart colors and styling

  • output_dir (Path | None) – Directory for saving Folium HTML map files. Defaults to ~/.siege_utilities for backward compatibility.

  • max_chart_width (float | None) – Maximum chart width in inches for ReportLab output. When set, charts wider than this are uniformly scaled down to fit. None disables width clamping.

  • max_chart_height (float | None) – Maximum chart height in inches for ReportLab output. When set, charts taller than this are uniformly scaled down to fit. None disables height clamping.

save_figure_as_vector(fig, output_path, fmt='svg')[source]

Save a matplotlib figure as a vector file (SVG, EPS, or PDF).

Parameters:
  • fig – Matplotlib figure.

  • output_path (str | Path) – Destination file path (extension is overridden by fmt).

  • fmt (str) – Vector format — 'svg', 'eps', or 'pdf'.

Returns:

Path to the saved file.

Raises:
  • ValueError – If fmt is not a supported vector format.

  • OSError – If the file cannot be written.

Return type:

Path

create_chart_with_caption(chart, caption, caption_style=None)[source]

Create a chart with a caption below it.

Parameters:
  • chart (None) – The chart image

  • caption (str) – Caption text

  • caption_style (str | None) – Style name for the caption

Returns:

List containing chart and caption

Return type:

List

create_chart_section(title, charts, description='', width=6.0)[source]

Create a complete chart section with title, description, and charts.

Parameters:
  • title (str) – Section title

  • charts (List[None]) – List of chart images

  • description (str) – Section description

  • width (float) – Maximum section width in inches. Charts exceeding this width are scaled down proportionally.

Returns:

List of flowables for the section

Return type:

List

generate_chart_from_dataframe(df, chart_type='bar', x_column=None, y_columns=None, title='', width=6.0, height=4.0)[source]

Generate a chart from a pandas DataFrame.

Parameters:
  • df – Pandas DataFrame

  • chart_type (str) – Type of chart to create

  • x_column (str) – Column to use for X-axis labels

  • y_columns (List[str]) – Columns to use for Y-axis data

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

Returns:

ReportLab Image object

Return type:

None

create_custom_chart(chart_config, width=6.0, height=4.0)[source]

Create a custom chart based on configuration.

Parameters:
  • chart_config (Dict[str, Any]) – Complete chart configuration

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

Returns:

ReportLab Image object

Return type:

None

class siege_utilities.reporting.engines.BarChartMixin[source]

Bases: object

Bar chart, line chart, pie chart, and proportional text bar chart methods.

create_bar_chart(data, x_column=None, y_column=None, title='', width=6.0, height=4.0, chart_type='bar', group_by=None, show_legend=True, legend_position='best')[source]

Create a bar chart from data.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • x_column (str) – Column name for X-axis (or ‘index’ for DataFrame index)

  • y_column (str) – Column name for Y-axis

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

  • chart_type (str) – Type of chart (‘bar’, ‘horizontal’)

  • group_by (str) – Column to group by for grouped bars

  • show_legend (bool)

  • legend_position (str)

Returns:

ReportLab Image object

Return type:

Image

create_line_chart(data, x_column=None, y_columns=None, title='', width=6.0, height=4.0, show_legend=True, legend_position='best')[source]

Create a line chart from data.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • x_column (str) – Column name for X-axis

  • y_columns (List[str]) – List of column names for Y-axis (multiple lines)

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

  • show_legend (bool)

  • legend_position (str)

Returns:

ReportLab Image object

Return type:

Image

create_pie_chart(data, labels_column=None, values_column=None, title='', width=6.0, height=4.0, show_legend=True, legend_position='right')[source]

Create a pie chart from data.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • labels_column (str) – Column name for labels

  • values_column (str) – Column name for values

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

  • show_legend (bool)

  • legend_position (str)

Returns:

ReportLab Image object

Return type:

Image

create_proportional_text_bar_chart(data, labels_column, values_column, title='Proportional Text Bar Chart', max_width=50, bar_char='█', show_values=True, sort_descending=True)[source]

Create a proportional text-based bar chart

Parameters:
  • data (pd.DataFrame) – DataFrame containing the data

  • labels_column (str) – Column name for labels

  • values_column (str) – Column name for values

  • title (str) – Chart title

  • max_width (int) – Maximum width of bars in characters

  • bar_char (str) – Character to use for bars

  • show_values (bool) – Whether to show actual values

  • sort_descending (bool) – Whether to sort by values descending

Returns:

Formatted text chart string

Return type:

str

class siege_utilities.reporting.engines.MapChartMixin[source]

Bases: object

Geographic map chart methods (choropleth, marker, 3D, heatmap, cluster, flow).

create_choropleth_map(data, geo_data=None, location_column=None, value_column=None, title='', width=8.0, height=6.0, map_type='us', key_on='feature.properties.geoid', fill_color='YlOrRd')[source]

Create a choropleth map from data using Folium.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • geo_data (Union['gpd.GeoDataFrame', str, Path, Dict, None]) – GeoDataFrame, path to GeoJSON, GeoJSON dict, or None. If a GeoDataFrame is passed it is converted to GeoJSON automatically.

  • location_column (str) – Column name for locations (must match geo_data features via key_on)

  • value_column (str) – Column name for values to color by

  • title (str) – Map title

  • width (float) – Map width in inches

  • height (float) – Map height in inches

  • map_type (str) – Type of map (‘world’, ‘us’, ‘europe’)

  • key_on (str) – GeoJSON feature property to join on (e.g. ‘feature.properties.geoid’)

  • fill_color (str) – Brewer color scheme name (e.g. ‘YlOrRd’, ‘BuGn’, ‘Blues’)

Returns:

ReportLab Image object (placeholder — HTML saved to output_dir)

Return type:

Image

create_bivariate_choropleth_matplotlib(data, geodata, location_column, value_column1, value_column2, title='', width=10.0, height=8.0, color_scheme='default')[source]

Create a bivariate choropleth map using matplotlib and geopandas. This method follows the approach from the bivariate-choropleth repository.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • geodata (Union['gpd.GeoDataFrame', str, Path]) – GeoDataFrame or path to GeoJSON file

  • location_column (str) – Column name for locations (must match geodata)

  • value_column1 (str) – Column name for the first value (X-axis in bivariate scheme)

  • value_column2 (str) – Column name for the second value (Y-axis in bivariate scheme)

  • title (str) – Map title

  • width (float) – Map width in inches

  • height (float) – Map height in inches

  • color_scheme (str) – Color scheme (‘default’, ‘custom’, ‘diverging’)

Returns:

ReportLab Image object

Return type:

Image

create_advanced_choropleth(data, geodata, location_column, value_column, title='', width=10.0, height=8.0, classification='quantiles', bins=5, color_scheme='YlOrRd')[source]

Create an advanced choropleth map with multiple classification options.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • geodata (Union['gpd.GeoDataFrame', str, Path]) – GeoDataFrame or path to GeoJSON file

  • location_column (str) – Column name for locations

  • value_column (str) – Column name for values to color by

  • title (str) – Map title

  • width (float) – Map width in inches

  • height (float) – Map height in inches

  • classification (str) – Classification method (‘quantiles’, ‘equal_interval’, ‘natural_breaks’)

  • bins (int) – Number of bins for classification

  • color_scheme (str) – Color scheme for the map

Returns:

ReportLab Image object

Return type:

Image

create_marker_map(data, latitude_column, longitude_column, value_column=None, label_column=None, title='', width=10.0, height=8.0, map_style='open-street-map', zoom_level=10)[source]

Create a map with markers showing point locations.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • latitude_column (str) – Column name for latitude values

  • longitude_column (str) – Column name for longitude values

  • value_column (str) – Column name for marker size/color values

  • label_column (str) – Column name for marker labels

  • title (str) – Map title

  • width (float) – Map width in inches

  • height (float) – Map height in inches

  • map_style (str) – Map tile style (‘open-street-map’, ‘cartodb-positron’, ‘stamen-terrain’)

  • zoom_level (int) – Initial zoom level for the map

Returns:

ReportLab Image object

Return type:

Image

create_3d_map(data, latitude_column, longitude_column, elevation_column, title='', width=12.0, height=10.0, view_angle=45, elevation_scale=1.0)[source]

Create a 3D map visualization showing elevation or height data.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • latitude_column (str) – Column name for latitude values

  • longitude_column (str) – Column name for longitude values

  • elevation_column (str) – Column name for elevation/height values

  • title (str) – Map title

  • width (float) – Map width in inches

  • height (float) – Map height in inches

  • view_angle (int) – 3D viewing angle in degrees

  • elevation_scale (float) – Scale factor for elevation values

Returns:

ReportLab Image object

Return type:

Image

create_heatmap_map(data, latitude_column, longitude_column, value_column, title='', width=10.0, height=8.0, grid_size=50, blur_radius=0.5)[source]

Create a heatmap overlay on a geographic map.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • latitude_column (str) – Column name for latitude values

  • longitude_column (str) – Column name for longitude values

  • value_column (str) – Column name for intensity values

  • title (str) – Map title

  • width (float) – Map width in inches

  • height (float) – Map height in inches

  • grid_size (int) – Number of grid cells for heatmap

  • blur_radius (float) – Blur radius for smoothing

Returns:

ReportLab Image object

Return type:

Image

create_cluster_map(data, latitude_column, longitude_column, cluster_column=None, label_column=None, title='', width=10.0, height=8.0, max_cluster_radius=80)[source]

Create a map with clustered markers for better visualization of dense data.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • latitude_column (str) – Column name for latitude values

  • longitude_column (str) – Column name for longitude values

  • cluster_column (str) – Column name for clustering values

  • label_column (str) – Column name for marker labels

  • title (str) – Map title

  • width (float) – Map width in inches

  • height (float) – Map height in inches

  • max_cluster_radius (int) – Maximum radius for clustering

Returns:

ReportLab Image object

Return type:

Image

create_flow_map(data, origin_lat_column, origin_lon_column, dest_lat_column, dest_lon_column, flow_value_column=None, title='', width=12.0, height=10.0)[source]

Create a flow map showing movement or connections between locations.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • origin_lat_column (str) – Column name for origin latitude

  • origin_lon_column (str) – Column name for origin longitude

  • dest_lat_column (str) – Column name for destination latitude

  • dest_lon_column (str) – Column name for destination longitude

  • flow_value_column (str) – Column name for flow intensity values

  • title (str) – Map title

  • width (float) – Map width in inches

  • height (float) – Map height in inches

Returns:

ReportLab Image object

Return type:

Image

create_bivariate_choropleth(data, geo_data=None, location_column=None, value_column1=None, value_column2=None, title='', width=8.0, height=6.0, color_scheme='default')[source]

Create a bivariate choropleth map from data using Folium.

Uses the same 3x3 bivariate color classification as create_bivariate_choropleth_matplotlib but renders the result as an interactive Folium map.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data (must include geometry if GeoDataFrame, or be joinable to geo_data via location_column)

  • geo_data (Union['gpd.GeoDataFrame', str, Path, Dict, None]) – GeoDataFrame, path to GeoJSON, GeoJSON dict, or None. If data is already a GeoDataFrame this can be omitted.

  • location_column (str) – Column to join data ↔ geo_data on

  • value_column1 (str) – First variable (X-axis in bivariate scheme)

  • value_column2 (str) – Second variable (Y-axis in bivariate scheme)

  • title (str) – Map title

  • width (float) – Map width in inches

  • height (float) – Map height in inches

  • color_scheme (str) – Bivariate color scheme (‘default’, ‘blue_red’, ‘green_orange’)

Returns:

ReportLab Image object (placeholder — HTML saved to output_dir)

Return type:

Image

class siege_utilities.reporting.engines.StatsChartMixin[source]

Bases: object

Statistical chart methods (heatmap, scatter plot, text heatmap).

create_heatmap(data, x_column=None, y_column=None, value_column=None, title='', width=8.0, height=6.0)[source]

Create a heatmap from data.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • x_column (str) – Column name for X-axis

  • y_column (str) – Column name for Y-axis

  • value_column (str) – Column name for values

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

Returns:

ReportLab Image object

Return type:

Image

create_scatter_plot(data, x_column, y_column, color_column=None, title='', width=6.0, height=4.0)[source]

Create a scatter plot from data.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • x_column (str) – Column name for X-axis

  • y_column (str) – Column name for Y-axis

  • color_column (str) – Column name for color coding

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

Returns:

ReportLab Image object

Return type:

Image

create_heatmap_text_chart(data, x_column, y_column, value_column, title='Text Heatmap', max_width=20, max_height=10, heat_chars=' ░▒▓█')[source]

Create a text-based heatmap visualization

Parameters:
  • data (pd.DataFrame) – DataFrame containing the data

  • x_column (str) – Column name for x-axis labels

  • y_column (str) – Column name for y-axis labels

  • value_column (str) – Column name for values

  • title (str) – Chart title

  • max_width (int) – Maximum width in characters

  • max_height (int) – Maximum height in characters

  • heat_chars (str) – Characters for heat intensity (light to dark)

Returns:

Formatted text heatmap string

Return type:

str

class siege_utilities.reporting.engines.CompositeChartMixin[source]

Bases: object

Composite chart methods (convergence diagram, dashboard, summary charts, subplots).

create_convergence_diagram(sources, hub_label='Unified Hub', outputs=None, title='Convergence Diagram', width=10.0, height=6.0, arrow_style='curved', arrow_count=None, arrow_color=None, show_magnitudes=False, magnitude_key='magnitude')[source]

Create a stylized convergence diagram with arrows into a labeled origin.

Parameters:
  • sources (List[Dict[str, Any]]) – Source node dictionaries; supports keys: label (required), color (optional), and optional magnitude key.

  • hub_label (str) – Center node label.

  • outputs (List[Dict[str, Any]] | None) – Optional output node dictionaries (same schema as sources).

  • title (str) – Diagram title.

  • width (float) – Figure width in inches.

  • height (float) – Figure height in inches.

  • arrow_style (str) – One of curved, radial, orthogonal.

  • arrow_count (int | None) – Optional max number of source arrows to render.

  • arrow_color (str | None) – Optional color override for arrows.

  • show_magnitudes (bool) – If True, append magnitudes to source labels when present.

  • magnitude_key (str) – Dict key to read magnitude from.

Returns:

ReportLab Image object.

Return type:

None

create_dashboard(charts, layout='2x2', width=12.0, height=8.0)[source]

Create a dashboard with multiple charts.

Parameters:
  • charts (List[Dict[str, Any]]) – List of chart configurations

  • layout (str) – Layout string (e.g., “2x2”, “3x1”)

  • width (float) – Total dashboard width in inches

  • height (float) – Total dashboard height in inches

Returns:

ReportLab Image object

Return type:

None

create_dataframe_summary_charts(df, title='', width=8.0, height=6.0)[source]

Create summary charts from a pandas DataFrame.

Parameters:
  • df (pd.DataFrame) – Pandas DataFrame

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

Returns:

ReportLab Image object

Return type:

None

Base engine mixin — __init__, scaling, placeholder, and conversion helpers.

class siege_utilities.reporting.engines.base_engine.BaseChartEngine[source]

Bases: object

Core infrastructure: init, colors, styling, scaling, save helpers.

__init__(branding_config=None, output_dir=None, max_chart_width=None, max_chart_height=None)[source]

Initialize the chart generator.

Parameters:
  • branding_config (Dict[str, Any] | None) – Branding configuration for chart colors and styling

  • output_dir (Path | None) – Directory for saving Folium HTML map files. Defaults to ~/.siege_utilities for backward compatibility.

  • max_chart_width (float | None) – Maximum chart width in inches for ReportLab output. When set, charts wider than this are uniformly scaled down to fit. None disables width clamping.

  • max_chart_height (float | None) – Maximum chart height in inches for ReportLab output. When set, charts taller than this are uniformly scaled down to fit. None disables height clamping.

save_figure_as_vector(fig, output_path, fmt='svg')[source]

Save a matplotlib figure as a vector file (SVG, EPS, or PDF).

Parameters:
  • fig – Matplotlib figure.

  • output_path (str | Path) – Destination file path (extension is overridden by fmt).

  • fmt (str) – Vector format — 'svg', 'eps', or 'pdf'.

Returns:

Path to the saved file.

Raises:
  • ValueError – If fmt is not a supported vector format.

  • OSError – If the file cannot be written.

Return type:

Path

create_chart_with_caption(chart, caption, caption_style=None)[source]

Create a chart with a caption below it.

Parameters:
  • chart (None) – The chart image

  • caption (str) – Caption text

  • caption_style (str | None) – Style name for the caption

Returns:

List containing chart and caption

Return type:

List

create_chart_section(title, charts, description='', width=6.0)[source]

Create a complete chart section with title, description, and charts.

Parameters:
  • title (str) – Section title

  • charts (List[None]) – List of chart images

  • description (str) – Section description

  • width (float) – Maximum section width in inches. Charts exceeding this width are scaled down proportionally.

Returns:

List of flowables for the section

Return type:

List

generate_chart_from_dataframe(df, chart_type='bar', x_column=None, y_columns=None, title='', width=6.0, height=4.0)[source]

Generate a chart from a pandas DataFrame.

Parameters:
  • df – Pandas DataFrame

  • chart_type (str) – Type of chart to create

  • x_column (str) – Column to use for X-axis labels

  • y_columns (List[str]) – Columns to use for Y-axis data

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

Returns:

ReportLab Image object

Return type:

None

create_custom_chart(chart_config, width=6.0, height=4.0)[source]

Create a custom chart based on configuration.

Parameters:
  • chart_config (Dict[str, Any]) – Complete chart configuration

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

Returns:

ReportLab Image object

Return type:

None

Bar, line, pie, and proportional text bar chart mixins.

class siege_utilities.reporting.engines.bar_engine.BarChartMixin[source]

Bases: object

Bar chart, line chart, pie chart, and proportional text bar chart methods.

create_bar_chart(data, x_column=None, y_column=None, title='', width=6.0, height=4.0, chart_type='bar', group_by=None, show_legend=True, legend_position='best')[source]

Create a bar chart from data.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • x_column (str) – Column name for X-axis (or ‘index’ for DataFrame index)

  • y_column (str) – Column name for Y-axis

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

  • chart_type (str) – Type of chart (‘bar’, ‘horizontal’)

  • group_by (str) – Column to group by for grouped bars

  • show_legend (bool)

  • legend_position (str)

Returns:

ReportLab Image object

Return type:

Image

create_line_chart(data, x_column=None, y_columns=None, title='', width=6.0, height=4.0, show_legend=True, legend_position='best')[source]

Create a line chart from data.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • x_column (str) – Column name for X-axis

  • y_columns (List[str]) – List of column names for Y-axis (multiple lines)

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

  • show_legend (bool)

  • legend_position (str)

Returns:

ReportLab Image object

Return type:

Image

create_pie_chart(data, labels_column=None, values_column=None, title='', width=6.0, height=4.0, show_legend=True, legend_position='right')[source]

Create a pie chart from data.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • labels_column (str) – Column name for labels

  • values_column (str) – Column name for values

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

  • show_legend (bool)

  • legend_position (str)

Returns:

ReportLab Image object

Return type:

Image

create_proportional_text_bar_chart(data, labels_column, values_column, title='Proportional Text Bar Chart', max_width=50, bar_char='█', show_values=True, sort_descending=True)[source]

Create a proportional text-based bar chart

Parameters:
  • data (pd.DataFrame) – DataFrame containing the data

  • labels_column (str) – Column name for labels

  • values_column (str) – Column name for values

  • title (str) – Chart title

  • max_width (int) – Maximum width of bars in characters

  • bar_char (str) – Character to use for bars

  • show_values (bool) – Whether to show actual values

  • sort_descending (bool) – Whether to sort by values descending

Returns:

Formatted text chart string

Return type:

str

Composite chart mixins — convergence diagrams, dashboards, and subplot helpers.

class siege_utilities.reporting.engines.composite_engine.CompositeChartMixin[source]

Bases: object

Composite chart methods (convergence diagram, dashboard, summary charts, subplots).

create_convergence_diagram(sources, hub_label='Unified Hub', outputs=None, title='Convergence Diagram', width=10.0, height=6.0, arrow_style='curved', arrow_count=None, arrow_color=None, show_magnitudes=False, magnitude_key='magnitude')[source]

Create a stylized convergence diagram with arrows into a labeled origin.

Parameters:
  • sources (List[Dict[str, Any]]) – Source node dictionaries; supports keys: label (required), color (optional), and optional magnitude key.

  • hub_label (str) – Center node label.

  • outputs (List[Dict[str, Any]] | None) – Optional output node dictionaries (same schema as sources).

  • title (str) – Diagram title.

  • width (float) – Figure width in inches.

  • height (float) – Figure height in inches.

  • arrow_style (str) – One of curved, radial, orthogonal.

  • arrow_count (int | None) – Optional max number of source arrows to render.

  • arrow_color (str | None) – Optional color override for arrows.

  • show_magnitudes (bool) – If True, append magnitudes to source labels when present.

  • magnitude_key (str) – Dict key to read magnitude from.

Returns:

ReportLab Image object.

Return type:

None

create_dashboard(charts, layout='2x2', width=12.0, height=8.0)[source]

Create a dashboard with multiple charts.

Parameters:
  • charts (List[Dict[str, Any]]) – List of chart configurations

  • layout (str) – Layout string (e.g., “2x2”, “3x1”)

  • width (float) – Total dashboard width in inches

  • height (float) – Total dashboard height in inches

Returns:

ReportLab Image object

Return type:

None

create_dataframe_summary_charts(df, title='', width=8.0, height=6.0)[source]

Create summary charts from a pandas DataFrame.

Parameters:
  • df (pd.DataFrame) – Pandas DataFrame

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

Returns:

ReportLab Image object

Return type:

None

Map chart mixins — choropleth, marker, 3D, heatmap, cluster, flow, and bivariate maps.

class siege_utilities.reporting.engines.map_engine.MapChartMixin[source]

Bases: object

Geographic map chart methods (choropleth, marker, 3D, heatmap, cluster, flow).

create_choropleth_map(data, geo_data=None, location_column=None, value_column=None, title='', width=8.0, height=6.0, map_type='us', key_on='feature.properties.geoid', fill_color='YlOrRd')[source]

Create a choropleth map from data using Folium.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • geo_data (Union['gpd.GeoDataFrame', str, Path, Dict, None]) – GeoDataFrame, path to GeoJSON, GeoJSON dict, or None. If a GeoDataFrame is passed it is converted to GeoJSON automatically.

  • location_column (str) – Column name for locations (must match geo_data features via key_on)

  • value_column (str) – Column name for values to color by

  • title (str) – Map title

  • width (float) – Map width in inches

  • height (float) – Map height in inches

  • map_type (str) – Type of map (‘world’, ‘us’, ‘europe’)

  • key_on (str) – GeoJSON feature property to join on (e.g. ‘feature.properties.geoid’)

  • fill_color (str) – Brewer color scheme name (e.g. ‘YlOrRd’, ‘BuGn’, ‘Blues’)

Returns:

ReportLab Image object (placeholder — HTML saved to output_dir)

Return type:

Image

create_bivariate_choropleth_matplotlib(data, geodata, location_column, value_column1, value_column2, title='', width=10.0, height=8.0, color_scheme='default')[source]

Create a bivariate choropleth map using matplotlib and geopandas. This method follows the approach from the bivariate-choropleth repository.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • geodata (Union['gpd.GeoDataFrame', str, Path]) – GeoDataFrame or path to GeoJSON file

  • location_column (str) – Column name for locations (must match geodata)

  • value_column1 (str) – Column name for the first value (X-axis in bivariate scheme)

  • value_column2 (str) – Column name for the second value (Y-axis in bivariate scheme)

  • title (str) – Map title

  • width (float) – Map width in inches

  • height (float) – Map height in inches

  • color_scheme (str) – Color scheme (‘default’, ‘custom’, ‘diverging’)

Returns:

ReportLab Image object

Return type:

Image

create_advanced_choropleth(data, geodata, location_column, value_column, title='', width=10.0, height=8.0, classification='quantiles', bins=5, color_scheme='YlOrRd')[source]

Create an advanced choropleth map with multiple classification options.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • geodata (Union['gpd.GeoDataFrame', str, Path]) – GeoDataFrame or path to GeoJSON file

  • location_column (str) – Column name for locations

  • value_column (str) – Column name for values to color by

  • title (str) – Map title

  • width (float) – Map width in inches

  • height (float) – Map height in inches

  • classification (str) – Classification method (‘quantiles’, ‘equal_interval’, ‘natural_breaks’)

  • bins (int) – Number of bins for classification

  • color_scheme (str) – Color scheme for the map

Returns:

ReportLab Image object

Return type:

Image

create_marker_map(data, latitude_column, longitude_column, value_column=None, label_column=None, title='', width=10.0, height=8.0, map_style='open-street-map', zoom_level=10)[source]

Create a map with markers showing point locations.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • latitude_column (str) – Column name for latitude values

  • longitude_column (str) – Column name for longitude values

  • value_column (str) – Column name for marker size/color values

  • label_column (str) – Column name for marker labels

  • title (str) – Map title

  • width (float) – Map width in inches

  • height (float) – Map height in inches

  • map_style (str) – Map tile style (‘open-street-map’, ‘cartodb-positron’, ‘stamen-terrain’)

  • zoom_level (int) – Initial zoom level for the map

Returns:

ReportLab Image object

Return type:

Image

create_3d_map(data, latitude_column, longitude_column, elevation_column, title='', width=12.0, height=10.0, view_angle=45, elevation_scale=1.0)[source]

Create a 3D map visualization showing elevation or height data.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • latitude_column (str) – Column name for latitude values

  • longitude_column (str) – Column name for longitude values

  • elevation_column (str) – Column name for elevation/height values

  • title (str) – Map title

  • width (float) – Map width in inches

  • height (float) – Map height in inches

  • view_angle (int) – 3D viewing angle in degrees

  • elevation_scale (float) – Scale factor for elevation values

Returns:

ReportLab Image object

Return type:

Image

create_heatmap_map(data, latitude_column, longitude_column, value_column, title='', width=10.0, height=8.0, grid_size=50, blur_radius=0.5)[source]

Create a heatmap overlay on a geographic map.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • latitude_column (str) – Column name for latitude values

  • longitude_column (str) – Column name for longitude values

  • value_column (str) – Column name for intensity values

  • title (str) – Map title

  • width (float) – Map width in inches

  • height (float) – Map height in inches

  • grid_size (int) – Number of grid cells for heatmap

  • blur_radius (float) – Blur radius for smoothing

Returns:

ReportLab Image object

Return type:

Image

create_cluster_map(data, latitude_column, longitude_column, cluster_column=None, label_column=None, title='', width=10.0, height=8.0, max_cluster_radius=80)[source]

Create a map with clustered markers for better visualization of dense data.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • latitude_column (str) – Column name for latitude values

  • longitude_column (str) – Column name for longitude values

  • cluster_column (str) – Column name for clustering values

  • label_column (str) – Column name for marker labels

  • title (str) – Map title

  • width (float) – Map width in inches

  • height (float) – Map height in inches

  • max_cluster_radius (int) – Maximum radius for clustering

Returns:

ReportLab Image object

Return type:

Image

create_flow_map(data, origin_lat_column, origin_lon_column, dest_lat_column, dest_lon_column, flow_value_column=None, title='', width=12.0, height=10.0)[source]

Create a flow map showing movement or connections between locations.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • origin_lat_column (str) – Column name for origin latitude

  • origin_lon_column (str) – Column name for origin longitude

  • dest_lat_column (str) – Column name for destination latitude

  • dest_lon_column (str) – Column name for destination longitude

  • flow_value_column (str) – Column name for flow intensity values

  • title (str) – Map title

  • width (float) – Map width in inches

  • height (float) – Map height in inches

Returns:

ReportLab Image object

Return type:

Image

create_bivariate_choropleth(data, geo_data=None, location_column=None, value_column1=None, value_column2=None, title='', width=8.0, height=6.0, color_scheme='default')[source]

Create a bivariate choropleth map from data using Folium.

Uses the same 3x3 bivariate color classification as create_bivariate_choropleth_matplotlib but renders the result as an interactive Folium map.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data (must include geometry if GeoDataFrame, or be joinable to geo_data via location_column)

  • geo_data (Union['gpd.GeoDataFrame', str, Path, Dict, None]) – GeoDataFrame, path to GeoJSON, GeoJSON dict, or None. If data is already a GeoDataFrame this can be omitted.

  • location_column (str) – Column to join data ↔ geo_data on

  • value_column1 (str) – First variable (X-axis in bivariate scheme)

  • value_column2 (str) – Second variable (Y-axis in bivariate scheme)

  • title (str) – Map title

  • width (float) – Map width in inches

  • height (float) – Map height in inches

  • color_scheme (str) – Bivariate color scheme (‘default’, ‘blue_red’, ‘green_orange’)

Returns:

ReportLab Image object (placeholder — HTML saved to output_dir)

Return type:

Image

Statistical chart mixins — heatmap, scatter plot, and text heatmap.

class siege_utilities.reporting.engines.stats_engine.StatsChartMixin[source]

Bases: object

Statistical chart methods (heatmap, scatter plot, text heatmap).

create_heatmap(data, x_column=None, y_column=None, value_column=None, title='', width=8.0, height=6.0)[source]

Create a heatmap from data.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • x_column (str) – Column name for X-axis

  • y_column (str) – Column name for Y-axis

  • value_column (str) – Column name for values

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

Returns:

ReportLab Image object

Return type:

Image

create_scatter_plot(data, x_column, y_column, color_column=None, title='', width=6.0, height=4.0)[source]

Create a scatter plot from data.

Parameters:
  • data (Union[pd.DataFrame, Dict[str, Any]]) – DataFrame or dictionary with data

  • x_column (str) – Column name for X-axis

  • y_column (str) – Column name for Y-axis

  • color_column (str) – Column name for color coding

  • title (str) – Chart title

  • width (float) – Chart width in inches

  • height (float) – Chart height in inches

Returns:

ReportLab Image object

Return type:

Image

create_heatmap_text_chart(data, x_column, y_column, value_column, title='Text Heatmap', max_width=20, max_height=10, heat_chars=' ░▒▓█')[source]

Create a text-based heatmap visualization

Parameters:
  • data (pd.DataFrame) – DataFrame containing the data

  • x_column (str) – Column name for x-axis labels

  • y_column (str) – Column name for y-axis labels

  • value_column (str) – Column name for values

  • title (str) – Chart title

  • max_width (int) – Maximum width in characters

  • max_height (int) – Maximum height in characters

  • heat_chars (str) – Characters for heat intensity (light to dark)

Returns:

Formatted text heatmap string

Return type:

str

Reports and Documents

Main report generator for siege_utilities reporting system. Orchestrates the creation of comprehensive reports with charts, tables, and branding.

class siege_utilities.reporting.report_generator.ReportGenerator[source]

Bases: object

Main report generator that creates comprehensive reports. Integrates templates, charts, and data sources.

__init__(client_name, output_dir=None)[source]

Initialize the report generator.

Parameters:
  • client_name (str) – Name of the client for branding

  • output_dir (Path | None) – Directory for output reports

create_analytics_report(title, charts, data_summary='', insights=None, recommendations=None, executive_summary=None, methodology=None)[source]

Create a comprehensive analytics report with multiple sections.

Parameters:
  • title (str) – Report title

  • charts (List[PIL.Image.Image]) – List of chart images

  • data_summary (str) – Summary of the data analyzed

  • insights (List[str]) – List of key insights

  • recommendations (List[str]) – List of actionable recommendations

  • executive_summary (str) – Executive summary text

  • methodology (str) – Methodology description

Returns:

Dictionary containing report content structure

Return type:

Dict[str, Any]

create_comprehensive_report(title, author=None, client=None, report_type='analysis', sections=None, appendices=None, table_of_contents=True, page_numbers=True, header_footer=True)[source]

Create a comprehensive report with full document structure.

Parameters:
  • title (str) – Report title

  • author (str) – Report author

  • client (str) – Client name

  • report_type (str) – Type of report

  • sections (List[Dict]) – List of report sections

  • appendices (List[Dict]) – List of appendices

  • table_of_contents (bool) – Include table of contents

  • page_numbers (bool) – Include page numbers

  • header_footer (bool) – Include headers and footers

Returns:

Dictionary containing complete report structure

Return type:

Dict[str, Any]

add_section(report_content, section_type, title, content, level=1, page_break_before=False, page_break_after=False)[source]

Add a new section to an existing report.

Parameters:
  • report_content (Dict[str, Any]) – Existing report content

  • section_type (str) – Type of section

  • title (str) – Section title

  • content (Any) – Section content

  • level (int) – Section level (0=main, 1=section, 2=subsection)

  • page_break_before (bool) – Add page break before section

  • page_break_after (bool) – Add page break after section

Returns:

Updated report content

Return type:

Dict[str, Any]

add_table_section(report_content, title, table_data, headers=None, level=1, table_style='default', sort_by=None, sort_order='asc')[source]

Add a table section to the report.

Parameters:
  • report_content (Dict[str, Any]) – Existing report content

  • title (str) – Section title

  • table_data (List[List] | pandas.DataFrame) – Table data (list of lists or DataFrame)

  • headers (List[str]) – Column headers

  • level (int) – Section level

  • table_style (str) – Table styling

  • sort_by (int | str | None) – Column index or header name to sort by. None preserves existing order.

  • sort_order (str) – 'asc' or 'desc'.

Returns:

Updated report content

Return type:

Dict[str, Any]

add_text_section(report_content, title, text_content, level=1, text_style='body')[source]

Add a text section to the report.

Parameters:
  • report_content (Dict[str, Any]) – Existing report content

  • title (str) – Section title

  • text_content (str) – Text content

  • level (int) – Section level

  • text_style (str) – Text styling

Returns:

Updated report content

Return type:

Dict[str, Any]

add_chart_section(report_content, title, charts, description='', level=1, layout='vertical')[source]

Add a chart section to the report.

Parameters:
  • report_content (Dict[str, Any]) – Existing report content

  • title (str) – Section title

  • charts (List[PIL.Image.Image]) – List of chart images

  • description (str) – Section description

  • level (int) – Section level

  • layout (str) – Chart layout (‘vertical’, ‘horizontal’, ‘grid’)

Returns:

Updated report content

Return type:

Dict[str, Any]

add_map_section(report_content, title, maps, map_type='choropleth', description='', level=1)[source]

Add a map section to the report.

Parameters:
  • report_content (Dict[str, Any]) – Existing report content

  • title (str) – Section title

  • maps (List[PIL.Image.Image]) – List of map images

  • map_type (str) – Type of maps

  • description (str) – Section description

  • level (int) – Section level

Returns:

Updated report content

Return type:

Dict[str, Any]

add_appendix(report_content, title, content, appendix_type='data', level=1)[source]

Add an appendix to the report.

Parameters:
  • report_content (Dict[str, Any]) – Existing report content

  • title (str) – Appendix title

  • content (Any) – Appendix content

  • appendix_type (str) – Type of appendix

  • level (int) – Section level

Returns:

Updated report content

Return type:

Dict[str, Any]

generate_pdf_report(report_content, output_path, template_config=None)[source]

Generate a comprehensive PDF report with full document structure.

Parameters:
  • report_content (Dict[str, Any]) – Report content structure

  • output_path (str) – Output PDF file path

  • template_config (str) – Template configuration file path

Raises:

OSError – If the output directory cannot be created or is not writable, or if the final rename fails.

Return type:

None

Analytics reports module for siege_utilities reporting system. Integrates with Google Analytics, databases, and other data sources.

class siege_utilities.reporting.analytics_reports.AnalyticsReportGenerator[source]

Bases: object

Generates analytics reports from various data sources. Integrates with Google Analytics, databases, and Spark dataframes.

__init__(client_name, output_dir=None)[source]

Initialize the analytics report generator.

Parameters:
  • client_name (str) – Name of the client for branding

  • output_dir (Path | None) – Directory for output reports

create_google_analytics_report(ga_data, date_range='', report_title='')[source]

Create a Google Analytics report.

Parameters:
  • ga_data (Dict[str, Any]) – Google Analytics data dictionary

  • date_range (str) – Date range for the report

  • report_title (str) – Custom title for the report

Returns:

Path to the generated PDF report

Return type:

Path

create_website_performance_report(performance_data, metrics, report_title='')[source]

Create a website performance report.

Parameters:
  • performance_data (Dict[str, Any]) – Website performance data

  • metrics (List[str]) – List of performance metrics to include

  • report_title (str) – Custom title for the report

Returns:

Path to the generated PDF report

Return type:

Path

create_custom_analytics_report(data_source, data, report_config)[source]

Create a custom analytics report from various data sources.

Parameters:
  • data_source (str) – Type of data source (‘dataframe’, ‘dict’, ‘json’, ‘csv’)

  • data (pandas.DataFrame | Dict[str, Any]) – The actual data

  • report_config (Dict[str, Any]) – Report configuration

Returns:

Path to the generated PDF report

Return type:

Path

create_monthly_analytics_report(monthly_data, year, month)[source]

Create a monthly analytics report.

Parameters:
  • monthly_data (Dict[str, Any]) – Monthly analytics data

  • year (int) – Year for the report

  • month (int) – Month for the report

Returns:

Path to the generated PDF report

Return type:

Path

create_quarterly_analytics_report(quarterly_data, year, quarter)[source]

Create a quarterly analytics report.

Parameters:
  • quarterly_data (Dict[str, Any]) – Quarterly analytics data

  • year (int) – Year for the report

  • quarter (int) – Quarter for the report (1-4)

Returns:

Path to the generated PDF report

Return type:

Path

create_campaign_performance_report(campaign_data, campaign_name, date_range='')[source]

Create a campaign performance report.

Parameters:
  • campaign_data (Dict[str, Any]) – Campaign performance data

  • campaign_name (str) – Name of the campaign

  • date_range (str) – Date range for the campaign

Returns:

Path to the generated PDF report

Return type:

Path

PowerPoint generation utilities for siege_utilities reporting system. Creates presentations from analytics data and report configurations.

class siege_utilities.reporting.powerpoint_generator.PowerPointGenerator[source]

Bases: object

Generates PowerPoint presentations from analytics data and report configurations. Requires python-pptx package for PowerPoint generation.

Internal-helper convention (writing-code:11): private _add_*_slide methods return the python-pptx Slide object they added. Public create_*_presentation methods log at INFO when the presentation is saved (floor (b) for the whole flow). The combination satisfies writing-code:11 floor for both the per-slide and the per-presentation observation level: a caller can confirm a specific slide was added by inspecting the return value, and an auditor can confirm a presentation was emitted by greping logs.

__init__(client_name, output_dir=None)[source]

Initialize the PowerPoint generator.

Parameters:
  • client_name (str) – Name of the client for branding

  • output_dir (Path | None) – Directory for output presentations

create_analytics_presentation(report_data, presentation_title='', include_charts=True, include_tables=True)[source]

Create a PowerPoint presentation from analytics data.

Parameters:
  • report_data (Dict[str, Any]) – Dictionary containing report data

  • presentation_title (str) – Title of the presentation

  • include_charts (bool) – Whether to include charts

  • include_tables (bool) – Whether to include data tables

Returns:

Path to the generated PowerPoint file

Return type:

Path

create_performance_presentation(performance_data, metrics, presentation_title='')[source]

Create a performance metrics presentation.

Parameters:
  • performance_data (Dict[str, Any]) – Dictionary containing performance metrics

  • metrics (List[str]) – List of metrics to include

  • presentation_title (str) – Custom title for the presentation

Returns:

Path to the generated PowerPoint file

Return type:

Path

create_custom_presentation(presentation_config)[source]

Create a custom PowerPoint presentation based on configuration.

Parameters:

presentation_config (Dict[str, Any]) – Complete presentation configuration

Returns:

Path to the generated PowerPoint file

Return type:

Path

create_comprehensive_presentation(title, author=None, client=None, presentation_type='analysis', sections=None, slide_layouts=None, include_toc=True, include_agenda=True)[source]

Create a comprehensive PowerPoint presentation with full slide structure.

Parameters:
  • title (str) – Presentation title

  • author (str) – Presentation author

  • client (str) – Client name

  • presentation_type (str) – Type of presentation

  • sections (List[Dict]) – List of presentation sections

  • slide_layouts (Dict[str, str]) – Custom slide layouts for different section types

  • include_toc (bool) – Include table of contents slide

  • include_agenda (bool) – Include agenda slide

Returns:

Dictionary containing complete presentation structure

Return type:

Dict[str, Any]

add_slide_section(presentation_content, section_type, title, content, level=1, slide_layout='default', notes=None)[source]

Add a new slide section to an existing presentation.

Parameters:
  • presentation_content (Dict[str, Any]) – Existing presentation content

  • section_type (str) – Type of slide section

  • title (str) – Slide title

  • content (Any) – Slide content

  • level (int) – Section level (0=main, 1=section, 2=subsection)

  • slide_layout (str) – Custom slide layout

  • notes (str) – Speaker notes for the slide

Returns:

Updated presentation content

Return type:

Dict[str, Any]

add_text_slide(presentation_content, title, text_content, level=1, text_style='body', bullet_points=True)[source]

Add a text slide to the presentation.

Parameters:
  • presentation_content (Dict[str, Any]) – Existing presentation content

  • title (str) – Slide title

  • text_content (str) – Text content

  • level (int) – Section level

  • text_style (str) – Text styling

  • bullet_points (bool) – Use bullet points for text

Returns:

Updated presentation content

Return type:

Dict[str, Any]

add_chart_slide(presentation_content, title, charts, description='', level=1, layout='single_chart')[source]

Add a chart slide to the presentation.

Parameters:
  • presentation_content (Dict[str, Any]) – Existing presentation content

  • title (str) – Slide title

  • charts (List[Any]) – List of chart images

  • description (str) – Slide description

  • level (int) – Section level

  • layout (str) – Chart layout (‘single_chart’, ‘two_charts’, ‘grid’)

Returns:

Updated presentation content

Return type:

Dict[str, Any]

add_map_slide(presentation_content, title, maps, map_type='choropleth', description='', level=1)[source]

Add a map slide to the presentation.

Parameters:
  • presentation_content (Dict[str, Any]) – Existing presentation content

  • title (str) – Slide title

  • maps (List[Any]) – List of map images

  • map_type (str) – Type of maps

  • description (str) – Slide description

  • level (int) – Section level

Returns:

Updated presentation content

Return type:

Dict[str, Any]

add_table_slide(presentation_content, title, table_data, headers=None, level=1, table_style='default', sort_by=None, sort_order='asc')[source]

Add a table slide to the presentation.

Parameters:
  • presentation_content (Dict[str, Any]) – Existing presentation content

  • title (str) – Slide title

  • table_data (List[List] | pandas.DataFrame) – Table data (list of lists or DataFrame)

  • headers (List[str]) – Column headers

  • level (int) – Section level

  • table_style (str) – Table styling

  • sort_by (int | str | None) – Column index or header name to sort by. None preserves existing order.

  • sort_order (str) – 'asc' or 'desc'.

Returns:

Updated presentation content

Return type:

Dict[str, Any]

add_comparison_slide(presentation_content, title, comparison_data, level=1)[source]

Add a comparison slide to the presentation.

Parameters:
  • presentation_content (Dict[str, Any]) – Existing presentation content

  • title (str) – Slide title

  • comparison_data (Dict[str, Any]) – Data for comparison (before/after, options, etc.)

  • level (int) – Section level

Returns:

Updated presentation content

Return type:

Dict[str, Any]

add_summary_slide(presentation_content, title, key_points, level=1)[source]

Add a summary slide to the presentation.

Parameters:
  • presentation_content (Dict[str, Any]) – Existing presentation content

  • title (str) – Slide title

  • key_points (List[str]) – List of key points to summarize

  • level (int) – Section level

Returns:

Updated presentation content

Return type:

Dict[str, Any]

generate_powerpoint_presentation(presentation_content, output_path)[source]

Generate a comprehensive PowerPoint presentation from a structure dict.

Consistent with sibling create_*_presentation methods (per writing-code:13): returns Path on success and raises on failure. The previous bool-return contract conflicted with the sibling family’s raise-on-failure contract and forced callers of the PowerPointGenerator class to handle two failure-indication mechanisms across methods that looked similar.

Parameters:
  • presentation_content (Dict[str, Any]) – Presentation content structure (a Dict produced by create_comprehensive_presentation + the add_*_slide builders).

  • output_path (str) – Output PowerPoint file path.

Returns:

Path to the saved .pptx file.

Raises:

Exception – any python-pptx or filesystem error during slide construction or save. Caller pattern-matches on the exception type, not on a boolean.

Return type:

Path

create_presentation_from_dataframe(df, presentation_title='', max_slides=10)[source]

Create a PowerPoint presentation from a pandas DataFrame.

Parameters:
  • df (pandas.DataFrame) – Pandas DataFrame

  • presentation_title (str) – Title of the presentation

  • max_slides (int) – Maximum number of slides to create

Returns:

Path to the generated PowerPoint file

Return type:

Path

IDML (InDesign Markup Language) report export.

Provides IDMLExporter for programmatic creation of IDML files that Adobe InDesign can open, plus a convenience export_report_idml() function that accepts the same ga_data dict used by the PDF/PPTX generators.

IDML is a ZIP archive containing a set of XML files (designmap.xml, Spreads/, Stories/, Resources/, etc.). When the simpleidml library is installed we delegate to it; otherwise we build the ZIP structure manually so that no external dependency is required at runtime.

class siege_utilities.reporting.idml_export.IDMLExporter[source]

Bases: object

Build an IDML file programmatically.

Parameters:
  • template_path (str or Path, optional) – Path to an existing .idml template. If provided and simpleidml is installed the template is loaded for modification. Otherwise the exporter builds the IDML structure from scratch.

  • page_width (float) – Page width in points (default 612 = US Letter).

  • page_height (float) – Page height in points (default 792 = US Letter).

__init__(template_path=None, page_width=612.0, page_height=792.0)[source]
Parameters:
  • template_path (str | None)

  • page_width (float)

  • page_height (float)

Return type:

None

add_text_frame(text, style_name='NormalParagraphStyle', x=72.0, y=72.0, width=468.0, height=36.0)[source]

Add a text frame to the document.

Parameters:
  • text (str) – Content of the text frame.

  • style_name (str) – InDesign paragraph style name.

  • x (float) – Top-left position in points.

  • y (float) – Top-left position in points.

  • width (float) – Dimensions in points.

  • height (float) – Dimensions in points.

Return type:

None

add_image_frame(image_path, x=72.0, y=72.0, width=200.0, height=200.0)[source]

Add an image placeholder frame.

Parameters:
  • image_path (str) – Path to the image file (stored as a link reference).

  • x (float) – Top-left position in points.

  • y (float) – Top-left position in points.

  • width (float) – Dimensions in points.

  • height (float) – Dimensions in points.

Return type:

None

add_table(headers, rows, x=72.0, y=72.0, width=468.0, height=200.0)[source]

Add a table as a text frame with tab-separated content.

Parameters:
  • headers (list[str]) – Column headers.

  • rows (list[list[str]]) – Row data — each inner list is one row.

  • x (float) – Top-left position in points.

  • y (float) – Top-left position in points.

  • width (float) – Dimensions in points.

  • height (float) – Dimensions in points.

Return type:

None

replace_placeholder(placeholder, content)[source]

Register a template placeholder substitution.

When save() is called every occurrence of placeholder in story XML content is replaced with content.

Parameters:
  • placeholder (str)

  • content (str)

Return type:

None

save(output_path)[source]

Write the IDML file to output_path.

Returns the resolved output path.

Parameters:

output_path (str)

Return type:

str

siege_utilities.reporting.idml_export.export_report_idml(ga_data, output_path, template_path=None, title='Google Analytics Report')[source]

Export a GA-data report as an IDML file.

Accepts the same ga_data dict produced by generate_sample_ga_data() / fetch_real_ga4_data() and writes an IDML file that Adobe InDesign can open.

Parameters:
  • ga_data (dict) – Google Analytics data dictionary (totals, traffic_sources, top_pages, devices, etc.).

  • output_path (str) – Destination file path for the .idml output.

  • template_path (str, optional) – Path to an IDML template with placeholders.

  • title (str) – Report title.

Returns:

The resolved output file path.

Return type:

str

Client branding management for siege_utilities reporting system. Handles client-specific configurations, logos, colors, and styling.

exception siege_utilities.reporting.client_branding.ClientBrandingError[source]

Bases: RuntimeError

Raised when a client-branding operation fails unexpectedly.

Use the __cause__ attribute (set via raise … from e) to inspect the underlying error (YAMLError, OSError, ValidationError, etc.).

class siege_utilities.reporting.client_branding.ClientBrandingManager[source]

Bases: object

Manages client branding configurations for reports. Handles logos, colors, fonts, and styling preferences.

__init__(config_dir=None)[source]

Initialize the branding manager.

Parameters:

config_dir (Path | None) – Directory containing branding configuration files

create_client_branding(client_name, branding_config)[source]

Create a new client branding configuration.

Parameters:
  • client_name (str) – Name of the client

  • branding_config (Dict[str, Any]) – Branding configuration dictionary

Returns:

Path to the created configuration file

Return type:

Path

get_client_branding(client_name)[source]

Get branding configuration for a specific client.

Parameters:

client_name (str) – Name of the client

Returns:

Branding configuration dictionary.

Raises:
Return type:

Dict[str, Any]

update_client_branding(client_name, updates)[source]

Update an existing client branding configuration.

Parameters:
  • client_name (str) – Name of the client

  • updates (Dict[str, Any]) – Dictionary of updates to apply

Raises:
Return type:

None

list_clients()[source]

List all available client branding configurations.

Returns:

List of client names

Return type:

List[str]

delete_client_branding(client_name)[source]

Delete a client branding configuration.

Parameters:

client_name (str) – Name of the client to delete

Raises:
Return type:

None

create_branding_from_template(client_name, template_name, customizations=None)[source]

Create client branding from a predefined template.

Parameters:
  • client_name (str) – Name of the new client

  • template_name (str) – Name of the template to use

  • customizations (Dict[str, Any] | None) – Optional customizations to apply

Returns:

Path to the created configuration file

Return type:

Path

validate_branding_config(branding_config)[source]

Validate a branding configuration.

Parameters:

branding_config (Dict[str, Any]) – Branding configuration to validate

Returns:

List of validation errors (empty if valid)

Return type:

List[str]

export_branding_config(client_name, export_path)[source]

Export a client branding configuration to a file.

Parameters:
  • client_name (str) – Name of the client

  • export_path (Path) – Path where to export the configuration

Raises:
Return type:

None

import_branding_config(import_path, client_name=None)[source]

Import a branding configuration from a file.

Parameters:
  • import_path (Path) – Path to the configuration file

  • client_name (str | None) – Name for the client (if not specified in config)

Raises:
Return type:

None

get_branding_summary(client_name)[source]

Get a summary of a client’s branding configuration.

Parameters:

client_name (str) – Name of the client

Returns:

Dictionary containing branding summary

Return type:

Dict[str, Any]

exception siege_utilities.reporting.client_branding.ClientBrandingNotFoundError[source]

Bases: LookupError

Raised when a named client’s branding configuration does not exist.

Analytics Reports

Analytics submodule - Analytics-specific report components

Deprecation shim — re-exports from siege_utilities.reporting.analytics_reports.

Moved up one level during ELE-2439 so the reporting/analytics/ subdirectory can be removed once PollingAnalyzer is deleted in v4.0.0. See docs/adr/0006-polling-analyzer-location.md.

class siege_utilities.reporting.analytics.analytics_reports.AnalyticsReportGenerator[source]

Bases: object

Generates analytics reports from various data sources. Integrates with Google Analytics, databases, and Spark dataframes.

__init__(client_name, output_dir=None)[source]

Initialize the analytics report generator.

Parameters:
  • client_name (str) – Name of the client for branding

  • output_dir (Path | None) – Directory for output reports

create_google_analytics_report(ga_data, date_range='', report_title='')[source]

Create a Google Analytics report.

Parameters:
  • ga_data (Dict[str, Any]) – Google Analytics data dictionary

  • date_range (str) – Date range for the report

  • report_title (str) – Custom title for the report

Returns:

Path to the generated PDF report

Return type:

Path

create_website_performance_report(performance_data, metrics, report_title='')[source]

Create a website performance report.

Parameters:
  • performance_data (Dict[str, Any]) – Website performance data

  • metrics (List[str]) – List of performance metrics to include

  • report_title (str) – Custom title for the report

Returns:

Path to the generated PDF report

Return type:

Path

create_custom_analytics_report(data_source, data, report_config)[source]

Create a custom analytics report from various data sources.

Parameters:
  • data_source (str) – Type of data source (‘dataframe’, ‘dict’, ‘json’, ‘csv’)

  • data (pandas.DataFrame | Dict[str, Any]) – The actual data

  • report_config (Dict[str, Any]) – Report configuration

Returns:

Path to the generated PDF report

Return type:

Path

create_monthly_analytics_report(monthly_data, year, month)[source]

Create a monthly analytics report.

Parameters:
  • monthly_data (Dict[str, Any]) – Monthly analytics data

  • year (int) – Year for the report

  • month (int) – Month for the report

Returns:

Path to the generated PDF report

Return type:

Path

create_quarterly_analytics_report(quarterly_data, year, quarter)[source]

Create a quarterly analytics report.

Parameters:
  • quarterly_data (Dict[str, Any]) – Quarterly analytics data

  • year (int) – Year for the report

  • quarter (int) – Quarter for the report (1-4)

Returns:

Path to the generated PDF report

Return type:

Path

create_campaign_performance_report(campaign_data, campaign_name, date_range='')[source]

Create a campaign performance report.

Parameters:
  • campaign_data (Dict[str, Any]) – Campaign performance data

  • campaign_name (str) – Name of the campaign

  • date_range (str) – Date range for the campaign

Returns:

Path to the generated PDF report

Return type:

Path

Polling analysis — cross-tabulation, longitudinal analysis, change detection.

Operates on long-form DataFrames with at least one dimension column and one numeric metric column (default metric='value'). Callers supply their own column names via keyword arguments.

exception siege_utilities.reporting.analytics.polling_analyzer.PollingAnalysisError[source]

Bases: RuntimeError

Raised when polling analysis cannot complete due to bad input or config.

class siege_utilities.reporting.analytics.polling_analyzer.PollingAnalyzer[source]

Bases: object

Cross-dimensional analytics for polling and survey data.

Deprecated since version PollingAnalyzer: predates the siege_utilities.survey module and bundles three unrelated concerns (cross-tabulation, longitudinal analysis, and chart rendering). Use the purpose-built replacements:

See docs/adr/0006-polling-analyzer-location.md for the rationale. This class will be removed in the v4.0.0.

__init__()[source]
Return type:

None

create_cross_tabulation_matrix(data, dimensions, *, metric='value', top_n=10)[source]

Build pairwise cross-tabulations for all dimension combinations.

Parameters:
  • data (pd.DataFrame) – Input data with one row per observation.

  • dimensions (list of str) – Column names to cross-tab. Must exist in data.

  • metric (str, keyword-only) – Numeric column to aggregate (sum).

  • top_n (int, keyword-only) – Keep only the top top_n values per dimension.

Returns:

Keys "{dim1}_x_{dim2}"; values are filtered cross-tab DataFrames.

Return type:

dict

Raises:

PollingAnalysisError – If a required column is missing or aggregation fails.

create_longitudinal_analysis(data, time_column, dimensions, *, metric='value', periods=('daily', 'weekly', 'monthly', 'quarterly'))[source]

Aggregate data by time period and dimension.

Parameters:
  • data (pd.DataFrame) – Input with a parseable time column.

  • time_column (str) – Column to convert to datetime and group by period.

  • dimensions (list of str) – Dimension columns to group within each period.

  • metric (str, keyword-only) – Numeric column to sum.

  • periods (tuple of str, keyword-only) – Subset of {"daily", "weekly", "monthly", "quarterly"}.

Returns:

{period: {dimension: DataFrame}}.

Return type:

dict

Raises:

PollingAnalysisError – If the time column cannot be parsed or a period name is unknown.

create_performance_rankings(data, dimensions, *, metric='value', top_n=10)[source]

Rank the top-N values per dimension by total metric.

Parameters:
  • data (pd.DataFrame)

  • dimensions (list of str)

  • metric (str, keyword-only)

  • top_n (int, keyword-only)

Returns:

For each dimension, a list of (value, sum_metric, percentage). percentage is the share of the dimension’s total, in [0, 100].

Return type:

dict of list of tuple

Raises:

PollingAnalysisError – If a required column is missing.

create_change_detection_data(current_data, historical_data, *, geographic_column='geography', metric='value')[source]

Compare current vs historical aggregates and compute growth/decline.

Parameters:
  • current_data (pd.DataFrame) – Long-form data sharing geographic_column and metric columns.

  • historical_data (pd.DataFrame) – Long-form data sharing geographic_column and metric columns.

  • geographic_column (str, keyword-only) – Column to aggregate on.

  • metric (str, keyword-only) – Numeric column to sum.

Returns:

Columns: geographic_column, {metric}_current, {metric}_historical, change_pct, change_direction.

Return type:

pd.DataFrame

Raises:

PollingAnalysisError – If either frame is missing the required columns.

create_polling_summary(data, *, metric='value', name_column=None)[source]

Build an executive-summary string from a dict of data-type frames.

Parameters:
  • data (dict of pd.DataFrame) – Keyed by data-type label (e.g. "region", "segment").

  • metric (str, keyword-only)

  • name_column (str, keyword-only, optional) – Column to read the top performer’s label from. If omitted, the first column that is not the metric is used.

Returns:

Multi-sentence summary.

Return type:

str

Raises:

PollingAnalysisError – If no frame in data contains the requested metric column, or a frame has no non-metric column to use as a label.

create_heatmap_visualization(crosstab_data, *, title='Cross-Tabulation Heatmap', metric='value', figsize=(10, 8))[source]

Render a cross-tab as a Seaborn heatmap.

metric is keyword-only; it is used only for the colorbar label. The annotation format is chosen automatically from the data dtype (integer data gets 'd', float data gets '.2f').

Parameters:
Return type:

matplotlib.figure.Figure

Raises:

PollingAnalysisError – If matplotlib or seaborn cannot render the input.

create_trend_analysis_chart(longitudinal_data, dimension, *, metric='value', figsize=(12, 6))[source]

Plot per-period trend lines for a single dimension.

Parameters:
  • longitudinal_data (dict of pd.DataFrame) – Keyed by period label.

  • dimension (str) – Dimension column name to title/label with.

  • metric (str, keyword-only)

  • figsize (tuple of int, keyword-only)

Return type:

matplotlib.figure.Figure

Raises:

PollingAnalysisError – If plotting fails.

Hex Cartograms

Hex cartogram (tile-map) construction and rendering.

A hex cartogram replaces each administrative unit (state, congressional district, county, country) with a single hexagon, positioned to roughly preserve geography. The whole point: small jurisdictions get the same visual weight as large ones, so Wyoming and DC don’t get drowned out by California.

Public API (re-exported from this package):

  • hex_tile_layout() — build a layout (GeoDataFrame[geometry, code, q, r]) from either a built-in name, an algorithmic placement of a GeoDataFrame, or a hand-drawn mapping registered via register_layout().

  • hex_tile_map() — matplotlib renderer that takes a values series + a layout and returns a Figure. Three sizing modes (equal, value_proportional, value_sqrt) per the design discussion.

  • register_layout() — extension hook for user-supplied hand-positioned layouts.

  • BUILTIN_LAYOUTS — set of layout names shipped with the package. Empty in v1; populated as we add canonical layouts in follow-up work.

  • Algorithm enum — placement-algorithm choices: greedy, hungarian, annealing. (force_directed and ilp are future work; see ELE-2482.)

  • Sizing enum — sizing modes: equal, value_proportional, value_sqrt.

See docs/source/hex_cartograms.md for the algorithm comparison and worked examples.

class siege_utilities.reporting.hex_cartogram.Algorithm[source]

Bases: str, Enum

Placement-algorithm choices for hex_tile_layout().

GREEDY = 'greedy'

Sort by area, place in nearest unoccupied hex. < 100 ms typical.

HUNGARIAN = 'hungarian'

Optimal centroid-distance assignment (no topology term).

ANNEALING = 'annealing'

Centroid + topology weighted; SA refinement of an initial layout.

FORCE_DIRECTED = 'force_directed'

Reserved — not implemented in v1.

ILP = 'ilp'

Reserved — not implemented in v1.

__new__(value)
class siege_utilities.reporting.hex_cartogram.Sizing[source]

Bases: str, Enum

Sizing-mode choices for hex_tile_map().

EQUAL = 'equal'

Every hex same size; values map to colour only.

VALUE_PROPORTIONAL = 'value_proportional'

Hex area proportional to value.

VALUE_SQRT = 'value_sqrt'

Hex side proportional to √value (perception-correct).

__new__(value)
siege_utilities.reporting.hex_cartogram.hex_tile_layout(source, *, code_col='code', algorithm=Algorithm.ANNEALING, components='auto', component_gap=1, hex_size=1.0, seed=None)[source]

Build a hex tile layout.

Parameters:
  • source (Union[str, 'gpd.GeoDataFrame']) – Either a registered/builtin layout name, or a GeoDataFrame of polygons to place algorithmically.

  • code_col (str) – Column name on the GeoDataFrame containing the polygon identifier (e.g. state abbreviation, FIPS code). Ignored when source is a string layout name.

  • algorithm (Union[Algorithm, str]) – One of Algorithm (or its string value). Ignored when source is a registered layout name.

  • components (Optional[Union[str, list[list[str]]]]) – "auto" (default) splits the input into connected components by polygon adjacency and lays each out independently with component_gap empty cells between them. "single" forces everything into one component. A pre-computed list[list[code]] lets the caller specify groups explicitly.

  • component_gap (int) – Number of empty hex cells between neighbouring components in the final output.

  • hex_size (float) – Cell circumradius in CRS units used for the output geometry. 1.0 is fine for visualization; choose a smaller value if you plan to overlay the cartogram on a real map.

  • seed (Optional[int]) – Random seed for the annealing algorithm; ignored otherwise.

Returns:

GeoDataFrame[geometry, code, q, r] — one hexagon per polygon, with axial coords on each row for downstream tooling.

Return type:

gpd.GeoDataFrame

siege_utilities.reporting.hex_cartogram.hex_tile_map(values, layout, *, sizing=Sizing.EQUAL, cmap='viridis', code_col='code', label_col='code', title=None, figsize=(10.0, 7.0), edge_color='#888', missing_color='#eeeeee')[source]

Render a hex cartogram.

Parameters:
  • values (pd.Series) – Values to encode, indexed by polygon code (matching the code_col of layout). Codes present in the layout but absent from values render in missing_color.

  • layout (gpd.GeoDataFrame) – GeoDataFrame from hex_tile_layout() — needs at minimum code, q, r columns.

  • sizing (Union[Sizing, str]) – One of Sizing (or its string value). EQUAL uses the layout’s geometry as-is; the proportional modes scale per-hex around the cell center.

  • cmap (str) – matplotlib colour map name.

  • code_col (str) – Name of the code column on layout.

  • label_col (Optional[str]) – Column to write inside each hex (typically the code). Pass None to omit labels.

  • missing_color (str) – Standard mpl knobs.

  • title (Optional[str])

  • figsize (tuple[float, float])

  • edge_color (str)

  • missing_color

Return type:

matplotlib.figure.Figure

siege_utilities.reporting.hex_cartogram.register_layout(name, mapping)[source]

Register a hand-positioned layout under name.

The mapping must be {code: (q, r)} with no duplicate (q, r) pairs. Use any reproducible code convention ("AL", "01", "al-cd-7"); hex_tile_layout() will join your data on whichever column you provide via code_col.

Parameters:
Return type:

None

Placement algorithms for hex cartograms.

Three algorithms shipped in v1:

  • Greedy — sort polygons by area (largest first), assign each to the nearest unoccupied hex by centroid distance. Fast, baseline quality.

  • Hungarian — bipartite matching via scipy.optimize.linear_sum_assignment(). Provably optimal for the centroid-distance objective. Doesn’t model topology, but sets a strong baseline.

  • Simulated annealing — start from greedy or Hungarian, repeatedly swap pairs whose swap improves a weighted α·centroid_error + β·topology_violation cost. The default for ≤ 200 polygons.

force_directed and ilp are documented as future work in the ticket; the API allows callers to pass the enum but raises NotImplementedError so the surface is forward-compatible.

Each algorithm returns a dict[code, AxialCoord] — a mapping from input polygon ID to its assigned hex cell.

class siege_utilities.reporting.hex_cartogram.algorithms.Algorithm[source]

Bases: str, Enum

Placement-algorithm choices for hex_tile_layout().

GREEDY = 'greedy'

Sort by area, place in nearest unoccupied hex. < 100 ms typical.

HUNGARIAN = 'hungarian'

Optimal centroid-distance assignment (no topology term).

ANNEALING = 'annealing'

Centroid + topology weighted; SA refinement of an initial layout.

FORCE_DIRECTED = 'force_directed'

Reserved — not implemented in v1.

ILP = 'ilp'

Reserved — not implemented in v1.

__new__(value)
siege_utilities.reporting.hex_cartogram.algorithms.place_polygons(gdf, code_col, *, algorithm=Algorithm.ANNEALING, candidate_cells=None, iterations=5000, initial_temperature=1.0, cooling_rate=0.9995, centroid_weight=1.0, topology_weight=0.5, seed=None)[source]

Assign each polygon in gdf to a hex cell.

Parameters:
  • gdf (gpd.GeoDataFrame) – GeoDataFrame of input polygons. Must have a geometry column and a string-valued code_col identifying each polygon.

  • code_col (str) – Column name holding the polygon identifier (used as the key in the returned mapping).

  • algorithm (Algorithm) – One of Algorithm.

  • candidate_cells (Optional[list[AxialCoord]]) – Pre-computed pool of axial coords to assign into. If None, uses bounding_grid() sized to the polygon count.

  • centroid_weight (float)

  • seed (Optional[int]) – Annealing-specific knobs. Ignored by greedy / hungarian.

  • iterations (int)

  • initial_temperature (float)

  • cooling_rate (float)

  • centroid_weight

  • topology_weight (float)

  • seed

Returns:

dict[code, (q, r)] mapping each polygon’s code to its hex coordinate.

Raises:
Return type:

dict[str, AxialCoord]

Connected-component splitting for non-contiguous admin sets.

CONUS + Alaska + Hawaii is the canonical case: three disconnected groups that each deserve their own sub-grid, with empty hexes between groups so the result reads as separated.

The wrapper:

  1. Build a graph where nodes are polygons and edges are “share a border” (or “centroids within a tunable distance”).

  2. Find connected components.

  3. Lay each component out independently using one of the placement algorithms.

  4. Position the per-component layouts in the output grid by their group centroid, with component_gap empty hexes between groups.

siege_utilities.reporting.hex_cartogram.components.find_components(gdf, code_col)[source]

Split gdf into connected components by polygon adjacency.

Two polygons are considered adjacent if their geometries share a border (shapely touches). Returns a list of lists of polygon codes — each inner list is one component.

The result is sorted with the largest component first, then by representative-centroid x-coordinate for stable output across runs.

Parameters:
  • gdf (gpd.GeoDataFrame)

  • code_col (str)

Return type:

list[list[str]]

siege_utilities.reporting.hex_cartogram.components.offset_layout(layout, *, dq, dr)[source]

Shift every cell in layout by (dq, dr).

Used by the multi-component pipeline after each per-component placement, to position the sub-grid in the final output.

Parameters:
Return type:

dict[str, tuple[int, int]]

siege_utilities.reporting.hex_cartogram.components.stitch_components(component_layouts, *, component_gap=1)[source]

Combine per-component layouts into one, separated by component_gap cells.

Components are laid out left-to-right in the order received (which find_components() already biases by size). Each subsequent component’s q-axis starts component_gap cells past the previous component’s max q.

Parameters:
Return type:

dict[str, tuple[int, int]]

Axial hex-grid coordinate math.

Uses axial (q, r) coordinates with pointy-top hexagons (the visual convention for cartograms — wider than tall, easier to read state abbreviations inside). All distance / Cartesian math derives from here; having one canonical conversion module keeps algorithms / rendering internally consistent.

Conventions

  • (q, r) are integers; the third cube coord s = -q - r is implicit.

  • Cartesian conversion uses unit-side-length hexes — caller can rescale.

  • Neighbor offsets: 6 directions, returned in the standard order (E, NE, NW, W, SW, SE).

siege_utilities.reporting.hex_cartogram.coords.axial_distance(a, b)[source]

Hex-grid Manhattan distance between two axial coordinates.

Equivalent to half the cube-coordinate L1 distance.

Parameters:
Return type:

int

siege_utilities.reporting.hex_cartogram.coords.axial_neighbors(qr)[source]

Return the six neighbors of qr in standard order.

Parameters:

qr (tuple[int, int])

Return type:

tuple[tuple[int, int], …]

siege_utilities.reporting.hex_cartogram.coords.axial_to_cartesian(qr, *, size=1.0)[source]

Convert an axial coord to a Cartesian (x, y) for a pointy-top hex.

size is the hex circumradius (corner distance). For unit side-length hexes the natural choice is size = 1.

Parameters:
Return type:

tuple[float, float]

siege_utilities.reporting.hex_cartogram.coords.bounding_grid(n_cells, *, aspect_ratio=1.3)[source]

Generate enough hex cells to plausibly hold n_cells polygons.

Picks a roughly oval grid sized to aspect_ratio (slightly wider than tall by default — matches the way countries are usually drawn on a page). The grid is generated as offset axial coords centered at (0, 0). Used by greedy and annealing algorithms as the candidate cell pool.

Parameters:
Return type:

list[tuple[int, int]]

siege_utilities.reporting.hex_cartogram.coords.hexagon_polygon(qr, *, size=1.0, scale=1.0)[source]

Return the 6 vertices of a pointy-top hexagon at qr.

Parameters:
  • qr (tuple[int, int]) – Axial coordinate of the cell center.

  • size (float) – The grid’s hex circumradius. Controls grid spacing.

  • scale (float) – Multiplier on the drawn hex radius. < 1.0 shrinks individual hexagons within the grid (used by the value-proportional / value-sqrt sizing modes).

Returns:

A list of 6 (x, y) tuples in counter-clockwise order. The polygon is open (no duplicate-first-point); callers that need a closed ring (matplotlib Polygon, shapely) typically don’t — matplotlib closes automatically; shapely’s Polygon constructor accepts the open form.

Return type:

list[tuple[float, float]]

Layout dispatcher for hex cartograms.

Resolves three input shapes into a uniform GeoDataFrame[geometry, code, q, r]:

  • Built-in name ("us_states", "us_cd_117", etc.) — looks up a registered canonical layout. v1 ships with no built-ins; the BUILTIN_LAYOUTS set is empty until ELE-2482 follow-up work bakes hand-positioned canonical layouts.

  • Algorithmic placement — pass a GeoDataFrame of polygons; the module runs one of the algorithms in algorithms to position them on a hex grid.

  • Hand-drawn mapping — register a dict[code, (q, r)] via register_layout() and pass the registered name.

siege_utilities.reporting.hex_cartogram.layouts.BUILTIN_LAYOUTS: set[str] = {}

Set of layout names shipped with the package. Empty in v1; will grow as canonical layouts (NPR-style US states, US CDs) are added in the ELE-2482 follow-up.

siege_utilities.reporting.hex_cartogram.layouts.REGISTERED_LAYOUTS: dict[str, dict[str, tuple[int, int]]] = {}

User-registered layouts, populated by register_layout().

siege_utilities.reporting.hex_cartogram.layouts.hex_tile_layout(source, *, code_col='code', algorithm=Algorithm.ANNEALING, components='auto', component_gap=1, hex_size=1.0, seed=None)[source]

Build a hex tile layout.

Parameters:
  • source (Union[str, 'gpd.GeoDataFrame']) – Either a registered/builtin layout name, or a GeoDataFrame of polygons to place algorithmically.

  • code_col (str) – Column name on the GeoDataFrame containing the polygon identifier (e.g. state abbreviation, FIPS code). Ignored when source is a string layout name.

  • algorithm (Union[Algorithm, str]) – One of Algorithm (or its string value). Ignored when source is a registered layout name.

  • components (Optional[Union[str, list[list[str]]]]) – "auto" (default) splits the input into connected components by polygon adjacency and lays each out independently with component_gap empty cells between them. "single" forces everything into one component. A pre-computed list[list[code]] lets the caller specify groups explicitly.

  • component_gap (int) – Number of empty hex cells between neighbouring components in the final output.

  • hex_size (float) – Cell circumradius in CRS units used for the output geometry. 1.0 is fine for visualization; choose a smaller value if you plan to overlay the cartogram on a real map.

  • seed (Optional[int]) – Random seed for the annealing algorithm; ignored otherwise.

Returns:

GeoDataFrame[geometry, code, q, r] — one hexagon per polygon, with axial coords on each row for downstream tooling.

Return type:

gpd.GeoDataFrame

siege_utilities.reporting.hex_cartogram.layouts.register_layout(name, mapping)[source]

Register a hand-positioned layout under name.

The mapping must be {code: (q, r)} with no duplicate (q, r) pairs. Use any reproducible code convention ("AL", "01", "al-cd-7"); hex_tile_layout() will join your data on whichever column you provide via code_col.

Parameters:
Return type:

None

Matplotlib renderer for hex cartograms.

Three sizing modes per the design discussion:

  • Sizing.EQUAL — every hex same size. Most charming, perceptually honest for “states are equal political units” (NPR’s pick). Default.

  • Sizing.VALUE_PROPORTIONAL — hex area ∝ value. Tilegram-style.

  • Sizing.VALUE_SQRT — hex side ∝ √value, perception-corrected for size-encoding.

The renderer takes a layout GeoDataFrame (from hex_tile_layout()) plus a values series indexed by code, and returns a matplotlib.figure.Figure.

class siege_utilities.reporting.hex_cartogram.renderer.Sizing[source]

Bases: str, Enum

Sizing-mode choices for hex_tile_map().

EQUAL = 'equal'

Every hex same size; values map to colour only.

VALUE_PROPORTIONAL = 'value_proportional'

Hex area proportional to value.

VALUE_SQRT = 'value_sqrt'

Hex side proportional to √value (perception-correct).

__new__(value)
siege_utilities.reporting.hex_cartogram.renderer.hex_tile_map(values, layout, *, sizing=Sizing.EQUAL, cmap='viridis', code_col='code', label_col='code', title=None, figsize=(10.0, 7.0), edge_color='#888', missing_color='#eeeeee')[source]

Render a hex cartogram.

Parameters:
  • values (pd.Series) – Values to encode, indexed by polygon code (matching the code_col of layout). Codes present in the layout but absent from values render in missing_color.

  • layout (gpd.GeoDataFrame) – GeoDataFrame from hex_tile_layout() — needs at minimum code, q, r columns.

  • sizing (Union[Sizing, str]) – One of Sizing (or its string value). EQUAL uses the layout’s geometry as-is; the proportional modes scale per-hex around the cell center.

  • cmap (str) – matplotlib colour map name.

  • code_col (str) – Name of the code column on layout.

  • label_col (Optional[str]) – Column to write inside each hex (typically the code). Pass None to omit labels.

  • missing_color (str) – Standard mpl knobs.

  • title (Optional[str])

  • figsize (tuple[float, float])

  • edge_color (str)

  • missing_color

Return type:

matplotlib.figure.Figure

3D Maps

3D map rendering utilities using pydeck (deck.gl).

Provides hexagonal binning, column layers, and extruded choropleth maps for Jupyter notebooks, Databricks, and standalone HTML export.

Requires the pydeck package (available via the [3d] or [streamlit] optional-dependency groups).

class siege_utilities.reporting.map_3d.ThreeDMapRenderer[source]

Bases: object

High-level helper for creating pydeck 3D map visualisations.

Parameters:
  • mapbox_token (str | None) – Mapbox API key. Falls back to the MAPBOX_ACCESS_TOKEN env-var that pydeck reads automatically when None.

  • map_style (str) – One of "dark", "light", "satellite", "streets", "outdoors" or a full mapbox:// URL.

__init__(mapbox_token=None, map_style='dark')[source]
Parameters:
  • mapbox_token (str | None)

  • map_style (str)

create_hexagon_layer(df, lat_col='latitude', lon_col='longitude', value_col=None, radius=1000, elevation_scale=100, color_range=None, auto_highlight=True, extruded=True, coverage=0.8, zoom=10.0, pitch=45.0)[source]

Create a 3D hexagonal-bin aggregation layer.

Parameters:
  • df (pandas.DataFrame) – Must contain lat_col and lon_col columns.

  • value_col (str | None) – Column whose values are summed per hex. When None the layer counts the number of points (default pydeck behaviour).

  • radius (int) – Hexagon radius in metres.

  • elevation_scale (int) – Multiplier applied to the aggregated elevation value.

  • lat_col (str)

  • lon_col (str)

  • color_range (List[List[int]] | None)

  • auto_highlight (bool)

  • extruded (bool)

  • coverage (float)

  • zoom (float)

  • pitch (float)

Return type:

pdk.Deck

create_column_layer(df, lat_col='latitude', lon_col='longitude', value_col='value', radius=500, elevation_scale=1, color=None, auto_highlight=True, zoom=10.0, pitch=45.0)[source]

Create a 3D column layer at point locations.

Each row produces a column whose height is proportional to value_col multiplied by elevation_scale.

Parameters:
  • color (list[int] | None) – RGBA colour list, e.g. [255, 140, 0, 200]. Defaults to orange.

  • df (pd.DataFrame)

  • lat_col (str)

  • lon_col (str)

  • value_col (str)

  • radius (int)

  • elevation_scale (int)

  • auto_highlight (bool)

  • zoom (float)

  • pitch (float)

Return type:

pdk.Deck

create_choropleth_3d(gdf, value_col='value', elevation_scale=100, fill_color=None, line_color=None, opacity=0.8, zoom=10.0, pitch=45.0)[source]

Create an extruded polygon (choropleth) layer from a GeoDataFrame.

The polygons are extruded by value_col multiplied by elevation_scale, giving a 3D bar-on-map effect.

Parameters:
  • gdf (geopandas.GeoDataFrame) – Must have a geometry column of Polygon / MultiPolygon.

  • fill_color (str | None) – A deck.gl JS expression for getFillColor. Defaults to an orange-to-red colour ramp based on value_col.

  • value_col (str)

  • elevation_scale (int)

  • line_color (List[int] | None)

  • opacity (float)

  • zoom (float)

  • pitch (float)

Return type:

pdk.Deck

render_to_html(deck, output_path)[source]

Save a Deck to a standalone HTML file.

Returns the resolved Path of the written file.

Parameters:
  • deck (pdk.Deck)

  • output_path (str | Path)

Return type:

Path

static render_in_notebook(deck)[source]

Display the Deck in a Jupyter / Databricks notebook.

Simply returns the deck object so that Jupyter’s _repr_html_ protocol renders it inline.

Parameters:

deck (pdk.Deck)

siege_utilities.reporting.map_3d.create_3d_columns(df, lat_col='latitude', lon_col='longitude', value_col='value', **kwargs)[source]

Convenience wrapper — create a column 3D map.

Accepts all keyword arguments supported by ThreeDMapRenderer.create_column_layer().

Parameters:
  • df (pd.DataFrame)

  • lat_col (str)

  • lon_col (str)

  • value_col (str)

Return type:

pdk.Deck

siege_utilities.reporting.map_3d.create_3d_hexbin(df, lat_col='latitude', lon_col='longitude', **kwargs)[source]

Convenience wrapper — create a hexagonal-bin 3D map.

Accepts all keyword arguments supported by ThreeDMapRenderer.create_hexagon_layer().

Parameters:
  • df (pd.DataFrame)

  • lat_col (str)

  • lon_col (str)

Return type:

pdk.Deck

Pages

Pages submodule - OOP page hierarchy for reports

class siege_utilities.reporting.pages.Page[source]

Bases: ABC

Abstract base class for all report pages

__init__(primary_color, secondary_color, accent_color)[source]
abstractmethod build()[source]

Build the page content

add_spacer(height)[source]

Add spacing to the page

add_paragraph(text, style)[source]

Add a paragraph to the page

add_page_break()[source]

Add a page break

get_content()[source]

Get the complete page content

class siege_utilities.reporting.pages.TitlePage[source]

Bases: Page

Title page implementation

__init__(primary_color, secondary_color, accent_color, client_name, client_url, prepared_by, report_type='ANALYTICS REPORT', tagline='', phone=None)[source]
Parameters:
  • report_type (str)

  • tagline (str)

  • phone (str | None)

create_blue_bar_style()[source]

Create the blue header bar style

create_title_style()[source]

Create the main title style

create_tagline_style()[source]

Create the tagline style

create_details_style()[source]

Create the details style

build(start_date, end_date)[source]

Build the complete title page

class siege_utilities.reporting.pages.TableOfContentsPage[source]

Bases: Page

Table of contents page implementation

__init__(primary_color, secondary_color, accent_color)[source]
create_header_style()[source]

Create the TOC header style

create_section_style()[source]

Create the TOC section style

create_item_style()[source]

Create the TOC item style

build(toc_data)[source]

Build the table of contents page.

Parameters:

toc_data (List[Dict]) – list of dicts with keys ‘section’, ‘title’, and optional ‘page_num’

class siege_utilities.reporting.pages.ContentPage[source]

Bases: Page

Base class for content pages (sections, charts, tables)

__init__(primary_color, secondary_color, accent_color)[source]
create_section_header_style()[source]

Create section header style

create_subsection_header_style()[source]

Create subsection header style

Page Models - OOP hierarchy for report pages

class siege_utilities.reporting.pages.page_models.TableType[source]

Bases: Enum

SINGLE_RESPONSE = 'single_response'
MULTIPLE_RESPONSE = 'multiple_response'
CROSS_TAB = 'cross_tab'
LONGITUDINAL = 'longitudinal'
RANKING = 'ranking'
MEAN_SCALE = 'mean_scale'
BANNER = 'banner'
class siege_utilities.reporting.pages.page_models.Argument[source]

Bases: object

Atomic report unit: headline → narrative → table → visualization(s).

layout is auto-resolved in __post_init__:
  • map_figure present → “full_width” (stacked: title / table / figure)

  • map_figure absent → “side_by_side” (title top, table left, figure right)

headline: str
narrative: str
table: Any
table_type: TableType
chart: Any | None = None
map_figure: Any | None = None
layout: str = 'auto'
base_note: str | None = None
source_note: str | None = None
tags: List[str]
__init__(headline, narrative, table, table_type, chart=None, map_figure=None, layout='auto', base_note=None, source_note=None, tags=<factory>)
Parameters:
Return type:

None

class siege_utilities.reporting.pages.page_models.Page[source]

Bases: ABC

Abstract base class for all report pages

__init__(primary_color, secondary_color, accent_color)[source]
abstractmethod build()[source]

Build the page content

add_spacer(height)[source]

Add spacing to the page

add_paragraph(text, style)[source]

Add a paragraph to the page

add_page_break()[source]

Add a page break

get_content()[source]

Get the complete page content

class siege_utilities.reporting.pages.page_models.TitlePage[source]

Bases: Page

Title page implementation

__init__(primary_color, secondary_color, accent_color, client_name, client_url, prepared_by, report_type='ANALYTICS REPORT', tagline='', phone=None)[source]
Parameters:
  • report_type (str)

  • tagline (str)

  • phone (str | None)

create_blue_bar_style()[source]

Create the blue header bar style

create_title_style()[source]

Create the main title style

create_tagline_style()[source]

Create the tagline style

create_details_style()[source]

Create the details style

build(start_date, end_date)[source]

Build the complete title page

class siege_utilities.reporting.pages.page_models.TableOfContentsPage[source]

Bases: Page

Table of contents page implementation

__init__(primary_color, secondary_color, accent_color)[source]
create_header_style()[source]

Create the TOC header style

create_section_style()[source]

Create the TOC section style

create_item_style()[source]

Create the TOC item style

build(toc_data)[source]

Build the table of contents page.

Parameters:

toc_data (List[Dict]) – list of dicts with keys ‘section’, ‘title’, and optional ‘page_num’

class siege_utilities.reporting.pages.page_models.ContentPage[source]

Bases: Page

Base class for content pages (sections, charts, tables)

__init__(primary_color, secondary_color, accent_color)[source]
create_section_header_style()[source]

Create section header style

create_subsection_header_style()[source]

Create subsection header style