Trying to shade between two lines using geom_ribbon -- Error: Aesthetics must be either length 1 or the same as the data (20): ymin, ymax

Hi there,

EDIT: sorry, I forgot to add one piece of code xstar=0.85

EDIT2: Removed quotations from alpha = "0.5"

I am struggling a little bit with troubleshooting and figuring out how to resolve the issue I am getting when I am particularly trying to add a geom_ribbon to my plot in order to shade between the area of a and b. My plot works fine without the geom_ribbon code but whenever I include it I get the following error:

"Error: Aesthetics must be either length 1 or the same as the data (20): ymin, ymax"


library(ggplot2)
library(magrittr)
library(scales)
library(tidyr)


x1 = c(0.8355500, 0.9195025, 0.8718606)
x2 = c(0.7020640, 0.8643428, 0.8718606)
x3 = c(0.7201364, 0.8718606, 0.8718606)

xstar = 0.85


a = c(0.30000, 0.83555, 0.83555, 0.83555)
b = c(0.9500000, 0.9500000, 0.8718606, 0.8718606)

acc = seq(from = 1, to = (length(x1)), by = 1)

totdat = data.frame(cbind(acc,x1,x2,x3,b,a))

totdat[[1]][(length(a))] = NA
totdat[[2]][(length(a))] = NA
totdat[[3]][(length(a))] = NA
totdat[[4]][(length(a))] = NA
totdat
adjtotdat = pivot_longer(totdat, c(x1,x2,x3,b,a))

adjtotdat

p = ggplot(adjtotdat, aes(x = acc, y = value, color = name))

p + geom_line(size=1) + geom_point(size=2) +
  
geom_ribbon(adjtotdat=subset(acc, 1 <= acc & acc <= (length(x1))), aes(ymin=a,ymax=b), fill="grey", alpha="0.5")+

scale_y_continuous(breaks=seq(0,1,0.1)) +
  
scale_x_continuous(breaks=seq(1,(length(x1)),1)) +
  
geom_hline(aes(yintercept = xstar, linetype ="Ex Ante Court Eff. Effort"), col = "green", size = 1.2)+

scale_linetype_manual(name = "", values = c(2), guide=guide_legend(override.aes = list(color=c("green"))))+
  
  scale_colour_manual(values = c("blue","red","purple","#006633","#336600"), limits = c("x1","x2","x3","b","a"), name="", labels = c("Driver 1", "Driver 2", "Driver 3", "Upper Threshold","Lower Threshold")) +

ggtitle("Evolution of Legal Threshold and Effort Levels", subtitle="One Incomplete Rule with No Cost Uncertainty") + xlab("Accident") + ylab("Effort Level/Legal Threshold") +

 # , scale_fill_discrete(name = "", labels = c("Driver 1", "Driver 2", "Driver 3", "Upper Threshold","Lower Threshold"))

  theme(panel.background = element_rect(fill = "white"),panel.grid.major = element_line(color = "gray"),panel.border = element_rect(colour = "black", fill = NA, size = 2.75)) +

theme(legend.key.size = unit(1,"cm"), legend.text = element_text(color="black",size = 15)) +
  
  theme(plot.title = element_text(size = 30, margin= margin(t = 0, r = 0, b = 10, l = 0),hjust=0.5, face = "bold"), plot.subtitle = element_text(size = 20, margin= margin(t = 5, r = 0, b = 10, l = 0),hjust=0.5),plot.margin = unit(c(0.5,0.5,0.5,0.5),"cm"), axis.text.y.left = element_text(size = 15, color = "black", margin = margin(t=0,r=5,b=0,l=0)), axis.title.y.left = element_text(size = 20, margin = margin(t = 0, r = 20, b = 0, l = 0)),axis.text.x = element_text(size = 15, color = "black", margin = margin(t=5,r=0,b=0,l=0)), axis.title.x.bottom = element_text(size = 20,margin = margin(t = 18, r = 0, b = 0, l = 0)))

Any suggestions or recommendations are welcome, thank you.

What happens if you execute just these lines:

p = ggplot(adjtotdat, aes(x = acc, y = value, color = name))

p + geom_line(size=1) + geom_point(size=2) +
  
geom_ribbon(adjtotdat=subset(acc, 1 <= acc & acc <= (length(x1))), aes(ymin=a,ymax=b), fill="grey", alpha="0.5")

Same error it seems! "Error: Aesthetics must be either length 1 or the same as the data (20): ymin, ymax"

Could you post the complete console output you get? I'd be surprised if that was all you get.

Not sure if this is what you would like, but I also included the "Tracebook" below the console.

> p = ggplot(adjtotdat, aes(x = acc, y = value, color = name))
> 
> p + geom_line(size=1) + geom_point(size=2)+
+ 
+ geom_ribbon(adjtotdat=subset(acc, 1 <= acc & acc <= (length(x1))),aes(ymin=a,ymax=b), fill="grey", alpha="0.5")
Ignoring unknown parameters: adjtotdatError: Aesthetics must be either length 1 or the same as the data (20): ymin, ymax


Tracebook
Error: Aesthetics must be either length 1 or the same as the data (20): ymin, ymax
10. stop("Aesthetics must be either length 1 or the same as the data (", n, "): ", paste(names(which(!good)), collapse = ", "), call. = FALSE)
9. check_aesthetics(evaled, n)
8. f(..., self = self)
7. l$compute_aesthetics(d, plot)
6. f(l = layers[[i]], d = data[[i]])
5. by_layer(function(l, d) l$compute_aesthetics(d, plot))
4. ggplot_build.ggplot(x)
3. ggplot_build(x)
2. print.ggplot(x)
1. (function (x, ...) UseMethod("print"))(x)

This is the first piece of information to deal with.

From here:

+ geom_ribbon(adjtotdat=subset(acc, 1 <= acc & acc <= (length(x1))),aes(ymin=a,ymax=b), fill="grey", alpha="0.5") 
Ignoring unknown parameters: adjtotdatError: Aesthetics must be either length 1 or the same as the data (20): ymin, ymax

you can see it's referring to your first argument to geom_ribbon(), and is telling you adjtotdat is being interpreted as the name of a geom_ribbon() parameter, which is unknown.

What was your purpose in including it?

My understanding was that it would serve to restrict the x-axis as necessary to limit the shaded area to certain spaces. Its not completely necessary however. When I remove it, I get the same error.

> p = ggplot(adjtotdat, aes(x = acc, y = value, color = name))
> 
> p + geom_line(size=1) + geom_point(size=2) + annotate(geom = "text",x = length(x1), y= min(c(a)), label = "Lower Legal Threshold")+ annotate(geom = "text",x = length(x1), y= min(c(b)), label = "Upper Legal Threshold")+
+   
+ geom_ribbon(aes(ymin=a,ymax=b), fill="grey", color = "grey", alpha="0.5")
Error: Aesthetics must be either length 1 or the same as the data (20): ymin, ymax
> 
>

Every instruction to render visual object, like geom_ribbon(), relies on access to a table of data to plot. If you pass the data in adjtotdat to the ggplot() call, it automatically gets used by the geom_ribbon() call (and has 20 rows).

The aes() call adds new columns to this table, so these new columns, ymax and ymin need to be of the same length, too, or need to created from a single (length 1) value that's used to fill up the new column. By specifying ymin = a, you're asking the column to be built from the object a, which you already built to be of length 4 early in your original code.

However, your code does plot a(n empty) ribbon with a top line at the first three values of b and a bottom line at the first three values of a -- along with a line each for the names x1, x2, and x3.

Did you simply want to fill that empty ribbon?

I see, thank you for the explanation and your patience. And yes, I would like to fill in that ribbon, but I don't want it to be inclusive of objects x1,x2,x3 in principle. This is one particular sample of data points that I have drawn and in other samples it is possible for the values of x1, x2 or x3 to fall outside of a and b and that's why in those instances I primarily wish to code it such that only between a and b is there shading...

OK, in that case, here is a suggestion, obtained from simplifying and modifying your original code:

library(tidyverse)

a = c(0.30000, 0.83555, 0.83555, 0.83555)
b = c(0.9500000, 0.9500000, 0.8718606, 0.8718606)

totdat <- 
  tibble(
    x1 = c(0.8355500, 0.9195025, 0.8718606),
    x2 = c(0.7020640, 0.8643428, 0.8718606),
    x3 = c(0.7201364, 0.8718606, 0.8718606),
    acc = 1:length(x1),
    a = a[acc],
    b = b[acc]
  )
totdat
#> # A tibble: 3 x 6
#>      x1    x2    x3   acc     a     b
#>   <dbl> <dbl> <dbl> <int> <dbl> <dbl>
#> 1 0.836 0.702 0.720     1 0.3   0.95 
#> 2 0.920 0.864 0.872     2 0.836 0.95 
#> 3 0.872 0.872 0.872     3 0.836 0.872

adjtotdat = pivot_longer(totdat, c(x1,x2,x3))

adjtotdat
#> # A tibble: 9 x 5
#>     acc     a     b name  value
#>   <int> <dbl> <dbl> <chr> <dbl>
#> 1     1 0.3   0.95  x1    0.836
#> 2     1 0.3   0.95  x2    0.702
#> 3     1 0.3   0.95  x3    0.720
#> 4     2 0.836 0.95  x1    0.920
#> 5     2 0.836 0.95  x2    0.864
#> 6     2 0.836 0.95  x3    0.872
#> 7     3 0.836 0.872 x1    0.872
#> 8     3 0.836 0.872 x2    0.872
#> 9     3 0.836 0.872 x3    0.872

p <- ggplot(adjtotdat, aes(x = acc, y = value)) # only x and y are reused
p + geom_line(aes(color = name), size=1) + geom_point(size=2) +
  geom_ribbon(aes(ymin=a,ymax=b), fill="grey", alpha= 0.5)

Created on 2020-03-27 by the reprex package (v0.3.0)

Is that closer to what you were looking for?

1 Like

This looks promising! I personally would like to include the a and b lines as well but maybe I can play around with this.

Just wondering what is the tibble function doing exactly? Just a quick google search looks like it is reorganizing the data frame?

I should add that I have made a slight error as well in my original code, posted above, sorry. Only x1,x2,x3 should have their lengths be shorter than a and b. In other words. The last points that are plotted are a and b. Like so it looks like this! (With in between a and b shaded.

All resolved!! Thank you for your help

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.