Uh oh!
There was an error while loading. Please reload this page.
Rangeslider allow zoom on oppaxis - #2364
Conversation
Thanks for the PR. Impressive work and clear explanation! But I have to say I'm not 100% sure the current behavior is incorrect. It might just be a matter of preference. Perhaps we can add an attribute e.g. |
TomDemulierChevret
commented
Feb 16, 2018
Just added a new attributes |
TomDemulierChevret
commented
Feb 16, 2018
Not really sure why the last test is failling, any hint from your side ? |
| 'If visible, perpendicular axes will be set to `fixedrange`' | ||
| ].join(' ') | ||
| }, | ||
| perpendicularaxesinitialrange: { |
There was a problem hiding this comment.
This is probably a little to verbose for our needs. Attribute names rarely have more than two words smashed together.
The best option that comes to my mind is xaxis.rangeslider.fixedanchor: false || true, but anchor is used already elsewhere to declare a different thing.
Looking for opinions from @alexcjohnson@cldougl and @chriddyp
There was a problem hiding this comment.
Yeah, I find it also too verbose but I prefered to use a clear name until we have a better proposal (since anchor is already used).
There was a problem hiding this comment.
given that the range slider is always an x axis, we could use something like fixedyrange - and if we ever make a y axis range slider it can get a fixedxrange attribute.
There was a problem hiding this comment.
It does makes sense, I was not quite sure rangeslider was for x-axis only.
etpinard
commented
Feb 16, 2018
We've been fighting some intermittent test failures lately. Your latest commit is now ✅ |
alexcjohnson
commented
Feb 16, 2018
referencing also #2172 - I love the effect here @TomDemulierChevret, just want to make sure we have a path forward when we add potentially stacked multiple axes. I guess it just means we'd end up with multiple clear and shaded regions stacked up, which should be fine. |
By stacked multiple axes, you're referencing multiple x-axis right ? edit : just saw the issue you're referencing. |
| } | ||
| // store the initial range for the rangeslider if we zoom on oppaxis | ||
| if((isNew && ax.fixedrange === false) || (overwrite && hasChanged)) { | ||
| ax._rangesliderInitialRange = ax.range.slice(); |
There was a problem hiding this comment.
Hmm, one issue with this: _rangesliderInitialRange isn't part of the figure JSON... so if you zoom in on the y axis, then you decide you like the plot and you save it, or you snapshot it even, the rangeslider y axis will not have the same range in the snapshot or when you reopen the plot.
That seems to me to mean that we need a real attribute for the range of each y axis on the rangeslider, and perhaps even an attribute for whether to autorange that y axis on the range slider - it would be cool if the y axis could be told to autorange in the range slider even if you start out zoomed in on the main plot, wouldn't it?
BTW I came to this realization as I was thinking "what tests should we have for this feature", noting that a big part of this is drawing code so it should have an image test, but then realizing as it stands we can't make an image test because we have no mechanism to force _rangesliderInitialRange to be different from the y axis range in an image test, therefore we can't make the opp axis masks appear there.
There was a problem hiding this comment.
Right, I didn't think about that.
I'll look into it.
Added new attributes to the figure JSON as suggested by @alexcjohnson.
Not sure exactly what id did broke for the |
alexcjohnson
commented
Feb 20, 2018
Good call putting the new attributes into the y axis - originally I was thinking that they belonged in the
I'll try out |
| // style constants | ||
| maskColor: 'rgba(0,0,0,0.4)', | ||
| maskOppColor: 'rgba(0,0,0,0.2)', |
There was a problem hiding this comment.
Just noticed this. Why pick a different opacity value here?
There was a problem hiding this comment.
I like this effect - you see that the y axis is constrained, but it's not shaded as darkly as the x axis constraint, which aligns with the fact that you can only affect the x axis constraint with the range slider handles.
But a different thought occurred to me on looking at this: this is semitransparent black, so does that mean range sliders don't work on a black background? That's a totally separate issue, doesn't need to be addressed in this PR, but we should look into it.
There was a problem hiding this comment.
Indeed, that's what I wanted to show with the 2 different values of opacity.
And yeah, the black backgrond will be an issue.
etpinard
commented
Feb 20, 2018
Hmm. I think people will inevitably confuse Perhaps, it would have been best to make range sliders a root layout component? 😡 Oh well, for now I can think of 3 options: // option 1
xaxis: {rangeslider: {// ...}},yaxis: {// finding a good concise name for this thing is very hardoppositerangeslider: {mode: ' ',range: [/* */],}}// option 2xaxis: {rangeslider: {yrangemode: ' ',yrange: [/* */],y2rangemode: ' ',y2range: [/* */],// ...}},// option 3 - which would be more similar to other // attributes with axis countersxaxis: {rangeslider: {rangemodey: ' ',rangey: [/* */],rangemodey2: ' ',rangey2: [/* */],// ....}After writing the 3 options down, I'd say I prefer option 3 by far. It keeps range sliders attributes contained in their base x-axis object. While axis counters (e.g. 'y', 'y2', 'y3', ...) aren't great, they are already a pretty big part of the plotly.js api. Thoughts? |
alexcjohnson
commented
Feb 20, 2018
I was hoping to avoid something like that, but I just realized there's a use case where we need to do it this way. Kinda convoluted, but imagine you have two side-by-side x axes sharing a y axis, each x axis has its own range slider, and you want different range settings for the y axes in the two rangesliders. Would be weird, as the y axes on the main plots are one axis so they must share a range... but I guess I can imagine wanting to restrict the range of the y axes in each range slider to just the data on the respective subplot. This is not possible with Option 3 is pretty good, but let me add one more to the mix: xaxis: {rangeslider: {yaxis: {range: [/* */],rangemode: ' '},yaxis2: {range: [/* */],rangemode: ' '},}} |
alexcjohnson
commented
Feb 20, 2018
(@TomDemulierChevret sorry for the back-and-forth here, attribute specs can be really tricky to get right, especially when we start thinking of all the possible edge cases involved) |
etpinard
commented
Feb 20, 2018
@alexcjohnson oh right, true. A given y axis can be linked to multiple x range sliders in general. Nice catch!
I like it, but I still prefer my option 3 by a slight margin (mainly due to possible confusion between We could also do something like: xaxis: {rangeslider: {oppaxis: {rangemode: ' ',range: [/* */]},oppaxis2: {}}}that way, the same But really, maybe we should thinking about pulling layout: {xaxis: {},yaxis: {},yaxis2: {},rangesliders: [{xref: 'x',yref: ['y','y2'],xaxis: {range: [/* */],// equivalent to current `xaxis.rangeslider.range`/// style attributes ...},yaxis: {rangemode: ' ',range: [/* */]}}] |
etpinard
commented
Mar 7, 2018
@TomDemulierChevret would if be ok if we start pushing a few commits to this branch directly? We're very close to merging your PR. Thanks again for all your efforts! |
TomDemulierChevret
commented
Mar 7, 2018
Yes of course, no problem. |
| yaxis3: {} | ||
| }); | ||
| expect(out).toBeUndefined(); |
There was a problem hiding this comment.
As promised in https://github.com/plotly/plotly.js/pull/2364/files#r171957082
Please note, the _isSubplotObj flag in the range slider opposite axis attributes is very important. Without it, this test would spit out:
that is Plotly.validate would think that rangeslider.yaxis2 and rangeslider.yaxis3 aren't part of the schema.
…ulierChevret/plotly.js into rangeslider-allow-zoom-on-oppaxis
| // the logic is complicated to figure this out later, particularly for y axes since | ||
| // the settings can be spread out in the x axes... so instead we'll collect them | ||
| // during supplyDefaults | ||
| containerOut._rangesliderAutorange = false; |
| var rangeMode = coerceRange(rangeContainerIn, rangeContainerOut, 'rangemode', rangemodeDflt); | ||
| if(rangeMode !== 'match') { | ||
| coerceRange(rangeContainerIn, rangeContainerOut, 'range', layoutOut[yName].range.slice()); | ||
| coerceRange(rangeContainerIn, rangeContainerOut, 'range', yAxOut.range.slice()); |
There was a problem hiding this comment.
Ok. Looks like rangeslider.yaxis?.range is still getting coerced when rangemode: 'auto' though this appears standard for subplot xaxis and yaxisrange under autorange: true, so this sounds fine 👌 .
That said, it would be nice in the future to make:
Plotly.validate([],{xaxis: {autorange: true,range: [0,1]}})spit out an unused log message for xaxis.range
| }, | ||
| "title": "Rangeslider Y2 rangemode fixed" | ||
| }, | ||
| "yaxis": {"type": "log", "range": [2, 6], "title": "Y explicit range"}, |
| values: ['auto', 'fixed', 'match'], | ||
| dflt: 'match', | ||
| role: 'style', | ||
| editType: 'calc', |
There was a problem hiding this comment.
@alexcjohnson we should be able to change these to editType: 'plot', correct?
There was a problem hiding this comment.
oh hmm... actually I don't think we can, it's like ax.autorange which is still calc, because this affects _rangesliderAutorange which determines whether we even bother calculating ax._min/_max during the calc step.
There was a problem hiding this comment.
Ok. I tried switching them to 'plot', but that didn't break any test 😕
| .then(done); | ||
| }); | ||
| it('should update rangeslider x/y ranges when data changes even if main axes are not autoranged', function(done) { |
etpinard
commented
Mar 7, 2018
All right. Time to merge to thing 💃 I'll let @alexcjohnson do the honors after a failing test case for #2364 (comment) is added.
Thanks a million to @TomDemulierChevret for first bringing this issue and persevering through our numerous iterations at solving this problem 💪 I'd like to make this PR an early nominee for community PR of the year 🏆 |
this test fails if rangeslider.yaxis.rangemode or rangeslider.(auto)range doesn't have editType: 'calc'
xapple
commented
Jul 29, 2018
So how do we make the range slider keep a constant y axis with the latest version of plotly? What's the configuration? |



By default we can't currently zoom on the y-axis if we set a rangeslider on the x-axis.
If we write
fixedrange: falsein our y-axis config, it will override the lock put by the rangeslider and allow us to zoom both in x-and y-axis.The issue is that the rangeslider is kinda broken if we zoom on y-axis since it will not keep the initial range on y-axis (like it does for the x-axis).
This PR :
Here is a set of screenshot to illustrate the issue and the PR :
Without zoom
With zoom on y-axis before PR
With zoom on y-axis after PR
If you have multiple y-axis and not all of them are zoomable, then you must add
anchor: 'y'in your x-axis config (withyreplaced with the name of one of the zoomable y-axis).