library(ggplot2)
library(dplyr)
owid <- 'https://covid.ourworldindata.org/data/owid-covid-data.csv'
dat <- "2021/02/20"
default_violet <- '#C77CFF'
default_cyan <- '#00BFC4'
Dane dotyczące zgonów z powodu COVID19 pobrano z https://covid.ourworldindata.org/data/owid-covid-data.csv (szczegóły za chwilę). Plik fao_names.csv
zawiera nazwy krajów także pobrane z bazy FAO, do których dodani (za pomocą skryptu Perlowego) następnie dodano do nich kody państw (https://pl.wikipedia.org/wiki/ISO_3166-1_alfa-2)
n <- read.csv("fao_names.csv", sep = ';', header=T, na.string="NA");
Także z bazy FAO pobrano liczbę ludności. Obie ramki połączono. FAO ma problem polityczny z Chinami, w szczególności nie istnieje tam Tajwan więc niezbędne są pewne poprawki:
popbase <- read.csv("FaoPopBase2018.csv", sep = ';', header=T, na.string="NA");
n <- left_join(n, popbase, by="country") %>%
filter (country != 'China') %>%
mutate(country = recode(country,
`Bolivia (Plurinational State of)`='Bolivia',
`Micronesia (Federated States of)`='Micronesia',
`United Kingdom of Great Britain and Northern Ireland`='UK',
`Venezuela (Bolivarian Republic of)`='Venezuela',
`China Hong Kong SAR`='Hong Kong',
`China Macao SAR`='Macao',
`China Taiwan Province of`='Taiwan',
`China mainland`='China',
`Iran (Islamic Republic of)`='Iran',
`Democratic People's Republic of Korea`='North Korea',
`United Republic of Tanzania`='Tanzania'
))
Teraz można wczytać dane dotyczące COVID (najbardziej aktualne dotyczą 2021-02-20) Dane te też są zanieczyszone zawierają mianowicie agregaty typu Europa czy Unia Europejska. Należy te agregaty usunąć, żeby się potem nie sumowało trzy razy to samo:
d <- read.csv("covid_20210220.csv", sep = ';', header=T, na.string="NA");
## należy usunąćbo mącą agregaty
aggregates <- c('Africa', 'Asia', 'Europe', 'European Union',
'International', 'North America', 'Oceania',
'South America', 'World')
d <- left_join(d, n, by='iso') %>% filter (! country.x %in% aggregates )
Liczymy współczynniki zgonów na 1mln mieszkańców (dr
). Ponieważ kolumna pop
zawiera liczbę ludności w tysiącach to żeby przejść na miliony należy oczywiście podzielić wartości totald
wartości przez tysiąc a nie przez milion:
## ponieważ w bazie FAO ludność jest w tys
million <- 1000
d <- d %>%
select(totalc, totald, country.y, iso, pop) %>%
mutate(popm = pop / million) %>%
## Oblicz współczynniki na 1mln
mutate(cr = totalc/popm, dr = totald/popm) %>%
## Tylko kraje wykazujące zmarłych
filter(totald > 0) %>% as.data.frame
totalWC <- sum(d$totald, na.rm = T)
totalPop <- sum (d$pop, na.rm=T)
Liczba krajów: 180. Łączna liczba zgonów na świecie 2460804 (2021/02/20)
Ponieważ wykres dla wszystkich krajów byłby nieczytelny ograniczymy się do krajów które reprezentują 90% wszystkich zgonów (w porządku malejącym):
## 90% przypadków na świecie
d90 <- d %>%
## oblicz udziały
mutate(totaldf = totald/totalWC *100 ) %>%
## uporządkuj malejąco
arrange(desc(totaldf)) %>%
## policz szereg kumulowany
mutate(totaldC = cumsum(totaldf)) %>%
filter (totaldC < 90)
c90n <- nrow(d90)
c90df <- sum(d90$totaldf)
Takich krajów jest 32 (reprezentują dokładnie 89.54% zgonów na świecie i mieszka tam łącznie 3700342.218 osób czyli 49.14%).
Marimekko to wykres pokazujący jednocześnie zjawisko w ujęciu jednostkowym i globalnym. Taki histogram, tyle że szerokości słupków są proporcjonalne do jednej cechy (a nie stałe) a wysokości są proporcjonalne do wielkości drugiej cechy. Jedną cechą jest zwykle jakiś iloraz a drugą mianownik tego ilorazu. W przypadku wizualizacji zgonów: wysokości słupków to liczba zgonów na milion, podczas gdy szerokości to liczba mieszkańców w kraju. Pole słupka jest zatem proporcjonalne do liczby zgonów.
Żeby wykreślić takie marimekko trzeba dokonać elementarnych przekształceń:
d90 <- d90 %>% arrange (dr) %>%
mutate( ww = cumsum(popm)) %>%
mutate( wm= ww - popm) %>%
mutate( wt = wm + (ww - wm)/2) %>%
mutate (isoh = as.character(iso), isol = as.character(iso), isoll=as.character(iso))
Zmienne isoh
/isol
będą potrzebne do wstawienia etykiet w dwu wierszach. Otóż gdyby etykiety wstawić w jednym to by na siebie zachodziły. Żeby tego nie było niektóre przesuwamy do drugiego wiersza (por wykres); niestety trzeba to robić ręcznie:
d90$isoh[ (d90$iso %in% c('CL', 'EC', 'HU', 'SE') ) ] <- ""
d90$isol[ (! d90$iso %in% c('CL', 'EC', 'HU', 'SE') ) ] <- ""
p9 <- ggplot(d90, aes(ymin = 0)) +
ylab(label="Covid deaths per 1mln") +
xlab(label="population (mln)") +
ggtitle(sprintf("Deaths from COVID19"),
subtitle=sprintf("%i krajów z największą liczbą zgonów (łącznie %.1f%% zgonów na świecie) \nsource %s (%s)",
c90n, c90df, owid, dat)) +
geom_rect(aes(xmin = wm, xmax = ww, ymax = dr, fill = iso)) +
##
geom_text(aes(x = wt, y = 0, label = isoh), vjust=+0.5, hjust=+1.25, size=2.0, angle = 90) +
geom_text(aes(x = wt, y = 0, label = isol), vjust=+0.5, hjust=2.95, size=2.0, angle = 90 ) +
##
ylim(-100, NA) +
theme(legend.position = "none")
p9
Wykres wygląda efektownie, ale cierpi na wszystkie wady wykresów powierzchniowych mianowicie małe różnice są niewidoczne. Owszem dokładnie widać które kraje mają jakie wielkości zgonów na milion ale jakie są różnice w wielkościach zgonów to już nie jest tak dobrze widoczne, np jak się ma łączna liczba zgonów w UK i w Meksyku…
Więc oczywiście zawsze można zamiast marimekko wyrysować obie cechy oddzielnie:
library("ggpubr")
## zgony na 1mln
p0 <- d90 %>%
ggplot(aes(x= reorder(as.factor(country.y), dr) , y=-dr )) +
geom_bar(alpha=.3, fill=default_cyan, stat="identity") +
xlab(label="") +
ylab(label="deaths") +
ggtitle(sprintf("Deaths from COVID19 (per 1mln)"),
subtitle=sprintf("source %s (%s)", owid, dat)) +
theme(axis.text = element_text(size = 8),
axis.ticks.y = element_blank(),
axis.text.y=element_blank()) +
theme(plot.title = element_text(hjust = 0.5)) +
##scale_y_continuous(breaks=seq(0,30, by=2)) +
coord_flip()
## udziały w całości
p1 <- d90 %>%
ggplot(aes(x= reorder(as.factor(country.y), dr) , y=totaldf )) +
geom_bar(alpha=.3, fill=default_cyan, stat="identity") +
xlab(label="") +
ylab(label="%") +
ggtitle(sprintf("Deaths from COVID19 (%% of world total)"),
subtitle=sprintf("source %s (%s)", owid, dat)) +
theme(axis.text = element_text(size = 8)) +
theme(plot.title = element_text(hjust = 0.5)) +
scale_y_continuous(breaks=seq(0,30, by=2)) +
coord_flip()
## https://rpkgs.datanovia.com/ggpubr/reference/ggarrange.html
ggarrange(p0, p1, ncol=2, widths = c(2.5, 3) )
Albo nawet na jednym ale to wymaga pewnej ekwilibrystyki. Np możemy przedstawić wielkość zgonów na 1mln jako wielkość względną, konkretnie względem wielkości maksymalnej. Wtedy wszystkie słupki odpowiadające zgonom/1mln będą się zawierały w przedziale 0–100. Wielkości udziałów w zgonach też są w tym przedziale:
### Normalize to 100
### zi = (xi – min(x)) / (max(x) – min(x)) * 100
drMin <- min(d90$dr)
drMax <- max(d90$dr)
d90$drn10 <- (d90$dr - drMin)/ (drMax - drMin) * 10
p2 <- d90 %>%
ggplot(aes(x= reorder(as.factor(country.y), totaldf) , y=totaldf )) +
geom_bar(size=2.5, alpha=.3, fill=default_cyan, stat="identity") +
geom_point(aes(y=drn10), size=2.5, alpha=.6, color=default_violet) +
xlab(label="") +
ylab(label="% of world total") +
ggtitle(sprintf("Deaths from COVID19 (%% of world total)"), subtitle=sprintf("source %s (%s)", owid, dat)) +
theme(axis.text = element_text(size = 8)) +
##theme(plot.title = element_text(hjust = 0.5)) +
scale_y_continuous(breaks=seq(0,30, by=2),
sec.axis = sec_axis(~ . * 10, name='death ratio % (BE=100)')) +
coord_flip()
p2
Dorysowujemy drugą oś (sec.axis
) o skali równej pierwszej przemnożonej przez 10 (wynik widać na wykresie). Druga cecha jest wizualizowana kropkami, żeby się słupki nie nakładały na siebie…
Szczegółowe dane dla 32 krajów są następujące (%zgonów
to udział danego kraju w zgonach ogółem–nie sumuje się do 100 bo, krajów jest tylko 32)
library(knitr)
d90 <- d90 %>% arrange(totald) %>% select(iso, country.y, totald, dr, pop, totaldf)
kable(d90,
col.names = c('kod', 'kraj', 'zgony', 'zgony/1mln', 'ludność', '%zgonów'))
kod | kraj | zgony | zgony/1mln | ludność | %zgonów |
---|---|---|---|---|---|
PH | Philippines | 12068 | 113.15370 | 106651.394 | 0.4904088 |
PK | Pakistan | 12601 | 59.37474 | 212228.286 | 0.5120684 |
SE | Sweden | 12649 | 1268.49771 | 9971.638 | 0.5140190 |
IQ | Iraq | 13245 | 344.62033 | 38433.600 | 0.5382387 |
HU | Hungary | 14252 | 1468.14334 | 9707.499 | 0.5791603 |
NL | Netherlands | 15323 | 898.20605 | 17059.560 | 0.6226827 |
EC | Ecuador | 15513 | 908.02359 | 17084.358 | 0.6304037 |
PT | Portugal | 15897 | 1549.99033 | 10256.193 | 0.6460084 |
CZ | Czechia | 19097 | 1790.50988 | 10665.677 | 0.7760472 |
RO | Romania | 19795 | 1014.81002 | 19506.114 | 0.8044119 |
CL | Chile | 19974 | 1066.46534 | 18729.160 | 0.8116859 |
CA | Canada | 21631 | 583.44587 | 37074.562 | 0.8790217 |
BE | Belgium | 21887 | 1906.17146 | 11482.178 | 0.8894248 |
UA | Ukraine | 26404 | 596.75240 | 44246.156 | 1.0729827 |
TR | Turkey | 27983 | 339.84661 | 82340.088 | 1.1371487 |
ID | Indonesia | 34316 | 128.20238 | 267670.543 | 1.3945036 |
PL | Poland | 42077 | 1109.57894 | 37921.592 | 1.7098883 |
PE | Peru | 44690 | 1397.03138 | 31989.260 | 1.8160731 |
ZA | South Africa | 48940 | 846.82242 | 57792.518 | 1.9887809 |
AR | Argentina | 51122 | 1152.40475 | 44361.150 | 2.0774511 |
CO | Colombia | 58685 | 1181.71087 | 49661.048 | 2.3847897 |
IR | Iran | 59409 | 726.26972 | 81800.188 | 2.4142110 |
ES | Spain | 67101 | 1437.07202 | 46692.858 | 2.7267917 |
DE | Germany | 67883 | 816.64331 | 83124.418 | 2.7585700 |
RU | Russian Federation | 81517 | 559.35457 | 145734.038 | 3.3126165 |
FR | France | 83546 | 1285.51074 | 64990.511 | 3.3950693 |
IT | Italy | 95486 | 1574.96729 | 60627.291 | 3.8802765 |
GB | UK | 120593 | 1796.09734 | 67141.684 | 4.9005528 |
IN | India | 156302 | 115.55309 | 1352642.280 | 6.3516639 |
MX | Mexico | 179797 | 1424.80289 | 126190.788 | 7.3064332 |
BR | Brazil | 245977 | 1174.28651 | 209469.323 | 9.9957981 |
US | United States of America | 497648 | 1521.41144 | 327096.265 | 20.2229840 |
Ten dokument w formacie Rmd oraz dane są dostępne tutaj: https://github.com/hrpunio/Bookdown/tree/main/Misc