jbkunst / highcharter

R wrapper for highcharts
http://jkunst.com/highcharter/
Other
720 stars 148 forks source link

Dynamic loading of Data #89

Open debsush opened 8 years ago

debsush commented 8 years ago

Hi,

I am using your package for the first time and since it is relatively new in the market, I am posing my problem here.

Objective: I want the highstockcharts to render fast. Today a 10 year data for 2-3 stocks (candlestick) takes ~ 3-5 seconds. I can optimize this by first loading only the weekly data. But if a user chooses to zoom-in (zoom period <365 days), the script should load the daily data for that zoomed in period + the original weekly data. Loading of the weekly data along with the zoomed in period daily data is necessary. Now when the chart redraws with the new data, it should zoom into the users extreme points. I have done this with amCharts but am struggling with Highcharts because the series of methods that gets triggered in case of HighCharts i s a little different.

In HighCharts, when we initialize the chart for the first time, the redraw event gets triggered followed by afterSetExtremes event and again finally the redraw event.

Redraw--> afterSetExtremes --> Redraw --> Stop

We can always use these events to build a logic to achieve the above objective but I am failing to trigger the Highcharts.charts[0].xAxis[0].setExtremes(start,end) statement. in my code below, when the user zooms-in <365 days, a r-script gets triggered which loads the new data. This is working fine but when it redraws the chart, it is not able to set the zoom periods to what the user had used. I am not sure if this is the right forum but any help will be appreciated.

PS: Highstock scores above amCharts in terms of performance and hence this feature is critical.

library(highcharter) library(quantmod) library(shinyBS) library(shiny) library(shinyjs)

