Skip to content

Commit

Permalink
Add support for Mapillary street level imagery
Browse files Browse the repository at this point in the history
  • Loading branch information
giswqs committed Jan 28, 2025
1 parent 6a0e685 commit 8f4efd9
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 11 deletions.
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
}
58 changes: 50 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 @@ -5212,6 +5214,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 +5245,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 +5297,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 +5356,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 +5389,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 +5441,7 @@ def on_reset_click(b):
prop_widgets,
widgets.HBox([save, export, reset]),
output,
image_widget,
]

left_col_layout = v.Col(
Expand Down

0 comments on commit 8f4efd9

Please sign in to comment.