Add vaccine stats (fixes #26), fix a few bugs in Corona, allow negative numbers to be displayed properly in corona, clean code up a bit, add daily difference for tests

pull/27/head
Stijn De Clercq 2021-01-20 00:55:32 +01:00
parent 2877def272
commit 5dd6b62a40
2 changed files with 121 additions and 16 deletions

View File

@ -31,7 +31,10 @@ class Corona(commands.Cog):
await self.sendError(ctx)
return
await self.sendEmbed(ctx, dic)
# Vaccination stats
vaccine = self.getVaccineData(country, dic["today"]["population"], dic["yesterday"]["population"])
await self.sendEmbed(ctx, dic, vaccine)
@corona.command(aliases=["lb", "leaderboards"], hidden=True)
async def leaderboard(self, ctx):
@ -43,7 +46,7 @@ class Corona(commands.Cog):
"""
await self.client.get_cog("Leaderboards").callLeaderboard("corona", ctx)
async def sendEmbed(self, ctx, dic):
async def sendEmbed(self, ctx, dic, vaccines):
"""
Function that sends a Corona embed from a dictionary.
:param ctx: Discord Context
@ -54,7 +57,7 @@ class Corona(commands.Cog):
# Total
embed.add_field(name="Totale Gevallen (Vandaag):",
value="{:,} **(+{:,})** {}".format(
value=self.createEmbedString(
dic["today"]["cases"],
dic["today"]["todayCases"],
self.trendIndicator(dic, "todayCases")
@ -63,7 +66,7 @@ class Corona(commands.Cog):
# Active
embed.add_field(name="Actieve Gevallen (Vandaag):",
value="{:,} **(+{:,})** {}".format(
value=self.createEmbedString(
dic["today"]["activeCases"],
dic["today"]["activeCases"] - dic["yesterday"]["activeCases"],
self.activeTrendIndicator(dic)
@ -72,7 +75,7 @@ class Corona(commands.Cog):
# Deaths
embed.add_field(name="Sterfgevallen (Vandaag):",
value="{:,} **(+{:,})** {}".format(
value=self.createEmbedString(
dic["today"]["deaths"],
dic["today"]["todayDeaths"],
self.trendIndicator(dic, "todayDeaths")
@ -81,7 +84,7 @@ class Corona(commands.Cog):
# Recovered
embed.add_field(name="Hersteld (Vandaag):",
value="{:,} **(+{:,}) {}**".format(
value=self.createEmbedString(
dic["today"]["recovered"],
dic["today"]["todayRecovered"],
self.trendIndicator(dic, "todayRecovered")
@ -90,15 +93,40 @@ class Corona(commands.Cog):
# Test Cases
embed.add_field(name="Aantal uitgevoerde tests:",
value="{:,}".format(dic["today"]["tests"]),
value=self.createEmbedString(
dic["today"]["tests"],
dic["today"]["todayTests"]
),
inline=False)
# Vaccines
if vaccines is not None:
embed.add_field(name="Aantal toegediende vaccins:",
value=self.createEmbedString(
vaccines["today"]["vaccines"],
vaccines["today"]["todayVaccines"],
self.trendIndicator(vaccines, "todayVaccines")
))
# Timestamp of last update
timeFormatted = timeFormatters.epochToDate(int(dic["today"]["updated"])/1000)
timeFormatted = timeFormatters.epochToDate(int(dic["today"]["updated"]) / 1000)
embed.set_footer(text="Laatst geüpdatet op {} ({} geleden)".format(
timeFormatted["date"], timeFormatted["timeAgo"]))
await ctx.send(embed=embed)
def createEmbedString(self, total, today, indicator="", isPercentage=False):
"""
Function that formats a string to add covid data into the embed,
separate function to make code more readable
"""
# + or - symbol | minus is included in the number so no need
symbol = "+" if today >= 0 else ""
perc = "%" if isPercentage else ""
return "{:,}{} **({}{:,}{})** {}".format(
total, perc, symbol, today, perc, indicator
)
@commands.command(name="Trends", aliases=["Ct"], usage="[Land]*")
@commands.check(checks.allowedChannels)
@help.Category(category=Category.Other)
@ -146,7 +174,7 @@ class Corona(commands.Cog):
distribution[0], distribution[1], distribution[2]), inline=False)
# Timestamp of last update
timeFormatted = timeFormatters.epochToDate(int(dic["today"]["updated"])/1000)
timeFormatted = timeFormatters.epochToDate(int(dic["today"]["updated"]) / 1000)
embed.set_footer(text="Laatst geüpdatet op {} ({} geleden)".format(
timeFormatted["date"], timeFormatted["timeAgo"]))
await ctx.send(embed=embed)
@ -184,7 +212,9 @@ class Corona(commands.Cog):
"recovered": today["recovered"],
"todayRecovered": today["todayRecovered"],
"tests": today["tests"],
"updated": today["updated"]
"todayTests": today["tests"] - yesterday["tests"],
"updated": today["updated"],
"population": today["population"]
},
"yesterday": {
"cases": yesterday["cases"],
@ -195,11 +225,78 @@ class Corona(commands.Cog):
"recovered": yesterday["recovered"],
"todayRecovered": yesterday["todayRecovered"],
"tests": yesterday["tests"],
"updated": yesterday["updated"]
"updated": yesterday["updated"],
"population": yesterday["population"]
}
}
return dic
def getVaccineData(self, country: str, todayPopulation: int, yesterdayPopulation: int):
"""
Function that gets vaccination stats for a specicic country.
This information is later added to the embed.
"""
if todayPopulation == 0:
todayPopulation = 1
if yesterdayPopulation == 0:
yesterdayPopulation = 1
# "all" has a different endpoint
if country == "global":
vaccine: dict = requests.get("https://disease.sh/v3/covid-19/vaccine/coverage?lastdays=3").json()
else:
vaccine: dict = requests.get("https://disease.sh/v3/covid-19/vaccine/coverage/countries/{}?lastdays=3"
.format(country)).json()
# Country-specific is structured differently
if "timeline" in vaccine:
vaccine = vaccine["timeline"]
# Error message returned or not enough data yet
if "message" in vaccine or len(vaccine.keys()) != 3:
return None
timeFormat = "%m/%d/%y"
def getDt(dt):
"""
Function that calls fromString with an argument
so it can be used in map
"""
return timeFormatters.fromString(dt, timeFormat)
def toString(dt):
"""
Function to cast datetime back to string
"""
st: str = dt.strftime(timeFormat)
# Api doesn't add leading zeroes so the keys don't match anymore ---'
if st.startswith("0"):
st = st[1:]
return st
# Order dates
ordered = sorted(map(getDt, vaccine.keys()))
# Datetime objects are only required for sorting, turn back into strings
ordered = list(map(toString, ordered))
info = {"today": {}, "yesterday": {}}
# Total vaccines
info["today"]["vaccines"] = vaccine[ordered[2]]
# New vaccines today
info["today"]["todayVaccines"] = vaccine[ordered[2]] - vaccine[ordered[1]]
# % of total population
info["today"]["perc"] = round(100 * vaccine[ordered[2]] / todayPopulation, 2)
info["yesterday"]["vaccines"] = vaccine[ordered[1]]
info["yesterday"]["todayVaccines"] = vaccine[ordered[1]] - vaccine[ordered[0]]
return info
def distribution(self, dic):
"""
Calculates the percentage distribution for every key & shows an indicator.
@ -209,9 +306,9 @@ class Corona(commands.Cog):
totalToday = dic["today"]["cases"] if dic["today"]["cases"] != 0 else 1
totalYesterday = dic["yesterday"]["cases"] if dic["yesterday"]["cases"] != 0 else 1
tap = round(100 * dic["today"]["activeCases"]/totalToday, 2) # Today Active Percentage
trp = round(100 * dic["today"]["recovered"]/totalToday, 2) # Today Recovered Percentage
tdp = round(100 * dic["today"]["deaths"]/totalToday, 2) # Today Deaths Percentage
tap = round(100 * dic["today"]["activeCases"] / totalToday, 2) # Today Active Percentage
trp = round(100 * dic["today"]["recovered"] / totalToday, 2) # Today Recovered Percentage
tdp = round(100 * dic["today"]["deaths"] / totalToday, 2) # Today Deaths Percentage
yap = round(100 * dic["yesterday"]["activeCases"] / totalYesterday, 2) # Yesterday Active Percentage
yrp = round(100 * dic["yesterday"]["recovered"] / totalYesterday, 2) # Yesterday Recovered Percentage
ydp = round(100 * dic["yesterday"]["deaths"] / totalYesterday, 2) # Yesterday Deaths Percentage
@ -245,7 +342,7 @@ class Corona(commands.Cog):
yesterday = dic["yesterday"][key] if dic["yesterday"][key] != 0 else 1
# Percentage
perc = round(100 * change/yesterday, 2)
perc = round(100 * change / yesterday, 2)
# Sign to add to the number
sign = "+" if change >= 0 else ""
@ -263,7 +360,8 @@ class Corona(commands.Cog):
:return: a triangle emoji or empty string
"""
todayNew = dic["today"]["todayCases"] - dic["today"]["todayDeaths"] - dic["today"]["todayRecovered"]
yesterdayNew = dic["yesterday"]["todayCases"] - dic["yesterday"]["todayDeaths"] - dic["yesterday"]["todayRecovered"]
yesterdayNew = dic["yesterday"]["todayCases"] - dic["yesterday"]["todayDeaths"] - dic["yesterday"][
"todayRecovered"]
return ":small_red_triangle:" if todayNew > yesterdayNew else \
(":small_red_triangle_down:" if todayNew < yesterdayNew else "")

View File

@ -142,3 +142,10 @@ def weekdayToInt(day):
def intToWeekday(day):
return ["Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag", "Zondag"][day]
def fromString(timeString: str, formatString="%d/%m/%Y"):
"""
Constructs a datetime object from an input string
"""
return datetime.datetime.strptime(timeString, formatString)