3

I'm trying to create a utility function that combines several geom_, like in this example (which doesn't work):

my_geom_y <- function(yy, colour){
  geom_line(aes(y=yy), col=colour) + geom_point(aes(y=yy), col=colour)
}

so that then I can do this:

myX <- 0:90
ggplot(mapping = aes(x=myX)) + my_geom_y(dlnorm(myX), "red") + my_geom_y(dexp(myX), "blue")

Is that possible?
I tried using get(), eval(), substitute(), as.name() with no avail. Looking at related posts: passing parameters to ggplot, Use of ggplot() within another function in R didn't help.

IVIM
  • 2,167
  • 1
  • 15
  • 41
  • Does it work if you include `x` in the aesthetics? I don't think you can draw lines or points with only a mapping for `y`. – Gregor Thomas May 19 '17 at 20:32
  • Thanks to Luke's answer, I see now that this is possible. However the issue is not that I don't include x in aesthetics. The solution is actually two-fold. It looks a bit contre-intuitive, but works: 1) you have to use `list()` to add `geom_`'s, and 2) you need have `data=` argument in `geom_` (i.e. it can't find name `yy` just from the function argument list) - Who would think! I just slightly modified it below so it refers to internal arguments only. – IVIM May 23 '17 at 19:09

3 Answers3

4

I like MSM's approach, but if you want to be able to add my_geom_y to a ggplot you've already made, this is an alternative that might suit what you're after:

library(ggplot2)
x <- 1:100

my_geom_y <- function(yy, colour = "black"){
  list(
    geom_line(mapping = aes(y= yy), 
              col = colour), 
              data = data.frame(x, yy)),
    geom_point(mapping = aes(y = yy), 
               col = colour, 
               data = data.frame(x, yy))
  )
 }

ggplot(mapping = aes(x))  + 
  my_geom_y(x, "red") + 
  my_geom_y(dlnorm(x), "blue") +
  my_geom_y((x^1.1), "black") +
  my_geom_y(x/2, "yellow")

enter image description here

IVIM
  • 2,167
  • 1
  • 15
  • 41
Luke C
  • 10,081
  • 1
  • 14
  • 21
1

I don't have enough reputations to comment so here is a suggestion:

my_geom_y <- function(xx, yy, colour){
    ggplot() + 
    geom_line(aes(x=xx, y=yy), col=colour) + 
    geom_point(aes(x=xx, y=yy), col=colour)
}

This will create one plot. To create multiple ones, you need to pass your inputs to the function as a list and loop through it inside the function for each geom (since we can't add two or more ggplot objects) - if that makes sense.

M_M
  • 899
  • 8
  • 21
0

Based on @luke-c idea, this makes the function standalone, cut-n-paste ready. We can also add now labels to each curve.

my_geom_y <- function(.xx, .yy, yLabel = 1, .colour=NA ){
  if (is.na(.colour)) 
    .colour <- palette()[yLabel%%length(palette())]
  list( geom_line(mapping=aes(.xx,.yy), col=.colour,  data=data.frame(.xx, .yy)), 
        geom_point(mapping=aes(.xx,.yy), col=.colour, data=data.frame(.xx, .yy)),
        annotate(geom="text" , col = .colour, label=deparse(substitute(.yy)),
                 x=mean(.xx),y=max(.yy)-(max(.yy)-min(.yy))/20*yLabel)
        )
}
myX <- 1:10
ggplot() + my_geom_y(myX, dlnorm(myX), 1) + 
           my_geom_y(myX, dexp(myX), 2) + my_geom_y(myX, dexp(myX,0.7), 3)

This function becomes handy when you need to visually compare multiple distributions.

enter image description here

IVIM
  • 2,167
  • 1
  • 15
  • 41