I'm helping out a Dash community user who could use interactive shape circles (https://community.plot.ly/t/moving-the-location-of-a-graph-point-interactively/7161/1)
I'd like a shape circle that has a fixed size in points but is positioned relative to data - something like a marker point that I can drag around but not necessarily resize.
Right now, circle shapes change size when you drag them around:

This is somewhat related to https://github.com/plotly/plotly.js/issues/2038
Cool idea, and there are a lot of variants of this that could be useful. Even for (fully or partially) paper-referenced shapes, it might be nice to be able to size them in px, like if you want to draw your own arrow pointing to a particular axis value, or you have a logo or something that you want a fixed size even if the plot resizes.
Seems to me the most flexible way to do this would be adding attributes like:
xmode: 'scaled' | 'pixel' // scaled (dflt) -> x0/x1 are data vals or plot units, anchorx is ignored
// pixel -> x0/x1 are pixels relative to anchorx
anchorx: (any) // data val or plot fraction, depending on `xref`
ymode, anchory: same for y
Not sure about the naming, but that would leave the flexibility to do things like make a shape off to the side of a data point, like (x|y)shift for annotations, not just centered.
I think it is worth noting that the API suggested by @alexcjohnson will support two different uses cases:
Despite it increases the API surface, I can clearly see the benefit of having an anchor. When annotating a specific data point you certainly would want the control to render it 3px left the data point, for example.
Regarding the naming, I find anchorx quite good. Might xsizing be more clear than xmode? But I also saw "mode" as parts of an attribute name already. So xmode might be more consistent within plotly.js...
One question, though: Should we take the dimensions of a fixed size shape into account when calculating the range of an axis?
It is clear to factor in the position of a fixed size shape, but when it comes to the dimensions, it could become hairy, right? It could easily be the case that a fixed size shape overflows the plotting area (the green rectangle). To prevent this, we would need to know how "much data" is worth one pixel at the time of calculating the axis range.

