Skip to content

mineproductivity.visualization

Auto-generated API reference for the Visualization package, rendered from the package's own docstrings. For the narrative overview, dependency rules, and extension guide, see Packages -> Visualization.

visualization

mineproductivity.visualization -- the presentation layer (design spec 12): the final package in the platform's architecture, built directly above agents. Defines what is shown (Visualization/PresentationModel), where it lives (Widget/Dashboard/Layout/Theme), and how rendering is orchestrated (RenderingPipeline/Report/Export) -- Visualization and Renderer are interface-only extension points; choosing a charting, templating, or document-generation backend is exactly the implementation decision this package excludes (§3.1, §4).

Public API (design spec §7) -- every name stable once implementation begins.

Visualization

Bases: ABC

The root of every registrable visualization type (design spec §8) -- the eighth package-defining "as-object" root in this series, whose category members (§26) are presentation roles rather than algorithmic paradigms.

Statelessness. Every subclass, of every category, is stateless -- no instance attribute is mutated by any _render implementation (§26, §29); statefulness lives entirely in Dashboard (§10), so the same registered Visualization type can back many concurrent Widget\ s safely.

Qualify, don't coerce (§30): no _render implementation raises for a legitimately incomplete widget binding or empty evidence -- it returns a PresentationModel carrying a warning instead.

VisualizationCategory

Bases: Enum

Closed enum -- adding a member is a governance-reviewed change, mirroring agents.AgentCategory's closed-enum rule (spec 11 §29): four general-purpose presentation shapes and four domain-specific views (design spec §17, §26).

VisualizationContext

VisualizationContext(*, kpi_results=(), analytics_results=(), decision_results=(), twin_snapshot=None, simulation_results=(), optimization_results=(), agent_audit_entries=())

Bundles the evidence a Visualization may need (design spec §8) -- carried once, at construction; this package renders exactly what the caller already assembled and never fetches additional evidence on its own initiative (§31).

Examples:

>>> context = VisualizationContext()
>>> context.kpi_results
()
>>> context.twin_snapshot is None
True

VisualizationMetadata dataclass

VisualizationMetadata(code, *, name='', description, tags=frozenset(), attributes=dict(), category, version='1.0.0')

Bases: BaseMetadata

The minimal registration schema for a discoverable Visualization type (design spec §26). code names a type (e.g. "KPI_CARD.Standard"), never a Widget.code.

Examples:

>>> meta = VisualizationMetadata(
...     code="KPI_CARD.Standard",
...     category=VisualizationCategory.KPI_CARD,
...     description="A single-KPI headline card.",
... )
>>> meta.name
'KPI_CARD.Standard'

Dashboard dataclass

Dashboard(id, name, owner, *, widgets=(), layout=None, theme_code='')

Bases: BaseEntity[str]

The root of one saved, editable presentation configuration -- 'Dashboard-as-entity' (design spec §10). Immutable; trivially safe to read and share across threads (§29). Two dashboards sharing the same name under different owner\ s are never in conflict -- id, not name, is the identity DashboardRepository keys on (§23).

Examples:

>>> dashboard = Dashboard(id="DASH-1", name="Night Shift Handover", owner="supervisor-a")
>>> dashboard.widgets
()
>>> import dataclasses as dc
>>> dc.replace(dashboard, theme_code="DARK_HIGH_CONTRAST").theme_code
'DARK_HIGH_CONTRAST'
>>> dashboard.theme_code  # the original instance is untouched
''

validate

validate()

Design spec §25: non-empty name and owner.

DashboardBuilder

DashboardBuilder(*, owner)

Bases: BaseBuilder[Dashboard]

Accumulates widgets, layout, and theme choices, then produces a Dashboard via :meth:build (design spec §12).

Examples:

>>> dashboard = (
...     DashboardBuilder(owner="supervisor-a")
...     .with_name("Night Shift Handover")
...     .with_theme("DARK_HIGH_CONTRAST")
...     .build()
... )
>>> dashboard.name
'Night Shift Handover'

reset

reset()

