[Python] Interactive Visualizations with Plotly and Deployment with Netlify

Static charts are great for printed reports and PDFs. But when your audience is viewing your work on a screen, interactivity can help them engage more deeply with the data. This post introduces Plotly, a Python library for creating interactive visualizations where users can hover for details, zoom into regions of interest, and filter data.

The Interactive Visualization

Before diving into Plotly, let’s browse the options for creating interactive visualizations. Different tools serve different purposes:

Paid Platforms (no coding required):

  • ArcGIS StoryMaps combines maps, images, text, and multimedia into scrolling narratives. The White House has used StoryMaps to explain infrastructure initiatives; members of Congress use them to show how policies affect specific districts. StoryMaps are particularly powerful when geography is central to your argument. Esri offers free accounts for students.
  • Tableau Public is a free version of the popular business intelligence tool. You can create dashboards and publish them online. Many newsrooms use Tableau for data journalism.
  • Flourish and Datawrapper are web-based tools popular with journalists. No coding needed, but less customizable than Python-based solutions.

Code-Based Tools:

  • Plotly (Python, R, JavaScript) creates interactive charts that export as HTML. This is what we’ll learn today.
  • Shiny (R) is the gold standard for interactive dashboards in the R ecosystem. If you know R, Shiny is excellent. Posit (formerly RStudio) is also developing Shiny for Python, though it’s still maturing compared to the R version.
  • Streamlit (Python) is what we’ll cover in Part 2. It’s simpler than Shiny and growing rapidly in popularity.
  • Bokeh and Altair are other Python options. Altair is particularly elegant if you like the grammar of graphics approach.

We will focus on Plotly (for individual interactive charts) and Streamlit (for dashboards) because they’re beginner-friendly, well-documented, and widely used in data science.

When Does Interactivity Help?

https://www.opportunityatlas.org/

As an example, Opportunity Atlas is an interactive map showing economic mobility across every Census tract in the United States. You can zoom into your neighborhood, hover to see specific statistics, and filter by demographic groups. This kind of exploration would be impossible with a static image. The dataset is too large, and different users have different questions.

Interactivity is most valuable when:

  • The dataset is large or dense. Hovering lets users explore individual cases without cluttering the view.
  • Users have different questions. A state administrator might filter to their region; a researcher might compare across regions.
  • Exploration is the goal. When you want users to discover patterns themselves.

Interactivity can hurt or not helpful at all comprehension when the message is simple. If your point is “New Mexico’s rate is 4x Utah’s,” a static bar chart communicates that instantly. It’s also not helpful when users are skimming. Busy policymakers won’t hover over every point.

Plotly vs. Matplotlib

FeatureMatplotlibPlotly
OutputStatic images (PNG, PDF)Interactive HTML
InteractivityNoneHover, zoom, pan, click
Best forPrint, PDFsWeb dashboards, exploration
File sizeSmallLarger (includes JavaScript)
Python
### 1. DATA SET-UP
# Install if needed
# !pip install plotly openpyxl

import plotly.express as px
import pandas as pd

# Load SNAP data from USDA ERS
df = pd.read_excel('state_participation_rate_map.xlsx', skiprows=1)
df.columns = ['State', 'SNAP_Rate']
df['SNAP_Rate'] = pd.to_numeric(df['SNAP_Rate'], errors='coerce')
df = df.dropna()

# Add region information
region_mapping = {
    'Connecticut': 'Northeast', 'Maine': 'Northeast', 'Massachusetts': 'Northeast',
    'New Hampshire': 'Northeast', 'Rhode Island': 'Northeast', 'Vermont': 'Northeast',
    'New Jersey': 'Northeast', 'New York': 'Northeast', 'Pennsylvania': 'Northeast',
    'Illinois': 'Midwest', 'Indiana': 'Midwest', 'Michigan': 'Midwest',
    'Ohio': 'Midwest', 'Wisconsin': 'Midwest', 'Iowa': 'Midwest',
    'Kansas': 'Midwest', 'Minnesota': 'Midwest', 'Missouri': 'Midwest',
    'Nebraska': 'Midwest', 'North Dakota': 'Midwest', 'South Dakota': 'Midwest',
    'Delaware': 'South', 'Florida': 'South', 'Georgia': 'South',
    'Maryland': 'South', 'North Carolina': 'South', 'South Carolina': 'South',
    'Virginia': 'South', 'District of Columbia': 'South', 'West Virginia': 'South',
    'Alabama': 'South', 'Kentucky': 'South', 'Mississippi': 'South',
    'Tennessee': 'South', 'Arkansas': 'South', 'Louisiana': 'South',
    'Oklahoma': 'South', 'Texas': 'South',
    'Arizona': 'West', 'Colorado': 'West', 'Idaho': 'West',
    'Montana': 'West', 'Nevada': 'West', 'New Mexico': 'West',
    'Utah': 'West', 'Wyoming': 'West', 'Alaska': 'West',
    'California': 'West', 'Hawaii': 'West', 'Oregon': 'West', 'Washington': 'West'
}
df['Region'] = df['State'].map(region_mapping)
df = df.sort_values('SNAP_Rate', ascending=True)

