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

Add support for Mapillary street level imagery #1035

Merged
merged 2 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 39 additions & 3 deletions docs/maplibre/create_vector.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,28 @@
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import leafmap.maplibregl as leafmap"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To use Mapillary street level imagery, you will need to sign up for a free account at [Mapillary](https://www.mapillary.com/) and get an access token. Please visit [the Mapillary API page](https://www.mapillary.com/developer/api-documentation) for more information on how to get an access token. \n",
"\n",
"Once you have an access token, uncomment the following line and replace `YOUR_ACCESS_TOKEN` with your actual access token."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# os.environ[\"MAPILLARY_API_KEY\"] = \"YOUR_ACCESS_TOKEN\""
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand All @@ -55,6 +74,7 @@
"source": [
"m = leafmap.Map(center=[-74.1935, 40.6681], zoom=15, style=\"liberty\")\n",
"m.add_basemap(\"Satellite\")\n",
"m.add_mapillary()\n",
"m.add_layer_control()\n",
"m.add_draw_control(\n",
" controls=[\"point\", \"polygon\", \"line_string\", \"trash\"], position=\"top-right\"\n",
Expand Down Expand Up @@ -95,7 +115,9 @@
"metadata": {},
"outputs": [],
"source": [
"widget = leafmap.create_vector_data(m, properties, file_ext=\"geojson\")\n",
"widget = leafmap.create_vector_data(\n",
" m, properties, file_ext=\"geojson\", add_mapillary=True\n",
")\n",
"widget"
]
},
Expand All @@ -115,10 +137,24 @@
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python"
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.9"
}
},
"nbformat": 4,
"nbformat_minor": 2
"nbformat_minor": 4
}
22 changes: 22 additions & 0 deletions docs/maplibre/mapillary.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"outputs": [],
"source": [
"m = leafmap.Map(style=\"bright\", center=[-73.99941, 40.71194], zoom=13)\n",
"m.add_basemap(\"Satellite\")\n",
"m.add_mapillary(minzoom=6, maxzoom=14, add_popup=True)\n",
"m.add_layer_control()\n",
"m"
Expand Down Expand Up @@ -126,6 +127,27 @@
"source": [
"common.get_mapillary_image_widget(image_ids[0], style=\"photo\", width=1000)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"m = leafmap.Map(style=\"bright\", center=[-73.99941, 40.71194], zoom=13)\n",
"m.add_basemap(\"Satellite\")\n",
"m.add_mapillary(minzoom=6, maxzoom=14, add_popup=True)\n",
"m.add_layer_control()\n",
"widget = m.create_mapillary_widget(style=\"photo\", width=500)\n",
"widget"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"![image](https://github.com/user-attachments/assets/a67a44ba-b15c-4916-9d88-14a744645364)"
]
}
],
"metadata": {
Expand Down
60 changes: 52 additions & 8 deletions leafmap/maplibregl.py
Original file line number Diff line number Diff line change
Expand Up @@ -3940,6 +3940,7 @@ def add_mapillary(
maxzoom: int = 14,
sequence_lyr_name: str = "sequence",
image_lyr_name: str = "image",
before_id: str = None,
sequence_paint: dict = None,
image_paint: dict = None,
image_minzoom: int = 17,
Expand All @@ -3954,6 +3955,7 @@ def add_mapillary(
maxzoom (int): Maximum zoom level for the Mapillary tiles. Defaults to 14.
sequence_lyr_name (str): Name of the sequence layer. Defaults to "sequence".
image_lyr_name (str): Name of the image layer. Defaults to "image".
before_id (str): The ID of an existing layer to insert the new layer before. Defaults to None.
sequence_paint (dict, optional): Paint properties for the sequence layer. Defaults to None.
image_paint (dict, optional): Paint properties for the image layer. Defaults to None.
image_minzoom (int): Minimum zoom level for the image layer. Defaults to 17.
Expand Down Expand Up @@ -4014,9 +4016,8 @@ def add_mapillary(
"minzoom": image_minzoom,
}

first_symbol_id = self.find_first_symbol_layer()["id"]
self.add_layer(sequence_lyr, name=sequence_lyr_name, before_id=first_symbol_id)
self.add_layer(image_lyr, name=image_lyr_name, before_id=first_symbol_id)
self.add_layer(sequence_lyr, name=sequence_lyr_name, before_id=before_id)
self.add_layer(image_lyr, name=image_lyr_name, before_id=before_id)
if add_popup:
self.add_popup(sequence_lyr_name)
self.add_popup(image_lyr_name)
Expand Down Expand Up @@ -4046,8 +4047,7 @@ def create_mapillary_widget(
radius (float): Search radius for Mapillary images. Defaults to 0.00005.
bbox (Optional[Union[str, List[float]]]): Bounding box for the search. Defaults to None.
image_id (Optional[str]): ID of the Mapillary image. Defaults to None.
style (str): Style of the Mapillary image. Defaults to "classic".
width (int): Width of the iframe. Defaults to 560.
style (str): Style of the Mapillary image. Can be "classic", "photo", and "split". Defaults to "classic".
height (int): Height of the iframe. Defaults to 600.
frame_border (int): Frame border of the iframe. Defaults to 0.
link (bool): Whether to link the widget to map clicks. Defaults to True.
Expand All @@ -4061,9 +4061,11 @@ def create_mapillary_widget(

if image_id is None:
if lon is None or lat is None:
if len(self.center) > 0:
lon = self.center["lng"]
lat = self.center["lat"]
if "center" in self.view_state:
center = self.view_state
if len(center) > 0:
lon = center["lng"]
lat = center["lat"]
else:
lon = 0
lat = 0
Expand Down Expand Up @@ -4096,6 +4098,8 @@ def log_lng_lat(lng_lat):
</iframe>
"""
widget.value = content
else:
widget.value = "No Mapillary image found."

self.observe(log_lng_lat, names="clicked")

Expand Down Expand Up @@ -5212,6 +5216,12 @@ def create_vector_data(
out_dir: Optional[str] = None,
filename_prefix: str = "",
file_ext: str = "geojson",
add_mapillary: bool = False,
style: str = "photo",
radius: float = 0.00005,
width: int = 300,
height: int = 420,
frame_border: int = 0,
**kwargs: Any,
) -> widgets.VBox:
"""Generates a widget-based interface for creating and managing vector data on a map.
Expand All @@ -5237,6 +5247,16 @@ def create_vector_data(
filename_prefix (str, optional): A prefix to be added to the exported filename.
Defaults to "".
file_ext (str, optional): The file extension for the exported file. Defaults to "geojson".
add_mapillary (bool, optional): Whether to add a Mapillary image widget that displays the
nearest image to the clicked point on the map. Defaults to False.
style (str, optional): The style of the Mapillary image widget. Can be "classic", "photo",
or "split". Defaults to "photo".
radius (float, optional): The radius (in degrees) used to search for the nearest Mapillary
image. Defaults to 0.00005 degrees.
width (int, optional): The width of the Mapillary image widget. Defaults to 300.
height (int, optional): The height of the Mapillary image widget. Defaults to 420.
frame_border (int, optional): The width of the frame border for the Mapillary image widget.
Defaults to 0.
**kwargs (Any): Additional keyword arguments that may be passed to the function.

Returns:
Expand Down Expand Up @@ -5279,6 +5299,8 @@ def create_default_map():

prop_widgets = widgets.VBox()

image_widget = widgets.HTML()

if isinstance(properties, dict):
for key, values in properties.items():

Expand Down Expand Up @@ -5336,6 +5358,26 @@ def draw_change(lng_lat):

m.observe(draw_change, names="draw_features_selected")

def log_lng_lat(lng_lat):
lon = lng_lat.new["lng"]
lat = lng_lat.new["lat"]
image_id = common.search_mapillary_images(lon, lat, radius=radius, limit=1)
if len(image_id) > 0:
content = f"""
<iframe
src="https://www.mapillary.com/embed?image_key={image_id[0]}&style={style}"
height="{height}"
width="{width}"
frameborder="{frame_border}">
</iframe>
"""
image_widget.value = content
else:
image_widget.value = "No Mapillary image found."

if add_mapillary:
m.observe(log_lng_lat, names="clicked")

button_layout = widgets.Layout(width="97px")
save = widgets.Button(
description="Save", button_style="primary", layout=button_layout
Expand All @@ -5349,6 +5391,7 @@ def draw_change(lng_lat):

def on_save_click(b):

output.clear_output()
if len(m.draw_features_selected) > 0:
feature_id = m.draw_features_selected[0]["id"]
for prop_widget in prop_widgets.children:
Expand Down Expand Up @@ -5400,6 +5443,7 @@ def on_reset_click(b):
prop_widgets,
widgets.HBox([save, export, reset]),
output,
image_widget,
]

left_col_layout = v.Col(
Expand Down
Loading