7  Grafikk med ggplot

Resten av dette heftet belager seg på å bruke datasettet abu89 som er benyttet i en annen lærebok. Dataene kan lastes ned fra den bokens hjemmeside.

Først må dataene leses inn. Siden dette er data i stata-formatet dta, så brukes importfunksjonen read_stata(). Som nevnt tidligere bør variabler av typen labelled gjøres om til factor. Vi sletter også labler som ikke er i faktisk bruk. Disse to tingene gjørs med as_factor() og fct_drop(), men de er lagt inn i en funksjon som går gjennom alle variable i datasettet, across() og sjekker om de er av labelled-typen where(is.labelled). Detaljene her er ikke sentrale for dette kurset: bare se å få lest inn dataene i R.

library(haven)
library(tidyverse)

abu89 <- read_stata("data/abu89.dta") %>% 
  mutate(across(where(is.labelled), ~as_factor(.)),
         across(where(is.factor), ~fct_drop(.)))

glimpse(abu89)
Rows: 4,127
Columns: 9
$ io_nr    <dbl> 3, 4, 5, 8, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 2…
$ time89   <dbl> 62.00000, NA, 91.32895, 84.23913, 90.42553, 103.28947, 75.000…
$ ed       <dbl> 0, 1, 3, 5, 3, 1, 1, 7, 3, 9, 0, 9, 1, 3, 9, 3, 0, 3, 1, 3, 3…
$ age      <dbl> 58, 24, 44, 46, 40, 36, 31, 31, 26, 29, 54, 58, 25, 25, 56, 5…
$ female   <dbl> 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1…
$ klasse89 <fct> III Rutinefunksjonærer, VIIa Ufaglærte arbeidere, II Nedre se…
$ promot   <fct> NEI, JA, JA, NEI, NEI, NEI, NEI, NEI, JA, NEI, JA, JA, NEI, J…
$ fexp     <dbl> 1.0, 0.3, 1.9, 0.3, 1.0, 1.2, 0.1, 0.4, 0.2, 0.3, 3.5, 3.1, 0…
$ private  <fct> Public, Private, Private, Public, Private, Public, Public, Pr…

7.1 Lagvis grafikk

I R er det mange funksjoner for å lage grafikk. Noen er spesialiserte og knyttet til spesielle analysemetoder og gir deg akkurat det du trenger. Vi skal her bruke et generelt system for grafikk som heter ggplot som kan brukes til all slags grafikk. Funksjonen ggplot er bygget opp som en gramatikk for grafisk fremstilling. Det ligger en teori til grunn som er utledet i boken ved omtrent samme navn: The grammar of graphics. Det er mye som kan sies om dette, men det viktige er at grafikken er bygget opp rundt noen bestanddeler. Når du behersker disse kan du fremstille nær sagt hva som helst av kvantitativ informasjon grafisk. Dette er altså et system for grafikk, ikke bare kommandoer for spesifikke typer plot. Vi skal likevel bare se på grunnleggende typer plot her.

Systemet er bygd opp lagvis. Det gjelder selve koden, men også hvordan det ser ut visuelt. Man kan utvide plottet med flere lag i samme plot og det legges da oppå hverandre i den rekkefølgen som angis i koden.

For enkle plot som vi skal bruke her angir man i denne rekkefølgen og med en + mellom hver del (vanligvis per linje, men linjeskift spiller ingen rolle). Hver del av koden spesifiserer enten hva som skal plottes eller hvordan det plottes, mens andre deler kan kontrollere utseende på akser, fargeskalaer, støttelinjer eller andre ting som har med layout å gjøre.

  1. Angi data og hva som skal plottes med ggplot()
  2. Angi hvordan det skal plottes med geom_*()
  3. Angi andre spesifikasjoner (farger, titler, koordinatsystemer osv)

Dette blir tydeligere i eksemplene og forklares underveis.

  • Det første argumentet i ggplot er data. Altså: hvilket datasett informasjonen hentes fra.
  • Inni ggplot() må det spesifiseres aes(), “aestethics”, som er hvilke variable som skal plottes. Først og fremst hva som skal på x-akse og y-akse (og evt. z-akse), men også spesifikasjon av om linjer (farge, linjetype) og fyllfarger, skal angis etter en annen variabel.
  • geom_* står for geometric og sier noe om hvordan data skal se ut. Det kan være punkter, histogram, stolper, linjer osv.
  • coord_* definerer koordinatsystemet. Stort sett blir dette bestemt av variablene. Men du kan også snu grafen eller definere sirkulært koordinatsystem, eller andre enklere ting.
  • facet_* definerer hvordan du vil dele opp grafikken i undergrupper

7.2 Kategoriske variabel

7.2.1 Stolpediagram

library(ggforce)
ggplot(abu89, aes(x = klasse89)) +
  geom_bar() +
  theme(axis.text.x = element_text(angle = 90))

Noen ganger ønsker man å vise fordelingen for to ulike grupper, la oss si for kjønn. En mulighet er da å rett og slett lage to stolpediagram ved siden av hverandre. Til dette kan man spesifisere at dataene er gruppert etter variabelen female og at fyllfargen skal settes etter denne variablen med fill = factor(female). Merk bruken av factor(female) fordi variabelen er numerisk og det vil da ellers brukes en kontinuerlig fargeskale, mens å gjøre om variabelen til kategorisk brukes en annen fargeskala.

I tillegg gjør vi her to ting til: setter et annet grafisk tema med theme_minimal() og snur plotvinduet slik at kategoriene er litt lettere å lese. Dette er smak og behag.

ggplot(abu89, aes(x = klasse89, group = female, fill = factor(female))) +
  geom_bar(position="dodge") +
  theme_minimal()+
  theme(axis.text.x = element_text(angle = 90))+
  coord_flip()

Et alternativ er å plassere grafikken for menn og kvinner ved siden av hverandre. Å legge til facet_wrap() gjør dette.

ggplot(abu89, aes(x = klasse89)) +
  geom_bar() +
  facet_wrap(~factor(female)) +
  theme(axis.text.x = element_text(angle = 90))

Et automatisk forvalg for geom_bar() er hvordan gruppene plasseres som er position="stack". Det betyr at gruppene stables oppå hverandre. Dette er godt egnet hvis poenget er å vise hvor mange av hvert kjønn som er i hver gruppe. Det er mindre egnet hvis du ønsker å sammenligne menn og kvinner. Da er alternativet å velge position="dodge" som følger:

7.2.2 Kakediagram

Generelt er ikke kakediagram å anbefale da korrekt tolkning involverer å tolke et areal som inneholder vinkel. Med få kategorier som er rimelig forskjellig kan det gi et ok inntrykk, men ofte ender man opp med å måtte skrive på tallene likevel. Vi tar det med her egentlig bare fordi mange insisterer på å bruke det. Så vet du at det er mulig.

Det enkleste er å bruke funksjonen pie() som gir følgende resultat.

tab <- table(abu89$klasse89) 
tab

    I Øvre serviceklasse   II Nedre serviceklasse   III Rutinefunksjonærer 
                     328                     1181                     1248 
 V-VI Faglærte arbeidere VIIa Ufaglærte arbeidere 
                     648                      637 
pie(tab)

Men hvis man skal bruke ggplot er det litt mer jobb. Fordelen med ggplot er at du har bedre kontroll for å lage publiserbar kvalitet. (Akkurat for kakediagram er det kanskje ikke så farlige, for du bør ikke bruke det i publikasjoner hvis du kan la være).

pc <- abu89 %>% 
  group_by(klasse89) %>% 
  summarise(n = n()) %>% 
  mutate(pct = n/sum(n)*100) %>% 
  ungroup()

ggplot(pc, aes(x = "", y = pct, fill = (klasse89))) +
  geom_bar(stat="identity", width=1) +
  coord_polar("y", start=0) +
  theme_void()+
  geom_text( aes(label = paste0( round(pct,1), "%"), x = 1.4), 
            position = position_stack(vjust=.5), check_overlap = F) +
  labs(x = NULL, y = NULL, fill = NULL)+
  theme(axis.line = element_blank(),
          axis.text = element_blank(),
          axis.ticks = element_blank()) +
  scale_fill_brewer(palette="Blues", direction = -1)

7.3 Kontinuerlige variable

7.3.1 Histogram

ggplot(abu89, aes(x = time89)) +
  geom_histogram()

Det er også vanlig å fremstille det samme på en “tetthetsskala”, der arealet summeres til 1. Det betyr at arealet for hvert intervall tilsvarer en andel. Visuelt sett er det vel så mye arealet vi oppfatter som høyden på stolpene. Men det er bare skalaen på y-aksen som har endret seg. Visuelt sett, ser histogrammene helt like ut.

ggplot(abu89, aes(x = time89, y = ..density..)) +
  geom_histogram()

7.3.2 Density plot

Density plot er en måte å fremstille det samme på, men i stedet for å dele inn i intervaller som i histogram lager vi en glattet kurve. Det blir på skalaen “tetthet” som i histogrammet ovenfor.

ggplot(abu89, aes(x = time89)) +
  geom_density()

ggplot(abu89, aes(x = time89)) +
  geom_histogram(aes(y = ..density..), fill = "lightgrey", col = "grey") +
  geom_density(col = "red", linewidth = 1) +
  theme_minimal()

En fordel med denne fremstillingen er at det er lettere å sammenligne grupper. Her er et eksempel med density plot etter hvor mye man drikker.

ggplot(abu89, aes(x = time89, group = klasse89, linetype = klasse89)) +
  geom_density(linewidth = 1)+
  guides(fill = guide_legend(override.aes = list(shape = 1 ) ) ) +
  theme_minimal()

ggplot(abu89, aes(x = time89)) +
  geom_density(linewidth = 1)+
  theme_minimal()+
  facet_wrap(~klasse89, scales="free")

ggplot(abu89, aes(x = time89, group = female,  fill = factor(female))) +
  geom_density(alpha = .3)+
  guides(fill=guide_legend(title="Kjønn"))+
  theme_minimal()

7.3.3 Flere variable samtidig

7.3.3.1 Boksplot

ggplot(abu89, aes(y = time89, group = klasse89)) +
  geom_boxplot()+
  theme_minimal()

7.3.3.2 Scatterplot

ggplot(abu89, aes(x = age, y = time89)) +
  geom_point(alpha=.3)+
  theme_minimal()

ggplot(abu89, aes(x = age, y = time89)) +
  geom_jitter(alpha=.1, width = .3)+
  theme_minimal()

7.3.3.3 Ridgeplot

Ridgeplot er en annen måte å sammenligne en kontinuerlig fordeling betinget på en gruppering.

library(ggridges)
ggplot( abu89,  aes(y = klasse89, x = time89)) +
  geom_density_ridges() 

7.4 Oppgaver

Slå opp i boken R for data science hvis du står fast eller ikke skjønner hva koden betyr.

Exercise 7.1 Last ned datasettet abu89 fra angitt hjemmeside og les inn dataene til R som vist ovenfor. Lag den samme grafikken som vist her, gjør noen endringer på kodene for å endre utseendet på plottene. Det er et mål at du skal forstå hva hver enkelt kommando gjør.

Exercise 7.2 Last inn datasettet NorLAG i R. Velg noen variable som du selv tenker kan være informative å se nærmere på. Bruk de samme teknikkene på disse variablene.