Skip to content

Commit

Permalink
Add draw control notebook example
Browse files Browse the repository at this point in the history
  • Loading branch information
giswqs committed Jun 26, 2024
1 parent fb477da commit b8a103e
Show file tree
Hide file tree
Showing 4 changed files with 275 additions and 5 deletions.
201 changes: 201 additions & 0 deletions docs/maplibre/draw_features.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
{
"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/draw_features.ipynb)\n",
"[![image](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/opengeos/leafmap/blob/master/docs/maplibre/draw_features.ipynb)\n",
"[![image](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/opengeos/leafmap/HEAD)\n",
"\n",
"**Draw features on the map**\n",
"\n",
"This notebook shows how to draw features on the map using the [mapbox-gl-draw](https://github.com/mapbox/mapbox-gl-draw) plugin.\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 leafmap.maplibregl as leafmap"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Add the default draw control."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"m = leafmap.Map(center=[-100, 40], zoom=3, style=\"positron\")\n",
"m.add_draw_control(position=\"top-left\")\n",
"m"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Only activate a give set of control."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from maplibre.plugins import MapboxDrawControls, MapboxDrawOptions"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"m = leafmap.Map(center=[-100, 40], zoom=3, style=\"positron\")\n",
"draw_options = MapboxDrawOptions(\n",
" display_controls_default=False,\n",
" controls=MapboxDrawControls(polygon=True, line_string=True, point=True, trash=True),\n",
")\n",
"m.add_draw_control(draw_options)\n",
"m"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Load a GeoJSON FeatureCollection to the draw control."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"m = leafmap.Map(center=[-100, 40], zoom=3, style=\"positron\")\n",
"geojson = {\n",
" 'type': 'FeatureCollection',\n",
" 'features': [\n",
" {\n",
" 'id': 'abc',\n",
" 'type': 'Feature',\n",
" 'properties': {},\n",
" 'geometry': {\n",
" 'coordinates': [\n",
" [\n",
" [-119.08, 45.95],\n",
" [-119.79, 42.08],\n",
" [-107.28, 41.43],\n",
" [-108.15, 46.44],\n",
" [-119.08, 45.95],\n",
" ]\n",
" ],\n",
" 'type': 'Polygon',\n",
" },\n",
" },\n",
" {\n",
" 'id': 'xyz',\n",
" 'type': 'Feature',\n",
" 'properties': {},\n",
" 'geometry': {\n",
" 'coordinates': [\n",
" [\n",
" [-103.87, 38.08],\n",
" [-108.54, 36.44],\n",
" [-106.25, 33.00],\n",
" [-99.91, 31.79],\n",
" [-96.82, 35.48],\n",
" [-98.80, 37.77],\n",
" [-103.87, 38.08],\n",
" ]\n",
" ],\n",
" 'type': 'Polygon',\n",
" },\n",
" },\n",
" ],\n",
"}\n",
"m.add_draw_control(position=\"top-left\", geojson=geojson)\n",
"m"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Retrieve the draw features."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"m.draw_features_selected"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"m.draw_feature_collection_all"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"![](https://i.imgur.com/w8UFssd.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.8"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
6 changes: 6 additions & 0 deletions docs/maplibre/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,12 @@ Drag the marker to a new location on a map and populate its coordinates in a dis

[![](https://i.imgur.com/9RNVuRf.png)](https://leafmap.org/maplibre/drag_a_marker)

## Draw features on the map

Use the draw control to draw features on the map.

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

## Use a fallback image

Use a coalesce expression to display another image when a requested image is not available.
Expand Down
72 changes: 67 additions & 5 deletions leafmap/maplibregl.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,13 +205,15 @@ def add_control(
Adds a control to the map.
This method adds a control to the map. The control can be one of the
following: 'scale', 'fullscreen', 'geolocate', 'navigation', and "attribution". If the
control is a string, it is converted to the corresponding control object.
If the control is not a string, it is assumed to be a control object.
following: 'scale', 'fullscreen', 'geolocate', 'navigation', "attribution",
and "draw". If the control is a string, it is converted to the
corresponding control object. If the control is not a string, it is
assumed to be a control object.
Args:
control (str or object): The control to add to the map. Can be one
of the following: 'scale', 'fullscreen', 'geolocate', 'navigation', and "attribution".
of the following: 'scale', 'fullscreen', 'geolocate', 'navigation',
"attribution", and "draw".
position (str, optional): The position of the control. Defaults to "top-right".
**kwargs: Additional keyword arguments that are passed to the control object.
Expand All @@ -235,14 +237,74 @@ def add_control(
control = NavigationControl(**kwargs)
elif control == "attribution":
control = AttributionControl(**kwargs)
elif control == "draw":
self.add_draw_control(position=position, **kwargs)
else:
print(
"Control can only be one of the following: 'scale', 'fullscreen', 'geolocate', 'navigation'"
"Control can only be one of the following: 'scale', 'fullscreen', 'geolocate', 'navigation', and 'draw'."
)
return

super().add_control(control, position)

def add_draw_control(
self,
options: Optional[Dict[str, Any]] = None,
position: str = "top-left",
geojson: Optional[Dict[str, Any]] = None,
**kwargs: Any,
) -> None:
"""
Adds a drawing control to the map.
This method enables users to add interactive drawing controls to the map,
allowing for the creation, editing, and deletion of geometric shapes on
the map. The options, position, and initial GeoJSON can be customized.
Args:
options (Optional[Dict[str, Any]]): Configuration options for the
drawing control. Defaults to None.
position (str): The position of the control on the map. Defaults
to "top-left".
geojson (Optional[Dict[str, Any]]): Initial GeoJSON data to load
into the drawing control. Defaults to None.
**kwargs (Any): Additional keyword arguments to be passed to the
drawing control.
Returns:
None
"""

super().add_mapbox_draw(
options=options, position=position, geojson=geojson, **kwargs
)

def save_draw_features(self, filepath: str, indent=4, **kwargs) -> None:
"""
Saves the drawn features to a file.
This method saves all features created with the drawing control to a
specified file in GeoJSON format. If there are no features to save, the
file will not be created.
Args:
filepath (str): The path to the file where the GeoJSON data will be saved.
**kwargs (Any): Additional keyword arguments to be passed to
json.dump for custom serialization.
Returns:
None
Raises:
ValueError: If the feature collection is empty.
"""

if len(self.draw_feature_collection_all) > 0:
with open(filepath, "w") as f:
json.dump(self.draw_feature_collection_all, f, indent=indent, **kwargs)
else:
print("There are no features to save.")

def add_source(self, id: str, source: Union[str, Dict]) -> None:
"""
Adds a source to the map.
Expand Down
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ nav:
- maplibre/disable_scroll_zoom.ipynb
- maplibre/display_rich_text.ipynb
- maplibre/drag_a_marker.ipynb
- maplibre/draw_features.ipynb
- maplibre/fallback_image.ipynb
- maplibre/fit_bounds.ipynb
- maplibre/fill_pattern.ipynb
Expand Down

0 comments on commit b8a103e

Please sign in to comment.