Shiny for Python




Deepsha Menghani

Who am I

Data Scientist manager at Microsoft…..

Self portrait.

The biggest career transition of my life!

Data Scientist manager at Microsoft…..

Self portrait.

And a parent as of a month ago!

Deepsha's puppy and baby hanging.

Let’s talk Shiny

Shiny: Started with R and now we Pythoning!

https://shiny.posit.co/py/

Shiny python dashboard example

Let’s create this dog characteristics dashboard

Data source: TidyTuesday

Shiny python dashboard example

Some initial setup


  1. Install Shiny for Python extension (For VSCode)
  2. Create a virtual environment for your project (just best practice)
  3. Install the required packages by either running individual commands like “pip install shiny” or installing all packages by running “pip install -r requirements.txt”

Shiny python dashboard example

The basic app commands and structure to get started

Shiny create - -help

Shiny python dashboard example

The base components

1.0 The code structure of a basic app

Shiny create -t basic-app

from shiny import App, render, ui

app_ui = ui.page_fluid(
    ui.panel_title("Hello Shiny!"),
    ui.input_slider("n", "N", 0, 100, 20),
    ui.output_text_verbatim("txt"),
)

def server(input, output, session):
    @render.text
    def txt():
        return f"n*2 is {input.n() * 2}"

app = App(app_ui, server)


Shiny python dashboard example

2.0 Personalizing the app

2.1 Adding a data frame output

from shiny import App, render, ui
import pandas as pd
from pathlib import Path

df = pd.read_csv(Path(__file__).parent / "dog_traits.csv", na_values = "NA")

app_ui = ui.page_fillable(
    ui.output_data_frame("dog_df")
)

def server(input, output, session):
    @render.data_frame
    def dog_df():
        return df
    
app = App(app_ui, server)


Shiny python dashboard example

2.2 Adding a plot output


from shiny import App, render, ui
import pandas as pd
from pathlib import Path
from trait_rating_plot import create_trait_rating_plot

df = pd.read_csv(Path(__file__).parent / "dog_traits.csv", na_values = "NA")

app_ui = ui.page_fillable(
    ui.output_data_frame("dog_df"),
    ui.output_plot("breed_plot")
)

def server(input, output, session):
    @render.data_frame
    def dog_df():
        return df
    
    @render.plot
    def breed_plot():
        fig = create_trait_rating_plot(df, "Bulldogs")
        return fig
    
app = App(app_ui, server)


Shiny python dashboard example

3.1 Adding sidebar layout and filters


from shiny import App, render, ui
import pandas as pd
from pathlib import Path
from trait_rating_plot import create_trait_rating_plot

df = pd.read_csv(Path(__file__).parent / "dog_traits.csv", na_values = "NA")
breeds = df.breed.unique().tolist()

app_ui = ui.page_fillable(
    ui.page_sidebar(
        ui.sidebar(
            ui.input_select("inputbreed", label = "Select breed", choices = breeds, selected="Bulldogs")
        ),
        ui.output_data_frame("dog_df"),
        ui.output_plot("breed_plot")
    ),
)

def server(input, output, session):
    @render.data_frame
    def dog_df():
        return df
    
    @render.plot
    def breed_plot():
        fig = create_trait_rating_plot(df, input.inputbreed())
        return fig
    
app = App(app_ui, server)


Shiny python dashboard example

3.2 Adding selectize filter


from shiny import App, render, ui
import pandas as pd
from pathlib import Path
from trait_rating_plot import create_trait_rating_plot

df = pd.read_csv(Path(__file__).parent / "dog_traits.csv", na_values = "NA")
breeds = df.breed.unique().tolist()
traits = df.trait.unique().tolist()

app_ui = ui.page_fillable(
    ui.page_sidebar(
        ui.sidebar(
            ui.input_select("inputbreed", label = "Select breed", choices = breeds, selected="Bulldogs"),
            ui.input_selectize(id = "inputtrait", label= "Select traits", choices = traits, multiple=True, selected="Adaptability Level"),
        ),
        ui.output_data_frame("dog_df"),
        ui.output_plot("breed_plot")
    ),
)

def server(input, output, session):
    @render.data_frame
    def dog_df():
        filtered_df = df[(df['trait'].isin(input.inputtrait()))]
        return filtered_df.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.plot
    def breed_plot():
        df_updated = df.copy()
        fig = create_trait_rating_plot(df_updated, input.inputbreed())
        return fig
    
