-
Notifications
You must be signed in to change notification settings - Fork 0
/
web.py
165 lines (140 loc) · 5.76 KB
/
web.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import os
import json
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import flask
import pandas as pd
from datetime import datetime
from flask_caching import Cache
from loguru import logger
from cov19 import Cov19Statistics, get_query_interval
from cov19.collect import Austria, Germany, Switzerland, UnitedKingdom, UnitedStates
import cov19
external_stylesheets = [
# Dash CSS
'https://codepen.io/chriddyp/pen/bWLwgP.css',
# Loading screen CSS
'https://codepen.io/chriddyp/pen/brPBPO.css']
server = flask.Flask(__name__)
app = dash.Dash(__name__, server=server, external_stylesheets=external_stylesheets)
app.config.suppress_callback_exceptions = True
CACHE_CONFIG = {
'CACHE_TYPE': 'filesystem',
'CACHE_DIR': os.environ.get('CACHE_DIR', 'cache-directory')
}
cache = Cache()
cache.init_app(server, config=CACHE_CONFIG)
@app.callback(Output('signal', 'children'), [Input('interval-component', 'n_intervals')])
def collect_data(n):
# get data from web sites and send a signal when done
global_store()
@cache.memoize(timeout=os.environ.get('CACHE_TIMEOUT', 120))
def global_store():
# perform expensive computations in this "global store"
# these computations are cached in a globally available
# redis memory store which is available across processes
# and for all time.
# do the real job, i.e. 1) get data from web site, 2) store it into a file and 3) then read the data into data frame
cov19 = Cov19Statistics()
for country in [Germany, Austria, Switzerland, UnitedKingdom, UnitedStates]:
c = country()
cov19.add_country(c)
cov19.write_statistics_to_file()
groups = read_data_as_groups(cov19.log_file)
de = groups.get_group('DE')
at = groups.get_group('AT')
ch = groups.get_group('CH')
uk = groups.get_group('UK')
us = groups.get_group('US')
return de, at, ch, uk, us
def serve_layout():
return html.Div(children=[
# hidden signal value
html.Div(id='signal', style={'display': 'none'}),
dcc.Interval(
id='interval-component',
interval=get_query_interval(),
n_intervals=0
),
html.H1(children='Covid-19 Statistics (D, A, CH, UK, US)'),
html.Div(children=[
'Sources: ',
dcc.Link('Robert-Koch-Institut (DE)',
href='https://www.rki.de/DE/Content/InfAZ/N/Neuartiges_Coronavirus/Fallzahlen.html'),
', ',
dcc.Link('Sozialministerium (AT)',
href='https://www.sozialministerium.at/Informationen-zum-Coronavirus/Neuartiges-Coronavirus-(2019-nCov).html'),
', ',
dcc.Link('Bundesamt fuer Gesundheit (CH)',
href='https://www.bag.admin.ch/bag/de/home/krankheiten/ausbrueche-epidemien-pandemien/aktuelle-ausbrueche-epidemien/novel-cov/situation-schweiz-und-international.html'),
', ',
dcc.Link('British Government (UK)',
href='https://www.gov.uk/guidance/coronavirus-covid-19-information-for-the-public'),
', ',
dcc.Link('Centers for Disease Control and Prevention (US)',
href='https://www.cdc.gov/coronavirus/2019-ncov/cases-updates/cases-in-us.html?CDC_AA_refVal=https%3A%2F%2Fwww.cdc.gov%2Fcoronavirus%2F2019-ncov%2Fcases-in-us.html'),
html.Br(),
html.Div(id='last-updated')
]),
dcc.Graph(id='covid-cases-graph'),
dcc.Graph(id='covid-deaths-graph'),
html.Br(),
dcc.Link('track-covid19', href="https://github.com/ondrno/track-covid19"),
html.Span(', version: {}'.format(cov19.__version__)),
])
def read_data_as_groups(logfile):
with open(logfile) as f:
data = []
for line in f.readlines():
data.append(json.loads(line))
df = pd.json_normalize(data)
df.drop_duplicates(keep='last', subset=['country', 'c', 'd'], inplace=True)
groups = df.groupby('country')
return groups
@app.callback(Output('last-updated', 'children'), [Input('signal', 'children')])
def update_metrics_text(n):
today = datetime.now().isoformat()
style = {'fontSize': '11px'}
return [
html.Span('Last update: {}'.format(today), style=style)
]
@app.callback(Output('covid-cases-graph', 'figure'), [Input('signal', 'children')])
def update_covid_cases_metrics(n):
de, at, ch, uk, us = global_store()
fig = {
'data': [
{'x': at["date"], 'y': at["c"], 'name': "Austria"},
{'x': de["date"], 'y': de["c"], 'name': "Germany"},
{'x': ch["date"], 'y': ch["c"], 'name': "Switzerland"},
{'x': uk["date"], 'y': uk["c"], 'name': "United Kingdom"},
{'x': us["date"], 'y': us["c"], 'name': "United States"},
],
'layout': {
'title': 'Confirmed cases',
'yaxis': {'type': 'log'},
}
}
return fig
@app.callback(Output('covid-deaths-graph', 'figure'), [Input('signal', 'children')])
def update_covid_deaths_metrics(n):
de, at, ch, uk, us = global_store()
fig = {
'data': [
{'x': at["date"], 'y': at["d"], 'name': "Austria"},
{'x': de["date"], 'y': de["d"], 'name': "Germany"},
{'x': ch["date"], 'y': ch["d"], 'name': "Switzerland"},
{'x': uk["date"], 'y': uk["d"], 'name': "United Kingdom"},
{'x': us["date"], 'y': us["d"], 'name': "United States"},
],
'layout': {
'title': 'Confirmed deaths',
'yaxis': {'type': 'log'},
}
}
return fig
app.layout = serve_layout
if __name__ == '__main__':
logger.info("Update cycle={} minutes", get_query_interval() / 1000 / 60)
app.run_server(port=os.environ.get('PORT', 8050))