Organisering och layout av figurer med multipla paneler

I kapitlet Facets (Subgrafer) demonstrerades hur en kategorisk variabel kan användas för att skapa flera subgrafer (facets) som presenterar av subgrupper av data. Detta görs med funktioner i ggplot2 (facet_wrap() och facet_grid()). Dessa funktioner kan inte användas för att placera separata grafer intill varandra. För det ändamålet behövs tilläggspaket till ggplot2. De två mest populära paketen är gridExtra och cowplot. Här kommer endast cowplot demonstreras eftersom det erbjuder alla funktioner som behövs, även för mer de mest avancerade användarna. Cowplot har en intuitiv syntax och skapar enhetliga och organiserade layouter med mycket hög flexibilitet.

Börja med att installera och aktivera cowplot. Aktivera även tidyverse som bland annat innehåller ggplot2 och gapminder som innehåller övningsdata.

install.packages("cowplot")

library(cowplot)
library(tidyverse)
library(gapminder)

## Inspektera gapminders första 5 rader
head(gapminder)
country<fctr> continent<fctr> year<int> lifeExp<dbl> pop<int> gdpPercap<dbl>
Afghanistan Asia 1952 28.801 8425333 779.4453
Afghanistan Asia 1957 30.332 9240934 820.8530
Afghanistan Asia 1962 31.997 10267083 853.1007
Afghanistan Asia 1967 34.020 11537966 836.1971
Afghanistan Asia 1972 36.088 13079460 739.9811
Afghanistan Asia 1977 38.438 14880372 786.1134

Första 5 raderna i gapminder.

För att organisera flera grafer i en layout behöver varje graf sparas som ett objekt. Objekten i detta kapitel kommer benämnas plot_1, plot_2, plot_3 och plot_4. Skillnaden mellan dessa grafer kommer vara liten men det har ingen betydelse för att demonstrera hur grafer organiseras.

Vi börjar med att skapa plot_1, plot_2, plot_3 och plot_4 med data från gapminder. Skillnaden på nedanstående grafer är endast vad som finns på x-axel, y-axel samt färgtemat.

## Första grafen
plot_1 <- ggplot(gapminder, aes(x=log(pop),
                                y=log(lifeExp),
                                color=year)) +
  geom_point() +
  scale_color_viridis_c(option = "plasma") +
  theme(legend.position = "none")

## Andra grafen
plot_2 <- ggplot(gapminder, aes(x=log(pop),
                                y=continent,
                                color=year)) +
  geom_point(size=3, alpha=.5) +
  scale_color_viridis_c(option = "magma") +
  theme(legend.position = "none")

## Tredje grafen
plot_3 <- ggplot(gapminder, aes(x=log(gdpPercap),
                                y=continent,
                                color=year)) +
  geom_point(size=3, alpha=.5) +
  scale_color_viridis_c(option = "plasma") +
  theme(legend.position = "none")

## Fjärde grafen
plot_4 <- ggplot(gapminder, aes(x=gdpPercap,
                                y=continent,
                                color=year)) +
  geom_point(size=3, alpha=.5) +
  scale_color_viridis_c(option = "magma") +
  theme(legend.position = "none")

Vi använder nu plot_grid() från cowplot för att organisera plot_1 och plot_2 till en figur med 2 kolumner (ncol). Vi skapar även labels, som framgår nedan.

plot_grid(plot_1, plot_2, ncol = 2, labels = c('A', 'B'))
Två spridningsdiagram sida vid sida, A: log(lifeExp) mot log(pop) och B: kontinent mot log(pop), färgade efter år

Figurerna kan placeras vertikalt istället genom att ändra ncol till ncol=1. Nedan använder vi labels="AUTO" istället för att få labels automatiskt.

plot_grid(plot_1, plot_2, ncol = 1, labels = "AUTO")
Samma två spridningsdiagram staplade vertikalt med etiketterna A och B, log(lifeExp) respektive kontinent mot log(pop)

Vi kan också använda align="h" för horisontell placering av figurer, respektive align="v" för vertikal placering.

plot_grid(plot_1, plot_2, aligh = "h")
Två spridningsdiagram sida vid sida, A: log(lifeExp) mot log(pop) och B: kontinent mot log(pop), färgade efter år

Vi kan justera hur stor andel av utrymmet som varje graf ska uppta genom argumentet rel_widths(). Nedan får första grafen hälften (1) så mycket utrymme som andra grafen (2).

plot_grid(plot_1, plot_2, ncol=2, rel_widths = c(1, 2))
Två spridningsdiagram sida vid sida där den högra panelen, kontinent mot log(pop), är dubbelt så bred som den vänstra

Notera i nedanstående graf att titeln på övre figurens y-axel har större distans från y-axelns siffror.

plot_grid(plot_1, plot_2, ncol = 1, align = 'v')
Två vertikalt staplade spridningsdiagram där den övre y-axelns titel log(lifeExp) står längre från axeln än den undre

När figurerna i en plot_grid() inte är placerade i linje vad avser titlar och axlar används argumentet axis för att justera detta. Axis har argumenten none, l (left), r (right), b (bottom) och t (top). Du kan använda en eller flera av dessa för att justera respektive sida. Nedan justerar vi graferna åt vänster med axis="l".

plot_grid(plot_1, plot_2, ncol = 1, align = 'v', axis = 'l')
Två vertikalt staplade spridningsdiagram vänsterjusterade så att y-axlarna för log(lifeExp) och kontinent ligger i linje

Du kan skapa tomma figurutrymmen med argumentet NULL i plot_grid(). Nedan skapar vi en matris med fyra figurer varav två är NULL, och vi lägger till labels automatiskt.

plot_grid(
  plot_1, NULL, NULL, plot_2,
  labels = "AUTO",
  ncol = 2
)
Rutnät två gånger två med spridningsdiagram i ruta A och D samt tomma rutor B och C

Du kan skapa matriser med figurer på flera rader och med varierande storlekar på dessa rader. Detta görs genom att skapa flera plot_grid() som sedan används som objekt i en slutlig plot_grid().

## Första raden med plot_grid()
upper_row <- plot_grid(plot_1, plot_2, ncol = 2, labels=c("A", "B"))

## Andra raden med plot_grid()
middle_row <- plot_grid(plot_3, labels=c("C"))

## Tredje raden med plot_grid()
bottom_row <- plot_grid(plot_4, plot_1, ncol = 2, labels=c("D", "E"))

## Slutlig plot_grid()
plot_grid(upper_row, middle_row, bottom_row, ncol=1)
Layout i tre rader med fem paneler A till E: två diagram överst, ett brett i mitten och två nederst, data från gapminder

Gemensam rubrik för många paneler

Med plot_grid() kan man ge varje panel en label och själva panelen kan ha en title skapad med ggplot(). Det kan dock vara önskvärt att ha en titel som sträcker sig över flera paneler. Detta åstadkommer man med ggdraw(), enligt följande:

plot_title <- ggdraw() +
  draw_label(
    "Här skriver vi en titel för samtliga paneler på en gång",
    fontface = 'bold',
    x = 0,
    hjust = 0) +
  # Adderar marginal på 7 pixlar till vänster, så titeln hamnar i linje med första panelen
  theme(plot.margin = margin(0, 0, 0, 7))

plot_row <- plot_grid(plot_1, plot_2, labels="AUTO")

plot_grid(
  plot_title,
  plot_row,
  ncol = 1,
  rel_heights = c(0.1, 1) # titeln får liten andel av höjden
)
Två spridningsdiagram A och B under en gemensam fetstilt rubrik som sträcker sig över båda panelerna

Överlappa figurer

Det kan vara användbart att överlappa figurer för att tydligare åskådliggöra samband. Detta är användbart om figurerna delar en axel (oftast x-axeln). Om två figurer har samma x-axel men olika y-axlar, så kan figurerna överlappas för att sambandet mellan x-axeln och båda y-axlarna kan visualiseras med överlappning. Detta kan ibland resultera i tydligare illustrationer, även om vinsten - jämfört med två separata figurer placerade bredvid varandra - egentligen är ganska liten.

För denna övning använder vi mpg (miles per gallon) data som innehåller data på bränsleförbrukning (variablerna cty och hwy) för olika bilar. Dessa data finns i tidyverse, vilket innebär att de borde finnas tillgängliga nu (annars skall tidyverse aktiveras med kommandot library(tidyverse)). Börja med att inspektera data:

head(mpg)
manufacturer <chr> model <chr> displ <dbl> year <int> cyl <int> trans <chr> drv <chr> cty <int> hwy <int> fl <chr>
audi a4 1.8 1999 4 auto(l5) f 18 29 p
audi a4 1.8 1999 4 manual(m5) f 21 29 p
audi a4 2.0 2008 4 manual(m6) f 20 31 p
audi a4 2.0 2008 4 auto(av) f 21 30 p
audi a4 2.8 1999 6 auto(l5) f 16 26 p
audi a4 2.8 1999 6 manual(m5) f 18 26 p

Vi skapar den första figuren (se kommentarer för förklaringar) enligt följande:

plot_1 <- ggplot(mpg, aes(x=manufacturer,
                          y=hwy)) +
  geom_boxplot() +
  # Temat "half open" har inget rutnät och endast två linjer (x-axel och y-axel)
  theme_half_open() +
  theme(
    # Roterar labels på x-axeln 45°
    axis.text.x = element_text(angle = 45, hjust = 1, vjust= 1),
    # Tar bort titeln på x-axeln
    axis.title.x = element_blank())

plot_1
Lådagram av hwy per biltillverkare med roterade tillverkarnamn på x-axeln, utan rutnät

Notera att figuren inte har linjer på högra sidan och överst. Vi fortsätter med andra figuren:

plot_2 <- ggplot(mpg, aes(x=manufacturer,
                          y=cty,
                          color=drv)) +
  geom_point(size=3) +
  # Flyttar y-axeln till höger sida
  scale_y_continuous(position = "right") +
  # Samma tema som ovan
  theme_half_open() +
  # Tar bort titel och labels på x-axeln
  theme(axis.text.x = element_blank(),
        axis.title.x = element_blank()) +
  # Använder ett vackert färgtema för color=drv
  scale_color_viridis_d()

plot_2
Punktdiagram av cty per tillverkare färgat efter drv, med y-axeln till höger och utan text på x-axeln

Slutligen skall dessa två grafer överlappas. Detta görs med align_plots() och ggdraw(), som följer:

## Placera graferna ovanpå varandra
aligned_plots <- align_plots(plot_1, plot_2, align="hv", axis="tblr")

## Visa den färdiga grafen
ggdraw(aligned_plots[[1]]) + draw_plot(aligned_plots[[2]])
Lådagram av hwy och punktdiagram av cty per biltillverkare överlagrade med hwy-axel till vänster och cty-axel till höger