app = App(app_ui, server)


Shiny python dashboard example

3.3 Adding slider inputs


from shiny import App, render, ui
import pandas as pd
from pathlib import Path
from trait_rating_plot import create_trait_rating_plot

df = pd.read_csv(Path(__file__).parent / "dog_traits.csv", na_values = "NA")
breeds = df.breed.unique().tolist()
traits = df.trait.unique().tolist()

app_ui = ui.page_fillable(
    ui.page_sidebar(
        ui.sidebar(
            ui.input_select("inputbreed", label = "Select breed", choices = breeds, selected="Bulldogs"),
            ui.input_selectize(id = "inputtrait", label= "Select traits", choices = traits, multiple=True, selected="Adaptability Level"),
            ui.input_slider(id = "ratingmin", label="Minimum rating", min=1, max=5, value=1),
            ui.input_slider(id = "ratingmax", label="Maximum rating", min=1, max=5, value=5),
        ),
        ui.output_data_frame("dog_df"),
        ui.output_plot("breed_plot")
    ),
)

def server(input, output, session):
    @render.data_frame
    def dog_df():
        filtered_df = df[(df['trait'].isin(input.inputtrait()))]
        return filtered_df.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.plot
    def breed_plot():
        df_updated = df.copy()
        fig = create_trait_rating_plot(df_updated, input.inputbreed())
        return fig
    
app = App(app_ui, server)


Shiny python dashboard example

3.4 Using reactive calc to filter across multiple outputs


from shiny import App, render, ui, reactive
import pandas as pd
from pathlib import Path
from trait_rating_plot import create_trait_rating_plot

df = pd.read_csv(Path(__file__).parent / "dog_traits.csv", na_values = "NA")
breeds = df.breed.unique().tolist()
traits = df.trait.unique().tolist()

app_ui = ui.page_fillable(
    ui.page_sidebar(
        ui.sidebar(
            ui.input_select("inputbreed", label = "Select breed", choices = breeds, selected="Bulldogs"),
            ui.input_selectize(id = "inputtrait", label= "Select traits", choices = traits, multiple=True, selected="Adaptability Level"),
            ui.input_slider(id = "ratingmin", label="Minimum rating", min=1, max=5, value=1),
            ui.input_slider(id = "ratingmax", label="Maximum rating", min=1, max=5, value=5),
        ),
        ui.output_data_frame("dog_df"),
        ui.output_plot("breed_plot")
    ),
)

def server(input, output, session):
    @reactive.Calc
    def filtered_ratings():
        filtered_rating = df[(df['rating'] >= input.ratingmin()) &
                     (df['rating'] <= input.ratingmax())]
        return filtered_rating.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.data_frame
    def dog_df():
        filtered_df = filtered_ratings()[(filtered_ratings()['trait'].isin(input.inputtrait()))]
        return filtered_df.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.plot
    def breed_plot():
        fig = create_trait_rating_plot(filtered_ratings(), input.inputbreed())
        return fig
    
app = App(app_ui, server)


Shiny python dashboard example

3.5 Action buttons


from shiny import App, render, ui, reactive
import pandas as pd
from pathlib import Path
from trait_rating_plot import create_trait_rating_plot

df = pd.read_csv(Path(__file__).parent / "dog_traits.csv", na_values = "NA")
breeds = df.breed.unique().tolist()
traits = df.trait.unique().tolist()

app_ui = ui.page_fillable(
    ui.page_sidebar(
        ui.sidebar(
            ui.input_select("inputbreed", label = "Select breed", choices = breeds, selected="Bulldogs"),
            ui.input_selectize(id = "inputtrait", label= "Select traits", choices = traits, multiple=True, selected="Adaptability Level"),
            ui.input_slider(id = "ratingmin", label="Minimum rating", min=1, max=5, value=1),
            ui.input_slider(id = "ratingmax", label="Maximum rating", min=1, max=5, value=5),
            ui.input_action_button("apply", "Apply settings", class_="btn-secondary"),
        ),
        ui.output_data_frame("dog_df"),
        ui.output_plot("breed_plot")
    ),
)

def server(input, output, session):
    @reactive.Calc
    def filtered_ratings():
        filtered_rating = df[(df['rating'] >= input.ratingmin()) &
                     (df['rating'] <= input.ratingmax())]
        return filtered_rating.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.data_frame
    @reactive.event(input.apply, ignore_none=False)
    def dog_df():
        filtered_df = filtered_ratings()[(filtered_ratings()['trait'].isin(input.inputtrait()))]
        return filtered_df.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.plot
    @reactive.event(input.apply, ignore_none=False)
    def breed_plot():
        fig = create_trait_rating_plot(filtered_ratings(), input.inputbreed())
        return fig
    
app = App(app_ui, server)


Shiny python dashboard example

4.0 Columns and ui.card layouts

4.1 Adding space around outputs with ui.card


from shiny import App, render, ui, reactive
import pandas as pd
from pathlib import Path
from trait_rating_plot import create_trait_rating_plot

df = pd.read_csv(Path(__file__).parent / "dog_traits.csv", na_values = "NA")
breeds = df.breed.unique().tolist()
traits = df.trait.unique().tolist()

app_ui = ui.page_fillable(
    ui.page_sidebar(
        ui.sidebar(
            ui.input_select("inputbreed", label = "Select breed", choices = breeds, selected="Bulldogs"),
            ui.input_selectize(id = "inputtrait", label= "Select traits", choices = traits, multiple=True, selected="Adaptability Level"),
            ui.input_slider(id = "ratingmin", label="Minimum rating", min=1, max=5, value=1),
            ui.input_slider(id = "ratingmax", label="Maximum rating", min=1, max=5, value=5),
            ui.input_action_button("apply", "Apply settings", class_="btn-secondary"),
        ),
        ui.card(
            ui.card_header("Select the traits to update this plot"),
            ui.output_data_frame("dog_df"),
        ),
        ui.card(
            ui.card_header("Select the breed to update this plot"),
            ui.output_plot("breed_plot")
        )
    ),
)

def server(input, output, session):
    @reactive.Calc
    def filtered_ratings():
        filtered_rating = df[(df['rating'] >= input.ratingmin()) &
                     (df['rating'] <= input.ratingmax())]
        return filtered_rating.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.data_frame
    @reactive.event(input.apply, ignore_none=False)
    def dog_df():
        filtered_df = filtered_ratings()[(filtered_ratings()['trait'].isin(input.inputtrait()))]
        return filtered_df.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.plot
    @reactive.event(input.apply, ignore_none=False)
    def breed_plot():
        fig = create_trait_rating_plot(filtered_ratings(), input.inputbreed())
        return fig
    
app = App(app_ui, server)


Shiny python dashboard example

4.2 Adding a column layout


from shiny import App, render, ui, reactive
import pandas as pd
from pathlib import Path
from trait_rating_plot import create_trait_rating_plot

df = pd.read_csv(Path(__file__).parent / "dog_traits.csv", na_values = "NA")
breeds = df.breed.unique().tolist()
traits = df.trait.unique().tolist()

app_ui = ui.page_fillable(
    ui.page_sidebar(
        ui.sidebar(
            ui.input_select("inputbreed", label = "Select breed", choices = breeds, selected="Bulldogs"),
            ui.input_selectize(id = "inputtrait", label= "Select traits", choices = traits, multiple=True, selected="Adaptability Level"),
            ui.input_slider(id = "ratingmin", label="Minimum rating", min=1, max=5, value=1),
            ui.input_slider(id = "ratingmax", label="Maximum rating", min=1, max=5, value=5),
            ui.input_action_button("apply", "Apply settings", class_="btn-secondary"),
        ),
        ui.layout_columns(
            ui.card(
            ui.card_header("Select the traits to update this plot"),
            ui.output_data_frame("dog_df"),
            ),
            ui.card(
                ui.card_header("Select the breed to update this plot"),
                ui.output_plot("breed_plot")
            ),
            gap = "2rem",
            col_widths={"sm": (5, 7)},
            height = "400px"
        )
    ),
)

def server(input, output, session):
    @reactive.Calc
    def filtered_ratings():
        filtered_rating = df[(df['rating'] >= input.ratingmin()) &
                     (df['rating'] <= input.ratingmax())]
        return filtered_rating.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.data_frame
    @reactive.event(input.apply, ignore_none=False)
    def dog_df():
        filtered_df = filtered_ratings()[(filtered_ratings()['trait'].isin(input.inputtrait()))]
        return filtered_df.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.plot
    @reactive.event(input.apply, ignore_none=False)
    def breed_plot():
        fig = create_trait_rating_plot(filtered_ratings(), input.inputbreed())
        return fig
    
app = App(app_ui, server)


Shiny python dashboard example

5.0 Images and text

5.1 Using tags to add images


from shiny import App, render, ui, reactive
import pandas as pd
from pathlib import Path
from trait_rating_plot import create_trait_rating_plot

df = pd.read_csv(Path(__file__).parent / "dog_traits.csv", na_values = "NA")
breeds = df.breed.unique().tolist()
traits = df.trait.unique().tolist()
dogimg_url = "https://camo.githubusercontent.com/97a9cd3442db4582637cacccfc9546801c05c4b98d23c23b85ffde9553a401f3/68747470733a2f2f6d656469612d636c646e72792e732d6e62636e6577732e636f6d2f696d6167652f75706c6f61642f6e657773636d732f323032305f32382f313538373636312f646f67732d6167652d79656172732d6b622d696e6c696e652d3230303730372e6a7067"

app_ui = ui.page_fillable(
    ui.page_sidebar(
        ui.sidebar(
            ui.input_select("inputbreed", label = "Select breed", choices = breeds, selected="Bulldogs"),
            ui.input_selectize(id = "inputtrait", label= "Select traits", choices = traits, multiple=True, selected="Adaptability Level"),
            ui.input_slider(id = "ratingmin", label="Minimum rating", min=1, max=5, value=1),
            ui.input_slider(id = "ratingmax", label="Maximum rating", min=1, max=5, value=5),
            ui.input_action_button("apply", "Apply settings", class_="btn-secondary"),
        ),
        ui.row(
            ui.column(6, ui.card(ui.tags.img(src=dogimg_url, height="100%", width="100%")))
        ),
        ui.layout_columns(
            ui.card(
            ui.card_header("Select the traits to update this plot"),
            ui.output_data_frame("dog_df"),
            ),
            ui.card(
                ui.card_header("Select the breed to update this plot"),
                ui.output_plot("breed_plot")
            ),
            gap = "2rem",
            col_widths={"sm": (5, 7)},
            height = "400px"
        )
    ),
)

def server(input, output, session):
    @reactive.Calc
    def filtered_ratings():
        filtered_rating = df[(df['rating'] >= input.ratingmin()) &
                     (df['rating'] <= input.ratingmax())]
        return filtered_rating.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.data_frame
    @reactive.event(input.apply, ignore_none=False)
    def dog_df():
        filtered_df = filtered_ratings()[(filtered_ratings()['trait'].isin(input.inputtrait()))]
        return filtered_df.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.plot
    @reactive.event(input.apply, ignore_none=False)
    def breed_plot():
        fig = create_trait_rating_plot(filtered_ratings(), input.inputbreed())
        return fig
    
app = App(app_ui, server)


Shiny python dashboard example

5.2 Tag headings and markdown text


from shiny import App, render, ui, reactive
import pandas as pd
from pathlib import Path
from trait_rating_plot import create_trait_rating_plot

df = pd.read_csv(Path(__file__).parent / "dog_traits.csv", na_values = "NA")
breeds = df.breed.unique().tolist()
traits = df.trait.unique().tolist()
dogimg_url = "https://camo.githubusercontent.com/97a9cd3442db4582637cacccfc9546801c05c4b98d23c23b85ffde9553a401f3/68747470733a2f2f6d656469612d636c646e72792e732d6e62636e6577732e636f6d2f696d6167652f75706c6f61642f6e657773636d732f323032305f32382f313538373636312f646f67732d6167652d79656172732d6b622d696e6c696e652d3230303730372e6a7067"

