условие if else в ggplot для добавления дополнительного слоя

#r #if-statement #ggplot2

#r #if-оператор #ggplot2

Вопрос:

допустим, я хочу построить два слоя в ggplot, один из которых содержит точки, а другой — линии, если выполняются определенные критерии.

Код без критериев может выглядеть следующим образом:

 library("ggplot2")

# Summarise number of movie ratings by year of movie
mry <- do.call(rbind, by(movies, round(movies$rating), function(df) {
  nums <- tapply(df$length, df$year, length)
  data.frame(rating=round(df$rating[1]), year = as.numeric(names(nums)), number=as.vector(nums))
}))

p <- ggplot(mry, aes(x=year, y=number, group=rating))

p   
geom_point() 
geom_line()
  

теперь условием для построения точек, а не только линий, будет то, что объект с именем tmp.data не равен выражению «нет значения».

 tmp.data<-c(1,2,3) # in this case the condition is fulfilled

# attempt to plot the two layers including the condition in the plotting function
p  
  if(tmp.data[1]!="no value"){ geom_point() }
  geom_line()
  

сбой….

 Error: unexpected '}' in:
"p  
if(tmp.data[1]!="no value"){ geom_point() }"
  

geom_line()
геометрическая линия:

stat_identity:
position_identity: (width = NULL, height = NULL)

Комментарии:

1. Почему бы просто не изменить порядок: p geom_line() if(tmp.data[1]!="no value"){ geom_point()}

2. @shadow. это работает, только если мой второй слой является последним аргументом в функции. если я добавлю дополнительные аргументы, такие как: theme(panel.background = element_rect(fill = "lightskyblue2")) это больше не работает

Ответ №1:

Это было сделано с использованием ggplot2 2.1.0. Я думаю, вы можете сделать именно то, что пожелал OP, просто переключив скобки так, чтобы они охватывали весь if оператор.

Вот пример, который добавляет горизонтальную линию в зависимости от того, Swtich является T или F . Во-первых, где условие равно TRUE

 library(ggplot2)

df<-data.frame(x=1:10,y=11:20)
Switch=T

ggplot(df,aes(x,y)) 
{if(Switch)geom_hline(yintercept=15)} 
  geom_point()
  

введите описание изображения здесь

Теперь то же самое, но условие FALSE

 df<-data.frame(x=1:10,y=11:20)
Switch=F

ggplot(df,aes(x,y)) 
{if(Switch)geom_hline(yintercept=15)} 
  geom_point()
  

введите описание изображения здесь

Комментарии:

1. кажется, что вы не можете использовать внутри { , поэтому, если вы хотите условно добавить несколько объектов в ggplot, я полагаю, вам нужно добавить еще один if оператор (внутри его собственного { ) для каждого объекта, который вы добавляете к графику.

2. Вы не можете использовать внутри { , но вы можете поместить все в list , если у вас есть несколько шагов. {if(Switch)list(geom_hline(yintercept=15), geom_hline(yintercept = 13))}

3. @StephenK за миллион лет я бы никогда интуитивно не догадался, что это правильный способ выполнить несколько шагов внутри {} , но, к счастью, я смог найти ваш комментарий!

Ответ №2:

То, что вы видите, является синтаксической ошибкой. Самый надежный способ, который я могу придумать, это:

 tmp.data<-c(1,2,3) 
if(tmp.data[1]!="no value") {
   p = p   geom_point()
}
p   geom_line()
  

Таким образом, вы создаете объект p в последовательности, добавляя только geom_point() тогда, когда инструкции if дают результат TRUE .

Комментарии:

1. это решение не работает, если есть попытка facet_wrap. Я получаю сообщение об ошибке: Ошибка в последовательности.по умолчанию (min, max, by = by): ‘from’ должно быть конечным числом

Ответ №3:

Следуя книге ggplot2, вы можете создать функцию, которая возвращает список. Любые нулевые компоненты будут проигнорированы.

 library(ggplot2)
library(ggplot2movies)

# Summarise number of movie ratings by year of movie
mry <- do.call(rbind, by(movies, round(movies$rating), function(df) {
    nums <- tapply(df$length, df$year, length)
    data.frame(rating=round(df$rating[1]), year = as.numeric(names(nums)), number=as.vector(nums))
}))

# create function to add points conditionally
# If the list contains any NULL elements, they’re ignored. 
my_plot <- function(point = FALSE){
    list(
        geom_line(),
        if (point) 
            geom_point()
    )

}

p <- ggplot(mry, aes(x=year, y=number, group=rating))
p   my_plot()
  

 p   my_plot(point = TRUE)
  

Создано 2020-02-25 пакетом reprex (версия 0.3.0)

Ответ №4:

 library(ggplot2)

# Summarise number of movie ratings by year of movie
mry <- do.call(rbind, by(movies, round(movies$rating), function(df) {
  nums <- tapply(df$length, df$year, length)
  data.frame(rating=round(df$rating[1]), year = as.numeric(names(nums)), number=as.vector(nums))
}))

tmp.data<-c(1,2,3) # in this case the condition is fulfilled

p <- ggplot(mry, aes(x=year, y=number, group=rating))

# this won't "loop through" the data points but it's what you asked for
if (tmp.data[1]!="no value") {
  p <- p   geom_point()   geom_line()
} else {
  p <- p   geom_line()
}
p
  

g1

но, возможно, это больше похоже на то, чего вы действительно хотите?

 mry$rating <- factor(mry$rating)
p <- ggplot(mry, aes(x=year, y=number, group=rating))
p <- p   geom_line()
p <- p   geom_point(data=mry[!(mry$rating %in% tmp.data),], 
                    aes(x=year, y=number, group=rating, color=rating), size=2)
p <- p   scale_color_brewer()
p
  

g2

Ответ №5:

Альтернативный пример, использующий iris dataset для создания графика с условными компонентами, некоторые из которых содержат более одной строки и с несколькими переключателями.

 library("ggplot2")

p <- ggplot(iris, 
            aes(x=Sepal.Length, 
                y=Sepal.Width, 
                colour=Species))

# set plot switches to turn on or off various components
include_points = TRUE
include_lines = FALSE
include_density = TRUE
include_facet = TRUE

p   
  list(
    if(include_points){geom_point()},
    if(include_lines){geom_line()},
    if(include_facet){
      
      # multi-line conditional elements can be included as a list
      list(
        facet_grid(rows = "Species"),
        labs(subtitle = "This plot has been faceted, and colour has been removed"),
        aes(colour = NULL)
      )
      
    },
    if(include_density){geom_density2d()})  
  
  # additional elements common to all possible conditional combinations
  # can be added as well
  theme_minimal()   
  labs(title = "Plot with conditional elements")
  

При выполнении следующих условий:

 include_points = TRUE
include_lines = FALSE
include_density = TRUE
include_facet = TRUE
  

Генерируется следующий график:

Фасетный график с плотностью и точками

Настройка include_facet = FALSE генерируется следующий график:

Цветной график с плотностью — без граней