How to recreate this excel Barchart + data table in R (ggplot2)?

Viewed 471

I have a bar chart that I made in excel using the mtcars dataset but I need to create it in R. I know how to make a stacked chart, but it is possible to add the data table like this below/integrated with the graphic?

enter image description here

Thank you,

3 Answers

patchwork can be used to combine the two graphs and ggtext can be used for the legend.

library(tidyverse)
library(patchwork)
library(ggtext)

Transform the data. With ggtext we can use markdown in the gear column. We'll use the ■ symbol and colour it.

df <-
  mtcars %>%
  mutate(
    color = case_when(
      gear == 5 ~ "#F8766D",
      gear == 4 ~ "#00BA38",
      gear == 3 ~ "#619CFF",
    ),
    gear = fct_reorder(as_factor(glue::glue("<b style='color:{color}'>■</b> {gear} Gears")), gear),
    cyl = paste0(cyl, " Cyl")
  ) %>%
  count(gear, cyl) 
p1 <-
  ggplot(df, aes(cyl, n, fill = gear)) +
  geom_col() +
  scale_y_continuous(breaks = seq(from = 0, to = 16, by = 2), lim = c(0, 16)) +
  theme_minimal() +
  theme(
    legend.position = "none",
    axis.title.x = element_blank(),
    axis.title.y = element_blank(),
    panel.grid.minor.x = element_blank(),
    panel.grid.major.x = element_blank(),
    panel.grid.minor.y = element_blank(),
    panel.grid.major.y = element_line(colour = "grey")
  ) +
  labs(
    title = "Gears and Cylinders - mtcars.csv"
  )

p2 <-
  df %>%
  ggplot(aes(cyl, gear, label = n)) +
  geom_text() +
  geom_hline(yintercept = c(0.5, 1.5, 2.5), colour='grey') +
  theme_void() +
  theme(
    axis.text.y = element_markdown(),
    plot.title = element_blank()
  )

Use patchwork to combine it together.

p1 + p2 + plot_layout(ncol = 1, heights = c(7, 2))

plot

I guess you could do something like this:

df <- as.data.frame(table(mtcars$cyl, mtcars$gear))
names(df) <- c("cyl", "gear", "n")
df$ypos <- -2 * as.numeric(df$gear) - 1
df$gear <- factor(df$gear, levels = c(5, 4, 3))

ggplot(df, aes(x = cyl, y = n, fill = gear)) +
  geom_col(position = position_stack(), width = 0.5) + 
  geom_hline(yintercept = c(-4, -6)) +
  geom_text(aes(label = n, y = ypos)) +
  geom_text(data = data.frame(label = c("4 cyl", "6 cyl", "8 cyl"),
                              cyl = c("4", "6", "8"), n = -1),
            aes(x = cyl, y = n, label = label), inherit.aes = FALSE) +
  scale_y_continuous(limits = c(-10, 16), breaks = 0:8 * 2) +
  scale_fill_manual(values = c("#ff8021","#5dceb0", "#5fccf3")) +
  labs(title = "Gears and Cylinders - mtcars.csv", y = "") +
  theme_bw() +
  theme(plot.title = element_text(hjust = 0.5, color = "gray50", size = 20),
        legend.position = c(0, 0.25),
        legend.key.height =  unit(1, "cm"), 
        panel.grid.major.x = element_blank(),
        panel.grid.minor.y = element_blank(),
        panel.border = element_rect(fill = NA, color = NA),
        axis.title.x = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.length.x = unit(0, "mm"))

enter image description here

Another approach would be:

library(ggplot2)
library(dplyr)
library(tidyr)
library(patchwork)
library(gridExtra)
#Data
data("mtcars")
#Code for data process
df <- mtcars %>% mutate(gear=factor(paste(gear,'gears'),
                                    levels=c('5 gears','4 gears','3 gears'),
                                    ordered = T),
                  cyl=paste(cyl,'Cyl')) %>%
  group_by(cyl,gear) %>% summarise(N=n())
#Plot
G1 <- ggplot(df,aes(x=cyl,y=N,fill=gear))+
  geom_bar(stat = 'identity')+
  theme_bw()+scale_fill_manual(values=c('orange','aquamarine3','cyan3'))+
  ggtitle('Gears and cylinders')+
  theme(plot.title = element_text(hjust=0.5),
        legend.position = 'none')
#Table
T1 <- df %>% pivot_wider(names_from = cyl,values_from=N) %>% replace(is.na(.),0)
#Format
#Theme
my_table_theme <- ttheme_default(core=list(bg_params = list(fill = c('orange','aquamarine3','cyan3'), col=NA)))
#Design
g1 <- gridExtra::tableGrob(T1["gear"], theme=my_table_theme, rows = NULL)
g2 <- gridExtra::tableGrob(T1[,-1], rows = NULL)
g2$widths <- unit(rep(0.25, 3), "npc")
haligned <- gtable_combine(g1,g2, along=1)
Fplot <- G1/haligned

Output:

enter image description here

Related