В моем приложении R Shiny есть два textAreaInput(), один для значений x, а другой для значений y. При нажатии кнопки подгоняется простая модель линейной регрессии, и результаты печатаются на основной панели. Это прекрасно работает.
Я пытаюсь проверить textAreaInput(), чтобы показать сообщение об ошибке
--- когда длина(x) != длина(y)
--- когда поля x или y пусты
--- когда поля x или y содержат недостаточно значений (менее двух пар данных)
--- когда поля x или y содержат NA или недопустимые символы
Вот минимальный репрекс-код. Я вижу, что проверки Shiny для вышеуказанных требований не отображаются должным образом на mainPanel, когда условия соблюдены. ИЗМЕНЕННЫЙ КОД НИЖЕ: Сделал код репрекса минимальным и удалил все reactive(), как советовали.
library(shiny)
library(shinythemes)
library(shinyjs)
library(shinyvalidate)
ui <- fluidPage(theme = bs_theme(version = 4, bootswatch = "minty"),
navbarPage(title = div(span("Simple Linear Regression", style = "color:#000000; font-weight:bold; font-size:18pt")),
tabPanel(title = "",
sidebarLayout(
sidebarPanel(
shinyjs::useShinyjs(),
id = "sideBar",
textAreaInput("x", label = strong("x (Independent Variable)"), value = "87, 92, 100, 103, 107, 110, 112, 127", placeholder = "Enter values separated by a comma with decimals as points", rows = 3),
textAreaInput("y", label = strong("y (Dependent Variable)"), value = "39, 47, 60, 50, 60, 65, 115, 118", placeholder = "Enter values separated by a comma with decimals as points", rows = 3),
actionButton(inputId = "goRegression", label = "Calculate",
style = "color: #fff; background-color: #337ab7; border-color: #2e6da4"),
actionButton("resetAllRC", label = "Reset Values",
style = "color: #fff; background-color: #337ab7; border-color: #2e6da4"), #, onclick = "history.go(0)"
),
mainPanel(
div(id = "RegCorMP",
textOutput("xArray"),
textOutput("yArray"),
textOutput("arrayLengths"),
verbatimTextOutput("linearRegression"),
) # RegCorMP
) # mainPanel
) # sidebarLayout
)
)
)
server <- function(input, output) {
# Data validation
iv <- InputValidator$new()
iv$add_rule("x", sv_required())
iv$add_rule("y", sv_required())
iv$enable()
# String List to Numeric List
createNumLst <- function(text) {
text <- gsub("","", text)
split <- strsplit(text, ",", fixed = FALSE)[[1]]
as.numeric(split)
}
observeEvent(input$goRegression, {
datx <- createNumLst(input$x)
daty <- createNumLst(input$y)
if (length(datx)<2){
output$xArray <- renderPrint({
"Not enough x values"
})
}
else if (length(daty)<2){
output$yArray <- renderPrint({
"Not enough y values"
})
}
if (length(datx) != length(daty)) {
print(length(datx))
print(length(daty))
output$arrayLengths <- renderPrint({
"Length of x and length of y must be the same"
})
}
else if (length(datx) == length(daty)) {
output$linearRegression <- renderPrint({
summary(lm(daty ~ datx))
})
}
})
observeEvent(input$goRegression, {
show(id = "RegCorMP")
})
observeEvent(input$resetAllRC, {
hide(id = "RegCorMP")
shinyjs::reset("RegCorMP")
})
}
shinyApp(ui = ui, server = server)```
@Limey Любые советы о том, как выйти из катастрофы? Вы имеете в виду, что я должен использовать один отдельный observeEvent для каждого reactive утверждения?
Нет. Я имею в виду, я думаю, что вы можете полностью отказаться от observeEvent. ВСЕ ваши reactive (и observeEvent, если необходимо) должны быть определены непосредственно в теле вашей серверной функции. Я не буду пытаться это сделать, потому что ваш код далеко не минимален: ни один из CSS не имеет прямого отношения к вашей проблеме. MathJax тоже нет. Ни radioButtons. И так далее. «Минимальная» часть MRE так же важна, как и «воспроизводимая». Дисциплина создания минимального воспроизводимого примера часто позволяет мне решить проблему до публикации вопроса.
@Limey Спасибо за ваш совет, я удалил все reactive и сократил код до минимума. Сообщения проверки печатаются на mainPanel, хотя они также выводят результаты вместе с сообщениями, когда условия действительно выполняются. Любые советы о том, как распечатать тот или иной, т. е. предупреждение или правильные результаты. Сейчас он печатает оба.





Я думаю, что это близко к тому, что вы хотите. Обратите внимание, что каждый reactive определяется в теле серверной функции, а не в теле другого reactive. Это очень важно. А также полностью устраняет необходимость в вашем observeEvent.
Я удалил больше материалов (divs, themes и т. д.), которые не имеют отношения к вашему вопросу. Я тоже не уверен, что shinyjs нужен. Кроме того, я не уверен, что вы пытаетесь сделать с помощью кнопки сброса (похоже, она ничего не делает в данный момент), поэтому я оставил ее.
Я добавил проверку, чтобы убедиться, что ни в одном из входных данных нет NA, но предоставил вам реализовать проверку на равенство длины.
Кроме того, нет необходимости разделять ваши входные данные запятыми: достаточно пробелов... ;=)
library(shiny)
library(shinyjs)
library(shinyvalidate)
ui <- fluidPage(
useShinyjs(),
navbarPage(
title = "Simple Linear Regression",
tabPanel(
title = "",
sidebarLayout(
sidebarPanel(
id = "sideBar",
textAreaInput(
"x",
label = strong("x (Independent Variable)"),
value = "87, 92, 100, 103, 107, 110, 112, 127",
placeholder = "Enter values separated by a comma with decimals as points",
rows = 3
),
textAreaInput(
"y",
label = strong("y (Dependent Variable)"),
value = "39, 47, 60, 50, 60, 65, 115, 118",
placeholder = "Enter values separated by a comma with decimals as points",
rows = 3
),
actionButton(
inputId = "goRegression",
label = "Calculate",
),
actionButton(
"resetAllRC",
label = "Reset Values",
)
),
mainPanel(
div(
textOutput("xArray"),
textOutput("yArray"),
textOutput("arrayLengths"),
verbatimTextOutput("linearRegression"),
) # RegCorMP
) # mainPanel
) # sidebarLayout
)
)
)
server <- function(input, output) {
# Data validation
iv <- InputValidator$new()
iv$add_rule("x", sv_required())
iv$add_rule("x", ~ if (any(is.na(as.numeric(strsplit(., ",", fixed = FALSE)[[1]])))) "NAs are not allowed")
iv$add_rule("y", sv_required())
iv$add_rule("y", ~ if (any(is.na(as.numeric(strsplit(., ",", fixed = FALSE)[[1]])))) "NAs are not allowed")
iv$enable()
# See https://rstudio.github.io/shinyvalidate/articles/advanced.html for clues on
# how to implement length(x) == length(y) validation
createNumLst <- function(text) {
text <- gsub("","", text)
split <- strsplit(text, ",", fixed = FALSE)[[1]]
d <- as.numeric(split)
if (length(d) < 2) "Not enough values"
d
}
xData <- reactive({
createNumLst(input$x)
})
yData <- reactive({
createNumLst(input$y)
})
output$xArray <- renderPrint({ xData() })
output$yArray <- renderPrint({ yData() })
output$arrayLengths <- renderPrint({
if (length(xData()) != length(yData())) "Length of x and length of y must be the same"
})
# Use isolate to ensure that results are updated only when action button is clicked, not
# every time the input data changes
output$linearRegression <- renderPrint({
input$goRegression
isolate({
summary(lm(yData() ~ xData()))
})
})
observeEvent(input$goRegression, {
show(id = "RegCorMP")
})
# Not sure what you are trying to do here
observeEvent(input$resetAllRC, {
hide(id = "RegCorMP")
shinyjs::reset("RegCorMP")
})
}
shinyApp(ui = ui, server = server)
Большое спасибо за ответы. divs, themes, shinyjs и т. д. полезны для более зрелого приложения Shiny, над которым я работаю ссылка. Этот конкретный пост был небольшой его частью, где я работал над простой линейной регрессией и хотел проверить поля x и ytextAreaInput. Кнопка «Сброс» предназначена для очистки всего (выходных данных, предупреждений, графиков и т. д.), отображаемого в данный момент на основной панели.
«div, темы, блестящие и т. д. — все это полезно для более зрелого приложения Shiny, над которым я работаю по ссылке». Это все вполне разумно. Но они не имеют отношения к заданному вами вопросу.
Вложенность
reactive— это рецепт катастрофы. Это скорее всего ваша проблема. ВашobserveEventопределяет несколькоreactiveвнутри себя. Обычные правила области видимости R означают, что эти вложенные функции недоступны для других элементов вашего приложения.