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

1. Drawing a descending barplot

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)))

2. Lumping smaller groups together in the “Other” category within a plot

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.

3. Ploting with percent

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"
  )