#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
но, возможно, это больше похоже на то, чего вы действительно хотите?
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
Ответ №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
генерируется следующий график: