Why can't ggplot2 use %>%?

Just saw this making its way around twitter. Thought it would be relevant here.

5 Likes

Packages based on ggplot2 and shiny have grown in numbers. And are scattered throughout the net. Are you ever planning to compile them into one ggverse or shinyverse or something. It would be very very useful though. I don't think it would be hard. But just give it a thought at least please...

My main grievance with + is the weak operator precedence. I have a function that saves plots, which takes the plot as the first argument. It makes it natural to pipe to, but it requires an awkward set of parenthesis starting before the pipe flow and ending after the last ggplot element. For illustration I here use print() instead of the function that saves plots.

# Parentheses needed. Ends after ggtitle()
(mtcars %>% 
    ggplot() +
        aes(x=hp, y=mpg) +
        geom_point() +
        geom_smooth() +
        ggtitle('Fantastic Plot')) %>%
    print()

With a small helper function that nicely groups the ggplot elements together it becomes cleaner.

ggplot_sum <- function(data, ...){
    p <- ggplot(data)
    args = list(...)
    for (arg in args){
        p <- p + arg
    }
    return (p)
}

Which in use makes the following nice syntax possible

mtcars %>% 
    ggplot_sum(
        aes(x=hp, y=mpg),
        geom_point(),
        geom_smooth(),
        ggtitle('Fantastic Plot')
    ) %>%
    print()
1 Like

more simply

ggplot_sum <- function(data, ...){
  ggplot(data) + list(...)
}
5 Likes

True, it does in the sense that layers added later sit "above" (and thus can "hide") layers added earlier. But it still feels like an addition of layers on top of each other rather than a left hand side expression passed to a right hand side one. To me, + makes more sense than %>% for that reason. If the pipe made sense, then %<>% should make sense too. And I really struggle understanding what ggplot(...) %<>% geom_point(...) would mean. Might just be me not being able to wrap my head around something that might make prefect sense to someone else though.

I mean, I can imagine how such code might work with ggplot1 (though I have never tested it). But conceptually, it doesn't feel right to me. Maybe simply because the concept is too novel for me and the + has given me a certain subconscious understanding of how the grammar of graphics works that might not be correct. I would be happy to be corrected by @hadley on all of this.

1 Like

Right. Exactly. That's how I see it too.

1 Like

Another mental model for this is that the operands of the pipe operator are verbs: the pipe passes data from one verb to the next. In contrast, in ggplot2 the functions you add together are components, which are nouns.

That's not to say a pipe-based ggplot couldn't use functions that sound more like verbs (eg. add_geom_*). But they'd basically all be add_*, so I feel like they wouldn't add a heap of semantic meaning.

Fundamentally, a data analysis is a process, which means it's made up of verbs, while a plot is a thing, which means it's most intuitively (at least, IMHO) best described as a series of other things.

EDIT: it's worth noting that plot aesthetics are really a series of relations—but those are nouns too!

3 Likes

Hello, folks. I didn't see this posted here, so I think it might be relevant.

magrittr provides you with functional math operators, such as magrittr::add.

And you can use it to have pipes with ggplot2, such as:

require(ggplot2)
require(magrittr)

ggplot(mtcars, aes(x=hp, y=mpg)) %>%
    add(geom_point()) %>%
    add(geom_smooth()) %>%
    add(ggtitle('Fantastic Plot'))

It's a little bit more verbose, but I think it's nicer than creating custom functions or operators.

11 Likes