Dynamic ylim in ggplot2 using dplyr pipe
Asked Answered
H

4

8

I want to create dynamic ylim values in a ggplot so that the ylim parameter is referencing to the value that dplyr is providing via a pipe. To illustrate the problem, please see a working (non-generic) code that I want to change into a (currently not working generic) code.

require(dplyr)
require(scales)
require(ggplot2)

x <- data.frame(name = c("A","B","C"), 
                value = c(2,4,6))

working non-generic code:

arrange(x[1:2, ], value) %>%
  ggplot(data=., aes(x=factor(name), y=value)) + 
  geom_bar(stat="identity") +
  scale_y_continuous(labels=comma, 
                     limits=c(0,max(arrange(x[1:2, ], value)$value) * 1.1))

not working generic code (call does not find value):

arrange(x[1:2, ], value) %>%
  ggplot(data=., aes(x=factor(name), y=value)) + 
  geom_bar(stat="identity") +
  scale_y_continuous(labels=comma, 
                     limits=c(0,max(value) * 1.1))

So the question is if there is any way to set the limits generally i.e. the part after the arrange will always be the same (I need to produce a lot of the same graphs with differing x i.e. different limits). Thanks!

Hindi answered 18/3, 2015 at 12:24 Comment(0)
A
3

You could plot a dummy point with zero size at your limit values. This isn't an especially pretty solution but it does seem to be fairly flexible. Code would look like

arrange(x[1:2, ], value) %>%
  ggplot(data=., aes(x=factor(name), y=value)) + 
  geom_bar(stat="identity") +
  geom_point(aes(x=c(name[1], name[1]), y = c(0, max(value)*1.1)), size=0) +
  scale_y_continuous(labels=comma)
Atrip answered 18/3, 2015 at 13:49 Comment(1)
That is a nice workaround although I haven't thought about any drawbacks yet. One thing I am still struggling with in this solution is that my tables do not always have a column called "name". It will always be something different e.g. name1, name2, etc.Hindi
A
8

If you can live with using <<- and also don't mind using one additional variable, the following will preserve the pipeline and give you a dynamic ylim:

max_val <- 0
arrange(x[1:2, ], value) %>%
{ max_val <<- max(.$value) 
. } %>% 
  ggplot(data=., aes(x=factor(name), y=value)) + 
  geom_bar(stat="identity") +
  scale_y_continuous(labels=comma, 
                     limits=c(0, max_val * 1.1))
Aliunde answered 18/3, 2015 at 12:48 Comment(4)
Is there any way to have "max_val <- 0" only assigned once rather than in front of every ggplot call?Hindi
Aye. If you define it near the top of your script it'll be in the namespace/environment (which is all that really matters for <<- to work), then each time the {} block is executed in any pipe it'll just assign into that scoped variable. No need to do the <- 0 every time.Aliunde
I have been looking for this answer for two days now. Thanks. I think the {} comes from magrittr, am I correct in assuming this?Karriekarry
The .} %>% seems only to work if it is on a separate line. Otherwise it doesn't.Karriekarry
A
3

You could plot a dummy point with zero size at your limit values. This isn't an especially pretty solution but it does seem to be fairly flexible. Code would look like

arrange(x[1:2, ], value) %>%
  ggplot(data=., aes(x=factor(name), y=value)) + 
  geom_bar(stat="identity") +
  geom_point(aes(x=c(name[1], name[1]), y = c(0, max(value)*1.1)), size=0) +
  scale_y_continuous(labels=comma)
Atrip answered 18/3, 2015 at 13:49 Comment(1)
That is a nice workaround although I haven't thought about any drawbacks yet. One thing I am still struggling with in this solution is that my tables do not always have a column called "name". It will always be something different e.g. name1, name2, etc.Hindi
B
0

If you call max(x$value[1,2]) you can avoid making ggplot work to parse the arg to max(). Also your code doesn't explain comma so I've left it out of the answer.

arrange(x[1:2, ], value) %>%     
    ggplot(data=., aes(x=factor(name), y=value)) + 
    geom_bar(stat="identity") +
    scale_y_continuous(limits=c(0,max(x$value[1:2])) * 1.1)
Bohemian answered 18/3, 2015 at 12:49 Comment(2)
I'm not sure I understand this answer. The idea was to get "x" out of the scale_y_continuous call?Hindi
whatever you do to subset x in the call to arrange(), use the same subsetting in the call to max().Bohemian
P
0

Tried these two solutions

arrange(x[1:3, ], value) %>%
    ggplot(data=.,
           aes(x=factor(name),
               y=value)) +
    geom_bar(stat="identity") +
    scale_y_continuous()
arrange(x[1:2, ], value) %>%
    ggplot(data=., aes(x=factor(name), y=value)) +
    geom_bar(stat="identity") +
    geom_point(aes(x=c(name[1], name[1]), y = c(0, max(value)*1.1)), size=0) +
    scale_y_continuous()

Seem as if it adjust (automatically)? Seems as if it adjust to limits?

The original from code two The original target

Ponderous answered 1/1, 2022 at 14:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.