Spaces:
Runtime error
Runtime error
Nicolas Pierson commited on
✨ Add covid tracker
Browse files- .streamlit/config.toml +6 -0
- Dockerfile +26 -0
- README.md +14 -1
- app.py +182 -0
.streamlit/config.toml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[browser]
|
| 2 |
+
serverAddress = '0.0.0.0'
|
| 3 |
+
|
| 4 |
+
[theme]
|
| 5 |
+
base="dark"
|
| 6 |
+
primaryColor="#4be8e0"
|
Dockerfile
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.9-slim
|
| 2 |
+
|
| 3 |
+
RUN apt-get update && apt-get install -y \
|
| 4 |
+
build-essential \
|
| 5 |
+
curl \
|
| 6 |
+
software-properties-common \
|
| 7 |
+
git \
|
| 8 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 9 |
+
|
| 10 |
+
RUN useradd -m -u 1000 user
|
| 11 |
+
|
| 12 |
+
ENV HOME=/home/user \
|
| 13 |
+
PATH=/home/user/.local/bin:$PATH
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
WORKDIR $HOME/app
|
| 17 |
+
|
| 18 |
+
RUN pip3 install altair pandas numpy streamlit pydeck
|
| 19 |
+
|
| 20 |
+
COPY --chown=user . $HOME/app
|
| 21 |
+
|
| 22 |
+
EXPOSE 8501
|
| 23 |
+
|
| 24 |
+
HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
|
| 25 |
+
|
| 26 |
+
ENTRYPOINT ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"]
|
README.md
CHANGED
|
@@ -8,4 +8,17 @@ pinned: false
|
|
| 8 |
short_description: A covid tracker app
|
| 9 |
---
|
| 10 |
|
| 11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
short_description: A covid tracker app
|
| 9 |
---
|
| 10 |
|
| 11 |
+
# Streamlit Demo app
|
| 12 |
+
|
| 13 |
+
Welcome to this streamlit demo app. The goal of this application is to quickly onboard you on `streamlit`'s functionalities. If you want to check out
|
| 14 |
+
the end work, simply go to this URL --> https://jedha-streamlit-demo.herokuapp.com/
|
| 15 |
+
|
| 16 |
+
## Checkout code
|
| 17 |
+
|
| 18 |
+
If you want to checkout the code, simply run this command on your terminal:
|
| 19 |
+
|
| 20 |
+
`git clone https://github.com/JedhaBootcamp/streamlit-demo-app`
|
| 21 |
+
|
| 22 |
+
Then you will be able to see `app.py` where the whole code is commented.
|
| 23 |
+
|
| 24 |
+
Happy coding 😀
|
app.py
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import plotly.graph_objects as go
|
| 4 |
+
import numpy as np
|
| 5 |
+
|
| 6 |
+
### Config
|
| 7 |
+
st.set_page_config(page_title="Covid Tracker", page_icon="🦠 ", layout="wide")
|
| 8 |
+
|
| 9 |
+
DATE_COLUMN = "dateRep"
|
| 10 |
+
DATA_URL = "https://opendata.ecdc.europa.eu/covid19/nationalcasedeath_eueea_daily_ei/csv/data.csv"
|
| 11 |
+
|
| 12 |
+
### App
|
| 13 |
+
st.title("Covid Tracker")
|
| 14 |
+
st.markdown(
|
| 15 |
+
"👋 Hello there! Welcome to this simple covid tracker app. We simply track the evolution of cases accross the world. Data comes from the European Centre for Disease Prevention and Control (ECDC)"
|
| 16 |
+
)
|
| 17 |
+
st.markdown(
|
| 18 |
+
"Check out data here: [Data on the daily number of new reported COVID-19 cases and deaths by EU/EEA country](https://www.ecdc.europa.eu/en/publications-data/data-daily-new-cases-covid-19-eueea-country)"
|
| 19 |
+
)
|
| 20 |
+
st.caption("At the moment of this app, data was lastly collected on December 25th 2021")
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
@st.cache_data
|
| 24 |
+
def load_data(nrows):
|
| 25 |
+
data = pd.read_csv(DATA_URL, nrows=nrows)
|
| 26 |
+
data[DATE_COLUMN] = pd.to_datetime(data[DATE_COLUMN])
|
| 27 |
+
return data
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
data_load_state = st.text("Loading data...")
|
| 31 |
+
data = load_data(None)
|
| 32 |
+
|
| 33 |
+
if st.checkbox("Show raw data"):
|
| 34 |
+
st.subheader("Raw data")
|
| 35 |
+
st.write(data)
|
| 36 |
+
|
| 37 |
+
### World analysis
|
| 38 |
+
st.subheader("World Analysis")
|
| 39 |
+
world = data.groupby("dateRep").sum().reset_index()
|
| 40 |
+
world_cases = world.loc[:, ["dateRep", "cases"]]
|
| 41 |
+
|
| 42 |
+
#### cases - cumulated
|
| 43 |
+
st.markdown("#### Cumulated cases")
|
| 44 |
+
world_cases["cumulated_cases"] = world_cases["cases"].cumsum()
|
| 45 |
+
|
| 46 |
+
world_fig1 = go.Figure(
|
| 47 |
+
go.Scatter(
|
| 48 |
+
x=world_cases["dateRep"],
|
| 49 |
+
y=world_cases["cumulated_cases"],
|
| 50 |
+
fill="tozeroy",
|
| 51 |
+
name="Cumulated cases",
|
| 52 |
+
)
|
| 53 |
+
)
|
| 54 |
+
|
| 55 |
+
st.plotly_chart(world_fig1, use_container_width=True)
|
| 56 |
+
|
| 57 |
+
#### cases - new
|
| 58 |
+
st.markdown("#### New cases")
|
| 59 |
+
### Remove outlier (from Jan 3rd)
|
| 60 |
+
world_cases = world_cases.iloc[21:, :]
|
| 61 |
+
world_cases["moving_average"] = (
|
| 62 |
+
world_cases["cases"].rolling(window=7, min_periods=1).mean()
|
| 63 |
+
)
|
| 64 |
+
|
| 65 |
+
world_fig2 = go.Figure()
|
| 66 |
+
world_fig2.add_trace(
|
| 67 |
+
go.Scatter(x=world_cases["dateRep"], y=world_cases["cases"], name="New cases")
|
| 68 |
+
)
|
| 69 |
+
|
| 70 |
+
world_fig2.add_trace(
|
| 71 |
+
go.Scatter(
|
| 72 |
+
x=world_cases["dateRep"], y=world_cases["moving_average"], name="7-day average"
|
| 73 |
+
)
|
| 74 |
+
)
|
| 75 |
+
|
| 76 |
+
world_fig2.update_xaxes(showgrid=False)
|
| 77 |
+
world_fig2.update_yaxes(showgrid=False)
|
| 78 |
+
|
| 79 |
+
st.plotly_chart(world_fig2, use_container_width=True)
|
| 80 |
+
|
| 81 |
+
### Country analysis
|
| 82 |
+
st.subheader("Country Analysis")
|
| 83 |
+
countries = data["countriesAndTerritories"].unique()
|
| 84 |
+
country = st.selectbox("Which country would you like to see?", countries)
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
### Number of cases
|
| 88 |
+
cases_per_country = data[data["countriesAndTerritories"] == country].loc[
|
| 89 |
+
:, ["dateRep", "cases"]
|
| 90 |
+
]
|
| 91 |
+
cases_per_country = cases_per_country.sort_values("dateRep", ascending=True).iloc[1:, :]
|
| 92 |
+
cases_per_country["moving_average"] = (
|
| 93 |
+
cases_per_country["cases"].rolling(window=7, min_periods=1).mean()
|
| 94 |
+
)
|
| 95 |
+
|
| 96 |
+
#### Growth rate
|
| 97 |
+
current_growth_rate = (
|
| 98 |
+
cases_per_country["moving_average"].iloc[-1]
|
| 99 |
+
/ cases_per_country["moving_average"].iloc[-2]
|
| 100 |
+
)
|
| 101 |
+
previous_growth_rate = (
|
| 102 |
+
cases_per_country["moving_average"].iloc[-2]
|
| 103 |
+
/ cases_per_country["moving_average"].iloc[-3]
|
| 104 |
+
)
|
| 105 |
+
growth_rate_evolution = current_growth_rate - previous_growth_rate
|
| 106 |
+
|
| 107 |
+
content, empty_space = st.columns([3, 2])
|
| 108 |
+
with empty_space:
|
| 109 |
+
st.empty()
|
| 110 |
+
|
| 111 |
+
with content:
|
| 112 |
+
st.metric(
|
| 113 |
+
"Current growth rate",
|
| 114 |
+
np.round(current_growth_rate, 3),
|
| 115 |
+
np.round(growth_rate_evolution, 3),
|
| 116 |
+
"inverse",
|
| 117 |
+
)
|
| 118 |
+
st.caption(
|
| 119 |
+
"Growth rate compares the average number of cases of today to the average number of cases of yesterday. If growth rate > 1 - the virus is spreading. If growth rate < 1 - the wave is slowing down"
|
| 120 |
+
)
|
| 121 |
+
#####
|
| 122 |
+
|
| 123 |
+
col1, col2 = st.columns(2)
|
| 124 |
+
|
| 125 |
+
fig1 = go.Figure()
|
| 126 |
+
fig1.add_trace(
|
| 127 |
+
go.Scatter(
|
| 128 |
+
x=cases_per_country["dateRep"],
|
| 129 |
+
y=cases_per_country["cases"],
|
| 130 |
+
name="Number of cases per day",
|
| 131 |
+
)
|
| 132 |
+
)
|
| 133 |
+
|
| 134 |
+
fig1.add_trace(
|
| 135 |
+
go.Scatter(
|
| 136 |
+
x=cases_per_country["dateRep"],
|
| 137 |
+
y=cases_per_country["moving_average"],
|
| 138 |
+
name="7-day average",
|
| 139 |
+
)
|
| 140 |
+
)
|
| 141 |
+
|
| 142 |
+
fig1.update_xaxes(showgrid=False)
|
| 143 |
+
fig1.update_yaxes(showgrid=False)
|
| 144 |
+
|
| 145 |
+
with col1:
|
| 146 |
+
st.markdown("#### Positive cases")
|
| 147 |
+
st.plotly_chart(fig1, use_container_width=True)
|
| 148 |
+
|
| 149 |
+
### Number of deaths
|
| 150 |
+
deaths_per_country = data[data["countriesAndTerritories"] == country].loc[
|
| 151 |
+
:, ["dateRep", "deaths"]
|
| 152 |
+
]
|
| 153 |
+
deaths_per_country = deaths_per_country.sort_values("dateRep", ascending=True).iloc[
|
| 154 |
+
1:, :
|
| 155 |
+
]
|
| 156 |
+
deaths_per_country["moving_average"] = (
|
| 157 |
+
deaths_per_country["deaths"].rolling(window=7, min_periods=1).mean()
|
| 158 |
+
)
|
| 159 |
+
|
| 160 |
+
fig2 = go.Figure()
|
| 161 |
+
fig2.add_trace(
|
| 162 |
+
go.Scatter(
|
| 163 |
+
x=deaths_per_country["dateRep"],
|
| 164 |
+
y=deaths_per_country["deaths"],
|
| 165 |
+
name="Number of deaths per day",
|
| 166 |
+
)
|
| 167 |
+
)
|
| 168 |
+
|
| 169 |
+
fig2.add_trace(
|
| 170 |
+
go.Scatter(
|
| 171 |
+
x=deaths_per_country["dateRep"],
|
| 172 |
+
y=deaths_per_country["moving_average"],
|
| 173 |
+
name="7-day average",
|
| 174 |
+
)
|
| 175 |
+
)
|
| 176 |
+
|
| 177 |
+
fig2.update_xaxes(showgrid=False)
|
| 178 |
+
fig2.update_yaxes(showgrid=False)
|
| 179 |
+
|
| 180 |
+
with col2:
|
| 181 |
+
st.markdown("#### Deaths")
|
| 182 |
+
st.plotly_chart(fig2, use_container_width=True)
|