app_ui = ui.page_fillable(
    ui.page_sidebar(
        ui.sidebar(
            ui.input_select("inputbreed", label = "Select breed", choices = breeds, selected="Bulldogs"),
            ui.input_selectize(id = "inputtrait", label= "Select traits", choices = traits, multiple=True, selected="Adaptability Level"),
            ui.input_slider(id = "ratingmin", label="Minimum rating", min=1, max=5, value=1),
            ui.input_slider(id = "ratingmax", label="Maximum rating", min=1, max=5, value=5),
            ui.input_action_button("apply", "Apply settings", class_="btn-secondary"),
        ),
        ui.row(
            ui.column(6, ui.card(ui.tags.img(src=dogimg_url, height="100%", width="100%"))),
            ui.column(5, 
                ui.tags.h1("Who is the goodest doggy?!?"),
                ui.markdown("TidyTuesday dataset courtesy of [KKakey](https://github.com/kkakey/dog_traits_AKC/blob/main/README.md) sourced from the [American Kennel Club](https://www.akc.org/).")
            ),
        ),
        ui.layout_columns(
            ui.card(
            ui.card_header("Select the traits to update this plot"),
            ui.output_data_frame("dog_df"),
            ),
            ui.card(
                ui.card_header("Select the breed to update this plot"),
                ui.output_plot("breed_plot")
            ),
            gap = "2rem",
            col_widths={"sm": (5, 7)},
            height = "400px"
        )
    ),
)

def server(input, output, session):
    @reactive.Calc
    def filtered_ratings():
        filtered_rating = df[(df['rating'] >= input.ratingmin()) &
                     (df['rating'] <= input.ratingmax())]
        return filtered_rating.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.data_frame
    @reactive.event(input.apply, ignore_none=False)
    def dog_df():
        filtered_df = filtered_ratings()[(filtered_ratings()['trait'].isin(input.inputtrait()))]
        return filtered_df.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.plot
    @reactive.event(input.apply, ignore_none=False)
    def breed_plot():
        fig = create_trait_rating_plot(filtered_ratings(), input.inputbreed())
        return fig
    
app = App(app_ui, server)


Shiny python dashboard example

6.0 Panels

6.1 Draggable panels


from shiny import App, render, ui, reactive
import pandas as pd
from pathlib import Path
from trait_rating_plot import create_trait_rating_plot

df = pd.read_csv(Path(__file__).parent / "dog_traits.csv", na_values = "NA")
breeds = df.breed.unique().tolist()
traits = df.trait.unique().tolist()
dogimg_url = "https://camo.githubusercontent.com/97a9cd3442db4582637cacccfc9546801c05c4b98d23c23b85ffde9553a401f3/68747470733a2f2f6d656469612d636c646e72792e732d6e62636e6577732e636f6d2f696d6167652f75706c6f61642f6e657773636d732f323032305f32382f313538373636312f646f67732d6167652d79656172732d6b622d696e6c696e652d3230303730372e6a7067"

app_ui = ui.page_fillable(
    ui.page_sidebar(
        ui.sidebar(
            ui.input_select("inputbreed", label = "Select breed", choices = breeds, selected="Bulldogs"),
            ui.input_selectize(id = "inputtrait", label= "Select traits", choices = traits, multiple=True, selected="Adaptability Level"),
            ui.input_slider(id = "ratingmin", label="Minimum rating", min=1, max=5, value=1),
            ui.input_slider(id = "ratingmax", label="Maximum rating", min=1, max=5, value=5),
            ui.input_action_button("apply", "Apply settings", class_="btn-secondary"),
        ),
        ui.row(
            ui.column(6, ui.card(ui.tags.img(src=dogimg_url, height="100%", width="100%"))),
            ui.column(5,
                ui.panel_absolute(  
                    ui.panel_well(
                        ui.tags.h1("Who is the goodest doggy?!?"),
                        ui.markdown("TidyTuesday dataset courtesy of [KKakey](https://github.com/kkakey/dog_traits_AKC/blob/main/README.md) sourced from the [American Kennel Club](https://www.akc.org/).")
                    ),
                    width="450px",  
                    right="75px",  
                    draggable=False,  
                )
            ),
        ),
        ui.layout_columns(
            ui.card(
            ui.card_header("Select the traits to update this plot"),
            ui.output_data_frame("dog_df"),
            ),
            ui.card(
                ui.card_header("Select the breed to update this plot"),
                ui.output_plot("breed_plot")
            ),
            gap = "2rem",
            col_widths={"sm": (5, 7)},
            height = "400px"
        )
    ),
)

