lattice-grid-jupyter
Edit a pandas DataFrame as an interactive Lattice Grid inside Jupyter, with a live two-way round-trip back to Python.
import pandas as pd
from lattice_grid_jupyter import LatticeGridWidget
df = pd.DataFrame({"name": ["Ada", "Grace"], "score": [91, 88], "active": [True, False]})
w = LatticeGridWidget(df) # renders an editable grid
w # display it in a notebook cell
# ...edit cells in the grid...
w.df # the DataFrame, reflecting your edits (dtypes preserved)
Built on anywidget, so it works in JupyterLab, classic Notebook, VS Code, Colab, and anywhere ipywidgets render.
Install
pip install lattice-grid-jupyter
Depends on anywidget and pandas. The wheel vendors the published Lattice
Grid bundle (@toclocoinc/lattice-grid@1.40.0) so offline notebooks work with no
network at render time.
The grid bundle: CDN vs vendored
Two ways the browser gets the grid JS/CSS, chosen per widget:
| Mode | How | When |
|---|---|---|
| CDN (default) | dynamic import() from jsDelivr at render time |
online notebooks; smallest saved-notebook size |
Vendored (offline=True) |
the bundle text ships in the widget model | air-gapped / offline notebooks |
w = LatticeGridWidget(df) # CDN (default)
w = LatticeGridWidget(df, offline=True) # vendored, no network needed
The default is CDN. Vendored mode carries ~3 MB of grid JS in the widget model,
which inflates a saved .ipynb; prefer CDN when you have network. (An alternative
not implemented here would serve the vendored asset over Jupyter's own static
handler instead of the comm; see Notes below.)
What the DataFrame maps to
dtypes -> grid column types
| pandas dtype | grid column type |
|---|---|
int*, Int* (nullable), float* |
number |
bool, boolean (nullable) |
boolean |
datetime64 (naive or tz-aware) |
timestamp (ISO 8601) |
category, object, string, timedelta |
text |
Index
- A default
RangeIndex(0..n-1)is not shown as a column (it adds nothing). - A named / non-default index becomes one read-only leading column.
- A
MultiIndexbecomes one read-only column per level. - Row identity is a stable, positional id (
__row_id__), never the index label — so duplicate index labels and every other index shape work correctly and edits always land on the right row.
Missing values — NaN, NaT and pd.NA all serialize to JSON null.
Editing round-trip
Every committed cell edit in the grid flows back to w.df, cast to the column's
dtype (an int column stays int, etc.). Index columns are read-only.
Live updates: Python -> grid
w.set_data(new_df) # replace the whole frame, repaint
keys = w.append_rows([{...}, ...]) # append rows (DataFrame or list-of-dicts)
w.append_rows(other_df)
w.delete_rows(keys) # delete by the keys append_rows returned
append_rows / delete_rows push incremental changes to the grid
(grid.rows.apply({add|remove})); set_data does a full grid.rows.load().
Row keys are stable, so keys returned by append_rows stay valid for
delete_rows and for later edits.
Large DataFrames
The frame is serialized column-major ({field: [values...]}), not as a
list-of-dicts:
- field names are not repeated per row (roughly halves the payload for wide frames);
- each column is built with a vectorized pass, not
DataFrame.iterrows()— which is the real reason a naive list-of-dicts build stalls at 100k rows; - the grid's memory source virtualizes rendering, so only the visible window is ever in the DOM.
This handles a 100,000-row frame without freezing (see tests/ and the demo
notebook). For frames far larger than fit in the browser (millions of rows), the
grid also exposes paged / remote / stream source modes whose fetch
callback would page back into the Python kernel over the comm — that is the
documented extension point, not wired in this release.
Licensing
The grid renders fully and unwatermarked on localhost (the normal
data-science case) with no key — that is the free tier. A widget served from
a non-localhost origin (a deployed notebook server, Voila, Binder on a public
host) should pass a key:
w = LatticeGridWidget(df, licence="LG-...")
The key is threaded straight into createGrid({ licence }); grid.licence.state()
resolves to localhost, licensed, or trial.
Development / tests
pip install -e ".[dev]"
pytest tests/test_serialize.py tests/test_roundtrip.py # Python round-trip (no browser)
pytest tests/test_smoke_browser.py # real-browser smoke test
The smoke test drives a real Chromium via Playwright: it renders the widget's front end, performs a real edit in the grid, and asserts the edit payload reached the (mocked) model — the one gap the headless Python tests cannot cover. It uses the vendored bundle, so it needs no network. If no browser is available it is skipped (never faked).
Notes / not in this release
- Vendored mode transfers the bundle through the widget comm; serving it over Jupyter's static handler would keep saved notebooks small — a future option.
set_dataassumes the same schema (columns/index shape). A different schema should use a fresh widget.- Binary (Arrow/typed-array) transfer would beat columnar-JSON for very wide numeric frames; columnar-JSON is what ships here.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file lattice_grid_jupyter-0.1.0.tar.gz.
File metadata
- Download URL: lattice_grid_jupyter-0.1.0.tar.gz
- Upload date:
- Size: 739.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b55be7b3c488a87049bf17f1314008416884812d7cce62a0e4a84d620165483e
|
|
| MD5 |
e9f1e3dd89206979cee5a27df1fd602f
|
|
| BLAKE2b-256 |
6709a31925e6a0e71eb5d1359e8acd441fc48f55f890ab5df162aec86d166347
|
Provenance
The following attestation bundles were made for lattice_grid_jupyter-0.1.0.tar.gz:
Publisher:
publish-pypi.yml on toclocoinc/lattice-grid-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lattice_grid_jupyter-0.1.0.tar.gz -
Subject digest:
b55be7b3c488a87049bf17f1314008416884812d7cce62a0e4a84d620165483e - Sigstore transparency entry: 2751950486
- Sigstore integration time:
-
Permalink:
toclocoinc/lattice-grid-python@413eab2e38be795ed6bbd325b7a14e411faa35cf -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/toclocoinc
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@413eab2e38be795ed6bbd325b7a14e411faa35cf -
Trigger Event:
push
-
Statement type:
File details
Details for the file lattice_grid_jupyter-0.1.0-py3-none-any.whl.
File metadata
- Download URL: lattice_grid_jupyter-0.1.0-py3-none-any.whl
- Upload date:
- Size: 741.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2470d9d9f8b566bd906be6d2866a297a04a04fd40cc3431640ee62468596b0de
|
|
| MD5 |
f858c86deb40d7564dc4dd15ecb4a515
|
|
| BLAKE2b-256 |
a9443dd418c4a1d176d9599662012fe1ef99d7e72ff4fec7d0c207b43c2ff24a
|
Provenance
The following attestation bundles were made for lattice_grid_jupyter-0.1.0-py3-none-any.whl:
Publisher:
publish-pypi.yml on toclocoinc/lattice-grid-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lattice_grid_jupyter-0.1.0-py3-none-any.whl -
Subject digest:
2470d9d9f8b566bd906be6d2866a297a04a04fd40cc3431640ee62468596b0de - Sigstore transparency entry: 2751950525
- Sigstore integration time:
-
Permalink:
toclocoinc/lattice-grid-python@413eab2e38be795ed6bbd325b7a14e411faa35cf -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/toclocoinc
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@413eab2e38be795ed6bbd325b7a14e411faa35cf -
Trigger Event:
push
-
Statement type: