Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for log scale of the y axis #103

Closed
rossb34 opened this issue Jun 9, 2015 · 4 comments
Closed

Allow for log scale of the y axis #103

rossb34 opened this issue Jun 9, 2015 · 4 comments
Labels
Milestone

Comments

@rossb34
Copy link
Collaborator

rossb34 commented Jun 9, 2015

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.

@ethanbsmith
Copy link
Contributor

ethanbsmith commented Oct 16, 2022

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

joshuaulrich added a commit that referenced this issue Nov 13, 2022
Also add ASCII art to illustrate definitions and layout.

See #103.
@joshuaulrich
Copy link
Owner

joshuaulrich commented Dec 1, 2022

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)

@ethanbsmith
Copy link
Contributor

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

@joshuaulrich
Copy link
Owner

joshuaulrich commented Dec 1, 2022

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 added a commit that referenced this issue Apr 2, 2023
Also add ASCII art to illustrate definitions and layout.

See #103.
joshuaulrich added a commit that referenced this issue Oct 6, 2023
We need to control the y-axis line and label locations for each panel
in order to support a log y-axis in a panel.

See #103.
joshuaulrich added a commit that referenced this issue Oct 6, 2023
The yaxis_expr() function captured the first argument as an expression
and substituted that argument symbol into the y-axis expression to
render. This was more complicated than necessary.

Put all the logic into one single expression, instead of building
multiple expressions and concatenating them together based on arguments
to new_panel(). This required adding 'use_get_ylim', 'draw_left_yaxis',
and 'draw_right_axis' into the panel environment.

Adding 'use_get_ylim' to the panel environment means get_ylim() is only
called once. This improves performance because each call to get_ylim()
calls update_panels().

See #103.
joshuaulrich added a commit that referenced this issue Oct 6, 2023
These values are the same for every point the function is called.

See #103.
joshuaulrich added a commit that referenced this issue Oct 6, 2023
Multi-panel plots were the only time 'use_get_ylim' was TRUE. And the
only time it had any effect was when 'is_ylim_fixed' was also FALSE,
which was only true when 'yaxis.same' was TRUE.

This was one of two times we had to re-calculate the 'ylim' based on
every panel. The other time was when 'ylim' is NULL and 'multi.panel'
was FALSE. And 'is_ylim_fixed' is also FALSE in that case, so we know
to re-calculate 'ylim' whenever 'is_ylim_fixed' is FALSE.

See #103.
joshuaulrich added a commit that referenced this issue Oct 6, 2023
It's hard for me to reason about doing something different when a
boolean is FALSE. It's easier to reason about doing something different
when the boolean is TRUE.

Rename 'is_ylim_fixed' to 'use_global_ylim' and reverse the logic so we
recalculate ylim when 'use_global_ylim' is TRUE.

See #103.
joshuaulrich added a commit that referenced this issue Oct 9, 2023
This creates y-axis labels using the raw series values, instead of the
log series values. So the labels and locations are in round values of
the raw series, but rendered at the logged locations.

See #103.
@joshuaulrich joshuaulrich added this to the 0.13.2 milestone Nov 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants