Skip to content

Instantly share code, notes, and snippets.

@jonathanferrari
Last active June 13, 2026 20:07
Show Gist options
  • Select an option

  • Save jonathanferrari/fb5e61beef35d54d5b7bbcc2eec88b6b to your computer and use it in GitHub Desktop.

Select an option

Save jonathanferrari/fb5e61beef35d54d5b7bbcc2eec88b6b to your computer and use it in GitHub Desktop.
Create an Interactive Table using Ipywidgets and Pandas
import pandas as pd
import ipywidgets as widgets
import numpy as np
from IPython.display import *
class Make:
def headers(cols, labels):
header_widgets = []
for label in labels:
label_lay = widgets.Layout(width="auto")
header_label = widgets.HTML(f'<div class="table-cell"><b font-size:13px;>{label}</b></div>', layout = label_lay)
header_lay = widgets.Layout(width="80px", margin="0 10px 10px 0")
header_widget = widgets.VBox([header_label, widgets.HTML('<div style="height: 10px;"></div>')], layout = header_lay)
header_widgets.append(header_widget)
header_lay = widgets.Layout(grid_template_columns="repeat({0}, auto)".format(cols),
margin="0 0 10px", display="flex", flex_wrap="wrap",
justify_content="flex-start", border="none")
headers = widgets.GridBox(header_widgets, layout = header_lay)
return headers
def grid(headers, cells):
grid_items = [headers]
for row_widgets in cells:
row_lay = widgets.Layout(display = "flex", flex_wrap = "wrap",
justify_content = "flex-start", border = "none")
grid_item = widgets.GridBox(row_widgets, layout = row_lay)
grid_items.append(grid_item)
grid_lay = widgets.Layout(grid_template_rows = "auto", grid_gap = "0px",
padding = "10px", border = "none",
align_items = "flex-start")
grid = widgets.GridBox(grid_items, layout = grid_lay)
return grid
def labels_and_types(cols, labels, types):
if not labels:
labels = [f"Column {i}" for i in range(cols)]
if not types:
types = "text"
if isinstance(types, str):
types = [types] * cols
return labels, types
def df(rows, labels, types):
type_map = {"integer": 0, "decimal": 0.0, "text": ""}
return pd.DataFrame({label : [type_map[type]] * rows for label, type in zip(labels, types)})
def cells(rows, cols, df):
type_funcs = {np.dtype("int64"): lambda x: int(x), np.dtype("float64"): lambda x: float(x), np.dtype("object"): lambda x: str(x)}
widget_types = {np.dtype("int64"): widgets.IntText, np.dtype("float64"): widgets.FloatText, np.dtype("object"): widgets.Text}
cells = []
for i in range(rows):
row_widgets = []
for j in range(cols):
dtype = df.iloc[i, :].dtype
func = type_funcs[dtype]
val = func(df.iloc[i, j])
cell_widget = widget_types[dtype]
text_widget = cell_widget(value=val,
layout=widgets.Layout(width="80px", margin="0 10px 10px 0"))
row_widgets.append(text_widget)
# register callback to update dataframe when any cell value changes
def update_df(change):
for ii in range(rows):
for jj in range(cols):
if cells[ii][jj] == change.owner:
df.iloc[ii, jj] = change.new
text_widget.observe(update_df, names="value")
cells.append(row_widgets)
return cells
def widget(grid):
stylesheet = """
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+JQLM9vH+iA8tZIc5oTp75j7Bh/kzQ"
crossorigin="anonymous">
<style>
.table-cell {
display: table-cell;
padding: 10px 5px;
border-top: none !important;
border-right: none !important;
vertical-align: middle;
}
.form-control {
width: 80px;
}
</style>'
"""
display(widgets.HTML(stylesheet))
display(grid)
def table(rows, cols, labels=None, types=None):
labels, types = Make.labels_and_types(cols, labels, types)
# create empty dataframe with given number of rows and columns
df = Make.df(rows, labels, types)
# create table headers
headers = Make.headers(cols, labels)
# create table cells
cells = Make.cells(rows, cols, df)
# create a grid of widgets with headers and cells
grid = Make.grid(headers, cells)
# display the grid with Bootstrap styling
Make.widget(grid)
# return the dataframe
return df
# Sample
# df = Make.table(5, 5,['id', 'age', 'height', "name", "weight"], ["integer", "integer", "decimal", "text", "decimal"])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment