BrodieG
BrodieG

Reputation: 52667

Generate a Filled geom_step

I can get a "filled" geom_line with either geom_ribbon or geom_area. Is there an equivalent for geom_step that doesn't require messing with polygons/barplots or creating the actual step points? Here is some sample data:

library(ggplot2)
set.seed(1)
df <- data.frame(
  x=rep(sort(sample(1:20, 5)), 3), 
  y=ave(runif(15), rep(1:3, each=5), FUN=cumsum),
  grp=letters[rep(1:3, each=5)]
)
ggplot(df, aes(x=x, y=y, color=grp)) + geom_step(position="stack")

Which produces:

enter image description here

Basically, I want exactly the same thing, but with filled areas. I know how to do this by actually creating the x/y values required for the steps and using geom_area, but I'm hoping there is something simpler.

Upvotes: 18

Views: 7763

Answers (3)

Allan Cameron
Allan Cameron

Reputation: 174278

We can emulate the way geom_step calculates the x and y positions internally using unexported ggplot2 functions:

ggplot(ggplot2:::dapply(df, 'grp', ggplot2:::stairstep), aes(x, y, fill = grp)) + 
  geom_area(position = "stack")

enter image description here

Upvotes: 3

Tobias Hotzenplotz
Tobias Hotzenplotz

Reputation: 1217

I know the question is a few years old, but I had the same problem today. For reference here's my solution. It's not more concise than the original answer, but may be easier to understand for some.

library(ggplot2)
library(dplyr)

df <- data.frame(x = seq(10), y = sample(10))

df_areaStep <- bind_rows(old = df, 
                         new = df %>% mutate(y = lag(y)),
                         .id = "source") %>%
               arrange(x, source)

ggplot(df, aes(x,y)) + 
  geom_ribbon(aes(x = x, ymin = 0, ymax = y), data = df_areaStep)

See this gist for longer version with comments.

Upvotes: 14

BrodieG
BrodieG

Reputation: 52667

Here is the answer I was thinking of, for reference, but I'm hoping for something simpler/built-in if possible:

df2 <- rbind(
  df,
  transform(df[order(df$x),],
    x=x - 1e-9,  # required to avoid crazy steps
    y=ave(y, grp, FUN=function(z) c(z[[1]], head(z, -1L)))
) )
ggplot(df2, aes(x=x, y=y, fill=grp)) + geom_area()

enter image description here

Upvotes: 12

Related Questions