def server(input, output, session):
    @reactive.Calc
    def filtered_ratings():
        filtered_rating = df[(df['rating'] >= input.ratingmin()) &
                     (df['rating'] <= input.ratingmax())]
        return filtered_rating.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.data_frame
    @reactive.event(input.apply, ignore_none=False)
    def dog_df():
        filtered_df = filtered_ratings()[(filtered_ratings()['trait'].isin(input.inputtrait()))]
        return filtered_df.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.plot
    @reactive.event(input.apply, ignore_none=False)
    def breed_plot():
        fig = create_trait_rating_plot(filtered_ratings(), input.inputbreed())
        return fig
    
app = App(app_ui, server)


Shiny python dashboard example

6.2 Conditional panels


from shiny import App, render, ui, reactive
import pandas as pd
from pathlib import Path
from trait_rating_plot import create_trait_rating_plot

df = pd.read_csv(Path(__file__).parent / "dog_traits.csv", na_values = "NA")
breeds = df.breed.unique().tolist()
traits = df.trait.unique().tolist()
dogimg_url = "https://camo.githubusercontent.com/97a9cd3442db4582637cacccfc9546801c05c4b98d23c23b85ffde9553a401f3/68747470733a2f2f6d656469612d636c646e72792e732d6e62636e6577732e636f6d2f696d6167652f75706c6f61642f6e657773636d732f323032305f32382f313538373636312f646f67732d6167652d79656172732d6b622d696e6c696e652d3230303730372e6a7067"

app_ui = ui.page_fillable(
    ui.page_sidebar(
        ui.sidebar(
            ui.input_select("inputbreed", label = "Select breed", choices = breeds, selected="Bulldogs"),
            ui.input_selectize(id = "inputtrait", label= "Select traits", choices = traits, multiple=True, selected="Adaptability Level"),
            ui.input_checkbox("show", "Set limits for ratings", False),
            ui.panel_conditional(
                "input.show", 
                ui.input_slider(id = "ratingmin", label="Minimum rating", min=1, max=5, value=1),
                ui.input_slider(id = "ratingmax", label="Maximum rating", min=1, max=5, value=5),
            ),
            ui.input_action_button("apply", "Apply settings", class_="btn-secondary"),
        ),
        ui.row(
            ui.column(6, ui.card(ui.tags.img(src=dogimg_url, height="100%", width="100%"))),
            ui.column(5,
                ui.panel_absolute(  
                    ui.panel_well(
                        ui.tags.h1("Who is the goodest doggy?!?"),
                        ui.markdown("TidyTuesday dataset courtesy of [KKakey](https://github.com/kkakey/dog_traits_AKC/blob/main/README.md) sourced from the [American Kennel Club](https://www.akc.org/).")
                    ),
                    width="450px",  
                    right="75px",  
                    draggable=False,  
                )
            ),
        ),
        ui.layout_columns(
            ui.card(
            ui.card_header("Select the traits to update this plot"),
            ui.output_data_frame("dog_df"),
            ),
            ui.card(
                ui.card_header("Select the breed to update this plot"),
                ui.output_plot("breed_plot")
            ),
            gap = "2rem",
            col_widths={"sm": (5, 7)},
            height = "400px"
        )
    ),
)

def server(input, output, session):
    @reactive.Calc
    def filtered_ratings():
        filtered_rating = df[(df['rating'] >= input.ratingmin()) &
                     (df['rating'] <= input.ratingmax())]
        return filtered_rating.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.data_frame
    @reactive.event(input.apply, ignore_none=False)
    def dog_df():
        filtered_df = filtered_ratings()[(filtered_ratings()['trait'].isin(input.inputtrait()))]
        return filtered_df.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.plot
    @reactive.event(input.apply, ignore_none=False)
    def breed_plot():
        fig = create_trait_rating_plot(filtered_ratings(), input.inputbreed())
        return fig
    
app = App(app_ui, server)


Shiny python dashboard example

7.0 Themes

7.1 Updating sidebar color scheme


from shiny import App, render, ui, reactive
import pandas as pd
from pathlib import Path
from trait_rating_plot import create_trait_rating_plot

