Skip to content

Commit 387dea3

Browse files
authored
Merge pull request #697 from ocefpaf/refactor_imageoverlay
refactor ImageOverlay
2 parents 0534f46 + dfffea0 commit 387dea3

File tree

6 files changed

+377
-232
lines changed

6 files changed

+377
-232
lines changed

CHANGES.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ API changes
1818
If a popup requires rendering use the `kwarg` `parse_html=True`.
1919
- `Circle` and `CircleMarker` are set to leaflet's defaults and accepted all
2020
`Path` optional arguments (ocefpaf #683)
21-
- `WmsTileLayer` is set to leaflet's defaults and accepted all `TileLayer.WMS`
22-
optional arguments (ocefpaf #695)
21+
- `WmsTileLayer` and `ImageOverlay` are set to leaflet's defaults and accepted
22+
all `TileLayer.WMS` and `ImageOverlay` optional arguments respectively (ocefpaf #695 and #697)
2323
- Changed default `max_bounds` to `False` to reflect leaflet's default value (rdd9999 #641)
2424
- Modified `Fullscreen` plugin `kwargs` to be more "pythonic"
2525
- All `.format` properties are now `.fmt` for consistency

examples/GeodedeticImageOverlay.ipynb

Lines changed: 19 additions & 15 deletions
Large diffs are not rendered by default.

examples/GulfStreamImageOverlay.ipynb

Lines changed: 46 additions & 13 deletions
Large diffs are not rendered by default.

examples/ImageOverlay.ipynb

Lines changed: 61 additions & 118 deletions
Large diffs are not rendered by default.

folium/plugins/image_overlay.py

Lines changed: 31 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -5,73 +5,13 @@
55
import json
66

77
from branca.element import Element, Figure
8-
from branca.utilities import image_to_url
98

109
from folium.map import Layer
10+
from folium.utilities import image_to_url, mercator_transform
1111

1212
from jinja2 import Template
1313

1414

15-
def mercator_transform(data, lat_bounds, origin='upper', height_out=None):
16-
"""
17-
Transforms an image computed in (longitude,latitude) coordinates into
18-
the a Mercator projection image.
19-
20-
Parameters
21-
----------
22-
23-
data: numpy array or equivalent list-like object.
24-
Must be NxM (mono), NxMx3 (RGB) or NxMx4 (RGBA)
25-
26-
lat_bounds : length 2 tuple
27-
Minimal and maximal value of the latitude of the image.
28-
Bounds must be between -85.051128779806589 and 85.051128779806589
29-
otherwise they will be clipped to that values.
30-
31-
origin : ['upper' | 'lower'], optional, default 'upper'
32-
Place the [0,0] index of the array in the upper left or lower left
33-
corner of the axes.
34-
35-
height_out : int, default None
36-
The expected height of the output.
37-
If None, the height of the input is used.
38-
39-
See https://en.wikipedia.org/wiki/Web_Mercator for more details.
40-
41-
"""
42-
import numpy as np
43-
44-
def mercator(x):
45-
return np.arcsinh(np.tan(x*np.pi/180.))*180./np.pi
46-
47-
array = np.atleast_3d(data).copy()
48-
height, width, nblayers = array.shape
49-
50-
lat_min = max(lat_bounds[0], -85.051128779806589)
51-
lat_max = min(lat_bounds[1], 85.051128779806589)
52-
if height_out is None:
53-
height_out = height
54-
55-
# Eventually flip the image
56-
if origin == 'upper':
57-
array = array[::-1, :, :]
58-
59-
lats = (lat_min + np.linspace(0.5/height, 1.-0.5/height, height) *
60-
(lat_max-lat_min))
61-
latslats = (mercator(lat_min) +
62-
np.linspace(0.5/height_out, 1.-0.5/height_out, height_out) *
63-
(mercator(lat_max)-mercator(lat_min)))
64-
65-
out = np.zeros((height_out, width, nblayers))
66-
for i in range(width):
67-
for j in range(nblayers):
68-
out[:, i, j] = np.interp(latslats, mercator(lats), array[:, i, j])
69-
70-
# Eventually flip the image.
71-
if origin == 'upper':
72-
out = out[::-1, :, :]
73-
return out
74-
7515

7616
class ImageOverlay(Layer):
7717
"""
@@ -91,47 +31,56 @@ class ImageOverlay(Layer):
9131
Image bounds on the map in the form [[lat_min, lon_min],
9232
[lat_max, lon_max]]
9333
opacity: float, default Leaflet's default (1.0)
94-
attr: string, default Leaflet's default ("")
95-
origin : ['upper' | 'lower'], optional, default 'upper'
34+
alt: string, default Leaflet's default ('')
35+
origin: ['upper' | 'lower'], optional, default 'upper'
9636
Place the [0,0] index of the array in the upper left or
9737
lower left corner of the axes.
98-
colormap : callable, used only for `mono` image.
38+
colormap: callable, used only for `mono` image.
9939
Function of the form [x -> (r,g,b)] or [x -> (r,g,b,a)]
10040
for transforming a mono image into RGB.
10141
It must output iterables of length 3 or 4,
10242
with values between 0 and 1.
103-
Hint : you can use colormaps from `matplotlib.cm`.
104-
mercator_project : bool, default False.
43+
Hint: you can use colormaps from `matplotlib.cm`.
44+
mercator_project: bool, default False.
10545
Used only for array-like image. Transforms the data to
10646
project (longitude, latitude) coordinates to the
10747
Mercator projection.
10848
Beware that this will only work if `image` is an array-like
10949
object.
50+
pixelated: bool, default True
51+
Sharp sharp/crips (True) or aliased corners (False).
52+
53+
See http://leafletjs.com/reference-1.2.0.html#imageoverlay for more options.
11054
11155
"""
112-
def __init__(self, image, bounds, opacity=1., attr=None,
113-
origin='upper', colormap=None, mercator_project=False,
114-
overlay=True, control=True, pixelated=True):
115-
super(ImageOverlay, self).__init__(overlay=overlay, control=control)
56+
def __init__(self, image, bounds, origin='upper', colormap=None,
57+
mercator_project=False, overlay=True, control=True,
58+
pixelated=True, name=None, **kwargs):
59+
super(ImageOverlay, self).__init__(overlay=overlay, control=control, name=name) # noqa
60+
61+
options = {
62+
'opacity': kwargs.pop('opacity', 1.),
63+
'alt': kwargs.pop('alt', ''),
64+
'interactive': kwargs.pop('interactive', False),
65+
'crossOrigin': kwargs.pop('cross_origin', False),
66+
'errorOverlayUrl': kwargs.pop('error_overlay_url', ''),
67+
'zIndex': kwargs.pop('zindex', 1),
68+
'className': kwargs.pop('class_name', ''),
69+
}
11670
self._name = 'ImageOverlay'
117-
self.overlay = overlay
11871
self.pixelated = pixelated
11972

12073
if mercator_project:
121-
image = mercator_transform(image,
122-
[bounds[0][0], bounds[1][0]],
123-
origin=origin)
74+
image = mercator_transform(
75+
image,
76+
[bounds[0][0],
77+
bounds[1][0]],
78+
origin=origin)
12479

12580
self.url = image_to_url(image, origin=origin, colormap=colormap)
12681

12782
self.bounds = json.loads(json.dumps(bounds))
128-
options = {
129-
'opacity': opacity,
130-
'attribution': attr,
131-
}
132-
self.options = json.dumps({key: val for key, val
133-
in options.items() if val},
134-
sort_keys=True)
83+
self.options = json.dumps(options, sort_keys=True, indent=2)
13584
self._template = Template(u"""
13685
{% macro script(this, kwargs) %}
13786
var {{this.get_name()}} = L.imageOverlay(
@@ -160,7 +109,7 @@ def render(self, **kwargs):
160109
</style>"""
161110

162111
if self.pixelated:
163-
figure.header.add_child(Element(pixelated), name='leaflet-image-layer')
112+
figure.header.add_child(Element(pixelated), name='leaflet-image-layer') # noqa
164113

165114
def _get_self_bounds(self):
166115
"""

0 commit comments

Comments
 (0)