xts icon indicating copy to clipboard operation
xts copied to clipboard

Allow for log scale of the y axis

Open rossb34 opened this issue 10 years ago • 1 comments

Allow for log scale of the y axis. This is supported by base::plot and PerformanceAnalytics::Chart.TimeSeries so we should support it in plot.xts as well. Thanks to Gei Lin for the feature request via R-SIG-Finance.

rossb34 avatar Jun 09 '15 14:06 rossb34

just some notes for myself:

  • use devtools::load_all() to build and load the package from source w/ namespace and bindings that work for interactive debugging. just modifying and source()-ing files runs into a plethora of issues.
  • set_window is called for each plot. it sets up the coordinate system so that subsequent plotting code renders in the correct place. there is only 1 set_window call for eaxh xts plot, so the coordinates have to account for headers AND multi.panel
  • scale_ranges() produces a unified ylim for all headers and multi.plot regions so that they each render in the correct location using their native coordinates
  • ultimately, log='y'' needs to be passed to plot.window() from set_window().
  • As an example, this happens quite easily during the cs$add_frame(0,ylim=c(0,1),asp=0.5) which sets up the frame for the header. The parameters of this call are intertwined w/ the subsequent text(xlim[1],0.5,..) call that actually produces the title.. While the particular frame for the title should not be log scale the negative ylim from the title affects subsequent processing. there are a few other similar situation
  • each call to plot.xts is treated as a single plot from an R perspective. i.e. the title, subtitles, labels, subcharts for multi.panel are all a single plot. if caller has already partitioned the screen using layout, the whole call to plot.xts renders intot he current plot area. eg: layout(matrix(1:2)); plot(getSymbols("SPY", auto.assign = F), multi.panel = T);plot(getSymbols("SPY", auto.assign = F), multi.panel = T). Same holds true if a nox xts plot is rendered into one of the plots areas

ideas:

  • maybe bult the coordinate transform bottom up, instead of top down. i.e. calculate the header above the main area, instead of the main area below the header. on multi.panel, render panels above the last instead of below the first. just a thought

ethanbsmith avatar Oct 16 '22 17:10 ethanbsmith

We can't simply use plot.window(..., log = "y") because the range for the raw data passed in may include values <= 0, which means log() returns NaN. We will need to scale the data so it only has positive values. And that means we will need to adjust the y-axis labels to represent the actual (not the positive-adjusted) values.

Taking the log of a value <= 0 can also be a problem if we add a panel to the plot. We use the xts plot object asp values to (re-)set the global/device ylim for each panel in order to put the panels in the correct relative locations on the device. This can create negative global ylim value(s) for one or more of the panels, which will cause plot.window(..., log = "y") to error.

So we may need to manually map in/out of log space. Here are some thoughts on what needs to happen if we go that route:

  • Scale the raw data so the min is always 1 before taking the log, and map the y-axis labels (based on the raw data) to their respective scaled values
  • May have to use axTicks() for because pretty() does not support log scales
  • Test if log needs to be global to the plot, or can be by panel (I think it can be by panel)

joshuaulrich avatar Dec 01 '22 21:12 joshuaulrich

dont think the data itself should ever have values <= 0 . neither base nor quantmod plotting currently supports that kind of input. if more talking about negative ranges in the plot area introduced by the multi.plot > 1, then i probably reluctantly agree

ethanbsmith avatar Dec 01 '22 22:12 ethanbsmith

Hmm, guess that wasn't clear. I'm referring to when the raw data has negative values. And that causes plot.window(..., log = "y") to error. So we can't just add log = "y" and be done. For example, plot.window(c(-1, 1), c(-1, 1), log = "y")


EDIT: never mind. I don't know what made me think you could plot negative values in log-scale with plot.default(). For example, this warns about the negative values and doesn't plot them: plot(-1:10, log = "y").

joshuaulrich avatar Dec 01 '22 23:12 joshuaulrich