Skip to main content

ipyrowtable

Editable ipywidgets tables for problems made of elements in series: wall layers, pipe segments, cable runs, process stages. You describe the columns and write a compute function; ipyrowtable gives a table where Jupyter users add and remove rows, edit inputs, see computed results update immediately, and easily use the configured inputs in downstream cells.

A layer table with an SI / Imperial toggle and a live temperature profile

What sets it apart from a general-purpose data grid:

  • Every cell is a real widget. Dropdowns, number boxes and text boxes in the table itself, with add and remove buttons per row.
  • Values between rows. A NodeColumn holds the n + 1 values at the joints of n elements (interface temperatures, joint pressures, node voltages), with editable boundary conditions at either end.
  • Unit systems. A toggle switches everything shown between, say, SI and Imperial. Values are stored in your base units, so switching never changes the physics or drifts.
  • Live plots. LiveFigure keeps a matplotlib figure in step with the table.
  • Saved between sessions. A table can keep its inputs across kernel restarts, making it a friendlier alternative to a hard-coded dict of inputs.

It suits small, carefully entered inputs: tens of rows, not thousands. For large data, use a grid such as ipydatagrid or Panel's Tabulator.

Install

pip install ipyrowtable            # the table
pip install "ipyrowtable[plot]"    # plus matplotlib, for LiveFigure and the conduction example

Needs Python 3.10+ and ipywidgets 8.1+. It uses only standard widgets, with no custom JavaScript, so it works wherever ipywidgets does: JupyterLab, Jupyter Notebook, VS Code, Voilà.

Try it

A complete application ships with the package: steady conduction through a plane composite wall, with an SI / Imperial toggle and a temperature-profile plot.

from ipyrowtable.examples.conduction import layer_stack_app

layer_stack_app(layers=[("Gypsum board", 12.7), ("Fiberglass insulation", 89), ("Brick", 90)],
                T_top=21, T_bottom=-10)

Quick start

Voltage along a cable run. Each row is a segment; the voltage at each joint is computed from the source voltage (an editable boundary value) and the load current (a parameter that applies to the whole run).

import numpy as np
from ipyrowtable import ChoiceColumn, NodeColumn, NumberColumn, OutputColumn, RowTable

OHM_PER_M = {"14 AWG": 0.008286, "12 AWG": 0.005211, "10 AWG": 0.003277}  # copper, 20 °C

def voltage_drop(inputs):
    ohm_per_m = np.array([OHM_PER_M[g] for g in inputs.column("gauge")])
    drop = 2 * inputs.params["current"] * ohm_per_m * inputs.column("length")  # out and back
    V_source = inputs.edges["voltage"][0]
    return {"drop": drop, "voltage": V_source - np.concatenate(([0.0], np.cumsum(drop)))}

cable = RowTable(
    columns=[
        ChoiceColumn("gauge", "Wire", options=OHM_PER_M),
        NumberColumn("length", "Length (m)", default=10.0, min=0),
        OutputColumn("drop", "Drop (V)"),
        NodeColumn("voltage", "Voltage (V)", inputs="first", first_default=120.0),
    ],
    compute=voltage_drop,
    parameters=[NumberColumn("current", "Current (A)", default=15.0)],
    leading_label="— source —",
    item_name="segment",
)
cable

cable.results["voltage"] holds the latest values, and cable.results.records() gives one dict per row, ready for pandas.DataFrame.

Concepts

Columns

Column Kind Per row
ChoiceColumn input a dropdown; options can carry data, like a material's conductivity
NumberColumn input a number, optionally unit-aware (quantity=) and bounded (min=, max=)
TextColumn input free text, such as a name or tag
OutputColumn output one computed value
NodeColumn output the value at the row's bottom or outlet face; the value at the top or inlet goes in a leading row

Headers can include units: "Thickness ({unit})" shows the column's own unit, and "k in {conductivity}" shows any other quantity's unit.

Input columns can also be parameters, shown above the table for values that apply to the whole problem. To add a new input type, subclass InputColumn and implement create_widget. The 03_extending notebook adds a whole-number column this way.

Values between rows

A NodeColumn holds n + 1 values for n rows. Use inputs= to say which ends are editable:

  • ("first", "last") for both ends, like the two surface temperatures of a wall
  • "first" for the inlet only, like a supply pressure
  • "last" for the outlet only
  • () for neither

Your compute function receives the boundary values as inputs.edges[key] and returns all n + 1 values, including the ends.

Units

from ipyrowtable import Unit, UnitSystem

SI = UnitSystem("SI", {"length": Unit("mm", 1000.0), "temperature": Unit("°C")})
IMPERIAL = UnitSystem("Imperial", {"length": Unit("in", 1 / 0.0254),
                                   "temperature": Unit("°F", 1.8, 32.0)})

