BANA409BANA409

Data App Tutorial

In this tutorial, you build a Streamlit app that explores a world cities dataset, then deploy it to Streamlit Cloud so anyone can use it.

Before the Lesson

  1. Create a GitHub account at https://github.com/signup if you don't have one (done in the previous lab), and install GitHub Desktop.
  2. Create a Streamlit account at https://share.streamlit.io/signup — sign up with your GitHub account.
  3. Download worldcities.csv.zip. The dataset is revised based on this Kaggle Dataset.

Set Up the Project

Create a new uv project for the app and install the packages:

uv init --python 3.14 my-streamlit
cd my-streamlit
uv add streamlit pandas matplotlib

Unzip worldcities.csv.zip and move worldcities.csv into the my-streamlit folder.

The Dataset

Each row of worldcities.csv is a city with a population over one million. The app uses these columns:

  • city and country — the city name and its country
  • lat and lon — the location, used by st.map()
  • population — the population in millions, from about 1.0 (the smallest city) to 38.0 (Tokyo), with a mean of 3.6. The app's population slider goes from 0 to 40 with a default of 3.6.
  • capital — whether the city is a capital, used by the app's multi-select:
    • primary - country's capital (e.g. Washington D.C.)
    • admin - first-level admin capital (e.g. Little Rock, AR)
    • minor - lower-level admin capital (e.g. Fayetteville, AR)
    • nan if not a capital (nan is not a string - it's a keyword in Pandas for Null)

Build the App

Create a new app-cities.py file in the my-streamlit folder with the following content, which is explained next:

import streamlit as st
import pandas as pd
import matplotlib.pyplot as plt
plt.style.use('seaborn-v0_8')

st.title('World Cities')
df = pd.read_csv('worldcities.csv')

# note that you have to use 0.0 and 40.0 given that the data type of population is float
population_filter = st.slider('Minimal Population (Millions):', 0.0, 40.0, 3.6)  # min, max, default

# create a multi select
capital_filter = st.sidebar.multiselect(
     'Capital Selector',
     df.capital.unique(),  # options
     df.capital.unique())  # defaults

# create a input form
form = st.sidebar.form("country_form")
country_filter = form.text_input('Country Name (enter ALL to reset)', 'ALL')
form.form_submit_button("Apply")

# filter by population
df = df[df.population >= population_filter]

# filter by capital
df = df[df.capital.isin(capital_filter)]

if country_filter!='ALL':
    df = df[df.country == country_filter]

# show on map
st.map(df)

# show dataframe
st.subheader('City Details:')
st.write(df[['city', 'country', 'population']])

# show the plot
st.subheader('Total Population By Country')
fig, ax = plt.subplots(figsize=(20, 5))
pop_sum = df.groupby('country')['population'].sum()
pop_sum.plot.bar(ax=ax)
st.pyplot(fig)

NOTE: whenever you interact with the app using any widget, such as changing the slider's value, the ENTIRE file is executed again from top to bottom.

  • title, subtitle using st.title() and st.subheader()
  • show the map using st.map() the dataframe must have columns named latitude or lat and longitude or lon
  • create a slider using st.slider()
  • create a multi-select using st.multiselect()
  • put widgets in sidebar using st.sidebar such as st.sidebar.multiselect()
  • use st.form() to group multiple widgets and only refresh the app when the form button is clicked, see the country filter as an example

Run the app from the my-streamlit folder:

uv run streamlit run app-cities.py

Deploy the App

To deploy the app to Streamlit Cloud, you publish the my-streamlit project to a public GitHub repository and then point Streamlit Cloud at that repository. You don't need a requirements.txt: Streamlit Cloud reads uv.lock and installs exactly the packages the project uses.

uv init already made my-streamlit a git repository, and its .gitignore keeps the .venv folder out of it. Open GitHub Desktop, choose File > Add Local Repository (or Add an Existing Repository from your Hard Drive), and select the my-streamlit folder. If GitHub Desktop says the folder is not a git repository (uv only creates one when command-line Git is installed), click create a repository and choose Python under Git Ignore, so the .venv folder stays out of the repository.

The Changes tab lists every file in the project, including app-cities.py, worldcities.csv, pyproject.toml, and uv.lock. Enter a summary such as world cities app and click Commit to main.

Then click Publish repository:

Publish the repository

The repository must be PUBLIC — uncheck "Keep this code private". You can change the name, such as world-cities:

Make the repository public

Go to GitHub and you should see all the project files in your repo.

Log in to https://share.streamlit.io/ and create a new app:

Create a new app on Streamlit Cloud

Choose the repo you just published, set the main file path to app-cities.py, and open Advanced settings to set the Python version to 3.14 — Streamlit Cloud defaults to 3.12, and the install fails because the project requires 3.14. Then click Deploy. You can also use the Paste GitHub URL option and enter the URL of the app file, such as https://github.com/<your-username>/world-cities/blob/main/app-cities.py:

Deploy using a GitHub URL

Or fill in the repository, branch, and main file path directly:

Deploy by choosing the repository and main file

Wait for the process to finish and you should see your app deployed:

The app is being built

You can share the app with anyone in the world:

Share the app

The deployed World Cities app

To update the app later, edit the files in my-streamlit, then commit and click Push origin in GitHub Desktop — Streamlit Cloud redeploys the app automatically.

On this page