Reputation: 4239
I am building a shiny application where every 30 secs, reactivefilereader
reads in new data and process it by appending to data accumulated since the the app starts running (the data processing function append new data with existing aggregated data and returns one single row), and then ggplot
will plot this single observation on the plot. And it will plot out the observations continuously with a line. However, I received this error message and nothing is being plotted on the shiny app.
geom_path: Each group consists of only one observation. Do you need to adjust the group aesthetic?
My data is as follow:
ts
Px
2020-03-13 17:15:19.000 23335.5
I have the global variable outside the server
function. Note that below doesn't contain any data because the shiny will read in the data every 30 seconds.
ggprice <- ggplot() + scale_colour_manual(values=c(Px="black"))
And the plot is updated through below and ts
is the data. And it will contain ONLY one observation.
ggprice <<- ggprice + geom_line(aes(x=Index,y=Px,colour = "Px"),data=ts)
How do I overcome this ?
Update: A reproducible example as requested.
I have 2 global variables below, which i know are super clumsy.
xts_bars_Agg
used to store all the processed data since the app starts runningggprice
. Every new observation is appended on this global variable by geom_line(...)
.How can this be optimized ? Can the global variables be avoided here?
# 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)
Upvotes: 2
Views: 207
Reputation: 5003
Hi you could try working with reactive Values like this
# --- 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)
Hope this helps!!
Upvotes: 1