Skip to content

Commit

Permalink
Add add_source function and custom marker notebook (#787)
Browse files Browse the repository at this point in the history
* Add add_source function and custom marker notebook

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Add add_gdf method

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
giswqs and pre-commit-ci[bot] committed Jun 24, 2024
1 parent 924102d commit 9569dd6
Show file tree
Hide file tree
Showing 5 changed files with 333 additions and 1 deletion.
129 changes: 129 additions & 0 deletions docs/maplibre/custom_marker.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
{
"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/custom_marker.ipynb)\n",
"[![image](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/opengeos/leafmap/blob/master/docs/maplibre/custom_marker.ipynb)\n",
"[![image](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/opengeos/leafmap/HEAD)\n",
"\n",
"**Customize marker icon image**\n",
"\n",
"The list of available icons can be found [here](https://github.com/mapbox/mapbox-gl-styles/tree/master/sprites).\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 os\n",
"import requests\n",
"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 set it as an environment variable in your notebook or script as follows:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# os.environ[\"MAPTILER_KEY\"] = \"YOUR_API_KEY\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"MAPTILER_KEY = leafmap.get_api_key(\"MAPTILER_KEY\")\n",
"style = f\"https://api.maptiler.com/maps/streets/style.json?key={MAPTILER_KEY}\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"url = (\n",
" \"https://github.com/opengeos/datasets/releases/download/world/world_cities.geojson\"\n",
")\n",
"geojson = requests.get(url).json()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"m = leafmap.Map(style=style)\n",
"source = {\"type\": \"geojson\", \"data\": geojson}\n",
"\n",
"layer = {\n",
" \"id\": \"cities\",\n",
" \"type\": \"symbol\",\n",
" \"source\": \"point\",\n",
" \"layout\": {\n",
" \"icon-image\": \"marker_15\",\n",
" \"icon-size\": 1,\n",
" },\n",
"}\n",
"m.add_source(\"point\", source)\n",
"m.add_layer(layer)\n",
"m.add_popup(\"cities\")\n",
"m"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"![](https://i.imgur.com/yEVKJlA.png)"
]
}
],
"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
}
111 changes: 111 additions & 0 deletions docs/maplibre/geopandas.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
{
"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/geopandas.ipynb)\n",
"[![image](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/opengeos/leafmap/blob/master/docs/maplibre/geopandas.ipynb)\n",
"[![image](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/opengeos/leafmap/HEAD)\n",
"\n",
"**Add a GeoPandas GeoDataFrame to the map**\n",
"\n",
"The following notebook demonstrates how to add a GeoPandas GeoDataFrame 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 os\n",
"import geopandas as gpd\n",
"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 set it as an environment variable in your notebook or script as follows:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# os.environ[\"MAPTILER_KEY\"] = \"YOUR_API_KEY\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"MAPTILER_KEY = leafmap.get_api_key(\"MAPTILER_KEY\")\n",
"style = f\"https://api.maptiler.com/maps/streets/style.json?key={MAPTILER_KEY}\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"m = leafmap.Map(center=[-100, 40], zoom=3, style=style)\n",
"url = \"https://github.com/opengeos/datasets/releases/download/us/us_states.geojson\"\n",
"gdf = gpd.read_file(url)\n",
"paint = {\n",
" \"fill-color\": \"#3388ff\",\n",
" \"fill-opacity\": 0.8,\n",
" \"fill-outline-color\": \"#ffffff\",\n",
"}\n",
"m.add_gdf(gdf, layer_type=\"fill\", name=\"States\", paint=paint)\n",
"m"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"![](https://i.imgur.com/CQHcD7N.png)"
]
}
],
"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
}
12 changes: 12 additions & 0 deletions docs/maplibre/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ Use setPaintProperty to change a layer's fill color.

