Merge pull request #1 from derogab/dev

Restyle
This commit is contained in:
Gabriele De Rosa 2021-05-21 15:19:16 +02:00 committed by GitHub
commit 69d9d57832
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 207 additions and 87 deletions

View File

@ -23,4 +23,4 @@ Il bot è stato sviluppato da [@derogab](https://github.com/derogab) e il codice
I dati mostrati sono scaricati dagli [Open Data ufficiali](https://github.com/italia/covid19-opendata-vaccini) sui vaccini in Italia.
I grafici sono automaticamente generati mediante il codice della [repository pubblica](https://github.com/MarcoBuster/quanto-manca) di [@MarcoBuster](https://github.com/MarcoBuster).
Fino alla [v1.0.0](https://github.com/derogab/ITAvsCOVIDbot/releases/tag/v1.0.0) i grafici sono automaticamente generati mediante il codice della [repository pubblica](https://github.com/MarcoBuster/quanto-manca) di [@MarcoBuster](https://github.com/MarcoBuster). Dalla [v2.0.0](https://github.com/derogab/ITAvsCOVIDbot/releases/tag/v2.0.0) sono invece utilizzati dei grafici differenti costruiti sulla base dei precedenti.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

@ -41,33 +41,11 @@
</p>
<h3>Analisi dei dati della campagna vaccinale</h3>
<p class="mb-2">
La campagna vaccinale in Italia è iniziata da poco e chiaramente non è ancora a regime. La stima qui effettuata
sarà via via più affidabile con l'aumentare dei dati e indica il tempo che mancherebbe al raggiungimento
La stima qui effettuata indica il tempo che mancherebbe al raggiungimento
dell'immunità di gregge qualora si tenesse il ritmo degli ultimi 7 giorni. <br />
</p>
<hr>
<div class="text-center">
In Italia sono state somministrate <br />
<span class="text-big">
<!-- totalDoses -->
dosi di vaccino</span> <br />
che corrispondono a <br />
<span class="text-big">
<!-- totalVaccinations -->
persone vaccinate,</span> <br />
ovvero <br />
<span class="text-big">
<!-- totalVaccinationsPerc -->
della popolazione.
</span> <br />
Ne abbiamo vaccinate <br />
<span class="text-big">
<!-- totalVaccinationsLastWeek -->
nell'ultima settimana,</span> <br />
con un ritmo di <br />
<span class="text-big">
<!-- vaccinesPerDay -->
vaccinati al giorno.</span> <br />
Continuando di questo passo, raggiungeremo l'immunità di gregge il <br />
<span class="text-bigger">
<!-- hitDate -->
@ -81,13 +59,13 @@
giorni.
</span>
</div>
<img alt="Grafico vaccinati ultima settimana" src="plot.png" class="img-fluid">
<hr>
<p class="pt-2 notes">
I dati non comprendono quelli del giorno attuale perché solitamente incompleti.
</p>
<p class="pt-2 notes">
Dal 2 febbraio 2021 il grafico mostra i dati delle persone vaccinate,
ovvero di chi ha ricevuto entrambe le dosi.
Dal 21 maggio 2021 sono mostrati due differenti grafici per differenziare
le prime e le seconde dosi.
</p>
</div>
</body>

View File

@ -0,0 +1,88 @@
<!DOCTYPE html>
<!-- Source: https://github.com/MarcoBuster/quanto-manca/blob/master/template.html -->
<html lang="it">
<head>
<title>@itavscovidbot</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<style>
.text-big {
font-size: 130%;
font-weight: bold;
position: relative;
top: -5px;
margin-bottom: -4px;
}
.text-bigger {
font-size: 200%;
font-weight: bold;
position: relative;
top: -6px;
margin-bottom: -4px;
}
p.notes{
padding-top: 0px !important;
margin-bottom: 5px;
}
.box {
text-align: center;
padding: 10px 0px;
margin: 5px -7px;
border: 1px solid black;
border-radius: 5px;
}
#content {
padding: 35px;
}
</style>
</head>
<body>
<div class="container mt-2 pt-2 px-xl-5" id="content">
<div class="row">
<div class="col-md-6">
<div class="box">
<h1>
<!-- totalVaccinations -->
</h1>
Somministrazioni
<!-- typeVaccinations -->
</div>
</div>
<div class="col-md-6">
<div class="box">
<h1>
<!-- totalVaccinationsPerc -->
</h1>
/ 100%
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="box">
<h1>
<!-- totalVaccinationsLastWeek -->
</h1>
Questa settimana
</div>
</div>
<div class="col-md-6">
<div class="box">
<h1>
<!-- vaccinesPerDay -->
</h1>
Media settimanale
</div>
</div>
</div>
<hr>
<img alt="Grafico vaccinati ultima settimana" src="plot.png" class="img-fluid">
</div>
</body>
</html>

154
bot.py
View File

@ -5,6 +5,7 @@ import secrets
import schedule
import time
from dotenv import load_dotenv
from telegram import InputMediaPhoto
from telegram.ext import Updater
from telegram.ext import CommandHandler
from pymongo import MongoClient
@ -52,7 +53,7 @@ mongodb_pass = os.environ.get('MONGODB_PASS')
if mongodb_user is None or mongodb_pass is None:
print('No mongodb auth.')
exit()
mongodb_uri = 'mongodb://' + mongodb_user + ':' + mongodb_pass + '@db:27017',
mongodb_uri = 'mongodb://' + mongodb_user + ':' + mongodb_pass + '@db:27017'
# Init mongodb database
client = MongoClient(mongodb_uri)
@ -61,59 +62,57 @@ db = client['bot']
def progress(first, second, total = ITALIAN_POPULATION):
# Function to get data
def download():
progress_length = 20
# Download from open data
r = requests.get(DATA_URL)
# Create dataframe from data
df = pd.read_csv(
io.StringIO(r.text),
index_col="data_somministrazione",
)
# Set date as index
df.index = pd.to_datetime(
df.index,
format="%Y-%m-%d",
)
# Sort value based on date
df.sort_values('data_somministrazione')
# Delete sum data if already exists
df = df[df["area"] != "ITA"]
# Set target counters to numeric
df["totale"] = pd.to_numeric(df["totale"])
df["seconda_dose"] = pd.to_numeric(df["seconda_dose"])
# Group by day and sum counters
df_doses = df.groupby(['data_somministrazione'])['totale'].sum().reset_index()
df_vaccines = df.groupby(['data_somministrazione'])['seconda_dose'].sum().reset_index()
# Re-set date as ID in new dataframe
df_doses = df_doses.set_index('data_somministrazione')
df_vaccines = df_vaccines.set_index('data_somministrazione')
# first : total = x : 100
first_perc = (first * 100) / total
# second : total = x : 100
second_perc = (second * 100) / total
# If there are current day data...
if dt.now() - df_doses.index[-1] < td(days=1):
df_doses = df_doses[:-1] # Ignore the current day because it's often incomplete
if dt.now() - df_vaccines.index[-1] < td(days=1):
df_vaccines = df_vaccines[:-1] # Ignore the current day because it's often incomplete
# first_perc : x = 100 : progress_length
first_cycle = int(first_perc / (100 / progress_length))
# second_perc : x = 100 : progress_length
second_cycle = int(second_perc / (100 / progress_length))
totalDoses = sum(df_doses["totale"])
totalVaccines = sum(df_vaccines["seconda_dose"])
lastWeekData = df_vaccines.loc[df_vaccines.index > df_vaccines.index[-1] - td(days=7)]
vaccinesPerDayAverage = sum(lastWeekData["seconda_dose"]) / 7
# first progress
first_progress = ''
for i in range(0, first_cycle):
first_progress = first_progress + ''
for i in range(0, progress_length - first_cycle):
first_progress = first_progress + ''
# second progress
second_progress = ''
for i in range(0, second_cycle):
second_progress = second_progress + ''
for i in range(0, progress_length - second_cycle):
second_progress = second_progress + ''
return first_progress, second_progress
def generate(df, target, template):
# Get data from df
totalVaccines = sum(df[target])
lastWeekData = df.loc[df.index > df.index[-1] - td(days=7)]
vaccinesPerDayAverage = sum(lastWeekData[target]) / 7
remainingDays = (HIT - totalVaccines) / vaccinesPerDayAverage
hitDate = df_vaccines.index[-1] + td(days=remainingDays)
hitDate = df.index[-1] + td(days=remainingDays)
first_or_second = 'Seconda Dose' if target == 'seconda_dose' else 'Prima Dose' if target == 'prima_dose' else 'Totale'
# Generate plot
plt.ylabel("Vaccinati al giorno")
plt.ylabel(first_or_second)
plt.xlabel("Ultima settimana")
plt.grid(True)
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
plt.gca().xaxis.set_major_locator(mdates.AutoDateLocator())
plt.gcf().autofmt_xdate()
plt.bar(lastWeekData.index, height=lastWeekData["seconda_dose"])
plt.bar(lastWeekData.index, height=lastWeekData[target])
# Trendline
z = np.polyfit(range(0, 7), lastWeekData["seconda_dose"], 2)
z = np.polyfit(range(0, 7), lastWeekData[target], 2)
p = np.poly1d(z)
plt.plot(lastWeekData.index, p(range(0, 7)), "r--")
# Secret 4 filenames
@ -127,13 +126,13 @@ def download():
# Generate tmp webpage/html filename
webpage_filename = 'tmp_' + sf + '.html'
# Generate template
with open('template.html', 'r+') as f:
with open(template, 'r+') as f:
with open('out/' + webpage_filename, 'w+') as wf:
for line in f.read().splitlines():
if "<!-- totalDoses -->" in line:
line = f"{totalDoses}"
elif "<!-- totalVaccinations -->" in line:
if "<!-- totalVaccinations -->" in line:
line = f"{totalVaccines}"
elif "<!-- typeVaccinations -->" in line:
line = f"{first_or_second}"
elif "<!-- totalVaccinationsPerc -->" in line:
line = f"{str(round(totalVaccines / ITALIAN_POPULATION * 100, 2)).replace('.', ',')}%"
elif "<!-- totalVaccinationsLastWeek -->" in line:
@ -162,6 +161,53 @@ def download():
}
# Function to get data
def download():
# Download from open data
r = requests.get(DATA_URL)
# Create dataframe from data
df = pd.read_csv(
io.StringIO(r.text),
index_col="data_somministrazione",
)
# Set date as index
df.index = pd.to_datetime(
df.index,
format="%Y-%m-%d",
)
# Sort value based on date
df.sort_values('data_somministrazione')
# Delete sum data if already exists
df = df[df["area"] != "ITA"]
# Set target counters to numeric
df["prima_dose"] = pd.to_numeric(df["prima_dose"])
df["seconda_dose"] = pd.to_numeric(df["seconda_dose"])
# Group by day and sum counters
df_first = df.groupby(['data_somministrazione'])['prima_dose'].sum().reset_index()
df_second = df.groupby(['data_somministrazione'])['seconda_dose'].sum().reset_index()
# Re-set date as ID in new dataframe
df_first = df_first.set_index('data_somministrazione')
df_second = df_second.set_index('data_somministrazione')
# If there are current day data...
if dt.now() - df_first.index[-1] < td(days=1):
df_first = df_first[:-1] # Ignore the current day because it's often incomplete
if dt.now() - df_second.index[-1] < td(days=1):
df_second = df_second[:-1] # Ignore the current day because it's often incomplete
# Generata images
intro = generate(df_second, 'seconda_dose', 'assets/templates/intro.html')
plot1 = generate(df_first, 'prima_dose', 'assets/templates/plot.html')
plot2 = generate(df_second, 'seconda_dose', 'assets/templates/plot.html')
# Generate progression
progression = [sum(df_first['prima_dose']), sum(df_second['seconda_dose'])]
return intro, plot1, plot2, progression
# Help command
def help(update, context):
@ -291,12 +337,24 @@ def news(update, context):
def get(update, context):
# Download data
data = download()
intro, plot1, plot2, progression = download()
# Send photo
context.bot.send_photo(chat_id=update.effective_chat.id, photo=open(data['results'], 'rb'), caption="")
# Send photos
p1 = open(intro['results'], 'rb')
p2 = open(plot1['results'], 'rb')
p3 = open(plot2['results'], 'rb')
first, second = progress(progression[0], progression[1])
caption = 'Prima Dose\n' + first + '\nSeconda Dose\n' + second
p1 = InputMediaPhoto(media=p1, caption=caption)
p2 = InputMediaPhoto(media=p2)
p3 = InputMediaPhoto(media=p3)
context.bot.send_media_group(chat_id=update.effective_chat.id, media=[p1, p2, p3])
# Remove tmp files
for data in [intro, plot1, plot2]:
os.remove(data['plot'])
os.remove(data['webpage'])
os.remove(data['results'])

View File

@ -1,14 +1,15 @@
version: "3.5"
version: '3.7'
networks:
itavscovidbot.network:
name: itavscovidbot.network
driver: bridge
services:
db:
image: mongo
image: mongo:latest
container_name: itavscovidbot.db
restart: unless-stopped
env_file:
@ -21,11 +22,9 @@ services:
db.web:
depends_on:
- db
image: mongo-express
image: mongo-express:latest
container_name: itavscovidbot.db.web
restart: unless-stopped
links:
- db
env_file:
- ./db/web/.env
ports:
@ -36,13 +35,10 @@ services:
app:
depends_on:
- db
- db.web
build:
context: .
container_name: itavscovidbot.app
restart: unless-stopped
links:
- db
env_file:
- ./.env
networks: