Приложение ниже содержит selectInput с двумя вариантами iris и mtcars и заголовок, который отображает текущий выбор.
iris, под заголовком отображается DT соответствующего набора данных.mtcars, ниже заголовка ничего не отображается.Вот скриншот:
Я сохраняю выбранный набор данных в реактивном выражении, sel_df. Выражение проверяет, выбрал ли пользователь радужную оболочку с помощью req(input$dataset=='iris') перед возвратом соответствующего набора данных:
sel_df = reactive({
req(input$dataset=='iris')
iris
})
sel_df передается renderDT, который отображает данные:
output$df = renderDT({
sel_df()
})
Затем я визуализирую некоторый пользовательский интерфейс для отображения текущего значения selectInput, используя заголовок h3, таблицу данных и метку для таблицы данных:
output$tbl = renderUI({
tagList(
h3(paste0('Selected:', input$dataset)), # Header should be visible regardless of the value of input$dataset
tags$label(class = 'control-label', style = if (!isTruthy(isolate(sel_df()))) 'display:none;', `for` = 'df', 'Data:'), # Label should only show if input$dataset == 'iris'
DTOutput('df')
)
})
Я бы хотел, чтобы таблица данных и ее метка были видны только в том случае, если sel_df выводит набор данных. Но из-за того, как структурировано приложение, для этого требуется, чтобы output$tbl (renderUI выше) зависело от sel_df, чтобы вся часть пользовательского интерфейса исчезала всякий раз, когда input$dataset == 'mtcars'.
Мой желаемый результат требует, чтобы output$tbl зависел только от input$dataset, чтобы заголовок h3 всегда был виден независимо от значения input$dataset. Для этого я попытался «изолировать» sel_df с помощью isolate, но output$tbl по-прежнему вызывает sel_df каждый раз, когда становится недействительным.
Я не уверен, где я ошибаюсь здесь. Я думаю, что могу использовать isolate неправильно, но я не знаю, почему, и мне было интересно, может ли кто-нибудь пролить свет.
Вот приложение полностью:
library(shiny)
library(DT)
ui <- fluidPage(
selectInput('dataset', 'Dataset', c('iris', 'mtcars')),
uiOutput('tbl')
)
server <- function(input, output, session) {
sel_df = reactive({
req(input$dataset=='iris')
iris
})
output$df = renderDT({
sel_df()
})
output$tbl = renderUI({
tagList(
h3(paste0('Selected:', input$dataset)), # Header should be visible regardless of the value of input$dataset
tags$label(class = 'control-label', style = if (!isTruthy(isolate(sel_df()))) 'display:none;', `for` = 'df', 'Data:'), # Label should only show if input$dataset == 'iris'
DTOutput('df')
)
})
}
shinyApp(ui, server)
Я просто вывел это из того факта, что output$tbl полностью исчезает, если input$dataset != "iris", что означает, что output$tbl останавливается при вызове sel_df.





output$tbl зависит от input$dataset, поэтому, естественно, он вызывается каждый раз при изменении значения input$dataset. sel_df() также зависит от input$dataset и вызывается при его изменении. Это все, как ожидается, я не думаю, что ваш лейбл называется, потому что это зависит от sel_df().
Однако обратите внимание, что когда sel_df имеет значение NULL, вызов taglist() также вернет NULL. Это связано с тем, что ваш sel_df() вызывает терпит неудачу молча, когда input$dataset != "iris", и, следовательно, tagList также терпит неудачу:
If any of the given values is not truthy, the operation is stopped by raising a "silent" exception (not logged by Shiny, nor displayed in the Shiny app's UI).
Попробуй это:
server <- function(input, output, session) {
sel_df = reactive({
if (input$dataset=='iris') {
iris
} else {
NULL
}
})
Вы обнаружите, что с mtcars отображается тег h3(), но метка скрыта по желанию.
Да, я понимаю, что req вызывает sel_df молчаливый сбой, если input$dataset != 'iris', но как я могу проверить это в операторе IF, который решает, отображать ли метку? Первоначально я использовал if/else, но обнаружил, что req более удобен, поскольку sel_df также используется в других местах в вызовах других функций рендеринга, и это избавляет меня от необходимости писать req(sel_df()) в каждом из этих вызовов.
Кроме того, поскольку я проверяю несколько условий, я в конечном итоге использую вложенный if/else, который не так читаем, как req.
Боюсь, вы не можете есть торт и есть торт ;-) req в некотором смысле эквивалентно использованию stopifnot, и именно так вы должны относиться к этому! Как насчет определения другого реактивного выражения, которое проверяет, есть ли input$dataset == 'iris', и устанавливает флаг, аналогичный определению sel_df в моем ответе, без req?
Это правда :) Я просто хотел убедиться, что нет более простого пути. В итоге я использовал что-то вроде sel_df <- reactive({ #calculate value1; if (#value1 does not meet condition1) return(NULL); #calculate value2; if (#value2 does not meet condition2) return(NULL); #more calculations}). Спасибо за помощь!
Если вы хотите использовать req в sel_df(), вы можете использовать trycatch в renderDT, это решает проблему, упомянутую @January, из-за сбоя tagsList, когда вы не выбираете диафрагму.
Вам также нужно будет изменить оператор if, чтобы использовать is.null, так как я использую его как значение return по умолчанию в trycatch.
library(shiny)
library(DT)
ui <- fluidPage(
selectInput('dataset', 'Dataset', c('iris', 'mtcars')),
uiOutput('tbl')
)
server <- function(input, output, session) {
sel_df = reactive({
req(input$dataset=='iris')
iris
})
output$df = renderDT({
out <- tryCatch(sel_df(), error = function(e) NULL)
return(out)
})
output$tbl = renderUI({
tagList(
tags$h3(paste0('Selected:', input$dataset)), # Header should be visible regardless of the value of input$dataset
tags$label(class = 'control-label', style = if (is.null('df')) 'display:none;', `for` = 'df', 'Data:'), # Label should only show if input$dataset == 'iris'
DTOutput('df')
)
})
}
shinyApp(ui, server)
Спасибо @RK1, я не думал использовать tryCatch таким образом, я проголосовал.
«но output$tbl по-прежнему вызывает sel_df каждый раз, когда он становится недействительным». как вы это отслеживаете... с режимом отображения = витрина?