无法获得 flexdashboard 模态 Shiny 反应性来处理 NULL 状态
Can't get flexdashboard modal Shiny reactivity to deal with NULL state
首先,这是一个最小的可重现示例:
假设我有以下 flexdashboard
应用 example.Rmd:
---
title: "Test App"
output:
flexdashboard::flex_dashboard:
theme: ["lumen"]
orientation: ["columns"]
runtime: shiny
---
```{r setup, include=FALSE}
source('modules.R')
```
Test
==================
Inputs {.sidebar data-width=250}
------------------
```{r}
## Modules:
globalInputs <- callModule(setup, "inputs") # Note: you only need to call this one time!
callModule(chart, "modalChart", globalInputs)
## UI:
sidebar("inputs")
```
Column
-------------------------------------
### ModalTest
```{r}
chartUI2("modalChart")
```
这是我的 modules.R 文件:
sidebar <- function(id) {
ns <- NS(id)
tagList(
helpText("Press the button below to pull up a modal:"),
actionButton(ns("settings"), "Settings", icon = icon("cogs"), width = '100%')
)
}
# setup function
setup <- function(input, output, session) {
return(input) ## Note, input in this case is a reactive list of values that you can index against with $ or [[""]]
}
# UI module for the popup Settings modal
modalUI <- function(id) {
ns <- NS(id)
withTags({ # UI elements for the modal go in here
## Note: you can use the fluidPage() and fluidRow() functions to define a column-based UI for the chart inputs below:
fluidPage(
fluidRow(sliderInput(ns("bins"), "Number of bins:",
min = 1, max = 50, value = 30),
textInput(ns("plotTitle"), label = "Plot Title", value = "This is a test")
))
})
}
## UI module for the 2 buttons in the modal:
modalFooterUI <- function(id) {
ns <- NS(id)
tagList(
modalButton("Cancel", icon("remove")),
actionButton(ns("modalApply"), "Apply", icon = icon("check"))
)
}
## chart module ----------------------------------------------------------------
chartUI2 <- function(id) {
ns <- NS(id)
plotOutput(ns("distPlot"))
}
chart <- function(input, output, session, setup) {
observeEvent(setup$settings, {
showModal(modalDialog(
modalUI("inputs"), # Call UI function defined in './modules/modal.R'; note the namespace 'inputs' is the same globally for the app
title = "Settings",
footer = modalFooterUI("inputs"),
size = "l",
easyClose = TRUE,
fade = TRUE)
)
})
output$distPlot <- renderPlot({
if (setup$settings == 0)
return(
hist(faithful[, 2],
breaks = 5, # if the button hasn't been pressed, default
main = 'This is the default title',
col = 'darkgray',
border = 'white')
)
isolate({
x <- faithful[, 2]
bins <- setup$bins
hist(x,
breaks = bins,
main = setup$plotTitle,
col = 'darkgray',
border = 'white')
})
})
}
这是我想要完成的:
- 当页面加载时使用默认参数呈现
distPlot
。这应该总是发生。
- 当我单击 'Settings'
actionButton
时,它会弹出模态叠加层(但会在背景中保持原始状态的绘图)
- 允许用户更改弹出模式中的参数,但在用户点击 'Apply' 按钮之前不要重新渲染绘图。
我想我已经弄明白了#1,但是当我点击 'Settings' 按钮时,我得到了一个错误 Invalid breakpoints produced by 'breaks(x)': NULL
。然后,我更改了输入,但它什么也没做(除非我再次点击设置 actionButton
(这反过来用给定的输入渲染图)。
我做错了什么?
谢谢!!
可能存在时间问题。当您按下设置按钮时,setup$settings
变为 1,因此 renderPlot
会尝试重新绘制。如果在设置滑块之前发生这种情况,setup$bins
是 NULL
并且您会收到错误消息。
您可以在 renderPlot
的第一个 if
中添加一个条件,以便仅当用户按下模态中的“应用”按钮时才使用 setup$bins
绘制:
output$distPlot <- renderPlot({
if (setup$settings == 0 | !isTruthy(setup$modalApply)) {
hist(faithful[, 2],
breaks = 5, # if the button hasn't been pressed, default
main = 'This is the default title',
col = 'darkgray',
border = 'white')
} else {
isolate({
x <- faithful[, 2]
bins <- setup$bins
hist(x,
breaks = bins,
main = setup$plotTitle,
col = 'darkgray',
border = 'white')
})
!isTruthy
将是 TRUE
如果 setup$modalApply
是 NULL
(模态还没有被创建)或者如果它是 0
(用户没有尚未按下按钮)。
一旦用户按下“应用”按钮,绘图就会更新。
编辑:
为了方便起见,您可以使用 reactiveValues
来保存所有绘图参数,包括默认参数。它可以在用户单击应用按钮时更新,这又会更新绘图:
plot_params = reactiveValues(bins=5,title='This is the default title')
output$distPlot <- renderPlot({
hist(faithful[, 2],
breaks = plot_params$bins,
main = plot_params$title,
col = 'darkgray',
border = 'white')
})
observeEvent(setup$modalApply,{
plot_params$bins = setup$bins
plot_params$title = setup$plotTitle
})
首先,这是一个最小的可重现示例:
假设我有以下 flexdashboard
应用 example.Rmd:
---
title: "Test App"
output:
flexdashboard::flex_dashboard:
theme: ["lumen"]
orientation: ["columns"]
runtime: shiny
---
```{r setup, include=FALSE}
source('modules.R')
```
Test
==================
Inputs {.sidebar data-width=250}
------------------
```{r}
## Modules:
globalInputs <- callModule(setup, "inputs") # Note: you only need to call this one time!
callModule(chart, "modalChart", globalInputs)
## UI:
sidebar("inputs")
```
Column
-------------------------------------
### ModalTest
```{r}
chartUI2("modalChart")
```
这是我的 modules.R 文件:
sidebar <- function(id) {
ns <- NS(id)
tagList(
helpText("Press the button below to pull up a modal:"),
actionButton(ns("settings"), "Settings", icon = icon("cogs"), width = '100%')
)
}
# setup function
setup <- function(input, output, session) {
return(input) ## Note, input in this case is a reactive list of values that you can index against with $ or [[""]]
}
# UI module for the popup Settings modal
modalUI <- function(id) {
ns <- NS(id)
withTags({ # UI elements for the modal go in here
## Note: you can use the fluidPage() and fluidRow() functions to define a column-based UI for the chart inputs below:
fluidPage(
fluidRow(sliderInput(ns("bins"), "Number of bins:",
min = 1, max = 50, value = 30),
textInput(ns("plotTitle"), label = "Plot Title", value = "This is a test")
))
})
}
## UI module for the 2 buttons in the modal:
modalFooterUI <- function(id) {
ns <- NS(id)
tagList(
modalButton("Cancel", icon("remove")),
actionButton(ns("modalApply"), "Apply", icon = icon("check"))
)
}
## chart module ----------------------------------------------------------------
chartUI2 <- function(id) {
ns <- NS(id)
plotOutput(ns("distPlot"))
}
chart <- function(input, output, session, setup) {
observeEvent(setup$settings, {
showModal(modalDialog(
modalUI("inputs"), # Call UI function defined in './modules/modal.R'; note the namespace 'inputs' is the same globally for the app
title = "Settings",
footer = modalFooterUI("inputs"),
size = "l",
easyClose = TRUE,
fade = TRUE)
)
})
output$distPlot <- renderPlot({
if (setup$settings == 0)
return(
hist(faithful[, 2],
breaks = 5, # if the button hasn't been pressed, default
main = 'This is the default title',
col = 'darkgray',
border = 'white')
)
isolate({
x <- faithful[, 2]
bins <- setup$bins
hist(x,
breaks = bins,
main = setup$plotTitle,
col = 'darkgray',
border = 'white')
})
})
}
这是我想要完成的:
- 当页面加载时使用默认参数呈现
distPlot
。这应该总是发生。 - 当我单击 'Settings'
actionButton
时,它会弹出模态叠加层(但会在背景中保持原始状态的绘图) - 允许用户更改弹出模式中的参数,但在用户点击 'Apply' 按钮之前不要重新渲染绘图。
我想我已经弄明白了#1,但是当我点击 'Settings' 按钮时,我得到了一个错误 Invalid breakpoints produced by 'breaks(x)': NULL
。然后,我更改了输入,但它什么也没做(除非我再次点击设置 actionButton
(这反过来用给定的输入渲染图)。
我做错了什么?
谢谢!!
可能存在时间问题。当您按下设置按钮时,setup$settings
变为 1,因此 renderPlot
会尝试重新绘制。如果在设置滑块之前发生这种情况,setup$bins
是 NULL
并且您会收到错误消息。
您可以在 renderPlot
的第一个 if
中添加一个条件,以便仅当用户按下模态中的“应用”按钮时才使用 setup$bins
绘制:
output$distPlot <- renderPlot({
if (setup$settings == 0 | !isTruthy(setup$modalApply)) {
hist(faithful[, 2],
breaks = 5, # if the button hasn't been pressed, default
main = 'This is the default title',
col = 'darkgray',
border = 'white')
} else {
isolate({
x <- faithful[, 2]
bins <- setup$bins
hist(x,
breaks = bins,
main = setup$plotTitle,
col = 'darkgray',
border = 'white')
})
!isTruthy
将是 TRUE
如果 setup$modalApply
是 NULL
(模态还没有被创建)或者如果它是 0
(用户没有尚未按下按钮)。
一旦用户按下“应用”按钮,绘图就会更新。
编辑:
为了方便起见,您可以使用 reactiveValues
来保存所有绘图参数,包括默认参数。它可以在用户单击应用按钮时更新,这又会更新绘图:
plot_params = reactiveValues(bins=5,title='This is the default title')
output$distPlot <- renderPlot({
hist(faithful[, 2],
breaks = plot_params$bins,
main = plot_params$title,
col = 'darkgray',
border = 'white')
})
observeEvent(setup$modalApply,{
plot_params$bins = setup$bins
plot_params$title = setup$plotTitle
})