Programování

Jak na Živě vznikají grafy ke koronaviru: skripty v R a trocha ruční práce

  • Někoho možná bude zajímat, jak na Živě vznikají každodenně aktualizované grafy ke koronaviru.
  • Z jakých zdrojů dat vycházíme, jak je upravujeme a kombinujeme.
  • Jaké nástroje používáme pro tvorbu grafů.

Nové grafy v článku na Živě připravuji každý den ráno, jakmile Ministerstvo zdravotnictví oznámí čerstvá čísla: počty známých nakažených a mrtvých. Aktuálně používám tyto zdroje dat:

Univerzita Johnse Hopkinse

Jeden z prvních zdrojů informací o koronaviru, autor známé nástěnky, zveřejňuje data na GitHubu. Odsud beru datasety k počtu potvrzených nakažených a mrtvých.

a8cd8884-e07f-4860-8dbb-00c0d83d74a8 
Nástěnku o koronaviru od Univerzity Johnse Hopkinse určitě znáte. Denní data publikuje na GitHubu, odkud si je každý může vzít pro vlastní analýzy

Univerzita dříve sbírala i údaje o počtu uzdravených. Ale jakmile se nemoc přelila do USA, začala se soustředit primárně na svoji mateřskou zemi a svět trochu omezila. To je důvod, proč s teď s počtem uzdravených na Živě nepracujeme.

Univerzita počty nakažených a mrtvých na GitHubu aktualizuje jednou denně, kolem půlnoci našeho času. Ráno přímo z adresy GitHubu stahuji do R široké CSV se zeměmi a daty.

1857cc44-c9a8-4276-b723-9c9c2d486098 
Na Gitfhubu jsou tabulky uložené v této podobě. Nestahuji je ručně, skript si přímo sahá na jejich adresu RAW

Ministerstvo zdravotnictví

Ministerstvo provozuje český dashboard s různými daty k onemocnění COVID-19 v České republice.

Na začátku března to bylo jednoduché, stačilo stáhnout HTML tabulku na staré webové stránce. Po přechodu na Data Studio se situace zkomplikovala. Chvíli jsem z tabulek ručně exportoval data a uložené soubory importoval (teď už to ani není možné). Vznikala pak i různá neoficiální API, přes která se dalo dostat k datům ve formátu JSON. Ale jak se struktura nástěnky měnila, bylo je nutné často upravovat.

3f301689-499a-401d-b8dd-78d1198acaeb 
Od doby, kdy ministerstvo začalo zveřejňovat denní data ve strojově čitelné podobě, všechno funguje

Až nakonec samo ministerstvo zveřejnilo datové sady a JSONy importuji přímo z nich. Zajímá mě dataset s počtem testů a počtem nakažených. Jedno neoficiální API stále používám pro získání počtu nakažených podle krajů.

Česká správa sociálního zabezpečení

ČSSZ zveřejňuje tabulku s počtem osob v karanténě po okresech. Dokud nebyly k dispozici údaje o počtu nakažených, šlo o jedinou možnost, jak se dostat k nějakým číslům z okresů.

Je to tabulka v Excelu, kterou zpracovávám ručně. Bylo by to možné dělat i strojově, R si s Excelem rozumí, ale tohle je minuta. Řádek s daty si přenesu do svého Excelu, kde funkcí SVYHLEDAT upravím názvy okresů, abych z nich potom mohl generovat mapu. Stejným způsobem přidám rovnou počet obyvatel a rozlohu (nakonec ji ale nepoužívám). Tabulku z Excelu zkopíruji do textového souboru a do R importuji jako CSV.

b57f74ba-0b19-4b80-a8ab-a2798754db1d 
Moje pracovní tabulka v Excelu. Zvýrazněné sloupce přes schránku zkopíruji do textového souboru, který následně načítám. Šlo by to určitě lépe automatizovat

Krajské hygienické stanice

Každá ze čtrnácti hygienických stanic na svém webu denně zveřejňuje čerstvá data o počtu potvrzených nakažených. Každý web je ale jiný, informace jsou na něm podané jiným způsobem a tento způsob se navíc občas ještě mění.

