This post demonstrates how to build a “time machine” that lets you easily navigate through different stages of table construction using Great Tables in a marimo notebook.
Building the Time Machine Core
Give It a Sec – WASM Magic Happening
The widgets may take a few moments to load, as they rely on WebAssembly under the hood.
The goal is to create a WigGT object that behaves like a GT object from Great Tables. As we progressively build the table, we maintain two versions:
The original (non-interactive) table
An interactive version that includes a marimo widget (in this case, a slider)
This setup allows us to move back and forth through the table-building steps and see how each method transforms the output — effectively creating a table “time machine.”
First, we need a list of Great Tables methods that should be wrapped and recorded. For now, this list is constructed manually, but ideally, Great Tables could expose this for easier third-party use.
The lazify decorator wraps each method call and stores it in a pipeline. This allows us to defer execution until we’re ready to materialize the final table using .collect(). Only the selected methods from Great Tables will be decorated.
Original tables are stored in self._tables, accessible via the .tables property.
Interactive versions with embedded marimo widgets are stored in self._wtables. These aren’t exposed directly — interaction is done through the marimo UI.
The rendering method follows marimo’s convention, trying _display_, then _repr_html_, and finally _mime_, in that order.
With this setup, WigGT tracks the full transformation pipeline and allows easy replay of each step through a slider.
Now we’re ready to time travel through the table-building process!
Step 1: Create a Slider to Navigate Table States
We begin by creating a slider that represents each step in the build pipeline.
Step 0 is the original GT object.
Step 1 applies the first method call, and so on.
Slider Range Limitation
Because all method calls are deferred, we can’t determine the total number of steps ahead of time. This means the developer needs to manually specify a reasonable range for the slider. If the selected index exceeds the available range, the last table will be shown by default.
Next, we use an example from the Great Tables documentation to create a lazy WigGT object. This will internally store each method call but won’t execute them just yet.
You’ll see a slider widget embedded in the table’s source note — but it won’t be functional until we finalize the process.
lazy_wig_gt = ( WigGT(airquality.head(10).assign(Year=1973), widget=time_widget) .opt_stylize(color="pink", style=2) .tab_header( title="New York Air Quality Measurements", subtitle="Daily measurements in New York City (May 1-10, 1973)", ) .tab_spanner(label="Time", columns=["Year", "Month", "Day"]) .tab_spanner( label="Measurement", columns=["Ozone", "Solar_R", "Wind", "Temp"] ) .cols_move_to_start(columns=["Year", "Month", "Day"]) .cols_label( Ozone=html("Ozone,<br>ppbV"), Solar_R=html("Solar R.,<br>cal/m<sup>2</sup>"), Wind=html("Wind,<br>mph"), Temp=html("Temp,<br>°F"), ))lazy_wig_gt