[![](https://i.imgur.com/Q3BbItI.png)](https://leafmap.org/maplibre/color_switcher)

## Customize marker icon image

Use the icon-image property to change the icon image of a marker.

[![](https://i.imgur.com/yEVKJlA.png)](https://leafmap.org/maplibre/custom_marker)

## Style lines with a data-driven property

Create a visualization with a data expression for line-color.
Expand Down Expand Up @@ -200,6 +206,12 @@ Style a polygon with the fill layer type.

[![](https://i.imgur.com/ZRFTymo.png)](https://leafmap.org/maplibre/geojson_polygon)

## Add a GeoPandas GeoDataFrame

Add a GeoPandas GeoDataFrame to a map.

[![](https://i.imgur.com/CQHcD7N.png)](https://leafmap.org/maplibre/geopandas)

## Create a heatmap layer

Visualize earthquake frequency by location using a heatmap layer.
Expand Down
80 changes: 79 additions & 1 deletion leafmap/maplibregl.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ def __init__(
self.style_dict = {}
for layer in self.get_style_layers():
self.style_dict[layer["id"]] = layer
self.source_dict = {}

def add_layer(
self,
Expand Down Expand Up @@ -242,6 +243,20 @@ def add_control(

super().add_control(control, position)

def add_source(self, id: str, source: Union[str, Dict]) -> None:
"""
Adds a source to the map.
Args:
id (str): The ID of the source.
source (str or dict): The source data. .
Returns:
None
"""
super().add_source(id, source)
self.source_dict[id] = source

def set_center(self, lon: float, lat: float, zoom: Optional[int] = None) -> None:
"""
Sets the center of the map.
Expand Down Expand Up @@ -482,7 +497,7 @@ def add_geojson(
geom_type = data["features"][0]["geometry"]["type"]
elif "geometry" in data:
geom_type = data["geometry"]["type"]
if geom_type in ["Point", "MultiPoint"] and layer_type == "circle":
if geom_type in ["Point", "MultiPoint"]:
if layer_type is None:
layer_type = "circle"
paint = {
Expand Down Expand Up @@ -514,6 +529,7 @@ def add_geojson(
**kwargs,
)
self.add_layer(layer, before_id=before_id, name=name)
self.add_popup(name)
if fit_bounds and bounds is not None:
self.fit_bounds(bounds)
self.set_visibility(name, visible)
Expand Down Expand Up @@ -574,6 +590,8 @@ def add_vector(

if not isinstance(data, gpd.GeoDataFrame):
data = gpd.read_file(data).__geo_interface__
else:
data = data.__geo_interface__

self.add_geojson(
data,
Expand All @@ -588,6 +606,66 @@ def add_vector(
**kwargs,
)

def add_gdf(
self,
gdf: gpd.GeoDataFrame,
layer_type: Optional[str] = None,
filter: Optional[Dict] = None,
paint: Optional[Dict] = None,
name: Optional[str] = None,
fit_bounds: bool = True,
visible: bool = True,
before_id: Optional[str] = None,
source_args: Dict = {},
**kwargs: Any,
) -> None:
"""
Adds a vector layer to the map.
This method adds a GeoDataFrame to the map as a vector layer.
Args:
gdf (gpd.GeoDataFrame): The GeoDataFrame to add to the map.
layer_type (str, optional): The type of the layer. If None, the type
is inferred from the GeoJSON data.
filter (dict, optional): The filter to apply to the layer. If None,
no filter is applied.
paint (dict, optional): The paint properties to apply to the layer.
If None, no paint properties are applied.
name (str, optional): The name of the layer. If None, a random name
is generated.
fit_bounds (bool, optional): Whether to adjust the viewport of the
map to fit the bounds of the GeoJSON data. Defaults to True.
visible (bool, optional): Whether the layer is visible or not.
Defaults to True.
before_id (str, optional): The ID of an existing layer before which
the new layer should be inserted.
source_args (dict, optional): Additional keyword arguments that are
passed to the GeoJSONSource class.
**kwargs: Additional keyword arguments that are passed to the Layer class.
Returns:
None
Raises:
ValueError: If the data is not a URL or a GeoJSON dictionary.
"""
if not isinstance(gdf, gpd.GeoDataFrame):
raise ValueError("The data must be a GeoDataFrame.")
geojson = gdf.__geo_interface__
self.add_geojson(
geojson,
layer_type=layer_type,
filter=filter,
paint=paint,
name=name,
fit_bounds=fit_bounds,
visible=visible,
before_id=before_id,
source_args=source_args,
**kwargs,
)

def add_tile_layer(
self,
url: str,
Expand Down
Loading

0 comments on commit 9569dd6

Please sign in to comment.