# Define consistent colors for all charts
region_colors = {
    'South': '#B22234',
    'Midwest': '#2ca02c',
    'West': '#1f77b4',
    'Northeast': '#9467bd'
}

print(df.head())

Chart Type 1: Bar Chart

The most common chart for comparing categories. Horizontal bars work well when you have many categories or long labels:

Python
fig = px.bar(df, 
             x='SNAP_Rate', 
             y='State', 
             orientation='h',
             color='Region',
             color_discrete_map=region_colors,
             title='SNAP Participation Rates by State (FY 2024)')

fig.update_layout(
    height=800,
    xaxis_title='SNAP Participation Rate (%)',
    yaxis_title='',
    xaxis_range=[0, 25]
)

# Add national average line
national_avg = df['SNAP_Rate'].mean()
fig.add_vline(x=national_avg, line_dash='dash', line_color='gray',
              annotation_text=f'Avg: {national_avg:.1f}%')

fig.show()

Try hovering over any bar to see the exact value. With 51 states, this interactivity is useful.

Chart Type 2: Histogram

Histograms show the distribution of a single variable. How are SNAP rates distributed across states?

Python
fig = px.histogram(df, 
                   x='SNAP_Rate',
                   nbins=15,
                   color='Region',
                   color_discrete_map=region_colors,
                   title='Distribution of SNAP Participation Rates')

fig.update_layout(
    xaxis_title='SNAP Participation Rate (%)',
    yaxis_title='Number of States',
    bargap=0.1
)

fig.show()

Hover over each bar to see exactly how many states fall in that range. The histogram reveals that most states cluster between 8-15%, with a few outliers on both ends.

Chart Type 3: Box Plot

Box plots show distribution statistics (median, quartiles, outliers) for each group:

Python
fig = px.box(df, 
             x='Region', 
             y='SNAP_Rate',
             color='Region',
             color_discrete_map=region_colors,
             points='all',  # Show individual data points
             title='SNAP Rates by Region')

fig.update_layout(
    xaxis_title='Region',
    yaxis_title='SNAP Participation Rate (%)',
    showlegend=False
)

fig.show()

The points='all' parameter shows every state as a dot alongside the box. Hover over any dot to see which state it represents. This reveals that the South has the widest spread, while the Northeast clusters more tightly.

Chart Type 4: Pie and Donut Charts

Pie charts show parts of a whole. Let’s see what proportion of states fall into each region:

# Count states per region
region_counts = df['Region'].value_counts().reset_index()
region_counts.columns = ['Region', 'Count']

fig = px.pie(region_counts, 
             values='Count', 
             names='Region',
             color='Region',
             color_discrete_map=region_colors,
             title='Number of States by Region')

fig.show()

For a donut chart (pie with a hole), add the hole parameter:

fig = px.pie(region_counts, 
             values='Count', 
             names='Region',
             color='Region',
             color_discrete_map=region_colors,
             hole=0.4,  # Creates donut chart
             title='Number of States by Region')

fig.update_traces(textposition='inside', textinfo='percent+label')
fig.show()

A word of caution: pie charts are often criticized because humans are bad at comparing angles. Bar charts are usually better for precise comparisons. Use pie charts sparingly, mainly when you want to emphasize “part of a whole” relationships.

Chart Type 5: Scatter Plot

Scatter plots show relationships between two variables. Let’s add poverty rate data to explore whether states with higher poverty have higher SNAP participation and that association is similar/different across regions. Poverty rate can be downloaded here in KFF website: https://www.kff.org/state-health-policy-data/state-indicator/poverty-rate-by-raceethnicity/

