В настоящее время я работаю над приложением Rshiny. Мне пришлось сделать несколько диаграмм с несколькими выбранными входами и флажком. Я почти закончил свою задачу, и теперь мне просто нужно сделать так, чтобы каждый раз, когда я меняю выбранный вид, масштаб оставался прежним (если, конечно, не были введены другие переменные).
Мой код выглядит так:
library(shiny)
library(palmerpenguins)
library(dplyr)
library(ggplot2)
data <- na.omit(penguins)
colnames(data) <- c("Species",
"Island",
"Bill Length (mm)",
"Bill Depth (mm)",
"Flipper Length (mm)",
"Body Mass (g)",
"Sex",
"Year")
data.numeric <- data[, c(3:6, 8)]
data.categorical <- data[, c(1,7)]
ui <- fluidPage(
headerPanel("Penguin boxplots"),
selectInput("ycol",
"Numeric Variable",
names(data.numeric),
selected = names(data.numeric)[3]),
selectInput("xcol",
"Categorical Variable",
names(data.categorical),
selected = names(data.categorical)[2]),
checkboxInput("split",
"Split levels by Island",
value = FALSE),
selectInput("species",
"Species Type",
c("Unspecified", levels(data$Species))),
mainPanel(
plotOutput("plot1")
))
# 4. Use a select input to allow the user to view separate plotting
# panels for each species, with each plot panel on the same scale.
server <- function(input, output){
output$plot1 <- renderPlot({
par(mar = c(5, 4.1, 0, 1))
if (input$species == "Unspecified"){
if (input$split) {
ggplot(data, aes(x = data[[input$xcol]], y = data[[input$ycol]], fill = Island)) +
geom_boxplot(na.rm = TRUE) +
if (input$ycol == "Bill Length (mm)"){
coord_cartesian(ylim = c(30, 60))
} else if (input$ycol == "Bill Depth (mm)"){
coord_cartesian(ylim = c(12.5, 21.5))
} else if (input$ycol == "Flipper Length(mm)"){
coord_cartesian(ylim = c(170, 232))
} else if (input$ycol == "Body Mass (g)"){
coord_cartesian(ylim = c(2500, 6500))
} else if (input$ycol == "Year"){
coord_cartesian(ylim = c(2006, 2009))
} +
xlab(input$xcol) +
ylab(input$ycol) +
scale_x_discrete(labels = c("Female", "Male")) +
theme(text = element_text(size = 15))
} else {
ggplot(data, aes(x = data[[input$xcol]], y = data[[input$ycol]])) +
geom_boxplot(na.rm = TRUE) +
if (input$ycol == "Bill Length (mm)"){
coord_cartesian(ylim = c(30, 60))
} else if (input$ycol == "Bill Depth (mm)"){
coord_cartesian(ylim = c(12.5, 21.5))
} else if (input$ycol == "Flipper Length(mm)"){
coord_cartesian(ylim = c(170, 232))
} else if (input$ycol == "Body Mass (g)"){
coord_cartesian(ylim = c(2500, 6500))
} else if (input$ycol == "Year"){
coord_cartesian(ylim = c(2006, 2009))
} +
xlab(input$xcol) +
ylab(input$ycol) +
theme(text = element_text(size = 15))
}
} else {
data <- data %>%
filter(data$Species == input$species)
if (input$split) {
ggplot(data, aes(x = data[[input$xcol]], y = data[[input$ycol]], fill = Island)) +
geom_boxplot(na.rm = TRUE) +
xlab(input$xcol) +
ylab(input$ycol) +
scale_x_discrete(labels = c("Female", "Male")) +
theme(text = element_text(size = 15))
} else {
ggplot(data, aes(x = data[[input$xcol]], y = data[[input$ycol]])) +
geom_boxplot(na.rm = TRUE) +
xlab(input$xcol) +
ylab(input$ycol) +
theme(text = element_text(size = 15))
}
}
})
}
shinyApp(ui = ui, server = server)
Проблема возникает, когда я запускаю строки, содержащие else if (input$ycol == "Year"){ coord_cartesian(ylim = c(2006, 2009))}
, когда я получаю следующую ошибку: Невозможно добавить объекты ggproto вместе. Вы забыли добавить этот объект в объект ggplot?
Я не уверен, где я ошибаюсь, или я просто пропускаю какую-то синтаксическую ошибку.
p.s. Код не закончен — мне все еще нужно добавить код для управления масштабами, когда вид не является «неуказанным», но я не буду этого делать, пока не выясню это.
Видите ли, я думал об этом раньше и пробовал, но это не сработало. Я снова изменил его на это, и он все еще не работает. Все равно пишет ту же ошибку. Вот строка кода: else { coord_cartesian(ylim = c(2006, 2009))}
Вы можете упростить ситуацию, создав функцию, которая возвращает желаемое выражение coord_cartesian
. Затем функцию можно добавить в цепочку ggplot с помощью +
, как в обычном рабочем процессе ggplot.
В приведенном ниже примере используются жестко запрограммированные варианты из вашего примера. Однако, если вы можете предоставить больше информации о том, как выбираются эти диапазоны, можно получить диапазон y более автоматизированным способом, вместо того, чтобы явно жестко запрограммировать каждый возможный случай.
В приведенном ниже примере оператор case_when
возвращает соответствующие значения ylim
для передачи в coord_cartesian
. Если input$ycol
не соответствует ни одному из параметров, case_when
вернет ylim=c(NA,NA)
, что приведет к тому, что ggplot сохранит диапазон осей по умолчанию.
# I've included only 3 choices. Add in as many additional choices as needed.
coord_fnc = function(x=input$ycol) {
ylim = dplyr::case_when(
x= = "Bill Length (mm)" ~ c(30,60),
x= = "Flipper Length(mm)" ~ c(170, 232),
x= = "Bill Depth (mm)" ~ c(12.5,21.5)
)
coord_cartesian(ylim=ylim)
}
ggplot(data, aes(x = data[[input$xcol]], y = data[[input$ycol]], fill = Island)) +
geom_boxplot(na.rm = TRUE) +
coord_fnc() +
xlab(input$xcol) +
ylab(input$ycol) +
theme(text = element_text(size = 15))
Попробуйте это со встроенным фреймом данных mtcars
:
ggplot(mtcars, aes(hp, mpg)) +
geom_point() +
coord_fnc("Bill Length (mm)")
Хотя строка операторов if else
занимает много кода, этот подход может работать, и я не уверен, почему вы получаете сообщение об ошибке (это может быть какая-то другая часть кода). Например, это работает:
input = list(ycol = "Year")
ggplot(mtcars, aes(hp, mpg)) +
geom_point() +
if (input$ycol == "Bill Length (mm)"){
coord_cartesian(ylim = c(30, 60))
} else if (input$ycol == "Bill Depth (mm)"){
coord_cartesian(ylim = c(12.5, 21.5))
} else if (input$ycol == "Flipper Length(mm)"){
coord_cartesian(ylim = c(170, 232))
} else if (input$ycol == "Body Mass (g)"){
coord_cartesian(ylim = c(2500, 6500))
} else if (input$ycol == "Year"){
coord_cartesian(ylim = c(2006, 2009))
}
Попробуйте просто
else
в последнем операторе ggplot вместоif else
.