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!

smci
  • 32,567
  • 20
  • 113
  • 146
Triamus
  • 2,415
  • 5
  • 27
  • 37

4 Answers4

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))
hrbrmstr
  • 77,368
  • 11
  • 139
  • 205
  • Is there any way to have "max_val <- 0" only assigned once rather than in front of every ggplot call? – Triamus Mar 18 '15 at 15:11
  • 2
    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. – hrbrmstr Mar 18 '15 at 19:04
  • I have been looking for this answer for two days now. Thanks. I think the {} comes from magrittr, am I correct in assuming this? – Sagar Dec 02 '21 at 12:53
  • The .} %>% seems only to work if it is on a separate line. Otherwise it doesn't. – Sagar Dec 02 '21 at 12:54
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)
WaltS
  • 5,410
  • 2
  • 18
  • 24
  • 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. – Triamus Mar 18 '15 at 14:44
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)
PeterK
  • 1,185
  • 1
  • 9
  • 23
  • I'm not sure I understand this answer. The idea was to get "x" out of the scale_y_continuous call? – Triamus Mar 18 '15 at 13:45
  • whatever you do to subset x in the call to `arrange()`, use the same subsetting in the call to `max()`. – PeterK Mar 18 '15 at 14:04
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

glensbo
  • 31
  • 1
  • 6