Python
### 1. DATA LOADING
# Load poverty rate data from KFF
# Source: https://www.kff.org/state-health-policy-data/state-indicator/poverty-rate-by-raceethnicity/
poverty_df = pd.read_csv('raw_data.csv', skiprows=2)

# Clean the data
poverty_df['Total'] = pd.to_numeric(poverty_df['Total'], errors='coerce')
poverty_df = poverty_df[poverty_df['Total'].notna()]
poverty_df = poverty_df[~poverty_df['Location'].isin(['United States', 'Puerto Rico'])]
poverty_df = poverty_df.rename(columns={'Location': 'State'})

# Convert to percentages and select columns
for col in ['White', 'Black', 'Hispanic', 'Total']:
    poverty_df[col] = pd.to_numeric(poverty_df[col], errors='coerce') * 100

poverty_df = poverty_df[['State', 'White', 'Black', 'Hispanic', 'Total']].copy()
poverty_df.columns = ['State', 'Poverty_White', 'Poverty_Black', 'Poverty_Hispanic', 'Poverty_Total']

# Merge with SNAP data
df = df.merge(poverty_df, on='State', how='inner')

print(df[['State', 'SNAP_Rate', 'Poverty_Total', 'Poverty_White', 'Poverty_Black']].head())

### 2. SCATTER PLOT
fig = px.scatter(df,
                 x='Poverty_Total',
                 y='SNAP_Rate',
                 color='Region',
                 color_discrete_map=region_colors,
                 hover_name='State',
                 title='SNAP Participation vs. Overall Poverty Rate',
                 trendline='ols')

fig.update_layout(
    xaxis_title='Poverty Rate (%)',
    yaxis_title='SNAP Participation Rate (%)'
)

fig.show()

The hover_name='State' makes state names appear prominently when hovering. The trendline='ols' adds a linear regression line to show the overall relationship.

The correlation is 0.63, a moderately strong positive relationship. States with higher poverty rates tend to have higher SNAP participation, which makes sense since SNAP targets low-income households. However, the association is stronger in West region (R2 = 0.71) weaker in South region (R2 = 0.38). You can see it visually with the slope of each line.

Chart Type 6: Choropleth Map

Maps are powerful for geographic data. Plotly can create choropleth maps (maps where regions are colored by a value):

Python
# State abbreviations needed for the map
state_abbrev = {
    'Alabama': 'AL', 'Alaska': 'AK', 'Arizona': 'AZ', 'Arkansas': 'AR',
    'California': 'CA', 'Colorado': 'CO', 'Connecticut': 'CT', 'Delaware': 'DE',
    'District of Columbia': 'DC', 'Florida': 'FL', 'Georgia': 'GA', 'Hawaii': 'HI',
    'Idaho': 'ID', 'Illinois': 'IL', 'Indiana': 'IN', 'Iowa': 'IA',
    'Kansas': 'KS', 'Kentucky': 'KY', 'Louisiana': 'LA', 'Maine': 'ME',
    'Maryland': 'MD', 'Massachusetts': 'MA', 'Michigan': 'MI', 'Minnesota': 'MN',
    'Mississippi': 'MS', 'Missouri': 'MO', 'Montana': 'MT', 'Nebraska': 'NE',
    'Nevada': 'NV', 'New Hampshire': 'NH', 'New Jersey': 'NJ', 'New Mexico': 'NM',
    'New York': 'NY', 'North Carolina': 'NC', 'North Dakota': 'ND', 'Ohio': 'OH',
    'Oklahoma': 'OK', 'Oregon': 'OR', 'Pennsylvania': 'PA', 'Rhode Island': 'RI',
    'South Carolina': 'SC', 'South Dakota': 'SD', 'Tennessee': 'TN', 'Texas': 'TX',
    'Utah': 'UT', 'Vermont': 'VT', 'Virginia': 'VA', 'Washington': 'WA',
    'West Virginia': 'WV', 'Wisconsin': 'WI', 'Wyoming': 'WY'
}

df['State_Abbrev'] = df['State'].map(state_abbrev)

