Skip to content

Commit

Permalink
Merge pull request #27 from heremaps/xyzservices
Browse files Browse the repository at this point in the history
Added support for external basemaps
  • Loading branch information
sackh authored Aug 10, 2021
2 parents b2b198a + 27289a9 commit 75eb1f2
Show file tree
Hide file tree
Showing 8 changed files with 179 additions and 16 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ name: Tests

on:
push:
branches:
- master
pull_request:
branches:
- master
Expand Down
3 changes: 2 additions & 1 deletion docs/source/api_reference/basemap/basemap.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ These are the various basemaps supported by ``here-map-widget-for-jupyter``
japan
raster
vector
map_tile
map_tile
external_basemap
33 changes: 33 additions & 0 deletions docs/source/api_reference/basemap/external_basemap.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
External Basemaps
=================
``here-map-widget-for-jupyter`` also supports basemaps from external tile providers.
We use tile providers defined in `xyzservices <https://github.com/geopandas/xyzservices>`_
:attr:`here_map_widget.basemaps` is mapped to :class:`xyzservices.providers`


Example
-------

.. jupyter-execute::

import os
from here_map_widget import Map, basemaps

m = Map(
api_key=os.environ["LS_API_KEY"],
center=[52.51477270923461, 13.39846691425174],
zoom=4,
basemap=basemaps.OpenStreetMap.Mapnik,
)
m



Attributes
----------

=================== ============================================================ ===
Attribute Type Doc
=================== ============================================================ ===
basemap object The basemap is object of :class:`xyzservices.lib.TileProvider`, defined under :attr:`here_map_widget.basemaps`.
=================== ============================================================ ===
1 change: 1 addition & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ For full list of functionalities please see below sections.
api_reference/basemap/raster
api_reference/basemap/vector
api_reference/basemap/map_tile
api_reference/basemap/external_basemap