df = pd.read_csv(Path(__file__).parent / "dog_traits.csv", na_values = "NA")
breeds = df.breed.unique().tolist()
traits = df.trait.unique().tolist()
dogimg_url = "https://camo.githubusercontent.com/97a9cd3442db4582637cacccfc9546801c05c4b98d23c23b85ffde9553a401f3/68747470733a2f2f6d656469612d636c646e72792e732d6e62636e6577732e636f6d2f696d6167652f75706c6f61642f6e657773636d732f323032305f32382f313538373636312f646f67732d6167652d79656172732d6b622d696e6c696e652d3230303730372e6a7067"

app_ui = ui.page_fillable(
    ui.page_sidebar(
        ui.sidebar(
            ui.input_select("inputbreed", label = "Select breed", choices = breeds, selected="Bulldogs"),
            ui.input_selectize(id = "inputtrait", label= "Select traits", choices = traits, multiple=True, selected="Adaptability Level"),
            ui.input_checkbox("show", "Set limits for ratings", False),
            ui.panel_conditional(
                "input.show", 
                ui.input_slider(id = "ratingmin", label="Minimum rating", min=1, max=5, value=1),
                ui.input_slider(id = "ratingmax", label="Maximum rating", min=1, max=5, value=5),
            ),
            ui.input_action_button("apply", "Apply settings", class_="btn-secondary"),
            bg="#f6e7e8", open="open"
        ),
        ui.row(
            ui.column(6, ui.card(ui.tags.img(src=dogimg_url, height="100%", width="100%"))),
            ui.column(5,
                ui.panel_absolute(  
                    ui.panel_well(
                        ui.tags.h1("Who is the goodest doggy?!?"),
                        ui.markdown("TidyTuesday dataset courtesy of [KKakey](https://github.com/kkakey/dog_traits_AKC/blob/main/README.md) sourced from the [American Kennel Club](https://www.akc.org/).")
                    ),
                    width="450px",  
                    right="75px",  
                    draggable=False,  
                )
            ),
        ),
        ui.layout_columns(
            ui.card(
            ui.card_header("Select the traits to update this plot"),
            ui.output_data_frame("dog_df"),
            ),
            ui.card(
                ui.card_header("Select the breed to update this plot"),
                ui.output_plot("breed_plot")
            ),
            gap = "2rem",
            col_widths={"sm": (5, 7)},
            height = "400px"
        )
    ),
)

def server(input, output, session):
    @reactive.Calc
    def filtered_ratings():
        filtered_rating = df[(df['rating'] >= input.ratingmin()) &
                     (df['rating'] <= input.ratingmax())]
        return filtered_rating.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.data_frame
    @reactive.event(input.apply, ignore_none=False)
    def dog_df():
        filtered_df = filtered_ratings()[(filtered_ratings()['trait'].isin(input.inputtrait()))]
        return filtered_df.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.plot
    @reactive.event(input.apply, ignore_none=False)
    def breed_plot():
        fig = create_trait_rating_plot(filtered_ratings(), input.inputbreed())
        return fig
    
app = App(app_ui, server)


Shiny python dashboard example

7.2 Updating page theme


from shiny import App, render, ui, reactive
import pandas as pd
from pathlib import Path
from trait_rating_plot import create_trait_rating_plot
from shinyswatch import theme

df = pd.read_csv(Path(__file__).parent / "dog_traits.csv", na_values = "NA")
breeds = df.breed.unique().tolist()
traits = df.trait.unique().tolist()
dogimg_url = "https://camo.githubusercontent.com/97a9cd3442db4582637cacccfc9546801c05c4b98d23c23b85ffde9553a401f3/68747470733a2f2f6d656469612d636c646e72792e732d6e62636e6577732e636f6d2f696d6167652f75706c6f61642f6e657773636d732f323032305f32382f313538373636312f646f67732d6167652d79656172732d6b622d696e6c696e652d3230303730372e6a7067"

