From 05105fa285eb798b733e66de556e88c00449c802 Mon Sep 17 00:00:00 2001 From: Qiusheng Wu Date: Sun, 17 Nov 2024 01:24:57 -0500 Subject: [PATCH] Add directional symbol to MapLibre (#981) --- docs/maplibre/add_icon.ipynb | 99 ++++++++++++++++++++++++++++++++++++ docs/maplibre/overview.md | 6 +++ leafmap/leafmap.py | 6 +++ leafmap/maplibregl.py | 60 ++++++++++++++++++++++ mkdocs.yml | 1 + 5 files changed, 172 insertions(+) create mode 100644 docs/maplibre/add_icon.ipynb diff --git a/docs/maplibre/add_icon.ipynb b/docs/maplibre/add_icon.ipynb new file mode 100644 index 0000000000..56a0627d94 --- /dev/null +++ b/docs/maplibre/add_icon.ipynb @@ -0,0 +1,99 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[![image](https://jupyterlite.rtfd.io/en/latest/_static/badge.svg)](https://demo.leafmap.org/lab/index.html?path=maplibre/add_icon.ipynb)\n", + "[![image](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/opengeos/leafmap/blob/master/docs/maplibre/add_icon.ipynb)\n", + "[![image](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/opengeos/leafmap/HEAD)\n", + "\n", + "**Add a directional icon to the map**\n", + "\n", + "The notebook demonstrates how to add a directional icon to the map.\n", + "\n", + "Uncomment the following line to install [leafmap](https://leafmap.org) if needed." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install \"leafmap[maplibre]\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import leafmap.maplibregl as leafmap" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To run this notebook, you will need an [API key](https://docs.maptiler.com/cloud/api/authentication-key/) from [MapTiler](https://www.maptiler.com/cloud/). Once you have the API key, you can uncomment the following code block and replace `YOUR_API_KEY` with your actual API key. Then, run the code block code to set the API key as an environment variable." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# import os\n", + "# os.environ[\"MAPTILER_KEY\"] = \"YOUR_API_KEY\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "m = leafmap.Map(style=\"3d-terrain\")\n", + "url = \"https://github.com/opengeos/datasets/releases/download/hydrology/streams.geojson\"\n", + "m.add_geojson(url, name=\"Streams\")\n", + "m.add_layer_control()\n", + "image = \"https://i.imgur.com/ZMMvXuT.png\"\n", + "m.add_symbol(\n", + " image, source=\"Streams\", icon_size=0.1, symbol_placement=\"line\", minzoom=10\n", + ")\n", + "m" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![image](https://github.com/user-attachments/assets/b4082d29-b604-4f52-a7e7-88d15d37c7fc)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "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": 4 +} diff --git a/docs/maplibre/overview.md b/docs/maplibre/overview.md index 0677099d82..3061b3327f 100644 --- a/docs/maplibre/overview.md +++ b/docs/maplibre/overview.md @@ -86,6 +86,12 @@ Add HTML content to the map. [![](https://i.imgur.com/TgalNOv.png)](https://leafmap.org/maplibre/add_html) +## Add a directional icon to the map + +Add a directional icon to streams. + +[![](https://github.com/user-attachments/assets/b4082d29-b604-4f52-a7e7-88d15d37c7fc)](https://leafmap.org/maplibre/add_icon) + ## Add an icon to the map Add an icon to the map from an external URL and use it in a symbol layer. diff --git a/leafmap/leafmap.py b/leafmap/leafmap.py index e221ab7217..05462a40f5 100644 --- a/leafmap/leafmap.py +++ b/leafmap/leafmap.py @@ -40,11 +40,14 @@ gedi_search, geojson_to_gdf, geojson_to_pmtiles, + get_3dep_dem, get_api_key, get_census_dict, get_overture_data, + get_nhd_basins, get_wbd, image_comparison, + image_metadata, image_to_numpy, map_tiles_to_geotiff, netcdf_to_tif, @@ -75,10 +78,13 @@ stac_stats, stac_tile, start_server, + vector_set_crs, vector_to_gif, view_lidar, write_lidar, zonal_stats, + WhiteboxTools, + whiteboxgui, ) diff --git a/leafmap/maplibregl.py b/leafmap/maplibregl.py index 422b5fcbc4..5b580820a4 100644 --- a/leafmap/maplibregl.py +++ b/leafmap/maplibregl.py @@ -38,6 +38,7 @@ pandas_to_geojson, pmtiles_metadata, pmtiles_style, + random_string, stac_assets, start_server, ) @@ -2156,6 +2157,65 @@ def add_image( kwargs["layout"]["icon-size"] = icon_size self.add_layer(kwargs) + def add_symbol( + self, + image: str, + source: str, + icon_size: int = 1, + symbol_placement: str = "line", + minzoom: Optional[float] = None, + maxzoom: Optional[float] = None, + filter: Optional[Any] = None, + name: Optional[str] = None, + **kwargs: Any, + ) -> None: + """ + Adds a symbol to the map. + + Args: + image (str): The URL or local file path to the image. + source (str): The source of the symbol. + icon_size (int, optional): The size of the symbol. Defaults to 1. + symbol_placement (str, optional): The placement of the symbol. Defaults to "line". + minzoom (Optional[float], optional): The minimum zoom level for the symbol. Defaults to None. + maxzoom (Optional[float], optional): The maximum zoom level for the symbol. Defaults to None. + filter (Optional[Any], optional): A filter to apply to the symbol. Defaults to None. + name (Optional[str], optional): The name of the symbol layer. Defaults to None. + **kwargs (Any): Additional keyword arguments to pass to the layer layout. + For more info, see https://maplibre.org/maplibre-style-spec/layers/#symbol + + Returns: + None + """ + id = f"image_{common.random_string(3)}" + self.add_image(id, image) + + if name is None: + name = f"symbol_{common.random_string(3)}" + + layer = { + "id": name, + "type": "symbol", + "source": source, + "layout": { + "icon-image": id, + "icon-size": icon_size, + "symbol-placement": symbol_placement, + }, + } + + if minzoom is not None: + layer["minzoom"] = minzoom + if maxzoom is not None: + layer["maxzoom"] = maxzoom + if filter is not None: + layer["filter"] = filter + + kwargs = common.replace_underscores_in_keys(kwargs) + layer["layout"].update(kwargs) + + self.add_layer(layer) + def to_streamlit( self, width: Optional[int] = None, diff --git a/mkdocs.yml b/mkdocs.yml index 057ef52c71..fd0eed74ca 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -157,6 +157,7 @@ nav: - maplibre/add_deckgl_layer.ipynb - maplibre/add_gif.ipynb - maplibre/add_html.ipynb + - maplibre/add_icon.ipynb - maplibre/add_image.ipynb - maplibre/add_image_generated.ipynb - maplibre/add_legend.ipynb