Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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.

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

The :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 = radius

@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/xarray-contrib/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