fig = px.choropleth(df,
                    locations='State_Abbrev',
                    locationmode='USA-states',
                    color='SNAP_Rate',
                    color_continuous_scale='Reds',
                    scope='usa',
                    title='SNAP Participation Rates by State (FY 2024)',
                    labels={'SNAP_Rate': 'SNAP Rate (%)'})

fig.update_layout(
    geo=dict(bgcolor='rgba(0,0,0,0)'),
    margin=dict(l=0, r=0, t=50, b=0)
)

fig.show()

Hover over any state to see its exact rate. The map immediately reveals geographic patterns.

Chart Type 7: Line Chart (Time Series)

Line charts are ideal for showing change over time. Let’s use real historical SNAP data from the U.S. Census Bureau’s American Community Survey.

The data was retrieved using the Census API. For a tutorial on how to pull Census data yourself, see: Working with the Census API in Python. You can also download here for practice.

Python
# Load historical SNAP data (2010-2023)
# Source: U.S. Census Bureau, American Community Survey via Census API
ts_df = pd.read_csv('snap_state_2013_2022.csv')

print(ts_df.head())
print(f"Years available: {ts_df['year'].min()} - {ts_df['year'].max()}")

# Calculate national average by year
national_trend = ts_df.groupby('year')['pct_snap'].mean().reset_index()
national_trend.columns = ['Year', 'SNAP_Rate']

fig = px.line(national_trend, 
              x='Year', 
              y='SNAP_Rate',
              markers=True,
              title='Average SNAP Participation Rate Over Time (2010-2023)')

fig.update_layout(
    xaxis_title='Year',
    yaxis_title='SNAP Participation Rate (%)',
    hovermode='x unified'
)

fig.show()

The hovermode='x unified' creates a single tooltip showing all series values when you hover at any x-position.

Now let’s compare specific states:

Python
# Select a few states to compare
states_to_compare = ['California', 'Texas', 'New York', 'Louisiana', 'Utah']
compare_df = ts_df[ts_df['state_name'].isin(states_to_compare)]

fig = px.line(compare_df, 
              x='year', 
              y='pct_snap',
              color='state_name',
              markers=True,
              title='SNAP Participation Trends: Selected States')

fig.update_layout(
    xaxis_title='Year',
    yaxis_title='SNAP Participation Rate (%)',
    legend_title='State',
    hovermode='x unified'
)

fig.show()


The hovermode='x unified' creates a single tooltip showing all states’ values when you hover at any year. This makes comparison easy.

You can also let users select which states to display using a dropdown:

Python
# Create dropdown for state selection
fig = px.line(ts_df, 
              x='year', 
              y='pct_snap',
              color='state_name',
              title='SNAP Participation by State (2010-2023)')

# Add dropdown menu
fig.update_layout(
    updatemenus=[
        dict(
            active=0,
            buttons=[
                dict(label="All States",
                     method="update",
                     args=[{"visible": [True] * len(ts_df['state_name'].unique())}]),
                dict(label="Top 5 (2023)",
                     method="update", 
                     args=[{"visible": [name in ['Louisiana', 'New Mexico', 'West Virginia', 
                                                  'Mississippi', 'Oklahoma'] 
                            for name in ts_df['state_name'].unique()]}]),
                dict(label="Bottom 5 (2023)",
                     method="update",
                     args=[{"visible": [name in ['Utah', 'New Hampshire', 'Wyoming', 
                                                  'North Dakota', 'Colorado'] 
                            for name in ts_df['state_name'].unique()]}]),
            ],
            direction="down",
            x=0.1,
            y=1.15
        )
    ],
    xaxis_title='Year',
    yaxis_title='SNAP Participation Rate (%)',
    legend_title='State',
    height=600
)

fig.show()

This adds a dropdown menu that lets users filter which states are displayed. The “Top 5” and “Bottom 5” refer to 2023 participation rates.

Chart Type 8: Animated Charts

Plotly can animate charts to show change over time. This is powerful for presentations:

Python
# Load time series data
ts_df = pd.read_csv('snap_state_2013_2022.csv')

# Add state abbreviations for the map
state_abbrev = {
    'Alabama': 'AL', 'Alaska': 'AK', 'Arizona': 'AZ', 'Arkansas': 'AR',
    'California': 'CA', 'Colorado': 'CO', 'Connecticut': 'CT', 'Delaware': 'DE',
    'District of Columbia': 'DC', 'Florida': 'FL', 'Georgia': 'GA', 'Hawaii': 'HI',
    'Idaho': 'ID', 'Illinois': 'IL', 'Indiana': 'IN', 'Iowa': 'IA',
    'Kansas': 'KS', 'Kentucky': 'KY', 'Louisiana': 'LA', 'Maine': 'ME',
    'Maryland': 'MD', 'Massachusetts': 'MA', 'Michigan': 'MI', 'Minnesota': 'MN',
    'Mississippi': 'MS', 'Missouri': 'MO', 'Montana': 'MT', 'Nebraska': 'NE',
    'Nevada': 'NV', 'New Hampshire': 'NH', 'New Jersey': 'NJ', 'New Mexico': 'NM',
    'New York': 'NY', 'North Carolina': 'NC', 'North Dakota': 'ND', 'Ohio': 'OH',
    'Oklahoma': 'OK', 'Oregon': 'OR', 'Pennsylvania': 'PA', 'Rhode Island': 'RI',
    'South Carolina': 'SC', 'South Dakota': 'SD', 'Tennessee': 'TN', 'Texas': 'TX',
    'Utah': 'UT', 'Vermont': 'VT', 'Virginia': 'VA', 'Washington': 'WA',
    'West Virginia': 'WV', 'Wisconsin': 'WI', 'Wyoming': 'WY', 'Puerto Rico': 'PR'
}

ts_df['State_Abbrev'] = ts_df['state_name'].map(state_abbrev)

# Create animated choropleth
fig = px.choropleth(ts_df,
                    locations='State_Abbrev',
                    locationmode='USA-states',
                    color='pct_snap',
                    color_continuous_scale='Reds',
                    scope='usa',
                    animation_frame='year',
                    hover_name='state_name',
                    title='SNAP Participation Rate by State (2010-2023)',
                    labels={'pct_snap': 'SNAP Rate (%)'})

fig.update_layout(
    geo=dict(bgcolor='rgba(0,0,0,0)'),
    margin=dict(l=0, r=0, t=50, b=0)
)

fig.show()

Press the play button to watch rates change from 2010 to 2023.

Customizing Hover Information

One of Plotly’s biggest strengths is customizable tooltips:

Python
fig = px.bar(df.head(20), 
             x='SNAP_Rate', 
             y='State', 
             orientation='h',
             color='Region',
             color_discrete_map=region_colors,
             custom_data=['Region'])

fig.update_traces(
    hovertemplate=
        '<b>%{y}</b><br>' +
        'SNAP Rate: %{x:.1f}%<br>' +
        'Region: %{customdata[0]}' +
        '<extra></extra>'
)

fig.update_layout(title='Top 20 States by SNAP Participation')
fig.show()

The hovertemplate uses placeholders: %{y} for y-value, %{x} for x-value, %{customdata[0]} for extra data. The <extra></extra> hides the default secondary box.

Saving and Exporting

Python
# Save as interactive HTML (anyone can open in browser)
fig.write_html('snap_interactive.html')

# Save as static image (requires kaleido)
# !pip install kaleido
fig.write_image('snap_chart.png', scale=2)  # scale=2 for high resolution
fig.write_image('snap_chart.pdf')           # Vector format

Deploying to the Web

Deploying to the Web

You’ve created interactive charts. Now you want to share them with others via a URL. Let’s walk through the actual process step by step.

What You’re Deploying

When you call fig.write_html('my_chart.html'), Plotly creates a self-contained HTML file. This file includes your data, the chart specification, and the Plotly JavaScript library (~3MB). Anyone can open this HTML file in a browser and interact with your chart. No Python needed on their end.

Option 1: GitHub Pages (Free, Version-Controlled)

Step 1: Create your HTML files locally

Python
# Save your charts
fig1.write_html('chart1.html')
fig2.write_html('chart2.html')

Step 2: Create an index.html that links to your charts

Create a file called index.html in a text editor:

