2

I am trying to manually reorder the x-axis labels within each facet.

The data are as follows:

df = structure(list(block = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 
4L, 4L, 4L, 4L, 4L, 5L, 5L, 5L, 5L, 5L, 5L, 5L), .Label = c("1", 
"2", "3", "4", "5"), class = "factor"), item = structure(c(14L, 
15L, 28L, 29L, 30L, 31L, 32L, 15L, 16L, 17L, 18L, 19L, 20L, 21L, 
15L, 22L, 23L, 24L, 25L, 26L, 27L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 
1L, 8L, 9L, 10L, 11L, 12L, 13L), .Label = c("p00e00d00", "p00e00d11", 
"p00e00d12", "p00e00d13", "p00e00d21", "p00e00d22", "p00e00d23", 
"p00e11d00", "p00e12d00", "p00e13d00", "p00e21d00", "p00e22d00", 
"p00e23d00", "p01e00d00", "p11e00d00", "p11e00d11", "p11e00d12", 
"p11e00d13", "p11e00d21", "p11e00d22", "p11e00d23", "p11e11d00", 
"p11e12d00", "p11e13d00", "p11e21d00", "p11e22d00", "p11e23d00", 
"p12e00d00", "p13e00d00", "p14e00d00", "p21e00d00", "p22e00d00"
), class = "factor"), response = structure(c(2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("2", 
"1"), class = "factor"), n = c(345L, 511L, 583L, 613L, 612L, 
222L, 142L, 531L, 546L, 589L, 636L, 478L, 364L, 313L, 502L, 533L, 
587L, 603L, 385L, 298L, 263L, 518L, 546L, 563L, 593L, 435L, 351L, 
310L, 478L, 579L, 629L, 646L, 357L, 307L, 230L), freq = c(0.408284023668639, 
0.604733727810651, 0.689940828402367, 0.725443786982249, 0.724260355029586, 
0.262721893491124, 0.168047337278107, 0.628402366863905, 0.646153846153846, 
0.697041420118343, 0.752662721893491, 0.565680473372781, 0.430769230769231, 
0.370414201183432, 0.594082840236686, 0.630769230769231, 0.694674556213018, 
0.713609467455621, 0.455621301775148, 0.352662721893491, 0.311242603550296, 
0.61301775147929, 0.646153846153846, 0.666272189349112, 0.701775147928994, 
0.514792899408284, 0.415384615384615, 0.366863905325444, 0.565680473372781, 
0.685207100591716, 0.744378698224852, 0.764497041420118, 0.422485207100592, 
0.363313609467456, 0.272189349112426)), class = c("tbl_df", "tbl", 
"data.frame"), row.names = c(NA, -35L), .Names = c("block", "item", 
"response", "n", "freq"))

There are five blocks, each block contains 7 items, and some items have the same names across blocks. I can therefore facet by block as follows:

df %>% 
  ggplot(aes(x = item, y = freq)) + 
  geom_bar(stat = "identity", position = "dodge", color = "black") +
  facet_grid(.~block, scales = "free") + 
  coord_cartesian(ylim = c(0, 1), expand = F) +  # need to add expanse = F to prevent zooming away 
  scale_y_continuous(labels = scales::percent) +
  theme(axis.text.x = element_text(angle=45, hjust=1, vjust=1))

I also have vectors which states for each block the order that items should appear in. For example:

block_3_order = c("p11e13d00","p11e12d00", "p11e11d00", "p11e00d00", "p11e21d00", "p11e22d00","p11e23d00")
             )
block_4_order =  c("p00e00d13", "p00e00d12", "p00e00d11", "p00e00d00", "p00e00d21","p00e00d22","p00e00d23")
             )

I tried to reorder the "item" factor, but to get the desired effect I would need to split the dataframe into subsets representing blocks. Otherwise I am having trouble grasping how you can integrate the ordering of factors with the ggplot treatment of item as a single factor across facets.

Any help is greatly appreciated.

Annie Ito
  • 25
  • 5

1 Answers1

3

To get a different custom axis order in each facet, you can create each "facet" as a separate plot and then lay them out together as if they were a single faceted plot.

library(tidyverse)
#devtools::install_github("baptiste/egg")
library(egg)
library(gridExtra)
library(grid)
theme_set(theme_bw())

First, create the custom orderings. The ones that are NULL will just be sorted alphabetically in the final plot.

b.order = list(b1 = NULL,
               b2 = NULL,
               b3 = c("p11e13d00","p11e12d00", "p11e11d00", "p11e00d00", "p11e21d00", "p11e22d00","p11e23d00"),
               b4 = c("p00e00d13", "p00e00d12", "p00e00d11", "p00e00d00", "p00e00d21","p00e00d22","p00e00d23"),
               b5 = NULL)

Create a list of plots, one for each block. We do this by splitting df by block. To get the custom ordering, we use factor to set the custom order based on the list b.order.

plist = map2(split(df, df$block), b.order,  
     ~ .x %>% group_by(block) %>% 
         mutate(item = factor(item, levels=if(is.null(.y)) sort(unique(item)) else .y)) %>%
       ggplot(aes(x = item, y = freq)) + 
        geom_bar(stat = "identity", position = "dodge", color = "black") +
        facet_grid(.~block, scales = "free") + 
        coord_cartesian(ylim = c(0, 1), expand = F) +  # need to add expanse = F to prevent zooming away 
        scale_y_continuous(labels = scales::percent) +
        theme(axis.text.x = element_text(angle=45, hjust=1, vjust=1),
             plot.margin=margin(b=-5)) +
        labs(x=""))

Remove y-axis labels, title, and ticks from all but the left-most plot:

plist[2:length(plist)] = plist[2:length(plist)] %>% 
  map(~ .x + theme(axis.text.y=element_blank(),
                   axis.title.y=element_blank(),
                   axis.ticks.y=element_blank()))   

Arrange the plots. We use ggarrange from the egg package in order to ensure that the plot panels all have the same horizontal width. We also need to add the Item label beneath the plot. However, ggarrange prints the plot to the output device, even inside arrangeGrob. So we create the object p, clear the device and then redraw the final plot.

p = arrangeGrob(ggarrange(plots=plist, ncol=length(plist)),
                textGrob("Item"), heights=c(20,1))
grid.newpage()
grid.draw(p)

enter image description here

eipi10
  • 91,525
  • 24
  • 209
  • 285
  • This is a fantastic answer and I really appreciate the tips on removing all but the leftmost axis and ggarrange. Thanks! – Annie Ito May 09 '17 at 21:13