Skip to main content

Browser capture & custom renderer pipeline for Plotly Dash components

Project description

PyPI Python License Plotly Dash Ruff uv ty prek

dash-capture

Plotly figures in Dash are rendered by JavaScript in the browser — the Python server never holds the chart as pixels. dash-capture bridges this gap by triggering the capture directly in the running browser, with no server-side headless browser (Chrome, Playwright, webshot2) required. The result is delivered to Python for post-processing, custom rendering, and download.

Installation

pip install dash-capture

Optional extras for built-in decoration renderers:

pip install 'dash-capture[pil]'   # bordered / titled / watermarked

Usage

Default — one-line wizard, no setup

from dash_capture import capture_graph

# Returns an html.Div — place it next to your dcc.Graph
capture_graph("my-graph", trigger="Export")

The default renderer is a zero-dependency passthrough: the wizard shows just Generate + Download. Clicking the trigger opens a modal with the live preview and a PNG / JPEG / SVG download.

Plotly chart capture

from dash_capture import capture_graph, plotly_strategy

capture_graph(
    "my-graph",
    trigger="Export",
    strategy=plotly_strategy(
        strip_title=True,
        strip_legend=True,
        strip_margin=True,
        format="png",   # or "jpeg", "webp", "svg"
    ),
)

Strip patches remove chart decorations before capture without touching the live chart.

Any DOM element (table, custom widget) — html2canvas

from dash_capture import capture_element

capture_element("my-data-table", trigger="Capture table")

capture_element defaults to html2canvas_strategy() and works with any Dash component that has an id.

Built-in PIL renderers (dash-capture[pil])

from dash_capture import capture_graph
from dash_capture.pil import titled, bordered, watermarked

# Title bar above the captured chart
capture_graph("my-graph", renderer=titled)

# Colored border
capture_graph("my-graph", renderer=bordered)

# Diagonal watermark
capture_graph("my-graph", renderer=watermarked)

The wizard auto-generates form fields (text input, color picker, dropdown) from each renderer's type hints, so users can edit title, color, width, etc. before downloading.

Custom renderer

Define a function that takes _target (file-like) and _snapshot_img (callable returning raw PNG bytes). Type-hinted parameters become auto-generated form fields in the wizard.

from dash_capture import capture_graph, renderer

@renderer
def my_renderer(_target, _snapshot_img, title: str = "", dpi: int = 150):
    png = _snapshot_img()
    # post-process: add a watermark, corporate frame, etc.
    _target.write(png)

capture_graph("my-graph", renderer=my_renderer)

The @renderer decorator validates the magic parameter names at definition time. A typo like _snaphot_img raises ValueError with a "did you mean ...?" hint instead of silently failing at runtime.

Low-level — wire capture to your own UI

from dash import Input
from dash_capture import capture_binding, plotly_strategy

binding = capture_binding(
    "my-graph",
    strategy=plotly_strategy(strip_title=True),
    trigger=Input("my-btn", "n_clicks"),
)

# Place binding.store in the layout
# React to binding.store_id to get the base64 PNG

Strategies

Strategy Method Use case
plotly_strategy() Plotly.toImage() Plotly charts — exact resolution
html2canvas_strategy() html2canvas Any DOM element (tables, divs)
canvas_strategy() canvas.toDataURL() Raw <canvas> elements

plotly_strategy() accepts strip flags (strip_title, strip_legend, strip_annotations, strip_axis_titles, strip_colorbar, strip_margin) and format. For per-export width / height / scale, declare capture_width: int / capture_height: int / capture_scale: float parameters on your renderer — they get plumbed into Plotly.toImage() automatically.

capture_* parameter resolution

The same capture_width / capture_height / capture_scale magic params work with any strategy that consumes them (plotly_strategy, html2canvas_strategy, dygraph_strategy, …). Three ways to provide values:

How Where the value comes from Use case
Omit (no field_specs, no capture_resolver) The element's current size in the browser Fast, sensible default — works without any config.
fixed(value) in field_specs Inlined as a JS constant Pin a specific export size at import time.
capture_resolver=fn Computed server-side from form fields Drive sizes from user input, with snapshot caching keyed by the resolved options.
from dash_fn_form import fixed
from dash_capture import capture_graph

# (1) Omit — capture at the live element's current size:
capture_graph(graph, renderer=my_renderer)

# (2) fixed — pin an export size:
capture_graph(graph, renderer=my_renderer,
              field_specs={"capture_width": fixed(1200), "capture_height": fixed(600)})

# (3) capture_resolver — drive from form fields:
capture_graph(graph, renderer=my_renderer,
              capture_resolver=lambda width, height, **_:
                  {"capture_width": width, "capture_height": height})

Pre-filling fields from the live figure

FromPlotly reads a value from the running Plotly figure to pre-populate auto-generated form fields:

from dash import dcc
from dash_capture import capture_graph, FromPlotly, renderer

graph = dcc.Graph(id="my-graph", figure=fig)

@renderer
def export(_target, _snapshot_img, title: str = "", sources: str = ""):
    _target.write(_snapshot_img())

capture_graph(
    graph,
    renderer=export,
    field_specs={"title": FromPlotly("layout.title.text", graph)},
)

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dash_capture-0.0.12.tar.gz (339.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dash_capture-0.0.12-py3-none-any.whl (86.5 kB view details)

Uploaded Python 3

File details

Details for the file dash_capture-0.0.12.tar.gz.

File metadata

  • Download URL: dash_capture-0.0.12.tar.gz
  • Upload date:
  • Size: 339.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dash_capture-0.0.12.tar.gz
Algorithm Hash digest
SHA256 372bd6d67286101c0a312a5f05923ab78c6ae288c0b896b8e8d67f5a34d49ffe
MD5 89f808c217c43f096c4d2146ba2c3dfa
BLAKE2b-256 0e4675ccc86704a6ef4ac0a03969cd9d400223de2103505efb75f6ee2cc30d85

See more details on using hashes here.

Provenance

The following attestation bundles were made for dash_capture-0.0.12.tar.gz:

Publisher: publish.yml on saemeon/dash-capture

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dash_capture-0.0.12-py3-none-any.whl.

File metadata

  • Download URL: dash_capture-0.0.12-py3-none-any.whl
  • Upload date:
  • Size: 86.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dash_capture-0.0.12-py3-none-any.whl
Algorithm Hash digest
SHA256 67729ea5bc3acedff1118f90cf70e698a3992557a6052550569b25518f7aa027
MD5 f2bfeb73db7145afeb00610628156c69
BLAKE2b-256 41702a9b4cbf9a34d9a1d7b2165ea6ddf647e8aa7e1e411d62d89bffd0c10f00

See more details on using hashes here.

Provenance

The following attestation bundles were made for dash_capture-0.0.12-py3-none-any.whl:

Publisher: publish.yml on saemeon/dash-capture

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page