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.express import render, ui

penguins = load_penguins()

ui.h2("Palmer Penguins")

@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"),
    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)
No matching items

Relevant Functions

No matching items

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:

  1. 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 of ui.output_data_frame() to a unique value.

  2. 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.

  3. 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 is the name of the function decorated with @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)
# shiny.express
from palmerpenguins import load_penguins
from shiny.express import render, ui

penguins = load_penguins()

ui.h2("Palmer Penguins")

@render.data_frame
def penguins_df():
    return render.DataGrid(penguins, filters=True)  
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.express import render, ui

penguins = load_penguins()

ui.h2("Palmer Penguins")

@render.data_frame
def penguins_df():
    return render.DataGrid(
        penguins,
        editable=True,  
    )
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.express import render, ui

penguins = load_penguins()

ui.h2("Palmer Penguins")

@render.data_frame
def penguins_df():
    return render.DataGrid(penguins, width="300px", height="250px")  
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.express import render, ui

penguins = load_penguins()

ui.h2("Palmer Penguins")

@render.data_frame
def penguins_df():
    return render.DataGrid(
        penguins,
        summary="Viendo filas {start} a {end} de {total}",  
    )
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)
No matching items