.. toctree::
:caption: Layers
Expand Down
91 changes: 81 additions & 10 deletions examples/basemaps.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,19 @@
"os.environ[\"LS_API_KEY\"] = \"MY-API-KEY\" # replace your API key here."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Default Basemap Example"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Default Basemap Example\n",
"\n",
"from here_map_widget import Map\n",
"import os\n",
"\n",
Expand All @@ -47,14 +52,19 @@
"m.bounds = (42.3472, 42.3736, -71.0408, -71.0751) # South, West, North, East"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Default Basemap with dark style"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Default Basemap with dark style\n",
"\n",
"from here_map_widget import Map, Style\n",
"import os\n",
"\n",
Expand All @@ -72,14 +82,19 @@
"m"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Default layers raster basemap"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Default layers raster basemap\n",
"\n",
"from here_map_widget import Map, DefaultLayers, DefaultLayerNames, Platform\n",
"import os\n",
"\n",
Expand All @@ -101,14 +116,19 @@
"m.basemap = DefaultLayers(layer_name=DefaultLayerNames.raster.terrain.map)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## HERE OMV service data as basemap"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# HERE OMV service data as basemap\n",
"\n",
"from here_map_widget import Map, OMV, Platform, Style, TileLayer\n",
"from here_map_widget import ServiceNames, OMVUrl\n",
"import os\n",
Expand Down Expand Up @@ -141,6 +161,13 @@
"m"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## HERE Maptile service data as basemap"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand All @@ -149,8 +176,6 @@
},
"outputs": [],
"source": [
"# HERE Maptile service data as basemap\n",
"\n",
"from here_map_widget import Map, Platform, MapTile, TileLayer\n",
"from here_map_widget import ServiceNames, MapTileUrl\n",
"import os\n",
Expand Down Expand Up @@ -184,6 +209,52 @@
")\n",
"m"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## External basemaps\n",
"Basemaps from other tile providers are also supported.\n",
"[xyzservices](https://github.com/geopandas/xyzservices) supports all the external tile providers in single place and has easy to use \n",
"python API. External basemaps in here-map-widget-for-jupyter are mapped to `xyzservices.providers`"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from here_map_widget import basemaps"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"basemaps.OpenStreetMap.Mapnik"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"from here_map_widget import Map\n",
"\n",
"m = Map(\n",
" api_key=os.environ[\"LS_API_KEY\"],\n",
" center=[52.51477270923461, 13.39846691425174],\n",
" zoom=4,\n",
" basemap=basemaps.OpenStreetMap.Mapnik,\n",
")\n",
"m"
]
}
],
"metadata": {
Expand Down
2 changes: 2 additions & 0 deletions here_map_widget/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
to make analysis ofgeospatial data easier and more interactive.
"""

import xyzservices.providers as basemaps # noqa E501

from ._version import __version__, version_info
from .configs import *
from .map import *
Expand Down
60 changes: 56 additions & 4 deletions here_map_widget/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import copy
import json

import xyzservices
from branca.colormap import ColorMap, linear
from ipywidgets import (
Box,
Expand Down Expand Up @@ -42,6 +43,29 @@
def_loc = [20.5937, 78.9629]


def basemap_to_tiles(basemap, opacity=1, **kwargs):
"""Turn a basemap into a TileLayer object.
Parameters
----------
basemap : class:`xyzservices.lib.TileProvider`
Basemap description coming from here_map_widget.basemaps.
opacity: Int, Optional
Opacity of the TileLayer, default 1.
kwargs: key-word arguments
Extra key-word arguments to pass to the ``basemap.build_url`` method.
"""
url = basemap.build_url(**kwargs)
provider = ImageTileProvider(
url=url,
max_zoom=basemap.get("max_zoom", 19),
min_zoom=basemap.get("min_zoom", 1),
attribution=basemap.get("html_attribution", ""),
opacity=opacity,
)
return TileLayer(provider=provider, name=basemap.get("name", ""))


class InteractMixin(object):
"""Abstract InteractMixin class."""

Expand Down Expand Up @@ -1936,17 +1960,45 @@ class Map(DOMWidget, InteractMixin):
)
basemap = Union(
(
Instance(DefaultLayers, default_value=None, allow_none=True),
Instance(TileLayer, default_value=None, allow_none=True),
Instance(MapTile, default_value=None, allow_none=True),
)
Instance(DefaultLayers),
Instance(TileLayer),
Instance(MapTile),
Instance(xyzservices.lib.TileProvider),
),
default_value=DefaultLayers(layer_name=DefaultLayerNames.vector.normal.map),
).tag(sync=True, **widget_serialization)

zoom_control = Bool(True)

_view_module_version = Unicode(EXTENSION_VERSION).tag(sync=True)
_model_module_version = Unicode(EXTENSION_VERSION).tag(sync=True)

_layer_ids = List()

def __init__(self, api_key, **kwargs):
self.zoom_control_instance = None
self.api_key = api_key
super().__init__(**kwargs)
if self.zoom_control:
self.zoom_control_instance = ZoomControl(alignment="LEFT_TOP")
self.add_control(self.zoom_control_instance)
if isinstance(self.basemap, xyzservices.lib.TileProvider):
if "HEREv3" in self.basemap.name:
self.basemap["apiKey"] = self.api_key
self.basemap = basemap_to_tiles(self.basemap)

@observe("zoom_control")
def observe_zoom_control(self, change):
if change["new"]:
self.zoom_control_instance = ZoomControl(alignment="LEFT_TOP")
self.add_control(self.zoom_control_instance)
else:
if (
self.zoom_control_instance is not None
and self.zoom_control_instance in self.controls
):
self.remove_control(self.zoom_control_instance)

@validate("layers")
def _validate_layers(self, proposal):
"""Validate layers list.
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
ipywidgets>=7.6.0,<8
branca>=0.3.1,<0.5
branca>=0.3.1,<0.5
xyzservices>=2021.8.0

0 comments on commit 75eb1f2

Please sign in to comment.