Clean Room

Beta Access — Clean Room is currently in beta and not yet generally available. To request early access, email [email protected]envelope.

Python only — Clean Room currently supports Python. R support is coming soon.

Overview

Clean Room turns a Python function into a self-contained, reproducible, interactive application. You decorate a function with @reproducible, and GoFigr draws a clean boundary around it: the function can only access the variables you pass in, the packages you declare, and nothing else. When the function produces a figure, everything—code, data, parameters, environment—is captured and published automatically.

The workflow:

  1. Explore — work however you normally work in Jupyter

  2. Distill — pull the core logic into a @reproducible function

  3. Run — call the function; GoFigr captures everything automatically

  4. Share — send a link; stakeholders interact with the figure in the browser

Quick Start

Load the GoFigr extension and configure it:

%load_ext gofigr
# configure() # only needed if overriding defaults

The %load_ext gofigr magic injects reproducible, SliderParam, DropdownParam, and other names into your notebook namespace.

Simplest Example

That's it. When the function runs, GoFigr captures:

  • Source code — the function body, extracted from the notebook cell

  • Parameters — types, defaults, and values for every argument

  • Data — DataFrames passed as arguments, serialized alongside the revision

  • Environment — package names and versions, Python version

  • Output — the figures produced by the run

Interactive Mode

Add interactive=True to render parameter widgets directly in Jupyter. Changing a widget re-runs the function immediately.

Requires the anywidget package and its JupyterLab frontend extension:

After installing, fully restart JupyterLab (not just the kernel) and hard-reload the browser so the frontend extension registers. If widgets still don't render, run the built-in health check:

This verifies the Python package, traitlets, the Jupyter kernel, and prints guidance for fixing the frontend extension.

Full Example

In Jupyter, this renders sliders, dropdowns, a checkbox, and a text input above the figure. Adjusting any control re-executes the function and updates the plot.

Parameter Widgets

GoFigr maps Python types to interactive controls. You can rely on auto-inference or use explicit Param classes for more control.

Auto-Inference

Default value type
Widget
Example

int or float

Slider

bins: int = 20

bool

Checkbox

show_grid: bool = True

str

Text input

title: str = "My Chart"

Literal[...] type hint

Dropdown

mode: Literal["a", "b"] = "a"

pd.DataFrame

Static (read-only)

Passed at call time

SliderParam

Numeric slider with explicit bounds.

If you omit bounds, they are resolved automatically:

int

float

min

0

0

max

max(value * 2, 100)

max(value * 2, 1.0)

step

1

0.1

Categorical dropdown with explicit choices.

You can also use a Literal type hint to create a dropdown automatically without DropdownParam:

CheckboxParam

Boolean toggle. Auto-inferred for bool defaults—you rarely need this explicitly.

TextParam

Free-form text input. Auto-inferred for str defaults.

StaticParam

For DataFrames and other complex objects. Read-only in interactive mode—no widget is rendered. The value is available in the Clean Room studio for inspection.

Custom Packages

By default, the clean room environment includes:

Alias
Package

pd

pandas

np

numpy

plt

matplotlib.pyplot

sns

seaborn

Adding Packages

Use the packages argument to add more. By default, your packages are merged with the defaults:

Replacing Default Packages

Set merge_packages=False to use only the packages you specify:

Global Package Configuration

To change defaults for all @reproducible functions in a session:

Publishing

Automatic Capture (Jupyter)

With configure(auto_publish=True) (the default), figures are published automatically when a @reproducible function runs. No extra code needed.

Explicit Publishing

For more control, use the publisher argument and call publish() inside the function:

The publish() function is injected into the clean room globals when a publisher is provided.

What Gets Stored

Each published revision includes:

  • Source code — the function body

  • Manifest — JSON with parameter types, widget config, imports, and package versions

  • DataFrame parameters — serialized as Parquet

  • Revision flag — marks the revision as a Clean Room revision

Nested Calls

Each @reproducible call gets its own context. If you nest @reproducible functions, the innermost context wins for publish(). The context is reset after the function returns or raises an exception.

Edge Cases and Caveats

Clean room isolation — The function cannot access module-level variables from your notebook. Only declared packages, builtins, and function arguments are available. This is by design: it ensures the function is self-contained and reproducible.

DataFrames are copied — DataFrame arguments are round-tripped through Parquet serialization. The function receives a deserialized copy, not the original object. This ensures the clean room version matches what gets stored.

100 MB limit — Total DataFrame size (estimated via memory_usage(deep=True)) must be under 100 MB. If exceeded, a warning is issued and clean room is skipped—the function still runs normally but without isolation or capture.

Unsupported parameter types — Custom objects, numpy arrays, and lambdas cannot be serialized. If detected, a warning is issued and the function falls back to direct execution (no clean room).

interactive=True outside Jupyter — A warning is issued and the function runs non-interactively.

plt.show() auto-called — If matplotlib figures exist after execution, plt.show() is called automatically. You don't need to call it yourself.

Source code extraction — The function must be defined in importable source (a notebook cell or .py file). Dynamically created functions (e.g., via exec) are not supported.

Return values — In non-interactive mode, the function's return value is returned normally. In interactive mode, the return value is None (the output is rendered in the widget).

Usage in Scripts

Clean Room works outside Jupyter with a few differences:

  • No interactive modeinteractive=True is ignored (with a warning)

  • No automatic capture — you must use the publisher argument explicitly

  • Explicit imports — import from gofigr.reproducible instead of relying on the %load_ext magic

Last updated