Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .DS_Store
Binary file not shown.
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,28 @@ Streamlit dashboard with analysis of cases and hospitalizations from Genebra.
```bash
$ streamlit run dashboard.py --server.port 8502
```

### Run with docker-compose :

**Pre-requisites**
* Docker installed and running
* docker-compose installed

It also works fine with podman and [podman-compose].(https://phoenixnap.com/kb/podman-compose#ftoc-heading-3)

```bash
$ docker-compose -f docker/docker-compose.yml up
# or
$ podman-compose -f docker/docker-compose.yml up

# When dependencies change and you need to force a rebuild
$ docker-compose -f docker/docker-compose.yml up --build

# When finished
$ docker-compose down
```

You can see the app running at http://localhost:8501


docker-compose -f docker/docker-compose.yaml --env-file .env build
4 changes: 2 additions & 2 deletions SIR_forecast.py → app/SIR_forecast.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
import matplotlib.pyplot as plt
from get_data import get_canton_data
from sqlalchemy import create_engine
engine = create_engine("postgresql://epigraph:epigraph@localhost:5432/epigraphhub")

import config
engine = create_engine(config.DB_URI)

def make_inference_sir():
Prev_post = pd.read_sql_table('prev_post', engine, schema = 'switzerland', index_col = 'datum')
Expand Down
5 changes: 3 additions & 2 deletions bayesian_inference.py → app/bayesian_inference.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@
@author: eduardoaraujo
"""
#import arviz as az

import plotly.graph_objects as go
import pandas as pd
import streamlit as st
from PIL import Image
from get_data import get_canton_data
from sqlalchemy import create_engine

engine = create_engine("postgresql://epigraph:epigraph@localhost:5432/epigraphhub")
import config
engine = create_engine(config.DB_URI)



Expand Down
9 changes: 6 additions & 3 deletions clustering.py → app/clustering.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import streamlit as st
from get_data import compute_clusters
from geoanalysis import correlation_map
from geoanalysis import correlation_map, correlation_map_bokeh


def app():
Expand Down Expand Up @@ -44,5 +44,8 @@ def app():
curve = st.selectbox("On which series you want to base the correlation on?",
('cases', 'hospitalizations')
)
figmap = correlation_map(curve=curve)
st.pyplot(figmap)
#figmap = correlation_map(curve=curve)
#st.pyplot(figmap)

figmap_bokeh = correlation_map_bokeh(curve=curve)
st.bokeh_chart(figmap_bokeh)
14 changes: 14 additions & 0 deletions app/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import os
from dotenv import load_dotenv
load_dotenv('../.env')

POSTGRES_USER = os.getenv("POSTGRES_USER")
POSTGRES_PASSWORD = os.getenv("POSTGRES_PASSWORD")
POSTGRES_HOST = os.getenv("POSTGRES_HOST")
POSTGRES_PORT = os.getenv("POSTGRES_PORT")
POSTGRES_DB = os.getenv("POSTGRES_DB")

DB_URI = (
f"postgresql://{POSTGRES_USER}:{POSTGRES_PASSWORD}"
f"@{POSTGRES_HOST}:{POSTGRES_PORT}/{POSTGRES_DB}"
)
File renamed without changes.
2 changes: 0 additions & 2 deletions dashboard.py → app/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
"""

import streamlit as st
import bayesian_inference
import SIR_forecast
import forecast
import for_other_cantons
import credits
Expand Down
File renamed without changes
File renamed without changes
4 changes: 2 additions & 2 deletions for_other_cantons.py → app/for_other_cantons.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
from get_data import get_curve
from sqlalchemy import create_engine
from plots import scatter_plot_cases_hosp_all
engine = create_engine(
"postgresql://epigraph:epigraph@localhost:5432/epigraphhub")
import config
engine = create_engine(config.DB_URI)

dict_cantons_names = {
'Uri (UR)': 'UR',
Expand Down
6 changes: 2 additions & 4 deletions forecast.py → app/forecast.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,8 @@
from get_data import get_canton_data, get_curve
from plots import scatter_plot_cases_hosp
from sqlalchemy import create_engine
engine = create_engine(
"postgresql://epigraph:epigraph@localhost:5432/epigraphhub")


import config
engine = create_engine(config.DB_URI)



Expand Down
97 changes: 97 additions & 0 deletions app/geoanalysis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import pandas as pd
import matplotlib.pyplot as plt
from bokeh.models import (ColorBar,
GeoJSONDataSource, HoverTool,
LinearColorMapper)
from bokeh.palettes import brewer
from bokeh.plotting import figure

from get_data import get_ch_map, lag_ccf, engine

def correlation_map(curve='cases'):
if curve == 'hospitalizations':
curve = 'hosp'
chmap = get_ch_map()

df = pd.read_sql_table(f'foph_{curve}', engine, schema = 'switzerland', columns = ['datum','geoRegion', 'entries'])
df.index = pd.to_datetime(df.datum)
inc_canton = df.pivot(columns='geoRegion', values='entries')
del inc_canton['CHFL']
del inc_canton['CH']
cm, lm = lag_ccf(inc_canton.values)
corrsGE = pd.DataFrame(index= inc_canton.columns, data={'corr':cm[8,:]})
chmap_corr = pd.merge(left=chmap, right=corrsGE, on='geoRegion')
fig, ax = plt.subplots(1, 1)

chmap_corr.plot(column='corr', ax=ax,
legend=True,
legend_kwds={'label': "Correlation",
'orientation': "horizontal"}
)
ax.set_axis_off();
return fig


def correlation_map_bokeh(curve='cases'):
if curve == 'hospitalizations':
curve = 'hosp'
chmap = get_ch_map()

df = pd.read_sql_table(f'foph_{curve}', engine, schema = 'switzerland', columns = ['datum','geoRegion', 'entries'])
df.index = pd.to_datetime(df.datum)
inc_canton = df.pivot(columns='geoRegion', values='entries')
del inc_canton['CHFL']
del inc_canton['CH']
cm, lm = lag_ccf(inc_canton.values)
corrsGE = pd.DataFrame(index= inc_canton.columns, data={'corr':cm[8,:]})
chmap_corr = pd.merge(left=chmap, right=corrsGE, on='geoRegion')

# Input GeoJSON source that contains features for plotting
geosource = GeoJSONDataSource(geojson = chmap_corr.to_json())

# Define custom tick labels for color bar.
palette = brewer['BuGn'][8]
palette = palette[::-1] # reverse order of colors so higher values have darker colors
# Instantiate LinearColorMapper that linearly maps numbers in a range, into a sequence of colors.
color_mapper = LinearColorMapper(palette = palette, low = 0.6, high = 1.0)
# Define custom tick labels for color bar.
tick_labels = { '0.7': '0.7', '0.75': '0.75', '0.8': '0.8', '0.85': '0.85', '0.9': '0.9', '0.95': '0.95', '1.00': '1.00'}
# Create color bar.
color_bar = ColorBar(color_mapper = color_mapper,
label_standoff = 8,
width = 500, height = 20,
border_line_color = None,
location = (0,0),
orientation = 'horizontal',
major_label_overrides = tick_labels,
title = 'Correlation')
# Create figure object.
p = figure(title = '',
plot_height = 600, plot_width = 950,
toolbar_location = 'below',
tools = "pan, wheel_zoom, box_zoom, reset")
p.xgrid.grid_line_color = None
p.ygrid.grid_line_color = None
# Add patch renderer to figure.
states = p.patches('xs','ys', source = geosource,
fill_color = { 'field' :'corr',
'transform' : color_mapper},
line_color = 'black',
line_width = 0.8,
fill_alpha = 1)
# Create hover tool
p.add_tools(HoverTool(renderers = [states],
tooltips = [('Cantons','@geoRegion'),
('Correlation', '@corr')]))
# Specify layout
p.add_layout(color_bar, 'below')

p.xaxis.visible = False

p.yaxis.visible = False

return p




16 changes: 7 additions & 9 deletions get_data.py → app/get_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,16 @@
import scipy.cluster.hierarchy as hcluster
from sqlalchemy import create_engine
import matplotlib.pyplot as plt
#import streamlit as st

engine_public = create_engine("postgresql://epigraph:epigraph@localhost:5432/epigraphhub")

import config
engine = create_engine(config.DB_URI)

def get_curve_all(curve):

'''
Function to return the cases or hosp for all the switzerland
'''

df2 = pd.read_sql(f"select datum, sum(entries) from switzerland.foph_{curve}_d group by datum;", engine_public)
df2 = pd.read_sql(f"select datum, sum(entries) from switzerland.foph_{curve}_d group by datum;", engine)
df2.index = pd.to_datetime(df2.datum)
df2 = df2.rename(columns={'sum': 'entries'})
df2.sort_index(inplace = True)
Expand All @@ -45,7 +43,7 @@ def get_curve(curve, canton):
dict_dates = {'cases': 'datum', 'hosp': 'datum',
'hospcapacity': 'date'}

df = pd.read_sql(f"select {dict_columns[curve]} from switzerland.foph_{curve}_d where georegion='{canton}';", engine_public)
df = pd.read_sql(f"select {dict_columns[curve]} from switzerland.foph_{curve}_d where georegion='{canton}';", engine)

df.index = pd.to_datetime(df[dict_dates[curve]])

Expand Down Expand Up @@ -104,7 +102,7 @@ def compute_clusters(curve, t, plot=False):
-> all_regions: is the array with all the regions
'''

df = pd.read_sql_table(f'foph_{curve}_d', engine_public, schema = 'switzerland', columns = ['datum','georegion', 'entries'])
df = pd.read_sql_table(f'foph_{curve}_d', engine, schema = 'switzerland', columns = ['datum','georegion', 'entries'])

df.index = pd.to_datetime(df.datum)

Expand Down Expand Up @@ -171,7 +169,7 @@ def get_canton_data(curve, canton, ini_date=None):
}

# getting the data from the databank
df = pd.read_sql_table(f'foph_{curve}_d', engine_public, schema = 'switzerland', columns = dict_cols[curve])
df = pd.read_sql_table(f'foph_{curve}_d', engine, schema = 'switzerland', columns = dict_cols[curve])

# filtering by cantons
df = df.loc[(df.georegion.isin(canton))]
Expand All @@ -190,6 +188,6 @@ def get_canton_data(curve, canton, ini_date=None):

def get_ch_map():
chmap = gpd.read_postgis("select * from switzerland.map_cantons;",
con=engine_public, geom_col="geometry")
con=engine, geom_col="geometry")
chmap['geoRegion'] = chmap.HASC_1.transform(lambda x: x.split('.')[-1])
return chmap
4 changes: 4 additions & 0 deletions plots.py → app/plots.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ def scatter_plot_cases_hosp(region):
sns.regplot(x=cases['2022-01-01':'2022-03-31'].entries,
y=hosp['2022-01-01':'2022-03-31'].entries,
label='2022-Q1', color='tab:green',robust=True, ax=ax)

sns.regplot(x=cases['2022-04-01':'2022-06-30'].entries,
y=hosp['2022-04-01':'2022-06-30'].entries,
label='2022-Q2', color='tab:red',robust=True, ax=ax)

ax.set_title('Cases vs hospitalizations in Geneva')

Expand Down
File renamed without changes
14 changes: 14 additions & 0 deletions conda/dev.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: env-covidch
channels:
- conda-forge
- nodefaults
dependencies:
# - docker-compose
- pip
- gdal
- arviz
- geopandas
- psycopg2
- statsmodels
- openpyxl

51 changes: 51 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
FROM condaforge/mambaforge

USER root

ENV DEVIAN_FRONTEND=noninteractive

ENV HOME "/home/covidch"
ENV PATH "$PATH:/home/covidch/.local/bin"
ENV ENV_NAME base
ENV PATH "/opt/conda/envs/$ENV_NAME/bin:$PATH"
ENV PATH "/opt/poetry/bin:$PATH"

RUN apt-get -qq update --yes \
&& apt-get -qq install --yes --no-install-recommends \
ca-certificates sudo curl \
&& rm -rf /var/lib/apt/lists/*


RUN useradd -ms /bin/bash covidch \
&& echo "covidch ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/covidch \
&& chmod 0440 /etc/sudoers.d/ \
&& echo 'source /opt/conda/bin/activate "$ENV_NAME" && exec "$@"' > /activate.sh \
&& echo 'source activate "$ENV_NAME"' > /home/covidch/.bashrc \
&& chmod +x /activate.sh \
&& chmod -R a+rwx /opt/conda /tmp \
&& sudo chown -R covidch:covidch /usr/src


COPY --chown=covidch:covidch conda/dev.yaml /tmp/dev.yaml
COPY --chown=covidch:covidch pyproject.toml poetry.lock README.md /usr/src/
COPY --chown=covidch:covidch app /home/covidch/app/

RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py | POETRY_HOME=/opt/poetry python && \
cd /usr/local/bin && \
ln -s /opt/poetry/bin/poetry && \
poetry config virtualenvs.create false

RUN chmod -R a+rwx /home/covidch/.config/pypoetry/

USER covidch

RUN mamba env update -n $ENV_NAME \
--file /tmp/dev.yaml \
&& cd /usr/src && poetry install \
&& mamba clean -afy

WORKDIR /home/covidch/app/

ENTRYPOINT ["streamlit", "run", "dashboard.py"]

#ENTRYPOINT ["bash", "/activate.sh"]
17 changes: 17 additions & 0 deletions docker/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
version: "3.9"
services:
streamlit-app:
build:
context: ".."
dockerfile: docker/Dockerfile
env_file:
- ../.env
#environment:
# - PSQL_HOST=${PSQL_HOST}
# - PSQL_PORT=${PSQL_PORT}
ports:
- "8501:8501"
volumes:
# Mounting this file allows updates to the webpage without restarting the container
- ./:/app/

Loading