hafen / trelliscopejs

TrelliscopeJS R Package
https://hafen.github.io/trelliscopejs
Other
263 stars 37 forks source link

Provide general mechanism for axis limit control #4

Open hafen opened 7 years ago

hafen commented 7 years ago

In both facet_trelliscope() and trelliscope(), we need to provide arguments like x_scales and y_scales with options "free", "same", and "sliced" and build a general mechanism for handling these that works with different plotting systems.

Multi-panel displays are generally more useful when scales are aligned in one of the two latter ways, and it should be easy for a user to specify.

For systems like ggplot2 and rbokeh, we can analyze each panel to extract each panel's limits, and then use these to find the appropriate limits to apply to each panel to achieve the desired effect prior to writing the panel out to disk. There is some logic along these lines for trellis and ggplot2 already in the trelliscope package, but it is not robust or very clean (see here and here).

For any candidate graphics system, we could create s3 methods (axis_range_get() and axis_range_set()) for extracting and applying axis limits. For ggplot2 and rbokeh (and maybe lattice), we can write these and bundle them with this package. If these methods don't exist for a plotting system, then the x/y_scales arguments will be ignored with a warning. I think this will only work well with categorical, continuous, or date axes.

schloerke commented 7 years ago

starting on free and same. Sliced will take some effort

hafen commented 7 years ago

Great! In general, once we have get and set methods, the idea is to run over all panels with the get method and collect all the x and y limits. For same, you just get the extent of all the results and then pass this in to the set method prior to writing out each panel. For sliced, it is actually straightforward as well. Instead of getting the extent of all the extracted limits, you get the extent of the range of all the extracted limits, and then in the setter you center the current panel's data such that the axis limits extend to the overall range. If that makes any sense :). I have logic that does this in the trelliscope package, but it's probably easier just to rewrite for this case.

I suppose in the same case, you could just extract the overall limits by not adding in the faceting since we have the whole object.

For free, there's actually nothing that needs to be done.

schloerke commented 7 years ago

I was thinking of implementing the existing ggplot2 "fixed" (same), "free", "free_x", and "free_y". Then adding the functionality of "sliced".

Sounds good!

On Wed, Jan 4, 2017 at 4:28 PM hafen notifications@github.com wrote:

Great! In general, once we have get and set methods, the idea is to run over all panels with the get method and collect all the x and y limits. For same, you just get the extent of all the results and then pass this in to the set method prior to writing out each panel. For sliced, it is actually straightforward as well. Instead of getting the extent of all the extracted limits, you get the extent of the range of all the extracted limits, and then in the setter you center the current panel's data such that the axis limits extend to the overall range. If that makes any sense :). I have logic that does this in the trelliscope package, but it's probably easier just to rewrite for this case.

I suppose in the same case, you could just extract the overall limits by not adding in the faceting since we have the whole object.

For free, there's actually nothing that needs to be done.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/hafen/trelliscopejs/issues/4#issuecomment-270491873, or mute the thread https://github.com/notifications/unsubscribe-auth/AAFsL6ELhd1ikTPNbeeBS3MhLxeJxOI7ks5rPA74gaJpZM4KivxE .

hafen commented 7 years ago

We may have to depart (slightly) from the ggplot2 syntax here if we want to include sliced (which we most certainly do - it's an important case that ideally should be part of ggplot2 as well).

My reasoning for this departure is that right now if you say scales = "free_x" in ggplot2, this automatically implies that the y axis is fixed. But what if you want x to be free and y to be sliced? There are too many combinations to specify in a single string in a nice way.

I think it would be good to optionally allow a vector of length 2 specifying the x and y axes individually as fixed, sliced, or free. If the parameter is a single string, then apply that to both axes. We can also still honor free_x and free_y as special cases so that they continue to provide the type of behavior one would expect with ggplot2.

So all of these would be valid:

scales = "free" # both x and y scales are free
scales = "sliced" # both x and y scales are sliced
scales = c("free", "fixed") # x is free, y is fixed
scales = c("sliced", "fixed") # x is sliced, y is fixed
scales = "free_x" # x is free, y is fixed (ggplot2 behavior)
scales = "free_y" # y is free, x is fixed (ggplot2 behavior)

Also, I favor same over fixed as it has more meaning (fixed seems to imply that you are fixing what the axis limits should be manually or something), but we can stick with fixed to be consistent with ggplot2 expectations.

schloerke commented 7 years ago

I like the length 2 vector. "free_x" will imply c("free", "same") and "free_y" will imply c("same", "free").

Since we're doing something different by allowing for two scale values, changing to "same" makes sense.

On Wed, Jan 4, 2017 at 5:01 PM hafen notifications@github.com wrote:

We may have to depart (slightly) from the ggplot2 syntax here if we want to include sliced (which we most certainly do - it's an important case that ideally should be part of ggplot2 as well).

My reasoning for this departure is that right now if you say scales = "free_x" in ggplot2, this automatically implies that the y axis is fixed. But what if you want x to be free and y to be sliced? There are too many combinations to specify in a single string in a nice way.

I think it would be good to optionally allow a vector of length 2 specifying the x and y axes individually as fixed, sliced, or free. If the parameter is a single string, then apply that to both axes. We can also still honor free_x and free_y as special cases so that they continue to provide the type of behavior one would expect with ggplot2.

So all of these would be valid:

scales = "free" # both x and y scales are freescales = "sliced" # both x and y scales are slicedscales = c("free", "fixed") # x is free, y is fixedscales = c("sliced", "fixed") # x is sliced, y is fixedscales = "free_x" # x is free, y is fixed (ggplot2 behavior)scales = "free_y" # y is free, x is fixed (ggplot2 behavior)

Also, I favor same over fixed as it has more meaning (fixed seems to imply that you are fixing what the axis limits should be manually or something), but we can stick with fixed to be consistent with ggplot2 expectations.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/hafen/trelliscopejs/issues/4#issuecomment-270499646, or mute the thread https://github.com/notifications/unsubscribe-auth/AAFsLxHcggE7MvzwtNK_peNE-Wnne_feks5rPBbBgaJpZM4KivxE .

schloerke commented 7 years ago

going to have to use the output of ggplot2_build(). ran into an issue with trying to set the same y scale when doing a histogram. the "count" is calculated and can't be figured out until after the data is processed.

hafen commented 7 years ago

I wondered if we would run into this. Does it look possible to be able to salvage the ggplot2_build() or do we need to rebuild again after applying the new axes prior to writing out the panels?

schloerke commented 7 years ago

should be able to salvage it, but idk if we should as the scales will change afterwards.

the ggplot_build is about half the time of the ggplot building time.

We can sure try! the build has 'data', 'layout', and 'plot', we should be able to alter that plot object from that point on. Extracting the axis components requires the "ggplot_gtable(built_object)", so that's not an issue.

On Fri, Jan 6, 2017 at 5:07 PM hafen notifications@github.com wrote:

I wondered if we would run into this. Does it look possible to be able to salvage the ggplot2_build() or do we need to rebuild again after applying the new axes prior to writing out the panels?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/hafen/trelliscopejs/issues/4#issuecomment-271022168, or mute the thread https://github.com/notifications/unsubscribe-auth/AAFsL1co99LD6_f8paW5K3ZYYOU5q2jWks5rPrsVgaJpZM4KivxE .

schloerke commented 7 years ago

Don't know why we shouldn't be able to. We would only be shifting the limits, which does not affect the layout or the data. It would only effect the 'plot' object

On Fri, Jan 6, 2017 at 5:13 PM Barret Schloerke schloerke@gmail.com wrote:

should be able to salvage it, but idk if we should as the scales will change afterwards.

the ggplot_build is about half the time of the ggplot building time.

We can sure try! the build has 'data', 'layout', and 'plot', we should be able to alter that plot object from that point on. Extracting the axis components requires the "ggplot_gtable(built_object)", so that's not an issue.

On Fri, Jan 6, 2017 at 5:07 PM hafen notifications@github.com wrote:

I wondered if we would run into this. Does it look possible to be able to salvage the ggplot2_build() or do we need to rebuild again after applying the new axes prior to writing out the panels?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/hafen/trelliscopejs/issues/4#issuecomment-271022168, or mute the thread https://github.com/notifications/unsubscribe-auth/AAFsL1co99LD6_f8paW5K3ZYYOU5q2jWks5rPrsVgaJpZM4KivxE .