10 Workshop 10: Visualising Data
Aims:
- Practice working with ggplot() to produce a bar chart for a 2x2 factorial design.
- Explore alternative plots using code for a violin plot and a box plot.
- Practice working with ggplot() to produce a line graph for a data set looking at data over time points.
- Build and interpret a complex snowman plot.
10.1 Bar Chart
In this part of the workshop you will work step by step to build a bar chart in order to learn about ggplot().
As covered in lecture ggplot() is a very powerful package that can be used to create all sorts of figures, graphs plots, or data visuals.
As explained in lecture, to build these plots you use layers.
10.1.1 Exercise 1.1: Import Data
Import the circadian.csv data set. The code below assumes it will be called mydata.
In this data set we have two independent variables: drink type and circadian chronotype. Each with two levels. The dependent variable was self-reported “alertness”. Participants consumed one of the two energy drinks at 9am before reporting their alertness an hour later. They also completed a questionnaire to determine their circadian chronotype.
Ensure any factors are coded as a factor.
mydata$circadian = factor(mydata$circadian, levels = c("morning", "evening"))
mydata$drink = factor(mydata$drink) #turns into a factorWhy does the code above have levels = c() for one of them. This is how we can re-order the levels if needed. R will automatically have these in alphabetical order, however, as morning does indeed come before evening on each day, I will specify the order.
10.1.2 Exercise 1.2: Build the Bar Chart
You will build a bar chart step by step to learn about the different components at each layer of the code.
- Layer 1: Add data and plot aesthetics
- Layers 2 & 3: Add values and error bars.
- Layer 4: Axis labels
- Layer 5: Factor level labels
- Layer 6: Apply a theme.
Here we go…
Layer 1 Add data and plot aesthetics
Think carefully what you want to appear on the x-axis, the y-axis, and in the legend (called fill =). Change NULL with the variable names in mydata (or your data file).
Sometimes it can be helpful to sketch out your figure on paper first before trying to work with the code.
For this example, we are particularly interested in comparing the two energy drinks.
Layer 2 Add values
You have told R where to find the data (in the object called mydata) and you have plotted what should go on the two axes (x = and y=) and the figure legend (fill =) but now you need to code what values you want to display.
For a bar chart, use the mean.
Remember to use + to add this on to the code above to build the layers.
stat_summary(fun = mean, geom = "bar",
position = position_dodge(), color = "black")Layer 3 Error bars
Really simple, we will use the standard error.
If you want to instead show +/- 1 standard deviation, use the additional code below instead of this one.
Remember for each layer to add +
stat_summary(fun.data = mean_se, geom = "errorbar",
position = position_dodge(0.9), width = 0.25) 👀 Click for Standard Deviation
stat_summary(
fun.data = function(x) mean_sdl(x, mult = 1),
geom = "errorbar",
position = position_dodge(0.9),
width = 0.25)Layer 4 Axis labels
Decide on appropriate names for both the x and y axes by changing NULL.
labs(title = NULL, # keep NULL APA figures don't use titles.
x = "Circadian Chronotype",
y = "Mean Alertness Score",
fill = "Drink")Layer 5 Factor level labels
If you look at your figure at the moment, you’ll see that “morning” and “evening” are lowercase. This is the same for the drink types. Let’s change this.
Usually we want to keep our data files all lowercase. This is generally good practice because it means we do not need to keep using capital letters when coding.
However, if you look at your figure, you’ll see that “morning” and “evening” are lowercase. This is the same for the drink types. Let’s change this.
scale_fill_manual(values = c("redcow" = "slategrey", "yumster" = "slategray1"),
labels = c("Red Cow", "Yumster")) +
scale_x_discrete(labels = c("morning" = "Morning", "evening" = "Evening"))scale_fill_manual:
values =will allow you to assign colours to each level (if you have a figure legend). ’ve pickedslategrey4andslategrey2\but there are lots to choose from here: https://r-charts.com/colors/ Try to be sensible when picking colours…labels =will allow you to code what the text says within the legend itself. Here we can add capital letters.
scale_x_discrete:
-
labels =will again allow you to code what the text says on the x axis.
Layer 6 Add a theme
Themes in ggplot allow you to tidy up the figure as a whole. Here you could change the grey background, change the font types or sizes, and a few other things.
The code below does not need tweaking as it is a theme which closely mimics an APA style figure.
theme_minimal(base_size = 12) +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_rect(color = "black", fill = NA, size = 1),
legend.title = element_text(face = "bold"),
axis.title.x = element_text(face = "bold"),
axis.title.y = element_text(face = "bold"),
axis.ticks.x = element_line())Hopefully you should now have the completed figure.
10.1.3 Exercise 1.3: Tweaking the Colours
I know above I did say to be sensible about the colours. However, you might remember some quite specific branding from the two energy drinks.
Change your code from figure above to use the following colours for the two energy drink types.
- For Red Cow use
"steelblue1" - For Yumster use
"forestgreen"
10.1.4 Exercise 1.4: Saving a Plot
To save a plot, you can use the ggsave() function.
ggsave("NULL.jpg")Change NULL to a name for your file. All the text should be in quotation marks (e.g., ggsave("my_file.png")) You can also amend the file type, for example, to save it as a .jpg or .png image file.
Finally, this will then export the most recently created plot directly to your working directory.
Hint: you should do this for the plots you produce today as you will need some of them for the weekly quiz.
10.2 Violin Plot
Have a go at running this code to produce a violin plot.
ggplot(mydata, aes(x = circadian, y = alert, fill = drink)) +
geom_violin(trim = TRUE, scale = "area", alpha = 0.2, color = "white", linewidth = 0.1) +
geom_boxplot(width = 0.2, position = position_dodge(0.9), color = "black", alpha = 0.8, outlier.shape = 1) +
labs(title = NULL, # keep NULL APA figures don't use titles.
x = "Circadian Chronotype",
y = "Mean Alertness Score",
fill = "Drink") +
scale_fill_manual(values = c("redcow" = "steelblue1", "yumster" = "forestgreen"),
labels = c("Red Cow", "Yumster")) +
scale_x_discrete(labels = c("Morning", "Afternoon")) +
theme_minimal(base_size = 12) +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_rect(color = "black", fill = NA, size = 1),
legend.title = element_text(face = "bold"),
axis.title.x = element_text(face = "bold"),
axis.title.y = element_text(face = "bold"),
axis.ticks.x = element_line())10.3 Box Plot
Have a go at running this code to produce a boxplot plot.
ggplot(mydata, aes(x = circadian, y = alert, fill = drink)) +
geom_boxplot(width = 0.5, alpha = 0.7, color = "black", size = 0.2) +
labs(title = NULL, # keep NULL APA figures don't use titles.
x = "Circadian Chronotype",
y = "Mean Alertness Score",
fill = "Drink") +
scale_fill_manual(values = c("redcow" = "steelblue1", "yumster" = "forestgreen"),
labels = c("Red Cow", "Yumster")) +
scale_x_discrete(labels = c("Morning", "Afternoon")) +
theme_minimal(base_size = 12) +
theme_minimal(base_size = 12) +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_rect(color = "black", fill = NA, size = 1),
legend.title = element_text(face = "bold"),
axis.title.x = element_text(face = "bold"),
axis.title.y = element_text(face = "bold"),
axis.ticks.x = element_line())10.4 Line Chart
Import the data set called christmas.csv, save it as an object called tree.
This data contains Christmas tree sales (in millions) in the US for both real and artificial Christmas trees from 2004.
This exercise is just to help you learn to adapt code.
- Layer 1: Add data and plot aesthetics
- Layers 2 & 3: Add values and line of best fit.
- Layer 4: Labels
- Layer 5: Factor level labels and colours
- Layer 6: Apply a theme.
Layer 1 Add data and plot aesthetics
Look through the data set so you are aware what to include. Amend the code below to add data and plot the aesthetics.
Use the drop down below if you need a hint…
👀 Click for a hint
NULL1- what is the name of your object with the data.NULL2- what variable should be on the x (horizontal axis). As this is a line graph, try to think carefully what would be most appropriate.NULL3- what variable should be in the y (vertical) axis. This is usually a numeric value for most charts.NULL4- We can usecol =to decide if we have factors with multiple levels. We can then later assign these a colour or pattern (e.g. dash vs. solid line).
Layers 2 & 3 Add values and line of best fit
geom_point() +
geom_smooth(method = "lm", se = FALSE)geom_point() will add the data as points, and geom_smooth() will give us a line of best fit .
method = "lm specifies the type of line: “lm” means linear model (simple linear regression).
se = FALSE will turn off a shaded area called a confidence interval around the line.
Layer 4 Labels
Run the code below before changing any NULL values. Then look at your plot to see which NULL labels appear on each part of the plot.
Then, update these to give your plot a suitable title* and labels.
*Yes, APA format doesn’t make use of titles, but for practice why not have a go at creating one.
labs(title = "NULL1",
x = "NULL2",
y = "NULL3",
col = "NULL4") 👀 Click for the answer
labs(title = "Real and Artificial Christmas Trees Sold in the US",
x = "Year",
y = "Trees Sold (Millions)",
col = "Type of Tree") Layer 5 Factor level labels and colours
scale_colour_manual(
values = c("Artificial Tree" = "green2", "Real Tree" = "darkgreen"),
labels = c("NULL1", "NULL2"))Change NULL values to suitable labels for the two tree types.
Layer 6 Apply a theme.
AGain, not stricly APA but just to try out different things, keep it simple and apply
theme_bw()Consider trying different themes. Change theme_bw() to one of these below to see how it changes the plot. Which is your favourite?
theme_bw()
#or
theme_classic()
#or
theme_linedraw()
#or
theme_grey()There you go, you now have a perfectly functioning line chart.
10.5 Snowman Plot
Now for some real serious complicated plotting…
ggplot() is really powerful and there are so many things you can do with it.
You’ll need these packages.
install.packages("ggforce") # you'll need this package if not installed
library(ggforce)
library(tidyverse) # if not already loadedCopy and paste the code below for the snowman plot… The code is quite long so expand the section below to copy it, and then run it all at once.
❄️ Click to build a snowman
snowman <- tibble(y = 1:3, x = 0, r = 1:3)
p <- ggplot(snowman) +
geom_circle(aes(x0 = x, y0 = y, r = r)) +
coord_fixed()
snowman <- tibble(x = 0, r = 3:1) %>%
mutate(y =(r^2) *-1)
p <- ggplot(snowman) +
geom_circle(aes(x0 = x, y0 = y, r = r),
fill = "white",
colour = "lightgrey") +
coord_fixed()
face <- tibble(x = c(-0.5, 0.5, 0),
y = c(.75, .75, 1)*-1,
type = c("eye", "eye", "nose"),
colour = c("black","black", "coral2"))
p <- p + geom_point(data = face, show.legend = FALSE,
aes(x = x, y = y,
shape = type, colour = I(colour)))
p <- p + geom_arc(aes(x0 = snowman$x[nrow(snowman)],
y0 = snowman$y[nrow(snowman)],
start = 2.2, end = 4, r=.6))
arms <- tibble(x = c(-3.5, -2, -3, -3.4, -3, -3.2, 2, 3.6, 3.1, 3.5, 3.1, 3.3),
y = c(-3, -3.7, -3.2, -3.5, -3.2, -2.8, -3.7, -3, -3.2, -3.4, -3.1, -2.5),
side = c(rep("left arm", 2),
rep("left finger1", 2),
rep("left finger2", 2),
rep("right arm", 2),
rep("right finger1", 2),
rep("right finger2", 2)))
p <- p + geom_line(data = arms,
size = 1.5, lineend = "round",
aes(x = x, y = y, group = side))
p <- p + geom_point(aes(x = 0, y = -3:-5), size = 4)
tophat <- tibble(x = c(-1, -0.9, -0.3, -0.4, 1.1, 0.8, 1.5, 1.4),
y = c(0, .25, .15, 1, .75, -0.04, -.25, -.5),
id = 1)
p <- p + geom_polygon(data = tophat,
aes(x = x, y = y, group = id))
scarf <- tibble(x = c(-0.5, 0.3, 0.4, 0.3, 0.5),
y = c(-2, -2, -3, -2, -2))
p <- p + geom_line(data = scarf, size = 3,
lineend="round",
colour = "firebrick4",
aes(x = x, y = y))
p + theme_void() +
theme(plot.background = element_rect(fill = "skyblue3"))This code was adapted from:
DrMowinckels (Dec 11, 2019) Do you wanna build a snowman?. Retrieved from https://drmowinckels.io/blog/2019/do-you-wanna-build-a-snowman/. DOI: https://www.doi.org/10.5281/zenodo.13273500
Well Done. You have reached the end of the workshop
10.6 Optional Exercises and Resources for Data Visualisation
The code below might be useful for your lab report to display a main effect. You’ll need the tidyverse package.
10.7 Bar Charts (for t-tests, one-way designs, or main effects)
Download and import the hazard data set for this example. The code below assumes the data has been saved as an object called mydata.
In this data set cc is the circadian chronotype either morning (lark), neither, or evening (owl) preference. slp is whether the participant reported a calm or disturbed night sleep. alert was the dependent variable and measured morning alertness. Although this is a factorial design, this example will only look at cc independent variable, similar to that of a one-way ANOVA or if you only wanted to report the main effect of circadian chronotype.
This is already in long format, so no need to amend it. However, it is good to check and re-order any factors.
mydata$cc <- factor(mydata$cc, levels = c("lark", "neither", "owl"))
mydata$slp <- factor(mydata$slp)10.7.1 Bar Chart
This code will plot mean alertness scores for the three circadian chronotype groups cc, ignoring sleep quality slp.
ggplot(mydata, aes(x = cc, y = alert)) +
stat_summary(fun = mean, geom = "bar",
position = position_dodge(), color = "black",
fill = "steelblue") +
stat_summary(fun.data = mean_se, geom = "errorbar",
position = position_dodge(0.9), width = 0.25) +
labs(title = NULL, # keep NULL APA figures don't use titles.
x = "Circadian Chronotype",
y = "Mean Alertness Score") +
scale_x_discrete(labels = c("Lark", "Neither", "Owl")) +
theme_minimal(base_size = 12) +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_rect(color = "black", fill = NA, linewidth = 1),
legend.title = element_text(face = "bold"),
axis.title.x = element_text(face = "bold"),
axis.title.y = element_text(face = "bold"),
axis.ticks.x = element_line())10.7.2 Violin Plot
Same data set, just a different way to show the three groups.
ggplot(mydata, aes(x = cc, y = alert)) +
geom_violin(trim = TRUE, scale = "area", alpha = 0.2, color = "white", linewidth = 0.1, fill = "steelblue") +
geom_boxplot(width = 0.2, position = position_dodge(0.9), color = "black", alpha = 0.8, outlier.shape = 1,
fill = "steelblue") +
labs(title = NULL, # keep NULL APA figures don't use titles.
x = "Circadian Chronotype",
y = "Mean Alertness Score") +
scale_x_discrete(labels = c("Lark", "Neither", "Owl")) +
theme_minimal(base_size = 12) +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_rect(color = "black", fill = NA, linewidth = 1),
legend.title = element_text(face = "bold"),
axis.title.x = element_text(face = "bold"),
axis.title.y = element_text(face = "bold"),
axis.ticks.x = element_line())10.7.3 Box Plot
Same data set, just a different way to show the three groups. All you’ll notice here is the geom_violin() function has been removed, because a box plot is essentially a violn plot but without the density information.
The width for the boxplot has also increased a little too.
ggplot(mydata, aes(x = cc, y = alert)) +
geom_boxplot(width = 0.5, position = position_dodge(0.9), color = "black", alpha = 0.8, outlier.shape = 1,
fill = "steelblue") +
labs(title = NULL, # keep NULL APA figures don't use titles.
x = "Circadian Chronotype",
y = "Mean Alertness Score") +
scale_x_discrete(labels = c("Morning", "Neither", "Evening")) +
theme_minimal(base_size = 12) +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_rect(color = "black", fill = NA, linewidth = 1),
legend.title = element_text(face = "bold"),
axis.title.x = element_text(face = "bold"),
axis.title.y = element_text(face = "bold"),
axis.ticks.x = element_line())If you have only two levels, this code will still work! You just need to remove the third label in scale_x_discrete() when you change the labels to match your data set. A bar chart example is below for an example using sleep qualit: calm vs. disturbed.
ggplot(mydata, aes(x = slp, y = alert)) +
stat_summary(fun = mean, geom = "bar",
position = position_dodge(), color = "black",
fill = "steelblue") +
stat_summary(fun.data = mean_se, geom = "errorbar",
position = position_dodge(0.9), width = 0.25) +
labs(title = NULL, # keep NULL APA figures don't use titles.
x = "Sleep Quality",
y = "Mean Alertness Score") +
scale_x_discrete(labels = c("Calm", "Disturbed")) +
theme_minimal(base_size = 12) +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_rect(color = "black", fill = NA, linewidth = 1),
legend.title = element_text(face = "bold"),
axis.title.x = element_text(face = "bold"),
axis.title.y = element_text(face = "bold"),
axis.ticks.x = element_line())