Clear every accumulated step (owner is kept -- it is the builder's construction-time identity, not an accumulated step), per core.BaseBuilder.reset()'s own contract.

build

build()

Construct the final Dashboard.

Raises:

Type Description
VisualizationValidationError

For an empty name or owner (design spec §12) -- the incomplete-state failure core.BaseBuilder.build()'s own docstring anticipates.

DashboardNotFoundError

DashboardNotFoundError(message, *, details=None)

Bases: NotFoundError

DashboardRepository.get(dashboard_id) found no dashboard for that id, or REGISTRY.get(code)/RENDERERS.get(code) found no registered type for that code (design spec §6).

RenderingError

RenderingError(message, *, details=None)

Bases: MineProductivityError

RenderingPipeline raised for a step that should have been structurally valid -- distinct from a legitimately-incomplete widget binding (design spec §30's 'qualify, don't coerce' rule), which returns a PresentationModel/RenderedOutput carrying a warning instead of raising.

VisualizationValidationError

VisualizationValidationError(message, *, details=None)

Bases: ValidationError

A VisualizationMetadata, Dashboard, Widget, or Layout failed validation (design spec §26, §10) -- e.g. an empty code, a Widget with no bound visualization_code, or a Layout with no slots.

VisualizationVersionConflictError

VisualizationVersionConflictError(message, *, details=None)

Bases: RegistrationError

A plugin attempted to re-register an existing Visualization or Renderer type code with materially different metadata without a version bump, mirroring agents.AgentVersionConflictError's identical reasoning (spec 11 §6).

ExportRequest dataclass

ExportRequest(renderer_code, *, dashboard_id=None, report=None)

Bases: BaseValueObject

A request to convert a Dashboard's current rendering or an already-built Report into a single downloadable artifact (design spec §18).

Examples:

>>> ExportRequest(renderer_code="PDF.Standard", dashboard_id="DASH-1").renderer_code
'PDF.Standard'

ExportResult dataclass

ExportResult(format, payload, exported_at)

Bases: BaseValueObject

The outcome of one export request (design spec §18).

Examples:

>>> from datetime import timezone
>>> ExportResult(
...     format="pdf", payload=b"%PDF",
...     exported_at=datetime(2026, 7, 6, tzinfo=timezone.utc),
... ).format
'pdf'

Layout dataclass

Layout(code, *, slots=dict())

Bases: BaseValueObject

Maps each Widget.code to an opaque position spec (a CSS grid area, a terminal row/column pair, a PDF page region) a concrete Renderer interprets entirely on its own (design spec §10, §16).

Examples:

>>> Layout(code="handover_grid", slots={"tph_card": "row=1;col=1"}).slots["tph_card"]
'row=1;col=1'

RenderingPipeline

RenderingPipeline(*, registry, renderers)

Resolves widget.visualization_code against the composed visualization registry, dispatches to the registered Visualization's _render, then resolves renderer_code against the composed renderer registry and hands the resulting PresentationModel to that Renderer's render (design spec §11's sequence diagram). Composes the two registries (§20) directly -- no bespoke lookup mechanism of its own. Carries no shared mutable state across calls: independent widget renders execute fully in parallel (§29).

render

render(widget, *, context, renderer_code)

Render widget end to end. A widget bound to incomplete or not-yet-computed evidence flows through as a warning-carrying model/output, never a raise (design spec §30).

Raises:

Type Description
DashboardNotFoundError

If no Visualization is registered for widget.visualization_code, or no Renderer for renderer_code.

RenderingError

If the dispatched _render/render raised for a structurally valid input (design spec §30).

PresentationModel dataclass

PresentationModel(category, title, *, series=dict(), evidence_refs=(), warnings=())

Bases: BaseValueObject

What should be shown -- series, labels, category hint, evidence references -- without committing to any concrete medium (design spec §9). series is an open Mapping[str, Any], since one category's data shape (a Pareto front's two axes; a timeline's ordered events) varies far more than a lower package's own result shapes do.

Examples:

>>> model = PresentationModel(
...     category=VisualizationCategory.KPI_CARD,
...     title="Tonnes per hour",
...     series={"value": 1212.1},
...     evidence_refs=("PROD.TPH",),
... )
>>> model.series["value"]
1212.1

RenderedOutput dataclass

RenderedOutput(format, payload, *, warnings=())

Bases: BaseValueObject

A record of one Renderer.render() call and its result (design spec §16).

Examples:

>>> RenderedOutput(format="html", payload="<div>1212.1</div>").format
'html'

Renderer

Bases: ABC

The contract a future rendering-backend plugin implements (an HTML renderer, a PDF renderer, a terminal renderer). THIS MODULE SHIPS NO CONCRETE SUBCLASS -- choosing a specific charting or document-generation library is exactly the kind of implementation decision this package's charter (design spec §3.1, §3.5, §4) excludes.

render abstractmethod

render(model, *, context)

Convert model into this renderer's concrete medium. A legitimately incomplete model surfaces as a warning-carrying RenderedOutput, never a raise (design spec §30).

RendererMetadata dataclass

RendererMetadata(code, *, name='', description, tags=frozenset(), attributes=dict(), version='1.0.0')

Bases: BaseMetadata

The minimal registration schema for a discoverable Renderer type -- as light as agents.ToolMetadata (spec 11 §17).

Examples:

>>> meta = RendererMetadata(code="HTML.Standard", description="Renders to HTML.")
>>> meta.name
'HTML.Standard'

Report dataclass

Report(report_code, generated_at, *, sections=(), warnings=())

Bases: BaseValueObject

An ordered set of fully-rendered sections as one exportable artifact -- sections are RenderedOutput\ s, never raw PresentationModel\ s: a Report is, by definition, the finished document a human reads or downloads (design spec §13).

Examples:

>>> from datetime import timezone
>>> report = Report(
...     report_code="SHIFT.Handover.2026-07-06",
...     generated_at=datetime(2026, 7, 6, tzinfo=timezone.utc),
... )
>>> report.sections
()

ReportBuilder

ReportBuilder(*, report_code, pipeline)

Bases: BaseBuilder[Report]

Accumulates rendered sections -- each produced by an actual RenderingPipeline.render call, never a re-implementation of it -- then assembles the final Report via :meth:build (design spec §14). A section that produced a warning-carrying RenderedOutput has that warning preserved on the final Report.warnings, never silently dropped (§30).

with_section

with_section(widget, *, context, renderer_code)

Render one section now, via the composed pipeline, and append it (design spec §14).

reset

reset()

Clear every accumulated section (report_code and the composed pipeline are the builder's construction-time identity, not accumulated steps), per core.BaseBuilder.reset()'s own contract.

build

build()

Assemble the final Report from the sections rendered so far, carrying every section warning forward.

Theme dataclass

Theme(code, *, palette=dict(), typography=dict())

Bases: BaseValueObject

A small, named visual styling configuration. palette/ typography are renderer-interpreted open mappings, never a typed per-property schema (design spec §21).

Examples:

>>> Theme(code="DARK_HIGH_CONTRAST", palette={"background": "#000"}).code
'DARK_HIGH_CONTRAST'

Widget dataclass

Widget(code, visualization_code, *, binding=dict())

Bases: BaseValueObject

One bound unit of presentation. binding is an open Mapping[str, str] naming which evidence this widget reads (e.g. {"kpi_code": "PROD.TPH", "scope": "site=Karara"}) -- never a typed reference (design spec §10), and never interpreted by this package's own code on a Renderer's behalf (§16).

Examples:

>>> Widget(
...     code="tph_card", visualization_code="KPI_CARD.Standard",
...     binding={"kpi_code": "PROD.TPH"},
... ).binding["kpi_code"]
'PROD.TPH'

register

register(cls)

Register cls into :data:REGISTRY, keyed by cls.meta.code.

Raises:

Type Description
VisualizationValidationError

If cls.meta.code is empty (defensive, redundant guard -- VisualizationMetadata.validate() already rejects it).

VisualizationVersionConflictError

If cls.meta.code is already registered -- add-only, raised at registration time, never deferred (design spec §23).

register_renderer

register_renderer(cls)

Register cls into :data:RENDERERS, keyed by cls.meta.code -- identical shape and identical error semantics as :func:register, specialized for Renderer (design spec §20).

Raises:

Type Description
VisualizationValidationError

If cls.meta.code is empty.

VisualizationVersionConflictError

If cls.meta.code is already registered in :data:RENDERERS.

by_owner

by_owner(owner)

A specification satisfied by every dashboard owned by owner -- a convenience query only, never an access-control boundary (design spec §31).

Examples:

>>> from mineproductivity.core import InMemoryRepository
>>> repository: InMemoryRepository[Dashboard, str] = InMemoryRepository()
>>> repository.list(by_owner("supervisor-a"))
[]

by_theme

by_theme(theme_code)

A specification satisfied by every dashboard referencing theme_code -- compose with DashboardRepository.list() freely; an empty result is a legitimate answer, never a raise (design spec §27).

Examples:

>>> from mineproductivity.core import InMemoryRepository
>>> repository: InMemoryRepository[Dashboard, str] = InMemoryRepository()
>>> repository.list(by_theme("DARK_HIGH_CONTRAST"))
[]