Vladimír Smitka i tak v Pythonu připravil crawler, který data z KHS vytahuje a nahrává je do pracovního listu mé tabulky na Google Disku. Odsud je každý den v noci překopíruji do finálního listu a data na webech KHS ručně ověřím a opravím.

54e6a39c-eecf-4a1e-bfb7-5f0ecc1aa125 
Večerní počty nakažených po okresech si z webů hygienických stanic opisuji sám

Zdroje místních názvů

Zejména kvůli mapám musím sjednocovat místní názvy, aby je potom knihovna v R dokázala vykreslit. Univerzita Johnse Hopkinse je u názvů zemí bohužel hodně kreativní, k tomu je ještě někdy mění. Škoda, že od začátku nevsadila na standardizované kódy ISO. Navíc jsem si to celé zkomplikoval, když jsem názvy zemí začal počešťovat.

Každý den proto udělám export zemí a v Excelu porovnám, jestli nějaké nepřibyly. U takových doplním české jméno, pomocí SVYHLEDAT najdu v druhé tabulce anglický název, kterému porozumí mapová knihovna v R. Stejným způsobem z jiné tabulky doplním počet obyvatel, označím, jestli jde o evropskou zemi a nedávno jsem přidal název kontinentu. Tabulku opět překopíruji do textového CSV. Jak jsem psal, R sice dokáže načíst i Excel, ale CSV je rychlé a jisté.

fd968874-4405-4b5f-9093-e9d55a9fe3fe 
Kousek tabulky se zeměmi. Poslední dobou už moc nových nepřibývá

Shrnu tedy ruční práci s daty:

  • Doplnění tabulky s s počtem nakažených po okresech
  • Kontrola, jestli ČSSZ aktualizovala počty lidí v karanténě a příprava nových dat

Další činnosti jsou už celkem automatizované, probíhají v R.

Co je to R?

Několikrát jsem už zmínil R. Je to programovací jazyk, ve kterém zpracovávám data a generuji samotné grafy. Jde o nástroj připravený původně pro statistiky, postupně ale vzniklo velké množství knihoven, se kterými se R dá použít takřka pro jakékoli úlohy.

2e6f4049-5527-4f31-9207-15461401a0f7 
Tohle je samotné R, přímo v terminálu s ním ale asi nikdo nepracuje

R je skvělé při statistice, analytice a má velmi dobré grafické výstupy. Kolem tohoto jazyka je také silná komunita, která poradí, když není jasné, kudy dál; například na Stack Overflow.

Samotné R (web) je terminálová multiplatformní aplikace. Pro pohodlnou práci ve Windows používám vývojové prostředí RStudio.

9a0aeba9-530f-473b-919f-df4ca690fdff 
Pro psaní i spouštění kódu používám RStudio

V závěru článku najdete seznam knihoven, které v R při přípravě koronavirových grafů používám.

Stahování a transformace dat

Popíšu, co s daty postupně můj skript v R dělá. Jak je stahuje a jak transformuje do požadovaného tvaru.

Široké tabulky z Univerzity Johnse Hopkinse převedu do dlouhého formátu. Z originálu odstraňuji zeměpisné souřadnice a jednotlivá data ze sloupců převádím do řádků. Zatímco zdrojová tabulka k nakaženým má třeba právě teď 256 řádků (hlavně jednotlivé dny) a 75 sloupců (země), transformace ji změní na 3 sloupce a 12 780 řádků. Je to vhodnější pro strojové zpracování, zdroj v původní struktuře bych do grafů nedostal.

7071bfa4-c45d-4717-9f41-9f9da014977e 
Funkce pro zpracování dat z Univerzity Johnse Hopkinse. Pouštím ji na tabulky s potvrzenými a mrtvými

Tabulky s nakaženými a mrtvými sloučím a získám strojově dobře zpracovatelnou strukturu se čtyřmi sloupci: Země, Datum, Počet nakažených, Počet mrtvých.

87c11f1b-097e-4ec7-a256-77fa4d8a4c51
Kousek výsledné tabulky. S tím už bude možné pracovat

V datech univerzity jsou občas chybějící data, některý den vypadne. V grafech nechci zuby, tyto výpadky proto interpolací dopočítávám z okolních dat. Snažím se, aby tím nevznikly další chyby, takže řádek musí splnit hodně podmínek, než ho uznám za vhodný k opravě. Je to ve výsledku jen pár desítek řádků.

K České republice v této světové tabulce nyní přidám aktuální ranní údaje Ministerstva zdravotnictví. Všechno sečtu a na konec tabulky přidám nový blok Celý svět.

6993e2b6-4c21-400e-ac91-2a17fd105576
Aktualizace dat k České republice a přidání nového bloku s čísly pro celý svět

Nyní je čas na přidání tabulky s českými názvy zemí, s anglickými názvy pro korektní spárování s mapovou knihovnou, s počty obyvatel atd. Spočítám změny v počtu nakažených a mrtvých vůči předchozímu dni.

50d75a4e-6e49-4298-9ee5-1a1888c44c67
Přidání českých názvů a sloupců se změnami oproti předchozímu dni
39620230-f73a-4dff-b892-b9d3c31b8ea7
Tabulka se trochu rozrostla, v tomto okamžiku vypadá takto. Nevýhodou dlouhého formátu je datová nehospodárnost, počítač to ale zvládne

Další blok kódu zpracovává do samostatné tabulky data pro Českou republiku. Stáhnu a zpracuji oficiální JSONy s počtem testů a počtem nakažených. Přes neoficiální API sáhnu na počty nakažených po krajích. Tady opět musím upravit názvy, abych potom mohl kraje vykreslit v mapě. Dělám to přes externí CSV, ze kterého rovnou přiřadím i počet obyvatel a rozlohu krajů.

5c727209-4515-4ee0-88a0-a9af40f1444f
Zpracování oficiálních JSONů ministerstva zdravotnictví

Musím připravit ještě další tabulky, kterým porozumí mapová knihovna. Nedávno jsem začal dělat srovnání po kontinentech, takže je před tím ještě potřeba provést výpočty, které sečtou čísla u zemí na jednotlivých světadílech.

Příprava pro mapy spočívá zjednodušeně v tom, že tabulku s daty ke koronaviru spojím podle sloupce s názvem (země, kraje, okresu) s tabulkou mapových polygonů, které získávám z příslušných knihoven.

Ještě zbývají okresy podle počtu osob v karanténě. Tady jen naimportuji CSV a propojím je s mapovou tabulkou.

Na počty nakažených po okresech sahám z R přímo do své tabulky na Google Disku. Kromě záhlaví Okres/Kraj z ní vytáhnu poslední sloupec s nejnovějším datem. Opět provedu spárování s mapovou tabulkou.

7d2ce2f3-d0b1-4e5d-b8f8-6d75fa7c0991
Přímo v R načítám tabulku s okresními daty z Google Disku

Teď už jsem na konci práce s daty. V R mám zhruba dvacet tabulek, vektorů a proměnných. Některé možná ani dál nepoužiji, protože jsou pracovní a zapomněl jsem je včas smazat. Data uložím, ještě jednou raději do zálohy a soubor se skripty pro přípravu dat mohu zavřít.

Všechno, co jsem teď popsal, bych mohl pustit najednou – všech asi 400 řádků kódu (část jsou jen komentáře a staré zakomentované řádky). Postupuji ale raději po blocích, kdy na některých místech zkontroluji, jestli všechno správně proběhlo a načítané zdroje mají aktuální data. Zabere mi to pár minut.

Jak se v R kreslí grafy

Skripty pro generování grafů píšu do samostatného souboru. Dnes má už 1100 řádků, ale opět část tvoří komentáře a staré, už nepoužívané bloky. Některé zakomentované grafy ani nedávám do článku, pouštím si je jen občas, když se chci na něco podívat.

Pro přípravu grafů používám knihovnu ggplot2. V R je k tomuto účelu nejspíš nejlepší, nejpoužívanější, umím s ní pracovat a mám ji rád. Podívejte se na web ggplot2, co všechno umí (lepší přehled je možná tady a tady).

Vybral jsem jeden typický graf s vývojem rychlosti šíření. Na něm ukážu, jak ho v ggplot2 sestavím.

2020-04-04 H Rychlost šíření.png
Tento graf teď budeme kreslit

Nejsem úplně důsledný v oddělení přípravy dat a generování grafů. I u grafů si ještě dopočítávám různé další proměnné, přidávám nové sloupce nebo celé pracovní tabulky. Hned na začátku kódu je třeba vidět, že vycházím z tabulky confirmed – tu jsem si před tím upravil ze základní tabulky coron.

7829111a-14a6-4416-8064-cb637e27452b
V dalších dvou odstavcích budu popisovat tento kód

Abych mohl v ggplot2 seřadit řady (zde země), jak chci, musím jejich názvy ve sloupci tabulky převést do datového typu factor, ve kterém jsou položky v požadovaném pořadí. V popisovaném grafu chci země seřazené podle rychlosti šíření. Takže z tabulky confirmed si vyfiltruji nejnovější datum, země seřadím podle sloupce s rychlostí šíření a ze sloupce se zeměmi vytvořím vektor countries.speed, ve kterém jsou názvy zemí od nejrychlejších.

Tabulku confirmed zkopíruji do nové t.speed a v ní názvy zemí nastavím jako factor s pořadím vektoru countries.speed. Kdybych tohle neudělal, budou potom v grafu země seřazené podle abecedy.

Teď už mohu začít s kódem pro vykreslení grafu. Budu popisovat jeho jednotlivé bloky:

72f1d4c8-10e6-4311-a68a-c4fee531b4f7
Kód pro vygenerování grafu Rychlost šíření

1. blok, ggplot(): Napřed řeknu, z jaké tabulky má ggplot2 vyjít. Chci z ní jen prvních 19 zemí a jako dvacátou ručně přidám Českou republiku. Pomocí funkce match() najdu její pořadí ve sloupci tabulky. V těchto grafech vykresluji jen určitý počet dnů, takže další podmínkou vyfiltruji jen tento počet řádků.

Ve funkci aes definuji, co má být na ose X (datum), co na ose Y (rychlost šíření) a podle čeho se mají data rozdělit do skupin (podle zemí). Zde bych případně mohl také nastavit, aby se barva nebo výplň měnily podle země atd.

c8c1bd02-113d-4685-8092-3b304dfb3aeb
V této fázi R vykreslí jen takové pozadí grafu

2. blok, geom_line(): Tato funkce vykresluje čarový graf. Natvrdo nastavuji tloušťku, barvu a kulatá zakončení čáry.

442cd719-a978-4094-b5c3-4274f284d684
V grafu jsou už vidět křivky jednotlivých zemí. Nechávám je šedé, hlavní tady budou trendy

3. blok, geom_smooth(): Funkce proloží data trendovou křivkou. Ponechávám standardní metodu výpočtu loess, nechci zde zobrazovat pruh s intervalem spolehlivosti, nastavuji barvu a tloušťku.

45294b0f-c44b-42cb-8ba6-120b788305bb
Každou šedou lomenou čarou je nyní proložená červená křivka znázorňující trend

Funkce geom definují typ grafu. Podívejte se, jaké varianty ggplot 2 umí.

4. blok, facet_wrap(): Graf zatím zobrazil všech dvacet zemí najednou. Funkcí facet_wrap() ho teď rozdělím do malých minigrafů. Nastavuji, podle jakého sloupce tabulky má ggplot2 rozdělení provést (země), že chci pět sloupců a každý z minigrafů má mít svoji samostatnou osu Y. Facet je výborná funkce!

c2c758bd-7913-455b-8b2b-480d3beb055b
Každá země má teď svůj samostatný minigraf. Aby bylo na malém obrázku něco vidět, snížil jsem počet zemí na patnáct

5. blok, scale_x_date(): V tomto řádku definuji, jak má vypadat osa X. Názvem funkce nastavím, že jsou na ní datové údaje. Pomocí paste0() skládám dohromady popis, kombinuji zde statický text s proměnnou confirmed.days. Parametrem breaks řeknu, aby se na ose ukázalo jen počáteční a koncové datum, upravím jeho formát.

