diff --git a/book/geospatial/maplibre.ipynb b/book/geospatial/maplibre.ipynb index 4f366db..e9f6448 100644 --- a/book/geospatial/maplibre.ipynb +++ b/book/geospatial/maplibre.ipynb @@ -11,24 +11,27 @@ "\n", "## Overview\n", "\n", - "This lecture introduces the [MapLibre](https://github.com/eodaGmbH/py-maplibregl) Python package, a flexible open-source mapping Python package that allows users to create interactive and customizable 3D and 2D maps in Python. By leveraging the MapLibre library, GIS developers can visualize geospatial data with a variety of customization options and mapping styles. The notebook demonstrates essential concepts like creating interactive maps, customizing basemaps, adding various data layers, and implementing map controls for enhanced functionality. Additionally, advanced features, such as 3D building visualization and layer control, provide students with practical tools for real-world geospatial data analysis and visualization.\n", + "This lecture introduces the [MapLibre](https://github.com/eodaGmbH/py-maplibregl) mapping backend in the Leafmap library—a powerful open-source Python tool for creating customizable 2D and 3D interactive maps. With MapLibre, GIS professionals can develop tailored visualizations that enhance data presentation and geospatial analysis. The provided Jupyter notebook demonstrates foundational skills, including interactive map creation, basemap customization, and data layer integration. Additionally, advanced features such as 3D building visualizations and dynamic map controls equip students with practical skills for effective geospatial data visualization and analysis.\n", "\n", "## Learning Outcomes\n", "\n", "By the end of this lecture, students will be able to:\n", "\n", - "1. Set up and install MapLibre for geospatial visualization in Python.\n", - "2. Create basic interactive maps and apply different basemap styles.\n", - "3. Customize map features, including markers, lines, polygons, and map controls.\n", - "4. Utilize advanced features such as 3D buildings and choropleth maps.\n", - "5. Integrate and manage multiple data layers, including GeoJSON, raster, and vector layers.\n", - "6. Export map visualizations as standalone HTML files for sharing and deployment.\n", + "1. **Set up and install MapLibre** for Python-based geospatial visualization.\n", + "2. **Create interactive maps** and apply various basemap styles.\n", + "3. **Customize map elements**, including markers, lines, polygons, and interactive controls.\n", + "4. **Explore advanced features** like 3D building models and choropleth maps.\n", + "5. **Integrate and manage multiple data layers**, such as GeoJSON, raster, and vector formats.\n", + "6. **Export interactive maps** as standalone HTML files for easy sharing and web deployment.\n", "\n", "## Useful Resources\n", "\n", - "- Notebooks: https://leafmap.org/maplibre/overview\n", - "- Videos: https://bit.ly/maplibre\n", - "- Demos: https://maps.gishub.org\n", + "- [MapLibre GL JS Documentation](https://maplibre.org/maplibre-gl-js/docs): Comprehensive documentation for MapLibre GL JS.\n", + "- [MapLibre Python Bindings](https://github.com/eoda-dev/py-maplibregl): Information on using MapLibre with Python.\n", + "- [MapLibre in Leafmap](https://leafmap.org/maplibre/overview): Examples and tutorials for MapLibre in Leafmap.\n", + "- [Video Tutorials](https://bit.ly/maplibre): Video guides for practical MapLibre skills.\n", + "- [MapLibre Demos](https://maps.gishub.org): Interactive demos showcasing MapLibre’s capabilities.\n", + "\n", "\n", "## Installation and Setup\n", "\n", @@ -72,7 +75,7 @@ "\n", "### Basic Map Setup\n", "\n", - "Let’s start by creating a simple interactive map with default settings. This basic setup provides a blank canvas on which you can add data layers, controls, and other customizations." + "Let’s start by creating a simple interactive map with default settings. This basic setup provides simple map with the `dark-matter` style on which you can add data layers, controls, and other customizations." ] }, { @@ -111,6 +114,14 @@ "cell_type": "markdown", "id": "8", "metadata": {}, + "source": [ + "Hold down the `Ctrl` key. Click and drag to pan the map." + ] + }, + { + "cell_type": "markdown", + "id": "9", + "metadata": {}, "source": [ "### Choosing a Basemap Style\n", "\n", @@ -120,7 +131,7 @@ { "cell_type": "code", "execution_count": null, - "id": "9", + "id": "10", "metadata": {}, "outputs": [], "source": [ @@ -128,10 +139,18 @@ "m" ] }, + { + "cell_type": "markdown", + "id": "11", + "metadata": {}, + "source": [ + "[OpenFreeMap](https://openfreemap.org) provides a variety of basemap styles that you can use in your interactive maps. These styles include `liberty`, `bright`, and `positron`." + ] + }, { "cell_type": "code", "execution_count": null, - "id": "10", + "id": "12", "metadata": {}, "outputs": [], "source": [ @@ -141,7 +160,7 @@ }, { "cell_type": "markdown", - "id": "11", + "id": "13", "metadata": {}, "source": [ "### Adding Background Colors\n", @@ -152,7 +171,7 @@ { "cell_type": "code", "execution_count": null, - "id": "12", + "id": "14", "metadata": {}, "outputs": [], "source": [ @@ -162,7 +181,7 @@ }, { "cell_type": "markdown", - "id": "13", + "id": "15", "metadata": {}, "source": [ "Alternatively, you can provide a URL to a vector style." @@ -171,7 +190,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "16", "metadata": {}, "outputs": [], "source": [ @@ -182,7 +201,7 @@ }, { "cell_type": "markdown", - "id": "15", + "id": "17", "metadata": {}, "source": [ "## Adding Map Controls\n", @@ -191,9 +210,8 @@ "\n", "### Available Controls\n", "\n", - "- **Scale**: Adds a scale bar to indicate the map’s scale.\n", - "- **Fullscreen**: Expands the map to a full-screen view for better focus.\n", "- **Geolocate**: Centers the map based on the user’s current location, if available.\n", + "- **Fullscreen**: Expands the map to a full-screen view for better focus.\n", "- **Navigation**: Provides zoom controls and a compass for reorientation.\n", "- **Draw**: Allows users to draw and edit shapes on the map.\n", "\n", @@ -205,7 +223,7 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "18", "metadata": {}, "outputs": [], "source": [ @@ -216,7 +234,7 @@ }, { "cell_type": "markdown", - "id": "17", + "id": "19", "metadata": {}, "source": [ "### Adding Fullscreen Control\n", @@ -227,7 +245,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "20", "metadata": {}, "outputs": [], "source": [ @@ -238,7 +256,7 @@ }, { "cell_type": "markdown", - "id": "19", + "id": "21", "metadata": {}, "source": [ "### Adding Navigation Control\n", @@ -249,7 +267,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "22", "metadata": {}, "outputs": [], "source": [ @@ -260,7 +278,7 @@ }, { "cell_type": "markdown", - "id": "21", + "id": "23", "metadata": {}, "source": [ "### Adding Draw Control\n", @@ -271,7 +289,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "24", "metadata": {}, "outputs": [], "source": [ @@ -282,7 +300,7 @@ }, { "cell_type": "markdown", - "id": "23", + "id": "25", "metadata": {}, "source": [ "You can configure the Draw control to activate specific tools, like polygon, line, or point drawing, while also enabling or disabling a \"trash\" button to remove unwanted shapes." @@ -291,7 +309,7 @@ { "cell_type": "code", "execution_count": null, - "id": "24", + "id": "26", "metadata": {}, "outputs": [], "source": [ @@ -301,7 +319,7 @@ { "cell_type": "code", "execution_count": null, - "id": "25", + "id": "27", "metadata": {}, "outputs": [], "source": [ @@ -316,7 +334,7 @@ }, { "cell_type": "markdown", - "id": "26", + "id": "28", "metadata": {}, "source": [ "Additionally, you can load a GeoJSON FeatureCollection into the Draw control, which will allow users to view, edit, or interact with pre-defined geographical features, such as boundaries or points of interest." @@ -325,7 +343,7 @@ { "cell_type": "code", "execution_count": null, - "id": "27", + "id": "29", "metadata": {}, "outputs": [], "source": [ @@ -377,7 +395,15 @@ }, { "cell_type": "markdown", - "id": "28", + "id": "30", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/w8UFssd.png)" + ] + }, + { + "cell_type": "markdown", + "id": "31", "metadata": {}, "source": [ "Two key methods for accessing drawn features:\n", @@ -389,7 +415,7 @@ { "cell_type": "code", "execution_count": null, - "id": "29", + "id": "32", "metadata": {}, "outputs": [], "source": [ @@ -399,7 +425,7 @@ { "cell_type": "code", "execution_count": null, - "id": "30", + "id": "33", "metadata": {}, "outputs": [], "source": [ @@ -408,10 +434,10 @@ }, { "cell_type": "markdown", - "id": "31", + "id": "34", "metadata": {}, "source": [ - "## Add Layers\n", + "## Adding Layers\n", "\n", "Adding layers to a map enhances the data it presents, allowing different types of basemaps, tile layers, and thematic overlays to be combined for in-depth analysis.\n", "\n", @@ -423,7 +449,7 @@ { "cell_type": "code", "execution_count": null, - "id": "32", + "id": "35", "metadata": {}, "outputs": [], "source": [ @@ -436,7 +462,7 @@ { "cell_type": "code", "execution_count": null, - "id": "33", + "id": "36", "metadata": {}, "outputs": [], "source": [ @@ -444,28 +470,28 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "34", + "cell_type": "markdown", + "id": "37", "metadata": {}, - "outputs": [], "source": [ - "m = leafmap.Map()\n", - "m" + "You can also add basemaps interactively, which provides flexibility for selecting the best background for your map content." ] }, { - "cell_type": "markdown", - "id": "35", + "cell_type": "code", + "execution_count": null, + "id": "38", "metadata": {}, + "outputs": [], "source": [ - "You can also add basemaps interactively, which provides flexibility for selecting the best background for your map content." + "m = leafmap.Map()\n", + "m" ] }, { "cell_type": "code", "execution_count": null, - "id": "36", + "id": "39", "metadata": {}, "outputs": [], "source": [ @@ -474,7 +500,7 @@ }, { "cell_type": "markdown", - "id": "37", + "id": "40", "metadata": {}, "source": [ "### Adding XYZ Tile Layer\n", @@ -485,7 +511,7 @@ { "cell_type": "code", "execution_count": null, - "id": "38", + "id": "41", "metadata": {}, "outputs": [], "source": [ @@ -497,7 +523,7 @@ }, { "cell_type": "markdown", - "id": "39", + "id": "42", "metadata": {}, "source": [ "### Adding WMS Layer\n", @@ -508,7 +534,7 @@ { "cell_type": "code", "execution_count": null, - "id": "40", + "id": "43", "metadata": {}, "outputs": [], "source": [ @@ -523,7 +549,7 @@ { "cell_type": "code", "execution_count": null, - "id": "41", + "id": "44", "metadata": {}, "outputs": [], "source": [ @@ -538,7 +564,7 @@ }, { "cell_type": "markdown", - "id": "42", + "id": "45", "metadata": {}, "source": [ "### Adding Raster Tiles\n", @@ -551,7 +577,7 @@ { "cell_type": "code", "execution_count": null, - "id": "43", + "id": "46", "metadata": {}, "outputs": [], "source": [ @@ -582,7 +608,7 @@ { "cell_type": "code", "execution_count": null, - "id": "44", + "id": "47", "metadata": {}, "outputs": [], "source": [ @@ -592,18 +618,18 @@ }, { "cell_type": "markdown", - "id": "45", + "id": "48", "metadata": {}, "source": [ "## MapTiler\n", "\n", - "To use MapTiler with this notebook, you need to set up a MapTiler API key. You can obtain a free API key by signing up at [https://cloud.maptiler.com/](https://cloud.maptiler.com/)." + "To use MapTiler with this notebook, you need to set up a MapTiler API key. You can obtain a free API key by signing up at [https://cloud.maptiler.com/](https://cloud.maptiler.com)." ] }, { "cell_type": "code", "execution_count": null, - "id": "46", + "id": "49", "metadata": {}, "outputs": [], "source": [ @@ -613,7 +639,7 @@ }, { "cell_type": "markdown", - "id": "47", + "id": "50", "metadata": {}, "source": [ "Set the API key as an environment variable to access MapTiler's resources. Once set up, you can specify any named style from MapTiler by using the style parameter in the map setup.\n", @@ -631,7 +657,7 @@ { "cell_type": "code", "execution_count": null, - "id": "48", + "id": "51", "metadata": {}, "outputs": [], "source": [ @@ -642,7 +668,7 @@ { "cell_type": "code", "execution_count": null, - "id": "49", + "id": "52", "metadata": {}, "outputs": [], "source": [ @@ -653,7 +679,7 @@ { "cell_type": "code", "execution_count": null, - "id": "50", + "id": "53", "metadata": {}, "outputs": [], "source": [ @@ -664,7 +690,7 @@ { "cell_type": "code", "execution_count": null, - "id": "51", + "id": "54", "metadata": {}, "outputs": [], "source": [ @@ -674,10 +700,10 @@ }, { "cell_type": "markdown", - "id": "52", + "id": "55", "metadata": {}, "source": [ - "### Add a vector tile source\n", + "### Adding a vector tile source\n", "\n", "To include vector data from MapTiler, first obtain the MapTiler API key and then set up a vector source with the desired tile data URL. The vector tile source can then be added to a layer to display features such as contour lines, which are styled for better visibility and engagement." ] @@ -685,7 +711,7 @@ { "cell_type": "code", "execution_count": null, - "id": "53", + "id": "56", "metadata": {}, "outputs": [], "source": [ @@ -695,7 +721,7 @@ { "cell_type": "code", "execution_count": null, - "id": "54", + "id": "57", "metadata": {}, "outputs": [], "source": [ @@ -719,7 +745,7 @@ }, { "cell_type": "markdown", - "id": "55", + "id": "58", "metadata": {}, "source": [ "## 3D Mapping\n", @@ -742,7 +768,7 @@ { "cell_type": "code", "execution_count": null, - "id": "56", + "id": "59", "metadata": {}, "outputs": [], "source": [ @@ -753,10 +779,18 @@ "m" ] }, + { + "cell_type": "markdown", + "id": "60", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/3Q2Q3CG.png)" + ] + }, { "cell_type": "code", "execution_count": null, - "id": "57", + "id": "61", "metadata": {}, "outputs": [], "source": [ @@ -771,10 +805,18 @@ "m" ] }, + { + "cell_type": "markdown", + "id": "62", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/5PNMbAv.png)" + ] + }, { "cell_type": "code", "execution_count": null, - "id": "58", + "id": "63", "metadata": {}, "outputs": [], "source": [ @@ -791,10 +833,18 @@ "m" ] }, + { + "cell_type": "markdown", + "id": "64", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/y33leIj.png)" + ] + }, { "cell_type": "code", "execution_count": null, - "id": "59", + "id": "65", "metadata": {}, "outputs": [], "source": [ @@ -812,7 +862,7 @@ { "cell_type": "code", "execution_count": null, - "id": "60", + "id": "66", "metadata": {}, "outputs": [], "source": [ @@ -823,7 +873,15 @@ }, { "cell_type": "markdown", - "id": "61", + "id": "67", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/m6NwSWG.png)" + ] + }, + { + "cell_type": "markdown", + "id": "68", "metadata": {}, "source": [ "### 3D Buildings\n", @@ -834,7 +892,7 @@ { "cell_type": "code", "execution_count": null, - "id": "62", + "id": "69", "metadata": {}, "outputs": [], "source": [ @@ -889,10 +947,18 @@ "m" ] }, + { + "cell_type": "markdown", + "id": "70", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/9QeicaE.png)" + ] + }, { "cell_type": "code", "execution_count": null, - "id": "63", + "id": "71", "metadata": {}, "outputs": [], "source": [ @@ -907,7 +973,7 @@ }, { "cell_type": "markdown", - "id": "64", + "id": "72", "metadata": {}, "source": [ "### 3D Indoor Mapping\n", @@ -918,7 +984,7 @@ { "cell_type": "code", "execution_count": null, - "id": "65", + "id": "73", "metadata": {}, "outputs": [], "source": [ @@ -930,7 +996,7 @@ { "cell_type": "code", "execution_count": null, - "id": "66", + "id": "74", "metadata": {}, "outputs": [], "source": [ @@ -940,7 +1006,7 @@ { "cell_type": "code", "execution_count": null, - "id": "67", + "id": "75", "metadata": {}, "outputs": [], "source": [ @@ -965,7 +1031,15 @@ }, { "cell_type": "markdown", - "id": "68", + "id": "76", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/eYhSWaT.png)" + ] + }, + { + "cell_type": "markdown", + "id": "77", "metadata": {}, "source": [ "### 3D Choropleth Map\n", @@ -982,7 +1056,7 @@ { "cell_type": "code", "execution_count": null, - "id": "69", + "id": "78", "metadata": {}, "outputs": [], "source": [ @@ -1028,10 +1102,18 @@ "m" ] }, + { + "cell_type": "markdown", + "id": "79", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/fLgqYTa.png)" + ] + }, { "cell_type": "code", "execution_count": null, - "id": "70", + "id": "80", "metadata": {}, "outputs": [], "source": [ @@ -1071,10 +1153,10 @@ }, { "cell_type": "markdown", - "id": "71", + "id": "81", "metadata": {}, "source": [ - "## Visualize Vector Data\n", + "## Visualizing Vector Data\n", "\n", "Leafmap provides a variety of methods to visualize vector data on a map, allowing you to display points, lines, polygons, and other vector shapes with custom styling and interactivity.\n", "\n", @@ -1094,7 +1176,7 @@ { "cell_type": "code", "execution_count": null, - "id": "72", + "id": "82", "metadata": {}, "outputs": [], "source": [ @@ -1103,10 +1185,18 @@ "m" ] }, + { + "cell_type": "markdown", + "id": "83", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/ufmqTzx.png)" + ] + }, { "cell_type": "code", "execution_count": null, - "id": "73", + "id": "84", "metadata": {}, "outputs": [], "source": [ @@ -1118,7 +1208,7 @@ { "cell_type": "code", "execution_count": null, - "id": "74", + "id": "85", "metadata": {}, "outputs": [], "source": [ @@ -1131,7 +1221,7 @@ { "cell_type": "code", "execution_count": null, - "id": "75", + "id": "86", "metadata": {}, "outputs": [], "source": [ @@ -1144,7 +1234,7 @@ { "cell_type": "code", "execution_count": null, - "id": "76", + "id": "87", "metadata": {}, "outputs": [], "source": [ @@ -1168,10 +1258,10 @@ }, { "cell_type": "markdown", - "id": "77", + "id": "88", "metadata": {}, "source": [ - "### Customize Marker Icon Image\n", + "### Customizing Marker Icon Image\n", "\n", "To further customize point data, an image icon can be used instead of the default marker:\n", "\n", @@ -1181,7 +1271,7 @@ { "cell_type": "code", "execution_count": null, - "id": "78", + "id": "89", "metadata": {}, "outputs": [], "source": [ @@ -1214,7 +1304,7 @@ }, { "cell_type": "markdown", - "id": "79", + "id": "90", "metadata": {}, "source": [ "### Line Data\n", @@ -1227,7 +1317,7 @@ { "cell_type": "code", "execution_count": null, - "id": "80", + "id": "91", "metadata": {}, "outputs": [], "source": [ @@ -1281,7 +1371,7 @@ }, { "cell_type": "markdown", - "id": "81", + "id": "92", "metadata": {}, "source": [ "### Polygon Data\n", @@ -1298,7 +1388,7 @@ { "cell_type": "code", "execution_count": null, - "id": "82", + "id": "93", "metadata": {}, "outputs": [], "source": [ @@ -1349,7 +1439,7 @@ { "cell_type": "code", "execution_count": null, - "id": "83", + "id": "94", "metadata": {}, "outputs": [], "source": [ @@ -1362,7 +1452,7 @@ { "cell_type": "code", "execution_count": null, - "id": "84", + "id": "95", "metadata": {}, "outputs": [], "source": [ @@ -1376,7 +1466,7 @@ { "cell_type": "code", "execution_count": null, - "id": "85", + "id": "96", "metadata": {}, "outputs": [], "source": [ @@ -1392,7 +1482,7 @@ }, { "cell_type": "markdown", - "id": "86", + "id": "97", "metadata": {}, "source": [ "### Multiple Geometries\n", @@ -1405,7 +1495,7 @@ { "cell_type": "code", "execution_count": null, - "id": "87", + "id": "98", "metadata": {}, "outputs": [], "source": [ @@ -1439,7 +1529,7 @@ { "cell_type": "code", "execution_count": null, - "id": "88", + "id": "99", "metadata": {}, "outputs": [], "source": [ @@ -1448,7 +1538,7 @@ }, { "cell_type": "markdown", - "id": "89", + "id": "100", "metadata": {}, "source": [ "### Marker Cluster\n", @@ -1459,7 +1549,7 @@ { "cell_type": "code", "execution_count": null, - "id": "90", + "id": "101", "metadata": {}, "outputs": [], "source": [ @@ -1521,7 +1611,15 @@ }, { "cell_type": "markdown", - "id": "91", + "id": "102", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/VWvJKwl.png)" + ] + }, + { + "cell_type": "markdown", + "id": "103", "metadata": {}, "source": [ "### Local Vector Data\n", @@ -1532,7 +1630,7 @@ { "cell_type": "code", "execution_count": null, - "id": "92", + "id": "104", "metadata": {}, "outputs": [], "source": [ @@ -1544,7 +1642,7 @@ { "cell_type": "code", "execution_count": null, - "id": "93", + "id": "105", "metadata": {}, "outputs": [], "source": [ @@ -1555,7 +1653,7 @@ { "cell_type": "code", "execution_count": null, - "id": "94", + "id": "106", "metadata": {}, "outputs": [], "source": [ @@ -1564,7 +1662,7 @@ }, { "cell_type": "markdown", - "id": "95", + "id": "107", "metadata": {}, "source": [ "### Local Vector Data\n", @@ -1575,7 +1673,7 @@ { "cell_type": "code", "execution_count": null, - "id": "96", + "id": "108", "metadata": {}, "outputs": [], "source": [ @@ -1593,10 +1691,10 @@ }, { "cell_type": "markdown", - "id": "97", + "id": "109", "metadata": {}, "source": [ - "### Change Building Color\n", + "### Changing Building Color\n", "\n", "You can customize the color and opacity of buildings based on the map’s zoom level. This example changes building colors from orange at lower zoom levels to lighter shades as the zoom level increases. Additionally, the opacity gradually transitions to fully opaque, making buildings more visible at close-up zoom levels." ] @@ -1604,7 +1702,7 @@ { "cell_type": "code", "execution_count": null, - "id": "98", + "id": "110", "metadata": {}, "outputs": [], "source": [ @@ -1626,7 +1724,7 @@ { "cell_type": "code", "execution_count": null, - "id": "99", + "id": "111", "metadata": {}, "outputs": [], "source": [ @@ -1635,10 +1733,18 @@ }, { "cell_type": "markdown", - "id": "100", + "id": "112", "metadata": {}, "source": [ - "### Add a New Layer Below Labels\n", + "![](https://i.imgur.com/PayiTON.png)" + ] + }, + { + "cell_type": "markdown", + "id": "113", + "metadata": {}, + "source": [ + "### Adding a New Layer Below Labels\n", "\n", "A layer can be added below existing labels on the map to enhance clarity without obscuring labels. The urban areas dataset is displayed as a fill layer in a color and opacity that visually distinguishes it from other map elements. The layer is positioned below symbols, allowing place names to remain visible." ] @@ -1646,7 +1752,7 @@ { "cell_type": "code", "execution_count": null, - "id": "101", + "id": "114", "metadata": {}, "outputs": [], "source": [ @@ -1670,7 +1776,7 @@ }, { "cell_type": "markdown", - "id": "102", + "id": "115", "metadata": {}, "source": [ "### Heat Map\n", @@ -1681,7 +1787,7 @@ { "cell_type": "code", "execution_count": null, - "id": "103", + "id": "116", "metadata": {}, "outputs": [], "source": [ @@ -1775,10 +1881,18 @@ }, { "cell_type": "markdown", - "id": "104", + "id": "117", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/OLCRPKj.png)" + ] + }, + { + "cell_type": "markdown", + "id": "118", "metadata": {}, "source": [ - "### Visualize Population Density\n", + "### Visualizing Population Density\n", "\n", "Population density can be calculated and displayed dynamically. This example loads a GeoJSON of Rwandan provinces, calculating density by dividing population by area. The fill color of each province is then adjusted based on density, with different color schemes applied depending on the zoom level." ] @@ -1786,7 +1900,7 @@ { "cell_type": "code", "execution_count": null, - "id": "105", + "id": "119", "metadata": {}, "outputs": [], "source": [ @@ -1841,10 +1955,10 @@ }, { "cell_type": "markdown", - "id": "106", + "id": "120", "metadata": {}, "source": [ - "## Visualize Raster Data\n", + "## Visualizing Raster Data\n", "\n", "### Local Raster Data\n", "\n", @@ -1858,7 +1972,7 @@ { "cell_type": "code", "execution_count": null, - "id": "107", + "id": "121", "metadata": {}, "outputs": [], "source": [ @@ -1870,7 +1984,7 @@ { "cell_type": "code", "execution_count": null, - "id": "108", + "id": "122", "metadata": {}, "outputs": [], "source": [ @@ -1884,17 +1998,25 @@ { "cell_type": "code", "execution_count": null, - "id": "109", + "id": "123", "metadata": {}, "outputs": [], "source": [ "m.layer_interact()" ] }, + { + "cell_type": "markdown", + "id": "124", + "metadata": {}, + "source": [ + "A Digital Elevation Model (DEM) is also downloaded and visualized with a terrain color scheme. Leafmap’s `layer_interact` method allows interactive adjustments." + ] + }, { "cell_type": "code", "execution_count": null, - "id": "110", + "id": "125", "metadata": {}, "outputs": [], "source": [ @@ -1906,7 +2028,7 @@ { "cell_type": "code", "execution_count": null, - "id": "111", + "id": "126", "metadata": {}, "outputs": [], "source": [ @@ -1915,18 +2037,10 @@ "m" ] }, - { - "cell_type": "markdown", - "id": "112", - "metadata": {}, - "source": [ - "A Digital Elevation Model (DEM) is also downloaded and visualized with a terrain color scheme. Leafmap’s `layer_interact` method allows interactive adjustments." - ] - }, { "cell_type": "code", "execution_count": null, - "id": "113", + "id": "127", "metadata": {}, "outputs": [], "source": [ @@ -1935,7 +2049,7 @@ }, { "cell_type": "markdown", - "id": "114", + "id": "128", "metadata": {}, "source": [ "### Cloud Optimized GeoTIFF (COG)\n", @@ -1946,7 +2060,7 @@ { "cell_type": "code", "execution_count": null, - "id": "115", + "id": "129", "metadata": {}, "outputs": [], "source": [ @@ -1966,7 +2080,7 @@ { "cell_type": "code", "execution_count": null, - "id": "116", + "id": "130", "metadata": {}, "outputs": [], "source": [ @@ -1975,7 +2089,7 @@ }, { "cell_type": "markdown", - "id": "117", + "id": "131", "metadata": {}, "source": [ "### STAC Layer\n", @@ -1986,7 +2100,7 @@ { "cell_type": "code", "execution_count": null, - "id": "118", + "id": "132", "metadata": {}, "outputs": [], "source": [ @@ -2001,7 +2115,7 @@ { "cell_type": "code", "execution_count": null, - "id": "119", + "id": "133", "metadata": {}, "outputs": [], "source": [ @@ -2010,16 +2124,16 @@ }, { "cell_type": "markdown", - "id": "120", + "id": "134", "metadata": {}, "source": [ - "For more control, the `collection` and `item` parameters let you specify specific assets, such as color infrared bands, for focused analysis." + "Leafmap also supports loading STAC items from the [Microsoft Planetary Computer](https://planetarycomputer.microsoft.com). The example demonstrates how to load a STAC item from the Planetary Computer and display it on the map." ] }, { "cell_type": "code", "execution_count": null, - "id": "121", + "id": "135", "metadata": {}, "outputs": [], "source": [ @@ -2030,7 +2144,7 @@ { "cell_type": "code", "execution_count": null, - "id": "122", + "id": "136", "metadata": {}, "outputs": [], "source": [ @@ -2040,7 +2154,7 @@ { "cell_type": "code", "execution_count": null, - "id": "123", + "id": "137", "metadata": {}, "outputs": [], "source": [ @@ -2056,15 +2170,15 @@ }, { "cell_type": "markdown", - "id": "124", + "id": "138", "metadata": {}, "source": [ - "## Interact with the Map\n", + "## Interacting with the Map\n", "\n", "Interactivity allows for a more tailored map experience.\n", "\n", "\n", - "### Display a Non-Interactive Map\n", + "### Displaying a Non-Interactive Map\n", "\n", "To create a static map, set `interactive=False`. This disables all user interactions, making it ideal for static presentations." ] @@ -2072,7 +2186,7 @@ { "cell_type": "code", "execution_count": null, - "id": "125", + "id": "139", "metadata": {}, "outputs": [], "source": [ @@ -2084,10 +2198,10 @@ }, { "cell_type": "markdown", - "id": "126", + "id": "140", "metadata": {}, "source": [ - "### Disable Scroll Zoom\n", + "### Disabling Scroll Zoom\n", "\n", "Use `scroll_zoom=False` to prevent map zooming with the scroll wheel, maintaining a fixed zoom level." ] @@ -2095,7 +2209,7 @@ { "cell_type": "code", "execution_count": null, - "id": "127", + "id": "141", "metadata": {}, "outputs": [], "source": [ @@ -2105,10 +2219,10 @@ }, { "cell_type": "markdown", - "id": "128", + "id": "142", "metadata": {}, "source": [ - "### Fit Bounds\n", + "### Fitting Bounds\n", "\n", "The `fit_bounds` method focuses the map on a specified area. In this example, the map centers on Kenya. Additionally, a GeoJSON line is added to the map, and its bounds are automatically calculated with `geojson_bounds` for a custom zoom fit." ] @@ -2116,7 +2230,7 @@ { "cell_type": "code", "execution_count": null, - "id": "129", + "id": "143", "metadata": {}, "outputs": [], "source": [ @@ -2126,7 +2240,7 @@ }, { "cell_type": "markdown", - "id": "130", + "id": "144", "metadata": {}, "source": [ "Fit to Kenya." @@ -2135,7 +2249,7 @@ { "cell_type": "code", "execution_count": null, - "id": "131", + "id": "145", "metadata": {}, "outputs": [], "source": [ @@ -2146,7 +2260,7 @@ { "cell_type": "code", "execution_count": null, - "id": "132", + "id": "146", "metadata": {}, "outputs": [], "source": [ @@ -2193,7 +2307,7 @@ { "cell_type": "code", "execution_count": null, - "id": "133", + "id": "147", "metadata": {}, "outputs": [], "source": [ @@ -2204,7 +2318,7 @@ { "cell_type": "code", "execution_count": null, - "id": "134", + "id": "148", "metadata": {}, "outputs": [], "source": [ @@ -2213,10 +2327,10 @@ }, { "cell_type": "markdown", - "id": "135", + "id": "149", "metadata": {}, "source": [ - "### Restrict Map Panning to an Area\n", + "### Restricting Map Panning to an Area\n", "\n", "To limit map panning to a specific area, define a bounding box. The map is then restricted within the bounds, ensuring users do not accidentally pan away from the area of interest." ] @@ -2224,7 +2338,7 @@ { "cell_type": "code", "execution_count": null, - "id": "136", + "id": "150", "metadata": {}, "outputs": [], "source": [ @@ -2237,7 +2351,7 @@ { "cell_type": "code", "execution_count": null, - "id": "137", + "id": "151", "metadata": {}, "outputs": [], "source": [ @@ -2247,10 +2361,10 @@ }, { "cell_type": "markdown", - "id": "138", + "id": "152", "metadata": {}, "source": [ - "### Fly To\n", + "### Flying To\n", "\n", "The `fly_to` method smoothly navigates to specified coordinates. Parameters like speed and zoom provide control over the fly-to effect. This example flies from the initial map location to New York City." ] @@ -2258,7 +2372,7 @@ { "cell_type": "code", "execution_count": null, - "id": "139", + "id": "153", "metadata": {}, "outputs": [], "source": [ @@ -2269,7 +2383,7 @@ { "cell_type": "code", "execution_count": null, - "id": "140", + "id": "154", "metadata": {}, "outputs": [], "source": [ @@ -2279,7 +2393,7 @@ { "cell_type": "code", "execution_count": null, - "id": "141", + "id": "155", "metadata": {}, "outputs": [], "source": [ @@ -2290,7 +2404,7 @@ { "cell_type": "code", "execution_count": null, - "id": "142", + "id": "156", "metadata": {}, "outputs": [], "source": [ @@ -2309,10 +2423,10 @@ }, { "cell_type": "markdown", - "id": "143", + "id": "157", "metadata": {}, "source": [ - "### Jump to a Series of Locations\n", + "### Jumping to a Series of Locations\n", "\n", "Using `jump_to`, you can navigate between multiple locations. This example sets up a list of coordinates representing cities and automatically pans to each one in sequence. Adding a delay between transitions enhances the animation effect." ] @@ -2320,7 +2434,7 @@ { "cell_type": "code", "execution_count": null, - "id": "144", + "id": "158", "metadata": {}, "outputs": [], "source": [ @@ -2330,7 +2444,7 @@ { "cell_type": "code", "execution_count": null, - "id": "145", + "id": "159", "metadata": {}, "outputs": [], "source": [ @@ -2377,7 +2491,7 @@ { "cell_type": "code", "execution_count": null, - "id": "146", + "id": "160", "metadata": {}, "outputs": [], "source": [ @@ -2389,10 +2503,10 @@ }, { "cell_type": "markdown", - "id": "147", + "id": "161", "metadata": {}, "source": [ - "### Get Coordinates of the Mouse Pointer\n", + "### Getting Coordinates of the Mouse Pointer\n", "\n", "With widgets, you can display the current mouse pointer coordinates as it moves across the map. This is useful for precision mapping tasks where knowing exact coordinates is essential." ] @@ -2400,7 +2514,7 @@ { "cell_type": "code", "execution_count": null, - "id": "148", + "id": "162", "metadata": {}, "outputs": [], "source": [ @@ -2410,7 +2524,7 @@ { "cell_type": "code", "execution_count": null, - "id": "149", + "id": "163", "metadata": {}, "outputs": [], "source": [ @@ -2421,7 +2535,7 @@ { "cell_type": "code", "execution_count": null, - "id": "150", + "id": "164", "metadata": {}, "outputs": [], "source": [ @@ -2431,7 +2545,7 @@ { "cell_type": "code", "execution_count": null, - "id": "151", + "id": "165", "metadata": {}, "outputs": [], "source": [ @@ -2450,14 +2564,14 @@ }, { "cell_type": "markdown", - "id": "152", + "id": "166", "metadata": {}, "source": [ "## Customizing Layer Styles\n", "\n", "Customizing layer styles enables personalized map designs.\n", "\n", - "### Change Layer Color\n", + "### Changing Layer Color\n", "\n", "Use `style_layer_interact` to interactively change the color of map layers, such as water bodies. This method provides an interactive palette for immediate style changes." ] @@ -2465,7 +2579,7 @@ { "cell_type": "code", "execution_count": null, - "id": "153", + "id": "167", "metadata": {}, "outputs": [], "source": [ @@ -2476,7 +2590,7 @@ { "cell_type": "code", "execution_count": null, - "id": "154", + "id": "168", "metadata": {}, "outputs": [], "source": [ @@ -2485,10 +2599,10 @@ }, { "cell_type": "markdown", - "id": "155", + "id": "169", "metadata": {}, "source": [ - "### Change Case of Labels\n", + "### Changing Case of Labels\n", "\n", "This example displays labels in upper or lower case based on their properties. The layout options let you customize font, size, and alignment. For example, facility names are displayed in uppercase, and comments are displayed in lowercase for contrast." ] @@ -2496,7 +2610,7 @@ { "cell_type": "code", "execution_count": null, - "id": "156", + "id": "170", "metadata": {}, "outputs": [], "source": [ @@ -2532,7 +2646,15 @@ }, { "cell_type": "markdown", - "id": "157", + "id": "171", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/FzGOovv.png)" + ] + }, + { + "cell_type": "markdown", + "id": "172", "metadata": {}, "source": [ "### Variable Label Placement\n", @@ -2543,7 +2665,7 @@ { "cell_type": "code", "execution_count": null, - "id": "158", + "id": "173", "metadata": {}, "outputs": [], "source": [ @@ -2611,7 +2733,7 @@ { "cell_type": "code", "execution_count": null, - "id": "159", + "id": "174", "metadata": {}, "outputs": [], "source": [ @@ -2620,14 +2742,14 @@ }, { "cell_type": "markdown", - "id": "160", + "id": "175", "metadata": {}, "source": [ "## Adding Custom Components\n", "\n", "Enhance your maps by adding custom components such as images, videos, text, color bars, and legends.\n", "\n", - "### Add Image\n", + "### Adding Image\n", "\n", "You can add an image as an overlay or as an icon for a specific layer. For instance:\n", "- Overlaying an image directly on the map at the \"bottom-right\" corner.\n", @@ -2637,7 +2759,7 @@ { "cell_type": "code", "execution_count": null, - "id": "161", + "id": "176", "metadata": {}, "outputs": [], "source": [ @@ -2672,10 +2794,18 @@ "m" ] }, + { + "cell_type": "markdown", + "id": "177", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/Nq1uV9d.png)" + ] + }, { "cell_type": "code", "execution_count": null, - "id": "162", + "id": "178", "metadata": {}, "outputs": [], "source": [ @@ -2688,7 +2818,7 @@ { "cell_type": "code", "execution_count": null, - "id": "163", + "id": "179", "metadata": {}, "outputs": [], "source": [ @@ -2700,7 +2830,7 @@ }, { "cell_type": "markdown", - "id": "164", + "id": "180", "metadata": {}, "source": [ "To customize icons, you can also generate icon data with `numpy`, creating unique color gradients and using it as a map icon." @@ -2709,7 +2839,7 @@ { "cell_type": "code", "execution_count": null, - "id": "165", + "id": "181", "metadata": {}, "outputs": [], "source": [ @@ -2765,10 +2895,18 @@ }, { "cell_type": "markdown", - "id": "166", + "id": "182", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/qWWlnAm.png)" + ] + }, + { + "cell_type": "markdown", + "id": "183", "metadata": {}, "source": [ - "### Add Text\n", + "### Adding Text\n", "\n", "Add text annotations to the map, specifying parameters like font size and background color. For example:\n", "- Text \"Hello World\" in the bottom-right corner with a transparent background.\n", @@ -2778,7 +2916,7 @@ { "cell_type": "code", "execution_count": null, - "id": "167", + "id": "184", "metadata": {}, "outputs": [], "source": [ @@ -2792,10 +2930,18 @@ }, { "cell_type": "markdown", - "id": "168", + "id": "185", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/UAtlh3r.png)" + ] + }, + { + "cell_type": "markdown", + "id": "186", "metadata": {}, "source": [ - "### Add GIF\n", + "### Adding GIF\n", "\n", "GIFs can be added as animated overlays to bring your map to life. Example: add a sloth GIF in the bottom-right and a second GIF in the bottom-left corner, with a text label indicating “I love sloth!” for added character." ] @@ -2803,7 +2949,7 @@ { "cell_type": "code", "execution_count": null, - "id": "169", + "id": "187", "metadata": {}, "outputs": [], "source": [ @@ -2819,10 +2965,18 @@ }, { "cell_type": "markdown", - "id": "170", + "id": "188", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/auytBtD.png)" + ] + }, + { + "cell_type": "markdown", + "id": "189", "metadata": {}, "source": [ - "### Add HTML\n", + "### Adding HTML\n", "\n", "Embed custom HTML content to display various HTML elements, such as emojis or stylized text. You can also adjust the font size and background transparency for better integration into the map design." ] @@ -2830,7 +2984,7 @@ { "cell_type": "code", "execution_count": null, - "id": "171", + "id": "190", "metadata": {}, "outputs": [], "source": [ @@ -2857,10 +3011,18 @@ }, { "cell_type": "markdown", - "id": "172", + "id": "191", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/TgalNOv.png)" + ] + }, + { + "cell_type": "markdown", + "id": "192", "metadata": {}, "source": [ - "### Add Colorbar\n", + "### Adding Color bar\n", "\n", "Adding a color bar enhances data interpretation. In the example:\n", "1. A Digital Elevation Model (DEM) is displayed with a color ramp from 0 to 1500 meters.\n", @@ -2870,7 +3032,7 @@ { "cell_type": "code", "execution_count": null, - "id": "173", + "id": "193", "metadata": {}, "outputs": [], "source": [ @@ -2891,10 +3053,18 @@ "m" ] }, + { + "cell_type": "markdown", + "id": "194", + "metadata": {}, + "source": [ + "Make the color bar background transparent to blend seamlessly with the map." + ] + }, { "cell_type": "code", "execution_count": null, - "id": "174", + "id": "195", "metadata": {}, "outputs": [], "source": [ @@ -2918,10 +3088,18 @@ "m" ] }, + { + "cell_type": "markdown", + "id": "196", + "metadata": {}, + "source": [ + "Make the color bar vertical for a different layout." + ] + }, { "cell_type": "code", "execution_count": null, - "id": "175", + "id": "197", "metadata": {}, "outputs": [], "source": [ @@ -2949,10 +3127,10 @@ }, { "cell_type": "markdown", - "id": "176", + "id": "198", "metadata": {}, "source": [ - "### Add Legend\n", + "### Adding Legend\n", "\n", "Custom legends help users understand data classifications. Two methods are shown:\n", "1. Using built-in legends, such as for NLCD (National Land Cover Database) or wetland types.\n", @@ -2962,7 +3140,7 @@ { "cell_type": "code", "execution_count": null, - "id": "177", + "id": "199", "metadata": {}, "outputs": [], "source": [ @@ -2983,7 +3161,7 @@ { "cell_type": "code", "execution_count": null, - "id": "178", + "id": "200", "metadata": {}, "outputs": [], "source": [ @@ -2999,7 +3177,7 @@ { "cell_type": "code", "execution_count": null, - "id": "179", + "id": "201", "metadata": {}, "outputs": [], "source": [ @@ -3042,22 +3220,26 @@ }, { "cell_type": "markdown", - "id": "180", + "id": "202", "metadata": {}, "source": [ - "### Add Video\n", - "\n", - "Videos can be added with geographic context by specifying corner coordinates. Videos must be listed in multiple formats to ensure compatibility across browsers. The coordinates array should define the video’s location on the map in the order: top-left, top-right, bottom-right, and bottom-left. This is demonstrated by adding drone footage to a satellite map view, enhancing the user experience with real-world visuals.\n", - "\n", + "![](https://i.imgur.com/dy60trf.png)" + ] + }, + { + "cell_type": "markdown", + "id": "203", + "metadata": {}, + "source": [ + "### Adding Video\n", "\n", - "The `urls` value is an array. For each URL in the array, a video element source will be created. To support the video across browsers, supply URLs in multiple formats.\n", - "The `coordinates` array contains [longitude, latitude] pairs for the video corners listed in clockwise order: top left, top right, bottom right, bottom left." + "Videos can be added with geographic context by specifying corner coordinates. Videos must be listed in multiple formats to ensure compatibility across browsers. The coordinates array should define the video’s location on the map in the order: top-left, top-right, bottom-right, and bottom-left. This is demonstrated by adding drone footage to a satellite map view, enhancing the user experience with real-world visuals." ] }, { "cell_type": "code", "execution_count": null, - "id": "181", + "id": "204", "metadata": {}, "outputs": [], "source": [ @@ -3082,7 +3264,7 @@ { "cell_type": "code", "execution_count": null, - "id": "182", + "id": "205", "metadata": {}, "outputs": [], "source": [ @@ -3104,12 +3286,12 @@ }, { "cell_type": "markdown", - "id": "183", + "id": "206", "metadata": {}, "source": [ "## PMTiles\n", "\n", - "Leafmap supports the [PMTiles](https://protomaps.com/docs/pmtiles/) format, enabling efficient storage and fast rendering of vector tiles directly in the browser.\n", + "Leafmap supports visualizing [PMTiles](https://protomaps.com/docs/pmtiles/), which enables efficient storage and fast rendering of vector tiles directly in the browser.\n", "\n", "### Protomaps Sample Data\n", "\n", @@ -3119,7 +3301,7 @@ { "cell_type": "code", "execution_count": null, - "id": "184", + "id": "207", "metadata": {}, "outputs": [], "source": [ @@ -3132,7 +3314,7 @@ { "cell_type": "code", "execution_count": null, - "id": "185", + "id": "208", "metadata": {}, "outputs": [], "source": [ @@ -3180,7 +3362,7 @@ { "cell_type": "code", "execution_count": null, - "id": "186", + "id": "209", "metadata": {}, "outputs": [], "source": [ @@ -3189,20 +3371,18 @@ }, { "cell_type": "markdown", - "id": "187", + "id": "210", "metadata": {}, "source": [ "### Source Cooperative Data\n", "\n", - "Visualize the Google-Microsoft Open Buildings dataset, managed by VIDA, in PMTiles format. Fetch metadata to identify available layers, apply custom styles to the building footprints, and render them with semi-transparent colors for a clear visualization.\n", - "\n", - "Let's visualize the [Google-Microsoft Open Buildings - combined by VIDA](https://beta.source.coop/repositories/vida/google-microsoft-open-buildings/description)." + "Visualize the [Google-Microsoft Open Buildings dataset](https://beta.source.coop/repositories/vida/google-microsoft-open-buildings/description), managed by VIDA, in PMTiles format. Fetch metadata to identify available layers, apply custom styles to the building footprints, and render them with semi-transparent colors for a clear visualization." ] }, { "cell_type": "code", "execution_count": null, - "id": "188", + "id": "211", "metadata": {}, "outputs": [], "source": [ @@ -3215,7 +3395,7 @@ { "cell_type": "code", "execution_count": null, - "id": "189", + "id": "212", "metadata": {}, "outputs": [], "source": [ @@ -3257,7 +3437,7 @@ { "cell_type": "code", "execution_count": null, - "id": "190", + "id": "213", "metadata": {}, "outputs": [], "source": [ @@ -3266,7 +3446,7 @@ }, { "cell_type": "markdown", - "id": "191", + "id": "214", "metadata": {}, "source": [ "### 3D PMTiles\n", @@ -3277,7 +3457,7 @@ { "cell_type": "code", "execution_count": null, - "id": "192", + "id": "215", "metadata": {}, "outputs": [], "source": [ @@ -3290,7 +3470,7 @@ { "cell_type": "code", "execution_count": null, - "id": "193", + "id": "216", "metadata": {}, "outputs": [], "source": [ @@ -3345,7 +3525,7 @@ }, { "cell_type": "markdown", - "id": "194", + "id": "217", "metadata": {}, "source": [ "### 3D Buildings\n", @@ -3356,7 +3536,7 @@ { "cell_type": "code", "execution_count": null, - "id": "195", + "id": "218", "metadata": {}, "outputs": [], "source": [ @@ -3371,7 +3551,7 @@ }, { "cell_type": "markdown", - "id": "196", + "id": "219", "metadata": {}, "source": [ "### 2D Buildings, Transportation, and Other Themes\n", @@ -3384,7 +3564,7 @@ { "cell_type": "code", "execution_count": null, - "id": "197", + "id": "220", "metadata": {}, "outputs": [], "source": [ @@ -3397,7 +3577,7 @@ }, { "cell_type": "markdown", - "id": "198", + "id": "221", "metadata": {}, "source": [ "Transportation theme:" @@ -3406,7 +3586,7 @@ { "cell_type": "code", "execution_count": null, - "id": "199", + "id": "222", "metadata": {}, "outputs": [], "source": [ @@ -3419,7 +3599,7 @@ }, { "cell_type": "markdown", - "id": "200", + "id": "223", "metadata": {}, "source": [ "Places theme:" @@ -3428,7 +3608,7 @@ { "cell_type": "code", "execution_count": null, - "id": "201", + "id": "224", "metadata": {}, "outputs": [], "source": [ @@ -3441,7 +3621,7 @@ }, { "cell_type": "markdown", - "id": "202", + "id": "225", "metadata": {}, "source": [ "Addresses theme:" @@ -3450,7 +3630,7 @@ { "cell_type": "code", "execution_count": null, - "id": "203", + "id": "226", "metadata": {}, "outputs": [], "source": [ @@ -3463,7 +3643,7 @@ }, { "cell_type": "markdown", - "id": "204", + "id": "227", "metadata": {}, "source": [ "Base theme:" @@ -3472,7 +3652,7 @@ { "cell_type": "code", "execution_count": null, - "id": "205", + "id": "228", "metadata": {}, "outputs": [], "source": [ @@ -3485,7 +3665,7 @@ }, { "cell_type": "markdown", - "id": "206", + "id": "229", "metadata": {}, "source": [ "Divisions themem:" @@ -3494,7 +3674,7 @@ { "cell_type": "code", "execution_count": null, - "id": "207", + "id": "230", "metadata": {}, "outputs": [], "source": [ @@ -3507,7 +3687,7 @@ }, { "cell_type": "markdown", - "id": "208", + "id": "231", "metadata": {}, "source": [ "## Deck.GL Layers\n", @@ -3522,7 +3702,7 @@ { "cell_type": "code", "execution_count": null, - "id": "209", + "id": "232", "metadata": {}, "outputs": [], "source": [ @@ -3551,7 +3731,7 @@ }, { "cell_type": "markdown", - "id": "210", + "id": "233", "metadata": {}, "source": [ "### Multiple Deck.GL Layers\n", @@ -3564,7 +3744,7 @@ { "cell_type": "code", "execution_count": null, - "id": "211", + "id": "234", "metadata": {}, "outputs": [], "source": [ @@ -3575,7 +3755,7 @@ { "cell_type": "code", "execution_count": null, - "id": "212", + "id": "235", "metadata": {}, "outputs": [], "source": [ @@ -3626,7 +3806,7 @@ }, { "cell_type": "markdown", - "id": "213", + "id": "236", "metadata": {}, "source": [ "The result is a rich, interactive visualization that highlights both point data and relational data connections, useful for airport connectivity or hub-and-spoke modeling.\n", @@ -3642,7 +3822,7 @@ { "cell_type": "code", "execution_count": null, - "id": "214", + "id": "237", "metadata": {}, "outputs": [], "source": [ @@ -3658,7 +3838,7 @@ { "cell_type": "code", "execution_count": null, - "id": "215", + "id": "238", "metadata": {}, "outputs": [], "source": [ @@ -3667,16 +3847,24 @@ }, { "cell_type": "markdown", - "id": "216", + "id": "239", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/oHQDf79.png)" + ] + }, + { + "cell_type": "markdown", + "id": "240", "metadata": {}, "source": [ - "You can overlay Earth Engine data with other 3D elements, like buildings, to create a multi-layered, interactive map. If you have an Earth Engine account, authenticate and initialize Earth Engine in your notebook by uncommenting the relevant code." + "You can overlay Earth Engine data with other 3D elements, like buildings, to create a multi-layered, interactive map. " ] }, { "cell_type": "code", "execution_count": null, - "id": "217", + "id": "241", "metadata": {}, "outputs": [], "source": [ @@ -3691,16 +3879,24 @@ }, { "cell_type": "markdown", - "id": "218", + "id": "242", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/Y52jep5.png)" + ] + }, + { + "cell_type": "markdown", + "id": "243", "metadata": {}, "source": [ - "If you have an Earth Engine, you can uncomment the first two code blocks to add any Earth Engine datasets." + "If you have an Earth Engine account, authenticate and initialize Earth Engine in your notebook by uncommenting the relevant code." ] }, { "cell_type": "code", "execution_count": null, - "id": "219", + "id": "244", "metadata": {}, "outputs": [], "source": [ @@ -3713,7 +3909,7 @@ { "cell_type": "code", "execution_count": null, - "id": "220", + "id": "245", "metadata": {}, "outputs": [], "source": [ @@ -3728,12 +3924,12 @@ }, { "cell_type": "markdown", - "id": "221", + "id": "246", "metadata": {}, "source": [ "## Animations\n", "\n", - "### Animate a Line\n", + "### Animating a Line\n", "\n", "Using Leafmap’s animation capabilities, you can animate a line by updating the coordinates of a GeoJSON line feature in real-time. The sample includes data loaded from a CSV file, which is sorted and plotted sequentially to show the line’s movement." ] @@ -3741,7 +3937,7 @@ { "cell_type": "code", "execution_count": null, - "id": "222", + "id": "247", "metadata": {}, "outputs": [], "source": [ @@ -3752,7 +3948,7 @@ { "cell_type": "code", "execution_count": null, - "id": "223", + "id": "248", "metadata": {}, "outputs": [], "source": [ @@ -3766,7 +3962,7 @@ { "cell_type": "code", "execution_count": null, - "id": "224", + "id": "249", "metadata": {}, "outputs": [], "source": [ @@ -3793,7 +3989,7 @@ { "cell_type": "code", "execution_count": null, - "id": "225", + "id": "250", "metadata": {}, "outputs": [], "source": [ @@ -3808,10 +4004,18 @@ }, { "cell_type": "markdown", - "id": "226", + "id": "251", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/LRwfBl9.png)" + ] + }, + { + "cell_type": "markdown", + "id": "252", "metadata": {}, "source": [ - "### Animate the Map Camera Around a Point\n", + "### Animating the Map Camera Around a Point\n", "\n", "Control the map camera's rotation, zoom, and angle around a given point to create a smooth animation effect. This technique is especially useful for visualizing cityscapes or other 3D environments by making buildings appear dynamic." ] @@ -3819,7 +4023,7 @@ { "cell_type": "code", "execution_count": null, - "id": "227", + "id": "253", "metadata": {}, "outputs": [], "source": [ @@ -3864,10 +4068,18 @@ }, { "cell_type": "markdown", - "id": "228", + "id": "254", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/odCwtjT.png)" + ] + }, + { + "cell_type": "markdown", + "id": "255", "metadata": {}, "source": [ - "### Animate a Point\n", + "### Animating a Point\n", "\n", "Animate a point along a circular path by computing points on a circle and updating the map. This is ideal for showing circular motion on the map, and can be customized for duration and frame rate to control the animation speed." ] @@ -3875,7 +4087,7 @@ { "cell_type": "code", "execution_count": null, - "id": "229", + "id": "256", "metadata": {}, "outputs": [], "source": [ @@ -3887,7 +4099,7 @@ { "cell_type": "code", "execution_count": null, - "id": "230", + "id": "257", "metadata": {}, "outputs": [], "source": [ @@ -3897,7 +4109,7 @@ { "cell_type": "code", "execution_count": null, - "id": "231", + "id": "258", "metadata": {}, "outputs": [], "source": [ @@ -3911,7 +4123,7 @@ { "cell_type": "code", "execution_count": null, - "id": "232", + "id": "259", "metadata": {}, "outputs": [], "source": [ @@ -3932,7 +4144,7 @@ { "cell_type": "code", "execution_count": null, - "id": "233", + "id": "260", "metadata": {}, "outputs": [], "source": [ @@ -3950,7 +4162,7 @@ { "cell_type": "code", "execution_count": null, - "id": "234", + "id": "261", "metadata": {}, "outputs": [], "source": [ @@ -3961,7 +4173,7 @@ { "cell_type": "code", "execution_count": null, - "id": "235", + "id": "262", "metadata": {}, "outputs": [], "source": [ @@ -3970,10 +4182,18 @@ }, { "cell_type": "markdown", - "id": "236", + "id": "263", + "metadata": {}, + "source": [ + "![](https://i.imgur.com/EAxNQx4.png)" + ] + }, + { + "cell_type": "markdown", + "id": "264", "metadata": {}, "source": [ - "### Animate a Point Along a Route\n", + "### Animating a Point Along a Route\n", "\n", "Create a point that follows a route specified by GeoJSON coordinates. For added realism, include rotation properties to simulate the direction of movement along the path. This animation is useful for tracking paths, such as vehicle or drone routes." ] @@ -3981,7 +4201,7 @@ { "cell_type": "code", "execution_count": null, - "id": "237", + "id": "265", "metadata": {}, "outputs": [], "source": [ @@ -4026,7 +4246,7 @@ { "cell_type": "code", "execution_count": null, - "id": "238", + "id": "266", "metadata": {}, "outputs": [], "source": [ @@ -4039,10 +4259,18 @@ }, { "cell_type": "markdown", - "id": "239", + "id": "267", "metadata": {}, "source": [ - "### Update a Feature in Real-Time\n", + "![](https://i.imgur.com/kdP1oT1.png)" + ] + }, + { + "cell_type": "markdown", + "id": "268", + "metadata": {}, + "source": [ + "### Updating a Feature in Real-Time\n", "\n", "For applications such as tracking or tracing a path in real time, load data from a source like GeoDataFrame, append coordinates incrementally to a line feature, and update the map display as the path extends." ] @@ -4050,7 +4278,7 @@ { "cell_type": "code", "execution_count": null, - "id": "240", + "id": "269", "metadata": {}, "outputs": [], "source": [ @@ -4060,7 +4288,7 @@ { "cell_type": "code", "execution_count": null, - "id": "241", + "id": "270", "metadata": {}, "outputs": [], "source": [ @@ -4071,7 +4299,7 @@ { "cell_type": "code", "execution_count": null, - "id": "242", + "id": "271", "metadata": {}, "outputs": [], "source": [ @@ -4084,7 +4312,7 @@ { "cell_type": "code", "execution_count": null, - "id": "243", + "id": "272", "metadata": {}, "outputs": [], "source": [ @@ -4110,7 +4338,7 @@ { "cell_type": "code", "execution_count": null, - "id": "244", + "id": "273", "metadata": {}, "outputs": [], "source": [ @@ -4123,7 +4351,7 @@ }, { "cell_type": "markdown", - "id": "245", + "id": "274", "metadata": {}, "source": [ "## To HTML\n", @@ -4134,7 +4362,7 @@ { "cell_type": "code", "execution_count": null, - "id": "246", + "id": "275", "metadata": {}, "outputs": [], "source": [ @@ -4146,7 +4374,7 @@ { "cell_type": "code", "execution_count": null, - "id": "247", + "id": "276", "metadata": {}, "outputs": [], "source": [ @@ -4167,7 +4395,7 @@ { "cell_type": "code", "execution_count": null, - "id": "248", + "id": "277", "metadata": {}, "outputs": [], "source": [ @@ -4189,7 +4417,7 @@ }, { "cell_type": "markdown", - "id": "249", + "id": "278", "metadata": {}, "source": [ "## Summary\n", diff --git a/book/geospatial/maplibre.md b/book/geospatial/maplibre.md index 871905f..7eff38f 100644 --- a/book/geospatial/maplibre.md +++ b/book/geospatial/maplibre.md @@ -17,24 +17,27 @@ kernelspec: ## Overview -This lecture introduces the [MapLibre](https://github.com/eodaGmbH/py-maplibregl) Python package, a flexible open-source mapping Python package that allows users to create interactive and customizable 3D and 2D maps in Python. By leveraging the MapLibre library, GIS developers can visualize geospatial data with a variety of customization options and mapping styles. The notebook demonstrates essential concepts like creating interactive maps, customizing basemaps, adding various data layers, and implementing map controls for enhanced functionality. Additionally, advanced features, such as 3D building visualization and layer control, provide students with practical tools for real-world geospatial data analysis and visualization. +This lecture introduces the [MapLibre](https://github.com/eodaGmbH/py-maplibregl) mapping backend in the Leafmap library—a powerful open-source Python tool for creating customizable 2D and 3D interactive maps. With MapLibre, GIS professionals can develop tailored visualizations that enhance data presentation and geospatial analysis. The provided Jupyter notebook demonstrates foundational skills, including interactive map creation, basemap customization, and data layer integration. Additionally, advanced features such as 3D building visualizations and dynamic map controls equip students with practical skills for effective geospatial data visualization and analysis. ## Learning Outcomes By the end of this lecture, students will be able to: -1. Set up and install MapLibre for geospatial visualization in Python. -2. Create basic interactive maps and apply different basemap styles. -3. Customize map features, including markers, lines, polygons, and map controls. -4. Utilize advanced features such as 3D buildings and choropleth maps. -5. Integrate and manage multiple data layers, including GeoJSON, raster, and vector layers. -6. Export map visualizations as standalone HTML files for sharing and deployment. +1. **Set up and install MapLibre** for Python-based geospatial visualization. +2. **Create interactive maps** and apply various basemap styles. +3. **Customize map elements**, including markers, lines, polygons, and interactive controls. +4. **Explore advanced features** like 3D building models and choropleth maps. +5. **Integrate and manage multiple data layers**, such as GeoJSON, raster, and vector formats. +6. **Export interactive maps** as standalone HTML files for easy sharing and web deployment. ## Useful Resources -- Notebooks: https://leafmap.org/maplibre/overview -- Videos: https://bit.ly/maplibre -- Demos: https://maps.gishub.org +- [MapLibre GL JS Documentation](https://maplibre.org/maplibre-gl-js/docs): Comprehensive documentation for MapLibre GL JS. +- [MapLibre Python Bindings](https://github.com/eoda-dev/py-maplibregl): Information on using MapLibre with Python. +- [MapLibre in Leafmap](https://leafmap.org/maplibre/overview): Examples and tutorials for MapLibre in Leafmap. +- [Video Tutorials](https://bit.ly/maplibre): Video guides for practical MapLibre skills. +- [MapLibre Demos](https://maps.gishub.org): Interactive demos showcasing MapLibre’s capabilities. + ## Installation and Setup @@ -54,7 +57,7 @@ import leafmap.maplibregl as leafmap ### Basic Map Setup -Let’s start by creating a simple interactive map with default settings. This basic setup provides a blank canvas on which you can add data layers, controls, and other customizations. +Let’s start by creating a simple interactive map with default settings. This basic setup provides simple map with the `dark-matter` style on which you can add data layers, controls, and other customizations. ```{code-cell} ipython3 m = leafmap.Map() @@ -70,6 +73,10 @@ m = leafmap.Map(center=[-100, 40], zoom=3, pitch=0, bearing=0) m ``` +Hold down the `Ctrl` key. Click and drag to pan the map. + ++++ + ### Choosing a Basemap Style MapLibre supports several pre-defined basemap styles such as `dark-matter`, `positron`, `voyager`, `liberty`, `demotiles`. You can also use custom basemap URLs for unique styling. @@ -79,6 +86,8 @@ m = leafmap.Map(style="positron") m ``` +[OpenFreeMap](https://openfreemap.org) provides a variety of basemap styles that you can use in your interactive maps. These styles include `liberty`, `bright`, and `positron`. + ```{code-cell} ipython3 m = leafmap.Map(style="liberty") m @@ -107,9 +116,8 @@ Map controls enhance the usability of the map by allowing users to interact in v ### Available Controls -- **Scale**: Adds a scale bar to indicate the map’s scale. -- **Fullscreen**: Expands the map to a full-screen view for better focus. - **Geolocate**: Centers the map based on the user’s current location, if available. +- **Fullscreen**: Expands the map to a full-screen view for better focus. - **Navigation**: Provides zoom controls and a compass for reorientation. - **Draw**: Allows users to draw and edit shapes on the map. @@ -218,6 +226,10 @@ m.add_draw_control(position="top-left", geojson=geojson) m ``` +![](https://i.imgur.com/w8UFssd.png) + ++++ + Two key methods for accessing drawn features: - **Selected Features**: Accesses only the currently selected features. @@ -231,7 +243,7 @@ m.draw_features_selected m.draw_feature_collection_all ``` -## Add Layers +## Adding Layers Adding layers to a map enhances the data it presents, allowing different types of basemaps, tile layers, and thematic overlays to be combined for in-depth analysis. @@ -250,13 +262,13 @@ m m.add_basemap("Esri.WorldImagery") ``` +You can also add basemaps interactively, which provides flexibility for selecting the best background for your map content. + ```{code-cell} ipython3 m = leafmap.Map() m ``` -You can also add basemaps interactively, which provides flexibility for selecting the best background for your map content. - ```{code-cell} ipython3 m.add_basemap() ``` @@ -333,7 +345,7 @@ m ## MapTiler -To use MapTiler with this notebook, you need to set up a MapTiler API key. You can obtain a free API key by signing up at [https://cloud.maptiler.com/](https://cloud.maptiler.com/). +To use MapTiler with this notebook, you need to set up a MapTiler API key. You can obtain a free API key by signing up at [https://cloud.maptiler.com/](https://cloud.maptiler.com). ```{code-cell} ipython3 # import os @@ -371,7 +383,7 @@ m = leafmap.Map(style="topo") m ``` -### Add a vector tile source +### Adding a vector tile source To include vector data from MapTiler, first obtain the MapTiler API key and then set up a vector source with the desired tile data URL. The vector tile source can then be added to a layer to display features such as contour lines, which are styled for better visibility and engagement. @@ -422,6 +434,8 @@ m.add_layer_control(bg_layers=True) m ``` +![](https://i.imgur.com/3Q2Q3CG.png) + ```{code-cell} ipython3 m = leafmap.Map( center=[-122.1874314, 46.2022386], @@ -434,6 +448,8 @@ m.add_layer_control(bg_layers=True) m ``` +![](https://i.imgur.com/5PNMbAv.png) + ```{code-cell} ipython3 m = leafmap.Map( center=[-122.1874314, 46.2022386], @@ -448,6 +464,8 @@ m.add_layer_control(bg_layers=True) m ``` +![](https://i.imgur.com/y33leIj.png) + ```{code-cell} ipython3 m = leafmap.Map( center=[-122.1874314, 46.2022386], @@ -466,6 +484,10 @@ m.add_layer_control(bg_layers=True) m ``` +![](https://i.imgur.com/m6NwSWG.png) + ++++ + ### 3D Buildings Adding 3D buildings enhances urban visualizations, showing buildings with height variations. The setup involves specifying the MapTiler API key for vector tiles and adding building data as a 3D extrusion layer. The extrusion height and color can be set based on data attributes to visualize structures with varying heights, which can be useful in city planning and urban analysis. @@ -522,6 +544,8 @@ m.add_layer_control() m ``` +![](https://i.imgur.com/9QeicaE.png) + ```{code-cell} ipython3 m = leafmap.Map( center=[-74.01201, 40.70473], zoom=16, pitch=60, bearing=35, style="basic-v2" @@ -566,6 +590,10 @@ m.add_layer_control() m ``` +![](https://i.imgur.com/eYhSWaT.png) + ++++ + ### 3D Choropleth Map Choropleth maps in 3D allow visualizing attribute data by height, where regions are colored and extruded based on specific attributes, such as age or population area. Two examples are provided below: @@ -619,6 +647,8 @@ m.add_layer_control() m ``` +![](https://i.imgur.com/fLgqYTa.png) + ```{code-cell} ipython3 m = leafmap.Map(center=[-100, 40], zoom=3, pitch=60, style="basic") source = { @@ -654,7 +684,7 @@ m.add_layer_control() m ``` -## Visualize Vector Data +## Visualizing Vector Data Leafmap provides a variety of methods to visualize vector data on a map, allowing you to display points, lines, polygons, and other vector shapes with custom styling and interactivity. @@ -676,6 +706,8 @@ m.add_marker(lng_lat=[12.550343, 55.665957]) m ``` +![](https://i.imgur.com/ufmqTzx.png) + ```{code-cell} ipython3 m = leafmap.Map(center=[12.550343, 55.665957], zoom=8, style="positron") m.add_marker(lng_lat=[12.550343, 55.665957], options={"draggable": True}) @@ -715,7 +747,7 @@ m.add_popup("cities") m ``` -### Customize Marker Icon Image +### Customizing Marker Icon Image To further customize point data, an image icon can be used instead of the default marker: @@ -984,6 +1016,10 @@ m.add_geojson( m ``` +![](https://i.imgur.com/VWvJKwl.png) + ++++ + ### Local Vector Data Local vector files, such as GeoJSON, can be loaded directly into the map. The example downloads a GeoJSON file representing U.S. states and adds it to the map using `open_geojson`. @@ -1020,7 +1056,7 @@ m.add_gdf(gdf, layer_type="fill", name="States", paint=paint) m ``` -### Change Building Color +### Changing Building Color You can customize the color and opacity of buildings based on the map’s zoom level. This example changes building colors from orange at lower zoom levels to lighter shades as the zoom level increases. Additionally, the opacity gradually transitions to fully opaque, making buildings more visible at close-up zoom levels. @@ -1044,7 +1080,11 @@ m m.add_call("zoomTo", 19, {"duration": 9000}) ``` -### Add a New Layer Below Labels +![](https://i.imgur.com/PayiTON.png) + ++++ + +### Adding a New Layer Below Labels A layer can be added below existing labels on the map to enhance clarity without obscuring labels. The urban areas dataset is displayed as a fill layer in a color and opacity that visually distinguishes it from other map elements. The layer is positioned below symbols, allowing place names to remain visible. @@ -1160,7 +1200,11 @@ m.add_layer(layer2, before_id="waterway") m ``` -### Visualize Population Density +![](https://i.imgur.com/OLCRPKj.png) + ++++ + +### Visualizing Population Density Population density can be calculated and displayed dynamically. This example loads a GeoJSON of Rwandan provinces, calculating density by dividing population by area. The fill color of each province is then adjusted based on density, with different color schemes applied depending on the zoom level. @@ -1214,7 +1258,7 @@ m.add_layer(layer) m ``` -## Visualize Raster Data +## Visualizing Raster Data ### Local Raster Data @@ -1242,6 +1286,8 @@ m m.layer_interact() ``` +A Digital Elevation Model (DEM) is also downloaded and visualized with a terrain color scheme. Leafmap’s `layer_interact` method allows interactive adjustments. + ```{code-cell} ipython3 url = "https://github.com/opengeos/datasets/releases/download/raster/srtm90.tif" filepath = "srtm90.tif" @@ -1254,8 +1300,6 @@ m.add_raster(filepath, colormap="terrain", name="DEM") m ``` -A Digital Elevation Model (DEM) is also downloaded and visualized with a terrain color scheme. Leafmap’s `layer_interact` method allows interactive adjustments. - ```{code-cell} ipython3 m.layer_interact() ``` @@ -1299,7 +1343,7 @@ m m.layer_interact() ``` -For more control, the `collection` and `item` parameters let you specify specific assets, such as color infrared bands, for focused analysis. +Leafmap also supports loading STAC items from the [Microsoft Planetary Computer](https://planetarycomputer.microsoft.com). The example demonstrates how to load a STAC item from the Planetary Computer and display it on the map. ```{code-cell} ipython3 collection = "landsat-8-c2-l2" @@ -1321,12 +1365,12 @@ m.add_stac_layer( m ``` -## Interact with the Map +## Interacting with the Map Interactivity allows for a more tailored map experience. -### Display a Non-Interactive Map +### Displaying a Non-Interactive Map To create a static map, set `interactive=False`. This disables all user interactions, making it ideal for static presentations. @@ -1337,7 +1381,7 @@ m = leafmap.Map( m ``` -### Disable Scroll Zoom +### Disabling Scroll Zoom Use `scroll_zoom=False` to prevent map zooming with the scroll wheel, maintaining a fixed zoom level. @@ -1346,7 +1390,7 @@ m = leafmap.Map(center=[-122.65, 45.52], zoom=9, scroll_zoom=False, style="liber m ``` -### Fit Bounds +### Fitting Bounds The `fit_bounds` method focuses the map on a specified area. In this example, the map centers on Kenya. Additionally, a GeoJSON line is added to the map, and its bounds are automatically calculated with `geojson_bounds` for a custom zoom fit. @@ -1412,7 +1456,7 @@ bounds m.fit_bounds(bounds) ``` -### Restrict Map Panning to an Area +### Restricting Map Panning to an Area To limit map panning to a specific area, define a bounding box. The map is then restricted within the bounds, ensuring users do not accidentally pan away from the area of interest. @@ -1428,7 +1472,7 @@ m = leafmap.Map(center=[-73.9978, 40.7209], zoom=13, max_bounds=bounds, style="l m ``` -### Fly To +### Flying To The `fly_to` method smoothly navigates to specified coordinates. Parameters like speed and zoom provide control over the fly-to effect. This example flies from the initial map location to New York City. @@ -1460,7 +1504,7 @@ options = { m.fly_to(**options) ``` -### Jump to a Series of Locations +### Jumping to a Series of Locations Using `jump_to`, you can navigate between multiple locations. This example sets up a list of coordinates representing cities and automatically pans to each one in sequence. Adding a delay between transitions enhances the animation effect. @@ -1516,7 +1560,7 @@ for index, city in enumerate(cities["features"]): m.jump_to({"center": coords}) ``` -### Get Coordinates of the Mouse Pointer +### Getting Coordinates of the Mouse Pointer With widgets, you can display the current mouse pointer coordinates as it moves across the map. This is useful for precision mapping tasks where knowing exact coordinates is essential. @@ -1551,7 +1595,7 @@ output Customizing layer styles enables personalized map designs. -### Change Layer Color +### Changing Layer Color Use `style_layer_interact` to interactively change the color of map layers, such as water bodies. This method provides an interactive palette for immediate style changes. @@ -1564,7 +1608,7 @@ m m.style_layer_interact(id="water") ``` -### Change Case of Labels +### Changing Case of Labels This example displays labels in upper or lower case based on their properties. The layout options let you customize font, size, and alignment. For example, facility names are displayed in uppercase, and comments are displayed in lowercase for contrast. @@ -1599,6 +1643,10 @@ m.add_layer(layer) m ``` +![](https://i.imgur.com/FzGOovv.png) + ++++ + ### Variable Label Placement Labels can be automatically positioned around features with `text-variable-anchor`. This example defines multiple anchor points for labels to avoid overlap and ensure clear visibility. The radial offset and auto-justification properties create a professional, clutter-free appearance around points of interest. @@ -1673,7 +1721,7 @@ m.rotate_to(bearing=180, options={"duration": 10000}) Enhance your maps by adding custom components such as images, videos, text, color bars, and legends. -### Add Image +### Adding Image You can add an image as an overlay or as an icon for a specific layer. For instance: - Overlaying an image directly on the map at the "bottom-right" corner. @@ -1711,6 +1759,8 @@ m.add_layer(layer) m ``` +![](https://i.imgur.com/Nq1uV9d.png) + ```{code-cell} ipython3 m = leafmap.Map(center=[-100, 40], zoom=3, style="positron") image = "https://i.imgur.com/LmTETPX.png" @@ -1778,7 +1828,11 @@ m.add_layer(layer) m ``` -### Add Text +![](https://i.imgur.com/qWWlnAm.png) + ++++ + +### Adding Text Add text annotations to the map, specifying parameters like font size and background color. For example: - Text "Hello World" in the bottom-right corner with a transparent background. @@ -1793,7 +1847,11 @@ m.add_text(text2, fontsize=25, bg_color="rgba(255, 255, 255, 0.8)", position="to m ``` -### Add GIF +![](https://i.imgur.com/UAtlh3r.png) + ++++ + +### Adding GIF GIFs can be added as animated overlays to bring your map to life. Example: add a sloth GIF in the bottom-right and a second GIF in the bottom-left corner, with a text label indicating “I love sloth!” for added character. @@ -1808,7 +1866,11 @@ m.add_image(image=image2, bg_color="transparent", position="bottom-left") m ``` -### Add HTML +![](https://i.imgur.com/auytBtD.png) + ++++ + +### Adding HTML Embed custom HTML content to display various HTML elements, such as emojis or stylized text. You can also adjust the font size and background transparency for better integration into the map design. @@ -1834,7 +1896,11 @@ m.add_html(html, bg_color="transparent") m ``` -### Add Colorbar +![](https://i.imgur.com/TgalNOv.png) + ++++ + +### Adding Color bar Adding a color bar enhances data interpretation. In the example: 1. A Digital Elevation Model (DEM) is displayed with a color ramp from 0 to 1500 meters. @@ -1858,6 +1924,8 @@ m.add_layer_control() m ``` +Make the color bar background transparent to blend seamlessly with the map. + ```{code-cell} ipython3 m = leafmap.Map(style="topo") m.add_cog_layer( @@ -1879,6 +1947,8 @@ m.add_colorbar( m ``` +Make the color bar vertical for a different layout. + ```{code-cell} ipython3 m = leafmap.Map(style="topo") m.add_cog_layer( @@ -1902,7 +1972,7 @@ m.add_colorbar( m ``` -### Add Legend +### Adding Legend Custom legends help users understand data classifications. Two methods are shown: 1. Using built-in legends, such as for NLCD (National Land Cover Database) or wetland types. @@ -1971,13 +2041,13 @@ m.add_legend( m ``` -### Add Video +![](https://i.imgur.com/dy60trf.png) -Videos can be added with geographic context by specifying corner coordinates. Videos must be listed in multiple formats to ensure compatibility across browsers. The coordinates array should define the video’s location on the map in the order: top-left, top-right, bottom-right, and bottom-left. This is demonstrated by adding drone footage to a satellite map view, enhancing the user experience with real-world visuals. ++++ +### Adding Video -The `urls` value is an array. For each URL in the array, a video element source will be created. To support the video across browsers, supply URLs in multiple formats. -The `coordinates` array contains [longitude, latitude] pairs for the video corners listed in clockwise order: top left, top right, bottom right, bottom left. +Videos can be added with geographic context by specifying corner coordinates. Videos must be listed in multiple formats to ensure compatibility across browsers. The coordinates array should define the video’s location on the map in the order: top-left, top-right, bottom-right, and bottom-left. This is demonstrated by adding drone footage to a satellite map view, enhancing the user experience with real-world visuals. ```{code-cell} ipython3 m = leafmap.Map( @@ -2017,7 +2087,7 @@ m ## PMTiles -Leafmap supports the [PMTiles](https://protomaps.com/docs/pmtiles/) format, enabling efficient storage and fast rendering of vector tiles directly in the browser. +Leafmap supports visualizing [PMTiles](https://protomaps.com/docs/pmtiles/), which enables efficient storage and fast rendering of vector tiles directly in the browser. ### Protomaps Sample Data @@ -2078,9 +2148,7 @@ m.layer_interact() ### Source Cooperative Data -Visualize the Google-Microsoft Open Buildings dataset, managed by VIDA, in PMTiles format. Fetch metadata to identify available layers, apply custom styles to the building footprints, and render them with semi-transparent colors for a clear visualization. - -Let's visualize the [Google-Microsoft Open Buildings - combined by VIDA](https://beta.source.coop/repositories/vida/google-microsoft-open-buildings/description). +Visualize the [Google-Microsoft Open Buildings dataset](https://beta.source.coop/repositories/vida/google-microsoft-open-buildings/description), managed by VIDA, in PMTiles format. Fetch metadata to identify available layers, apply custom styles to the building footprints, and render them with semi-transparent colors for a clear visualization. ```{code-cell} ipython3 url = "https://data.source.coop/vida/google-microsoft-open-buildings/pmtiles/go_ms_building_footprints.pmtiles" @@ -2380,7 +2448,11 @@ m m.layer_interact() ``` -You can overlay Earth Engine data with other 3D elements, like buildings, to create a multi-layered, interactive map. If you have an Earth Engine account, authenticate and initialize Earth Engine in your notebook by uncommenting the relevant code. +![](https://i.imgur.com/oHQDf79.png) + ++++ + +You can overlay Earth Engine data with other 3D elements, like buildings, to create a multi-layered, interactive map. ```{code-cell} ipython3 m = leafmap.Map( @@ -2392,7 +2464,11 @@ m.add_legend(builtin_legend="ESA_WorldCover", title="ESA Landcover") m ``` -If you have an Earth Engine, you can uncomment the first two code blocks to add any Earth Engine datasets. +![](https://i.imgur.com/Y52jep5.png) + ++++ + +If you have an Earth Engine account, authenticate and initialize Earth Engine in your notebook by uncommenting the relevant code. ```{code-cell} ipython3 # import ee @@ -2413,7 +2489,7 @@ If you have an Earth Engine, you can uncomment the first two code blocks to add ## Animations -### Animate a Line +### Animating a Line Using Leafmap’s animation capabilities, you can animate a line by updating the coordinates of a GeoJSON line feature in real-time. The sample includes data loaded from a CSV file, which is sorted and plotted sequentially to show the line’s movement. @@ -2461,7 +2537,11 @@ for i in range(run_times): m.set_data("line", geojson) ``` -### Animate the Map Camera Around a Point +![](https://i.imgur.com/LRwfBl9.png) + ++++ + +### Animating the Map Camera Around a Point Control the map camera's rotation, zoom, and angle around a given point to create a smooth animation effect. This technique is especially useful for visualizing cityscapes or other 3D environments by making buildings appear dynamic. @@ -2505,7 +2585,11 @@ m.add_layer(layer) m ``` -### Animate a Point +![](https://i.imgur.com/odCwtjT.png) + ++++ + +### Animating a Point Animate a point along a circular path by computing points on a circle and updating the map. This is ideal for showing circular motion on the map, and can be customized for duration and frame rate to control the animation speed. @@ -2563,7 +2647,11 @@ frame_rate = 30 # Frames per second animate_marker(duration, frame_rate, radius) ``` -### Animate a Point Along a Route +![](https://i.imgur.com/EAxNQx4.png) + ++++ + +### Animating a Point Along a Route Create a point that follows a route specified by GeoJSON coordinates. For added realism, include rotation properties to simulate the direction of movement along the path. This animation is useful for tracking paths, such as vehicle or drone routes. @@ -2614,7 +2702,11 @@ for index, coordinate in enumerate(coordinates): time.sleep(0.05) ``` -### Update a Feature in Real-Time +![](https://i.imgur.com/kdP1oT1.png) + ++++ + +### Updating a Feature in Real-Time For applications such as tracking or tracing a path in real time, load data from a source like GeoDataFrame, append coordinates incrementally to a line feature, and update the map display as the path extends.