M.R.Wani
M.R.Wani

Reputation: 107

How to add common line and text as second x-axis label

I want to plot a graph. Several of my x-axis labels have a common label. So I want to add common text as label instead of several separate labels on x-axis as shown in the attached images. How can this be done?

library(dplyr)
library(forcats)
library(ggplot2)

df <- data.frame(conc = c(0, 10, 50, 100, "Positive Control"),
                 values = c(3, 3, 4, 5, 10),
                 name = c("TiO2 NP", "TiO2 NP", "TiO2 NP", "TiO2 NP", "Cyclophosamide"))

df$conc <- as.factor(df$conc)
labels2 <- paste0(df$conc, "\n", df$name)

df %>% 
  mutate(conc = fct_reorder(conc, values)) %>% 
  ggplot(aes(x = conc, y=values, fill = conc))+
  geom_bar(stat = "identity",show.legend = FALSE, width = 0.6)+
  scale_x_discrete(labels = labels2)+
  labs(x = "\n Dose (mg/kg BW)")

Upvotes: 1

Views: 1360

Answers (2)

Z.Lin
Z.Lin

Reputation: 29095

For a more automated approach, you can try placing the common variable in facet_grid with scales = "free", space = "free", to simulate a 2nd x-axis line. The rest of the code below are for aesthetic tweaks:

df %>%
  mutate(conc = fct_reorder(conc, values)) %>%
  ggplot(aes(x = conc, y = values, fill = conc)) +
  geom_col(show.legend = F, width = 0.6) + #geom_col() is equivalent to geom_bar(stat = "identity")
  facet_grid(~ fct_rev(name), 
             scales = "free", space = "free", 
             switch = "x") + #brings the facet label positions from top (default) to bottom
  scale_x_discrete(expand = c(0, 0.5)) + #adjusts the horizontal space at the ends of each facet
  labs(x = "\n Dose (mg/kg BW)") +
  theme(axis.line.x = element_line(arrow = arrow(ends = "both")), #show line (with arrow ends) to
                                                                  #indicate facet label's extent
        panel.spacing = unit(0, "cm"), #adjusts space between the facets
        strip.placement = "outside", #positions facet labels below x-axis labels
        strip.background = element_blank()) #transparent background for facet labels

plot

Upvotes: 1

Paweł Chabros
Paweł Chabros

Reputation: 2399

I don't think there's a simple way. You have to play with ggplot2 for some time to make something really custom. Here's my example:

df %>%
  mutate(
    conc = fct_reorder(conc, values),
    labels2 = if_else(
      name == 'TiO2 NP',
      as.character(conc),
      paste0(conc, '\n', name)
    )
  ) %>% 
  ggplot(aes(x=conc, y=values, fill = conc)) +
  geom_bar(
    stat = "identity",
    show.legend = FALSE,
    width = 0.6
  ) +
  geom_rect(aes(
      xmin = .4,
      xmax = 5.6,
      ymin = -Inf,
      ymax = 0
    ),
    fill = 'white'
  ) +
  geom_text(aes(
      y = -.4,
      label = labels2
    ),
    vjust = 1,
    size = 3.4,
    color = rgb(.3, .3, .3)
  ) +
  geom_line(data = tibble(
      x = c(.9, 4.1),
      y = c(-1.2, -1.2)
    ),
    aes(
      x = x,
      y = y
    ),
    color = rgb(.3, .3, .3),
    inherit.aes = FALSE
  ) +
  geom_curve(data = tibble(
      x1 = c(.8, 4.1),
      x2 = c(.9, 4.2),
      y1 = c(-.8, -1.2),
      y2 = c(-1.2, -.8)
    ),
    aes(
      x = x1,
      y = y1,
      xend = x2,
      yend = y2
    ),
    color = rgb(.3, .3, .3),
    inherit.aes = FALSE
  ) +
  geom_text(aes(
      x = 2.5,
      y = -1.7,
      label = 'TiO2 NP'
    ),
    size = 3.4,
    color = rgb(.3, .3, .3),
    check_overlap = TRUE
  ) +
  geom_text(aes(
      x = 3,
      y = -2.4,
      label = '\n Dose (mg/kg BW)'
    ),
    show.legend = FALSE,
    check_overlap = TRUE
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_blank(),
    axis.title.x = element_blank()
  ) +
  scale_y_continuous(
    breaks = seq(0, 10, 2.5),
    limits = c(-2.5, 10)
  )

example plot

Upvotes: 3

Related Questions