This workshop will build upon “Introduction to R for Data Analysis”,
and assume you have a basic understanding of R, reading in data, and
subsetting data. We will use the dplyr package for data
manipulation and the ggplot2 package to create customised
visualisation.
This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.
When you click the Knit button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. Embed R code chunk can be run by pressing the green triangle in the top right of the code chunk. You can also run all code chunks in the document by clicking the Run button in the toolbar above.
Set your working directory to the folder where the data and this file
is located. This can be done in RStudio by Session > Set Working
Directory > To Source File Location. Alternatively, you can use the
setwd() function in R.
Your folder should contain: -
childhood_24month_immunisation_2015_2026.csv - the data we
will use in this workshop - resbaz_ggplot_2026.Rmd - this R
Markdown file
For data analysis and exploration. For yourself or the team
For data communication and dissemination. For an audience
For art. For yourself and an audience (https://www.data-to-art.com/)
The New Zealand government has set a target of 95% immunisation coverage for 24-month-old children by 2030. The data we will explore is from the Health New Zealand - Te Whatu Ora, covering the years 2015 to 2026. https://www.healthnz.govt.nz/about-us/health-data/data-sets-and-collections/immunisation-data-and-statistics/immunisation-coverage
“Health NZ is working towards a goal of 95% of tamariki aged 24-months to be fully immunised by 2030, and an interim target of 84% by June 2025.”
Select a health question to answer:
The “GG” in ggplot2 stands for “Grammar of Graphics”. It is a
powerful and flexible package for creating graphics in R. The package
allows you to build plots layer by layer, making it easy to customise
and enhance your visualisations. The ggplot2 package is
part of the tidyverse package, which also includes dplyr,
tidyr, readr, and other packages for data
manipulation and visualisation.
# start a line with a hash (#) for a comment inside a code chunk
# if you don't already have tidyverse, run the line of code below by
# removing the hash then run by pressing the green triangle in the top right of the code chunk
# install.packages("tidyverse")
library(tidyverse)
## Warning: package 'ggplot2' was built under R version 4.3.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.2 ✔ tibble 3.2.1
## ✔ lubridate 1.9.3 ✔ tidyr 1.3.1
## ✔ purrr 1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
# option 2,
# if you don't already have tidyverse and tidyverse is taking too long to download
# we will only require these four packages ggplot2, dplyr, tidyr, readr
# install.packages(c("ggplot2", "dplyr", "tidyr", "readr"))
#
# library(ggplot2)
# library(dplyr)
# library(tidyr)
# library(readr)
If the data is not found, please check the data in in the same folder as this Rmd file, and check that the working directory is set correctly. Instructions above.
# Load the data
child_imm_raw <- read_csv("./childhood_24month_immunisation_2015_2026.csv")
## Rows: 1260 Columns: 6
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (3): district_health_boards, region, ethnicity
## dbl (3): year, num_eligible, fully_immunised_for_age
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# show the first 6 rows of data
print(head(child_imm_raw))
## # A tibble: 6 × 6
## year district_health_boards region ethnicity num_eligible
## <dbl> <chr> <chr> <chr> <dbl>
## 1 2015 Auckland Northern Total 6003
## 2 2015 Auckland Northern Maori 737
## 3 2015 Auckland Northern Pacific 1087
## 4 2015 Auckland Northern Asian 1793
## 5 2015 Auckland Northern European or Other 2386
## 6 2015 Bay of Plenty Te Manawa Taki Total 3002
## # ℹ 1 more variable: fully_immunised_for_age <dbl>
# shape of the data (number of rows and columns)
# should be 1260 rows and 6 columns
print(dim(child_imm_raw))
## [1] 1260 6
# print unique district health boards
# should be 21, i.e. 20 districts and "National"
print(child_imm_raw |> select (district_health_boards) |> unique())
## # A tibble: 21 × 1
## district_health_boards
## <chr>
## 1 Auckland
## 2 Bay of Plenty
## 3 Canterbury
## 4 Capital and Coast
## 5 Counties Manukau
## 6 Hawkes Bay
## 7 Hutt Valley
## 8 Lakes
## 9 MidCentral
## 10 National
## # ℹ 11 more rows
Let’s demonstrate how to build up a plot in ggplot2. We will plot the immunisation coverage of 24-month-old children in each district health board in 2020.
perc_fully_immunised_for_age
which is the percentage of children fully immunised for their age group.
This is done by dividing the number of fully immunised children
(fully_immunised_for_age) by the number of eligible
children (num_eligible)Fill in the blanks to select the desired data, there should be 20 rows of data and 7 columns in the resulting data frame.
# fill in the blanks below
# create the percentage column here, we can reuse child_imm later
child_imm <- child_imm_raw |>
mutate(perc_fully_immunised_for_age = fully_immunised_for_age / num_eligible)
# create a new data frame child_imm_2020_dhb for this plot
child_imm_2020_dhb <- child_imm |>
filter(ethnicity == "Total", year == 2020, district_health_boards != "National")
# this should have 20 rows and 7 columns
print(child_imm_2020_dhb)
## # A tibble: 20 × 7
## year district_health_boards region ethnicity num_eligible
## <dbl> <chr> <chr> <chr> <dbl>
## 1 2020 Auckland Northern Total 5249
## 2 2020 Bay of Plenty Te Manawa Taki Total 3179
## 3 2020 Canterbury Te Waipounamu Total 6416
## 4 2020 Capital and Coast Central Total 3242
## 5 2020 Counties Manukau Northern Total 8313
## 6 2020 Hawkes Bay Central Total 2154
## 7 2020 Hutt Valley Central Total 2035
## 8 2020 Lakes Te Manawa Taki Total 1590
## 9 2020 MidCentral Central Total 2243
## 10 2020 Nelson Marlborough Te Waipounamu Total 1586
## 11 2020 Northland Northern Total 2365
## 12 2020 South Canterbury Te Waipounamu Total 625
## 13 2020 Southern Te Waipounamu Total 3383
## 14 2020 Tairawhiti Te Manawa Taki Total 724
## 15 2020 Taranaki Te Manawa Taki Total 1682
## 16 2020 Waikato Te Manawa Taki Total 5620
## 17 2020 Wairarapa Central Total 535
## 18 2020 Waitemata Northern Total 7655
## 19 2020 West Coast Te Waipounamu Total 334
## 20 2020 Whanganui Central Total 841
## # ℹ 2 more variables: fully_immunised_for_age <dbl>,
## # perc_fully_immunised_for_age <dbl>
ggplot2 uses a layered approach to building plots. See: https://ggplot2.tidyverse.org/articles/ggplot2.html
The basic structure of a ggplot2 plot is:
# ggplot(<data>,
# aes(<mapping>)
# ) +
# <geom_function>() +
# <theme_function>()
Notice how layers are added with the + operator. The
aes() function is used to map variables in the data to
aesthetics of the plot, such as x and y axes, colour, size, etc. The
geom_function() is used to specify the type of plot (e.g.,
geom_bar(), geom_line(),
geom_point(), etc.). The theme_function() is
used to customise the appearance of the plot.
ggplot(child_imm_2020_dhb,
aes(
x = perc_fully_immunised_for_age,
y = fct_reorder(district_health_boards, num_eligible),
fill = -num_eligible,
color = region
)) +
geom_col() +
coord_cartesian(xlim = c(0.75,1)) +
labs(
title = "2020 immunisation data",
x = "Coverage (%)",
y = "District"
)
ggplot(child_imm_2020_dhb) # data only
ggplot(child_imm_2020_dhb,
aes(x = district_health_boards,
y = perc_fully_immunised_for_age) # added aesthetics, but no geometry
)
ggplot(child_imm_2020_dhb,
aes(x = district_health_boards,
y = perc_fully_immunised_for_age)
) +
geom_col() +# this adds a column plot layer
theme(axis.text.x = element_text(angle = 45, hjust = 1))
Replacing the labels with plain English and adding a title will
improve readability. To avoid the x-axis labels overlapping, we can
rotate the labels by 45 degrees using the theme() function.
We can also set the y-axis to go from 0% to 100%.
ggplot(child_imm_2020_dhb,
aes(x = district_health_boards,
y = perc_fully_immunised_for_age)
) +
geom_col() +
# NEW LINES:
labs(title = "Immunisation Coverage of 24-month-old Children in 2020", # title at the top of the plot
x = "District Health Boards", # x-axis label
y = "Percentage Fully Immunised") + # y-axis label
scale_y_continuous(labels = scales::percent_format()) + # this line formats the y-axis labels as percentages
coord_cartesian(ylim = c(0,1)) + # this line sets the y-axis limits to 0% to 100%
theme(axis.text.x = element_text(angle = 45, hjust = 1)) # this rotates the x-axis labels by 45 degrees
Alternatively, we can place the districts on the y-axis and the immunisation coverage on the x-axis
ggplot(child_imm_2020_dhb,
# NEW LINES: swapped x and y
aes(x = perc_fully_immunised_for_age,
y = district_health_boards)
) +
geom_col() +
# NEW LINES:
labs(title = "Immunisation Coverage of 24-month-old Children in 2020",
x = "Percentage Fully Immunised",
y = "District Health Boards") +
scale_x_continuous(labels = scales::percent_format()) +
coord_cartesian(xlim = c(0,1))
You may also choose to focus on the range 75% to 100%
ggplot(child_imm_2020_dhb,
aes(x = district_health_boards,
y = perc_fully_immunised_for_age)
) +
geom_col() +
labs(title = "Immunisation Coverage of 24-month-old Children in 2020",
x = "District Health Boards",
y = "Percentage Fully Immunised") +
scale_y_continuous(labels = scales::percent_format()) + # this line formats the y-axis labels as percentages
# NEW LINE:
coord_cartesian(ylim = c(0.75,1)) + # this line sets the y-axis limits to 75% to 100%
theme(axis.text.x = element_text(angle = 45, hjust = 1))