-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
rework matching & scaleanchor so they work together #5287
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
Conversation
match-scale partial matches + scaleanchor partial 2 scale-match even more match-scale moremore
Thanks @alexcjohnson ! It seems to work well for our application (see animated gif) : matching subplots have the correct scale anchor. Looking forward to releasing this cool feature soon! :-) |
Great! 🥇 |
var ax2 = getFromId(gd, axId2); | ||
var extremes2 = concatExtremes(gd, ax2, true); | ||
// convert padding on the second axis to the first with lenRatio | ||
var lenRatio = ax._length / ax2._length; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously we calculated autorange for matched axes incorrectly: we just took the minimum and maximum of all the individually-calculated ranges. This is fine when there's no padding around the edges (pixel padding or the 5% "extrapad") but when we have either of these, the simple combination of results gives too little padding. So what I changed to instead is combining the extremes
arrays (sets of min and max items each with its own padding) by converting pixel padding to its equivalent on one axis. Note that this is still compatible with constrain='domain'
because, while it shrinks the axes' _length
, it does so symmetrically across the whole matching group.
Thanks very much for addressing rangebreaks issue as well as the note on extrapad calculations. |
var domain = ax.domain; | ||
if(!domain) { | ||
// at this point overlaying axes haven't yet inherited their main domains | ||
// TODO: constrain: domain with overlaying axes is likely a bug. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one I haven't tested, but it certainly seems problematic to have overlaying axes and use the domain (which would apply to all of them) to satisfy a constraint on just one.
} | ||
|
||
// scales may be numbers or 'x1.3', 'yy4.5' etc to multiply by as-yet-unknown | ||
// ratios between x and y plot sizes n times |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the mock axes_chain_scaleanchor_matches2
for an extreme example of this - chaining matches
and scaleanchor
constraints while going back and forth between the x and y directions will compound the subplot aspect ratios. Probably we won't ever see a plot that takes it to that extreme, but you can imagine for example creating an engineering diagram with front, top, and side views - three subplots so six axes, comprising three matching pairs all scaled together - where you start down this path. So I felt it important to make it work.
links = calcLinks(gd, gd._fullLayout._axisConstraintGroups, xaHash, yaHash, matches); | ||
var spConstrained = links.isSubplotConstrained || matches.isSubplotConstrained; | ||
editX = ew || spConstrained; | ||
editY = ns || spConstrained; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This whole section is badly in need of a rewrite, but I didn't do it here, I just patched it up to work - fixing some existing bugs that are particularly evident in axes_scaleanchor-with-matches
. Ideally we would make it much more explicit what's going on, rather than the very indirect actions happening in dragAxList
, updateMatchedAxRange
, updateSubplots
, and ticksAndAnnotations
.
{ | ||
"mode": "lines+markers", | ||
"x": [ | ||
"2020-05-09", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you look at the baseline for this mock, you can see a bug in the autorange where the left edge gets no padding. This has nothing to do with matching axes, it'll happen on a single axis with rangebreaks, just because the first point is inside a break.
[['yaxis'], yr0, {noChange: true}] | ||
], | ||
dblclickSubplot: 'xy' | ||
}, { | ||
desc: 'drag e on xy', | ||
drag: ['xy', 'e', 30, 30], | ||
exp: [ | ||
[['xaxis', 'xaxis2', 'xaxis3'], [xr0[0], 1.366], {dragged: true}], | ||
// FIXME On CI we need 1.359 but locally it's 1.317 ?? | ||
[['xaxis', 'xaxis2', 'xaxis3'], [xr0[0], 1.359], {dragged: true}], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand what's going on here - just this test and the next one (the two where you're dragging one end of one or two axes) have different results on CI and locally. All the other tests behave identically in both environments, the test is repeatable in each environment, and it's clear that there is a change that's roughly what it should be in both cases. Anyway I set it so CI passes but that means it fails locally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI most of the other changes here are due to the matched axes autorange fixes.
Closes #3539
This PR removes the limitation that any given axis can only be involved in either a
matches
or ascaleanchor
constraint. To ensure consistency of the constraints we create, any given axis can still only supply a single constraint. Specifically, ifmatches
is supplied,scaleanchor
will be ignored within that axis. However one axis may specifymatches
pointing to an axis that specifiesscaleanchor
to a third axis, and so on.For example, to create many subplots whose x axes are all identical, y axes are all identical too, and x and y scales match, you would specify a single
scaleanchor
, typically between x and y on the first subplot but in principle it could be any of the subplots. Then all the other x axes would specifymatches
to that first x axis, and all the other y axes would specifymatches
to that first y axis.Also, as was the case previously, any attribute that creates a circular chain of constraints (given all the attributes we've already processed) will simply be ignored. At best such an attribute would be redundant, and at worst it would be self-contradictory.
Tests still to come, but please give it a try @emmanuelle
scaleanchor
+matches
scaleanchor
+matches
axes_scaleanchor-with-matches
(existing bugs, fixed in this PR):