Shiny: Как избежать глобальных переменных и проблем с ggplot по одному наблюдению за раз - PullRequest
2 голосов
/ 30 марта 2020

Я создаю блестящее приложение, в котором каждые 30 секунд reactivefilereader считывает новые данные и обрабатывает их, добавляя к данным, накопленным с момента запуска приложения (функция обработки данных добавляет новые данные к существующим агрегированным данным и возвращает одно один ряд), а затем ggplot нанесет это единственное наблюдение на график. И он будет непрерывно строить наблюдения с линией. Однако я получил это сообщение об ошибке, и в блестящем приложении ничего не отображается.

geom_path: Each group consists of only one observation. Do you need to adjust the group aesthetic?

Мои данные таковы:

ts
                          Px
2020-03-13 17:15:19.000 23335.5

У меня есть глобальная переменная вне функции server. Обратите внимание, что ниже не содержится никаких данных, потому что блестящий будет считывать данные каждые 30 секунд.

ggprice   <-  ggplot() + scale_colour_manual(values=c(Px="black"))

И график обновляется ниже и ts - это данные. И он будет содержать только одно наблюдение.

ggprice   <<-    ggprice   + geom_line(aes(x=Index,y=Px,colour = "Px"),data=ts)

Как мне преодолеть это?

Обновление: воспроизводимый пример по запросу.

У меня есть 2 глобальные переменные ниже, которые я знаю супер неуклюжий.

  1. Глобальная переменная 1 - xts_bars_Agg используется для хранения всех обработанных данных с момента запуска приложения
  2. Глобальная переменная 2 - ggprice. Каждое новое наблюдение добавляется к этой глобальной переменной с помощью geom_line(...).

Как это можно оптимизировать? Можно ли здесь избежать глобальных переменных?

# Global variables
xts_bars_Agg <-  NULL


#   --- Function: Data I/O ------------------------------------------------------
data_processing <- function(csv_file){

    df                              <-  read.csv(csv_file, header=T,stringsAsFactors = F,colClasses = c("character","double"))
        # convert String to timestamp, remove string timestamp
        df                          <-  (data.frame( Timestamp = strptime(df[,1],"%Y-%m-%d %H:%M:%OS"), df[,c(-1)]))
        df_xts                      <-  xts(x=df[,c(-1)], order.by=df$Timestamp)
        xts_bars_Agg                <<- rbind.xts(xts_bars_Agg,df_xts)
        # *** the reason I need to rbind the new df_xts to 
        # existing xts_bars_agg (xts object) 
        # because the computeMagicalVal function below needs 
        # both the previous aggregated xts data plus the current xts data
        # to compute a value.
        # This and the usage of global variable looks very clumsy and inefficient and stupid to me. 
        # Is there a way to optimise this ?
        df_xts_final                 <- computeMagicalVal(xts_bars_Agg)

    # return df_xts_final with only one row, 
    # whereas xts_bars_Agg contains all the xts data with many rows
    return(df_xts_final)
}

# second global variable
# global variable
ggprice      <-  ggplot() +
                scale_colour_manual(values=c(Price="black"))

ggplot_func <- function(ts){
    ggprice      <<-    ggprice      + geom_line(aes(x=Index,y=Px,colour = "Price"),data=ts)
    return(ggprice)
}

# UI
ui <- fluidPage(
    #ggplot
    mainPanel(
        plotOutput(outputId = 'ggp')
    )
)

# Define server logic
server <- function(input, output, session) {    
    df_update <- reactiveFileReader(intervalMillis = 10000,session=NULL,
                                    filePath = "output.csv",
                                    readFunc = data_processing)

    output$ggp <- renderPlot({
        ggplot_func(df_update())
    })
}

# Run the application 
shinyApp(ui = ui, server = server)

1 Ответ

1 голос
/ 30 марта 2020

Привет, вы можете попробовать поработать с такими реактивными значениями, как это

#   --- Function: Data I/O ------------------------------------------------------
data_processing <- function(csv_file){

  df                              <-  read.csv(csv_file, header=T,stringsAsFactors = F,colClasses = c("character","double"))
  # convert String to timestamp, remove string timestamp
  df                          <-  (data.frame( Timestamp = strptime(df[,1],"%Y-%m-%d %H:%M:%OS"), df[,c(-1)]))
  df_xts                      <-  xts(x=df[,c(-1)], order.by=df$Timestamp)


  return(df_xts)
}

# UI
ui <- fluidPage(
  #ggplot
  mainPanel(
    plotOutput(outputId = 'ggp')
  )
)

# Define server logic
server <- function(input, output, session) {

  rective_values <- reactiveValues(
    xts_bars_Agg = tibble(),
    ggprice = ggplot() +
      scale_colour_manual(values=c(Price="black"))
  )

  # whereas xts_bars_Agg contains all the xts data with many rows
  observe({
    reactive_values$xts_bars_Agg = rbind.xts(xts_bars_Agg,df_update()) 
    # *** the reason I need to rbind the new df_xts to 
    # existing xts_bars_agg (xts object) 
    # because the computeMagicalVal function below needs 
    # both the previous aggregated xts data plus the current xts data
    # to compute a value.
    # This and the usage of global variable looks very clumsy and inefficient and stupid to me. 
    # Is there a way to optimise this ?
  })

  observeEvent(reactive_values$xts_bars_Agg,{
    df_xts_final = computeMagicalVal(reactive_values$xts_bars_Agg)
    reactive_values$ggprice = reactive_values$ggprice + 
      geom_line(aes(x=Index,y=Px,colour = "Price"),
                data= df_xts_final)
  })
  df_update <- reactiveFileReader(intervalMillis = 10000,session=NULL,
                                  filePath = "output.csv",
                                  readFunc = data_processing)



  output$ggp <- renderPlot({
    reactive_values$ggprice
  })
}

# Run the application 
shinyApp(ui = ui, server = server)

Надеюсь, это поможет !!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...