Skip to content

Refactor plot.xts() internals #408

Closed
@joshuaulrich

Description

Original design

plot.xts() is based on quantmod::chart_Series(). The internal structures have a lot of implicit assumptions and some duplicated code, which makes the code harder to reason about and change. For example:

  • There are no explicit "panels", i.e. what is added when addSeries() is called with on = NA. Instead, there is one list of "frames" that contains header and series frames. The odd numbered list elements are the header frames and the even numbered elements are the series frames.
    • Target: store the header and series frames in a panel object.
  • Everything that gets rendered is in one list of "actions". Where the action is rendered is stored in the "frame" attribute of the action.
    • Target: frames should contain actions that are rendered in the the frame.
  • There are separate lists for the ylim and x/y aspect ratio for each frame.
    • Target: frames should contain their ylim and x/y aspect ratio.
  • There are 5 separate code blocks to add y-axis grid lines and labels.
    • Target: the panel should control the y-axis settings.
  • Some functions are always called, even though they're only necessary in certain situations. For example, get_ylim() is always called but only needed when multi.panel = TRUE.
  • The x-axis action is part of the first series frame.
    • Target: the x-axis is the same for the entire plot, so it should be part of the plot object.

The main purpose for this refactor is to make it easier to implement y-axis log scaling (#103).

Refactor target design

The target design attempts to organize the plot components into their respective parts: the plot window, the window panels, and the panel data/actions.

  • The plot object contains the plot title/header (and optional timespan), the x-axis labels and tick marks, and a list of 'panel' objects. The main plot object contains:

    • Env: an environment to hold all the plot information
    • add_main_header(): add the main plot header
    • add_main_xaxis(): add the x-axis labels and ticks to the main plot
    • new_panel(): create a new panel and add it to the plot
    • get_xcoords(): get the x-coordinate values for the plot
    • get_panel(): get a specific panel
    • get_last_action_panel(): get the panel that had the last rendered action
    • new_environment(): create a new environment with Env as its parent
    • Functions that aren't intended to be called externally:
      • update_panels(): re-calculate the x-axis and y-axis values
      • render_panels(): render all the plot panels
      • x_grid_lines(): plot the x-axis grid lines
      • create_ylim(): create y-axis max/min, to handle when max(x) == min(x).
  • The panel object contains:

    • id: the numeric index of the panel in the plot's list of panels
    • asp: the x/y aspect ratio for the panel (relative vertical size)
    • ylim: the ylim of the panel when it was created
    • ylim_render: the ylim of the panel to use when rendering
    • use_fixed_ylim: when TRUE, do not update the panel ylim based on all panel series
    • header: the panel title
    • actions: a list of expressions used to render the panel
    • add_action(): add an action to the actions list
    • yaxis_expr the expression to render the y-axis min/max values, labels, and grid lines/ticks. It also contains the x-axis grid expression because we need the y-axis min/max values to know where to draw the x-axis grid lines on the panel.

Metadata

Assignees

Labels

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions