Saving & export¶
Ferrum charts render to SVG, PNG, HTML, and JSON — no system dependencies, no display server, no matplotlib. Every chart object (base charts, compound views, helper output, diagnostic charts) supports the same export surface.
Output formats¶
| Format | Method | File extension | Notes |
|---|---|---|---|
| SVG | .show_svg() |
.svg |
Vector graphics. Default render path. |
| PNG | .show_png() |
.png |
Rasterized via resvg in Rust. No Cairo/Pillow needed. |
| HTML | .save("out.html") |
.html |
Self-contained interactive page with inlined WASM renderer. |
| JSON | .save("out.json") |
.json |
Chart spec as JSON — the same format as .to_json(). |
Saving to disk¶
.save() infers the format from the file extension:
import ferrum as fm
import polars as pl
df = pl.DataFrame({"x": [1.0, 2.0, 3.0], "y": [2.0, 4.0, 3.0]})
chart = fm.Chart(df).mark_point().encode(x="x", y="y")
chart.save("scatter.svg") # vector
chart.save("scatter.png") # raster
chart.save("scatter.html") # interactive (WASM inlined)
chart.save("scatter.json") # spec
Pass format= explicitly to override the extension:
Controlling auto-raster¶
At high mark counts (default threshold: 500,000), Ferrum transparently substitutes a raster image for per-element SVG marks. Override this per-call with raster=:
chart.show_svg(raster=False) # force vector even at high counts
chart.save("out.svg", raster=False)
chart.show_png(raster=True) # force raster even at low counts
For persistent control, attach a RenderConfig to the chart:
from ferrum import RenderConfig
config = RenderConfig(raster_threshold=1_000_000, raster_behavior="silent")
chart = chart.render_config(config)
chart.save("out.svg") # auto-raster fires at 1M marks, silently
RenderConfig parameters: raster_threshold (mark count or None to disable), raster_behavior ("warn", "silent", "error"), raster_aggregate, and raster_cmap.
Getting raw bytes¶
For programmatic use (embedding in notebooks, serving from a web app, writing to S3):
svg_str = chart.show_svg() # str — complete <svg>…</svg> document
png_bytes = chart.show_png() # bytes — raw PNG data
Displaying in Jupyter¶
In a Jupyter notebook, charts render automatically via _repr_svg_ — just put the chart as the last expression in a cell:
For interactive rendering (selections, zoom/pan), call .interactive() instead — see Interactive rendering.
Outside of a notebook, .show() writes a temporary SVG and opens it in the system browser.
HTML export¶
.save("file.html") produces a self-contained HTML file with the WASM GPU renderer and scene data inlined. No server, no CDN, no external dependencies — the file works offline in any modern browser.
This is the right format for sharing interactive charts via email, Slack, or static hosting.
Compound views¶
All composition operators produce objects with the same export surface. A four-panel report saves exactly like a single chart:
report = (roc | calibration) & (confusion | residuals)
report.save("model_report.svg")
report.save("model_report.png")
No system dependencies¶
Ferrum's rendering pipeline is pure Rust. SVG rendering, PNG rasterization (resvg), and WASM compilation all happen inside the wheel. There is no dependency on Cairo, X11, Ghostscript, or any display server. pip install ferrum is the entire setup — charts render in Kubernetes, CI, SSH sessions, and headless containers.
Where to go next¶
- First plot for a quick start with rendering.
- Themes for controlling the visual style of exported charts.
- Interactive rendering for WASM-based interactive output.
- Composition for building multi-panel views before export.