Sources: https://www.youtube.com/watch?v=NDHSBUN_rVU + https://twitter.com/_ColinFay/status/1355132587149303812 + https://sebastiansauer.github.io/percentage_plot_ggplot2_V2/ + https://ggplot2-book.org/annotations.html + https://rpkgs.datanovia.com/ggpubr/reference/background_image.html
# Prepare the data
df1 <- iris
library(palmerpenguins)
df2 <- penguins
library(tidyverse)
library(forcats)
I like this one.
df2 %>%
count(species) %>%
mutate(species = fct_reorder(species, n)) %>% # turns a column into an ordered factor
ggplot(aes(species, n)) +
geom_col() + # instead of geom_bar(stat="identity")
coord_flip() +
geom_text(aes(label = n), hjust = 1.5, color = "white") +
theme_classic() +
theme(axis.text.y = element_text(size = rel(1.5))) # make Y-axis labels larger
I like this one less (because of the floating labels), but it is still okay.
df2 %>%
count(island) %>%
mutate(island = fct_reorder(island, n)) %>% # turns a column into an ordered factor
ggplot(aes(island, n)) +
geom_col() + # instead of geom_bar(stat="identity")
coord_flip(ylim = c(0, 200), expand = 0) +
geom_text(aes(label = n), hjust = -.3) +
theme_classic() +
theme(axis.text.y = element_text(size = rel(1.5)))
First, add some single-item groups to the data:
df1$Species <- as.character(df1$Species)
vec2 <- c(5, 4, 2, 1, "type1") # add a few small groups
vec3 <- c(5, 2, 2, 1, "type2")
vec4 <- c(5, 3, 2, 1, "type3")
df1 <- rbind(df1, vec2, vec3, vec4)
df1$Species <- as.factor(df1$Species)
df1$Sepal.Length <- as.numeric(df1$Sepal.Length)
df1$Sepal.Width <- as.numeric(df1$Sepal.Width)
df1$Petal.Length <- as.numeric(df1$Petal.Length)
df1$Petal.Width <- as.numeric(df1$Petal.Width)
table(df1$Species)
##
## setosa type1 type2 type3 versicolor virginica
## 50 1 1 1 50 50
df1 %>%
ggplot(aes(Species, Sepal.Width)) +
geom_boxplot() +
coord_flip() +
theme_bw()
This is what you get if you plot the data. But see:
df1 %>%
mutate(Species = fct_lump(Species), # merging factors by criteria
Species = fct_reorder(Species, Sepal.Width)) %>%
ggplot(aes(Species, Sepal.Width)) +
geom_boxplot() +
coord_flip() +
theme_bw() +
geom_rect(
mapping = aes(
xmin = 2.5,
xmax = 3.5,
ymin = 2.0,
ymax = 4.0
),
color = "red",
alpha = 0
)
Now they are all in the Other group.
This one is already better than the average as it shows percent instead of counts:
ggplot(df2) +
geom_bar(
aes(
x = species,
y = after_stat(100*count/sum(count))
)
) +
scale_y_continuous(limits = c(0,100)) +
labs(y = "Percent") +
theme_bw()
We can also add direct percent labels:
df2 %>%
count(species) %>%
mutate(pct = prop.table(n)) %>%
ggplot(aes(
x = forcats::fct_reorder(species,pct),
y = pct,
label = scales::percent(pct)
)) +
geom_col(width = 0.5, show.legend = "none") +
geom_text(
position = position_dodge(width = .9),
# move to center of bars
vjust = 1.5,
# nudge above top of bar
size = 3,
colour = "white"
) +
labs(x = "Species", y = "Percent") +
scale_y_continuous(labels = scales::percent, limits = c(0, 1)) +
theme_bw()
But if you prepare a party plot, you can go wherever the road takes you.
library(scales)
library(ggtext)
library(png)
library(ggpubr)
img <- png::readPNG("lter_penguins.png")
df2 %>%
count(species) %>%
mutate(pct = prop.table(n)) %>%
ggplot(aes(
x = forcats::fct_reorder(species,pct),
y = pct,
fill = factor(ifelse(species == "Adelie","Highlighted","Normal")),
label = scales::percent(pct)
)) +
background_image(img) +
geom_col(width = 0.5, show.legend = "none") +
labs(
title = "Normality was <b style='color:#6868ab'>never</b> an option",
x = "Share of Species",
y = "") +
geom_text(
position = position_dodge(width = .9),
# move to center of bars
vjust = 1.5,
# nudge above top of bar
size = 3,
colour = "white"
) +
scale_fill_manual(name = "species", values=c("#6868ab","grey30")) +
scale_y_continuous(labels = scales::percent, limits = c(0, 1)) +
theme_bw() +
theme(plot.title = element_markdown(),
axis.title.x = element_text(family = "mono"),
axis.text.x = element_text(family = "mono"),
axis.text.y = element_text(family = "mono"),
panel.grid.minor = element_blank()) +
annotate(
geom = "curve",
x = 3.25,
y = 0.75,
xend = 3,
yend = 0.45,
curvature = .3,
arrow = arrow(length = unit(2, "mm"))
) +
annotate(
geom = "text",
x = 3.6,
y = 0.76,
label = "Adelie are \n #1!",
family = "mono",
colour = "#6868ab",
fontface = 2, # bold
hjust = "right"
)