This reminds me of how we specify layout images. Attributes sizex, sizey, xanchor, yanchor and sizing could be used in scatter markers too.
Thanks @etpinard for pointing me into that direction. Here are my thoughts.
images layout attributes xanchor and yanchor are about an image's alignment – a different meaning than what we have in the initial proposal for fixed size shapes. Also, image sizex and sizey can't have pixel values.
So because of that, I stuck with the semantics of @alexcjohnson's initial proposal for the time being. Although with slightly different naming. Here's what the API currently looks like in my local branch.
// Shape positioned relative to data
shapes: [{
type: 'rect',
xref: 'x',
yref: 'y',
xsizemode: 'pixel',
ysizemode: 'pixel',
xanchor: '3',
yanchor: '0',
x0: 3,
x1: 25,
y0: 0,
y1: 25
}]
// Shape positioned relative to plot area, in this case top right corner
shapes: [{
type: 'rect',
xref: 'paper',
yref: 'paper',
xsizemode: 'pixel',
ysizemode: 'pixel',
xanchor: '1',
yanchor: '1',
x0: 3,
x1: 25,
y0: 0,
y1: 25
}]
Any feedback on that?
By the way, one can size by pixel horizontally and relative to data vertically and vice versa.
When calculating an axis range the xanchor and yanchor coordinates are taken into account. However, it still needs to be decided whether to factor in the size and position of the shape as well. I lean towards not factoring that in. What do you think?
Any feedback on that?
:+1: from me. Nice!
When calculating an axis range the xanchor and yanchor coordinates are taken into account. However, it still needs to be decided whether to factor in the size and position of the shape as well. I lean towards not factoring that in. What do you think?
In calc_autorange.js, we already take into account the shapes' bounds on auto-ranged graphs. It shouldn't be too hard to extend that to pixel size modes using the ax.p2c (for pixel-to-calculated data) convert method.
Yes, please do include the whole shape in autorange. But don't use ax.p2c to do it - that assumes the axis scaling (ie range & length) is already known, and a) that's what we're trying to calculate with Axes.expand, and b) we'd like this calculation to not need to be redone when the plot changes size, margins, etc.
Fortunately we DO have this built into Axes.expand, in the form of ppad (pixel padding) and its asymmetric variants ppadplus and ppadminus -
https://github.com/plotly/plotly.js/blob/master/src/plots/cartesian/autorange.js#L228-L230
Thanks @alexcjohnson, I've now implemented the correct auto-ranging for lines, rectangles and circles.
However, I wonder what we should do about path shapes. We haven't really discussed that in this thread except @alexcjohnson mentioned arrows in his initial reply. Should we allow pixel sized path shapes as well? It would certainly be a cool feature. But I'm not sure if enough people would use it so that the effort is worth it.
Yes, it'll be more effort to get path working with pixel sizing - but I think we should do it. We don't want any more exceptions in the API than we really need, and even if very few people use it, we'll be able to make some extra-cool demos with this feature.
Yes, it'll be more effort to get path working with pixel sizing - but I think we should do it
we'll be able to make some extra-cool demos with this feature
Yeah, that's pretty interesting. I wonder if this will allow the user to draw an entire line plot and then drag around the vertices, which is what the Dash community member originally asked about in https://community.plot.ly/t/moving-the-location-of-a-graph-point-interactively/7161:
I want to give the user the ability to drag a point on a line graph either up or down, thereby changing the underlying y-axis data (what if analysis). This would then change other charts on the dashboard.
Is this type of interactivity possible through Dash (clicking on and moving a point)?
We don't support editing vertices of path shapes by GUI currently, and while that could be interesting, I feel like dragging data points themselves would be a more valuable feature to add first. Not in this issue though, we can make another issue if there's sufficient interest.
Question about how the coordinate system for specifying fixed size shapes will be expected by the users: The positive x direction will point to the right.
But what about the positive y direction? Will it point to the bottom (as in SVG) or to the top (like the plot's coordinate system)? First, I leaned towards 'to the top'. But I suppose most users are coders, so they might be familiar with positive y-axis pointing 'to the bottom'.
It's true, this is a weird point that requires a lot of minus signs in our code, but I think positive y should be toward the top, no matter whether it's data (unless you explicitly flip the y axis), plot fraction, or pixels.
There's one exception to this, that I know of anyway, and that's annotations[i].ay, which is to the bottom. I think elsewhere "to the top" is consistent enough that we should make anything new be "to the top", and in v2.0 we should flip ay to match (or even before, if we couple the fix with giving this attribute a nicer name, then we can do it in a backward-compatible way).
but I think positive y should be toward the top, no matter whether it's data
+1
To expand an axis with a fixed size path shape, I need to extract the x and y coordinates of the path's d attribute (in order to set the ppadminus and ppadplus of Axes.expand correctly).
There's somewhat similar code in https://github.com/plotly/plotly.js/blob/13eb982ec9700ee9fe6cb8a93ee12d4ee8b0a215/src/components/shapes/draw.js#L325
I could base my code on that. But before doing so, I wanted to ask if there is already a function in the Plotly.js codebase that parses the d path attribute.
That's probably the only place we parse a d path attribute. See if you can generalize that code into a form you can reuse, and feel free to move it to another file that both shapes/draw and your addition (in shapes/calc_autorange?) can import from.
For a pixel-sized shape (rect, line, circle), should x1/y1 be the width/height of the shape relative to x0/y0 or should x1/y1 be relative to xanchor/yanchor? In the latter case width/height would be the distance between x0 and x1/y0 and y1.
I'm asking because right now I've implemented the former case with x1/y1 being the width/height. Unfortunately I overlooked @alexcjohnson initial spec saying
x0/x1 are pixels relative to anchorx
That describes the latter case. I see pros and cons for both approaches.
x1/y1 being the width/height
Pros and cons are the reverse of the above for x1/y1 being absolute (anchor is 0/0).
I should have implemented the initial spec in the first place, sorry. Anyways, there's now the chance to decide if x1/y1 being the width/height is the better way.
In today's check-in meeting we've decided the following: x1 and y1 are going to be absolute coordinates with xanchor and yanchor being the origin. There are certain situations where own way of specifying the dimension would be favorable over the other and vice versa. The absolute approach chosen is better for the most likely case: centering a shape (e.g. a circle) on a data point. And in addition to that, it is more consistent with the existing shapes API.
For the question 'When being moved, should the anchor or the x and y coordinates of a fixed size shape be changed?' it was concluded that the anchor should. This approach is resembling common UI patterns implemented in apps such as Google Slides.
@rmoestl did https://github.com/plotly/plotly.js/pull/2532 close this issue?
@etpinard yes!
Most helpful comment
In today's check-in meeting we've decided the following:
x1andy1are going to be absolute coordinates withxanchorandyanchorbeing the origin. There are certain situations where own way of specifying the dimension would be favorable over the other and vice versa. The absolute approach chosen is better for the most likely case: centering a shape (e.g. a circle) on a data point. And in addition to that, it is more consistent with the existing shapes API.For the question 'When being moved, should the anchor or the x and y coordinates of a fixed size shape be changed?' it was concluded that the anchor should. This approach is resembling common UI patterns implemented in apps such as Google Slides.