geoviews icon indicating copy to clipboard operation
geoviews copied to clipboard

Linked brushing with link_selections doesn't work

Open anitagraser opened this issue 3 years ago • 2 comments

Using holoviews.selection.link_selections with a GeoDataFrame plot + histogram plot, brushing only works in the histogram but not in the map plot.

Tested with holoviews 1.14.2, geopandas 0.9.0, bokeh 2.3.0.

A complete example is available at: https://mybinder.org/v2/gh/anitagraser/movingpandas-examples/main?filepath=tech-demos/linked-brushing.ipynb (particularly the Geopandas GeoDataFrame.hvplot section; the other sections are for comparison)

Alternatively, you can also see the issue here: https://youtu.be/OgJH0xUie8k?t=95

anitagraser avatar Mar 27 '21 20:03 anitagraser

I can replicate the issue using your binder link, thanks. I can't tell if it has to do with it being a GeoDataFrame, because your first and second examples differ not only in using GeoPandas but also because the second one uses GeoViews, which has to project the points for display. I would suspect that it's more about the projections not being handled in the linking than about GeoPandas, and indeed it doesn't work when I change your second example to replace gdf_map = gdf.hvplot(geo=True, tiles='CartoLight', width=400, height=300) with a standard-Pandas GeoViews version:

gdf.loc[:, 'x'], gdf.loc[:, 'y'] = (gdf.geometry.x, gdf.geometry.y)
gdf_map = pd.DataFrame(gdf).hvplot.points(x='x',y='y', geo=True, tiles='CartoLight', width=400, height=300)

But that didn't really clear anything up, because the Pandas GeoViews version behaves differently. Before making a selection on the map the Pandas GeoViews version is fine: image After, the geo plot looks blank: image It's not actually blank; if you zoom out, you can see a blue dot where the original data points are, and a tiny black dot at Null Island (0,0 lat/lon): image If you zoom in on Null Island, it's clear that the selection box is drawn as usual, but very, very tiny and not in the right spot: image So there definitely seem to be projection-related issues with linking, and there may also be some separate GeoDataFrame issue (can't tell yet). @philippjfr ?

jbednar avatar Apr 01 '21 02:04 jbednar

The original issue can be reproduced with the following example:

import geopandas as gpd
import geoviews as gv
import holoviews as hv
from holoviews.selection import link_selections
import pandas as pd

gv.extension('bokeh')

gdf = gpd.read_file('../data/ais.gpkg', rows=1000)
pts = gv.Points(gdf, vdims=['SOG'])
df = pd.DataFrame(gdf)
subdf = df.where((df.SOG>0) & (df.SOG<50))
ds = hv.Dataset(subdf)
hist = hv.operation.histogram(ds, dimension='SOG', bins=20).opts(width=400, height=300)
link_selections(pts + hist)

I get this warning when trying to box-select points on the map:

linked_selection aborted because it could not display selection for all elements: One or more dimensions in the expression ((dim('Longitude')>=11838135905465984)&(dim('Longitude')<=11858164865448021))&((dim('Latitude')>=5768261393401959)&(dim('Latitude')<=5768874941228565)) could not resolve on ':Dataset [Timestamp,MMSI,NavStatus,SOG,COG,Name,ShipType,geometry,x,y]' Ensure all dimensions referenced by the expression are present on the supplied object on ':Histogram [SOG] (SOG_count)'.

As nicely explained by the warning, the Latitude/Longitude dimensions aren't found in the histogram object so the linked selection that is based on dimension ranges fails going from the points to the histogram. But as theSOG dimension is found in both objects dimensions, the linked selection going the other way works as expected. image

It is the creation of the gv.Points object that derives the Latitude and Longitude dimensions from the GeoDataFrame geometry column. This is also what happens when an hvplot object is created: image

One immediate workaround is to setup an ID in the GeoDataFrame and use the index_cols List parameter offered by link_selections to link the plots based on indexes instead of dimension ranges.

import geopandas as gpd
import hvplot.pandas
import numpy as np
import pandas as pd

gdf = gpd.read_file('../data/ais.gpkg', rows=1000)
gdf['id'] = np.arange(len(gdf))
gdf_map = gdf.hvplot(geo=True, tiles='CartoLight', width=400, height=300)
gdf_hist = pd.DataFrame(gdf).where((gdf.SOG>0) & (gdf.SOG<50)).hvplot.hist("SOG",  bins=20, width=400, height=300)
link_selections(gdf_map + gdf_hist, index_cols=['id'])

image

maximlt avatar Nov 22 '21 21:11 maximlt