Hi there,
I have made an involved Panel app in which I’m showing some hv.Points through a DynamicMap overlayed by a curve and a tile_map in the background. Despite setting framewise=True xlim=xlim, ylim=ylim
for the DyamicMap, the axis ranges still don’t act as desired.
I have several datasets that I can pick from through a selector. Each dataset is from different area around the globe, so I want the plot to zoom in to the corresponding area when I select a different dataset.
Here’s a minimum example which is not showing the problem exactly because it’s simplified. Still after changing the “state” several times through the selector you can see that the plot gets distorted.
I’ve also tried gv.Points, but no map shows in the background at all, so I switched to hv.Points.
# https://discourse.holoviz.org/t/using-box-select-to-return-a-filtered-dataframe/4582/2
import pandas as pd
import holoviews as hv
import geoviews as gv
import panel as pn
from holoviews import streams
import cartopy.crs as ccrs
pn.extension(sizing_mode='fixed')
# create dataset
states={
'WA': pd.DataFrame({
'longitude': [-122.3328, -122.4443],
'latitude': [47.6061, 47.2529],
'city': ['Seattle', 'Tacoma'],
'population': [733919, 219205],
'x':[-1.361803e+07, -1.363044e+07],
'y':[6.041572e+06, 5.983452e+06],
'label':['A', 'B']
}),
'OR': pd.DataFrame({
'longitude': [-122.6784, -123.0351],
'latitude': [45.5152, 44.9429],
'city': ['Portland', 'Salem'],
'population': [641162, 177723],
'x':[-1.365650e+07, -1.369620e+07],
'y':[5.702997e+06, 5.612537e+06],
'label':['B', 'A']
}),
'NY': pd.DataFrame({
'longitude': [-74.0060, -78.8784],
'latitude': [40.7128, 42.8864],
'city': ['New York', 'Buffalo'],
'population': [8468000, 256304],
'x':[-8238310.0, -8780703.0],
'y':[4970072.0, 5294697.0],
'label':['B', 'A']
}),
}
# Selector to pick a dataset
state_selector = pn.widgets.Select(name='State', options=list(states))
# map for the background
tile_map = gv.tile_sources.OSM.opts(
global_extent=False,
# normalize=True,
# apply_ranges=True,
# padding=.9,
width=500,
height=500,
)
# plot points
geo_opts = dict(
xlabel="Longitude",
ylabel="Latitude",
default_span=2.0, # Defines the span of an axis if the axis range is zero
tools=["box_select", "hover"],
projection=ccrs.GOOGLE_MERCATOR,
)
@pn.depends(state_selector.param.value)
def get_plot(option):
'''
Get points plot for selected state
'''
# boundsxy.bounds=(0,0,0,0)
df = states[option]
pad = 3200 # for better visibility of border line points
points = hv.Points(
df,
kdims=["x", "y"],
vdims=['city','label']
).opts(
color="purple",
size=15,
# responsive=True,
xlim=(df.x.min() - pad, df.x.max() + pad),
ylim=(df.y.min() - pad, df.y.max() + pad),
)
return(
points.opts(**geo_opts) # * tile_map
)
iplot = pn.bind(get_plot,state_selector.param.value)
source = hv.Curve({})
boundsxy = streams.BoundsXY(source=source, bounds=(0,0,0,0))
@pn.depends(boundsxy.param.bounds)
def data_view(bounds):
'''
Show detailed info in a table format for BoxSelected points
'''
if bounds == (0, 0, 0, 0):
return pd.DataFrame(columns=['longitude', 'latitude', 'city', 'population', 'x', 'y'])
x_start, y_start, x_end, y_end = bounds
df = states[state_selector.value]
box_selected_points = df[
(df['x'].between(x_start, x_end))
& (df['y'].between(y_start, y_end))
]
return box_selected_points
# Note: "framewise" is not in "hv.help(hv.DynamicMap)". I came accross it through a post in discourse.
# Same for "data_aspect".
comp2 = pn.Column(
pn.Row(
(hv.DynamicMap(iplot).opts(framewise=True) * source * tile_map).opts(data_aspect=1),
state_selector
),
data_view,
)
comp2
Any tips are appreciated.