Skip to content
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

Output bounding box to hover event data #5512

Merged
merged 19 commits into from
Aug 26, 2021
Merged

Output bounding box to hover event data #5512

merged 19 commits into from
Aug 26, 2021

Conversation

rreusser
Copy link
Contributor

@rreusser rreusser commented Feb 18, 2021

Addressing #1323

This PR adds bbox: {x0, x1, y0, y1} data to the points of hover event data. I've so far opted to keep the same format as the original hover data since I think it's very easy understand and doesn't mix coordinates with information about the righthand side of the plot, which I think is best left to the user. (Or at the very least would be useful additional/duplicate information while leaving x0/x1/y0/y1 available.)

A short todo list:

  • fix pie
  • ensure it works with CSS transforms
  • add test(s)

A list of related tasks:

  • figure out the clearest way to convey the meaning of the coordinates
  • create a dash example for server-side hover
  • create a dash example for client-side spinner with server-side hover
  • add specification of hover info to plotly.js docs
  • add examples to dash-docs (partially complete, will submit WIP PR)

Regarding the last point, the coordinates are basically gd.offsetTop + gd.clientTop + offsetWithinPlot. The benefit of this is that positioning hovers within the plot should be very simple. You simply place a hover element as a sibling of the graph div, assign it the coordinates, and it should work without needing to worry about the margins, borders, or the offset parent (nearest element with position: 'relative' | 'absolute'). The downside is that this brings in position information from outside the graph div itself, but I think a reasonable solution is to state that if you want coordinates strictly limited to the plot, you should place HTML hover content and the graph div as direct children of a relative|absolute-positioned element.

Regarding CSS transforms, I think that I just need to apply layout._invTransform to the coordinates within the plot, but I haven't yet confirmed this. In matrix pseudocode, that would make the coordinates [offsetLeft, offsetTop] + [clientLeft, clientTop] + invTransform * [plotOffsetLeft, plotOffsetTop].

The current list of trace types supported is:

  • annotations
  • bar
  • barpolar
  • box
  • candlestick
  • choropleth
  • choroplethmapbox
  • cone
  • contour
  • contourcarpet (no hover info)
  • densitymapbox
  • funnel
  • funnelarea (fixing pie should catch this?)
  • heatmap
  • heatmapgl
  • histogram2d
  • histogram2dcontour
  • icicle
  • image
  • indicator (does not apply?)
  • mesh3d
  • ohlc
  • parcats
  • parcoords (does not apply?)
  • pie
  • pointcloud
  • sankey
  • scatter
  • scatter3d
  • scattercarpet
  • scattergeo
  • scattergl (x coordinate but not y coordinate, somehow??)
  • scatterpolar
  • scatterpolargl
  • scatterternary
  • splom
  • streamtube
  • sunburst
  • surface
  • table (does not apply)
  • treemap
  • violin
  • volume

Obviously some of these aren't so important, but I think if there are some not worth supporting (e.g. pointcloud?), it'd at least be nicely to clearly state expectations around what does happen. I think it should not be too bad to fix the GL plots, which probably mostly goes through loneHover.

Some of them (e.g. ohlc) also require particular knowledge of what the hover points mean since you get a flat list of maybe five points (bounding box, o, h, l, c?), but I think the main thing for now is that the data is there.

@rreusser
Copy link
Contributor Author

rreusser commented Mar 5, 2021

One thing I've noticed about this PR is that Dash rejects any nested properties so that adding bbox: {x0, x1, y0, y1} does not get passed to pointData in dash event data. I've kept them as flat properties at the moment, e.g. offsetX0, so that they end up in pointData in dash.

@alexcjohnson
Copy link
Collaborator

Dash rejects any nested properties

FYI that's here - if a flat object is too cumbersome to work with we can certainly carve out an exception in dcc.Graph to handle the preferred nested structure. I think the purpose of that rejection is so we don't try to include the whole x/y axis objects in the event data that gets serialized and sent to the server, but small nested objects would be fine.

@nicolaskruchten
Copy link
Contributor

Hey guys, what's the status of this PR?

@nicolaskruchten
Copy link
Contributor

This is to feed plotly/dash-core-components#940 right?

@nicolaskruchten
Copy link
Contributor

@archmoj @alexcjohnson what's left here? Can we merge this for 2.3.0?

if ('x0' in pt) out.x0 = pt.x0;
if ('x1' in pt) out.x1 = pt.x1;
if ('y0' in pt) out.y0 = pt.y0;
if ('y1' in pt) out.y1 = pt.y1;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🌴 there's 7 or 8 of these... could be something like copyCoords(pt, out) - could even include the xa/ya-> xaxis/yaxis part, AFAICT only scattercarpet is missing that one, but I bet it wouldn't even hurt to include that.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that information already accessible through plotly_hover? If so, can't we just modify dcc.Graph instead of making this PR?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original mouse event is accessible in plotly_hover, and that contains the pointer location in various coordinate systems. But plotly.js hover events are more sophisticated, and it would be far better if we can match the plotly.js behavior with our new interface.

  • These coordinates mark the data points rather than the mouse.
  • We give the full extent of the location being hovered on. For example, for a vertical bar this is the left and right edges of the top of the bar. For a scatter trace, this is the bounding box of the marker.
  • There can be multiple points in the hover set, each with their own bounding box.

v: pt.v,

// TODO: These coordinates aren't quite correct and don't take into account some offset
// I still haven't quite located (similar to xa._offset)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this doesn't work correctly yet, can we just drop it and leave pie as a TODO?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 03b22ec.

@archmoj archmoj marked this pull request as ready for review July 19, 2021 01:22
@archmoj archmoj added this to the v2.4.0 milestone Aug 24, 2021
var SORTED_EVENT_KEYS = [
'data', 'fullData', 'curveNumber', 'pointNumber', 'pointIndex',
'xaxis', 'yaxis', 'a', 'b', 'c',
'bbox', 'x0', 'x1', 'y0', 'y1'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need x0, x1, y0 and y1 keys here?
They are available in bbox.

if('x1' in pt) out.x1 = pt.x1;
if('y0' in pt) out.y0 = pt.y0;
if('y1' in pt) out.y1 = pt.y1;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need x0 , x1, y0 and y1 in event data? Having bbox in not enough?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we concluded that more was better here, to make it easier for folks in Dash-land.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this correct? For vertical bars y0 is equal to y1 here and in the bbox.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't p0, p1, s0 and s1 used instead of (x|y) (0|1)?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For vertical bars y0 is equal to y1

Yes, y0===y1 for vertical bars. We want the label to be at the end of the bar, not in the middle.

Shouldn't p0, p1, s0 and s1 used instead

The final event data should contain x/y. p/s is not useful to the user for positioning other elements, and that's the purpose here.

@archmoj
Copy link
Contributor

archmoj commented Aug 25, 2021

The x0, y0, x1, y1 positions outside bbox appear to be unused.
So after the revision made in 03b22ec commit x0, y0, x1, y1 re only exposed in the bbox and ONLY for the points that have x and y axes.

@alexcjohnson
Copy link
Collaborator

The x0, y0, x1, y1 positions outside bbox appear to be unused.

Yes, that's OK - currently dcc.Graph drops nested objects from the event so it doesn't try to serialize xaxis & yaxis objects, but in the tooltip PR (which I'm going to have to remake in the monorepo anyway) we're whitelisting this object.

So after the revision made in 03b22ec commit x0, y0, x1, y1 re only exposed in the bbox and ONLY for the points that have x and y axes.

That's fine for right now, but please make an issue to come back to this later and add support for other traces. I'm particularly expecting people will want this to work in pies and 3D.

Copy link
Collaborator

@alexcjohnson alexcjohnson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💃

@nicolaskruchten
Copy link
Contributor

The original issue for this was for 3D... this PR doesn't work for 3D scatter?

@archmoj
Copy link
Contributor

archmoj commented Aug 26, 2021

Right now marker sizes are take into account for scatter points; but not for scattergl points.

@archmoj
Copy link
Contributor

archmoj commented Aug 26, 2021

For image trace the y0 is always equal to y1!

@alexcjohnson
Copy link
Collaborator

y0===y1 isn't a big deal - mostly people will be using the average y value and depending on x0 & x1 to specify the horizontal extent. I wouldn't spend much time investigating all of these now, but later, if folks on the Dash side want to be able to position hover labels above or below the point instead of left/right, we can revisit this as a minor bug.

@archmoj
Copy link
Contributor

archmoj commented Aug 26, 2021

gl3d traces as well as pie, funnelarea, sunburst, treemap and icicle now add bbox to event data.

@archmoj archmoj merged commit ed63090 into master Aug 26, 2021
@archmoj archmoj deleted the external-hover-2 branch August 26, 2021 23:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature something new
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants