Google Translate:

Data Visualization Galleries

Publish date: Nov 13, 2021

Palletes

Show all palettes. - Diverging Scale (BrBG, PiYG, PRGn, PuOr, RdBu, RdGy, RdYlBu, RdYlGn, Spectral) - Qualitative Scale (Accent, Dark2, Paired, Pastel1, Pastel2, Set1, Set2, Set3) - Sequential Scale (Blues, BuGn, BuPu, GnBu, Greens, Greys, Oranges, OrRd, PuBu, PuBuGn, PuRd, Purples, RdPu, Reds, YlGn, YlGnBu, YlOrBr, YlOrRd)

library(RColorBrewer)
display.brewer.all() # colorblindFriendly = TRUE will exclude some palettes.

# Use following functions to apply preset or our own palette
# scale_fill_brewer(palette = "Set2")
# scale_color_brewer(palette = "Set2")
# scale_fill_manual(values=c('#00429d', '#4771b2', '#73a2c6', '#a5d5d8', '#ffffe0'))

Fonts

library(extrafont)
library(tidyverse)
library(patchwork)

# font_import()

plot <- ggplot(mtcars, aes(x=wt, y=mpg)) + 
  geom_point() +
  labs(
    title = "Fuel Efficiency of 32 Cars",
    x= "Weight (x1000 lb)",
    y = "Miles per Gallon"
  )+
  theme_minimal()+
  NULL

p1 <- plot + theme(text=element_text(size=16, family="Montserrat"))
p2 <- plot + theme(text=element_text(size=16, family="Bahnschrift"))
p3 <- plot + theme(text=element_text(size=16, family="Oswald"))
p4 <- plot + theme(text=element_text(size=16, family="Rock Salt"))

# Use patchwork to arrange  4 graphs on same page
(p1 + p2) / (p3 + p4)

Bar plot - Emperors

library(tidyverse)
library(vroom)
library(extrafont)
library(ggtext)
# emperors data
url <- "https://github.com/rfordatascience/tidytuesday/raw/master/data/2019/2019-08-13/emperors.csv"
emperors <- vroom(url)

# Count of Causes of Death
# New variable 'assassination' to colour differently (Highlight)
emperors_assassinated <- emperors %>%
  count(cause) %>%
  arrange(n) %>% 
  mutate(
    assassination = ifelse(cause == "Assassination" | cause == "Execution", TRUE, FALSE),
    cause = fct_inorder(cause)
  )

Trick: use fct_inorder after arrange to plot in a proper order.

# get hex code for color
gplots::col2hex("grey80")
## [1] "#CCCCCC"
gplots::col2hex("tomato")
## [1] "#FF6347"

Trick: gplots::col2hex to get hex code for color

# define colours to use: grey for everything, tomato for assassination
my_colours <- c("#CCCCCC", "#FF6347")

# let us create a text label to add as annotation to our graph
label <- "Execution is a third as likely \n as assassination"

emperors_assassinated %>%
  ggplot(aes(x = n, y = cause, fill = assassination)) +
  geom_col() +
  scale_fill_manual(values = my_colours)+
  geom_text(
    aes(label = n, x = n - .25),
    colour = "white",
    size = 5,
    hjust = 1,
    family="Lato"
  ) +
  
  # change font colour 
  labs(title = "<b> Cause of death of Roman emperors</b><br>
       <span style = 'font-size:12pt'>Roughly half of the emperors died of <span style='color:#FF6347'>assassination</span> and <span style='color:#FF6347'>execution </span>.</span>",
       x= "Number of emperors",
       y = "")+
  
  #add an arrow to draw attention to a value
  geom_curve(
    data = data.frame(x = 15, y = 3.2, xend = 8.1, yend = 5),
    mapping = aes(x = x, y = y, xend = xend, yend = yend),
    colour = "grey15",
    size = 0.5,
    curvature = 0.25,
    arrow = arrow(length = unit(2, "mm"), type = "closed"),
    inherit.aes = FALSE
  ) +
  
  # add the text label on the graph
  geom_text(
    data = data.frame(x = 15, y = 3, label = label),
    aes(x = x, y = y, label = label),
    colour="#FF6347",
    family="Lato",
    hjust = 0.5,
    lineheight = .8,
    inherit.aes = FALSE,
  ) +
  
  theme_minimal() +
  theme(
    plot.title.position = "plot",
    plot.title = element_textbox_simple(size=16), # with this line, html is compiled
    axis.text = element_text(size=12),
    legend.position = "none") +
  NULL

