domainpad: pixel spacing inside axis domains - #7965
Draft
SharadhNaidu wants to merge 4 commits into
Draft
Conversation
`domain` is a plot fraction, so the gap it leaves between subplots grows and shrinks with the figure while a subplot title does not. domainpad reserves a fixed number of pixels inside the domain edges instead, resolved at draw time. Applied in ax.setScale to _offset and _length rather than to ax.domain, so the domain keeps meaning what the user typed and anything referenced to `<axis> domain` follows the padded area without new drawing code. Along with it: - scattergl, splom and the rangeslider rebuilt the plot rect from `domain` and so did not see the pad; they now read _offset and _length - pads that do not fit are backed off together, since setScale already throws on a negative length - updateDomain scales the padded length rather than the raw span, so a scaleanchor ratio stays exact when the constraint shrinks a padded axis Refs plotly#7835
Removed attribution from the commit message.
The three places that build the plot rect from `domain` were changed to read _offset and _length instead. That round trips through pixel space, and the result is not exactly the value it started from: splom cell domains came back about one ulp out, which moved rasterised markers enough to fail the splom_*-nodiag image baselines even though no padding was involved. Add the resolved padding to the original expressions instead, and expose it as ax._padStart / ax._padEnd for those callers. Adding a literal zero is exact, so an unpadded plot now produces the same numbers it always did. Also list domainpad in swapAxisGroup's noSwapAttrs, next to domain: its keys are named for screen edges, so swapping x and y would need them remapped.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
draft spike for #7835, following the approach A direction @emilykl picked in
#7835 (comment). not asking for a
merge yet, the api is still open and three things in here are questions rather than
decisions. happy to rework any of it.
this is the plotly.js half of plotly/plotly.py#5606.
what it adds
layout.xaxis.domainpadandlayout.yaxis.domainpad, pixels reserved inside the edges ofdomain.leftandrighton x axes,topandbottomon y axes, as sketched in theissue.
domainis a plot fraction, so the gap it leaves between subplots grows and shrinks withthe figure. a subplot title does not, it is a fixed number of pixels. that mismatch is
#5606. here is the repro from that issue, rendered on this branch before and after:
the only change between them:
the reserved band is the same pixel height at 300px, 600px and 1200px tall, which is the
part plotly.py cannot do from its side.
how it works
the pad is applied in
ax.setScale, to_offsetand_length, andax.domainis leftexactly as the user typed it:
that is the whole drawing change. everything referenced to
<axis> domainalready reads_offsetand_length, so annotations, shapes, shape labels and images all land on thepadded area with no extra code. titles are not a special case.
it also keeps out of the way of
constrain: 'domain', which already rewritesax.domainat draw time and restores it from
ax._inputDomain.three things worth a second opinion
1.
scattergl,splomand the rangeslider moved onto_offsetand_length. theywere rebuilding the rect from
domain, so they did not see the pad. a 40px pad put the glrect 40px off the svg one, and the rangeslider came out 90px too wide with
domainpad: {left: 60, right: 30}. the honest cost of this route is thatdomainstopsbeing the one place the plot rect comes from. if you would rather the pad rewrote
ax.domainand left those alone, that is a smaller change and i am happy to switch.2. clamping. six stacked subplots asking for 60px each in a 200px figure throws
Something went wrong with axis scaling, sincesetScalealready errors on a negativelength. the pads are backed off together the way
doAutoMargindoes with margins, keepinga 2px floor because that guard is
< 0and a length of exactly 0 would slip past it.3. a small fix in
constraints.js.updateDomainscaled the domain span by thefactor, which assumes drawn length moves with the fraction. the pad takes fixed pixels off
the end, so only
(span - pad)scales. with a pad on the axis the constraint shrinks, ascaleanchorratio came out 1.0234 instead of 1. it now divides the padded length and addsthe pad back, giving 1 exactly.
scope
cartesian only, deliberately. polar, ternary, geo, map, smith and the domain traces take
their domains from
src/plots/domain.jsand each converts to pixels in its own file, sothey are a separate and much wider change. #5606 needs nothing beyond cartesian.
tests
13 specs in
test/jasmine/tests/axes_test.jsunderaxis domainpad, covering defaults andcoercion, padding on each side, the same pixels held at 300/600/1200px, the clamp,
overlayinginheritance, a domain referenced annotation landing in the band,scaleanchorwith the pad on either side of the constraint, the rangeslider, and geometry holding across
log, date, reversed, category, inset and
layout.gridlayouts.npm run lintclean,test/plot-schema.jsonregenerated,dist/untouched.