import altair as alt
from palmerpenguins import load_penguins
dat = load_penguins().dropna()
species = "Adelie" # selected species
sel = dat.loc[dat.species == species] # selected data
# base histogram for all data
base = (
alt.Chart(dat)
.mark_bar(color="#C2C2C4", binSpacing=0)
.encode(
alt.X("bill_length_mm:Q", bin=alt.Bin(step=1), title="bill_length_mm"),
alt.Y("count()", title="count"),
)
)
# overlay histogram for selected species
overlay = (
alt.Chart(sel)
.mark_bar(color="#447099", binSpacing=0)
.encode(alt.X("bill_length_mm:Q", bin=alt.Bin(step=1)), alt.Y("count()"))
)
# layer the charts
base + overlayYour first app
title: “Your first Shiny application”
Plan out your application data
- Start off with the data you have an some kind of data artifact without the interactivity
- Use a placeholder variable to apply the interactivity manually
Visualizing penguin data
Change the species
import altair as alt
from palmerpenguins import load_penguins
dat = load_penguins().dropna()
species = "Gentoo" # selected species
sel = dat.loc[dat.species == species] # selected data
# base histogram for all data
base = (
alt.Chart(dat)
.mark_bar(color="#C2C2C4", binSpacing=0)
.encode(
alt.X("bill_length_mm:Q", bin=alt.Bin(step=1), title="bill_length_mm"),
alt.Y("count()", title="count"),
)
)
# overlay histogram for selected species
overlay = (
alt.Chart(sel)
.mark_bar(color="#447099", binSpacing=0)
.encode(alt.X("bill_length_mm:Q", bin=alt.Bin(step=1)), alt.Y("count()"))
)
# layer the charts
base + overlayThe user interface
Best try to mock up or wireframe a UI before starting
Input Components Gallery: https://shiny.posit.co/py/components/#inputs
What might be a good component to use?
Run your application
- Positron/VS Code + Shiny Extension

Begin your application file names with app-* so you can use the play button.
- Command line:
shiny run --reload app.pyAdd in the figure
Now let’s add all that data and plotting code from earlier into our application.
If we just dump in our code, the application errors because it does not know what to do with the figure that’s trying to be printed.
Output will error
#| '!! shinylive warning !!': |
#| shinylive does not work in self-contained HTML documents.
#| Please set `embed-resources: false` in your metadata.
#| standalone: true
#| components: [editor, viewer]
#| layout: horizontal
from shiny import ui, render, App
import altair as alt
from palmerpenguins import load_penguins
dat = load_penguins().dropna()
app_ui = ui.page_fluid(
ui.input_radio_buttons(
id="species",
label="Species",
choices=["Adelie", "Gentoo", "Chinstrap"],
inline=True,
)
)
def server(input, output, session):
species = "Gentoo" # selected species
sel = dat.loc[dat.species == species] # selected data
# Base histogram for all data
base = (
alt.Chart(dat)
.mark_bar(color="#C2C2C4", binSpacing=0)
.encode(
alt.X("bill_length_mm:Q", bin=alt.Bin(step=1), title="bill_length_mm"),
alt.Y("count()", title="count"),
)
)
# Overlay histogram for selected species
overlay = (
alt.Chart(sel)
.mark_bar(color="#447099", binSpacing=0)
.encode(alt.X("bill_length_mm:Q", bin=alt.Bin(step=1)), alt.Y("count()"))
)
return base + overlay
app = App(app_ui, server)
Outputs (python core syntax + R)
Each output component has 2 parts:
ui.output_*call in the UI part of the application- each output needs to be wrapped in it’s own function with the corresponding output decorator. https://shiny.posit.co/py/components/#outputs
We now need to use one of the built-in Shiny output components,
plotninefigure (which is based onmatplotlib), plot output component.For example, we want to return a plot, so we will need to wrap our plotnine code, and decorate it with the
@render.plotdecorator.For altair (and jupyter widgets) we need to use the
shinywidgetspackage
Render plot output
...
from shinywidgets import render_altair, output_widget
...
app_ui = ui.page_fluid(
...
output_widget("plot"),
def server(input, output, session):
@render_altair
def plot():
dat = load_penguins().dropna()
...Don’t forget to return the object you want displayed in the function! Otherwise the output will not render.
Render plot output
#| '!! shinylive warning !!': |
#| shinylive does not work in self-contained HTML documents.
#| Please set `embed-resources: false` in your metadata.
#| standalone: true
#| components: [editor, viewer]
#| layout: horizontal
from shiny import ui, render, App
import altair as alt
from palmerpenguins import load_penguins
from shinywidgets import render_altair, output_widget
dat = load_penguins().dropna()
app_ui = ui.page_fluid(
ui.input_radio_buttons(
id="species",
label="Species",
choices=["Adelie", "Gentoo", "Chinstrap"],
inline=True,
),
output_widget("plot"),
)
def server(input, output, session):
@render_altair
def plot():
dat = load_penguins().dropna()
species = "Gentoo" # selected species
sel = dat.loc[dat.species == species] # selected data
# Base histogram for all data
base = (
alt.Chart(dat)
.mark_bar(color="#C2C2C4", binSpacing=0)
.encode(
alt.X("bill_length_mm:Q", bin=alt.Bin(step=1), title="bill_length_mm"),
alt.Y("count()", title="count"),
)
)
# Overlay histogram for selected species
overlay = (
alt.Chart(sel)
.mark_bar(color="#447099", binSpacing=0)
.encode(alt.X("bill_length_mm:Q", bin=alt.Bin(step=1)), alt.Y("count()"))
)
return base + overlay
app = App(app_ui, server)
Reactivity
But the radio buttons don’t change anything
We didn’t connect the input component to the output component
Reactivity is what makes Shiny unique
- More about reactivity next lecture
- tl;dr: use
input.ID()to read the input component value
The data reacts to the input
...
ui.input_radio_buttons(
id="species",
label="Species",
choices=["Adelie", "Gentoo", "Chinstrap"],
inline=True,
),
...
species = input.species()
...Your first application: altair
#| '!! shinylive warning !!': |
#| shinylive does not work in self-contained HTML documents.
#| Please set `embed-resources: false` in your metadata.
#| standalone: true
#| components: [editor, viewer]
#| layout: horizontal
#| viewerHeight: 500
from shiny import ui, render, App
import altair as alt
from palmerpenguins import load_penguins
from shinywidgets import render_altair, output_widget
dat = load_penguins().dropna()
app_ui = ui.page_fluid(
ui.input_radio_buttons(
id="species",
label="Species",
choices=["Adelie", "Gentoo", "Chinstrap"],
inline=True,
),
output_widget("plot"),
)
def server(input, output, session):
@render_altair
def plot():
species = input.species() # selected species
sel = dat.loc[dat.species == species] # selected data
# Base histogram for all data
base = (
alt.Chart(dat)
.mark_bar(color="#C2C2C4", binSpacing=0)
.encode(
alt.X("bill_length_mm:Q", bin=alt.Bin(step=1), title="bill_length_mm"),
alt.Y("count()", title="count"),
)
)
# Overlay histogram for selected species
overlay = (
alt.Chart(sel)
.mark_bar(color="#447099", binSpacing=0)
.encode(alt.X("bill_length_mm:Q", bin=alt.Bin(step=1)), alt.Y("count()"))
)
return base + overlay
app = App(app_ui, server)
Shiny + Altair
Components gallery docs are in a PR deployment preview (this is all very new docs!)
https://pr-326--pyshiny.netlify.app/components/outputs/plot-altair/
These docs will eventually be on the official components page