4
big_theme <- theme(
  panel.background = element_rect(fill = "black"),
  plot.background = element_rect(fill = "black", colour = NA),
  plot.title = element_text(hjust = 0.5, size = 15, color = "white"),
  axis.text.y = element_text(colour = "white", size = 14),
  axis.title.x = element_text(colour = "white", size = 14),
  axis.title.y = element_text(colour = "white", size = 14),
  axis.text.x = element_text(vjust = 1, angle = 45, color = "white", size = 14, hjust=1),
  strip.background = element_rect(fill = "black"),
  strip.text = element_text(colour = 'white'),
  strip.text.y = element_text(angle = 0), 
  legend.position = "top"
)

theme2 = theme(panel.background = element_rect(fill = 'black'),
  legend.background=element_rect(fill = "black"),
  legend.text = element_text(colour = "white", size = 14), 
  legend.justification = "right",
  legend.key.height = unit(1, "line"),
  legend.key = element_rect(color = "black", fill = "black"))

theme3 = theme(plot.background = element_rect(fill = 'black'))

plot1 <- ggplot(sample_data) + big_theme + theme2 + theme3
plot1 + 
  geom_col(position = "identity", 
           aes(x = category, y = value,
               fill = forcats::fct_relevel(variable, c("z", "x", "y")),
               color = forcats::fct_relevel(variable, c("z", "x", "y")))) + 
  scale_fill_manual(values = c("#000000","#D3667C","#53AC79")) + 
  scale_color_manual(values = c("#00A2EF","#D3667C","#53AC79")) + 
  geom_text(aes(label = big_category, x = big_category, y = 0), vjust = 0, 
            size = 3, color = "white", position = position_dodge(width = 1)) +  
  scale_y_continuous(limits = c(0, 2.4), expand = c(0, 0)) 

I have a dataset that looks like:

big_category category   variable    value
a     aa    x   1.2
a     ba    x   1.05
a     ca    x   1.11
a     aa    y   1.43
a     ba    y   1.09
a     ca    y   0.97
a     aa    z   1.12
a     ba    z   1.46
a     ca    z   1.32

b     ab    x   1.2
b     bb    x   1.05
b     cb    x   1.11
b     ab    y   1.43
b     bb    y   1.09
b     cb    y   0.97
b     ab    z   1.12
b     bb    z   1.46
b     cb    z   1.32
c     ac    x   1.2
c     ac    y   1.05
c     ac    z   1.11

I want the x-axis to be labeled by category and below that I want labels for big_category. For example, I want axis labels for aa,ba, and ca, and then one label below that for big_category a in the ggplot. I dont want it mixed in with the labels for category and I also want it underneath the x-axis labels displayed horizontally.

I've also tried facet_grid but that gives me a problem, as the bars aren't evenly sized. Like big_category a has 3 categories but big_category c has only 1. I want all of them to have the same width, and I want one continuous plot.

Update

big_category category variable value
a aa111111111 x 1.2
a ba111111111 x 1.05
a ca111111111 x 1.11
a aa111111111 y 1.43
a ba111111111 y 1.09
a ca111111111 y 0.97
a aa111111111 z 1.12
a ba111111111 z 1.46
a ca111111111 z 1.32
b ab111111111 x 1.2
b ab111111111 y 1.05
b ab111111111 z 1.11
c ac111111111 x 1.2
c bc111111111 x 1.05
c cc111111111 x 1.11
c ac111111111 y 1.43
c bc111111111 y 1.09
c cc111111111 y 0.97
c ac111111111 z 1.12
c bc111111111 z 1.46
c cc111111111 z 1.32

Code:

big_theme <- theme(
panel.background = element_rect(fill = "black"),
plot.background = element_rect(fill = "black", colour = NA),
plot.title = element_text(hjust = 0.5, size = 15, color = "white"),
axis.text.y = element_text(colour = "white", size = 14),
axis.title.x = element_text(colour = "white", size = 14),
axis.title.y = element_text(colour = "white", size = 14),
axis.text.x = element_text(vjust = 1, angle = 45, color = "white", size = 14, hjust=1),
strip.background = element_rect(fill = "black"),
strip.text = element_text(colour = 'white'),
strip.text.y = element_text(angle = 0),
legend.position = "top"
)

theme2 = theme(panel.background = element_rect(fill = 'black'),
legend.background=element_rect(fill = "black"),
legend.text = element_text(colour = "white", size = 14),
legend.justification = "right",
legend.key.height = unit(1, "line"),
legend.key = element_rect(color = "black", fill = "black"))

theme3 = theme(plot.background = element_rect(fill = 'black'))

ggplot(sample_data %>% mutate(variable=fct_relevel(variable, c("z","x","y")))) +
geom_col(position = "identity",
aes(x = category, y = value, fill = variable, color = variable)) +
facet_grid(. ~ big_category, space="free_x", scales="free_x", switch="x") +
big_theme + theme2 + theme3 +
theme(strip.placement = "outside",
strip.background = element_rect(fill=NA,colour="white"),
panel.spacing.x=unit(0,"cm"),
strip.text = element_text(hjust=0, face="bold", size=12))
Ark
  • 93
  • 2
  • 6
  • Options 1a and 1b in [this SO answer](https://stackoverflow.com/a/44616739/496488) may be helpful. The basic idea is that you facet by `big_category` and put the facet labels on the bottom (and outside the axis) instead of on the top. – eipi10 Jan 31 '18 at 23:23
  • I looked at it and it was helpful. However, the bars aren't evenly sized as there are not equal number of categories per big_category. – Ark Feb 01 '18 at 04:48

1 Answers1

10

Below is an example, using your sample data, of how to have category within big_category. I've included only the essential plot elements for simplicity. You can, of course, add your specific theme, colors, and other elements to the basic plot below.

library(tidyverse)

ggplot(sample_data %>% mutate(variable=fct_relevel(variable, c("z","x","y")))) +
  geom_col(position = "identity", 
           aes(x = category, y = value, fill = variable, color = variable)) + 
  facet_grid(. ~ big_category, space="free_x", scales="free_x", switch="x") +
  theme_classic() +
  theme(strip.placement = "outside",
        strip.background = element_rect(fill=NA, colour="grey50"),
        panel.spacing.x=unit(0,"cm"))

enter image description here

UPDATE: If I understand your comment, here's updated code to left-justify the strip text and remove the strip borders. I don't know of a way (without hacking the underlying graphical objects outside of ggplot) to have just vertical lines between strips. However, I've added back a bit of space between panels and added panel borders to delineate the big_category levels.

ggplot(sample_data %>% mutate(variable=fct_relevel(variable, c("z","x","y")))) +
  geom_col(position = "identity", 
           aes(x = category, y = value, fill = variable, color = variable)) + 
  facet_grid(. ~ big_category, space="free_x", scales="free_x", switch="x") +
  theme_bw() +
  theme(strip.placement = "outside",
        strip.background = element_rect(fill=NA,colour=NA),
        panel.spacing.x=unit(0.15,"cm"), 
        strip.text = element_text(hjust=0, face="bold", size=12))

enter image description here

UPDATE 2: I've created a plot with the following changes: (1) big_category labels at the left end of the x-axis labels, and (2) blank big_category labels when category has less than 3 unique levels. To keep the same facet "breaks" with blank labels, we create a unique white-space string (by varying the length of the string) for each former big_category value.

I don't think the plot looks very good (I actually think it would work better with the big_category facet strips on top in their standard position and with the text centered), but perhaps you can play around with it and get something that meets your needs. I've commented the code to explain what it's doing, but let me know if anything is unclear.

We'll use the new sample_data you posted, but we'll add a fourth level to big_category:

sample_data = sample_data %>% 
  bind_rows(data_frame(big_category="d",
                       category=c("da1111111111", "db111111"),
                       variable=c("z","x"), value=c(1.1,0.6)))

Now we'll make a few transformations of sample_data to set it up for plotting and pipe the adjusted data frame right into ggplot:

sample_data %>% 
  mutate(variable=fct_relevel(variable, c("z","x","y"))) %>% 
  # Create grouping column (called short_cat) to mark levels of big_category 
  #  with two or fewer unique levels of category
  group_by(big_category) %>% 
  mutate(short_cat = length(unique(category)) <= 2) %>% 
  ungroup %>% 
  # Create a unique white-space string for each unique value of grp
  mutate(grp = c(0, cumsum(diff(short_cat) != 0)),
         grp = sapply(grp, function(g) paste(rep(" ", g), collapse="")),
         # Assign white-space strings to each level of big_category for which short_cat 
         # is TRUE
         big_category=replace(big_category, short_cat, grp[short_cat]),
         # Set factor order for big_category so new levels will stay in same order 
         #  as original levels
         big_category=factor(big_category, levels=unique(big_category))) %>%
  ggplot() +
    geom_col(position = "identity", width=0.8, 
             aes(x = category, y = value, fill = variable, color = variable)) + 
    facet_grid(. ~ big_category, space="free_x", scales="free_x", switch="x") +
    theme_bw() +
    theme(axis.text.x=element_text(angle=45, vjust=1, hjust=1),
          strip.placement = "outside",
          strip.background = element_rect(fill=NA,colour=NA),
          panel.spacing.x=unit(0.15,"cm"), 
          # Left justify big_category labels
          strip.text = element_text(hjust=0, face="bold", size=12)) +
    # Expand left side of x-axis so that big_category labels will be under left 
    #  end of x-axis labels
    expand_limits(x=-0.5)

enter image description here

eipi10
  • 91,525
  • 24
  • 209
  • 285
  • How do I move the rectangle and text? I want the a, b, and c to be adjusted to the left since I did an just on the aa, ba, ca, ab, bb, cb, ac. I want to do an just but when I do an just on text, it does invisible, and I can't just the rectangle. I also want to put just 2 lines on the sides, not a full rectangle. Basically, the rectangle without the top and bottom. – Ark Feb 01 '18 at 18:16
  • Please see my updated answer and let me know if that helps. – eipi10 Feb 02 '18 at 06:35
  • Thanks for your update. I guess the problem doesn't show clearly in this sample data since it's too small. But I have like 50 long labels in category, and I adjusted it in a 45 degree angle. Hence, the labels go well to the left of the graph. I want the big category label to go all the way to the bottom left of the label. Also, I want to be able to remove the big_category label for big_categories with less than 2 categories. I have updated the code and chart to reflect this change and problem – Ark Feb 02 '18 at 20:40