File talk:COVID-19 Outbreak World Map Total Deaths per Capita.svg

From Wikimedia Commons, the free media repository
Jump to navigation Jump to search

Production[edit]

Generated by the following script:

from __future__ import print_function, division
import sys, urllib, re, math, os
from datetime import datetime

# Limitations:
# - The regions of the two sources may have some cases of poor correspondence.
#   This should be eventually addressed.

# Customization

calculateChineseProvinces = True
calculateItalianRegions = True
hideSmallFontLabelsViaFontSizeZero = True

regionNameCanonizationMap = {
  "Virgin Islands, British": "British Virgin Islands",
  "Virgin Islands, U.S.": "U.S. Virgin Islands",
  #"China (Mainland)": "China",
  #"China (mainland)": "China",
  "Congo, Democratic Republic of the": "DR Congo",
  "Cote d'Ivoire": "Ivory Coast",
  #"Greenland (Denmark)": "Greenland",
  #"Guernsey (UK)": "Guernsey",
  #"Hong Kong (China)": "Hong Kong",
  #"Isle of Man (UK)": "Isle of Man",
  #"Jersey (UK)": "Jersey",
  "Korea, Republic of": "South Korea",
  "Lao People's Democratic Republic": "Laos",
  #"Macau (China)": "Macau",
  "Macao": "Macau",
  "Republic of the Congo": "Congo",
  "Russian Federation": "Russia",
  "Saint Vincent and the Grenadines": "St. Vincent and the Grenadines",
  u"S\u00E3o Tom\u00E9 and Pr\u00EDncipe": "Sao Tome and Principe",
  "St. Vincent & the Grenadines": "St. Vincent and the Grenadines",
  "State of Palestine": "Palestine",
  "Syrian Arab Republic": "Syria",
  "The Gambia": "Gambia",
  "Timor-Leste": "East Timor",
  "United States of America": "United States",
  u"\u00C5land Islands": "Aaland Islands",
}

white, black, red, blue = "FFFFFF", "000000", "FF0000", "0000FF"
figureSpec = { # x, y, color, fontSize
  # Coverage: all countries for which the figure can reasonably be placed in the map at font size 35 or 20.
  # Some countries covered by indicating a very small label, not visible but present in the raw SVG text.
  #
  # Europe
  "France": (1310, 300, white, 20),
  "Germany": (1360, 257, white, 20),
  "Spain": (1265, 350, white, 20),
  "United Kingdom": (1252, 193, black, 20),
  "Iceland": (1230, 135, black, 20),
  "Ireland": (1203, 245, black, 20),
  "Denmark": (1322, 225, black, 20),
  "Greenland": (1080, 100, white, 35),
  "Sweden": (1405, 150, white, 20),
  "Norway": (1348, 150, black, 20),
  "Finland": (1458, 172, white, 20),
  "Romania": (1458, 310, white, 20),
  "Portugal": (1195, 360, black, 20),
  "Italy": (1376, 366, black, 20),
  "Greece": (1440, 398, black, 20),
  "Belarus": (1480, 245, white, 20),
  "Ukraine": (1515, 280, white, 20),
  "Bulgaria": (1470, 337, white, 20),
  "Poland": (1425, 255, white, 20),
  "Czech Republic": (1401, 273, white, 12),
  "Austria": (1401, 291, white, 12),
  "Hungary": (1430, 298, white, 12),
  "Switzerland": (1356, 296, white, 8),
  "Belgium": (1334, 265, white, 8),
  "Slovakia": (1435, 281, white, 8),
  "Serbia": (1445, 325, white, 12),
  "Bosnia and Herzegovina": (1423, 320, white, 12),
  # Americas
  "United States": (580, 370, white, 35),
  "Canada": (580, 240, white, 35),
  "Mexico": (505, 490, white, 35),
  "Brazil": (890, 800, white, 35),
  "Colombia": (715, 680, white, 35),
  "Bolivia": (785, 855, white, 35),
  "Argentina": (815, 1000, white, 35),
  "Chile": (710, 980, black, 35),
  "Paraguay": (850, 900, white, 20),
  "Suriname": (860, 670, white, 20),
  "Uruguay": (885, 990, white, 20),
  #"French Guiana": ... - belongs to France
  "Cuba": (690, 525, black, 20),
  "Panama": (680, 612, black, 20),
  "Dominican Republic": (784, 530, black, 20),
  "Venezuela": (790, 650, white, 35),
  "Guyana": (855, 638, black, 20),
  "Guatemala": (590, 590, black, 20),
  "Honduras": (645, 558, black, 20),
  "Nicaragua": (670, 580, black, 20),
  "Costa Rica": (630, 635, black, 20),
  "Jamaica": (710, 562, black, 20),
  "Haiti": (738, 560, black, 20),
  # Asia and Oceania
  "Russia": (1600, 220, white, 35),
  "Iran": (1670, 430, white, 35),
  "Turkey": (1550, 370, white, 20),
  "Ecuador": (635, 720, black, 20),
  "Peru": (730, 810, white, 20),
  "China":  (2100, 440, white, 35),
  "Mongolia": (1980, 310, white, 35),
  "Australia": (2300, 930, white, 35),
  "Indonesia": (2165, 762, black, 35),
  "New Zealand": (2480, 1050, black, 35),
  "Philippines": (2255, 595, black, 35),
  "Malaysia": (2095, 670, black, 20),
  "Kazakhstan": (1770, 290, white, 35),
  "Afghanistan": (1770, 415, white, 20),
  "Pakistan": (1800, 450, white, 20),
  "Kyrgyzstan": (1820, 345, white, 20),
  "Iraq": (1603, 415, white, 20),
  "Saudi Arabia": (1620,500, white, 35),
  "Japan": (2320, 390, black, 35),
  "South Korea": (2234, 380, black, 20),
  "India": (1870, 520, white, 35),
  "Uzbekistan": (1740, 340, white, 20),
  "Thailand": (2055, 570, white, 20),
  "Cambodia": (2084, 594, white, 20),
  "Vietnam": (2130, 594, black, 20),
  "Laos": (2061, 538, white, 20),
  "Papua New Guinea": (2378, 757, white, 20),
  "Syria": (1572, 400, white, 20),
  "Israel": (1528, 424, black, 20),
  "Cyprus": (1510, 404, black, 20),
  "Sri Lanka": (1922, 630, black, 20),
  "Bangladesh": (1960, 527, black, 20),
  "Nepal": (1910, 465, white, 12),
  "Taiwan": (2210, 500, black, 20),
  "Myanmar": (2002, 515, white, 20),
  "Yemen": (1635, 568, white, 20),
  "Oman": (1722, 516, white, 20),
  "United Arab Emirates": (1685, 486, black, 12),
  # Africa
  "Algeria": (1300, 470, white, 35),
  "Egypt": (1500, 480, white, 35),
  "Morocco": (1250, 426, white, 20),
  "Mali": (1280, 550, white, 35),
  "Niger": (1370, 555, white, 35),
  "Burkina Faso": (1285, 595, white, 20),
  "Cameroon": (1380, 665, white, 20),
  "South Africa": (1438, 977, white, 35),
  "Somalia": (1620, 680, white, 20),
  "Libya": (1420, 480, white, 35),
  "Sudan": (1510, 570, white, 35),
  "Chad": (1420, 570, white, 35),
  "Central African Republic": (1440, 652, white, 35),
  "South Sudan": (1510, 646, white, 35),
  "Uganda": (1540, 688, white, 20),
  "Mozambique": (1575, 825, white, 20),
  "Madagascar": (1635, 860, white, 20),
  "Mauritania": (1200, 545, white, 35),
  "Nigeria": (1340, 630, white, 35),
  "DR Congo": (1460, 730, white, 35),
  "Congo": (1415, 705, white, 20),
  "Kenya": (1580, 700, white, 20),
  "Tanzania": (1555, 760, white, 20),
  "Zambia": (1485, 830, white, 20),
  "Botswana": (1470, 900, white, 20),
  "Zimbabwe": (1515, 870, white, 20),
  "Senegal": (1175, 575, white, 20),
  "Ivory Coast": (1250, 640, white, 20),
  "Guinea": (1210, 610, white, 20),
  "Liberia": (1195, 665, black, 20),
  "Gabon": (1375, 708, white, 20),
  "Ethiopia": (1570, 640, white, 35),
  "Angola": (1405, 815, white, 35),
  "Namibia": (1412, 900, white, 20),
  "Ghana": (1280, 640, white, 20),
  "Sierra Leone": (1185, 640, black, 20),
}

