bluemouse
bluemouse

Reputation: 482

Adding section titles between tick labels in a horizontal bar plot

I am trying to make a horizontal grouped bar plot showing how people have answered different questions.

Is there a way I can divide the questions into sections, putting a bold heading above each section stating what it is? Preferably without it resulting in separate plot areas the way it would if I used panels.

For the example below, suppose the headings I want to insert are "Vowels" and "Consonants" (hand-drawn in red in the picture in this example)

enter image description here

library('ggplot2')
library('stringr')
set.seed(5)

questions <- str_wrap(c('Blah blah blah blah blah blah B?',
                        'Blbbity blah blibbity blah C?',
                        'Blah blah blibbity blah blah blah D?',
                        'Blah blah blah A?',
                        'Blah blah blah blibbity E?',
                        'Blah blah blibbity blah I?'),15)

status <- data.frame(matrix(data=NA, nrow=18,ncol=3))
names(status) <- c('varname','type','percent')
status['varname'] <- factor(c(rep(1,3),rep(2,3),rep(3,3),rep(4,3),rep(5,3),rep(6,3)),labels=questions)
status['type'] <- c(rep(c('Cohabiting','Married','Divorced'),6))
status['percent'] <- c(rnorm(18,.5,.2))
ggplot(status, aes(varname, percent)) +   
  theme(axis.title.y = element_blank(), legend.title = element_blank(), plot.title = element_text(hjust = 0.5), legend.position = "top") +
  geom_bar(aes(fill = type), position = "dodge", stat="identity") + coord_flip() + scale_fill_manual(values=c('cadetblue1','cadetblue3','darkcyan')) +
  ggtitle('By couple type') + labs(y='Percent') + ylim(0,1)

Upvotes: 3

Views: 88

Answers (2)

Tung
Tung

Reputation: 28451

You can tweak facet_grid() plot to remove all the panels to your liking.

If you want a y-axis across facets, see this answer

library(dplyr)
library("ggplot2")
library("stringr")

# create new alp variable
status <- status %>% 
  # edit: shamelessly steal from Maurits's answer :-)
  mutate(alp = if_else(str_detect(varname, "(I|E|A)\\?$"), "Vowels", "Consontants"))

p2 <- ggplot(status, aes(varname, percent)) +
  geom_col(aes(fill = type), position = "dodge") + 
  facet_grid(alp ~ ., scales = 'free_y', space = 'free_y', switch = 'y') +
  coord_flip() + 
  scale_fill_manual(values = c("cadetblue1", "cadetblue3", "darkcyan"),
                    # increase the spacing between legend key text
                    labels = stringr::str_pad(status$type, 5, "right"),) +
  ggtitle("By couple type") + 
  labs(y = "Percent") + 
  scale_x_discrete(expand = c(0, 0)) +
  scale_y_continuous(expand = c(0, 0), limits = c(0, 1)) +
  theme_classic(base_size = 14, base_family = 'mono') +
  theme(axis.title.y = element_blank(), 
        legend.spacing.x = unit(0.25, unit = "cm"),
        legend.title = element_blank(), 
        plot.title = element_text(hjust = 0.5), 
        legend.position = "top") +
  theme(panel.grid.minor.x = element_blank()) + 
  # switch the facet strip label to outside 
  theme(strip.placement = 'outside',
        strip.text.y = element_text(face = 'bold'),
        strip.background.y = element_rect(colour = NA, fill = 'grey80'))
p2

p3 <- ggplot(status, aes(varname, percent)) +
  geom_col(aes(fill = type), position = "dodge") + 
  facet_grid(alp ~ ., scales = 'free_y', space = 'free_y', switch = 'y') +
  coord_flip() + 
  scale_fill_manual(values = c("cadetblue1", "cadetblue3", "darkcyan"),
                    # increase the spacing between legend key text
                    labels = stringr::str_pad(status$type, 5, "right"),) +
  ggtitle("By couple type") + 
  labs(y = "Percent") + 
  scale_x_discrete(expand = c(0, 0)) +
  scale_y_continuous(expand = c(0, 0), limits = c(0, 1)) +
  theme_classic(base_size = 14, base_family = 'mono') +
  theme(axis.title.y = element_blank(), 
        legend.spacing.x = unit(0.25, unit = "cm"),
        legend.title = element_blank(), 
        plot.title = element_text(hjust = 0.5), 
        legend.position = "top") +
  theme(panel.grid.minor.x = element_blank()) + 
  # switch the facet strip label to outside 
  # remove background color
  theme(strip.placement = 'outside',
        strip.text.y = element_text(face = 'bold'),
        strip.background.y = element_blank())
p3

Created on 2018-10-02 by the reprex package (v0.2.1.9000)

Upvotes: 2

Maurits Evers
Maurits Evers

Reputation: 50738

How about using facets?

library(tidyverse)
status %>%
    mutate_if(is.factor, as.character) %>%
    mutate(Group = if_else(str_detect(varname, "(I|E|A)\\?$"), "Vowels", "Consontants")) %>%
    ggplot(aes(varname, percent)) +
    theme(
        axis.title.y = element_blank(),
        legend.title = element_blank(),
        plot.title = element_text(hjust = 0.5),
        legend.position = "top") +
  geom_bar(aes(fill = type), position = "dodge", stat = "identity") +
  facet_wrap(~Group, ncol = 1, scales = "free_y") +
  coord_flip() +
  scale_fill_manual(values = c('cadetblue1', 'cadetblue3', 'darkcyan')) +
  ggtitle('By couple type') +
  labs(y = 'Percent') +
  ylim(0, 1)

enter image description here

Or you can move the strip labels to the left:

library(tidyverse)
status %>%
    mutate_if(is.factor, as.character) %>%
    mutate(Group = if_else(str_detect(varname, "(I|E|A)\\?$"), "Vowels", "Consontants")) %>%
    ggplot(aes(varname, percent)) +
    theme(
        axis.title.y = element_blank(),
        legend.title = element_blank(),
        plot.title = element_text(hjust = 0.5),
        legend.position = "top") +
  geom_bar(aes(fill = type), position = "dodge", stat = "identity") +
  facet_wrap(~Group, ncol = 1, scales = "free_y", strip.position = "left") +
  coord_flip() +
  scale_fill_manual(values = c('cadetblue1', 'cadetblue3', 'darkcyan')) +
  ggtitle('By couple type') +
  labs(y = 'Percent') +
  ylim(0, 1)

enter image description here

Upvotes: 1

Related Questions