Treemap - Car Manufacturers

library(tidyverse)
library(treemapify)
library(ggalluvial)
library(ggridges)
library(ggthemes)
# Treemaps
# further treemap examples https://github.com/wilkox/treemapify 
mpg %>%
  filter(year == 1999) %>%
  count(manufacturer) %>%
  ggplot(aes(area = n,
             fill = manufacturer,
             label = manufacturer)) +
  geom_treemap() +
  geom_treemap_text() +
  theme(legend.position = "none")

Alluvial Plot - Vaccination Survey

# Alluvial or flow/Sankey diagrams
# https://corybrunson.github.io/ggalluvial/articles/ggalluvial.html

data(vaccinations)
ggplot(vaccinations,
       aes(x = survey, y = freq, 
           alluvium = subject, stratum = response,
           fill = response, label = response)) +
  scale_x_discrete(expand = c(.1, .1)) +
  geom_flow() +
  geom_stratum(alpha = .5) +
  geom_text(stat = "stratum", size = 3) +
  theme(legend.position = "none") +
  labs(title = "Vaccination survey response at three times")

Density Plot

1-Dimension: Distributions

library(gapminder)
# create gapminder2007, by just looking at 2007 data
gapminder2007 <- filter(gapminder, 
                        year == 2007)
# use ggridges::geom_density_ridges() for multiple density plots
ggplot(filter(gapminder2007, 
              continent != "Oceania"),
       aes(x = lifeExp,
           fill = continent,
           y = continent)) +
  geom_density_ridges(alpha = 5/8)+
  theme_minimal()+
  guides(fill=FALSE)+
  NULL

Comparision - With background

library(vroom)
# load titanic data
titanic <- vroom(here::here("data", "titanic3.csv"))
# Define a vector of colours... grey80 for background, and two different colours for male/female
density_colours <- c(
  "male" = "#0072B2",
  "female" = "#D55E00",
  "all passengers" = "grey80"
)

titanic %>%
  drop_na(sex, age) %>% # remove NAs for sex and age, and pass dataframe to ggplot
  
  # in the ggplot(), besides `x = age`, add `y = ..count..` to `aes()`
  ggplot(aes(x = age, y = ..count..)) + 
  
  
  # Add an additional `geom_density()` that will draw the background density, for all participants. 
  # This should come *before* the 'normal' `geom_density()` so that it draws the background.
  geom_density(
    
    # In the background geom_density(), set the `data` argument to be a function. This function 
    # takes a data frame and removes sex (select x, -sex) (on which sex we will facet on later).
    data = function(x) select(x, -sex),
    
    # Set both `colour` and `fill` equal to "all passengers", *not* `sex`.
    aes(fill = "all passengers", colour = "all passengers")
  ) +
  
  # now that we have the grey background, we can plot densities
  # coloured and facet_wrapped by sex
  geom_density(aes(fill = sex, colour = sex), alpha = 0.7, bw = 2) +
  
  # `facet_wrap()` to facet the plot by `sex`.
  # labeller() makes it easy to assign different labellers to different factors
  facet_wrap(~sex, labeller = labeller(sex = function(sex) paste(sex, "passengers"))) +
  
  
  # use the colours you defined for male, female, and all participants
  scale_colour_manual(
    values = density_colours,
    breaks = c("male", "female", "all passengers"),
    labels = c( "males", "females","all passengers"),
    name = NULL,
    guide = guide_legend(direction = "horizontal")
  )+
  scale_fill_manual(
    values = density_colours,
    breaks = c("male", "female", "all passengers"),
    labels = c( "males", "females","all passengers"),
    name = NULL,
    guide = guide_legend(direction = "horizontal")
  )+
  scale_x_continuous(name = "age (years)", limits = c(0, 75), expand = c(0, 0)) +
  scale_y_continuous(limits = c(0, 40), expand = c(0, 0), name = "scaled density") +
  coord_cartesian(clip = "off") +
  theme_minimal() +
  theme(legend.position = "bottom", 
        legend.justification = "center",
        text=element_text(size=12, family="Lato"),
        plot.title.position = "plot"
  ) +
  NULL

Comparision - with half box plot

library(tidyverse)
library(gapminder)
library(ggridges)
library(gghalves)
# use gghalves::geom_half_boxplot(), gghalves::geom_half_point()
ggplot(filter(gapminder2007, 
              continent != "Oceania"),
       aes(y = lifeExp,
           x = continent,
           colour = continent)) +
  geom_half_boxplot(side = "l") + # half boxplot to the left
  geom_half_point(side = "r")+    # points to the right
  theme_minimal()+
  guides(fill = FALSE, color = FALSE)+
  NULL

# Raincloud plots
ggplot(filter(gapminder2007, 
              continent != "Oceania"),
       aes(y = lifeExp,
           x = continent,
           colour = continent)) +
  geom_half_point(side = "l", size = 0.3) + 
  geom_half_boxplot(side = "l", width = 0.5, 
                    alpha = 0.3, nudge = 0.1) +
  geom_half_violin(aes(fill = continent), 
                   alpha = 0.8,
                   side = "r") +
  guides(fill = FALSE, color = FALSE) +
  coord_flip()+
  theme_minimal()+
  NULL

2-Dimension

mpg %>% 
  filter(class != "2seater") %>%
  ggplot(aes(x = cty, y = hwy)) +
  geom_density_2d(aes(color = class)) +
  facet_wrap(~class) +
  theme(legend.position = "none")+
  labs(x="city miles per gallon",
       y="highway miles per gallon")+
  NULL

# geom_hex: Divides the plane into regular hexagons
mpg %>% 
  filter(class != "2seater") %>%
  ggplot(aes(x = cty, y = hwy)) +
  geom_hex(aes(color = class), bins = 10) +
  facet_wrap(~class) +
  #theme(legend.position = "none")+
  labs(x="city miles per gallon",
       y="highway miles per gallon")+
  NULL

Heatmap

library(tidyverse)
library(wbstats)

# https://data.worldbank.org/indicator/IT.NET.USER.ZS
# Download data for Individuals Using Internet (% Of Population) IT.NET.USER.ZS 
# using the wbstats package

internet <- wb_data(country = "countries_only", 
                      indicator = "IT.NET.USER.ZS", 
                      start_date = 1995, end_date = 2017)

country_list = c("United States", "China", "India", "Japan", "Algeria",
                 "Brazil", "Germany", "France", "United Kingdom", "Italy", "New Zealand",
                 "Canada", "Mexico", "Chile", "Argentina", "Norway", "South Africa", "Kenya",
                 "Israel", "Iceland")

internet_short <- filter(internet, country %in% country_list) %>%
  rename(value = IT.NET.USER.ZS) %>% 
  mutate(users = ifelse(is.na(value), 0, value),
         year = as.numeric(date))

internet_summary <- internet_short %>%
  group_by(country) %>%
  summarize(year1 = min(year[users > 0]),
            last = users[n()]) %>%
  arrange(last, desc(year1))

internet_short <- internet_short %>%
  mutate(country = factor(country, levels = internet_summary$country))

ggplot(filter(internet_short, year > 1993),
       aes(x = year, y = country, fill = users)) +
  geom_tile(color = "white", size = 0.25) +
  scale_fill_viridis_c(
    option = "A", begin = 0.05, end = 0.98,
    limits = c(0, 100),
    name = "internet users / 100 people",
    guide = guide_colorbar(
      direction = "horizontal",
      label.position = "bottom",
      title.position = "top",
      ticks = FALSE,
      barwidth = grid::unit(3.5, "in"),
      barheight = grid::unit(0.2, "in")
    )
  ) +
  scale_x_continuous(expand = c(0, 0), name = NULL) +
  scale_y_discrete(name = NULL, position = "right") +
  theme(
    axis.line = element_blank(),
    axis.ticks = element_blank(),
    axis.ticks.length = grid::unit(1, "pt"),
    legend.position = "top",
    legend.justification = "left",
    legend.title.align = 0.5,
    legend.title = element_text(size = 12*12/14)
  )

## X-Y relationships

Linear Relationship

City miles vs Highway miles per gallon

library(tidyverse)
library(gapminder)
library(extrafont)
library(ggrepel)
set.seed(7)
# 20 random countries
some_countries <- gapminder$country %>% 
  levels() %>% 
  sample(20) 

gapminder %>%
  filter(year == 2007) %>%
  mutate(
    label = ifelse(country  %in% some_countries, as.character(country), "")
  ) %>%
  ggplot(aes(log(gdpPercap), lifeExp)) +
    geom_point(
    size = 3,
    alpha = 0.8,
    shape = 21,
    colour = "white",
    fill = "#001e62"
  )+
  geom_text_repel(aes(label=label))+
  theme_minimal()+
  theme(panel.grid.minor = element_blank())+
  labs(
    title = "Gapminder 2007: Life expectancy vs GDP per capita",
    x = "log(GDP per capita)",
    y = "Life Expectancy"
  )

Secondary Axis

car_counts <- mpg %>% 
  group_by(drv) %>% 
  summarize(total = n())

total_cars <- sum(car_counts$total)

ggplot(car_counts,
       aes(x = drv, y = total, 
           color = drv)) +
  geom_point() +
  scale_y_continuous(
    sec.axis = sec_axis(
      trans = ~ . / total_cars,
      labels = scales::percent,
      name = "%")
  ) +
  guides(fill = FALSE)+
  theme_minimal()+
  NULL

Time Series - Flights Number

library(nycflights13)
# just filter to have first 2 months
flights %>%
  mutate(day=as.Date(time_hour)) %>%
  filter(day < "2013-03-01") %>%
  count(day,origin) %>% 
  ggplot(aes(x=day, y=n, color=origin)) +
  geom_line(aes(group=origin)) +
  geom_point() +
  theme_bw()+
  theme(legend.position="bottom")+
  labs(subtitle="Number of Flights per Airports")+
  NULL

To highlight one among all others:

library(gghighlight)
africa <- gapminder %>%
  filter(continent == "Africa") %>% 
  # sort by life expectancy in 1952, the first year in the dataframe
  arrange(year, desc(lifeExp)) %>% 
  mutate(country = fct_inorder(factor(country)))

# find the African countries that had better life expectancy in 1992 compared to 2007
life_expectancy_dropped <- africa %>%
  
  # pivot wider to be able to compare life expectancy in 1992 to 2007,
  pivot_wider(country, names_from = year, values_from = lifeExp) %>%
  
  # create new variables, `le_dropped`, that is `TRUE` if life expectancy was higher in 1992
  # and `le_delta` which is simply the difference between life expectancy in 2007 and 1992
  mutate(
    le_delta = `2007` - `1992`,
    le_dropped = `1992` > `2007`) %>% 
  select(-c(2:13))

# join `le_dropped` to each observation for each country
africa <- left_join(africa, life_expectancy_dropped, by = "country")

le_line_plot <- africa %>%
  ggplot(aes(year, lifeExp, color = country, group = country)) +
  geom_line(size = 1.2, alpha = 0.9, color = "#E58C23") +
  theme_minimal(base_size = 14) +
  
  # let us add a vertical line at 1992, when we start our comparison
  geom_vline(xintercept = 1992, alpha = 0.1)+

  theme(
    # remove legend using the legend.position argument in theme()
    legend.position = "none",
    panel.grid.major.x = element_blank(),
    panel.grid.minor = element_blank()
  ) +
  labs(
    title = "Life expectancy reduction, 1992 to 2007",
    y = "life expectancy", 
    caption = "sorted by life expectancy in 1952") +
  scale_x_continuous(breaks = seq(1952, 2007, 10))+
  NULL

# Using `gghighlight()` we add add direct labels to the plot. 
# The first argument defines which lines to highlight using `le_dropped`. 
# Also add the arguments `use_group_by = FALSE` and `unhighlighted_colour = "grey80"`. 

#  If we facet_wrap() we do not need direct labels, so set `use_direct_label = FALSE` 

le_line_plot +
  gghighlight(
    le_dropped,
    use_group_by = FALSE,
    use_direct_label = FALSE,
    unhighlighted_colour = "grey80"
  ) +
  facet_wrap(~country)

Confidence Interval

l3 <- c("compact","subcompact","midsize",
        "2seater","minivan","suv","pickup")
# avg highway mpg with boostrapped 95% CI
mpg %>%
  mutate(class = factor(class, levels = l3)) %>%
  ggplot(aes(x = class, y = hwy, color = class))+
stat_summary(fun.y = mean, geom = "point") +
  stat_summary(fun.data = mean_cl_boot,
               geom = "errorbar") +
  theme_bw() +
  coord_flip() +
  theme(legend.position = "none") +
  labs(x = " ", y = "Highway MPG with 95% CI")

Jitter - to randomly spread the points

# geom_jitter
origin <- tibble(
  x = rep(0, times = 10),
  y = rep(0, times = 10)
)

#geom_point will only plot one point, as for all points x=0, y=0
ggplot(origin, aes(x=x, y=y))+
  geom_point(size=5, colour="orange")

# geom_jitter will randomly spread the points around (0.0)
ggplot(origin, aes(x=x, y=y))+
  geom_point(size=5, colour="orange")+
  geom_jitter()

Maps

sf basics

library(sf)
library(usethis)
library(tidyverse)
library(rnaturalearth)
library(patchwork)
world <- ne_countries(scale = "medium", returnclass = "sf") %>%
  filter(name != "Antarctica") 
# what happens if we change the crs/projection 

base_map <- ggplot() + 
  geom_sf(data = world, 
          aes(
            geometry = geometry, #use Natural Earth World boundaries
            fill = region_un  #fill colour = country’s region
          ),
          colour = "grey90",      # borders between regions
          show.legend = FALSE    # no legend) +
  )+
  theme_minimal()+
  NULL


base_map

