Skip to main content
A Python Panel is a dashboard widget whose contents you write yourself in Python. You write a short Streamlit script using pandas, matplotlib, seaborn or plotly, preview it against the runs selected in the UI, and save it alongside your charts and media widgets. Panels run entirely in your browser. The script executes in a sandboxed WebAssembly Python runtime (stlite, which is Streamlit on Pyodide). The server never runs panel code.

Writing a panel

Open a custom dashboard, click Edit Dashboard, then Add Widget and choose Python Panel. The editor shows your code on the left and a live preview on the right.
  • Run (or Cmd/Ctrl+Enter) executes the draft. Nothing runs as you type.
  • The first run boots the Python runtime, which takes 10–30 seconds. Later runs reuse it and take about 2 seconds. Changing the Packages list starts a fresh runtime.
  • Save becomes available after one successful run. It stores the code in the dashboard’s configuration.
  • The Templates menu has six starter panels: a metric line chart, a run comparison table, a correlation heatmap, per-run subplots, a logs viewer and a leaderboard. Picking one replaces your draft code and packages, and asks first if you have unsaved edits.

Reading run data

Panels read your data through the built-in mlop module. All of its data methods are async, so call them with await. Top-level await works in panel scripts. Run ids are the short string ids you see in URLs. A failed call raises mlop.MlopError with a code of FORBIDDEN_METHOD, BAD_PARAMS, UPSTREAM or TIMEOUT (each call times out after 60 seconds). Parameters outside the limits are rejected, never truncated.

Packages

These packages are always available:
  • Preinstalled: numpy, pandas, pillow, altair and their dependencies.
  • Add through the Packages field: matplotlib, seaborn (which pulls in matplotlib) and plotly. Up to 20 entries.
There is no PyPI access. The sandbox blocks all network access except Pluto’s own bundled packages, which is also why panels work unchanged on self-hosted and air-gapped deployments. Requesting any other package fails at install time with a clear error.

Security

  • A panel runs in a sandboxed iframe with no access to your cookies, browser storage or the surrounding page, and no network access.
  • Data reaches the panel only through the mlop calls above. Pluto runs each one as a read-only query under your own session, scoped to the organization and project you are viewing. A panel can never read data you couldn’t already see, and can never change anything.
  • Panels on a shared dashboard run in each viewer’s browser with that viewer’s access. Treat panel code like any other dashboard content: review a panel’s code before relying on it.

Panels on the dashboard

  • Panels load when scrolled into view, with progress shown while the runtime loads, packages install and the script runs.
  • When you change the selected runs:
    • with Re-run automatically when the selected runs change enabled, the panel re-runs about half a second after you stop clicking;
    • otherwise it keeps showing its last result and displays a Runs changed — Refresh button.
  • Fullscreen keeps the panel running, so it doesn’t restart. Press Esc or the button again to exit.
  • Panels follow the app’s light/dark theme. Switching theme restarts each panel, which takes about 10 seconds.

Limitations

  • Data calls must be awaited. Wrapping them in an ordinary synchronous function won’t work; use top-level await or an async def.
  • matplotlib and seaborn figures are static images (st.pyplot). For interactive charts use st.plotly_chart, st.line_chart or Altair.
  • Startup time: the first render takes 10–30 seconds; later reruns take about 2 seconds. The browser caches the runtime after the first panel you load.
  • Memory: each panel is its own Python runtime of about 100–200 MB, so keep the number of panels on one dashboard modest.
  • Fixed package set: only the packages listed above.
  • Size: code is limited to 64 KB per panel.
  • AI assistants read panels as code. The MCP dashboard tools return a panel’s source rather than an image of its output, because rendering it would mean running your Python on the server.