Report Features¶
Beyond basic save_report(), Data In Pane offers several options for customizing the output.
Offline Mode¶
Bundle all JavaScript and CSS inline for fully self-contained HTML that works without an internet connection:
The first call fetches assets from the CDN and caches them in ~/.cache/datainpane/cdn/. Subsequent calls are instant. Google Fonts are replaced with system font fallbacks.
Table of Contents¶
Generate a fixed sidebar from Page titles and Group labels:
view = dip.Blocks(
dip.Page(dip.Text("# Intro"), title="Introduction"),
dip.Page(dip.DataTable(df), title="Data"),
)
dip.save_report(view, path="report.html", toc=True)
The TOC appears as a fixed sidebar on the left with smooth-scroll navigation.
Header and Footer¶
Add branding to the top and bottom of reports:
fmt = dip.Formatting(
header="<strong>ACME Corp</strong> — Monthly Report",
footer="Generated by Data In Pane · Confidential",
)
dip.save_report(view, path="report.html", formatting=fmt)
Headers and footers accept raw HTML, so you can include logos:
Dark Mode Toggle¶
Add a floating button that lets viewers switch between light and dark modes:
fmt = dip.Formatting(dark_mode_toggle=True)
dip.save_report(view, path="report.html", formatting=fmt)
The toggle:
- Persists the viewer's preference via
localStorage - Uses CSS variable overrides (not crude filter hacks) for Callout, Progress, and Diff blocks
- Applies an invert filter to the main report content for broad compatibility
Multi-Page Export¶
Save each Page as a separate HTML file:
view = dip.Blocks(
dip.Page(dip.Text("# Introduction"), title="Introduction"),
dip.Page(dip.DataTable(df), title="Data"),
dip.Page(dip.Plot(chart), title="Charts"),
)
paths = dip.save_report_pages(view, dest="output/", name="Report")
# Creates: output/Report - Introduction.html
# output/Report - Data.html
# output/Report - Charts.html
Report Templates¶
Pre-built layout templates for common patterns:
import datainpane as dip
# Dashboard: BigNumbers on top, charts/tables in grid below
view = dip.templates.dashboard([
dip.BigNumber(heading="Users", value="10k"),
dip.BigNumber(heading="Revenue", value="$1.2M"),
dip.Plot(chart),
dip.DataTable(df),
])
# Titled pages: split blocks into pages at # headings
view = dip.templates.titled_pages([
dip.Text("# Overview"),
dip.DataTable(df),
dip.Text("# Analysis"),
dip.Plot(chart),
])
# Descriptive pages: new page at each text→non-text boundary
view = dip.templates.descriptive_pages([...])
Hiding Altair Action Menus¶
Remove the "View Source", "Save as PNG", etc. menu from Altair/Vega charts:
Table Cell Limit¶
By default, DataFrames with more than 250 cells are auto-wrapped as DataTable (interactive, searchable) instead of Table (static HTML). Override:
Custom CSS¶
Inject arbitrary CSS via the custom_css parameter on Formatting:
fmt = dip.Formatting(custom_css="""
/* Reduce spacing between blocks */
.group > * { margin-bottom: 4px; }
/* Remove scrollbar from DataTables */
[data-cy=block-datatable] { overflow: hidden; max-height: none; }
/* Limit report height with scroll */
#report { max-height: 80vh; overflow-y: auto; }
""")
Matplotlib DPI and Cropping¶
Control matplotlib rendering with scale (DPI multiplier) and savefig_kw:
dip.Plot(fig, scale=2.0) # 2x DPI for high-res output
dip.Plot(fig, savefig_kw={"dpi": 150, "pad_inches": 0.5})
tight_layout() is called automatically before saving to prevent cropping on multi-axes figures.