bokeh icon indicating copy to clipboard operation
bokeh copied to clipboard

Allow relative placement of renderers in dynamically sized parents

Open huaracheguarache opened this issue 2 years ago • 7 comments

Problem description

The current way of specifying positions of labels doesn't allow you to position them relative to the borders of dynamically sized figures in other locations than the lower left corner. I've previously brought this issue up in the Discourse forum: https://discourse.bokeh.org/t/placement-of-label-relative-to-figure/9349

It's very simple to create a label that stays put in the lower left corner even when zooming and panning this dynamically sized figure:

from bokeh.plotting import figure, show
from bokeh.models import Label

fig = figure(title='Label position test')
fig.sizing_mode = 'stretch_both'

fig.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="navy", alpha=0.5)

lower_left = Label(x=5, y=5, x_units='screen', y_units='screen', text='Lower left corner')
fig.add_layout(lower_left)

show(fig)

Screenshot from 2022-07-05 11-25-58

However, if I want to place a label in any of the other corners there's no way for me to do this reliably, because I don't know the size of the figure beforehand.

Feature description

An intuitive way of handling this would be to allow for negative values to offset the labels from the opposite side of the figure. Negative values are supported as coordinates, but they don't function in the way I described:

from bokeh.plotting import figure, show
from bokeh.models import Label

fig = figure(title='Label position test')
fig.sizing_mode = 'stretch_both'

fig.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=20, color="navy", alpha=0.5)

lower_left = Label(x=5, y=5, x_units='screen', y_units='screen', text='Lower left corner')
fig.add_layout(lower_left)

# How can I position this relative to the upper bound of the figure?
upper_left = Label(x=5, y=-5, x_units='screen', y_units='screen', text='Upper left corner')
fig.add_layout(upper_left)

show(fig)

Screenshot from 2022-07-05 11-31-53

Potential alternatives

For the specific example of a label in the upper left corner @bryevdv suggested doing a range callback and updating the y-position of the label whenever the range changes.

Additional information

No response

huaracheguarache avatar Jul 05 '22 09:07 huaracheguarache

To be honest I thought negative screen coordinates already behaved this way, but they don't (or don't any more). Are there any use cases to continue interpreting negative screen coordinates literally? If you really want the result above, a zero coordinate with negative offset should work.

I'd propose to have negative screen coordinates be interpreted as position relative to the opposite end of the frame (e.g. analogous to negative array indices). cc @bokeh/dev

bryevdv avatar Jul 05 '22 13:07 bryevdv

I would expect negative screen coordinates to plot outside the frame, if that's possible. Being able to position relative to the other edges is important, but I wouldn't want to give up negative locations to achieve that (if negative locations are currently respected properly).

If you really want the result above, a zero coordinate with negative offset should work.

Ah, ok, yes, I guess that would work. It still seems a bit strange, because positive coordinates that happen to be outside the current frame would draw outside the frame to the right and top while there's no corresponding behavior from the left and bottom. But yes, that would be usable, so I guess ok.

jbednar avatar Jul 05 '22 20:07 jbednar

@jbednar Currently the inner frame clips most anything that lands outside of it, labels included. That could be changed for labels, but FWIW I can't recall any time anyone has asked to be able to place labels outside the frame. In any case if we do make that change, what is the best way to allow positioning relative to the opposite axis? Saying that y=5 means two different things depending on some other flag seems pretty awkward and confusing.

bryevdv avatar Jul 05 '22 21:07 bryevdv

Yeah, placing outside the frame is largely theoretical. Where I would imagine using it is when there is no frame border and I'm super-tweaking something for publication, but it's a narrow use case. I don't have any proposed syntax; it would all be quite arbitrary.

jbednar avatar Jul 05 '22 22:07 jbednar

PR #12083 adds a symbolic coordinate system that allows relative placement like this. The exact syntax is not yet fully established in that PR at this point, but in the most generic setup, it allows linking position of any node (e.g. a corner) of any renderer with another node (of the same shape) of another renderer, e.g. bottom-left corner of a label with bottom-left corner of the (cartesian) frame, as requested here. This is more robust and generic than what's proposed here, because it doesn't assume whether a potentially negative coordinate would mean positioning top-left to bottom-left or bottom-left to bottom-left (in the proposed case), but allows any combination as needed.

mattpap avatar Jul 06 '22 07:07 mattpap

To be honest I thought negative screen coordinates already behaved this way, but they don't (or don't any more).

As far as I can tell, this never worked and was never tested.

Are there any use cases to continue interpreting negative screen coordinates literally?

Yes, since introduction of subcoordinates, screen coordinates (and cartesian frame in PR #12083) are not special anymore. One can apply the same mappings and transformations to screen coordinates as can with any other coordinate systems. The only thing that's special is the final coordinate system of the canvas. In fact, mapping negative values as proposed in this issue, should already be possible with an appropriately defined coordinate mapping. However, without PR #12083, this requires knowledge of widths/height of canvas, frames, etc., which is either inconvenient or impossible to know in a responsive setup.

If you really want the result above, a zero coordinate with negative offset should work.

If this means using -0, then this is exponentially more finicky than using infinities and nan in other places.

mattpap avatar Jul 06 '22 08:07 mattpap

@mattpap if #12083 handles this than that's great. What will the solution to this issue look like in concrete terms once #12083 is in place?

If this means using -0

No, it meant a negative offset value.

bryevdv avatar Jul 06 '22 14:07 bryevdv