Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/source/layers/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ Layers
choropleth
vector_tile.rst
wkt_layer

layer_like
68 changes: 68 additions & 0 deletions docs/source/layers/layer_like.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
Layer-Like Objects
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@davidbrochart and @martinRenou, please review this explanation and feel free to modify. This is what I came up with on a whim to document the interface.

==================

:class:`ipyleaflet.Map`'s :func:`ipyleaflet.Map.add` method supports
"layer-like" objects; meaning any object with an ``as_leaflet_layer`` method.
This interface can be especially useful for downstream developers who want
their users to more easily be able to add their objects to an
:class:`ipyleaflet.Map`.

Example
-------

Downstream objects should implement an ``as_leaflet_layer`` method that returns
an ``ipyleaflet`` type capable of being added to the ``Map``.

Here is a simple example of creating a custom data class to hold heatmap data
(coordinates with some numerical value).


.. jupyter-execute::

import numpy as np


class MyHeatMap:
def __init__(self, points, values, radius=20):
self.points = points
self.values = values
self.radius = 20

@property
def data(self):
return np.column_stack((self.points, self.values))

def as_leaflet_layer(self):
from ipyleaflet import Heatmap
return Heatmap(
locations=self.data.tolist(),
radius=self.radius,
)

We can now use that custom data class and because it has an
``as_leaflet_layer`` interface, we can pass the object directly to
:func:`ipyleaflet.Map.add`.


.. jupyter-execute::

from ipyleaflet import Map

n = 1000
data = MyHeatMap(
np.random.uniform(-80, 80, (n, 2)),
np.random.uniform(0, 1000, n),
)

m = Map(center=(0, 0), zoom=2)
m.add(data)
m


External Examples
-----------------

The following external libraries are working to implement this new interface

- `localtileserver <https://github.com/banesullivan/localtileserver>`_: a dynamic tile server built for visualizing large geospatial images/rasters with ipyleaflet.
- `xarray-leaflet <https://github.com/davidbrochart/xarray_leaflet>`_: an xarray extension for tiled map plotting, based on ipyleaflet.
6 changes: 5 additions & 1 deletion ipyleaflet/leaflet.py
Original file line number Diff line number Diff line change
Expand Up @@ -1165,11 +1165,15 @@ def add(self, layer):
Parameters
----------
layer: layer instance
The new layer to include in the group.
The new layer to include in the group. This can also be an object
with an ``as_leaflet_layer`` method which generates a compatible
layer type.
"""

if isinstance(layer, dict):
layer = basemap_to_tiles(layer)
elif hasattr(layer, 'as_leaflet_layer'):
layer = layer.as_leaflet_layer()
if layer.model_id in self._layer_ids:
raise LayerException('layer already in layergroup: %r' % layer)
self.layers = tuple([layer for layer in self.layers] + [layer])
Expand Down