2

I'm working on a function that creates a complicated ggplot graph. The graph has dozens of annotations both text and rectangular in addition to some categorical data in bars. I'd like to create an option to reverse the x axis in certain situations. So I need to add some logic to flip the axis if that option is turned on. But I'm running into snags because reversing the groupings of the data doesn't flip the annotations (of course). But I want to flip everything around.

Any thoughts on how to do this without boiling the ocean?

library(tidyverse)

mtcars %>%
  mutate( make =  word(rownames(mtcars))) %>%
  group_by(make) %>%
  summarize(wt = sum(wt)) %>%
  head ->
  mt

p <- ggplot(mt, aes(x = make, y = wt)) +
  geom_bar(stat = "identity") +
  annotate(
    "rect",
    xmin = 1.5,
    xmax = 4.5,
    ymin = 4,
    ymax = 7,
    alpha = .5
  )  + 
  annotate("label", x = 3, y = 6, label = "WTF, y'all?") 
p

I find I can't even use scale_x_reverse for some reason:

p + scale_x_reverse() 
#> Error in -x: invalid argument to unary operator

Please note that my reproducible example here is greatly simplified. In practice I have many dozen elements of different type on my graph.

zx8754
  • 52,746
  • 12
  • 114
  • 209
JD Long
  • 59,675
  • 58
  • 202
  • 294

2 Answers2

2

scale_x_reverse is for continuous scale. Here you will need to play with factors and with scale_x_discrete:

library(tidyverse)

mtcars %>%
  mutate( make =  word(rownames(mtcars))) %>%
  group_by(make) %>%
  summarize(wt = sum(wt)) %>%
  head %>% 
  mutate( make = as.factor(make) ) -> # make `make` as a factor
  mt

p <- ggplot(mt, aes(x = make, y = wt)) +
  geom_bar(stat = "identity") +
  annotate(
    "rect",
    xmin = 1.5,
    xmax = 4.5,
    ymin = 4,
    ymax = 7,
    alpha = .5
  )  + 
  annotate("label", x = 3, y = 6, label = "WTF, y'all?") 
p

# reverse used order of factor levels
p + scale_x_discrete(limits = rev(levels(mt$make)))

enter image description here

David Gohel
  • 9,180
  • 2
  • 16
  • 34
  • 1
    Great, this explains how to flip x axis when it is discrete (factor). But now the highlight and label is in the wrong place? – zx8754 Dec 11 '18 at 13:08
  • ah sorry, I did not understood that. Well every annotation is independent from the data so I don't think there is a solution to move the text box/highlight if they are expressed as annotations. – David Gohel Dec 11 '18 at 13:12
  • Related post with your solution is in [one of the answers here](https://stackoverflow.com/questions/28391850), if this is the answer then it is a duplicate. But let's wait for OP to clarify their expected output. – zx8754 Dec 11 '18 at 13:19
  • Yes, reversing the groups without the dozens of annotations is easy. But let's not forget my initial question: "I'm running into snags because reversing the groupings of the data doesn't flip the annotations" – JD Long Dec 11 '18 at 13:55
1

We could make annotation labels and shading part of the input data. Then annotations will reverse together with x-axis ordering. Something like:

library(tidyverse)

# dummy data
mtcars %>%
  mutate(make =  word(rownames(mtcars))) %>%
  group_by(make) %>%
  summarize(wt = sum(wt)) %>%
  head ->
  mt

# Option to reverse, choose one
# if it is a function, pass an argument
# foo <- function(data, myReverseOption = FALSE, ...
myReverseOption = TRUE
myReverseOption = FALSE

mt$make <- as.factor(mt$make)

if(myReverseOption){
  mt$make <- factor(mt$make, levels = rev(levels(mt$make))) }

# add annotaions
mt <- mt %>% 
  mutate(
    myLabel = if_else(make == "Camaro", "OK, y'all?", NA_character_),
    myShade = grepl("^C", make))

# plot
ggplot(mt, aes(x = make, y = wt)) +
  geom_bar(stat = "identity") +
  geom_text(aes(label = myLabel), nudge_y = 1) +
  geom_rect(aes(xmin = (as.numeric(make) - 0.5) * myShade,
                xmax = (as.numeric(make) + 0.5) * myShade,
                ymin = 4, ymax = 6),
            alpha = 0.5) +
  ggtitle(ifelse(myReverseOption, "reversed", "original"))

enter image description here

enter image description here

zx8754
  • 52,746
  • 12
  • 114
  • 209
  • This is a great expansion of my `ggplot` understanding. What's the right wording for this change? Is this right? -- You took the rectangle and text and moved them from the annotation layer to the data layer? I'm not sure the right terms – JD Long Dec 11 '18 at 20:44
  • @JDLong “annotate” is just a wrapper for other layers like: text (geom_text), label (geom_label). – zx8754 Dec 11 '18 at 20:52
  • @ zx8754 yeah, that's what I thought. Then why did they become reversible when you directly called geom_text and geom_rect but when I used the annotate wrapper they were not reversible? what changed? – JD Long Dec 12 '18 at 11:01
  • 1
    @JDLong because your annots are hardcoded (for example: `xmin = 1.5`), mine are within `mutate`, changes based on "myReverseOption" – zx8754 Dec 12 '18 at 11:03