app_ui = ui.page_fillable(
    theme.minty(),
    ui.page_sidebar(
        ui.sidebar(
            ui.input_select("inputbreed", label = "Select breed", choices = breeds, selected="Bulldogs"),
            ui.input_selectize(id = "inputtrait", label= "Select traits", choices = traits, multiple=True, selected="Adaptability Level"),
            ui.input_checkbox("show", "Set limits for ratings", False),
            ui.panel_conditional(
                "input.show", 
                ui.input_slider(id = "ratingmin", label="Minimum rating", min=1, max=5, value=1),
                ui.input_slider(id = "ratingmax", label="Maximum rating", min=1, max=5, value=5),
            ),
            ui.input_action_button("apply", "Apply settings", class_="btn-secondary"),
            bg="#f6e7e8", open="open"
        ),
        ui.row(
            ui.column(6, ui.card(ui.tags.img(src=dogimg_url, height="100%", width="100%"))),
            ui.column(5,
                ui.panel_absolute(  
                    ui.panel_well(
                        ui.tags.h1("Who is the goodest doggy?!?"),
                        ui.markdown("TidyTuesday dataset courtesy of [KKakey](https://github.com/kkakey/dog_traits_AKC/blob/main/README.md) sourced from the [American Kennel Club](https://www.akc.org/).")
                    ),
                    width="450px",  
                    right="75px",  
                    draggable=False,  
                )
            ),
        ),
        ui.layout_columns(
            ui.card(
            ui.card_header("Select the traits to update this plot"),
            ui.output_data_frame("dog_df"),
            ),
            ui.card(
                ui.card_header("Select the breed to update this plot"),
                ui.output_plot("breed_plot")
            ),
            gap = "2rem",
            col_widths={"sm": (5, 7)},
            height = "400px"
        )
    ),
)

def server(input, output, session):
    @reactive.Calc
    def filtered_ratings():
        filtered_rating = df[(df['rating'] >= input.ratingmin()) &
                     (df['rating'] <= input.ratingmax())]
        return filtered_rating.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.data_frame
    @reactive.event(input.apply, ignore_none=False)
    def dog_df():
        filtered_df = filtered_ratings()[(filtered_ratings()['trait'].isin(input.inputtrait()))]
        return filtered_df.sort_values(by=["trait", "rating"], ascending=[True, False])
    
    @render.plot
    @reactive.event(input.apply, ignore_none=False)
    def breed_plot():
        fig = create_trait_rating_plot(filtered_ratings(), input.inputbreed())
        return fig
    
app = App(app_ui, server)


Shiny python dashboard example

We just created this app with “Core Shiny”

Shiny python dashboard example

But what about Shiny express?

Shiny core and express code structure

CORE
Shiny create -t basic-app
And then select Core Shiny

from shiny import App, render, ui

app_ui = ui.page_fluid(
    ui.panel_title("Hello Shiny!"),
    ui.input_slider("n", "N", 0, 100, 20),
    ui.output_text_verbatim("txt"),
)

def server(input, output, session):
    @render.text
    def txt():
        return f"n*2 is {input.n() * 2}"

app = App(app_ui, server)



Shiny python dashboard example

Shiny core and express code structure

CORE
Shiny create -t basic-app
And then select Core Shiny

from shiny import App, render, ui

app_ui = ui.page_fluid(
    ui.panel_title("Hello Shiny!"),
    ui.input_slider("n", "N", 0, 100, 20),
    ui.output_text_verbatim("txt"),
)

def server(input, output, session):
    @render.text
    def txt():
        return f"n*2 is {input.n() * 2}"

app = App(app_ui, server)


EXPRESS APP
Shiny create -t basic-app
And then select Shiny Express

from shiny import render, ui
from shiny.express import input

ui.panel_title("Hello Shiny!")
ui.input_slider("n", "N", 0, 100, 20)

@render.text
def txt():
    return f"n*2 is {input.n() * 2}"

Ui and server do not have to be separate in Shiny Express

Shiny create -t basic-app

from shiny import render, ui
from shiny.express import input

ui.panel_title("Hello Shiny!")
ui.input_slider("n", "N", 0, 100, 20)

@render.text
def txt():
    return f"n*2 is {input.n() * 2}"

ui.panel_title("Hello again Shiny!")
ui.input_slider("z", "Z", 50, 100, 70)

@render.text
def txt2():
    return f"Z*3 is {input.z() * 3}"


Shiny python dashboard example

But does that mean Shiny core will go away?

Is Shiny Core gonna stay?
Link: Shiny express announcement

When to use what?
Link: Shiny express announcement

How do I translate from one to another
Link: Shiny code examples

I know that was a lot of information!!!


TSwift screaming

Resources

Let’s connect

Mastodon: @deepsha

LinkedIn: deepshamenghani

Github: deepshamenghani


Slides qr code

QR code to slides.