"""Module for basemaps.
Each basemap is defined as an item in the `basemaps` dictionary.
For example, to access Google basemaps, use the following:
* `basemaps['ROADMAP']`
* `basemaps['SATELLITE']`
* `basemaps['HYBRID']`
More WMS basemaps can be found at the following websites:
1. USGS National Map: https://viewer.nationalmap.gov/services/
2. MRLC NLCD Land Cover data: https://viewer.nationalmap.gov/services/
3. FWS NWI Wetlands data: https://www.fws.gov/wetlands/Data/Web-Map-Services.html
"""
# *******************************************************************************#
# This module contains core features and extra features of the geemap package. #
# The Earth Engine team and the geemap community will maintain the core features.#
# The geemap community will maintain the extra features. #
# The core features include classes and functions below until the line # ******* #
# *******************************************************************************#
import collections
import os
import requests
import folium
import ipyleaflet
import xyzservices
from .common import check_package, planet_tiles
# Custom XYZ tile services.
XYZ_TILES = {
"OpenStreetMap": {
"url": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
"attribution": "OpenStreetMap",
"name": "OpenStreetMap",
},
"ROADMAP": {
"url": "https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}",
"attribution": "Google",
"name": "Google Maps",
},
"SATELLITE": {
"url": "https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}",
"attribution": "Google",
"name": "Google Satellite",
},
"TERRAIN": {
"url": "https://mt1.google.com/vt/lyrs=p&x={x}&y={y}&z={z}",
"attribution": "Google",
"name": "Google Terrain",
},
"HYBRID": {
"url": "https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}",
"attribution": "Google",
"name": "Google Hybrid",
},
}
# Custom WMS tile services.
WMS_TILES = {
"FWS NWI Wetlands": {
"url": "https://www.fws.gov/wetlands/arcgis/services/Wetlands/MapServer/WMSServer?",
"layers": "1",
"name": "FWS NWI Wetlands",
"attribution": "FWS",
"format": "image/png",
"transparent": True,
},
"FWS NWI Wetlands Raster": {
"url": "https://www.fws.gov/wetlands/arcgis/services/Wetlands_Raster/ImageServer/WMSServer?",
"layers": "0",
"name": "FWS NWI Wetlands Raster",
"attribution": "FWS",
"format": "image/png",
"transparent": True,
},
"NLCD 2019 CONUS Land Cover": {
"url": "https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2019_Land_Cover_L48/wms?",
"layers": "NLCD_2019_Land_Cover_L48",
"name": "NLCD 2019 CONUS Land Cover",
"attribution": "MRLC",
"format": "image/png",
"transparent": True,
},
"NLCD 2016 CONUS Land Cover": {
"url": "https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2016_Land_Cover_L48/wms?",
"layers": "NLCD_2016_Land_Cover_L48",
"name": "NLCD 2016 CONUS Land Cover",
"attribution": "MRLC",
"format": "image/png",
"transparent": True,
},
"NLCD 2013 CONUS Land Cover": {
"url": "https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2013_Land_Cover_L48/wms?",
"layers": "NLCD_2013_Land_Cover_L48",
"name": "NLCD 2013 CONUS Land Cover",
"attribution": "MRLC",
"format": "image/png",
"transparent": True,
},
"NLCD 2011 CONUS Land Cover": {
"url": "https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2011_Land_Cover_L48/wms?",
"layers": "NLCD_2011_Land_Cover_L48",
"name": "NLCD 2011 CONUS Land Cover",
"attribution": "MRLC",
"format": "image/png",
"transparent": True,
},
"NLCD 2008 CONUS Land Cover": {
"url": "https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2008_Land_Cover_L48/wms?",
"layers": "NLCD_2008_Land_Cover_L48",
"name": "NLCD 2008 CONUS Land Cover",
"attribution": "MRLC",
"format": "image/png",
"transparent": True,
},
"NLCD 2006 CONUS Land Cover": {
"url": "https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2006_Land_Cover_L48/wms?",
"layers": "NLCD_2006_Land_Cover_L48",
"name": "NLCD 2006 CONUS Land Cover",
"attribution": "MRLC",
"format": "image/png",
"transparent": True,
},
"NLCD 2004 CONUS Land Cover": {
"url": "https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2004_Land_Cover_L48/wms?",
"layers": "NLCD_2004_Land_Cover_L48",
"name": "NLCD 2004 CONUS Land Cover",
"attribution": "MRLC",
"format": "image/png",
"transparent": True,
},
"NLCD 2001 CONUS Land Cover": {
"url": "https://www.mrlc.gov/geoserver/mrlc_display/NLCD_2001_Land_Cover_L48/wms?",
"layers": "NLCD_2001_Land_Cover_L48",
"name": "NLCD 2001 CONUS Land Cover",
"attribution": "MRLC",
"format": "image/png",
"transparent": True,
},
"USGS NAIP Imagery": {
"url": "https://imagery.nationalmap.gov/arcgis/services/USGSNAIPImagery/ImageServer/WMSServer?",
"layers": "USGSNAIPImagery:NaturalColor",
"name": "USGS NAIP Imagery",
"attribution": "USGS",
"format": "image/png",
"transparent": True,
},
"USGS NAIP Imagery False Color": {
"url": "https://imagery.nationalmap.gov/arcgis/services/USGSNAIPImagery/ImageServer/WMSServer?",
"layers": "USGSNAIPImagery:FalseColorComposite",
"name": "USGS NAIP Imagery False Color",
"attribution": "USGS",
"format": "image/png",
"transparent": True,
},
"USGS NAIP Imagery NDVI": {
"url": "https://imagery.nationalmap.gov/arcgis/services/USGSNAIPImagery/ImageServer/WMSServer?",
"layers": "USGSNAIPImagery:NDVI_Color",
"name": "USGS NAIP Imagery NDVI",
"attribution": "USGS",
"format": "image/png",
"transparent": True,
},
"USGS Hydrography": {
"url": "https://basemap.nationalmap.gov/arcgis/services/USGSHydroCached/MapServer/WMSServer?",
"layers": "0",
"name": "USGS Hydrography",
"attribution": "USGS",
"format": "image/png",
"transparent": True,
},
"USGS 3DEP Elevation": {
"url": "https://elevation.nationalmap.gov/arcgis/services/3DEPElevation/ImageServer/WMSServer?",
"layers": "33DEPElevation:Hillshade Elevation Tinted",
"name": "USGS 3DEP Elevation",
"attribution": "USGS",
"format": "image/png",
"transparent": True,
},
"ESA WorldCover 2020": {
"url": "https://services.terrascope.be/wms/v2",
"layers": "WORLDCOVER_2020_MAP",
"name": "ESA Worldcover 2020",
"attribution": "ESA",
"format": "image/png",
"transparent": True,
},
"ESA WorldCover 2020 S2 FCC": {
"url": "https://services.terrascope.be/wms/v2",
"layers": "WORLDCOVER_2020_S2_FCC",
"name": "ESA Worldcover 2020 S2 FCC",
"attribution": "ESA",
"format": "image/png",
"transparent": True,
},
"ESA WorldCover 2020 S2 TCC": {
"url": "https://services.terrascope.be/wms/v2",
"layers": "WORLDCOVER_2020_S2_TCC",
"name": "ESA Worldcover 2020 S2 TCC",
"attribution": "ESA",
"format": "image/png",
"transparent": True,
},
"ESA WorldCover 2021": {
"url": "https://services.terrascope.be/wms/v2",
"layers": "WORLDCOVER_2021_MAP",
"name": "ESA Worldcover 2021",
"attribution": "ESA",
"format": "image/png",
"transparent": True,
},
"ESA WorldCover 2021 S2 FCC": {
"url": "https://services.terrascope.be/wms/v2",
"layers": "WORLDCOVER_2021_S2_FCC",
"name": "ESA Worldcover 2021 S2 FCC",
"attribution": "ESA",
"format": "image/png",
"transparent": True,
},
"ESA WorldCover 2021 S2 TCC": {
"url": "https://services.terrascope.be/wms/v2",
"layers": "WORLDCOVER_2021_S2_TCC",
"name": "ESA Worldcover 2021 S2 TCC",
"attribution": "ESA",
"format": "image/png",
"transparent": True,
},
}
custom_tiles = {"xyz": XYZ_TILES, "wms": WMS_TILES}
[docs]def get_xyz_dict(free_only=True, france=False):
"""Returns a dictionary of xyz services.
Args:
free_only (bool, optional): Whether to return only free xyz tile
services that do not require an access token. Defaults to True.
france (bool, optional): Whether to include Geoportail France basemaps.
Defaults to False.
Returns:
dict: A dictionary of xyz services.
"""
xyz_bunch = xyzservices.providers
if free_only:
xyz_bunch = xyz_bunch.filter(requires_token=False)
if not france:
xyz_bunch = xyz_bunch.filter(
function=lambda tile: "france" not in dict(tile)["name"].lower()
)
xyz_dict = xyz_bunch.flatten()
for key, value in xyz_dict.items():
tile = xyzservices.TileProvider(value)
if "type" not in tile:
tile["type"] = "xyz"
xyz_dict[key] = tile
xyz_dict = collections.OrderedDict(sorted(xyz_dict.items()))
return xyz_dict
[docs]def xyz_to_leaflet():
"""Convert xyz tile services to ipyleaflet tile layers.
Returns:
dict: A dictionary of ipyleaflet tile layers.
"""
leaflet_dict = {}
# Add custom tiles.
for tile_type, tile_dict in custom_tiles.items():
for tile_provider, tile_info in tile_dict.items():
tile_info["type"] = tile_type
leaflet_dict[tile_info["name"]] = tile_info
# Add xyzservices.provider tiles.
for tile_provider, tile_info in get_xyz_dict().items():
tile_info["url"] = tile_info.build_url()
leaflet_dict[tile_info["name"]] = tile_info
return leaflet_dict
[docs]def xyz_to_folium():
"""Convert xyz tile services to folium tile layers.
Returns:
dict: A dictionary of folium tile layers.
"""
folium_dict = {}
for key, tile in custom_tiles["xyz"].items():
folium_dict[key] = folium.TileLayer(
tiles=tile["url"],
attr=tile["attribution"],
name=tile["name"],
overlay=True,
control=True,
max_zoom=22,
)
for key, tile in custom_tiles["wms"].items():
folium_dict[key] = folium.WmsTileLayer(
url=tile["url"],
layers=tile["layers"],
name=tile["name"],
attr=tile["attribution"],
fmt=tile["format"],
transparent=tile["transparent"],
overlay=True,
control=True,
)
for item in get_xyz_dict().values():
folium_dict[item.name] = folium.TileLayer(
tiles=item.build_url(),
attr=item.attribution,
name=item.name,
max_zoom=item.get("max_zoom", 22),
overlay=True,
control=True,
)
if os.environ.get("PLANET_API_KEY") is not None:
planet_dict = planet_tiles(tile_format="folium")
folium_dict.update(planet_dict)
return folium_dict
# ******************************************************************************#
# The classes and functions above are the core features of the geemap package. #
# The Earth Engine team and the geemap community will maintain these features. #
# ******************************************************************************#
# ******************************************************************************#
# The classes and functions below are the extra features of the geemap package. #
# The geemap community will maintain these features. #
# ******************************************************************************#
[docs]def xyz_to_pydeck():
"""Convert xyz tile services to pydeck custom tile layers.
Returns:
dict: A dictionary of pydeck tile layers.
"""
check_package("pydeck", "https://deckgl.readthedocs.io/en/latest/installation.html")
import pydeck as pdk
pydeck_dict = {}
for key, tile in custom_tiles["xyz"].items():
url = tile["url"]
pydeck_dict[key] = url
for key, item in get_xyz_dict().items():
url = item.build_url()
pydeck_dict[key] = url
if os.environ.get("PLANET_API_KEY") is not None:
planet_dict = planet_tiles(tile_format="ipyleaflet")
for id_, tile in planet_dict.items():
pydeck_dict[id_] = tile.url
pdk.settings.custom_libraries = [
{
"libraryName": "MyTileLayerLibrary",
"resourceUri": "https://cdn.jsdelivr.net/gh/giswqs/pydeck_myTileLayer@master/dist/bundle.js",
}
]
for key in pydeck_dict:
pydeck_dict[key] = pdk.Layer("MyTileLayer", pydeck_dict[key], key)
return pydeck_dict
[docs]def xyz_to_plotly():
"""Convert xyz tile services to plotly tile layers.
Returns:
dict: A dictionary of plotly tile layers.
"""
plotly_dict = {}
for key, tile in custom_tiles["xyz"].items():
plotly_dict[key] = {
"below": "traces",
"sourcetype": "raster",
"sourceattribution": tile["attribution"],
"source": [tile["url"]],
"name": key,
}
for item in get_xyz_dict().values():
plotly_dict[item.name] = {
"below": "traces",
"sourcetype": "raster",
"sourceattribution": item.attribution,
"source": [item.build_url()],
"name": item.name,
}
return plotly_dict
[docs]def search_qms(keywords, limit=10):
"""Search qms files for keywords. Reference: https://github.com/geopandas/xyzservices/issues/65
Args:
keywords (str): Keywords to search for.
limit (int): Number of results to return.
"""
QMS_API = "https://qms.nextgis.com/api/v1/geoservices"
services = requests.get(
f"{QMS_API}/?search={keywords}&type=tms&epsg=3857&limit={str(limit)}"
)
services = services.json()
if services["count"] == 0:
return None
elif services["count"] <= limit:
return services["results"]
else:
return services["results"][:limit]
[docs]def get_qms(service_id):
QMS_API = "https://qms.nextgis.com/api/v1/geoservices"
service_details = requests.get(f"{QMS_API}/{service_id}")
return service_details.json()
[docs]def qms_to_geemap(service_id):
"""Convert a qms service to an ipyleaflet tile layer.
Args:
service_id (str): Service ID.
Returns:
ipyleaflet.TileLayer: An ipyleaflet tile layer.
"""
service_details = get_qms(service_id)
name = service_details["name"]
url = service_details["url"]
attribution = service_details["copyright_text"]
layer = ipyleaflet.TileLayer(url=url, name=name, attribution=attribution)
return layer