Data Grid
#| standalone: true
#| components: [viewer]
#| viewerHeight: 375
from palmerpenguins import load_penguins
from shiny import App, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.data_frame
def penguins_df():
return render.DataGrid(penguins)
app = App(app_ui, server)
from palmerpenguins import load_penguins
from shiny import App, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.data_frame
def penguins_df():
return render.DataGrid(penguins)
app = App(app_ui, server)
Relevant Functions
-
ui.output_data_frame
ui.output_data_frame(id)
-
@render.data_frame
render.data_frame(fn=None)
-
render.DataGrid
render.DataGrid(self, data, *, width='fit-content', height='500px', summary=True, filters=False, row_selection_mode='none')
Details
A Data Grid presents tabular data in a spreadsheet-like view with cells separated by grid lines.
To make a reactive Data Grid, follow three steps:
Call
ui.output_data_frame()
in the UI of your app to create a div in which to display the table. Where you call this function within the UI functions will determine where the table will appear within the layout of the app. Set the id argument ofui.output_data_frame()
to a unique value.Within the server function, define a new function whose name matches the id used above. The function should assemble the table to display and then return the table wrapped in
render.DataGrid()
. Shiny will rerun this function whenever it needs to build or update the output that has the matching id.Decorate the function with
@render.data_frame
.
A Data Grid can also collect input from the user. To allow this, set render.DataGrid(selection_mode="row")
or render.DataGrid(selection_mode="rows")
to allow the user to select one or more rows of the Data Grid.
The indices of the selected rows will be accessible within the server function as a reactive variable returned by <name>.cell_selection()["rows"]
, where @render.data_frame
.
The value returned will be an empty tuple if no rows are selected, or a tuple of integers representing the indices of the selected rows. To filter a pandas data frame down to the selected rows, use df.iloc[list(<name>.cell_selection()["rows"])]
.
For more information about interacting with data frames, see the API documentation for Express or Core syntax.
If your table is a data frame that uses the pandas styler, replace ui.output_data_frame()
with ui.output_table()
and @render.data_frame
with @render.table
.
See also: Data Tables
Variations
Select Rows
Set selection_mode
in render.DataGrid()
to "row"
to allow the user to select one row at a time. Set it to "rows"
to allow the user to select multiple rows at a time. Access the selection(s) as <id>.cell_selection()["rows"]
.
#| standalone: true
#| components: [viewer]
#| viewerHeight: 350
from palmerpenguins import load_penguins
from shiny import App, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
ui.output_ui("rows"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.data_frame
def penguins_df():
return render.DataGrid(penguins, selection_mode="rows")
@render.ui
def rows():
rows = penguins_df.cell_selection()["rows"]
selected = ", ".join(str(i) for i in sorted(rows)) if rows else "None"
return f"Rows selected: {selected}"
app = App(app_ui, server)
from palmerpenguins import load_penguins
from shiny.express import input, render, ui
penguins = load_penguins()
ui.h2("Palmer Penguins")
@render.ui()
def rows():
rows = penguins_df.cell_selection()["rows"]
selected = ", ".join(str(i) for i in sorted(rows)) if rows else "None"
return f"Rows selected: {selected}"
@render.data_frame
def penguins_df():
return render.DataGrid(penguins, selection_mode="rows")
from palmerpenguins import load_penguins
from shiny import App, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
ui.output_ui("rows"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.data_frame
def penguins_df():
return render.DataGrid(penguins, selection_mode="rows")
@render.ui
def rows():
rows = penguins_df.cell_selection()["rows"]
selected = ", ".join(str(i) for i in sorted(rows)) if rows else "None"
return f"Rows selected: {selected}"
app = App(app_ui, server)
Filterable Table
Set render.DataGrid(filters=True)
to add a row of filter options to the header row. Users can interact with these options to filter the table.
#| standalone: true
#| components: [viewer]
#| viewerHeight: 350
from palmerpenguins import load_penguins
from shiny import App, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.data_frame
def penguins_df():
return render.DataGrid(penguins, filters=True)
app = App(app_ui, server)
from palmerpenguins import load_penguins
from shiny import App, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.data_frame
def penguins_df():
return render.DataGrid(penguins, filters=True)
app = App(app_ui, server)
Edit Table Cells
Set editable=True
to be able to edit cell contents without re-rendering the data frame.
#| standalone: true
#| components: [viewer]
#| viewerHeight: 350
from palmerpenguins import load_penguins
from shiny import App, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.data_frame
def penguins_df():
return render.DataGrid(
penguins,
editable=True,
)
app = App(app_ui, server)
from palmerpenguins import load_penguins
from shiny import App, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.data_frame
def penguins_df():
return render.DataGrid(
penguins,
editable=True,
)
app = App(app_ui, server)
Use Original Data
The reactive value .data()
will reactively return the unaltered data.
#| standalone: true
#| components: [viewer]
#| viewerHeight: 350
from palmerpenguins import load_penguins
from shiny import App, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
"The shape of the data frame is :",
ui.output_code("penguins_shape"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.data_frame
def penguins_df():
return render.DataGrid(penguins)
@render.code
def penguins_shape():
data = penguins_df.data()
return data.shape
app = App(app_ui, server)
from palmerpenguins import load_penguins
from shiny.express import render, ui
penguins = load_penguins()
ui.h2("Palmer Penguins")
"The shape of the data frame is :"
@render.code
def penguins_shape():
data = penguins_df.data()
return data.shape
@render.data_frame
def penguins_df():
return render.DataGrid(penguins)
from palmerpenguins import load_penguins
from shiny import App, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
"The shape of the data frame is :",
ui.output_code("penguins_shape"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.data_frame
def penguins_df():
return render.DataGrid(penguins)
@render.code
def penguins_shape():
data = penguins_df.data()
return data.shape
app = App(app_ui, server)
Use Edited Data
The reactive value .data_view()
(or .data_view(selected=True)
) will reactively return the edited data. The data will be updated as the user edits the table and the rows will be arranged to match the user’s sorting and filtering.
#| standalone: true
#| components: [viewer]
#| viewerHeight: 350
from palmerpenguins import load_penguins
from shiny import App, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
"The shape of the selected data frame is :",
ui.output_code("penguins_shape"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.data_frame
def penguins_df():
return render.DataGrid(penguins, selection_mode="rows")
@render.code
def penguins_shape():
data = penguins_df.data_view(selected=True)
return data.shape
app = App(app_ui, server)
from palmerpenguins import load_penguins
from shiny.express import render, ui
penguins = load_penguins()
ui.h2("Palmer Penguins")
"The shape of the selected data frame is :"
@render.code
def penguins_shape():
data = penguins_df.data_view(selected=True)
return data.shape
@render.data_frame
def penguins_df():
return render.DataGrid(penguins, selection_mode="rows")
from palmerpenguins import load_penguins
from shiny import App, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
"The shape of the selected data frame is :",
ui.output_code("penguins_shape"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.data_frame
def penguins_df():
return render.DataGrid(penguins, selection_mode="rows")
@render.code
def penguins_shape():
data = penguins_df.data_view(selected=True)
return data.shape
app = App(app_ui, server)
Set Table Size
Set the height
and width
parameters of render.DataGrid()
to constrain the output size of the table.
#| standalone: true
#| components: [viewer]
#| viewerHeight: 350
from palmerpenguins import load_penguins
from shiny import App, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.data_frame
def penguins_df():
return render.DataGrid(penguins, width="300px", height="250px")
app = App(app_ui, server)
from palmerpenguins import load_penguins
from shiny import App, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.data_frame
def penguins_df():
return render.DataGrid(penguins, width="300px", height="250px")
app = App(app_ui, server)
Styling
Set styles
in render.DataGrid()
to a customize the table display. styles
can take a list of dictionaries where each dictionary represents a style to be applied to the table (and thus should have at least a style
(or class
) key to apply CSS styles or classes to the relevant cells). To scope the styling to particular cells, use the rows
and cols
keys (with 0-based indexing). Note that if both rows
and cols
are specified, the style will be applied only to the intersection of the specified rows and columns.
#| standalone: true
#| components: [viewer]
#| viewerHeight: 350
import pandas as pd
from palmerpenguins import load_penguins
from shiny import App, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.data_frame
def penguins_df():
return render.DataGrid(
penguins.iloc[[0, 1, 200, 201, 300, 301], :],
styles=[
# Center the text of each cell (using Bootstrap utility class)
{
"class": "text-center",
},
# Bold the first column
{
"cols": [0],
"style": {"font-weight": "bold"},
},
# Highlight the penguin colors
{
"rows": [0, 1],
"cols": [0],
"style": {"background-color": "#ffdbaf"},
},
{
"rows": [2, 3],
"cols": [0],
"style": {"background-color": "#b1d6d6"},
},
{
"rows": [4, 5],
"cols": [0],
"style": {"background-color": "#d6a9f2"},
},
],
)
app = App(app_ui, server)
import pandas as pd
from palmerpenguins import load_penguins
from shiny.express import render, ui
penguins: pd.DataFrame = load_penguins()
ui.h2("Palmer Penguins")
@render.data_frame
def penguins_df():
return render.DataGrid(
penguins.iloc[[0, 1, 200, 201, 300, 301], :],
# penguins,
styles=[
# Center the text of each cell (using Bootstrap utility class)
{
"class": "text-center",
},
# Bold the first column
{
"cols": [0],
"style": {"font-weight": "bold"},
},
# Highlight the penguin colors
{
"rows": [0, 1],
"cols": [0],
"style": {"background-color": "#ffdbaf"},
},
{
"rows": [2, 3],
"cols": [0],
"style": {"background-color": "#b1d6d6"},
},
{
"rows": [4, 5],
"cols": [0],
"style": {"background-color": "#d6a9f2"},
},
],
)
import pandas as pd
from palmerpenguins import load_penguins
from shiny import App, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.data_frame
def penguins_df():
return render.DataGrid(
penguins.iloc[[0, 1, 200, 201, 300, 301], :],
styles=[
# Center the text of each cell (using Bootstrap utility class)
{
"class": "text-center",
},
# Bold the first column
{
"cols": [0],
"style": {"font-weight": "bold"},
},
# Highlight the penguin colors
{
"rows": [0, 1],
"cols": [0],
"style": {"background-color": "#ffdbaf"},
},
{
"rows": [2, 3],
"cols": [0],
"style": {"background-color": "#b1d6d6"},
},
{
"rows": [4, 5],
"cols": [0],
"style": {"background-color": "#d6a9f2"},
},
],
)
app = App(app_ui, server)
Update Filters
The data frame filters can be programmatically updated using the .update_filter()
method. It takes a list of column filters to apply to the data frame. Each column filter is a dictionary with the following keys: col
and value
. The col
key is the column index to filter on, and the value
key is the value to filter for. The value
key can be a single value for string columns or a list of values to filter for numeric columns. Note, to not set a minimum or maximum value for a numeric column, you can provide a None
value. To reset filters, provide None
for the filters (.update_filter(None)
).
#| standalone: true
#| components: [viewer]
#| viewerHeight: 350
from palmerpenguins import load_penguins
from shiny import App, reactive, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
ui.input_action_button("update_filters", "Update filters"),
ui.input_action_button("reset_filters", "Reset filters"),
ui.h5("Current filters: ", {"class": "pt-2"}),
ui.output_code("penguins_filter"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.code
def penguins_filter():
return penguins_df.filter()
@render.data_frame
def penguins_df():
return render.DataGrid(penguins, filters=True)
@reactive.effect
@reactive.event(input.update_filters)
async def _():
await penguins_df.update_filter(
[
# Set partial match
{"col": 0, "value": "Gen"},
# Set min value
{"col": 2, "value": (50, None)},
# Set max value
{"col": 3, "value": (None, 17)},
# Set range
{"col": 4, "value": (220, 225)},
],
)
@reactive.effect
@reactive.event(input.reset_filters)
async def _():
await penguins_df.update_filter(None)
app = App(app_ui, server)
from palmerpenguins import load_penguins
from shiny import reactive
from shiny.express import input, render, ui
penguins = load_penguins()
ui.h2("Palmer Penguins")
ui.input_action_button("update_filters", "Update filters")
ui.input_action_button("reset_filters", "Reset filters")
ui.h5("Current filters: ", {"class": "pt-2"})
@render.code
def _():
return penguins_df.filter()
@render.data_frame
def penguins_df():
return render.DataGrid(penguins, filters=True)
@reactive.effect
@reactive.event(input.update_filters)
async def _():
await penguins_df.update_filter(
[
# Set partial match
{"col": 0, "value": "Gen"},
# Set min value
{"col": 2, "value": (50, None)},
# Set max value
{"col": 3, "value": (None, 17)},
# Set range
{"col": 4, "value": (220, 225)},
],
)
@reactive.effect
@reactive.event(input.reset_filters)
async def _():
await penguins_df.update_filter(None)
from palmerpenguins import load_penguins
from shiny import App, reactive, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
ui.input_action_button("update_filters", "Update filters"),
ui.input_action_button("reset_filters", "Reset filters"),
ui.h5("Current filters: ", {"class": "pt-2"}),
ui.output_code("penguins_filter"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.code
def penguins_filter():
return penguins_df.filter()
@render.data_frame
def penguins_df():
return render.DataGrid(penguins, filters=True)
@reactive.effect
@reactive.event(input.update_filters)
async def _():
await penguins_df.update_filter(
[
# Set partial match
{"col": 0, "value": "Gen"},
# Set min value
{"col": 2, "value": (50, None)},
# Set max value
{"col": 3, "value": (None, 17)},
# Set range
{"col": 4, "value": (220, 225)},
],
)
@reactive.effect
@reactive.event(input.reset_filters)
async def _():
await penguins_df.update_filter(None)
app = App(app_ui, server)
Update Sorting
The data frame sorting can be programmatically updated using the .update_sort()
method. It takes a list of sorting information or column numbers to apply to the data frame. When using a number, the default sorting direction will be applied. When providing a sorting info object, col
and desc
describe the column index and whether or not the sorting direction is descending. To reset the sorting, provide None
for the sorting information (.update_sort(None)
).
#| standalone: true
#| components: [viewer]
#| viewerHeight: 350
from palmerpenguins import load_penguins
from shiny import App, reactive, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
ui.input_action_button("update_sorting", "Update sorting"),
ui.input_action_button("reset_sorting", "Reset sorting"),
ui.h5("Current sorting: ", {"class": "pt-2"}),
ui.output_code("penguins_sort"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.code
def penguins_sort():
return penguins_df.sort()
@render.data_frame
def penguins_df():
return render.DataGrid(penguins)
@reactive.effect
@reactive.event(input.update_sorting)
async def _():
await penguins_df.update_sort(
[1, 0, {"col": 6, "desc": False}, 7],
)
@reactive.effect
@reactive.event(input.reset_sorting)
async def _():
await penguins_df.update_sort([])
app = App(app_ui, server)
from palmerpenguins import load_penguins
from shiny import reactive
from shiny.express import input, render, ui
penguins = load_penguins()
ui.h2("Palmer Penguins")
ui.input_action_button("update_sorting", "Update sorting")
ui.input_action_button("reset_sorting", "Reset sorting")
ui.h5("Current sorting: ", {"class": "pt-2"})
@render.code
def _():
return penguins_df.sort()
@render.data_frame
def penguins_df():
return render.DataGrid(penguins)
@reactive.effect
@reactive.event(input.update_sorting)
async def _():
await penguins_df.update_sort(
[1, 0, {"col": 6, "desc": False}, 7],
)
@reactive.effect
@reactive.event(input.reset_sorting)
async def _():
await penguins_df.update_sort([])
from palmerpenguins import load_penguins
from shiny import App, reactive, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
ui.input_action_button("update_sorting", "Update sorting"),
ui.input_action_button("reset_sorting", "Reset sorting"),
ui.h5("Current sorting: ", {"class": "pt-2"}),
ui.output_code("penguins_sort"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.code
def penguins_sort():
return penguins_df.sort()
@render.data_frame
def penguins_df():
return render.DataGrid(penguins)
@reactive.effect
@reactive.event(input.update_sorting)
async def _():
await penguins_df.update_sort(
[1, 0, {"col": 6, "desc": False}, 7],
)
@reactive.effect
@reactive.event(input.reset_sorting)
async def _():
await penguins_df.update_sort([])
app = App(app_ui, server)
Customize Summary Statement
Set summary
in render.DataGrid()
to False
to remove the statement “Viewing rows 1 through 10 of 20”. Set it to a string template containing {start}
, {end}
, and {total}
tokens, to customize the message.
#| standalone: true
#| components: [viewer]
#| viewerHeight: 350
from palmerpenguins import load_penguins
from shiny import App, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.data_frame
def penguins_df():
return render.DataGrid(
penguins,
summary="Viendo filas {start} a {end} de {total}",
)
app = App(app_ui, server)
from palmerpenguins import load_penguins
from shiny import App, render, ui
penguins = load_penguins()
app_ui = ui.page_fluid(
ui.h2("Palmer Penguins"),
ui.output_data_frame("penguins_df"),
)
def server(input, output, session):
@render.data_frame
def penguins_df():
return render.DataGrid(
penguins,
summary="Viendo filas {start} a {end} de {total}",
)
app = App(app_ui, server)