'How to swap x-axis tick labels with plus/minus signs table

I'm struggling to figure how to change my x-axis label in ggplot2 from regular identifications to not-so-regular plus/minus signs to relate the addition or absence of a particular treatment on each bar. Something as this picture below:

Bar plot with pus/minus signs below

To be honest, I don't even know how this type of axis labeling is called. It is more frequent in biological sciences representations and I'm used to changing the plot using Gimp or other image editing software to manually add this. It is something like adding a table below the graph to identify each condition.



Solution 1:[1]

A potential solution without invoking a second plot is to plot it on a pseudo-discrete axis and place breaks accordingly.

library(ggplot2)

df <- data.frame(
    cpd1 = c("-", "-", "+", "+"),
    cpd2 = c("-", "+", "-", "+"),
    value = rpois(4, 10)
)

# Pre-form interaction
df <- transform(df, int = interaction(cpd1, cpd2, sep = "\n"))

ggplot(df, aes(as.numeric(int), value)) +
    geom_col() +
    scale_x_continuous(
        breaks = c(0.5, seq_len(nrow(df))),
        labels = c("Cpd 1\nCpd 2", as.character(df$int))
    )

Created on 2022-05-13 by the reprex package (v0.3.0)

You could even hide the first tick mark by adding:

  theme(
    axis.ticks.x.bottom = element_line(colour = c(NA, rep("black", nrow(df))))
  )

Solution 2:[2]

There are a few ways to accomplish this; here is one potential solution:

library(tidyverse)
library(cowplot)

df <- tibble(
  Names = c(rep("A", 11), rep("B", 7),
             rep("C", 4), rep("D", 12)),
  Values = rnorm(34, 25, 10),
  `Cpd 1` = c(rep("+", 11), rep("+", 7),
              rep("-", 4), rep("-", 12)),
  `Cpd 2` = c(rep("+", 11), rep("-", 7),
              rep("+", 4), rep("-", 12)),
)

p1 <- df %>% 
  ggplot(aes(x = Names, y = Values)) +
  geom_col(width = 0.25) +
  theme_minimal(base_size = 14) +
  theme(axis.text.x = element_blank(),
        axis.title.x = element_blank()) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.05)))

p2 <- df %>% 
  pivot_longer(-c(Names, Values)) %>% 
  ggplot(aes(x = Names, fct_rev(name), label = value)) +
  geom_text(size = 10) +
  labs(x = NULL, y = NULL) +
  theme_minimal(base_size = 14) +
  theme(panel.grid = element_blank(), axis.text.x = element_blank())

plot_grid(p1, p2, ncol = 1, align = "hv", rel_heights = c(0.75, 0.25))

Created on 2022-05-13 by the reprex package (v2.0.1)


If you also want group labels:

library(tidyverse)
library(cowplot)

df <- tibble(
  Names = c(rep("A", 11), rep("B", 7),
             rep("C", 4), rep("D", 12)),
  Values = rnorm(34, 25, 10),
  `Cpd 1` = c(rep("+", 11), rep("+", 7),
              rep("-", 4), rep("-", 12)),
  `Cpd 2` = c(rep("+", 11), rep("-", 7),
              rep("+", 4), rep("-", 12)),
)

p1 <- df %>% 
  ggplot(aes(x = Names, y = Values)) +
  geom_col(width = 0.4) +
  theme_minimal(base_size = 14) +
  theme(axis.text.x = element_text(size = 18),
        axis.title.x = element_blank(),
        axis.line = element_line(size = 2.5)) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.05)))

p2 <- df %>% 
  pivot_longer(-c(Names, Values)) %>% 
  ggplot(aes(x = Names, fct_rev(name), label = value)) +
  geom_text(size = 10) +
  labs(x = NULL, y = NULL) +
  theme_minimal(base_size = 14) +
  theme(panel.grid = element_blank(), axis.text.x = element_blank())

plot_grid(p1, p2, ncol = 1, align = "hv", rel_heights = c(0.7, 0.3))

Created on 2022-05-13 by the reprex package (v2.0.1)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 teunbrand
Solution 2 jared_mamrot