c05da2dc-96dd-4ab8-ace5-2ca3ada31397
Všimněte si změn na ose X

6. blok, scale_y_continuous(): U osy Y je to jednodušší. Nastavím jen, že je lineární a zadám její název.

10e292fc-5dda-4811-906d-3ea750109cc6
Osa Y dostala svůj název

7. blok, ggtitle(): Příprava titulku a podtitulku grafu. Kombinuji zde statické texty s proměnnými, pomocí \n dělím texty do více řádků.

832353f0-4512-495d-bf81-d447b4102885
V malém pracovním náhledu utíká podtitul grafu za roh, do výsledného obrázku se ale vejde

8. blok, theme_bw(): Nastavuji grafické téma grafu. V podstatě u každého svého grafu začínám s theme_bw(), které následně upravuji.

3f023399-7407-4388-ad1a-e6999fbbecdc
Hotová témata v ggplot nastavují základní vzhled grafu
756401eb-1057-4fcd-b741-ca6c775cd35a7eb77568-1e55-4952-95f4-0df7e1634b67e1686c4c-0693-4898-a7b8-a8574bbb35cd
Tři jiná témata aplikovaná na stejný graf

9. blok, theme(): Tady jsou různé detailní úpravy vzhledu grafu. V tomto případě je zde ještě docela málo řádků, u některých grafů jich mám i čtyřikrát tolik. Postupně zde říkám, aby se v grafu neukazovala sekundární mřížka, nastavuji velikost písma v hlavičce minigrafů, velikost písma titulku a podtitulku, okraje grafu (mám podezření, že mi to tam zůstalo z jiného a tady to vůbec nepotřebuji), vypínám malé čárky na osách.

b4ce651d-877e-4860-a9fa-29c3b3e3c5bb
Toto je už finální graf. V pracovním náhledu je trochu namačkaný, po uložení do obrázku bude vypadat lépe

10. blok, ggsave(): Tento řádek uloží graf do souboru PNG. Kombinací textů a proměnných specifikuji, do jaké složky a pod jakým názvem se má soubor uložit. Nastavuji velikost obrázku. Zrovna u toho je ggplot celkem neobratný – nemohu jednoduše zvolit velikost v pixelech, musím ji trefit kombinací šířky, výšky a rozlišení. U tohoto grafu je navíc aktivní vyhlazování pomocí knihovny Cairo.

Proč R, když je tady Python?

Pro graf, který jsem popisoval, stačil celkem krátký kód. Například k vykreslení tohoto grafu potřebuji blok se 42 řádky.

2020-04-04 B Vývoj v České republice.png

Kódy pro grafy každé ráno pouštím postupně po jednom a dívám se na výsledek. Jak totiž přibývají data, občas jsou nutné drobné úpravy. Například změnit intervaly na osách, někdy počet sérií vykreslených v grafu, délku sledovaného intervalu apod. Jindy měním texty, když mě napadnou srozumitelnější. Často přijdu ještě na různá další vylepšení, která třeba rovnou připravím.

Během generování si také všímám různých změn vývoje nemoci. Potom je zmíním v článku nebo v upoutávce na sociálních sítích.

Přidání nových grafů do článku je už potom rychlovka. Kvůli různým velikostem vkládám obrázky natřikrát do pracovního dokumentu, odkud jimi po jednom nahrazuji včerejší grafy. Během toho kontroluji texty v článku, jestli v nich nepíšu něco, co už neplatí, nebo co jsem v grafu mezi tím změnil. Nové grafy popíšu, vyřazené i s jejich texty odstraním.

Celé mi to ráno trvá asi dvacet minut. Kdybych skripty pustil najednou a nezdržoval se kontrolou a úpravami, stačila by polovina.

Mohl bych si ještě dát práci s automatickým zpracováním některých zdrojů, které by nahradily část manuálních činností. Přijde mi ale, že bych na tom strávil víc času než teď. Některé zásahy by stejně i dál musely být ruční.

