这是我制作的较大脚本的简化版本。本质上我有 3 个图表,第一个图表使用用户输入数据集总行数的百分比并绘制它。第二个图表使用第一个图表中未绘制的行,应用不同的百分比选择器并绘制它。第三张图做了同样的事情,但相对于第二张图。
我的问题是第二个图能够返回自定义错误消息,因为数据集可用,但因为闪亮是“懒惰”,我无法查询第三个图数据,因为它还不存在。我想这样做是为了将错误消息更改为对用户更有用的错误消息。
运行下面的代码时,第二张图有自定义错误,但第三张图显示
"Error: argument is of length zero"
但我希望它显示自定义错误。我知道我可以使用
validate(
need(nrow(Graph1_data_inverse()) > 0, 'There is no data available for this graph')
)
validate(
need(nrow(Graph2_data_inverse()) > 0, 'There is no data available for this graph')
)
但如果可能的话,我想要一个更优雅的解决方案。
library(shiny)
library(datasets)
library(shinyFeedback)
library(plotly)
data <- iris
ui <- fluidPage(
shinyFeedback::useShinyFeedback(),
column(4,
numericInput("Graph1_percent", tags$span(style="color: #000000; font-size: 13px;", "Percent (%)"), value = 100, min = 0, max = 100),
plotlyOutput("Graph1", height = 400)
),
column(4,
numericInput("Graph2_percent", tags$span(style="color: #000000; font-size: 13px;", "Percent (%)"), value = 100, min = 0, max = 100),
plotlyOutput("Graph2", height = 400)
),
column(4,
numericInput("Graph3_percent", tags$span(style="color: #000000; font-size: 13px;", "Percent (%)"), value = 100, min = 0, max = 100),
plotlyOutput("Graph3", height = 400)
)
)
server <- function(input, output, session) {
Graph1_data <- reactive({
n <- nrow(data)
if(input$Graph1_percent == 0 | n == 0) {
} else {
Graph1_data_ <- data[1:round(n*(input$Graph1_percent /100)), ]
}
})
Graph1_data_inverse <- reactive({
n <- nrow(data)
if(n == 0 | input$Graph1_percent == 100) {
} else {
Graph1_data_inv <- data[(round(n*(input$Graph1_percent /100))+1):n, ]
}
})
output$Graph1 <- renderPlotly({
ggplotly(Graph1_data() %>%
ggplot(aes(x = Sepal.Length, fill = Species))+
geom_bar()
)
})
###Graph 2
Graph2_data <- reactive({
validate(
need(nrow(Graph1_data_inverse()) > 0, 'There is no data available for this graph.')
)
n <- nrow(Graph1_data_inverse())
if(input$Graph2_percent == 0 | n == 0) {
} else {
Graph2_data_ <- Graph1_data_inverse()[1:round(n*(input$Graph2_percent /100)), ]
}
})
Graph2_data_inverse <- reactive({
n <- nrow(Graph1_data_inverse())
if(n == 0 | input$Graph2_percent == 100) {
} else {
Graph2_data_inv <- Graph1_data_inverse()[(round(n*(input$Graph2_percent /100))+1):n, ]
}
})
output$Graph2 <- renderPlotly({
req(Graph2_data())
ggplotly(Graph2_data() %>%
ggplot(aes(x = Sepal.Length, fill = Species))+
geom_bar()
)
})
###Graph 3
Graph3_data <- reactive({
###This section doesn't work
exists <- exists("Graph2_data_inverse", where = -1, mode='function')
if(exists != TRUE){
paste("There is no data available for this graph")
}
req(exists, cancelOutput = TRUE)
validate(
need(nrow(Graph2_data_inverse()) > 0, 'There is no data available for this graph')
)
n <- nrow(Graph2_data_inverse())
if(input$Graph3_percent == 0 | n == 0) {
} else {
Graph3_data_ <- Graph2_data_inverse()[1:round(n*(input$Graph3_percent /100)), ]
}
})
###this inverse dataset is not used but I'm including it here so the graphs retain the same structure
Graph3_data_inverse <- reactive({
n <- nrow(Graph2_data_inverse())
if(n == 0 | input$Graph3_percent == 100) {
} else {
Graph3_data_inv <- Graph2_data_inverse()[(round(n*(input$Graph3_percent /100))+1):n, ]
}
})
output$Graph3 <- renderPlotly({
req(Graph3_data())
ggplotly(Graph3_data() %>%
ggplot(aes(x = Sepal.Length, fill = Species))+
geom_bar()
)
})
}
# Run the application
shinyApp(ui = ui, server = server)
当您检查跟踪日志时,您应该注意到错误并不是真正源自
Graph3_data()
,而是 Graph2_data_inverse()
未能通过 Error in if 进行评估:
Warning: Error in if: argument is of length zero
150: <reactive:Graph2_data_inverse> [#43]
134: Graph2_data_inverse
126: <reactive:Graph3_data> [#68]
110: Graph3_data
103: renderPlotly [#92]
102: func
99: shinyRenderWidget
98: func
85: renderFunc
84: output$Graph3
3: runApp
2: print.shiny.appobj
1: <Anonymous>
这又是在
NULL
条件下具有潜在 |
值和元素 OR、
if
的结果。
例如。如果您有以下反应:
Graph2_data_inverse <- reactive({
n <- nrow(Graph1_data_inverse())
if(n == 0 | input$Graph2_percent == 100) {
} else {
Graph2_data_inv <- Graph1_data_inverse()[(round(n*(input$Graph2_percent /100))+1):n, ]
}
})
并且
Graph1_data_inverse()
恰好返回 NULL
,你会得到类似:
(n <- nrow(NULL))
#> NULL
if (n == 0 | FALSE ) {}
#> Error in if (n == 0 | FALSE) {: argument is of length zero
在
if
条件下,您最有可能想要使用 ||
、&&
而不是 |
、&
。如果 NULL
值有可能潜入并将整个表达式转换为 0 长度/非 TRUE/FALSE
,则 shiny::isTruthy()
会很方便,但由于 0
也是如此,因此可能需要进行最小更新像这样:
Graph2_data_inverse <- reactive({
n <- nrow(Graph1_data_inverse())
if(isTruthy(n) || n == 0 || input$Graph2_percent == 100) {
...
}
})
这适用于所有条件,而不仅仅是
Graph2_data_inverse()
中的条件。