HTML
<!DOCTYPE html>
<html>
<head>
    <title>SNAP Data Visualizations</title>
    <style>
        body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
        h1 { color: #333; }
        ul { line-height: 2; }
        a { color: #1f77b4; }
    </style>
</head>
<body>
    <h1>SNAP Participation Analysis</h1>
    <p>Interactive visualizations exploring SNAP participation rates across U.S. states.</p>
    
    <h2>Charts</h2>
    <ul>
        <li><a href="chart1.html">SNAP Participation by State</a></li>
        <li><a href="chart2.html">SNAP vs Poverty Rate</a></li>
    </ul>
    
    <p><small>Data sources: USDA ERS, KFF State Health Facts</small></p>
</body>
</html>

Step 3: Create a GitHub repository

  1. Go to github.com and sign in (create account if needed)
  2. Click the + icon in top right → New repository
  3. Name it something like snap-visualization
  4. Check “Add a README file”
  5. Click Create repository

Step 4: Upload your files

  1. In your new repository, click Add fileUpload files
  2. Drag all three files: index.html, chart1.html, chart2.html
  3. Scroll down, add a commit message like “Add visualization files”
  4. Click Commit changes

Step 5: Enable GitHub Pages

  1. In your repository, click Settings (tab at the top)
  2. In the left sidebar, click Pages
  3. Under “Source”, select Deploy from a branch
  4. Under “Branch”, select main and / (root)
  5. Click Save

Step 6: Access your site

Wait 1-2 minutes, then visit: https://YOUR-USERNAME.github.io/snap-visualization/

Option 2: Netlify Drop (VERY EASY!)

  1. Create a folder on your computer with index.html and your chart files
  2. Go to app.netlify.com/drop
  3. Drag your entire folder onto the page
  4. Done! You get a URL like https://jade-fairy-a1b2c3.netlify.app

No account needed. Perfect for quick sharing.

Embedding Multiple Charts in One Page

Instead of separate HTML files, put all charts on one scrollable page:

Python
# Save charts without the full HTML wrapper
fig1.write_html('temp1.html', full_html=False, include_plotlyjs=False)
fig2.write_html('temp2.html', full_html=False, include_plotlyjs=False)

# Read the chart divs
with open('temp1.html', 'r') as f:
    chart1_div = f.read()
with open('temp2.html', 'r') as f:
    chart2_div = f.read()

# Create combined HTML
combined_html = f'''
<!DOCTYPE html>
<html>
<head>
    <title>SNAP Analysis Dashboard</title>
    <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
    <style>
        body {{ font-family: Arial, sans-serif; max-width: 1200px; margin: 0 auto; padding: 20px; }}
        .chart-container {{ margin-bottom: 40px; }}
    </style>
</head>
<body>
    <h1>SNAP Participation Analysis</h1>
    
    <div class="chart-container">
        <h2>SNAP Participation by State</h2>
        {chart1_div}
    </div>
    
    <div class="chart-container">
        <h2>SNAP vs Poverty Rate</h2>
        {chart2_div}
    </div>
</body>
</html>
'''

with open('index.html', 'w') as f:
    f.write(combined_html)

Key settings:

  • full_html=False outputs just the chart <div>, not a complete HTML document
  • include_plotlyjs=False skips embedding Plotly (we load it once from CDN)
  • Loading from CDN makes your file much smaller (~KB instead of ~3MB per chart)

Troubleshooting

“Chart doesn’t show when I open HTML locally”: Some browsers block JavaScript in local files. Upload to GitHub Pages or use python -m http.server 8000 then visit localhost:8000.

“HTML file is huge”: Use fig.write_html('chart.html', include_plotlyjs='cdn') to load Plotly from internet instead of embedding it.

“GitHub Pages 404 error”: Make sure file is named index.html (lowercase). Wait a few minutes after enabling Pages.

When to Use Which Chart

Chart TypeBest For
BarComparing categories
HistogramDistribution of one variable
BoxComparing distributions across groups
Pie/DonutParts of a whole (use sparingly)
ScatterRelationship between two variables
LineChange over time
ChoroplethGeographic patterns
AnimatedPresenting change over time

Practice Exercise

Using the SNAP dataset:

  1. Create a choropleth map showing SNAP rates by state
  2. Create a box plot comparing regions
  3. Add a custom hover template showing state name, rate, and region
  4. Export as HTML and deploy to GitHub Pages or Netlify

What’s Next

In Part 2, we’ll build a complete dashboard using Streamlit. While Plotly creates individual interactive charts, Streamlit lets you build full web applications with dropdowns, sliders, and real-time updates.

Resources

Documentation:

Deployment:

Examples:

  • January 26, 2026