shiny:如何创建设置间隔模块并暂停/编辑间隔

问题描述 投票:0回答:1

TLDR:如何创建一个计时器对象来刷新闪亮应用程序中的部分,这应该是我可以跨应用程序导入的模块,以使所有内容与暂停/编辑间隔的能力保持同步。

我正在编写一个闪亮的应用程序。在此应用程序中,我有多个部分想要定期更新。

我正在寻找一种创建计时器对象的方法,我可以用它来按给定的时间间隔刷新不同的部分,以及一种暂停/更改reactiveTimer的时间间隔的方法。

我想出了在模块中使用通用计时器对象 (

setInterval
) 的想法(使用
rhino
box
),我将其导入到其他模块中并与
shiny$observeEvent(timer()...
一起使用。

这是一个简单的计时器,它所做的只是每 500 毫秒触发一次。现在我想添加暂停和编辑间隔的功能。

# Set up a common reactive timer to trigger every 500 ms
common_timer <- shiny$reactiveTimer(interval = 1500)

#' @export
timer <- function() {
    return(common_timer())
}

我尝试了一些不同的事情,例如创建一个

R6
类来处理计时器的状态(活动/非活动);返回计时器对象或
NULL
。但我无法让任何东西正常工作。我的
R6
类可以工作,但是当我暂停计时器时,我无法让它再次重新启动。

这是我的一些代码。这是我如何使用计时器将一些数据输入我的应用程序的示例。

box::use(shiny)

#' @export
live_data <- shiny$reactiveVal(NULL)

#' @export
date_interval <- shiny$reactiveValues(
    start_date = lubridate::as_datetime("2019-01-01"),
    end_date = lubridate::as_datetime("2019-01-28")
)

box::use(lubridate)

box::use(./common_timer[ timer ])
box::use(./modules/helpers)
box::use(./modules/cpp)

#' @export
call_data <- function(session, side_bar_options) {
    shiny$observeEvent(timer$get_timer, {
        currency <- shiny$isolate(side_bar_options$currency())

        dt <- helpers$read_market_data(
            file = "./data/kucoin_btc-usdt-hourly.csv",
            symbols = currency,
            from = date_interval$start_date,
            to = date_interval$end_date
        )

        live_data(dt)

        # bump the dates by 10 days
        date_interval$start_date <- date_interval$start_date + lubridate$days(1)
        date_interval$end_date <- date_interval$end_date + lubridate$days(1)
    })
}

这是我想要暂停的地方,然后添加编辑计时器间隔的功能。

box::use(shiny)

#' @export
ui <- function(id, width = 2) {
    ns <- shiny$NS(id)
    shiny$sidebarPanel(
        shiny$tags$h4("Side bar"),
        shiny$selectInput(
            inputId = ns("select_currency"),
            label = "Currency:",
            choices = c("BTC/USDT", "XMR/BTC"),
            selected = "BTC/USDT"
        ),
        shiny$selectInput(
            inputId = ns("supplementary_plot"),
            label = "Supplementary Plot:",
            choices = c("RSI", "MACD", "Volume")
        ),
        shiny$actionButton(
            inputId = ns("toggle_timer"),
            label = "Start/Pause"
        ),
        width = width
    )
}

box::use(../logic/common_timer[ timer ])

#' @export
server <- function(id, live_data) {
    shiny$moduleServer(id, \(input, output, session) {
        ns <- session$ns

        shiny$observeEvent(input$toggle_timer, {
            timer$toggle_timer()
        })

        supplementary_plot <- shiny$reactive({
            input$supplementary_plot
        })

        currency <- shiny$reactive({
            input$select_currency
        })

        return(list(
            currency = currency,
            supplementary_plot = supplementary_plot
        ))
    })
}

如有任何帮助,我们将不胜感激。非常感谢。

r shiny timer
1个回答
0
投票

我对原始示例进行了尽可能少的修改来演示这一点;并将解决方案交叉发布到社区。

library(shiny)

usesTimerModUI <- function(id) {
  ns <- NS(id)
  tagList(
    div(style="border:1px solid black;",
    h4(ns("")),
    verbatimTextOutput(ns("display"))
  ))
}

usesTimerModServer <- function(id,source_timer) {
  moduleServer(
    id,
    function(input, output, session) {
      stopifnot(is.reactive(source_timer))
      
      output$display <- renderText({
        capture.output(req(source_timer()))
      })
    }
  )
}

ui <- fluidPage(
  numericInput("ms","millisec",
               value=1000,
               min=100,
               max=2000,
               step=100),
  checkboxInput("chk","on/off",value=TRUE),
  hr(),
  usesTimerModUI("m1"),
  br(),
  usesTimerModUI("m2")

)

# to see more decimal points
op <- options(digits.secs = 6)

server <- function(input, output, session) {
  
  mytimer <- reactive({
    if(!isTruthy(input$chk)){
      return(NULL)
    } else{
      invalidateLater(millis=req(input$ms))
    }
    Sys.time()
  })
  
  last_timer_value <- reactiveVal(NULL)
  
  observeEvent(mytimer(),
               {if(!identical(last_timer_value,
                              mytimer())){
                 if(isTruthy(mytimer()))
                   last_timer_value(mytimer())
               }})
  
  usesTimerModServer(id="m1",
                     source_timer = last_timer_value)
  usesTimerModServer(id="m2",
                     source_timer = last_timer_value)
  

}

shinyApp(ui, server)
© www.soinside.com 2019 - 2024. All rights reserved.