pythonpy-shiny

Change style of DataTable in Shiny for Python


I would like to set a background color in a Shiny for Python DataTable

from palmerpenguins import load_penguins
from shiny import render
from shiny.express import ui

penguins = load_penguins()

ui.h2("Palmer Penguins")

@render.data_frame
def penguins_df():
    return render.DataTable(
        penguins,
        summary="Viendo filas {start} a {end} de {total}",  
    )

example of data table

Using a similar question for RShiny I tried to add a style keyword argument to render.DataTable but got unexpected keyword argument error.

How can I specify styling arguments when rendering a DataTable ?


Solution

  • Updated answer, Shiny >= 1.0.0

    Shiny now supports basic cell styling. From the Release Notes:

    @render.data_frame's render.DataGrid and render.DataTable added support for cell styling with the new styles= parameter. This parameter can receive a style info object (or a list of style info objects), or a function that accepts a data frame and returns a list of style info objects. Each style info object can contain the rows and cols locations where the inline style and/or CSS class should be applied.

    If you e.g. want to set the background-color of the cells at positions [4, 3] and [10, 3] to yellow then such a style info object could look like this:

    {
        "location": "body",
        "rows": [4, 10],
        "cols": [3],
        "style": {
            "background-color": "yellow",
        },
    }
    

    Note: Currently it is not possible to set "location" to something else than "body", so if you want to style the header, then you might need another approach, see e.g. my original answer for Shiny < 1.0.0 below for an example. We might expect more changes in a future release, see for example posit-dev/py-shiny#1472.

    Below is an example which yields the following result:

    enter image description here

    from palmerpenguins import load_penguins
    from shiny import render
    from shiny.express import ui
    
    penguins = load_penguins()
    
    df_styles = [
        {
            "location": "body",
            "style": {
                "background-color": "lightblue",
                "border": "0.5px solid black"
            },
        },
        {
            "location": "body",
            "rows": [4, 5, 10],
            "cols": [3],
            "style": {
                "background-color": "yellow",
            },
        },
        {
            "location": "body",
            "rows": [2, 8, 9],
            "cols": [2, 4],
            "style": {
                "background-color": "yellow",
            },
        },
        {
            "location": "body",
            "rows": [2],
            "cols": [2, 4],
            "style": {
                "width": "100px",
                "height": "75px",
            },
        },
    ]
    
    ui.h2("Palmer Penguins")
    
    @render.data_frame
    def penguins_df():
        return render.DataTable(
            penguins,
            selection_mode=("rows"),
            editable=True,
            summary="Show entries {start} to {end} from {total}",
            styles=df_styles
        )
    

    Original answer, Shiny < 1.0.0

    The approach in the linked R question can't be used in a similar fashion in your example. When using render.DataTable one can make use of the fact that the generated table like Shiny in general provides Bootstrap by default. So in order to change the style we can edit CSS variables (also see the Bootstrap docs on CSS variables).

    In your example you would like to change the background color of the table, therefore we can apply this CSS as an example:

    .table thead tr {
      --bs-table-bg: #007bc2;
      --bs-table-color-state: white;
    }
    .table tbody tr{ 
      --bs-table-bg: lightblue;
    }
    

    The variable --bs-table-bg defines the background color in the table which I separately defined here for the header and the body. --bs-table-color-state: white provides a white font in the header. You can provide the CSS via ui.tags.style. Also have a look at the Bootstrap docs on tables for more details and styling possibilities of tables. In the below example it looks like this:

    enter image description here

    from palmerpenguins import load_penguins
    from shiny import render
    from shiny.express import ui
    from htmltools import Tag
    
    penguins = load_penguins()
    
    ui.h2("Palmer Penguins")
    
    ui.tags.style("""
                  .table thead tr {
                      --bs-table-bg: #007bc2;
                      --bs-table-color-state: white;
                  }
                  .table tbody tr{ 
                      --bs-table-bg: lightblue;
                  }
                  """)
    
    @render.data_frame
    def penguins_df():
        return render.DataTable(
            penguins,
            summary="Viendo filas {start} a {end} de {total}"
        )