Deploy Streamlit or Dash

Posit Connect Cloud supports many kinds of frameworks. All you need is a requirements.txt so Connect Cloud can build the environment.

We will build and deploy the same application as we did in the Shiny Express Lab

#| '!! 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 palmerpenguins import load_penguins
from plotnine import aes, geom_histogram, ggplot, theme_minimal
from shiny.express import input, render, ui

dat = load_penguins()
species = dat["species"].unique().tolist()

ui.input_radio_buttons("species", "Species", species, inline=True)


@render.plot
def plot():
    sel = dat[dat["species"] == input.species()]
    return (
        ggplot(aes(x="bill_length_mm"))
        + geom_histogram(dat, fill="#C2C2C4", binwidth=1)
        + geom_histogram(sel, fill="#447099", binwidth=1)
        + theme_minimal()
    )

Before you begin

Posit Connect Cloud deploys applications in a GitHub repository, make sure you have a GitHub repository set up to put the code we will use for this lab. You can do this lab completely within the web interface.

Then create the requirements.txt file.

requirements.txt
dash
plotly
pandas
palmerpenguins
plotnine
streamlit

Streamlit

Here’s an example Streamlit application. Save it to an app.py file. You can check out the Connect Cloud documentation to learn more about deploying Streamlit applicaitons to Connect Cloud

app.py
import streamlit as st
from palmerpenguins import load_penguins
from plotnine import aes, geom_histogram, ggplot, theme_minimal
import matplotlib.pyplot as plt

# Load the data
dat = load_penguins()
species = dat["species"].unique().tolist()

# Add radio button widget
selected_species = st.radio("Species", species, horizontal=True)

# Filter data based on selection
sel = dat[dat["species"] == selected_species]

# Create plot
plot = (
    ggplot(aes(x="bill_length_mm"))
    + geom_histogram(dat, fill="#C2C2C4", binwidth=1)
    + geom_histogram(sel, fill="#447099", binwidth=1)
    + theme_minimal()
)

# Display the plot
st.pyplot(ggplot.draw(plot))

Dash

Here’s an example Dash application. Save this to an app.py file. You can check out the Connect Cloud documentation to learn more about deploying Dash applications to Connect Cloud

app.py
import dash
from dash import dcc, html
from dash.dependencies import Input, Output
import plotly.express as px
import plotly.graph_objects as go
from palmerpenguins import load_penguins

# Initialize the Dash app
app = dash.Dash(__name__)

# Load the data
dat = load_penguins()
species = dat["species"].unique().tolist()

# Define the layout
app.layout = html.Div([
    html.H1("Palmer Penguins Bill Length"),

    # Radio buttons for species selection
    html.Div([
        html.Label("Species:"),
        dcc.RadioItems(
            id='species-radio',
            options=[{'label': s, 'value': s} for s in species],
            value=species[0],
            inline=True
        )
    ]),

    # Graph container
    dcc.Graph(id='histogram-plot')
])

# Callback to update the plot based on species selection
@app.callback(
    Output('histogram-plot', 'figure'),
    Input('species-radio', 'value')
)
def update_plot(selected_species):
    # Create two histogram traces
    # 1. All penguins (light gray)
    all_penguins = go.Histogram(
        x=dat["bill_length_mm"].dropna(),
        xbins=dict(size=1),
        marker_color='#C2C2C4',
        name='All Penguins'
    )

    # 2. Selected species (blue)
    sel = dat[dat["species"] == selected_species]
    selected_penguins = go.Histogram(
        x=sel["bill_length_mm"].dropna(),
        xbins=dict(size=1),
        marker_color='#447099',
        name=f'{selected_species}'
    )

    # Create the figure
    fig = go.Figure(data=[all_penguins, selected_penguins])

    # Update layout
    fig.update_layout(
        title=f'Bill Length Distribution',
        xaxis_title='Bill Length (mm)',
        yaxis_title='Count',
        barmode='overlay',
        template='plotly_white',
        showlegend=False
    )

    return fig

# Run the app
if __name__ == '__main__':
    app.run()

Here’s a version that uses plotnine

from palmerpenguins import load_penguins
# Set matplotlib backend to non-GUI 'Agg' before importing plotnine
# Matplotlib is trying to create GUI elements outside the main thread, which is not allowed on macOS.
# common issue when using plotting libraries that rely on Matplotlib in threaded web applications
import matplotlib
matplotlib.use('Agg')
from plotnine import aes, geom_histogram, ggplot, theme_minimal
import dash
from dash import dcc, html, Input, Output
import plotly.graph_objects as go
from io import BytesIO
import base64

# Load the data
dat = load_penguins()
species = dat["species"].unique().tolist()

# Initialize the Dash app
app = dash.Dash(__name__)

# Define the layout
app.layout = html.Div([
    html.H1("Palmer Penguins"),

    # Radio buttons for species selection
    html.Div([
        html.Label("Species"),
        dcc.RadioItems(
            id="species",
            options=[{"label": s, "value": s} for s in species],
            value=species[0],  # Default to first species
            inline=True
        )
    ]),

    # Image component to display the plotnine plot
    html.Img(id='plot-image')
])

# Define callback to update the plot based on species selection
@app.callback(
    Output('plot-image', 'src'),
    Input('species', 'value')
)
def update_plot(selected_species):
    # Filter data for selected species
    sel = dat[dat["species"] == selected_species]

    # Create the plotnine plot
    plot = (
        ggplot(aes(x="bill_length_mm"))
        + geom_histogram(dat, fill="#C2C2C4", binwidth=1)
        + geom_histogram(sel, fill="#447099", binwidth=1)
        + theme_minimal()
    )

    # Save the plot to a BytesIO object
    img_buffer = BytesIO()
    plot.save(img_buffer, format="png", dpi=100, width=8, height=6, units="in")
    img_buffer.seek(0)

    # Convert to base64 for displaying in the Dash app
    img_str = base64.b64encode(img_buffer.read()).decode()

    return f'data:image/png;base64,{img_str}'

# Run the app
if __name__ == '__main__':
    app.run()

Deploy

We’ll be deploying our shiny application to Connect Cloud. Here are the steps to publish your application.

  1. Click the Publish icon button on the top of your Portfolio page
  2. Select Shiny
  3. Select the public repository that you created in this tutorial
  4. Confirm the branch
  5. Select app.py as the primary file
  6. Click Publish

Publishing will display status updates during the deployment process. You will also find build logs streaming on the lower part of the screen.

Congratulations! You successfully deployed to Connect Cloud and are now able to share the link with others.

Redeploy

If you update the code to your application or the underlying data source, commit and push the changes to your GitHub repository.

Once the repository has the updated code, you can republish the application on Connect Cloud by going to your Content List and clicking the republish icon.