I wanted to make a beautiful graph with a fading shadow in ggplot2.

This code works fine:

# библиотека library(ggplot2) # Создадим данные huron <- data.frame(year = 1875:1972, level = as.vector(LakeHuron)) m <- 1500 #Обратная ширина полосы #Базовый график h <- ggplot(huron, aes(year))+geom_line(aes(x=year, y=level), color='blue')+theme_bw() # График с 10 полосами тени h + geom_ribbon(aes(ymin=level-(level/m)*1, ymax=level), alpha=0.1, fill='blue')+ geom_ribbon(aes(ymin=level-(level/m)*2, ymax=level-(level/m)*1), alpha=0.09, fill='blue')+ geom_ribbon(aes(ymin=level-(level/m)*3, ymax=level-(level/m)*2), alpha=0.08, fill='blue')+ geom_ribbon(aes(ymin=level-(level/m)*4, ymax=level-(level/m)*3), alpha=0.07, fill='blue')+ geom_ribbon(aes(ymin=level-(level/m)*5, ymax=level-(level/m)*4), alpha=0.06, fill='blue')+ geom_ribbon(aes(ymin=level-(level/m)*6, ymax=level-(level/m)*5), alpha=0.05, fill='blue')+ geom_ribbon(aes(ymin=level-(level/m)*7, ymax=level-(level/m)*6), alpha=0.04, fill='blue')+ geom_ribbon(aes(ymin=level-(level/m)*8, ymax=level-(level/m)*7), alpha=0.03, fill='blue')+ geom_ribbon(aes(ymin=level-(level/m)*9, ymax=level-(level/m)*8), alpha=0.02, fill='blue')+ geom_ribbon(aes(ymin=level-(level/m)*10, ymax=level-(level/m)*9), alpha=0.01, fill='blue') 

Yeah, I thought. I will do the function and will draw beautiful graphics everywhere. But it was not there. When in a cycle you try to add this geom_ribbon to the chart - something goes wrong. Here, I tried just a cycle for now, without making out the procedure:

 count <- 5 # количество разбиений start_alpha <- 0.1 # начальная прозрачность p <- h for (i in 0:(count-1)) { p <- p + geom_ribbon(aes(ymin=level-(level/m)*i, ymax=level-(level/m)*(i+1)), alpha=start_alpha-(start_alpha/count)*i, fill='blue') } print(p) 

Long thought, looked sheet (p) which is generated in a cycle. It seems that all the layers are actually created, but the variable i, as it is, is not used by value, but remains a link, at each iteration of the loop.

Here is an example from which it can be seen:

 i <- 0 print(p) i <- 1 print(p) 

How can you defeat this problem?

UPD. Tried aes_string. Did not help. I tried this:

 geom_ribbon(aes_string(ymin="level-(level/m)*i", ymax="level-(level/m)*(i+1)"), alpha=0.05, fill='blue') 
  • aes_string try. - Artem Klevtsov
  • Did not help. The result is the same - Yury Arrow

2 answers 2

As suggested in the comments, you need to use aes_string() . However, the level variable is not visible in the loop, so you need to apply directly.

 p <- ggplot(huron, aes(year)) + geom_line(aes(x = year, y = level), color = 'blue') + theme_bw() for (i in 0:(count - 1)) { p <- p + geom_ribbon(aes_string( ymin = p$data$level - (p$data$level / m) * i, ymax=p$data$level - (p$data$level / m) * (i + 1)), alpha = start_alpha - (start_alpha / count) * i, fill = 'blue') } print(p) 

enter image description here

    The main idea for your case is to form a text string with a fragment of the necessary code, which you will later execute. Below is the working code based on your example:

     # Функция создает строковую переменную, которая в дальнейшем исполняется # max.count - количество разбиений # width - обратная ширина полосы # start.transparence - начальная прозрачность Creater.Command.String <- function (max.count, width, start.transparence){ rslt.strng = "" #создаем строку for (i in 1:max.count){ # rslt.strng <- paste(rslt.strng, "+", i) rslt.strng = paste(rslt.strng, "+", "geom_ribbon(aes(ymin=level-(level/m)*", i, ", ymax=level), alpha=", start.transparence*i, ", fill='blue')") } return (rslt.strng) } # библиотека library(ggplot2) # Создадим данные huron <- data.frame(year = 1875:1972, level = as.vector(LakeHuron)) m <- 1500 #Обратная ширина полосы #Базовый график h <- ggplot(huron, aes(year))+geom_line(aes(x=year, y=level), color='blue')+theme_bw() # формируем строку для выполнения run.string <- Creater.Command.String(15, m, 0.01) # дополняем переменной, содержащей Базовый график run.string <- paste("h", run.string) # print (run.string) # смотрим получившийся результат # выполняем код в переменной run.string eval(parse(text = run.string)) 

    Further improvement of the function code: add the Baseline, execution directly in the function