task guide
Edit a pandas DataFrame in the browser
A DataFrame becomes an editable grid, a person changes a cell, and the value lands back in the frame cast to the column's own dtype. The one type that needs a stated rule is a timestamp, so that rule is stated here, with a script you can run yourself.
The script, and what it printed
This is the whole thing: build a frame with a text column, a number column and a datetime column,
hand it to
LatticeGridWidget,
then apply two edits the same way a click in the grid
would. offline=True carries the grid's own JS and CSS inside the package, so nothing
is fetched from a CDN and no licence key is needed to run this on your own machine.
import pandas as pd
from lattice_grid_jupyter import LatticeGridWidget
df = pd.DataFrame({
"ticker": ["AAPL", "MSFT", "TSLA"],
"shares": [120, 45, 30],
"last_trade": pd.to_datetime([
"2026-09-23 09:31:00",
"2026-09-23 09:32:15",
"2026-09-23 09:33:40",
]), # naive: this wrapper treats naive as UTC, both ways
})
grid = LatticeGridWidget(df, offline=True) # offline=True: no licence needed on your own machine
# a person editing the grid in the browser sends the same message this line
# sends by hand -- apply_edit replays the exact payload an edit emits:
grid.apply_edit(key="1", col_id="shares", value=50)
grid.apply_edit(key="2", col_id="last_trade", value="2026-09-23T09:40:00Z")
print(grid.df)
print(grid.df.dtypes)
Run that cell and the two print calls give this, unedited:
ticker shares last_trade
0 AAPL 120 2026-09-23 09:31:00
1 MSFT 50 2026-09-23 09:32:15
2 TSLA 30 2026-09-23 09:40:00
ticker str
shares int64
last_trade datetime64[us]
dtype: object
Row "1"'s
shares
is 50, the number the edit sent, still an
int64.
Row "2"'s
last_trade
moved to the timestamp the edit named, still a
datetime64.
Nothing was exported, parsed back, or given a second
schema to agree with; grid.df is the same frame the widget was built from, mutated in
place.
The datetime contract
A timestamp is the one type where "just send the value" is ambiguous, because a naive Python
datetime carries no timezone to be unambiguous with. This wrapper picks one rule and holds it in
both directions: a naive
datetime64
column is read as UTC when it goes to the grid,
and an edit coming back is written as UTC into that same naive column, never coerced to the
machine's local zone. A timezone-aware column keeps its own zone: it travels as UTC on the wire and
lands back converted to the zone it already had, so a Europe/London column reads in
Europe/London after the edit, the same as before it.
In the script above, editing
last_trade
with the ISO string
"2026-09-23T09:40:00Z" and reading back 2026-09-23 09:40:00 with no
offset printed is that rule working: the column is naive, so the instant is stored and shown
without one, and it is the same instant a browser clock and this frame agree on.
Every other dtype
A boolean column reads and writes as True / False. An integer column
casts an edit with
int(),
so a decimal typed into a whole-number column is truncated
the way int() truncates it, not rounded.
A float column casts with
float().
A named index, including a multi-level one, arrives as read-only leading columns, so editing an
index value is refused rather than silently accepted. Casting is best-effort: a value that cannot
be cast is written back exactly as sent rather than raising out of an edit a user is in the middle
of making.
What next
For the notebook version of this with
append_rows
and delete_rows as
well, see a live grid in a notebook cell. For
the same round trip driven by a Dash callback instead of a print statement, see
a grid in a Dash app. Every constructor argument and
method, with its signature and return value, is in the
Python reference.