mirror of https://github.com/stijndcl/didier
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
parent
2877def272
commit
5dd6b62a40
118
cogs/corona.py
118
cogs/corona.py
|
@ -31,7 +31,10 @@ class Corona(commands.Cog):
|
||||||
await self.sendError(ctx)
|
await self.sendError(ctx)
|
||||||
return
|
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)
|
@corona.command(aliases=["lb", "leaderboards"], hidden=True)
|
||||||
async def leaderboard(self, ctx):
|
async def leaderboard(self, ctx):
|
||||||
|
@ -43,7 +46,7 @@ class Corona(commands.Cog):
|
||||||
"""
|
"""
|
||||||
await self.client.get_cog("Leaderboards").callLeaderboard("corona", ctx)
|
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.
|
Function that sends a Corona embed from a dictionary.
|
||||||
:param ctx: Discord Context
|
:param ctx: Discord Context
|
||||||
|
@ -54,7 +57,7 @@ class Corona(commands.Cog):
|
||||||
|
|
||||||
# Total
|
# Total
|
||||||
embed.add_field(name="Totale Gevallen (Vandaag):",
|
embed.add_field(name="Totale Gevallen (Vandaag):",
|
||||||
value="{:,} **(+{:,})** {}".format(
|
value=self.createEmbedString(
|
||||||
dic["today"]["cases"],
|
dic["today"]["cases"],
|
||||||
dic["today"]["todayCases"],
|
dic["today"]["todayCases"],
|
||||||
self.trendIndicator(dic, "todayCases")
|
self.trendIndicator(dic, "todayCases")
|
||||||
|
@ -63,7 +66,7 @@ class Corona(commands.Cog):
|
||||||
|
|
||||||
# Active
|
# Active
|
||||||
embed.add_field(name="Actieve Gevallen (Vandaag):",
|
embed.add_field(name="Actieve Gevallen (Vandaag):",
|
||||||
value="{:,} **(+{:,})** {}".format(
|
value=self.createEmbedString(
|
||||||
dic["today"]["activeCases"],
|
dic["today"]["activeCases"],
|
||||||
dic["today"]["activeCases"] - dic["yesterday"]["activeCases"],
|
dic["today"]["activeCases"] - dic["yesterday"]["activeCases"],
|
||||||
self.activeTrendIndicator(dic)
|
self.activeTrendIndicator(dic)
|
||||||
|
@ -72,7 +75,7 @@ class Corona(commands.Cog):
|
||||||
|
|
||||||
# Deaths
|
# Deaths
|
||||||
embed.add_field(name="Sterfgevallen (Vandaag):",
|
embed.add_field(name="Sterfgevallen (Vandaag):",
|
||||||
value="{:,} **(+{:,})** {}".format(
|
value=self.createEmbedString(
|
||||||
dic["today"]["deaths"],
|
dic["today"]["deaths"],
|
||||||
dic["today"]["todayDeaths"],
|
dic["today"]["todayDeaths"],
|
||||||
self.trendIndicator(dic, "todayDeaths")
|
self.trendIndicator(dic, "todayDeaths")
|
||||||
|
@ -81,7 +84,7 @@ class Corona(commands.Cog):
|
||||||
|
|
||||||
# Recovered
|
# Recovered
|
||||||
embed.add_field(name="Hersteld (Vandaag):",
|
embed.add_field(name="Hersteld (Vandaag):",
|
||||||
value="{:,} **(+{:,}) {}**".format(
|
value=self.createEmbedString(
|
||||||
dic["today"]["recovered"],
|
dic["today"]["recovered"],
|
||||||
dic["today"]["todayRecovered"],
|
dic["today"]["todayRecovered"],
|
||||||
self.trendIndicator(dic, "todayRecovered")
|
self.trendIndicator(dic, "todayRecovered")
|
||||||
|
@ -90,15 +93,40 @@ class Corona(commands.Cog):
|
||||||
|
|
||||||
# Test Cases
|
# Test Cases
|
||||||
embed.add_field(name="Aantal uitgevoerde tests:",
|
embed.add_field(name="Aantal uitgevoerde tests:",
|
||||||
value="{:,}".format(dic["today"]["tests"]),
|
value=self.createEmbedString(
|
||||||
|
dic["today"]["tests"],
|
||||||
|
dic["today"]["todayTests"]
|
||||||
|
),
|
||||||
inline=False)
|
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
|
# 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(
|
embed.set_footer(text="Laatst geüpdatet op {} ({} geleden)".format(
|
||||||
timeFormatted["date"], timeFormatted["timeAgo"]))
|
timeFormatted["date"], timeFormatted["timeAgo"]))
|
||||||
await ctx.send(embed=embed)
|
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.command(name="Trends", aliases=["Ct"], usage="[Land]*")
|
||||||
@commands.check(checks.allowedChannels)
|
@commands.check(checks.allowedChannels)
|
||||||
@help.Category(category=Category.Other)
|
@help.Category(category=Category.Other)
|
||||||
|
@ -184,7 +212,9 @@ class Corona(commands.Cog):
|
||||||
"recovered": today["recovered"],
|
"recovered": today["recovered"],
|
||||||
"todayRecovered": today["todayRecovered"],
|
"todayRecovered": today["todayRecovered"],
|
||||||
"tests": today["tests"],
|
"tests": today["tests"],
|
||||||
"updated": today["updated"]
|
"todayTests": today["tests"] - yesterday["tests"],
|
||||||
|
"updated": today["updated"],
|
||||||
|
"population": today["population"]
|
||||||
},
|
},
|
||||||
"yesterday": {
|
"yesterday": {
|
||||||
"cases": yesterday["cases"],
|
"cases": yesterday["cases"],
|
||||||
|
@ -195,11 +225,78 @@ class Corona(commands.Cog):
|
||||||
"recovered": yesterday["recovered"],
|
"recovered": yesterday["recovered"],
|
||||||
"todayRecovered": yesterday["todayRecovered"],
|
"todayRecovered": yesterday["todayRecovered"],
|
||||||
"tests": yesterday["tests"],
|
"tests": yesterday["tests"],
|
||||||
"updated": yesterday["updated"]
|
"updated": yesterday["updated"],
|
||||||
|
"population": yesterday["population"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dic
|
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):
|
def distribution(self, dic):
|
||||||
"""
|
"""
|
||||||
Calculates the percentage distribution for every key & shows an indicator.
|
Calculates the percentage distribution for every key & shows an indicator.
|
||||||
|
@ -263,7 +360,8 @@ class Corona(commands.Cog):
|
||||||
:return: a triangle emoji or empty string
|
:return: a triangle emoji or empty string
|
||||||
"""
|
"""
|
||||||
todayNew = dic["today"]["todayCases"] - dic["today"]["todayDeaths"] - dic["today"]["todayRecovered"]
|
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 \
|
return ":small_red_triangle:" if todayNew > yesterdayNew else \
|
||||||
(":small_red_triangle_down:" if todayNew < yesterdayNew else "")
|
(":small_red_triangle_down:" if todayNew < yesterdayNew else "")
|
||||||
|
|
|
@ -142,3 +142,10 @@ def weekdayToInt(day):
|
||||||
|
|
||||||
def intToWeekday(day):
|
def intToWeekday(day):
|
||||||
return ["Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag", "Zondag"][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)
|
||||||
|
|
Loading…
Reference in New Issue