rework on plots title, legend and name + generate html page with plots
This commit is contained in:
parent
a994f96eea
commit
c0f024043b
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
output
|
static/plots
|
||||||
data
|
data
|
||||||
|
build
|
||||||
.svn
|
.svn
|
||||||
@ -24,4 +24,6 @@ python owid.py <country_trigram> <var_1> <var_2> <var..n>
|
|||||||
python dress.py
|
python dress.py
|
||||||
```
|
```
|
||||||
|
|
||||||
**NOTE** : `-r` option is used to fetch update data
|
**NOTE** :
|
||||||
|
* `-r` option is used to fetch update data
|
||||||
|
* `dress.py` includes **--to-html** to generate html page with plots
|
||||||
98
drees.py
98
drees.py
@ -10,6 +10,7 @@ from typing import Any, Dict, List, Optional, OrderedDict, Tuple
|
|||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import requests
|
import requests
|
||||||
|
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
||||||
from matplotlib import dates as md
|
from matplotlib import dates as md
|
||||||
from matplotlib import pyplot as plt
|
from matplotlib import pyplot as plt
|
||||||
|
|
||||||
@ -20,7 +21,11 @@ DATE_FORMAT = "%Y-%m-%d"
|
|||||||
|
|
||||||
DATA_URL = "https://data.drees.solidarites-sante.gouv.fr/api/records/1.0/search/?dataset=covid-19-resultats-par-age-issus-des-appariements-entre-si-vic-si-dep-et-vac-si&q=&rows=-1&facet=date&facet=vac_statut&facet=age"
|
DATA_URL = "https://data.drees.solidarites-sante.gouv.fr/api/records/1.0/search/?dataset=covid-19-resultats-par-age-issus-des-appariements-entre-si-vic-si-dep-et-vac-si&q=&rows=-1&facet=date&facet=vac_statut&facet=age"
|
||||||
DATA_REPOSITORY = "data"
|
DATA_REPOSITORY = "data"
|
||||||
OUTPUT_REPOSITORY = "output"
|
STATIC_REPOSITORY = "static"
|
||||||
|
OUTPUT_REPOSITORY = os.path.join(STATIC_REPOSITORY, "plots")
|
||||||
|
BUILD_REPOSITORY = "build"
|
||||||
|
|
||||||
|
MAIN_URL = "https://covid.thegux.fr/"
|
||||||
|
|
||||||
# cycler could be better, but for ages plots it's ok
|
# cycler could be better, but for ages plots it's ok
|
||||||
AGE_COLORS = {
|
AGE_COLORS = {
|
||||||
@ -41,9 +46,9 @@ class DreesEnum(bytes, Enum):
|
|||||||
|
|
||||||
|
|
||||||
class Field(DreesEnum):
|
class Field(DreesEnum):
|
||||||
HC = (0, "hc")
|
HC = (0, "Hospitalisations")
|
||||||
SC = (1, "sc")
|
SC = (1, "Soins critiques")
|
||||||
DC = (2, "dc")
|
DC = (2, "Décés")
|
||||||
|
|
||||||
|
|
||||||
class VacStatus(DreesEnum):
|
class VacStatus(DreesEnum):
|
||||||
@ -109,7 +114,7 @@ def get_enum_age(value):
|
|||||||
|
|
||||||
def get_enum_field(value):
|
def get_enum_field(value):
|
||||||
for field in Field:
|
for field in Field:
|
||||||
if field.label == value:
|
if field.name.lower() == value:
|
||||||
return field.value
|
return field.value
|
||||||
|
|
||||||
|
|
||||||
@ -141,9 +146,8 @@ def group_by_age_date(data: Dict[str, Any]) -> Dict[dt, Any]:
|
|||||||
if vac_status not in dic_data_grouped[date][age]:
|
if vac_status not in dic_data_grouped[date][age]:
|
||||||
dic_data_grouped[date][age][vac_status] = OrderedDict()
|
dic_data_grouped[date][age][vac_status] = OrderedDict()
|
||||||
for field in Field:
|
for field in Field:
|
||||||
dic_data_grouped[date][age][vac_status][field.label] = row_fields[
|
field_name = field.name.lower()
|
||||||
field.label
|
dic_data_grouped[date][age][vac_status][field_name] = row_fields[field_name]
|
||||||
]
|
|
||||||
logging.info("data restructured")
|
logging.info("data restructured")
|
||||||
return dic_data_grouped
|
return dic_data_grouped
|
||||||
|
|
||||||
@ -284,7 +288,7 @@ def analyse(np_data: np.ndarray, np_date: np.ndarray) -> None:
|
|||||||
mean_vac_percent = np.round(
|
mean_vac_percent = np.round(
|
||||||
np.nanmean(np_percent_vac[:, age_group.value, field.value]) * 100, 2
|
np.nanmean(np_percent_vac[:, age_group.value, field.value]) * 100, 2
|
||||||
)
|
)
|
||||||
print(f"{field.label} - {age_group.label} - vac : {mean_vac_percent}%")
|
print(f"{field.name} - {age_group.label} - vac : {mean_vac_percent}%")
|
||||||
|
|
||||||
logging.info("--- age by field and vac status mean percent ---")
|
logging.info("--- age by field and vac status mean percent ---")
|
||||||
for field in Field:
|
for field in Field:
|
||||||
@ -297,22 +301,20 @@ def analyse(np_data: np.ndarray, np_date: np.ndarray) -> None:
|
|||||||
percent_age_mean = np.round(
|
percent_age_mean = np.round(
|
||||||
np.nanmean(np_percent_age[:, age_group.value]), 2
|
np.nanmean(np_percent_age[:, age_group.value]), 2
|
||||||
)
|
)
|
||||||
print(
|
print(f"age: {age_group.label} - field: {field.name} = {percent_age_mean}%")
|
||||||
f"age: {age_group.label} - field: {field.label} = {percent_age_mean}%"
|
|
||||||
)
|
|
||||||
|
|
||||||
percent_age_vac_mean = np.round(
|
percent_age_vac_mean = np.round(
|
||||||
np.nanmean(np_percent_age_vac[:, age_group.value]), 2
|
np.nanmean(np_percent_age_vac[:, age_group.value]), 2
|
||||||
)
|
)
|
||||||
print(
|
print(
|
||||||
f"age: {age_group.label} - status: vac - field: {field.label} = {percent_age_vac_mean}%"
|
f"age: {age_group.label} - status: vac - field: {field.name} = {percent_age_vac_mean}%"
|
||||||
)
|
)
|
||||||
|
|
||||||
percent_age_unvac_mean = np.round(
|
percent_age_unvac_mean = np.round(
|
||||||
np.nanmean(np_percent_age_unvac[:, age_group.value]), 2
|
np.nanmean(np_percent_age_unvac[:, age_group.value]), 2
|
||||||
)
|
)
|
||||||
print(
|
print(
|
||||||
f"age: {age_group.label} - status: unvac - field: {field.label} = {percent_age_unvac_mean}%"
|
f"age: {age_group.label} - status: unvac - field: {field.name} = {percent_age_unvac_mean}%"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -324,7 +326,8 @@ def plot_bar_age_percent_vac_status_by_field(
|
|||||||
) -> None:
|
) -> None:
|
||||||
fig, ax = get_plot_fig(figsize=(22, 8), locator=md.WeekdayLocator())
|
fig, ax = get_plot_fig(figsize=(22, 8), locator=md.WeekdayLocator())
|
||||||
bottom = np_data_vac_status[:, 0]
|
bottom = np_data_vac_status[:, 0]
|
||||||
title = "vac" if is_vac else "no vac"
|
suffix = "vac" if is_vac else "unvac"
|
||||||
|
title = "Vaccinés" if is_vac else "Non vaccinés"
|
||||||
for age_group in AgeGroup:
|
for age_group in AgeGroup:
|
||||||
percents_age = np_data_vac_status[:, age_group.value]
|
percents_age = np_data_vac_status[:, age_group.value]
|
||||||
if age_group.value > 0:
|
if age_group.value > 0:
|
||||||
@ -351,7 +354,7 @@ def plot_bar_age_percent_vac_status_by_field(
|
|||||||
)
|
)
|
||||||
save_and_close_fig(
|
save_and_close_fig(
|
||||||
fig,
|
fig,
|
||||||
os.path.join(OUTPUT_REPOSITORY, f"age_percent_{title}_{field.label}"),
|
os.path.join(OUTPUT_REPOSITORY, f"age_percent_{suffix}_{field.name.lower()}"),
|
||||||
has_legend=False,
|
has_legend=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -385,13 +388,13 @@ def plot_cumulative_field(
|
|||||||
np_cumulate_unvac: np.ndarray = np.cumsum(
|
np_cumulate_unvac: np.ndarray = np.cumsum(
|
||||||
np_data_unvac[:, age_group.value, field.value], axis=0
|
np_data_unvac[:, age_group.value, field.value], axis=0
|
||||||
)
|
)
|
||||||
plt.plot(np_date, np_cumulate_vac, label=f"{age_group.label} vac")
|
plt.plot(np_date, np_cumulate_vac, label=f"{age_group.label} Vaccinés")
|
||||||
plt.plot(np_date, np_cumulate_unvac, label=f"{age_group.label} no vac")
|
plt.plot(np_date, np_cumulate_unvac, label=f"{age_group.label} Non vaccinés")
|
||||||
|
|
||||||
plt.title(f"nombre de {field.label} cumulé par age")
|
plt.title(f"{field.label} cumulés par âge")
|
||||||
plt.xlabel("date")
|
plt.xlabel("date")
|
||||||
save_and_close_fig(
|
save_and_close_fig(
|
||||||
fig, os.path.join(OUTPUT_REPOSITORY, f"cumulative_{field.label}")
|
fig, os.path.join(OUTPUT_REPOSITORY, f"cumulative_{field.name.lower()}")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -411,11 +414,13 @@ def plot_fields_by_age_vac(
|
|||||||
)
|
)
|
||||||
plt.xlabel("date")
|
plt.xlabel("date")
|
||||||
plt.ylabel("nombre")
|
plt.ylabel("nombre")
|
||||||
plt.title(f"{age_group.label}ans - {vac_status.label}")
|
plt.title(f"{age_group.label} - {vac_status.label}")
|
||||||
|
|
||||||
save_and_close_fig(
|
save_and_close_fig(
|
||||||
fig,
|
fig,
|
||||||
os.path.join(OUTPUT_REPOSITORY, f"all_{age_group.label}_{vac_status.label}"),
|
os.path.join(
|
||||||
|
OUTPUT_REPOSITORY, f"all_{age_group.name.lower()}_{vac_status.name.lower()}"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -440,8 +445,10 @@ def plot_bar_data_by_age_field(
|
|||||||
unvac_percent = np.round(
|
unvac_percent = np.round(
|
||||||
np_percent_unvac[idx_date, age_group.value, field.value] * 100, 2
|
np_percent_unvac[idx_date, age_group.value, field.value] * 100, 2
|
||||||
)
|
)
|
||||||
bar_vac = ax.bar(idx_date, vac_percent, color="b", label="vac")
|
bar_vac = ax.bar(idx_date, vac_percent, color="b", label="Vaccinés")
|
||||||
ax.bar(idx_date, unvac_percent, bottom=vac_percent, color="r", label="no vac")
|
ax.bar(
|
||||||
|
idx_date, unvac_percent, bottom=vac_percent, color="r", label="Non vaccinés"
|
||||||
|
)
|
||||||
ax.bar_label(
|
ax.bar_label(
|
||||||
bar_vac, label_type="edge", color="black", fontsize="7", fmt="%.0f"
|
bar_vac, label_type="edge", color="black", fontsize="7", fmt="%.0f"
|
||||||
)
|
)
|
||||||
@ -458,11 +465,14 @@ def plot_bar_data_by_age_field(
|
|||||||
for idx, d in enumerate(np_date.astype(dt))
|
for idx, d in enumerate(np_date.astype(dt))
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
plt.legend(["vac", "no vac"], loc="upper right", frameon=True)
|
plt.legend(["Vaccinés", "Non vaccinés"], loc="upper right", frameon=True)
|
||||||
|
|
||||||
save_and_close_fig(
|
save_and_close_fig(
|
||||||
fig,
|
fig,
|
||||||
os.path.join(OUTPUT_REPOSITORY, f"vac_percent_{age_group.label}_{field.label}"),
|
os.path.join(
|
||||||
|
OUTPUT_REPOSITORY,
|
||||||
|
f"vac_percent_{age_group.name.lower()}_{field.name.lower()}",
|
||||||
|
),
|
||||||
has_legend=False,
|
has_legend=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -489,6 +499,27 @@ def get_age_field_args() -> List[Tuple[AgeGroup, Field]]:
|
|||||||
return pool_args
|
return pool_args
|
||||||
|
|
||||||
|
|
||||||
|
def generate_html_page() -> None:
|
||||||
|
logging.info("generating html page with plots...")
|
||||||
|
os.makedirs(BUILD_REPOSITORY, exist_ok=True)
|
||||||
|
env = Environment(
|
||||||
|
loader=FileSystemLoader("templates"), autoescape=select_autoescape()
|
||||||
|
)
|
||||||
|
template = env.get_template("index.template.html")
|
||||||
|
data = template.render(
|
||||||
|
**{
|
||||||
|
"fields": Field,
|
||||||
|
"ages": AgeGroup,
|
||||||
|
"status": VacStatus,
|
||||||
|
"static": os.path.join(MAIN_URL, STATIC_REPOSITORY),
|
||||||
|
"src": DATA_URL,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
with open(os.path.join(BUILD_REPOSITORY, "index.html"), "w") as f:
|
||||||
|
f.write(data)
|
||||||
|
logging.info("html page build")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
"""
|
"""
|
||||||
This script aims to plot DRESS data
|
This script aims to plot DRESS data
|
||||||
@ -517,13 +548,18 @@ if __name__ == "__main__":
|
|||||||
"--no-plot",
|
"--no-plot",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
default=False,
|
default=False,
|
||||||
help="redownload data for updates",
|
help="no plot data",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-th",
|
||||||
|
"--to-html",
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
help="create an html with the plots",
|
||||||
)
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
os.makedirs(OUTPUT_REPOSITORY, exist_ok=True)
|
|
||||||
|
|
||||||
dic_data: Dict[str, Any] = get_data(
|
dic_data: Dict[str, Any] = get_data(
|
||||||
file_path=os.path.join(DATA_REPOSITORY, "dress.json"), refresh=args.refresh
|
file_path=os.path.join(DATA_REPOSITORY, "dress.json"), refresh=args.refresh
|
||||||
)
|
)
|
||||||
@ -533,6 +569,7 @@ if __name__ == "__main__":
|
|||||||
analyse(np_data, np_date)
|
analyse(np_data, np_date)
|
||||||
|
|
||||||
if not args.no_plot:
|
if not args.no_plot:
|
||||||
|
os.makedirs(OUTPUT_REPOSITORY, exist_ok=True)
|
||||||
plot_fields_args = get_age_vac_args()
|
plot_fields_args = get_age_vac_args()
|
||||||
f_fields = partial(plot_fields_by_age_vac, np_data, np_date)
|
f_fields = partial(plot_fields_by_age_vac, np_data, np_date)
|
||||||
plot_vac_percent_age_args = get_age_field_args()
|
plot_vac_percent_age_args = get_age_field_args()
|
||||||
@ -544,3 +581,6 @@ if __name__ == "__main__":
|
|||||||
for field in Field:
|
for field in Field:
|
||||||
plot_cumulative_field(np_data, np_date, field)
|
plot_cumulative_field(np_data, np_date, field)
|
||||||
plot_bar_age_percent_by_field(np_data, np_date, field)
|
plot_bar_age_percent_by_field(np_data, np_date, field)
|
||||||
|
|
||||||
|
if args.to_html:
|
||||||
|
generate_html_page()
|
||||||
|
|||||||
31
static/css/index.css
Normal file
31
static/css/index.css
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
.main-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plot-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.plot-item {
|
||||||
|
flex: 0 1 33%
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-bars {
|
||||||
|
width: 1500px;
|
||||||
|
height: 500px;
|
||||||
|
border: solid
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
45
templates/index.template.html
Normal file
45
templates/index.template.html
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Covid data extraction from DRESS dataset</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="keywords" content="thegux, covid">
|
||||||
|
<link rel="stylesheet" href="{{ static }}/css/index.css">
|
||||||
|
<meta name="description" content="A simple page to share some useful data about covid 19">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="main-container">
|
||||||
|
<h1>Thegux covid-19</h1>
|
||||||
|
<div>source : <a href="{{ src }}">Data DRESS</a></div>
|
||||||
|
<h3>Hospitalisations/Soins critiques/Décés par status vaccinal groupés par tranches d'âges</h3>
|
||||||
|
{% for field in fields %}
|
||||||
|
<img src="{{ static }}/plots/age_percent_vac_{{ field.name.lower() }}.png"/>
|
||||||
|
<img src="{{ static }}/plots/age_percent_unvac_{{ field.name.lower() }}.png"/>
|
||||||
|
{% endfor %}
|
||||||
|
<h3>Hospitalisations/Soins critiques/Décés par tranches d'âges groupés par status vaccinal</h3>
|
||||||
|
{% for age in ages %}
|
||||||
|
{% for field in fields %}
|
||||||
|
<img src="{{ static }}/plots/vac_percent_{{ age.name.lower() }}_{{ field.name.lower() }}.png"/>
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
<h3>Hospitalisations/Soins critiques/Décés par tranches d'âges et status vaccinal</h3>
|
||||||
|
<div class="plot-container">
|
||||||
|
{% for age in ages %}
|
||||||
|
{% for vac_status in status %}
|
||||||
|
<div class="plot-item">
|
||||||
|
<img src="{{ static }}/plots/all_{{ age.name.lower() }}_{{ vac_status.name.lower() }}.png"/>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<h3>Hospitalisations/Soins critiques/Décés cumulés par tranches d'âges et status vaccinal</h3>
|
||||||
|
<div class="plot-container">
|
||||||
|
{% for field in fields %}
|
||||||
|
<div class="plot-item">
|
||||||
|
<img src="{{ static }}/plots/cumulative_{{ field.name.lower() }}.png"/>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
x
Reference in New Issue
Block a user