# Longitude/latitude
map_lat_lon <- base_map +
  coord_sf(crs = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_def") +
  labs(title = "Longitude-latitude",
       subtitle = 'crs = "+proj=longlat +ellps=WGS84"')

# Robinson
map_robinson <- base_map +
  coord_sf(crs = "+proj=robin") +
  labs(title = "Robinson",
       subtitle = 'crs = "+proj=robin"')

# Mercator (ew)
map_mercator <- base_map +
  coord_sf(crs = "+proj=merc") +
  labs(title = "Mercator",
       subtitle = 'crs = "+proj=merc"')

# Azimuthal Equidistant
map_azimuthal_equidistant <- base_map +
  coord_sf(crs = "+proj=aeqd") +  # Gall Peters / Equidistant cylindrical
  labs(title = "Azimuthal Equidistant",
       subtitle = "crs = +proj=aeqd")

#use patchwork to arrange 4 maps in one page
(map_lat_lon / map_mercator) | ( map_robinson / map_azimuthal_equidistant)

with Heatmap

# remotes::install_github("kjhealy/nycdogs")
library(nycdogs)
library(sf) # for geospatial visualisation

# load the data
data("nyc_license")
data("nyc_zips")

# what is the prevalent NYC breed ?
nyc_license %>% 
  count(breed_rc, sort=TRUE) 
## # A tibble: 301 × 2
##    breed_rc                     n
##    <chr>                    <int>
##  1 Unknown                  16797
##  2 Yorkshire Terrier         7786
##  3 Shih Tzu                  7154
##  4 Labrador (or Crossbreed)  6986
##  5 Pit Bull (or Mix)         6751
##  6 Chihuahua                 5785
##  7 Maltese                   4308
##  8 Pomeranian                2197
##  9 Beagle                    2111
## 10 Jack Russell Terrier      2041
## # … with 291 more rows
# what is the prevalent NYC dog name by animal gender? 
# Bella for girls, Max for boys!

nyc_license %>% 
  count(animal_name, animal_gender, sort=TRUE) 
## # A tibble: 19,294 × 3
##    animal_name       animal_gender     n
##    <chr>             <chr>         <int>
##  1 Unknown           M              1401
##  2 Bella             F              1365
##  3 Max               M              1272
##  4 Name Not Provided M              1111
##  5 Unknown           F              1093
##  6 Lola              F               875
##  7 Charlie           M               871
##  8 Rocky             M               869
##  9 Lucy              F               767
## 10 Buddy             M               743
## # … with 19,284 more rows
# Maps for two Breeds
top_breeds <- nyc_license %>%
  group_by(zip_code, breed_rc) %>%
  tally() %>%
  filter(n>10) %>% 
  mutate(freq = n / sum(n),
         pct = round(freq*100, 2)) %>%
  filter(breed_rc == "Yorkshire Terrier" |  breed_rc == "Labrador (or Crossbreed)") 

top_breeds_map <- left_join(nyc_zips, top_breeds) %>% 
  na.omit() 

top_breeds_map %>% ggplot(mapping = aes(fill = pct)) +
  geom_sf(color = "gray80", size = 0.1) +
  scale_fill_viridis_b(option = "A", direction= -1) +
  labs(fill = "Percent of Licensed Dogs") +
  facet_wrap(~breed_rc)+
  theme_void() + 
  guides(fill = guide_legend(title.position = "top", 
                             label.position = "bottom")) 

with Arrows

library(tidyverse)
library(sf)
library(rnaturalearth)
library(eurostat)
library(lubridate)
library(opencage)
library(hrbrthemes)
library(gridExtra)
# Air passenger transport between the main airports of the United Kingdom 
# and their main partner airports (routes data)
# https://ec.europa.eu/eurostat/web/products-datasets/-/avia_par_uk

flights_UK <- get_eurostat(id="avia_par_uk", 
                                select_time = "M") #get monthly data


# filter passengers only
flights <- flights_UK %>% 
  dplyr::filter(unit == "PAS") %>% 
  mutate(
    origin = str_sub(airp_pr, 1, 7),
    destination = str_sub(airp_pr, -7), 
    from = str_sub(origin, 4,7),
    to = str_sub(destination, 4,7),
    year = year(time),
    month_name = month(time, label = TRUE)
  ) 

flights %>% 
  filter(year>=2018) %>% 
  group_by(origin,year) %>% 
  summarise(totalpassengers = sum(values)) %>% 
  arrange(desc(totalpassengers))
## # A tibble: 95 × 3
## # Groups:   origin [34]
##    origin   year totalpassengers
##    <chr>   <dbl>           <dbl>
##  1 UK_EGLL  2019       315616656
##  2 UK_EGLL  2018       314171004
##  3 UK_EGKK  2019       174720542
##  4 UK_EGKK  2018       173091550
##  5 UK_EGCC  2019       102403412
##  6 UK_EGSS  2019       101440212
##  7 UK_EGSS  2018       100518160
##  8 UK_EGCC  2018        98376330
##  9 UK_EGLL  2020        64403150
## 10 UK_EGGW  2019        62841150
## # … with 85 more rows
london_airports <- c("UK_EGLL","UK_EGKK","UK_EGSS","UK_EGGW")

london_flights <- flights %>% 
  dplyr::filter(origin %in% london_airports) %>% 
  distinct()

# count number of flights from origins to destinations
origins <- london_flights %>% 
  count(from, sort=TRUE) %>% 
  mutate(prop = n/sum(n))

destinations <- london_flights %>% 
  count(to, sort=TRUE)  %>% 
  mutate(prop = n/sum(n))

# geocode origin/destination airports
origins <- origins %>% 
  mutate(
    origin_geo = purrr::map(from, opencage_forward, limit=1)
  ) %>% 
  unnest_wider(origin_geo) %>% 
  unnest(results) %>% 
  rename(from_y = geometry.lat,
         from_x = geometry.lng)

destinations <- destinations %>% 
  mutate(
    destination_geo = purrr::map(to, opencage_forward, limit=1)
  ) %>% 
  unnest_wider(destination_geo) %>% 
  unnest(results) %>% 
  rename(to_y = geometry.lat,
         to_x = geometry.lng)


#geocode airports

londonflights2018 <- london_flights %>% 
  filter(year==2018) %>% 
  group_by(year, destination, origin, from, to) %>% 
  summarise(totalpassengers = sum(values)) %>% 
  arrange(desc(totalpassengers)) %>% 

  #geocode origin (from_x, from_y)
  mutate(
    origin_geo = purrr::map(from, opencage_forward, limit=1)
  ) %>% 
  unnest_wider(origin_geo) %>% 
  unnest(results) %>% 
  rename(from_y = geometry.lat,
         from_x = geometry.lng) %>% 
  select(destination, from, to, totalpassengers, from_x, from_y) %>% 
  
  #geocode destination (to_x, to_y)
  mutate(
    destination_geo = purrr::map(to, opencage_forward, limit=1)
  ) %>% 
  unnest_wider(destination_geo) %>% 
  unnest(results) %>% 
  rename(to_y = geometry.lat,
         to_x = geometry.lng) %>% 
  select(destination, from, to, totalpassengers, from_x, from_y, to_x, to_y)


# for displaying a data table as annotation next to the map
table <- as_tibble(londonflights2018 %>% group_by(destination) %>%  head(20)) %>%
  select(Origin = origin, Destination = destination, Passengers = totalpassengers) %>%
  mutate(Passengers = glue::glue("{scales::comma(Passengers)}")) %>%
  tableGrob(
    rows = NULL,
    theme = ttheme_default(
      core = list(
        fg_params = list(
          fontfamily = "Lato",
          hjust = c(rep(0, 20), rep(1, 20)),
          x = c(rep(0.1, 20), rep(0.9, 20))
        )
      )
    )
  )


ggplot() +
  geom_sf(data = world, size = 0.125) +
  geom_curve(
    data = londonflights2018 %>% head(20), 
    aes(x = from_x, y = from_y, xend = to_x, yend = to_y, 
        size= totalpassengers, colour = totalpassengers),
    curvature = 0.2, arrow = arrow(length = unit(3, "pt"), type = "closed"),
  )+
  theme_void()+
  
  annotation_custom(table, xmin=-165, xmax=-160, ymin=-120, ymax=90) + 
  labs(
    x = NULL, y = NULL,
    title = "Top 20 destinations for London flights in 2018",
    subtitle = "Data source: Eurostat , id=avia_par_uk"
  ) +
  
  theme(
    text=element_text(size=16, family="Lato"),
    plot.title = element_text(),
    plot.title.position = "plot",
    axis.text.x = element_blank(),
    axis.title.y = element_blank(),
    legend.position = "none"
  ) +
  NULL

London Wards Map

mapview interactive map

library(tidyverse)
library(vroom)
library(sf)
library(rnaturalearth)
library(rnaturalearthdata)
library(rgdal)
library(rgeos)
library(patchwork)
library(mapview)
library(tmap)
library(viridis)
url <- "https://covid.ourworldindata.org/data/owid-covid-data.csv"
covid_data <- vroom(url) %>% 
  mutate(perc = round(100 * people_fully_vaccinated / population, 2)) 

map <- ne_countries(scale = "medium", returnclass = "sf") %>%
  dplyr::select(name, iso_a3, geometry) %>%
  filter(!name %in% c("Greenland", "Antarctica"))

df <- map %>% 
  rename(iso_code=iso_a3) %>% 
  left_join(
    covid_data %>% 
      select(location, iso_code, date, people_fully_vaccinated, perc, continent) %>% 
      group_by(location) %>% 
      slice_max(order_by = perc, n=1) %>% 
      ungroup(),
  by =  "iso_code") %>% 
  drop_na(date) 

# use viridis plasma colour scale
df  %>%
  mapview::mapview(zcol = "perc", 
                   at = seq(0, max(df$perc, na.rm = TRUE), 10), 
                   legend = TRUE,
                   col.regions = plasma(n = 8),
                   layer.name = "Fully Vaccinated %")
# Use tmap package

df %>% 
  filter(continent == "Asia") %>% 
  tm_shape() +
  tmap_options(check.and.fix = TRUE)+
  tm_polygons(col = "perc",  
              n = 5,
              title = "% vaccinated",
              palette = "Blues") 

tmap_mode("view") # for interactive maps

df %>% 
  filter(continent == "Asia") %>% 
  tm_shape() + 
  tm_polygons(col = "perc",  
              n = 5,
              title = "% vaccinated",
              palette = "Blues") 
tmap_mode("plot") # back to static maps for tmap


df %>% 
  filter(continent == "South America") %>% 
  tm_shape() +  
  tm_polygons(col = "perc",  
              n = 5,
              title = "% vaccinated",
              palette = "Greens") + 
  tmap_options(limits = c(facets.view = 13)) + 
  tm_facets(by = "name")