A Unit converts with display = base × scale + offset. Your compute function always works in base units (metres and °C here). Pass unit_systems=[SI, IMPERIAL] to get a toggle. Defaults can be given per system, such as default={"SI": 10, "Imperial": 0.5}, so new rows start at round numbers in whichever units are showing.

The compute function and results

compute(inputs) receives:

  • inputs.rows: a list of dicts, one per row
  • inputs.column(key): one column as an array
  • inputs.edges: the NodeColumn boundary values
  • inputs.params: the parameters

All of them are in base units. It returns {column key: values}, and any extra keys (totals, fluxes) are kept too. If it raises ValueError("message"), the message appears in place of the results.

After every change:

  • table.results[key] gives values in base units, and table.results.display(key) gives them in the units shown.
  • table.results.records() gives one dict per row.
  • table.on_update(callback) runs your code with the results, or with None while the inputs are invalid.
  • table.error says what went wrong, if anything did.

Saving inputs between sessions

cable = RowTable(..., rows=[...], persist="feeder")

With a persist key, the table saves its inputs whenever they change and restores them when a table with the same key is created again, for example after a kernel restart. The inputs are the rows, boundary values, parameters, and the unit system that was showing.

rows, edges, params and units then become the initial values. They're used:

  • when nothing has been saved yet;
  • when the saved inputs can't be used, for example because an option no longer exists (the table says why, and keeps the old file as a .bak copy before replacing it);
  • by the Reset button, which asks for a second click first.

Where the inputs go:

  • By default, into <notebook name>.ipyrowtable.json next to the notebook. If the notebook can't be identified, they go into ipyrowtable.json in the working folder. The note under the table names the file.
  • persist_file= picks a different file. One file can hold many tables, each under its own key.
  • Values are stored as plain JSON in base units, so it doesn't matter which unit system was showing.

They go in a file rather than the notebook's metadata because the kernel can't write notebook metadata.

To always start from the initial values, leave out persist. The environment variable IPYROWTABLE_PERSIST=off turns saving off for every table, which is useful for batch runs that must start from known inputs. table.get_inputs() and table.set_inputs(snapshot) let you keep and load snapshots yourself, such as several named designs.

Plots

from ipyrowtable import LiveFigure, side_by_side

def draw(fig, results):
    ax = fig.add_subplot()
    ax.plot(results["voltage"], marker="o")

side_by_side(cable, LiveFigure(cable, draw=draw))

Styling

Every part carries a CSS class you can style:

  • ipyrowtable-grid, ipyrowtable-add, ipyrowtable-reset, ipyrowtable-message, ipyrowtable-persist
  • ipyrowtable-<key> on each column's cells

Examples

The examples/ folder has four notebooks:

  1. 01_getting_started: a first table, values between rows, a live plot, driving a table from code.
  2. 02_plane_wall_conduction: the conduction app: units, reading results, plugging in your own solver.
  3. 03_extending: pipes in series (Darcy–Weisbach). Covers your own unit systems, a custom column type, parameters, on_update, and styling.
  4. 04_saving_inputs: keeping a table's inputs between sessions: initial values, the saved file, named snapshots, resetting, and turning saving off.

FAQ

In VS Code, a table shows "Failed to load model class …" instead of rendering

This can happen the first time a notebook runs in VS Code's Jupyter extension, when a table is created in one cell and displayed in a later one. It comes from how VS Code loads its widget support: widgets created before VS Code has finished loading it can fail to render. It isn't caused by ipyrowtable, which uses only standard ipywidgets. Seen with the Jupyter extension 2025.9.1 on Windows.

  • To fix it: re-run the cell that creates the table, then the cell that displays it.

Development

See CONTRIBUTING.md for setup, the test suite (including real-browser tests) and releasing.

License

MIT

Release files for ipyrowtable 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ipyrowtable 0.1.1
File Size Uploaded
ipyrowtable-0.1.1.tar.gz 120.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ipyrowtable 0.1.1
File Interpreter ABI Platform
ipyrowtable-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 151.5 kB

Release files / ipyrowtable-0.1.1.tar.gz

Download URL ipyrowtable-0.1.1.tar.gz
Size 120.9 kB
Tags Source
SHA-256 checksum
How to use checksums
5b6d820bf81b920dc774dac468bb5590c0296263970d066db5ca857bedfc7b20
BLAKE2b-256 checksum
How to use checksums
f3cc431f0ff1cc17a34672fcdb5a06f7fb9f8cc59d83d3c550ecca3072d637b0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.2

Release files / ipyrowtable-0.1.1-py3-none-any.whl

Download URL ipyrowtable-0.1.1-py3-none-any.whl
Size 30.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
07b227d826863952ba07cef2e70b6f4128e92a2877a4989fbef30856bde2c2b1
BLAKE2b-256 checksum
How to use checksums
4f90701db110bf791c7ce9cd34a47cac0c3e560059d7505b4ff303dfd77f393d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.2

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page