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

Geo refactor and lasso/select-box selections #2030

Merged
merged 42 commits into from
Sep 28, 2017
Merged

Conversation

etpinard
Copy link
Contributor

In brief, this PR brings geo subplots up-to-speed with other subplots. 🚀

Geo subplots have long suffered from a few design mistakes (e.g. as discussed #292 and #1486). This PR attempts to solve these issues - which are required to make lasso/select-box selections work.

Since the geo subplot constructor code was mostly rewritten (see 4c1ddb8), I decided to include the new lasso/select-box logic in this PR as well. I hope the reviewers won't mind. You may consider geo as a new subplot type and this its introduction PR.


What's inside this PR:

Stuff implemented:

peek 2017-09-21 23-10

Stuff fixed:

Baseline updates:

Unfortunately, all geo baselines had to be updated.

  • Most geo subplots now render a few pixels off their position in the old baselines (see a30beea).
  • The center of some scoped maps are shifted (see be59f69) due to the new default logic (of a0be087).
  • Maps with conic projections needed to be updated for similar reasons (see 32a29c7).
  • Finally, geo_fill was adapted to showcase the new geo.center attribute (see 36833d4)

Stuff I could do in this PR, but could wait for v2:

  • Rename (+ cleanLayout map) geo.projection.scale ➡️ geo.zoom (as in mapbox subplots)
  • Rename (+ cleanData map) choropleth z ➡️ values (similar to pie traces)

Open items:

  • Base layer ordering changes whenever a choropleth trace is present on the subplot (see this block). This logic is meant to preserve backward compatibility (i.e. to mimic what that block does in the current master). But really, we should make the base layer ordering consistent for all trace type combinations in v2. But in the meantime, we should make the base layer ordering customizable (similar to axis.layer).
  • Rewrite drag interactions using dragElement (i.e. get rid of d3.behavior.drag) and implement dragmode: 'zoom'` zoombox
  • Make scattergeo/plot.js update inner nodes instead of purging them. This is required for smooth animations and should be a performance boost.

Stuff I believe should wait for v2:

  • Make geo subplot respect the scrollZoom config option No way to disable mouse-scroll zoom for geo subplots #143. Unfortunately. geo assumes scrollZoom: true, but the scrollZoom default is faise. We could add some logic to make scrollZoom default to true if a geo subplot is present to preserve backward compatibility, but that hardly sounds worth it (to me at least).
  • Replace PlotlyGeoAssets global with some field on Plotly. No need to have another global variables, but this isn't a huge priority.

cc @alexcjohnson @rreusser @chriddyp @jackparmer @cldougl
and @cpsievert (this here might make him start using geo in the R API 😝 )

Temporarily committed as a new file to help reviewers

New stuff:
- d3-idiomatic base layers updates
- better layer scheme (inspired by ternary)
- persistent projection updates
- cleaner projection scale/translate logic
- faster render (using cached d3 selections)
- `geo.center` was required for persistent map interactions
- make `projection.rotation.lon` default value depend
  on lonaxis range (to get correct view for e.g. #1698)
- use lonaxis range OR rotation lon to determine
  the `geo.center.lon` default
- use lataxis range to determine `geo.center.lat` default
- as now all interactions can be describe using `geo` attributes
- it's about time 🎉
- and emit mocked `plotly_relayout` event on mouseup
- I chose to not call Plotly.relayout directly for performance
  reasons.
- note that we now bind a calcdata item with a ref to geojson
  to the scattergeo line nodes,
  instead of stitching calcdata things onto geojson feature.
- make choropleth trace go though a calc step
- use lib/polygon on hover 🎉,
  instead of old ad hoc mouse-event-on-svg-node way)
- use clean enter/exit/merge d3 pattern instead of inner node purgery
- bind 'real' calcdata items to selections,
  instead of patched geojson objects.
- make sure dragmode is set to 'pan' by default for geo plots
- add select and lasso mode bar button to geo plots
- add updateFx fast relayout pass
- init dragElement instance *just for* lasso and select drag modes,
  note that 'pan' still uses d3's drag abstaction
- with test support.
- with test support.
- 'simply' use the location's centroid to determine
  if it is selected or not.
- while #292 was fixed thanks to `geo.center`,
  it is 🔒 here.
- while #1698 was fixed by the improve geo defaults,
  this 🔒 it down.
- fixed earlier, 🔒 here.
- fixed earlier, 🔒 here.
- this mock shows how to position a non-clipped map
  about a center (lon, lat)
- side effect of new geo center logic
- that were affected by the new `geo.center` logic
- showing new way of doing things with `geo.center`
- fixing an issue-less bug discovered while working
  on this PR.
- which are mostly just offset by a few pixels.
@etpinard etpinard added status: reviewable bug something broken feature something new labels Sep 22, 2017
@etpinard etpinard added this to the v1.31.0 milestone Sep 22, 2017
- move enter-only methods to enter-block
- and use '.style()` instead of `.attr()` for consistency
  with Color and Drawing methods.
- using stashed geo layers
- to 🔒 west <-> east antimeridian crossings
... for hover when out-of-range pts are present in *albers usa* map
- making doModebar update subroutine much more manageable
});
});

it('should not throw during hover when out-of-range pts are present in *albers usa* map', function(done) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

which ✅ #2030 (comment)

Note that I kept the scattergeo-out-of-usa because the image test does 🔒 down the bug fix.

See the rogue point(s) in the upper-left corner:

image

this thing ⏬

image

But yeah, adding a jasmine test documents the behavior better, so here it is.

... when dragging off-screen

- attach handlers to bgRect (not framework), doesn't change
  any thing, but is more consistent.
... to not confuse positions on either side of the globe
- in that case, call Plotly.relayout to reset all
  attributes that could cause the invalid bounds.
- these countries are Russia and Fiji.
- Note that other countries have polygons on either side of
  the antimeridian (e.g. some Aleutian island for the USA),
  but those don't confuse the 'contains' method.
- instead of having components making <g .clips>
  before appending their <clipPath>s
- IMPORTANT: annotation put is clips in fulLayout._defs,
  even though annotation draw in `toppaper`. Now, annotations
  use fullLayout._topclips
@@ -194,7 +194,7 @@ function drawRaw(gd, options, index, subplotId, xa, ya) {

var isSizeConstrained = options.width || options.height;

var annTextClip = fullLayout._defs.select('.clips')
var annTextClip = fullLayout._topclips
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@alexcjohnson IMPORTANT: Annotation used to put its clips in fulLayout._defs, even though Annotation draws in toppaper. Clip ids are global to the page, so things still work fine (at in Chrome and FF). But, who knows maybe some other browsers don't apply clip ids outside the <svg> where the <defs> is located.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice find! Definitely not the intent, thanks for cleaning that up!

@alexcjohnson
Copy link
Collaborator

@etpinard and I discussed bubble opacity a bit more - I was on the fence but he won me over with keeping symmetry with regular scatter. So the behavior introduced here is great.

- ++ cleaner hover polygon logic
- no mutation when offsetting RUS and FJI longitudes
- do not offset RUS and FJI polygons that do not need modification
  for hover!

for(k in this.dataPoints) {
this.dataPoints[k]
.attr('display', hideShowPoints)
Copy link
Contributor Author

@etpinard etpinard Sep 27, 2017

Choose a reason for hiding this comment

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

marker.opacity wasn't applied properly on scattergeo bubbles
Was it just the default being applied improperly, or was opacity not supported before?

This here is why suddenly marker.opacity is applied correctly in scattergeo traces. Previously we used opacity 0 ↔️ 1 to hide points that over the map's edges which erroneously overrode whatever Drawing.pointStyle set. See #1861 (comment) for why we now use display hide/show points.

@etpinard and I discussed bubble opacity a bit more - I was on the fence but he won me over with keeping symmetry with regular scatter. So the behavior introduced here is great.

👌 let's leave it as is.

@etpinard
Copy link
Contributor Author

etpinard commented Sep 28, 2017

If I do Plotly.relayout(gd,{coastlinewidth:10}) (still using geo_orthographic), occasionally (I really can't figure out when ) the viewport shrinks:

(Referencing commits in: geo-refactor+lasso...try-bigger-clippad)

FYI I was able to reproduce the bug using a simple relayout call - see 3ad3d1e

The problem can be fixed by increasing the clipPad geo constant from 1e-3 to 1e-2. Now, why? Without a clipPad some clipped projections (e.g. orthographic), compute different bounds for different geo.projection.rotation values. But this shouldn't happen. Bounds should be a function of the lon/lat axis range only. This is possibly due to rounding errors in d3, but my investigation stopped there.

@alexcjohnson you can uncomment this line to draw the lon/lat range-box polygon on the map if you feel like investigating further.

Bumping clipPath to 1e-2 does affect the baselines - see 3cd0ca5, but not noticeably. The jasmine tests are passing fine.

There might be other situations where clipPath: 1e-2 will fail too. Maybe setting it to 0.1 would be safer. Oh well, I couldn't get geo to break with clipPath: 1e-2.

@alexcjohnson
Copy link
Collaborator

If I do Plotly.relayout(gd,{coastlinewidth:10}) (still using geo_orthographic), occasionally (I really can't figure out when ) the viewport shrinks:

There might be other situations where clipPath: 1e-2 will fail too. Maybe setting it to 0.1 would be safer. Oh well, I couldn't get geo to break with clipPath: 1e-2.

I'm uncomfortable with this solution. For example, what if you zoom in sufficiently that 0.1 (or even 0.01) is a noticeable fraction of the range? I think we need to step back and look into where this is coming from a little closer.

The bug exists on master (in fact it's worse, you just get the top or bottom half of the viewport rather than a centered half, see below) so lets ignore it for this PR and make a new bug report for it.
screen shot 2017-09-28 at 12 32 09 pm

@alexcjohnson
Copy link
Collaborator

💃 🕺 💃 🕺

Fantastic work - so much more solid and well-reasoned!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug something broken feature something new
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants