R Shiny — выделение реактивного выражения, использующего req() для проверки предварительных условий

Приложение ниже содержит selectInput с двумя вариантами iris и mtcars и заголовок, который отображает текущий выбор.

  • Если пользователь выбирает iris, под заголовком отображается DT соответствующего набора данных.
  • Если пользователь выбирает mtcars, ниже заголовка ничего не отображается.

Вот скриншот:

R Shiny — выделение реактивного выражения, использующего req() для проверки предварительных условий

Я сохраняю выбранный набор данных в реактивном выражении, 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 по-прежнему вызывает sel_df каждый раз, когда он становится недействительным». как вы это отслеживаете... с режимом отображения = витрина?

Tonio Liebrand 22.07.2019 10:13

Я просто вывел это из того факта, что output$tbl полностью исчезает, если input$dataset != "iris", что означает, что output$tbl останавливается при вызове sel_df.

user51462 22.07.2019 10:30
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
2
2 088
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

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()) в каждом из этих вызовов.

user51462 22.07.2019 10:28

Кроме того, поскольку я проверяю несколько условий, я в конечном итоге использую вложенный if/else, который не так читаем, как req.

user51462 22.07.2019 10:41

Боюсь, вы не можете есть торт и есть торт ;-) req в некотором смысле эквивалентно использованию stopifnot, и именно так вы должны относиться к этому! Как насчет определения другого реактивного выражения, которое проверяет, есть ли input$dataset == 'iris', и устанавливает флаг, аналогичный определению sel_df в моем ответе, без req?

January 22.07.2019 11:05

Это правда :) Я просто хотел убедиться, что нет более простого пути. В итоге я использовал что-то вроде 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}). Спасибо за помощь!

user51462 25.07.2019 03:27

Если вы хотите использовать 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 таким образом, я проголосовал.

user51462 25.07.2019 03:33

Другие вопросы по теме