-
Notifications
You must be signed in to change notification settings - Fork 0
Report Document
Report composes narrative prose, Reporting Tables, and
Reporting Charts into a single document you can export to
Markdown or HTML. It is a thin orchestrator: tables already know how to render
themselves (to_markdown()), and charts already know how to save themselves
(save()) — Report stitches them together in order and links the generated
assets.
from siamang.reporting import Report # also: from siamang import ReportEvery builder method returns self, so calls chain fluently; save() (or
to_markdown/to_html) is the terminal step.
Report(title: str | None = None, description: str | None = None)title becomes a top-level # H1; description is rendered in italics beneath
it. Both are optional.
Each appends a block and returns self.
| Method | Renders as |
|---|---|
heading(text, level=2) |
## text (level controls the # count). |
markdown(md) |
Raw Markdown, verbatim. |
text(md) |
Alias for markdown. |
note(md) |
> **Note:** md (a blockquote callout). |
value(label, value) |
**label:** value (an inline key figure). |
divider() |
--- (horizontal rule). |
def add(self, component: object, *, caption: str | None = None) -> Report: ...Inserts a SurveyTable (any Reporting Tables type), a
SurveyChart (any Reporting Charts type), or a raw
pandas.DataFrame. The optional caption is rendered in italics above tables
and as both the image alt-text and an italic caption beneath charts. Any other
type raises TypeError.
def image(self, path: str | Path, *, caption: str | None = None) -> Report: ...Inserts an existing image file by path (useful for figures produced outside siamang).
def to_markdown(self, asset_dir: str | Path = ".", *, embed_images: bool = False) -> str: ...Renders the whole document to a Markdown string. Charts are materialized to PNG
files named fig_<index>.png, where <index> is the chart block's position in
the whole document (narrative blocks count too) — so the numbers are ordered
but not consecutive:
- with
embed_images=False(default), each chart is written intoasset_dirand linked by relative filename; - with
embed_images=True, each chart is encoded inline as adata:URI (no files written).
def to_html(self) -> str: ...Renders to HTML (via the markdown library with the tables extension), always
embedding images inline. Requires the markdown package.
def save(self, path: str | Path) -> Path: ...Writes the document, choosing the format from the file suffix: .md/.markdown
(or no suffix) → Markdown with asset_dir set to the file's parent; .html/.htm
→ HTML. A .pdf suffix raises NotImplementedError; any other suffix raises
ValueError. Parent directories are created automatically.
The example assumes the simulated data from Analysis (n=200, seed=123).
from siamang.reporting import Report
report = (
Report(title="Remote Work & Autonomy", description="Pilot wave, Q2 2026")
.heading("Overview")
.text("Perceived autonomy was measured on a 5-point scale.")
.value("Respondents", len(data.frame))
.add(data.report.means("autonomy", by="remote_freq"), caption="Table 1. Mean autonomy by remote frequency")
.add(data.plot.bar("autonomy", by="remote_freq"), caption="Figure 1. Mean autonomy by remote frequency")
.note("Non-consenting respondents were excluded from the base.")
.divider()
)
# Write report.md plus fig_*.png into ./out/
report.save("out/autonomy_report.md")The Markdown begins:
# Remote Work & Autonomy
*Pilot wave, Q2 2026*
## Overview
Perceived autonomy was measured on a 5-point scale.
**Respondents:** 200
*Table 1. Mean autonomy by remote frequency*
| Remote Frequency | Mean | SD | Median | N |
|---|---|---|---|---|
| Never | 3.222 | 1.38 | 4.0 | 45 |
...
> **Note:** Non-consenting respondents were excluded from the base.
@classmethod
def combine(cls, reports: list[Report], *, title: str, toc: bool = True) -> Report: ...Merges several Report objects into one document. Each source report's title
becomes a ## H2 section heading (its description rendered in italics below),
and its blocks are appended in order. With toc=True (default), a Contents
list of anchor links to each section is inserted at the top. This is ideal for a
"run-all" report that concatenates per-analysis sections.
cleaning = Report(title="Data Cleaning", description="prep").text("49 cases dropped.")
tables = Report(title="Final Tables").add(data.report.freq("it_role"))
full = Report.combine([cleaning, tables], title="Full Report")
md = full.to_markdown()
# "# Full Report"
# "## Contents" -> "- [Data Cleaning](#data-cleaning)" / "- [Final Tables](#final-tables)"
# "## Data Cleaning" ... "## Final Tables" ...Section anchors are slugified from the title (lowercased, non-alphanumerics → -),
so "Data Cleaning" links to #data-cleaning.
See also: Reporting Tables · Reporting Charts · Working with Data · Tutorial Full Pipeline
siamang · siamang_cloud · Free for noncommercial use · Commercial licensing · Wiki source: wiki/
Getting started
Survey design
- Variables and Measurement
- Question Types
- Pages Blocks and Structure
- Visibility and Branching
- Quotas
- Scripts
Validate & simulate
Data & analysis
Reporting
Frontend & deploy
Tooling
More
Get started
Account & team
Build & deploy
Data & analysis
Author & configure
Reference