Quick start¶
Installation¶
# Core only
pip install montin
# Adds Markdown rendering + WebP image conversion
pip install "montin[full]"
Charts and tables use libraries you already have — add_plotly needs plotly,
add_table(df) / add_matplotlib need pandas / matplotlib. Since you create
those objects yourself, install them as you normally would; Montin doesn’t pin
them.
Basic structure¶
Every report follows the same pattern:
import plotly.express as px
from montin import Deck, Plugins
# 1. Create the deck
deck = Deck(
title="Q2 Report",
author="A. Dessimoni",
plugins=[Plugins.Plotly(), Plugins.Mermaid()],
)
# 2. Add slides
deck = Deck(title="Template Report", autosave='example',
autosave_level='cell', plugins=[Plugins.Mermaid(), Plugins.Plotly()])
# Trend chart + breakdown table
slide = deck.add_slide("Trends", nrows=1, ncols=2)
df = px.data.stocks()
fig = px.line(df, x="date", y=["GOOG", "AAPL"])
slide.add_plotly(fig, caption="Weekly close price")
slide.add_table({
"Component": ["Motor A", "Motor B", "Pump C", "Valve D"],
"Status": ["OK", "OK", "Warning", "OK"],
"Uptime (%)": [99.1, 97.8, 91.3, 98.6],
})
# KPIs + pipeline diagram
slide = deck.add_slide("Overview", nrows=2, ncols=3)
slide.add_metric(value=98.7, label="Efficiency (%)", delta=+2.3, delta_label="vs Q1")
slide.add_metric(value=142, label="Incidents", delta=-18, lower_is_better=True)
slide.add_metric(value="4.8 s", label="Avg response time")
slide.add_mermaid("""
gantt
title A Gantt Diagram
dateFormat YYYY-MM-DD
section Section
A task :a1, 2014-01-01, 30d
Another task :after a1, 20d
section Another
Task in Another :2014-01-12, 12d
another task :24d
""", colspan=2, row=2, col=1)
# 3. Generate the file
deck.write("report", open_browser=True)
This generates report.html — a single file with no external dependencies.
For a better view, click the ⛶ Fullscreen (F) button on the bottom toolbar.
Cell grid¶
Each slide has a CSS Grid canvas of nrows x ncols. Cells are positioned
automatically from left to right, top to bottom.
slide = deck.add_slide("Example", nrows=2, ncols=3)
# Spans columns 1 and 2 of row 1
slide.add_text("Wide text", colspan=2)
# Column 3 of row 1
slide.add_metric(value=42, label="KPI")
# Row 2, spans all 3 columns
slide.add_table(csv_data, colspan=3)
To position manually:
slide.add_image("photo.png", col=2, row=1, rowspan=2)
Preview in a notebook¶
In Jupyter, return a deck, slide, or cell as a cell’s last expression to render it inline — no file written. A single slide doubles as a layout for cell outputs: drop a few cells on its grid and display it.
slide = deck.add_slide("Run 42", nrows=1, ncols=2)
slide.add_metric(value=0.94, label="Accuracy", delta=+0.02)
slide.add_plotly(fig)
slide # renders a laid-out mini-dashboard as the cell output
See Live editing for more.
Plugins¶
Some cell types require a plugin, declared via the Plugins container and passed
to Deck(plugins=[...]). Nothing is mandatory — declare only what you use.
Plugin |
Cells |
|---|---|
|
|
|
|
|
|
|
LaTeX in |
Each loads from a CDN by default; pass source="bundled" (or
Deck(plugin_source="bundled")) to embed them for a fully offline file. See
Plugins and Security & offline use for details.
Common cell options¶
All add_* methods accept:
Parameter |
Type |
Description |
|---|---|---|
|
|
Number of columns spanned |
|
|
Number of rows spanned |
|
|
Manual position (1-indexed) |
|
|
Caption below the cell |
|
|
Internal scroll when content overflows |
|
|
Button to expand cell to full screen |
|
|
Button to copy cell content |
|
|
Hide border and background |
|
|
Horizontal alignment of cell content |
|
|
Vertical alignment of cell content |
|
|
Multiplier for this cell’s text size (composes on top of the deck’s |
Global defaults¶
Use CellDefaults and SlideDefaults to avoid repetition:
deck = Deck(
title="...",
slide_defaults=SlideDefaults(nrows=2, ncols=2),
cell_defaults=CellDefaults(
expand_button=True,
overflow=True,
transparent=False,
halign="center",
valign="middle",
fontscale=1.0,
),
)
Font scaling¶
Scale text without editing each cell or writing custom CSS:
Deck(fontsize_scale=…)multiplies every font in the presentation — slide content and the navigation chrome (sidebar, toolbar, TOC, lightbox). Spacing and layout are unaffected.fontscale(per cell, or as aCellDefaultsdefault) scales a single cell’s text and composes on top offontsize_scale.
deck = Deck(title="Report", fontsize_scale=1.2) # everything 20% larger
slide.add_text("Headline", fontscale=1.5) # this cell: 1.2 × 1.5
Fixed-size slides¶
By default the layout is fluid and fills the browser window. Pass size to
pin slides to fixed pixel dimensions instead. The slide becomes a stage that
is scaled with a CSS transform to fit the available space — fonts, images, and
layout all scale together, so the result behaves like a static PDF page.
deck = Deck(
title="Report",
size=(1366, 768), # 16:9 stage in pixels
scale_up=False, # don't grow past 1:1 on large screens (default)
keep_aspect_ratio=True, # uniform scale + letterbox (default)
)
Option |
Effect |
|---|---|
|
Enables fixed-size mode. |
|
Allow the stage to grow beyond its native size to fill larger windows |
|
Stretch to fill both dimensions independently (distorts content) |
This is also the recommended mode for embedding a deck in an <iframe>, since
the slide keeps a predictable aspect ratio regardless of the frame size.
Single-slide / embeddable files¶
For a clean, minimal file — such as the slides embedded throughout this documentation — hide the navigation sidebar and/or the bottom toolbar:
deck = Deck(
title="Demo",
size=(960, 540),
show_sidebar=False,
show_toolbar=False,
)
deck.add_slide("Just this slide").add_text("No chrome around me.")
With both hidden the slide fills the whole frame. Combine with size for a
fixed aspect ratio that embeds cleanly in an <iframe>.
To keep the sidebar available but out of the way, start it collapsed instead of
hiding it — it can still be toggled open with the toolbar button or the B key:
deck = Deck(title="Report", sidebar_collapsed=True)