shinyUI(fluidPage( bsButton("demobtn",type="action", label = NULL,class="btn-group btn-group-xs",icon=icon("plus")), column(3,HTML('

-
')), column(3,HTML('
-
')), column(3,HTML('
-
')), column(3,HTML('
-
')), highchartOutput("hcontainer",height = "800px")
))

server = function(input, output, session) {

values <- reactiveValues() values$Validate=0 onclick("demobtn",values$Validate <- runif(1, 1, 10000))

SPY <- getSymbols("SPY", from="2006-01-01", auto.assign=FALSE) SPY <- adjustOHLC(SPY)

SPY.SMA.10 <- SMA(Cl(SPY), n=10) SPY.SMA.200 <- SMA(Cl(SPY), n=200) SPY.RSI.14 <- RSI(Cl(SPY), n=14) SPY.RSI.SellLevel <- xts(rep(70, NROW(SPY)), index(SPY)) SPY.RSI.BuyLevel <- xts(rep(30, NROW(SPY)), index(SPY))

indx <- as.Date(as.integer(apply.monthly(SPY,function(x)index(first(x[as.POSIXlt(index(x))$mday>=10],"day"))))) indx1 <- as.Date(as.integer(apply.monthly(SPY,function(x)index(first(x[as.POSIXlt(index(x))$mday>=15],"day"))))) indx2 <- as.Date(as.integer(apply.monthly(SPY,function(x)index(first(x[as.POSIXlt(index(x))$mday>=20],"day"))))) SPY<-c(SPY[.indexmday(SPY)==1],SPY[index<-indx],SPY[index<-indx1],SPY[index<-indx2]) SPY.SMA.10<-c(SPY.SMA.10[.indexmday(SPY.SMA.10)==1],SPY.SMA.10[index<-indx],SPY.SMA.10[index<-indx1],SPY.SMA.10[index<-indx2]) SPY.SMA.200<-c(SPY.SMA.200[.indexmday(SPY.SMA.200)==1],SPY.SMA.200[index<-indx],SPY.SMA.200[index<-indx1],SPY.SMA.200[index<-indx2]) SPY.RSI.14<-na.omit(c(SPY.RSI.14[.indexmday(SPY.RSI.14)==1],SPY.RSI.14[index<-indx],SPY.RSI.14[index<-indx1],SPY.RSI.14[index<-indx2])) SPY.RSI.SellLevel<-na.omit(c(SPY.RSI.SellLevel[.indexmday(SPY.RSI.SellLevel)==1],SPY.RSI.SellLevel[index<-indx],SPY.RSI.SellLevel[index<-indx1],SPY.RSI.SellLevel[index<-indx2])) SPY.RSI.BuyLevel<-na.omit(c(SPY.RSI.BuyLevel[.indexmday(SPY.RSI.BuyLevel)==1],SPY.RSI.BuyLevel[index<-indx],SPY.RSI.BuyLevel[index<-indx1],SPY.RSI.BuyLevel[index<-indx2]))

observeEvent(input$zoomstart,{ check<<-"Pakad" if (is.null(input$zoomend)==FALSE){ enddt<<-input$zoomend startdt<<-input$zoomstart SPY <<- getSymbols("SPY", from="2006-01-01", auto.assign=FALSE) SPY <<- adjustOHLC(SPY)

  SPY.SMA.10 <<- SMA(Cl(SPY), n=10)
  SPY.SMA.200 <<- SMA(Cl(SPY), n=200)
  SPY.RSI.14 <<- RSI(Cl(SPY), n=14)
  SPY.RSI.SellLevel <<- xts(rep(70, NROW(SPY)), index(SPY))
  SPY.RSI.BuyLevel <<- xts(rep(30, NROW(SPY)), index(SPY))
} 
values$Validate <- runif(1, 1, 10000)

})

output$hcontainer <- renderHighchart({ values$Validate

#     if (values$Validate==0)
#       return()

highchart() %>% 
  # create axis :)
  hc_yAxis_multiples(
    list(title = list(text = NULL), height = "65%", top = "0%"),
    list(title = list(text = NULL), height = "10%", top = "72.5%", opposite = TRUE),
    list(title = list(text = NULL), height = "15%", top = "85%")
  ) %>% 
  # series :D
  hc_add_series_ohlc(SPY, yAxis = 0, name = "SPY",smoothed=TRUE,forced=TRUE,groupPixelWidth=240) %>% 
  #       hc_add_series_xts(SPY.SMA.10, yAxis = 0, name = "Fast MA",forced=TRUE,groupPixelWidth=240) %>% 
  #       hc_add_series_xts(SPY.SMA.200, yAxis = 0, name = "Slow MA",forced=TRUE,groupPixelWidth=240) %>% 
  hc_add_series_xts(SPY$SPY.Volume, color = "gray", yAxis = 1, name = "Volume", type = "column",forced=TRUE,groupPixelWidth=240) %>% 
  hc_add_series_xts(SPY.RSI.14, yAxis = 2, name = "Osciallator",forced=TRUE,groupPixelWidth=240) %>% 
  hc_add_series_xts(SPY.RSI.SellLevel, color = "red", yAxis = 2, name = "Sell level", enableMouseTracking = FALSE,forced=TRUE,groupPixelWidth=240) %>% 
  hc_add_series_xts(SPY.RSI.BuyLevel, color = "blue", yAxis = 2, name = "Buy level", enableMouseTracking = FALSE,forced=TRUE,groupPixelWidth=240) %>% 
  # I <3 themes
  hc_add_theme(hc_theme_538())%>%
  hc_chart(zoomType = "xy") %>%
  hc_xAxis(
    events = list(
      setExtremes = JS('function(event){
                       document.getElementById("ZoomFlag").innerHTML = "Yes";
        }'),
        afterSetExtremes = JS('function(event){
                              if (document.getElementById("ZoomST").innerHTML!="-") {
                              var start = document.getElementById("ZoomST").innerHTML;
                              var end = document.getElementById("ZoomEND").innerHTML;
                              } else  {
                              var start = this.getExtremes()["min"];
                              var end = this.getExtremes()["max"];   
                              }
                              var timeDiff = Math.abs(parseInt(end) - parseInt(start));
                              var diffDays = Math.ceil(timeDiff / (1000 * 3600 * 24));

                              if (document.getElementById("ZoomFlag").innerHTML=="Yes" && diffDays<365) {
                              if (document.getElementById("DataPull").innerHTML=="-"){
                              alert("Hello");
                              document.getElementById("DataPull").innerHTML="PullIt";
                              //document.getElementById("ZoomFlag").innerHTML = "-";
                              alert(document.getElementById("DataPull").innerHTML);
                              document.getElementById("ZoomST").innerHTML= this.getExtremes()["min"];
                              document.getElementById("ZoomEND").innerHTML= this.getExtremes()["max"];
                              alert(document.getElementById("ZoomST").innerHTML);
                              clearTimeout();
                              setTimeout(function(){
                              Shiny.onInputChange("zoomstart", start)
                              Shiny.onInputChange("zoomend", end)
                              }, 1);
                              } else {    clearTimeout();
                              document.getElementById("ZoomFlag").innerHTML = "-";
                              document.getElementById("ZoomST").innerHTML= "-";
                              document.getElementById("ZoomEND").innerHTML = "-";
                              alert(document.getElementById("ZoomFlag").innerHTML);
                              alert("This is when we need to chart to set extremes");
                              setTimeout(function(){
                              Highcharts.charts[0].xAxis[0].setExtremes(start,end);
                              }, 1);
                              }
                              } else {
                              alert(document.getElementById("ZoomFlag").innerHTML);
                              }

        }')
                      )
      )%>%
  hc_chart(
    events = list(
      redraw = JS('function(event){
      }')
    ))%>%
  hc_rangeSelector(buttons=list(
    list(type= 'month',count= 1,text= '1m'),
    list(type= 'month',count= 3,text= '3m'),
    list(type= 'month',count= 6,text= '6m'),
    list(type= 'ytd', text= 'YTD'),
    list(type= 'year',count= 1,text= '1Y'),
    list(type= 'year',count= 3,text= '3Y'),
    list(type= 'year',count= 5,text= '5Y'),
    list(type= 'year',count= 7,text= '7Y'),
    list(type= 'all',text= 'All')
  ))
})

}

debsush commented 8 years ago

I guess I am trying the lazy load technique but unable to import dynamic data function using a data loading function (which is in R) and call it within the JS event function

http://www.highcharts.com/stock/demo/lazy-loading

jbkunst commented 8 years ago

Hi @debsush ,

How is this issue going? I guess that link can solve partially the issue. But I dont know how to solve but I think your approach is correct nut I'm not sure due I didnt do something like this.

Next time, can you format the code so it will be easier to read and understand? ;) thanks.

If I make some experiments I'll let you know.

debsush commented 8 years ago

I have not yet been able to make it work in R. I agree that I should format the code so that it cane be a use case for others. Please keep me posted in case you are able to make any progress.

I also appeal to all users of highcharter to review my case and suggest workarounds.

ui.R

library(highcharter)
library(quantmod)
library(shinyBS)
library(shiny)
library(shinyjs)

shinyUI(fluidPage(
  useShinyjs(),
  bsButton("demobtn",type="action", label = NULL,class="btn-group btn-group-xs",icon=icon("plus")),
  column(3,HTML('<div id="ZoomST" style:>-</div>')),
  column(3,HTML('<div id="ZoomEND">-</div>')),
  column(3,HTML('<div id="ZoomFlag">-</div>')),
  column(3,HTML('<div id="DataPull">-</div>')),
  highchartOutput("hcontainer",height = "800px")  
))
server.R

server = function(input, output, session) {

  values <- reactiveValues()
  values$Validate=0
  onclick("demobtn",values$Validate <- runif(1, 1, 10000))

  # Load the Data
  SPY <- getSymbols("SPY", from="2006-01-01", auto.assign=FALSE)
  SPY <- adjustOHLC(SPY)
  SPY.SMA.10 <- SMA(Cl(SPY), n=10)
  SPY.SMA.200 <- SMA(Cl(SPY), n=200)
  SPY.RSI.14 <- RSI(Cl(SPY), n=14)
  SPY.RSI.SellLevel <- xts(rep(70, NROW(SPY)), index(SPY))
  SPY.RSI.BuyLevel <- xts(rep(30, NROW(SPY)), index(SPY))

  # During initialization of the chart, sample and push only weekly data
  SPY<-c(SPY[.indexwday(SPY)==1],SPY[.indexwday(SPY)==5])
  SPY.SMA.10<-c(SPY.SMA.10[.indexwday(SPY.SMA.10)==1],SPY.SMA.10[.indexwday(SPY.SMA.10)==5])
  SPY.SMA.200<-c(SPY.SMA.200[.indexwday(SPY.SMA.200)==1],SPY.SMA.200[.indexwday(SPY.SMA.200)==5])
  SPY.RSI.14<-c(SPY.RSI.14[.indexwday(SPY.RSI.14)==1],SPY.RSI.14[.indexwday(SPY.RSI.14)==5])
  SPY.RSI.SellLevel<-c(SPY.RSI.SellLevel[.indexwday(SPY.RSI.SellLevel)==1],SPY.RSI.14[.indexwday(SPY.RSI.14)==5])
  SPY.RSI.BuyLevel<-c(SPY.RSI.BuyLevel[.indexwday(SPY.RSI.BuyLevel)==1],SPY.RSI.14[.indexwday(SPY.RSI.14)==5])

  # When user zooms-in (period < 365 days) load the entire data
  observeEvent(input$zoomstart,{
    if (is.null(input$zoomend)==FALSE){
      enddt<<-input$zoomend
      startdt<<-input$zoomstart
      SPY <- getSymbols("SPY", from="2006-01-01", auto.assign=FALSE)
      SPY <- adjustOHLC(SPY)
      SPY.SMA.10 <- SMA(Cl(SPY), n=10)
      SPY.SMA.200 <- SMA(Cl(SPY), n=200)
      SPY.RSI.14 <- RSI(Cl(SPY), n=14)
      SPY.RSI.SellLevel <- xts(rep(70, NROW(SPY)), index(SPY))
      SPY.RSI.BuyLevel <- xts(rep(30, NROW(SPY)), index(SPY))
       # shinyjs::html(id="DataPull", "-")
    } 
    values$Validate <- runif(1, 1, 10000)
  })

  hc_yAxis_multiples <- function(hc, ...) {

    hc$x$hc_opts$yAxis <- list(...)

    hc
  }

  output$hcontainer <- renderHighchart({
    values$Validate

        if (values$Validate==0)
          return()

    highchart() %>% 
      # create axis :)
      hc_yAxis_multiples(
        list(title = list(text = NULL), height = "65%", top = "0%"),
        list(title = list(text = NULL), height = "10%", top = "72.5%", opposite = TRUE),
        list(title = list(text = NULL), height = "15%", top = "85%")
      ) %>% 
      # series :D
      hc_add_series_ohlc(SPY, yAxis = 0, name = "SPY",smoothed=TRUE,forced=TRUE,groupPixelWidth=240) %>% 
      hc_add_series_xts(SPY$SPY.Volume, color = "gray", yAxis = 1, name = "Volume", type = "column",forced=TRUE,groupPixelWidth=240) %>% 
      hc_add_series_xts(SPY.RSI.14, yAxis = 2, name = "Osciallator",forced=TRUE,groupPixelWidth=240) %>% 
      hc_add_series_xts(SPY.RSI.SellLevel, color = "red", yAxis = 2, name = "Sell level", enableMouseTracking = FALSE,forced=TRUE,groupPixelWidth=240) %>% 
      hc_add_series_xts(SPY.RSI.BuyLevel, color = "blue", yAxis = 2, name = "Buy level", enableMouseTracking = FALSE,forced=TRUE,groupPixelWidth=240) %>% 
      # I <3 themes
      hc_add_theme(hc_theme_538())%>%
      hc_chart(zoomType = "xy") %>%
      hc_xAxis(
        events = list(
          setExtremes = JS('function(event){
                           document.getElementById("ZoomFlag").innerHTML = "Yes";
                           }'),
        afterSetExtremes = JS('function(event){
                              if (document.getElementById("ZoomST").innerHTML!="-") {
                              var start = document.getElementById("ZoomST").innerHTML;
                              var end = document.getElementById("ZoomEND").innerHTML;
                              } else  {
                              var start = this.getExtremes()["min"];
                              var end = this.getExtremes()["max"];   
                              }
                              var timeDiff = Math.abs(parseInt(end) - parseInt(start));
                              var diffDays = Math.ceil(timeDiff / (1000 * 3600 * 24));

                              if (document.getElementById("ZoomFlag").innerHTML=="Yes" && diffDays<365) {
                              if (document.getElementById("DataPull").innerHTML=="-"){
                              alert("Hello");
                              document.getElementById("DataPull").innerHTML="PullIt";
                              //document.getElementById("ZoomFlag").innerHTML = "-";
                              alert(document.getElementById("DataPull").innerHTML);
                              document.getElementById("ZoomST").innerHTML= this.getExtremes()["min"];
                              document.getElementById("ZoomEND").innerHTML= this.getExtremes()["max"];
                              alert(document.getElementById("ZoomST").innerHTML);
                              clearTimeout();
                              setTimeout(function(){
                              Shiny.onInputChange("zoomstart", start)
                              Shiny.onInputChange("zoomend", end)
                              }, 1);
                              } else {    clearTimeout();
                              document.getElementById("ZoomFlag").innerHTML = "-";
                              document.getElementById("ZoomST").innerHTML= "-";
                              document.getElementById("ZoomEND").innerHTML = "-";
                              alert(document.getElementById("ZoomFlag").innerHTML);
                              alert("This is when we need to chart to set extremes");
                              setTimeout(function(){
                              Highcharts.charts[0].xAxis[0].setExtremes(start,end);
                              }, 1);
                              }
                              } else {
                              alert(document.getElementById("ZoomFlag").innerHTML);
                              }
                          }')
                      )
      )%>%
  hc_rangeSelector(buttons=list(
    list(type= 'month',count= 1,text= '1m'),
    list(type= 'month',count= 3,text= '3m'),
    list(type= 'month',count= 6,text= '6m'),
    list(type= 'ytd', text= 'YTD'),
    list(type= 'year',count= 1,text= '1Y'),
    list(type= 'year',count= 3,text= '3Y'),
    list(type= 'year',count= 5,text= '5Y'),
    list(type= 'year',count= 7,text= '7Y'),
    list(type= 'all',text= 'All')
  ))
})

}

Please let me know if you are able to reproduce my code at your end

jbkunst commented 8 years ago

Hi @debsush

Have you any news about this?

debsush commented 8 years ago

No i did pursue the approach. So i returned to JS

On 26 Sep 2016 20:59, "Joshua Kunst" notifications@github.com wrote:

Hi @debsush https://github.com/debsush

Have you any news about this?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/jbkunst/highcharter/issues/89#issuecomment-249664401, or mute the thread https://github.com/notifications/unsubscribe-auth/AOYQSeacvCOdjt2hXp0FQ9WUpkv2MagFks5quBYlgaJpZM4IUC2S .