Proč místo R nepoužívám Python, ve kterém také pracuji? Jednak ho tak dobře neumím a platforma R mi vyhovuje; snad i kvůli tomu, že ji vyvinuli statistici a ne programátoři. Postup práce víc odpovídá způsobu mého myšlení. Navíc knihovna ggplot2 je výborná a umím s ní dobře pracovat. V Pythonu jsem u vizualizace dat stále na začátku.


Jaké v R používám knihovny a k čemu slouží

Knihoven používám samozřejmě víc, toto jsou jen ty, které najdou uplatnění při přípravě koronavirových grafů.

Odkazy na názvech knihoven vedou do repozitáře CRAN. Když na některé stránce najdete řádek Vignettes, měly by u něj být srozumitelné příklady, co lze s knihovnou dělat.

data.table: Knihovna určená původně pro práci s rozsáhlými daty, kterou ale používám pro úplně všechno.

lubridate: Zjednodušuje operace s datovými a časovými údaji. Nepoužívám ji tady pro nic, co by nešlo udělat základními funkcemi, ale převody řetězců do dat jsou s ní krásně jednoduché.

ggplot2: Špičková knihovna pro vizualizace, generování grafů.

bit64: Pro velká čísla, když je chci nechat ve formátu integer.

scales: Pro definici formátu čísel s mezerou mezi tisíci.

rvest: Knihovna pro stahování dat. Použil jsem ji na začátku, když mělo Ministerstvo zdravotnictví data na běžné webové stránce. Teď už data v JSON stahuji rovnou pomocí knihovny jsonlite.

jsonlite: To je ona. Ze strukturovaného JSONu také dokáže vytvořit jednoduchou dvourozměrnou tabulku.

countrycode: Tohle je zbytek z pokusů, kdy jsem se snažil názvy zemí z tabulek Univerzity Johnse Hopkinse automaticky převést do podoby, které porozumí mapy. Nakonec jsem zůstal u ručního zpracování.

maps: Základní knihovna pro práci s mapami v R. Pro data na úrovni zemí a kontinentů stačí.

RCzechia: Knihovna připravená speciálně pro mapy České republiky. Jsou zde polygony pro kraje, okresy, města a další oblasti.

dplyr: Velmi oblíbená knihovna pro zjednodušenou práci s tabulkami. Už ji nepoužívám, jsem zvyklý na data.table, ale použil jsem část staršího kódu, která byla určená pro dplyr a nechtělo se mi ji přepisovat.

googlesheets: Knihovna pro práci s tabulkami na Google Disku. Čtu s ní data o nakažených po okresech.

Cairo: Knihovna pro kvalitní grafické výstupy, u většiny grafů ji používám pro vyhlazování.

2020-04-05 H Rychlost šíření 2.png2020-04-05 H Rychlost šíření.png
Porovnejte stejný graf bez vyhlazení a s vyhlazením. Cairo ale není všemocné, někdy spíš uškodí než pomůže

viridis: Pěkné barevné přechody, které můžete vidět v mapách.

knitr: Tuto knihovnu zde mám jen pro funkci kable, která lépe formátuje tabulky v konzoli. Když chci rychle něco ukázat.

20-04-06 08-25-53.png 
Tohle je výstup funkce kable() z knihovny knitr. Ukáže v terminálu pěknou tabulku

gridExtra: Pro případy, když chci dostat dva nebo více grafů do jednoho obrázku. V článku teď už žádné takové nejsou.

2020-03-20 B Celkový vývoj.png 
Tohle umí gridExtra. Dva samostatné grafy vytvořené v ggplot2 ukáže v jednom obrázku

ggrepel: Velmi užitečná knihovna, která zajistí, aby se textové popisky v grafu nepřekrývaly. Používám ji u grafu s odchylkami od exponenciálního vývoje. Můžete si všimnout, že každý den jsou popisky umístěné trochu jinak podle toho, jak tato knihovna skončila s iteracemi.

2020-04-05 I Vývoj počtu nakažených, výstup z exponcenciály.png 
Bez ggreppel bych tento graf neudělal
Diskuze (7) Další článek: Google ukončuje další sociální síť. Neighbourly jste možná neznali a určitě nepoužívali

Témata článku: , , , , , , , , , , , , , , , , , , , , , , , ,