referenceTimeStamp = None

def main():
  covidCasesPerCapita, covidDeathsPerCapita = grabAndCalcCovidPerCapita()
  grabAndSaveSvg(covidCasesPerCapita, covidDeathsPerCapita)

def getLinesFromUrl(url):
  return [line.rstrip() for line in urllib.urlopen(url).readlines()]
  
def grabAndCalcCovidPerCapita():
  global referenceTimeStamp

  capita = grapCapitaFromWpTable()
  covid = grabCovidDataFromWpTemplate()
  countries = sorted(set(capita.keys()) & set(covid.keys()))
  covidCasesPerCapita = {}
  covidDeathsPerCapita = {}
  try:
    for region in countries:
      covidCasesPerCapita[region] = covid[region][0] / float(capita[region])
    for region in countries:
      covidDeathsPerCapita[region] = covid[region][1] / float(capita[region])
  except Exception as ex:
    print(region, ex)

  covidNotCapita = sorted(set(covid.keys()) - set(capita.keys()))
  print("\nRegion names with covid data but not capita:")  
  for item in covidNotCapita:
    print(item)
  
  print("\nPopulation:")
  for key in sorted(capita):
    print(key, capita[key])

  print("\nConfirmed cases, deaths and recoveries:")
  for key in sorted(covid):
    print(key, covid[key])

  print("\nDeaths in context:")
  outputDeathsInContext(covid)
    
  print("\nTotal confirmed cases per capita:")
  for region in sorted(countries):
    print(region, "%.2g" % covidCasesPerCapita[region])

  print("\nDeaths per capita:")
  for region in sorted(countries):
    print(region, "%.2g" % covidDeathsPerCapita[region])

  print("\nDeaths per total reported cases:")
  deathsPerCases = calcDeathsPerCases(covid)
  deathsPerCasesSorted = sorted(deathsPerCases.items(), key=lambda x: x[1], reverse=True)
  for key, value in deathsPerCasesSorted:
    print("%-15s %.2g" % (key, value))

  print("\nTop 100 total confirmed cases per million people:")
  casesPerCapSorted = sorted(covidCasesPerCapita.items(), key=lambda x: x[1], reverse=True)
  for key, value in casesPerCapSorted[0:100]:
    value = value * 1E6
    if value >= 1000:
      print("%-15s %i" % (key, value))
    else:
      print("%-15s %.3g" % (key, value))

  print("\nTop 100 deaths per million people:")
  deathsSorted = sorted(covidDeathsPerCapita.items(), key=lambda x: x[1], reverse=True)
  for key, value in deathsSorted[0:100]:
    value = value * 1E6
    if value >= 1000:
      print("%-15s %i" % (key, value))
    else:
      print("%-15s %.3g" % (key, value))

  if calculateChineseProvinces:
    print("\nDeaths per million people in Chinese provinces:")
    chineseProvinceData = grabCovidDataForChineseProvincesFromWpTemplate()  
    deathsPerCapitaChina = {regionName: dataRow[0] / dataRow[1] for regionName, dataRow in chineseProvinceData.items()}
    deathsPerCapitaChinaSorted = sorted(deathsPerCapitaChina.items(), key=lambda x: x[1], reverse=True)
    for key, value in deathsPerCapitaChinaSorted:
      value = value * 1E6
      if value >= 1000:
        print("%-15s %i" % (key, value))
      else:
        print("%-15s %.3g" % (key, value))
    if not chineseProvinceData:
      print("WARNING: covid data for Chinese provinces invalid. Possible cause: change in data source format.")
  
  if calculateItalianRegions:
    print("\nDeaths per million people in Italian regions:")
    covidItalian = grabCovidDataForItalianRegionsFromWp()
    populationItalian = grabPopulationForItalianRegionsFromWp()
    try:
      deathsPerCapitaItaly = {regionName: covidRow[1] / populationItalian[regionName]
                             for regionName, covidRow in covidItalian.items()}
    except Exception as ex:
      print(ex)
    deathsPerCapitaItalySorted = sorted(deathsPerCapitaItaly.items(), key=lambda x: x[1], reverse=True)
    for key, value in deathsPerCapitaItalySorted:
      value = value * 1E6
      if value >= 1000:
        print("%-15s %i" % (key, value))
      else:
        print("%-15s %.3g" % (key, value))

  referenceTimeStamp = datetime.utcnow()

  createWikiTable(covidCasesPerCapita, covidDeathsPerCapita)
  
  print("\nCurrent time (UTC):", referenceTimeStamp)
  return covidCasesPerCapita, covidDeathsPerCapita

def outputDeathsInContext(covidDataFromTemplate=None):

  # "annual-number-of-deaths-by-cause.csv": from https://ourworldindata.org/grapher/annual-number-of-deaths-by-cause

  annualByCauseFile = "annual-number-of-deaths-by-cause.csv"
  if not os.path.exists(annualByCauseFile):
    print("File not found:", annualByCauseFile)
    return

  if not covidDataFromTemplate:
    covidDataFromTemplate = grabCovidDataFromWpTemplate()
  
  pickedYear = 2017
  avgDailyDeathsRounded = {}
  with open("annual-number-of-deaths-by-cause.csv") as myfile:
    for line in myfile:
      if "Entity" in line:
        continue
      fields = line.rstrip().split(",")
      region = ensureCanonicalRegionName(fields[0])
      year = fields[2]
      if year != str(pickedYear):
        continue
      total = 0
      for idx in range(4, len(fields)):
        try:
          fieldStr = fields[idx]
          if fieldStr != "":
            total += float(fields[idx])
        except ValueError as err:
          print(err, "_%s_" % fields[idx], idx)
      avgDailyDeathsRounded[region] = int(round(total/365.0))      
    print("%-15s %-20s %-10s %7s" % ("Region", "Covid-Positive Deaths", "2017 Avg Daily Deaths", "Ratio"))
    for key in sorted(covidDataFromTemplate):
      covidDeaths = covidDataFromTemplate[key][1]
      if key in avgDailyDeathsRounded:
        try:
          ratio = covidDeaths / float(avgDailyDeathsRounded[key])
        except ZeroDivisionError:
          ratio = float("nan")
        except TypeError as ex:
          ratio = float("nan")
          print("Exception:", key, ex)
          continue
        print("%-25s %6i %10i %10.2f" % (key, covidDeaths, avgDailyDeathsRounded[key], ratio))
      elif covidDeaths is not None:
        print("%-25s %6i %10s" % (key, covidDeaths, "N/A"))
      else:
        print("%-25s %6s %10s" % (key, covidDeaths, "N/A"))
          
def createWikiTable(covidCasesPerCapita, covidDeathsPerCapita):

  def formatValue(value):
    return "%.0f" % (value * 1E6)

  with open("CovidTableWiki.txt", "w") as out:
    formattedTime = referenceTimeStamp.strftime("%Y-%m-%d %H:%M")
    print((u"Confirmed cases and deaths per million inhabitants calculated from [[Template:2019\u201320 coronavirus pandemic data]]"
           " and [[List of countries and dependencies by population]] on %s UTC:" % formattedTime).encode('utf-8'), file=out)
    print("{| class=\"sortable wikitable\"", file=out)
    print("|-", file=out)
    print("! Country !! Cases per<br> million inhabitants<br>(rounded) !! Deaths per<br> million inhabitants<br>(rounded)", file=out)
    regions = set(covidCasesPerCapita.keys()) & set(covidDeathsPerCapita.keys())
    for region in sorted(regions):
      print("|-", file=out)
      print("| style=\"text-align: left;\" | %s || style=\"text-align: right;\" |  %s || style=\"text-align: right;\" |  %s " %
           (region, formatValue(covidCasesPerCapita[region]),
                    formatValue(covidDeathsPerCapita[region])), file=out)
    print("|}", file=out)
          
def calcDeathsPerCases(covidData):
  # covidData: dict: region name --> triple (a list)
  deathsPerCases = {}
  for regionName in covidData:
    deaths, cases = covidData[regionName][1], covidData[regionName][0]
    if cases >= 100:
      deathsPerCases[regionName] = deaths / cases
  return deathsPerCases
  
def cleanAndSetupHtmlForTableExtraction(allLines):
  allLines = re.sub("</table.*", "", allLines)
  allLines = re.sub("<(th|td)[^>]*>", r"<td>", allLines)
  allLines = re.sub("</?(span|img|a|sup|div)[^>]*>", "", allLines)
  allLines = re.sub("</(th|td|tr)[^>]*>", "", allLines)
  allLines = re.sub("&#91;.*?&#93;", "", allLines)
  allLines = re.sub(",", "", allLines)
  allLines = re.sub("<small>.*?</small>;?", "", allLines)
  allLines = re.sub("</?(i|b|p)>", "", allLines)
  allLines = re.sub("&#160;", " ", allLines)
  return allLines
  
def grapCapitaFromWpTable():
  lines = getLinesFromUrl(
    "https://en.wikipedia.org/wiki/List_of_countries_and_dependencies_by_population")
  lines = " ".join(lines)
  lines = re.sub("^.*Country (or dependent territory).*</tr>", "", lines)
  lines = cleanAndSetupHtmlForTableExtraction(lines)

  outData = {}
  rows = lines.split("<tr> ")
  for row in rows:
    try:
      if "Population" in row: continue
      cols = row.split("<td>")
      region = ensureCanonicalRegionName(cols[2])
      population = int(cols[3])
    except Exception as ex:
      print(ex)
      continue
    outData[region] = population
  return outData

def grabCovidDataFromWpTemplate():
  # Returns a dict: region name --> [cases, deaths, recoveries]
  lines = getLinesFromUrl(
    "https://en.wikipedia.org/wiki/Template:2019%E2%80%9320_coronavirus_pandemic_data")
  lines = " ".join(lines)
  lines = re.sub("^.*jquery-tablesorter", "", lines) # This used to work.
  lines = re.sub("^.*<table class=.wikitable", "", lines)
  lines = cleanAndSetupHtmlForTableExtraction(lines)

  outData = {}
  rows = lines.split("<tr> ")
  for row in rows:
    region = None
    try:
      if "Location" in row: continue
      if "&#8205;" in row: continue # Row with totals
      cols = row.split("<td>")
      region = cols[2].strip()
      region = ensureCanonicalRegionName(region)
      if re.match("^ *[0-9,]* *$", region): continue # Not a region but totals
      if region == "Cases": continue
      cols = cols[3:6]
      cols = [int(col) if re.match("^ *[0-9]* *$", col) else None for col in cols]
      if cols == [None, None, None]: # Skip regions reporting no data, e.g. Tanzania at one point
        continue
    except Exception as ex:
      print(region, ex)
      continue
    outData[region] = cols
  return outData

def grabCovidDataForChineseProvincesFromWpTemplate():
  # Retuns a dict: region names --> (deaths, population)
  lines = getLinesFromUrl(
    "https://en.wikipedia.org/wiki/Template:2019%E2%80%9320_coronavirus_pandemic_data/China_medical_cases_by_province")
  lines = " ".join(lines)
  lines = re.sub("^.*?Cases of COVID.19 in Mainland China.*?</caption>", "", lines)
  lines = re.sub("<th rowspan=.*?</th>", "", lines)
  lines = cleanAndSetupHtmlForTableExtraction(lines)

  outData = {}
  rows = lines.split("<tr> ")
  for row in rows:
    try:
      if "Type" in row: continue
      if "Last Updated" in row: continue
      if "Country" in row: continue
      if "tbody" in row: continue
      cols = row.split("<td>")
      region = cols[1].strip()
      region = ensureCanonicalRegionName(region)
      if re.match("^ *[0-9,]* *$", region): continue # Not a region but totals
      deaths = int(cols[7])
      population = int(cols[8].replace("M", ""))*1E6 # e.g. 59M
      cols = (deaths, population)
    except Exception as ex:
      print(row, ex)
      continue
    outData[region] = cols
  dataInvalid = "Hubei" not in outData
  if dataInvalid:
    return {}
  else:
    return outData

def grabCovidDataForItalianRegionsFromWp():
  # Returns dict: region name --> [confirmed cases, deaths, recoveries, tamponi eseguity (tests performed?)]
  lines = getLinesFromUrl("https://it.wikipedia.org/wiki/Pandemia_di_COVID-19_del_2020_in_Italia")
  lines = " ".join(lines)
  lines = re.sub("^.*?Tabelle e grafici sulla distribuzione dei casi in Italia.*?<th>Regione.*?</tr>", "", lines)
  lines = cleanAndSetupHtmlForTableExtraction(lines)

  outData = {}
  rows = lines.split("<tr> ")
  for row in rows:
    try:
      if re.match("^ *$", row): continue
      if "tbody" in row: continue
      if "Italia" in row or "Vaticano" in row or "San Marino" in row: continue
      cols = row.split("<td>")
      region = cols[1].strip()
      region = ensureCanonicalRegionName(region)
      cols = cols[2:5]
      cols = [int(x.replace(" ", "")) for x in cols]
    except Exception as ex:
      print(row, ex)
      continue
    outData[region] = cols
  return outData

def grabPopulationForItalianRegionsFromWp():
  lines = getLinesFromUrl("https://it.wikipedia.org/wiki/Regione_%28Italia%29")
  lines = " ".join(lines)
  lines = re.sub("^.*?tabella contenente popolazione.*?<th.*?>Regione.*?</tr>", "", lines) # Brittle
  lines = cleanAndSetupHtmlForTableExtraction(lines)
  outData = {}
  rows = lines.split("<tr> ")
  for row in rows:
    try:
      if re.match("^ *$", row): continue
      if "tbody" in row: continue
      if "Italia" in row or "Vaticano" in row or "San Marino" in row: continue
      cols = row.split("<td>")
      region = cols[1].strip()
      region = ensureCanonicalRegionName(region)
      population = int(cols[3].replace(" ", ""))
    except Exception as ex:
      print(row, ex)
      continue
    outData[region] = population
  return outData

def extractRegionCodeToTitleFromSvg(svgLines):
  regionTitles = {}
  openedRegion = ""
  for line in svgLines:
    match = re.match(".*<(g|path) id=\"(.*?)\"", line)
    if match:
      openedRegion = match.group(2)
    elif openedRegion != "" and "<title>" in line:
      line = re.sub(".*<title>", "", line)
      line = re.sub("</title>.*", "", line)
      regionTitles[openedRegion] = ensureCanonicalRegionName(line)
    else:
      openedRegion = ""
  return regionTitles
  
def ensureCanonicalRegionName(name):
  name = name.strip()
  if name in regionNameCanonizationMap:
    name = regionNameCanonizationMap[name]
  if unicode(name, "utf-8") in regionNameCanonizationMap:
    name = regionNameCanonizationMap[unicode(name, "utf-8")]
  name = re.sub(",.*", "", name)
  name = re.sub("&amp;", "and", name) # e.g. Bosnia &amp; Herzegovina --> Bosnia and Herzegovina
  name = re.sub(r" *\(.*\)", "", name) # e.g. Bermuda (UK) --> Bermuda
  if name in regionNameCanonizationMap:
    name = regionNameCanonizationMap[name]
  if unicode(name, "utf-8") in regionNameCanonizationMap:
    name = regionNameCanonizationMap[unicode(name, "utf-8")]  
  return name

colorsForDeaths = [
  #"#eeccee", "#cc99cc", "#aa77aa", "#885588", "#663366", "#441144",
  #"#eeccee", "#cc99cc", "#aa77aa", "#885588", "#663366", "#000000",
  #"#f1eef6", "#d4b9da", "#c994c7", "#df65b0", "#dd1c77", "#980043",
  # ^ https://colorbrewer2.org/#type=sequential&scheme=PuRd&n=6
  #"#e1e0f6", "#d4b9da", "#c994c7", "#df65b0", "#dd1c77", "#980043", # Mod.of above
  #"#d1d0e6", "#d4b9da", "#c994c7", "#df65b0", "#dd1c77", "#980043", # Mod.of above
  #"#edf8fb", "#bfd3e6", "#9ebcda", "#8c96c6", "#8856a7", "#810f7c",
  # ^ https://colorbrewer2.org/#type=sequential&scheme=BuPu&n=6
  "#ffffcc", "#c7e9b4", "#7fcdbb", "#41b6c4", "#2c7fb8", "#253494",
  # ^ https://colorbrewer2.org/#type=sequential&scheme=YlGnBu&n=6
]

colorsForCases = [
  "#FDD5C1", "#ffC0C0", "#ee7070", "#c80200", "#900000", "#510000",
]
  
def createSvgStyles(regionTitles, covidCasesPerCapita, forDeaths=False):
  regionTitleToCode =  {v: k for k, v in regionTitles.iteritems()}
  colors = colorsForDeaths if forDeaths else colorsForCases
  def appendStyleForRegion(styleLines, regionName, colorIndex):
    if regionName in regionTitleToCode:
      selector = "." + regionTitleToCode[regionName]
      if selector == ".ma-":
        selector = "#ma-" # Exception for Morocco to separate it from West Sahara
      importance = ""
      if regionName == "Taiwan":
        importance = " !important"
      styleLines.extend([
        "/* " + regionName + " */",
        selector,
        "{",
        "   fill:%s%s;" % (colors[colorIndex], importance),
        "}"
        ""])
    else:
      print("WARNING: region name not found in name-to-code mapping:", regionName)
  styleLines = []
  for regionName in covidCasesPerCapita:
    count = covidCasesPerCapita[regionName]
    if count == 0:
      continue
    countLog = int(math.log(count, 10))
    colorIndex = countLog + (8 if forDeaths else 8)
    colorIndex = min(colorIndex, 5)
    colorIndex = max(colorIndex, 0)
    appendStyleForRegion(styleLines, regionName, colorIndex)
  return styleLines

def insertStyleLines(allLines, styleLines):
  # Find index of  </style> and place svgStyleLines before that.
  styleLines.reverse()
  lineNo = 0
  for line in allLines:
    if re.match("^[ \t]*</style>[ \t]*$", line):
      break
    lineNo += 1
  styleEndIndex = lineNo
  for line in styleLines:
    allLines.insert(styleEndIndex, line)

def insertTimeStampAndLegend(allLines, valuesPerCapita, forDeaths=False):

  valueMaximum = 1E6 * max(valuesPerCapita.values())
  valueMaximum = int(math.ceil(valueMaximum / 100.0) * 100) # Round up
  
  # Limitation: the colors are hardwired for deaths.
  
  legend = """
    <path
       d="m 1823,1004 h 49 v 28 h -49 v -28"
       style="fill:#%s" />
    <text
       x="1887" y="1028" font-size="34" font-family="Verdana" fill="#666666"
       >&lt; 0.1</text>
    <path
       d="m 1823,1048 h 49 v 28 h -49 v -28"
       style="fill:#%s" />
    <text
       x="1887" y="1074" font-size="34" font-family="Verdana" fill="#666666"
       >0.1&#x2013;1</text>
    <path
       d="m 1823,1095 h 49 v 28 h -49 v -28"
       style="fill:#%s" />
    <text
       x="1887" y="1121" font-size="34" font-family="Verdana" fill="#666666"
       >1&#x2013;10</text>
    <path
       d="m 1823,1142 h 49 v 28 h -49 v -28"
       style="fill:#%s" />
    <text
       x="1887" y="1168" font-size="34" font-family="Verdana" fill="#666666"
       >10&#x2013;100</text>
    <path
       d="m 1823,1188 h 49 v 28 h -49 v -28"
       style="fill:#%s" />
    <text
       x="1887" y="1214" font-size="34" font-family="Verdana" fill="#666666"
       >100&#x2013;%i</text>
""" % ("c7e9b4", "7fcdbb", "41b6c4", "2c7fb8", "253494", valueMaximum)

  formattedTime = referenceTimeStamp.strftime("%Y-%m-%d %H:%M")
  deathSign = "&#x271D; " if forDeaths else ""
  timeText = ('<text x="1300" y="1360" fill="#666666" font-size="34" '
              'font-family="Verdana">%s%s UTC</text>\n' % (deathSign, formattedTime))
  lineNo = 0
  for line in allLines:
    if re.match("^[ \t]*</svg>[ \t]*$", line):
      break
    lineNo += 1
  svgEndIndex = lineNo
  allLines.insert(svgEndIndex, timeText)
  if forDeaths:
    allLines.insert(svgEndIndex, legend)

def insertFigures(allLines, valuesPerCapita):
  figures = ""
  #
  for region in sorted(valuesPerCapita):
    if not region in figureSpec:
      print("WARNING: no figure label specification for region %s" % region)
      continue
    unroundedValue = valuesPerCapita[region] * 1E6
    if unroundedValue < 0.01:
      continue
    if unroundedValue < 0.1:
      value = str(round(unroundedValue, 2)).replace("0.", ".") # Drop the leading zero
    elif unroundedValue < 1:
      value = str(round(unroundedValue, 1)).replace("0.", ".") # Drop the leading zero
      value = value.replace("1.0", "1")
    else:
      value = int(round(unroundedValue))
    fontSize = figureSpec[region][3]
    if hideSmallFontLabelsViaFontSizeZero and fontSize < 20:
      fontSize = 0 # Disable display while keeping the information in the text
    #
    figure = ('<text x="%s" y="%s" fill="#%s" font-size="%s" '
              'font-family="Verdana">%s</text><!-- %s: %.3f-->\n' %
              (figureSpec[region][0], figureSpec[region][1], figureSpec[region][2], fontSize, value, region, unroundedValue))
    figures += figure
  #
  lineNo = 0
  for line in allLines:
    if re.match("^[ \t]*</svg>[ \t]*$", line):
      break
    lineNo += 1
  svgEndIndex = lineNo
  allLines.insert(svgEndIndex, figures)
  
def setDefaultLandColor(allLines, colorSpec):
  # colorSpec is rrggbb, with no "#".
  allLines[:] = [line.replace("c0c0c0", colorSpec) for line in allLines]

def writeLinesToFile(fileName, lines):
  with open(fileName, "w") as outfile:
    for line in lines:
      outfile.write(line)
      outfile.write("\n")

def grabAndSaveSvg(covidCasesPerCapita, covidDeathsPerCapita):
  allLines = getLinesFromUrl("https://upload.wikimedia.org/wikipedia/commons/4/4d/BlankMap-World.svg")
  allLinesBackup = allLines[:]
  regionTitles = extractRegionCodeToTitleFromSvg(allLines)

  styleLines = createSvgStyles(regionTitles, covidCasesPerCapita)
  insertStyleLines(allLines, styleLines)
  insertTimeStampAndLegend(allLines, covidCasesPerCapita)
  setDefaultLandColor(allLines, "e0e0e0")
  writeLinesToFile("COVID-19 Outbreak World Map Total Cases per Capita.svg", allLines)

  allLines = allLinesBackup
  styleLines = createSvgStyles(regionTitles, covidDeathsPerCapita, forDeaths=True)
  insertStyleLines(allLines, styleLines)
  insertTimeStampAndLegend(allLines, covidDeathsPerCapita, forDeaths=True)
  insertFigures(allLines, covidDeathsPerCapita)
  setDefaultLandColor(allLines, "e0e0e0")
  writeLinesToFile("COVID-19 Outbreak World Map Total Deaths per Capita.svg", allLines)

main()

The script takes no arguments, downloads the data and the world map template from Wikipedia, outputs calculation results and creates two SVG files. There may be glitches in region matches between the two main data sources in Wikipedia, and we need to figure out how to fix them; overall, the map should be fine. --Dan Polansky (talk) 08:08, 18 March 2020 (UTC)[reply]

Script updated. --Dan Polansky (talk) 08:40, 18 March 2020 (UTC)[reply]
Script updated. --Dan Polansky (talk) 09:59, 18 March 2020 (UTC)[reply]
Script updated. --Dan Polansky (talk) 10:35, 18 March 2020 (UTC)[reply]
Script updated. --Dan Polansky (talk) 19:08, 18 March 2020 (UTC)[reply]
Script updated. --Dan Polansky (talk) 15:53, 19 March 2020 (UTC)[reply]
Script updated. --Dan Polansky (talk) 07:07, 20 March 2020 (UTC)[reply]
Script updated; it now calculates and outputs deaths per million in Chinese provinces. But since I have no world map with Chinese provinces, no impact on maps yet. --Dan Polansky (talk) 10:17, 20 March 2020 (UTC)[reply]
Script now calculates and outputs deaths per million for Italian regions; no impact on maps. --Dan Polansky (talk) 12:52, 20 March 2020 (UTC)[reply]
Script updated. --Dan Polansky (talk) 19:43, 21 March 2020 (UTC)[reply]
Script updated. Extraction of Chinese province data does not work, but has no impact on the map production. --Dan Polansky (talk) 19:06, 27 March 2020 (UTC)[reply]
Script updated, especially for region name mapping. --Dan Polansky (talk) 17:04, 3 April 2020 (UTC)[reply]
Script updated to work for Morocco: I have forbidden dash in id strings. The change looks good, but I am afraid there could be side effects in future. --Dan Polansky (talk) 18:04, 3 April 2020 (UTC)[reply]
Script updated to separate Morocco from West Sahara. --Dan Polansky (talk) 18:03, 4 April 2020 (UTC)[reply]
Script updated to output deaths in the context of average daily 2017 deaths, given file annual-number-of-deaths-by-cause.csv from https://ourworldindata.org/grapher/annual-number-of-deaths-by-cause. --Dan Polansky (talk) 11:41, 8 April 2020 (UTC)[reply]
Script updated to calculate ratio for the death context. --Dan Polansky (talk) 13:16, 8 April 2020 (UTC)[reply]
Script updated: added timestamp, a legend and changed the color scheme to green-to-blue for deaths. --Dan Polansky (talk) 13:49, 9 April 2020 (UTC)[reply]
Error in legend colors corrected. --Dan Polansky (talk) 14:08, 9 April 2020 (UTC)[reply]
Expanded to created CovidTableWiki.txt. --Dan Polansky (talk) 15:55, 10 April 2020 (UTC)[reply]
Changed the legend to show the maximum value rounded up; etc. --Dan Polansky (talk) 17:57, 12 April 2020 (UTC)[reply]
Expanded to show figures for the darker countries except for some small ones with figure placement difficulties. --Dan Polansky (talk) 18:09, 19 April 2020 (UTC)[reply]
Added "!important" for Taiwan to prevent China color applying to it. --Dan Polansky (talk) 06:06, 20 April 2020 (UTC)[reply]
More country label specs added; etc. --Dan Polansky (talk) 16:32, 21 April 2020 (UTC)[reply]
Better mapping for some regions; etc. --Dan Polansky (talk) 17:08, 23 April 2020 (UTC)[reply]
Number labels for many more counties; etc. --Dan Polansky (talk) 16:14, 24 April 2020 (UTC)[reply]
More number labels, aiming to cover all 5 colors except for countries with label placement difficulties; etc. --15:59, 26 April 2020 (UTC)
Tweak number label production; etc. --Dan Polansky (talk) 17:08, 30 April 2020 (UTC)[reply]
More number labels; etc. --Dan Polansky (talk) 17:16, 1 May 2020 (UTC)[reply]
More number labels; etc. --Dan Polansky (talk) 17:01, 2 May 2020 (UTC)[reply]
More number labels; etc. --Dan Polansky (talk) 17:19, 20 May 2020 (UTC)[reply]
Misc updates. --Dan Polansky (talk) 17:35, 28 June 2020 (UTC)[reply]
Misc updates. --Dan Polansky (talk) 19:26, 26 July 2020 (UTC)[reply]

