Lattice Grid Buy a licence

task guide

A grid in a Dash app

lattice_grid_dash.LatticeGrid puts the grid in a Dash layout, and every committed edit arrives at an ordinary callback as {colId, key, value}, the same shape a dropdown or a slider would send. One file, run below against the real package.

app.py

A small inventory grid: four SKUs, their warehouse, what is on hand and the reorder point. Editing is turned on with options={"edit": True}, and the callback watches for a change and recomputes which SKUs are now below their reorder point.

import pandas as pd
from dash import Dash, Input, Output, callback, html
import lattice_grid_dash
from lattice_grid_dash import dataframe_to_data, apply_cell_edit

df = pd.DataFrame({
    "sku": ["BRK-100", "BRK-101", "BRK-102", "BRK-103"],
    "warehouse": ["north", "north", "south", "south"],
    "on_hand": [42, 15, 8, 120],
    "reorder_at": [20, 20, 10, 50],
})

app = Dash(__name__)
app.layout = html.Div([
    lattice_grid_dash.LatticeGrid(
        id="grid",
        data=dataframe_to_data(df),
        options={"edit": True},
    ),
    html.Pre(id="out"),
])


@callback(Output("out", "children"), Input("grid", "cellChanged"))
def on_edit(edit):
    if not edit:
        return "Edit on_hand for a SKU to see it here."
    apply_cell_edit(df, edit)          # keeps the server-side DataFrame in sync, typed
    low = df[df["on_hand"] < df["reorder_at"]]["sku"].tolist()
    return f"{edit['colId']} on {edit['key']} is now {edit['value']}. Below reorder point: {low}"


if __name__ == "__main__":
    app.run(debug=False)

What the callback receives

Committing an edit in the grid sends cellChanged as {"colId": ..., "key": ..., "value": ...}, one dictionary per edit. apply_cell_edit(df, edit) looks up the column and the row by that key, casts the value to the column's dtype, and writes it into df in place, returning the same frame. Below, the callback is called directly, exactly as Dash calls it after a grid edit, against the app above:

# Driving the callback exactly as Dash would after a grid edit event:
edit1 = {"colId": "on_hand", "key": "1", "value": 12}
print(on_edit(edit1))
edit2 = {"colId": "on_hand", "key": "2", "value": 3}
print(on_edit(edit2))
print(df)
on_hand on 1 is now 12. Below reorder point: ['BRK-101', 'BRK-102']
on_hand on 2 is now 3. Below reorder point: ['BRK-101', 'BRK-102']
       sku warehouse  on_hand  reorder_at
0  BRK-100     north       42          20
1  BRK-101     north       12          20
2  BRK-102     south        8          10
3  BRK-103     south      120          50

on_hand is still int64 after both edits, and the reorder check, which reads straight from the DataFrame's own dtypes, sees the change immediately because apply_cell_edit mutated the same frame the check runs against.

Run it

The grid's front-end code ships inside the package, so this runs with no build step and no request to a CDN at render time.

python app.py

Open the address Dash prints. Double-click an on_hand value, type a new number and commit it: the text under the grid updates with the exact message above, computed against the DataFrame the app is actually holding.

What next

For the same round trip in a notebook instead of an app, see a live grid in a notebook cell. For the datetime rule an edited timestamp column follows, see edit a DataFrame in the browser. Every prop and helper function is in the Python reference.