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

feature: add support to zoom into a specific layer #544

Open
ncclementi opened this issue Jun 13, 2024 · 2 comments
Open

feature: add support to zoom into a specific layer #544

ncclementi opened this issue Jun 13, 2024 · 2 comments

Comments

@ncclementi
Copy link

When plotting a Map with multiple layers, I'd like to have an option to zoom in into a specific layer. For example, in this blog https://ibis-project.org/posts/ibis-duckdb-geospatial/ I have some code that plots a point, two lines (over some roads), and the NYC streets, that looks like this

broad_station_layer = ScatterplotLayer.from_geopandas(
    broad_station_gdf, get_fill_color="blue", get_radius=5
)
sts_near_broad_layer = PathLayer.from_geopandas(
    sts_near_broad_gdf, get_color="red", opacity=0.4, get_width=2
)
streets_layer = PathLayer.from_geopandas(streets_gdf, get_color="grey", opacity=0.3)
m = Map(
    [
        broad_station_layer,
        sts_near_broad_layer,
        streets_layer,
    ],
    view_state={"longitude": -74.01066, "latitude": 40.7069, "zoom": 16} # need this to zoom into desired outcome
)
m

Screenshot 2024-06-13 at 2 01 47 PM

However, without specifying the view_state the map displays like this, and the first two layers get completely lost unless I manually zoom in. It would be great if I could zoom in a box around let's say the first two layers or one of them, without having to find what is the lat, lon and specific zoom value.

Screenshot 2024-06-13 at 2 01 28 PM

@kylebarron
Copy link
Member

All layers already have bounding box and weighted centroid attributes that are inferred from the input data.

_bbox = Bbox()
_weighted_centroid = WeightedCentroid()

Currently it's on the Map class to compute a default view state from the union of all input layers:

lonboard/lonboard/_map.py

Lines 445 to 447 in 5560ead

@traitlets.default("view_state")
def _default_initial_view_state(self):
return compute_view(self.layers)

compute_view converts that bbox and weighted centroid to a view state.

def compute_view(layers: List[BaseLayer]):
"""Automatically computes a view state for the data passed in."""
bbox, center = get_bbox_center(layers)
# When no geo column is found, bbox will have inf values
try:
zoom = bbox_to_zoom_level(bbox)
return {
"longitude": center.x,
"latitude": center.y,
"zoom": zoom,
"pitch": 0,
"bearing": 0,
}
except OverflowError:
return {
"longitude": center.x or 0,
"latitude": center.y or 0,
"zoom": 0,
"pitch": 0,
"bearing": 0,
}

I think possibly the cleanest API here is to add a default_view_state attribute onto each layer, which passes the BaseLayer._bbox and BaseLayer._weighted_centroid into compute_view.

Then you'd be able to do

layer = ScatterplotLayer(...)
layer2 = PolygonLayer(...)
map = Map([layer, layer2], view_state=layer.view_state)

That would also let you e.g. override only the zoom, by setting

new_view_state = layer.view_state
new_view_state["zoom"] = 4
map.view_state = new_view_state

I don't have a lot of spare time right now; would you be interested in making a PR?

@ncclementi
Copy link
Author

I'll take a look, but at the moment I'm a bit swamped, but I saw you'll be at Scipy next month, it might be a good place to pair on it and chat also about Ibis + duckdb + lonboard.

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

No branches or pull requests

2 participants