Calculation results[edit]

The map is made via scripted calculation whose textual results are currently published at B:User:Dan Polansky/COVID-19#Deaths per capita. The Wikibooks page may get out of date if me or someone else updates the map but not the results. Can be used for double-checking: you can double-check the colors against the rates per capita, and you can double check the rates per capita against the data sources. --Dan Polansky (talk) 13:57, 18 March 2020 (UTC)[reply]

Issues[edit]

1) South Korea has no color which cannot be. Other countries can be missing in a similar vein.

--Dan Polansky (talk) 08:56, 18 March 2020 (UTC)[reply]

Fixed issue 1. --Dan Polansky (talk) 10:00, 18 March 2020 (UTC)[reply]

2) Shouldn't there be a delay in downloading successive URLs so that the WMF servers are not overloaded? At least a few seconds? We don't want to DDOS the servers - and we don't want well-intentioned newbies to get blocked by the servers as suspected (non-distributed)DOSers. Boud (talk) 00:24, 19 March 2020 (UTC)[reply]

Thank you. There are 3 web pages in total being downloaded by the script, which does not see too many. The demand on servers is going to be negligible compared to the demand created by Wikipedia viewers. But should people report actual problems (blocked by servers from running the script), I will surely add a delay before each download. --Dan Polansky (talk) 07:26, 19 March 2020 (UTC)[reply]

3) The script should probably be located somewhere where only a narrow group of editors can edit the script, starting with me. What is the usual practice for script storage? At a minimum, the present talk page hosting the script should be locked so that no IP can edit it, only confirmed users if there's such a thing in Wikipedia, or autopatrollers, or the like. --Dan Polansky (talk) 12:09, 19 March 2020 (UTC)[reply]

Color scheme[edit]

I now use this:

 
100 ≤ total deaths per 1 million people
 
10 ≤ total deaths per 1 million people < 100
 
1 ≤ total deaths per 1 million people < 10
 
0.1 ≤ total deaths per 1 million people < 1
 
0.01 ≤ total deaths per 1 million people < 0.1
 
0 < total deaths per 1 million people < 0.01

Before I used this and you can see in the image history how it looks like:

 
100 ≤ total deaths per 1 million people
 
10 ≤ total deaths per 1 million people < 100
 
1 ≤ total deaths per 1 million people < 10
 
0.1 ≤ total deaths per 1 million people < 1
 
0.01 ≤ total deaths per 1 million people < 0.1
 
0 < total deaths per 1 million people < 0.01

The current scheme shifts hues a little (good), but its lighter colors are lighter than the non-color gray indicating no data or deaths (not so good). In some ways, the previous scheme was better. We need to find a good color scheme. --Dan Polansky (talk) 11:03, 18 March 2020 (UTC)[reply]

@Dan Polansky: I think the background for countries with no deaths should be lightened a bit to match the color used for the per capita and totals maps. Also, can you update the legend to include the color for no deaths, as was done with the other two maps? Sdkb (talk) 21:28, 19 March 2020 (UTC)[reply]
Sdkb, done. I used e0e0e0 for the default land and I made the lightest region a bit darker, using d1d0e6. --Dan Polansky (talk) 07:08, 20 March 2020 (UTC)[reply]
Looks good! I'm itching to get this map added to the main article, but I need to let this discussion (which is getting strangely low participation) play out first. Sdkb (talk) 07:20, 20 March 2020 (UTC)[reply]


Redundancy[edit]

A png variant from Our World in Data

There is also File:Total-covid-deaths-per-million.png obtained from Our World in Data, now included in the article body. For reference. They distinguish zero deaths from no data. --Dan Polansky (talk) 08:34, 20 March 2020 (UTC)[reply]

Separate zero deaths from no data[edit]

Should I separate zero deaths from no data? I would place zero deaths to the lightest range and the legend for that range would be changed from ">0–0.01 deaths per million inhabitants" to "0–0.01 deaths per million inhabitants", dropping the leading ">". --Dan Polansky (talk) 09:14, 20 March 2020 (UTC)[reply]

There is a fundamental difference between 0 deaths and 1 death, though. If you separate zero deaths from no data, it needs to be done in a way that does not mix countries with and without deaths. If light purple were used, I'm afraid it would give the intuitive impression that those countries have deaths. May I suggest a darker shade of gray could be used for no data? —St.nerol (talk) 09:06, 24 March 2020 (UTC)[reply]

Per capita = per each, not per million[edit]

Apparently no one here knows the meaning of per capita. Can someone revise the map and accompanying caption to indicate that the deaths are per million.

For example: Japanese national debt is ~$11.06 trillion in total, but per capita it is ~$102,000. 73.26.46.210 15:49, 21 March 2020 (UTC)[reply]

This is just a matter of scale in the legend. Where the legend says "0.1–1 deaths per million inhabitants", it could equally say "0.0000001–0.000001 deaths per capita (per single inhabitant)". An image per capita looks the same, just has different legend. I see no need for a revision. Let's also look at File:COVID-19 Outbreak World Map per Capita.svg: its legend says "per 1,000 inhabitants", "per 10,000 inhabitants", etc.; and yet, it is still fundamentally a per-capita map, with a certain way of representing the dimensions in the legend. --Dan Polansky (talk) 16:11, 21 March 2020 (UTC)[reply]
The singular 'per caput' is per single person (literally: per head). The plural 'per capita' is per any given amount of people. CasparV (talk) 06:52, 29 April 2021 (UTC)[reply]

Keeping caption at Wikipedia up to date[edit]

I just updated the caption at the main coronavirus pandemic article, which was still saying 21 March even though this is up to date to today (the 23rd, at least for much of the world rn). When this map gets updated in the future, is there any better way to make sure captions in the places where it's used on WP are also updated along with it? Sdkb (talk) 21:28, 23 March 2020 (UTC)[reply]

A friend suggested that I place a timestamp directly to the svg. I thought it was a pretty fine idea; what stopped me from doing it is that it is not customary in Wikipedia for similar maps. --Dan Polansky (talk) 19:10, 24 March 2020 (UTC)[reply]
For reference, the image has featured a timestamp directly in the svg since Apr 9. I believe it is a good thing, even an essential thing. --Dan Polansky (talk) 09:44, 2 May 2020 (UTC)[reply]

Cutoff levels[edit]

The lowest category (lightest purple) is very specific and will very soon be redundant. It's for countries with deaths less then one per 100 million inhabitants, and so is only relevant for countries with huge populations, most of which already have higher death rates. It's currently used only for India and Nigeria, and its only other potential use is for Russia and Ethiopia, during the time which they have exactly one death. —St.nerol (talk) 09:17, 24 March 2020 (UTC)[reply]

I've now removed this color from the palette. –St.nerol (talk) 08:24, 9 April 2020 (UTC)[reply]

Morocco vs. West Sahara[edit]

Someone pointed out the distinction; the script currently colors both Morocco and West Sahara using the same color. We probably need to pick Morocco via "#ma-" rather than via ".ma", where the latter is a class selector and picks both Morocco and West Sahara. Since the script actually uses regex to match ids rather than classes, using id selectors (#) for coloring would probably be more appropriate. I'll see what I can do upon the next update. For comparison, File:Total-covid-deaths-per-million.png has West Sahara separate from Morocco. --Dan Polansky (talk) 20:14, 3 April 2020 (UTC)[reply]

Corrected; using #ma- to pick Morocco. --Dan Polansky (talk) 18:06, 4 April 2020 (UTC)[reply]

Abandoning the map to prevent misleading the reader[edit]

I am increasing concerned about whether this map should be in Wikipedia articles at all. An objection I have read elsewhere is that it is probably not a good idea to make a map that is fed with poor data basis. And the suspition has it that the data basis for the covid-related deaths is not all that much better than the data basis for covid-positive cases: it depends on the rate in which testing increases with vastly differing testing regimens in different countries, and many countries seem to report covid-positive deaths rather than covid-caused deaths. The reader would quite possibly be better off if they were looking at the numbers (deaths per capita) and read disclaimers rather than looking at world maps that use colors. And the colors chosen signal alarm: the deaths per capita uses reddish colors although with violet, and the cases per capita map uses reddish colors. While the situation may be grave, the mere numbers from which the maps are made alone do not indicate gravity, and the maps should not prejudge gravity of the situation by the choice of color, I think. --Dan Polansky (talk) 10:54, 6 April 2020 (UTC)[reply]

We can't let the perfect be the enemy of the good. This is the data we have for now, and I think we should believe in communicating verifiable and relevant facts, regardless of whether the information causes alarm. Perhaps the situation is alarming? Let everyone judge for themselves. If plain numbers cause less alarm, that's probably because they don't communicate as effectively as a visual representation. What color palette is used is really secondary, I think. Purple looks nice, though. --St.nerol (talk) 08:22, 9 April 2020 (UTC)[reply]
Then show the data, not an image that suggests false confidence in the data. And again, the image should not prejudge anything. When you look at the data calculated to produce the image, the data does not suggest anything catastrophic. The worst deaths the data shows is San Marino: 1012 per million; Lombardia: 944 per million; Spain: 295 per million; Italy: 284 per million; Andorra: 284 per million; Wuhan: 226 per million. None of that shows a catastrophy or very grave situation, only a moderately grave impact. When you consider the death rate per year is on the order of 1% in most countries, that is 10000 per million in a year. Yes, something's going on there with the covid, but not catastrophic.
Re: "Let everyone judge for themselves.": Indeed, so why am I prejudging by showing reddish colors?
And Wikipedia is not showing the data. Wikipedia is showing the image, but it does not show the per capita data. That is bad. --Dan Polansky (talk) 10:56, 9 April 2020 (UTC)[reply]

(outdent) I went ahead and changed the color scheme since I can no longer put my name on the previous color scheme. I added time stamp and a legend, so the map is a bit more professional. --Dan Polansky (talk) 13:54, 9 April 2020 (UTC)[reply]

The '✟' to me indicates a single person died on Antarctica on that date. I don't associate that cross with the last update-date. I think it'd be better to write out the explicit text: "last updated: 22 April 2021"; there's more than enough room. CasparV (talk) 07:00, 29 April 2021 (UTC)[reply]

Taiwan[edit]

@User:Dan Polansky: This File:COVID-19 Outbreak World Map Total Deaths per Capita.svg map is shading Taiwan the same as China, which is inconsistent with the data (per en:Template:2019-20 coronavirus pandemic data, Taiwan currently has 6 deaths, for a population of 23,780,452, giving 0.25 per million, which is an order of magnitude lower than China's ratio of 4,632 for a population of 1,427,647,786, which is 3.24 per million) and inconsistent with the practice on other maps like File:COVID-19 Outbreak World Map per Capita.svg and File:COVID-19 Outbreak World Map.svg which treat Taiwan separately. —Lowellian (talk) 23:57, 19 April 2020 (UTC)[reply]

Actually, investigating some more, this is weird: the SVG version at https://upload.wikimedia.org/wikipedia/commons/8/88/COVID-19_Outbreak_World_Map_Total_Deaths_per_Capita.svg is showing Taiwan with the same (wrong) color as China but the PNG version at https://upload.wikimedia.org/wikipedia/commons/thumb/8/88/COVID-19_Outbreak_World_Map_Total_Deaths_per_Capita.svg/1280px-COVID-19_Outbreak_World_Map_Total_Deaths_per_Capita.svg.png is showing Taiwan with a different (correct) color from China. Both are dated 2020-04-19 at the bottom. Why are the SVG and PNG rendering differently? Is there a glitch in the layers in the SVG? —Lowellian (talk) 00:08, 20 April 2020 (UTC)[reply]

Lowellian: Taiwan is coded like this: <g id="tw" class="landxx coastxx cn tw">. Thus, bot "cn" (China) and "tw" (Taiwan) classes apply to Taiwan, and I wonder about priority of application of styles. I added "!important" to CSS for Taiwan, and at least in one rendering context, it helped. Let's see whether it solves the problem everywhere. --Dan Polansky (talk) 06:08, 20 April 2020 (UTC)[reply]
@User:Dan Polansky: Thanks, but wouldn't it be better to just remove the "cn" class from the <g> element for Taiwan to avoid any ambiguity as to which style gets applied? —Lowellian (talk)
@Lowellian: The result would be the same, right? There is some elegance in leaving the source map intact and only working with CSS. Are there still any problems remaining in any rendering context? --Dan Polansky (talk) 19:14, 20 April 2020 (UTC)[reply]

Legend and numbers in the image file[edit]

@Dan Polansky: Could we remove the legend from the image file itself? Every instance of this image will need to have a legend in the text (since the units are necessarily unlabeled in the actual image, which is used in many languages), so it's always going to be redundant. Regarding the numbers over countries in the image, I kinda like those, but right now it seems very arbitrary which ones are labeled and which aren't. Why Peru but not China? I would keep them only for the geographically largest countries, where they can be made a reasonable size (the ones for Europe are too tiny). Sdkb (talk) 04:18, 24 April 2020 (UTC)[reply]

  • The legend directly placed in the SVG provides scale for display contexts where only the map is shown, such as an enlarged view or a full-screen view. The textual legend outside of the map does not necessarily need to indicate the numerical ranges; if it does, that's ok. Similar maps from ourworldindata.org also have a legend.
  • The choice of countries to show numbers for was driven by the color and thus by the numerical ranges: the regions for the two highest colors/ranges have numbers shown except for regions where there is not enough room in the map. With more effort, I should be able to place the numbers also to the 3rd-color regions, although that is not so interesting since we know from the color the figures/numbers for these regions are under 10. As for the smaller-font numbers in Europe, the small font is indeed not ideal, but my conclusion after having thought about it was that it is better to provide information that can be comfortably viewed in an enlarged image view than to fail to provide that information altogether; information utility over aesthetics. --Dan Polansky (talk) 06:48, 24 April 2020 (UTC)[reply]
    Looks good to me! Thanks for your work on this! Sdkb (talk) 00:06, 28 April 2020 (UTC)[reply]

Ecuador has more than 100 deaths per cápita[edit]

With the last data given by the Ecuadorian government (2,127 deaths), the country has more than 100 deats per cápita, being one of the most affected countries in the world by the disease. Please correct the map with the latest information about the outbreak of the COVID-19 in Ecuador.

Greetings.— Emilio Mondragón (talk) 21:54, 10 May 2020 (UTC) — Preceding unsigned comment added by Emilio Santander (talk • contribs) 21:53, 10 May 2020 (UTC)[reply]

I update the map about every 2 or 3 days, occasionally every single day. Thus, the map gets outdated a little, but especially the numbers are usually on the proper scale, and the reader is well advised to look at the numbers in the map, not only at the colors. --Dan Polansky (talk) 10:51, 15 May 2020 (UTC)[reply]

Decimal values[edit]

@Dan Polansky: I'm unsure if this has been brought up previously, but I think that decimal values in the map should be changed to include leading zeros (e.g. ".4" to "0.4"). My main concern is that the decimal point can be very easy for readers to miss, thus making a particular value seem to be an order of magnitude larger than it actually is. This would also be in line with the Manual of Style at Wikipedia. — RAVENPVFF · talk · 09:37, 15 May 2020 (UTC)[reply]

When designing the number labels, I have learned that the ".x" format as opposed to "0.x" format looks much better in the map, to me anyway. My thought was that, should someone be confused, the background color unmistakably disambiguates, say, ".4" from "4". --Dan Polansky (talk) 10:40, 15 May 2020 (UTC)[reply]
@Dan Polansky: That can be true, yes, but it then brings up the question of accessibility – colour-blind readers might not be able to distinguish the two easily. Using the "0.x" format would be definitively unambiguous to everyone, in my opinion. — RAVENPVFF · talk · 05:11, 16 May 2020 (UTC)[reply]

Comparing to excess deaths[edit]

As a follow up on #Abandoning the map to prevent misleading the reader, the reader is well advised to compare the data on the map with excess deaths, which can be obtained for some European countries on Euromomo[1].

For instance, Denmark has over 100 per million pop deaths shown in the map, much worse than, say, Australia. However, there are no obvious excess deaths for Denmark in Euromomo[2].

Some of the covid-relating deaths are really mere covid-positive deaths rather than covid-caused deaths. One should always compare to excess deaths data if available. (Old news, but for the record.) --Dan Polansky (talk) 21:01, 7 June 2020 (UTC)[reply]

Site mortality.org is another source of excess death data; it has visualization in shinyapps.io[3]. The vizualization shows deaths rather than EuroMOMO's z-scores and it allows to show deaths per sex and per age group. The age group can be seen e.g. by choosing "Deaths, Ages 15-64" in "Measure" field. As a baseline to compare to, they use averages over a time range, and the time range can be adjusted. --Dan Polansky (talk) 10:58, 31 July 2020 (UTC)[reply]

U.K. number went down[edit]

I noted the U.K. number went down from 697 to 619. That would be explained by the review and resulting revision of the number reported in the media. --Dan Polansky (talk) 06:05, 17 August 2020 (UTC)[reply]

Change levels?[edit]

I note that there is only one country in the "< 0.1" level (Rwanda - a country which is actally now beyond that level) and that - sadly - it's likely that Peru will soon pass the 1000 mark and others may join it. Is it time to combine it with the "0.1-1" level, and add in either a ">500" or ">1000" level at the top? Grutness (talk) 10:07, 14 September 2020 (UTC)[reply]

Proposal noted. I may implement some of it depending on gumption and the like. The map seems fine as is especially since it has all the numerical labels that make the optimality of division into ranges for coloring less critical, but nice-to-have improvements may be implemented nonetheless. --Dan Polansky (talk) 16:31, 4 October 2020 (UTC)[reply]

Updating the script[edit]

I don't know much about Python and when trying to interpret the script there are some errors I can't resolve. Could somebody update it? (or explain how to fix "AttributeError: module 'urllib' has no attribute 'urlopen'") --Antondimak (talk) 13:57, 10 November 2020 (UTC) Could someone please respond? --Antondimak (talk) 17:05, 17 December 2020 (UTC)[reply]

It was a problem with the libraries. --Antondimak (talk) 07:18, 19 December 2020 (UTC)[reply]

Legend, 2 colors for some numbers.[edit]

Can the legend be changed so that there isn't 2 different colors for 6, 32, 178, and 1000? -- Jeandré, 2021-01-13t06:37z

Legend number scaling.[edit]

Can the numbers used be less random? Either go decimal:

  • 0
  • 1-4
  • 5-9
  • 10-49
  • 50-99
  • 100-499
  • 500-999
  • 1000+

or binary?:

  • 0
  • 1-3
  • 4-15
  • 16-63
  • 64-255
  • 256-1023
  • 1024+

-- Jeandré, 2021-01-13t06:37z

The key's calibration[edit]

New echelons in the key.

  1. 100-349.99
  2. 350-599.99
  3. 600+

79.76.241.130 00:19, 19 August 2021 (UTC)[reply]

Deaths per capita number wrong for Iceland[edit]

The map incorrectly states that there have been 6 COVID deaths in Iceland per 1 million inhabitants whereas the real number is 79.

The absolute number of COVID deaths is 29, as both Real Clear Politics and Statista correctly claim, in line with the data from Iceland's Directorate of Health. Iceland's population is about 0.367 million meaning the deaths per million are about 79. This is displayed correctly on Statista.

However there seems to be a mistake in Real Clear Politics' data for inhabitants of Iceland as the website claims that 29 COVID deaths amounts to 6 deaths per million inhabitants, and this mistake gets transferred to the map. This would suggest that Iceland's population were around 4.8 million. (Coincidentally, that is around the population of Ireland – which leads one to hypothesize that a staff member of Real Clear Politics might accidentally have confused Iceland and Ireland when manually registering the population of each country).

I informed Real Clear Politics about this error weeks ago but got no response. Since this is a clear mistake, and other sources such as the Directorate of Health and Statista have it right, I suggest that this map be updated. — Preceding unsigned comment was added by 130.226.217.195 (talk) 22:59, 16 March 2021 (UTC)[reply]

Table of COVID-19 death rates by country[edit]

This table of COVID-19 death rates per million by country may help in updating your map:

It is continually updated. Source tab says: "Raw data on confirmed cases and deaths for all countries is sourced from the COVID-19 Data Repository by the Center for Systems Science and Engineering (CSSE) at Johns Hopkins University." --Timeshifter (talk) 13:02, 18 June 2021 (UTC)[reply]

Update map legend?[edit]

For this map there are no longer any countries with <0.1 deaths per 100,000 population, so it might be a good idea to remove the lightest shade in the legend. An update to the range of values for each shade might also be appropriate; there are now only 6 countries in the 0.1–0.6 range, 19 in the 0.6–3.3 range, 42 in the 3.3–18 range, 52 in the 18–100 range, 67 in the 100–555 range, and just 1 in the 555+ range. JACKINTHEBOXTALK 18:26, 26 October 2021 (UTC)[reply]

In my 15 Nov update to the map, I replaced the lightest shade (which no longer represents any country) with a grey 'N/A' shade used for countries/territories with no data or confirmed deaths. JACKINTHEBOXTALK 01:43, 17 November 2021 (UTC)[reply]

Is this actually being updated correctly?[edit]

@JackintheBox Are you actually updating every single country? And where are you getting this data from? There should be a single source and it should be included in the image description. Lights and freedom (talk) 18:11, 20 May 2023 (UTC)[reply]

I updated the map using data from the table under Statistics - Total cases, deaths, and death rates by country in the article COVID-19 pandemic by country and territory. JACKINTHEBOXTALK 21:46, 20 May 2023 (UTC)[reply]