Search code examples
rquantmod

Getting the subset for a quantmod chartSeries after a call to zooom


After a call to the zooom function (which allows the user to interactively change the zoom of the chart by clicking on the leftmost and rightmost bounds for the zoom), is it possible to get the resulting subset displayed?

The reasons I want this:

  1. To set an appropriate yrange for my chart based on the custom TAs that I've added that would otherwise not be visible, because the automatic yrange is based only the timeseries passed to the original call to chartSeries
  2. To implement functions to pan the chart left and right

Workarounds for these 2 goals that don't involve getting the current subset would also be helpful. Currently the only option I can think of is to avoid the use of the interactive zooom function and just use chartZoom.


Solution

  • The first thing to know is why zoomChart() returns the values you want, but zooom() doesn't.

    zoomChart() does because it calls the function reChart(), which ends with the line invisible(chob). (chob is the name of the object you're after.)

    zooom() doesn't do this. It calls zoomChart(), but it doesn't arrange to pass chob out of the environment within which zoomChart() is being evaluated. You can do that, though, by creating a modified version of zooom()

    I did this by first dumping zooom to a file and then creating an edited function called zooom2:

    require(quantmod)
    dump("zooom", file="zooom2.R")
    

    The three edits I made were:

    1. Replace calls to get.chob() with calls to quantmod:::get.chob(). This is needed because, unlike zooom, zooom2 does not have namespace:quantmod as its enclosing environment.

    2. Assign the output of zoomChart() to the object chob.

    3. Return chob to the calling environment by ending the function with invisible(chob).

    Here's the modified function:

    zooom2 <-
    function (n = 1, eps = 2) 
    {
    for (i in 1:n) {
        cat("select left and right extremes by clicking the chart\n")
        points <- locator(2)
        if (abs(diff(points$x)) < eps) {
        zoomChart()
        }
        else {
        usr <- par("usr")
        xdata <- quantmod:::get.chob()[[2]]@xdata
        xsubset <- quantmod:::get.chob()[[2]]@xsubset
        sq <- floor(seq(usr[1], usr[2], 1))
        st <- which(floor(points$x[1]) == sq)/length(sq) * 
            NROW(xdata[xsubset])
        en <- which(floor(points$x[2]) == sq)/length(sq) * 
            NROW(xdata[xsubset])
        sorted <- sort(c(st, en))
        st <- sorted[1]
        en <- sorted[2] * 1.05
        chob <- zoomChart(paste(index(xdata[xsubset])[max(1, floor(st), 
            na.rm = TRUE)], index(xdata[xsubset])[min(ceiling(en), 
            NROW(xdata[xsubset]), na.rm = TRUE)], sep = "::"))
        }
    }
    cat("done\n")
    invisible(chob)
    
    }
    

    You can source or paste the function back into your R session, and then use it like this (for example):

      data(sample_matrix)
      chartSeries(sample_matrix)
      d <- zooom2()
      # Click to interactively zoom in
    
      # extract the data visible in the selected region
      d_sub <- d@xdata[d@xsubset,]
      head(d_sub)
    #                Open     High      Low    Close
    # 2007-03-28 48.33090 48.53595 48.33090 48.53595
    # 2007-03-29 48.59236 48.69988 48.57432 48.69988
    # 2007-03-30 48.74562 49.00218 48.74562 48.93546
    # 2007-03-31 48.95616 49.09728 48.95616 48.97490
    # 2007-04-01 48.94407 48.97816 48.80962 48.87032
    # 2007-04-02 48.90488 49.08400 48.90488 49.06316
    

    If this is something that's useful to you, you might want to add it to the quantmod sources, and recompile your own version of the package.

    Hope this helps.