Skip to content

Commit 0e527a3

Browse files
authored
Merge pull request #2 from python-visualization/master
Update master branch
2 parents bd4ac9f + 99449e2 commit 0e527a3

File tree

11 files changed

+589
-227
lines changed

11 files changed

+589
-227
lines changed

.travis.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ before_install:
3838
conda config --set always_yes yes --set changeps1 no --set show_channel_urls true
3939
conda update conda --quiet
4040
conda config --add channels conda-forge --force
41-
conda install pycryptosat
4241
conda config --set channel_priority strict
4342
conda config --set safety_checks disabled
4443
conda create --name TEST python=$PY --file requirements.txt --file requirements-dev.txt
@@ -77,7 +76,7 @@ script:
7776
fi
7877

7978
- if [[ $TRAVIS_JOB_NAME == 'notebooks-code' ]]; then
80-
pytest --nbval-lax -p no:python /tmp/examples ;
79+
pytest --nbval-lax /tmp/examples ;
8180
fi
8281

8382
# Docs

examples/plugin-PolyLineOffset.ipynb

Lines changed: 319 additions & 0 deletions
Large diffs are not rendered by default.

folium/folium.py

Lines changed: 60 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@
1212

1313
from folium.map import FitBounds
1414
from folium.raster_layers import TileLayer
15-
from folium.utilities import _parse_size, _tmp_html, validate_location
15+
from folium.utilities import (
16+
_parse_size,
17+
_tmp_html,
18+
validate_location,
19+
parse_options,
20+
)
1621

1722
from jinja2 import Environment, PackageLoader, Template
1823

@@ -93,23 +98,15 @@ class Map(MacroElement):
9398
tiles: str, default 'OpenStreetMap'
9499
Map tileset to use. Can choose from a list of built-in tiles,
95100
pass a custom URL or pass `None` to create a map without tiles.
96-
API_key: str, default None
97-
API key for Cloudmade or Mapbox tiles.
101+
For more advanced tile layer options, use the `TileLayer` class.
98102
min_zoom: int, default 0
99103
Minimum allowed zoom level for the tile layer that is created.
100104
max_zoom: int, default 18
101105
Maximum allowed zoom level for the tile layer that is created.
102-
max_native_zoom: int, default None
103-
The highest zoom level at which the tile server can provide tiles.
104-
If provided you can zoom in past this level. Else tiles will turn grey.
105106
zoom_start: int, default 10
106107
Initial zoom level for the map.
107108
attr: string, default None
108109
Map tile attribution; only required if passing custom tile URL.
109-
detect_retina: bool, default False
110-
If true and user is on a retina display, it will request four
111-
tiles of half the specified size and a bigger zoom level in place
112-
of one to utilize the high resolution.
113110
crs : str, default 'EPSG3857'
114111
Defines coordinate reference systems for projecting geographical points
115112
into pixel (screen) coordinates and back.
@@ -140,20 +137,23 @@ class Map(MacroElement):
140137
rare environments) even if they're supported.
141138
zoom_control : bool, default True
142139
Display zoom controls on the map.
140+
**kwargs
141+
Additional keyword arguments are passed to Leaflets Map class:
142+
https://leafletjs.com/reference-1.4.0.html#map
143143
144144
Returns
145145
-------
146146
Folium Map Object
147147
148148
Examples
149149
--------
150-
>>> map = folium.Map(location=[45.523, -122.675],
150+
>>> m = folium.Map(location=[45.523, -122.675],
151151
... width=750, height=500)
152-
>>> map = folium.Map(location=[45.523, -122.675],
152+
>>> m = folium.Map(location=[45.523, -122.675],
153153
tiles='Mapbox Control Room')
154-
>>> map = folium.Map(location=(45.523, -122.675), max_zoom=20,
154+
>>> m = folium.Map(location=(45.523, -122.675), max_zoom=20,
155155
tiles='Cloudmade', API_key='YourKey')
156-
>>> map = folium.Map(
156+
>>> m = folium.Map(
157157
... location=[45.523, -122.675],
158158
... zoom_start=2,
159159
... tiles='http://{s}.tiles.mapbox.com/v3/mapbox.control-room/{z}/{x}/{y}.png',
@@ -181,25 +181,14 @@ class Map(MacroElement):
181181
{% endmacro %}
182182
183183
{% macro script(this, kwargs) %}
184-
{%- if this.max_bounds %}
185-
var bounds = L.latLngBounds(
186-
[{{ this.min_lat }}, {{ this.min_lon }}],
187-
[{{ this.max_lat }}, {{ this.max_lon }}]
188-
);
189-
{%- else %}
190-
var bounds = null;
191-
{%- endif %}
192-
193184
var {{ this.get_name() }} = L.map(
194185
{{ this.get_name()|tojson }},
195186
{
196187
center: {{ this.location|tojson }},
197-
zoom: {{ this.zoom_start|tojson }},
198-
maxBounds: bounds,
199-
layers: [],
200-
worldCopyJump: {{ this.world_copy_jump|tojson }},
201188
crs: L.CRS.{{ this.crs }},
202-
zoomControl: {{ this.zoom_control|tojson }},
189+
{%- for key, value in this.options.items() %}
190+
{{ key }}: {{ value|tojson }},
191+
{%- endfor %}
203192
}
204193
);
205194
@@ -220,15 +209,33 @@ class Map(MacroElement):
220209
{% endmacro %}
221210
""")
222211

223-
def __init__(self, location=None, width='100%', height='100%',
224-
left='0%', top='0%', position='relative',
225-
tiles='OpenStreetMap', API_key=None, max_zoom=18, min_zoom=0,
226-
max_native_zoom=None, zoom_start=10, world_copy_jump=False,
227-
no_wrap=False, attr=None, min_lat=-90, max_lat=90,
228-
min_lon=-180, max_lon=180, max_bounds=False,
229-
detect_retina=False, crs='EPSG3857', control_scale=False,
230-
prefer_canvas=False, no_touch=False, disable_3d=False,
231-
subdomains='abc', png_enabled=False, zoom_control=True):
212+
def __init__(
213+
self,
214+
location=None,
215+
width='100%',
216+
height='100%',
217+
left='0%',
218+
top='0%',
219+
position='relative',
220+
tiles='OpenStreetMap',
221+
attr=None,
222+
min_zoom=0,
223+
max_zoom=18,
224+
zoom_start=10,
225+
min_lat=-90,
226+
max_lat=90,
227+
min_lon=-180,
228+
max_lon=180,
229+
max_bounds=False,
230+
crs='EPSG3857',
231+
control_scale=False,
232+
prefer_canvas=False,
233+
no_touch=False,
234+
disable_3d=False,
235+
png_enabled=False,
236+
zoom_control=True,
237+
**kwargs
238+
):
232239
super(Map, self).__init__()
233240
self._name = 'Map'
234241
self._env = ENV
@@ -239,10 +246,9 @@ def __init__(self, location=None, width='100%', height='100%',
239246
if location is None:
240247
# If location is not passed we center and zoom out.
241248
self.location = [0, 0]
242-
self.zoom_start = 1
249+
zoom_start = 1
243250
else:
244251
self.location = validate_location(location)
245-
self.zoom_start = zoom_start
246252

247253
Figure().add_child(self)
248254

@@ -253,17 +259,18 @@ def __init__(self, location=None, width='100%', height='100%',
253259
self.top = _parse_size(top)
254260
self.position = position
255261

256-
self.min_lat = min_lat
257-
self.max_lat = max_lat
258-
self.min_lon = min_lon
259-
self.max_lon = max_lon
260-
self.max_bounds = max_bounds
261-
self.no_wrap = no_wrap
262-
self.world_copy_jump = world_copy_jump
262+
max_bounds_array = [[min_lat, min_lon], [max_lat, max_lon]] \
263+
if max_bounds else None
263264

264265
self.crs = crs
265266
self.control_scale = control_scale
266-
self.zoom_control = zoom_control
267+
268+
self.options = parse_options(
269+
max_bounds=max_bounds_array,
270+
zoom=zoom_start,
271+
zoom_control=zoom_control,
272+
**kwargs
273+
)
267274

268275
self.global_switches = GlobalSwitches(
269276
prefer_canvas,
@@ -274,12 +281,9 @@ def __init__(self, location=None, width='100%', height='100%',
274281
self.objects_to_stay_in_front = []
275282

276283
if tiles:
277-
self.add_tile_layer(
278-
tiles=tiles, min_zoom=min_zoom, max_zoom=max_zoom,
279-
max_native_zoom=max_native_zoom, no_wrap=no_wrap, attr=attr,
280-
API_key=API_key, detect_retina=detect_retina,
281-
subdomains=subdomains
282-
)
284+
tile_layer = TileLayer(tiles=tiles, attr=attr,
285+
min_zoom=min_zoom, max_zoom=max_zoom)
286+
self.add_child(tile_layer, name=tile_layer.tile_name)
283287

284288
def _repr_html_(self, **kwargs):
285289
"""Displays the HTML Map in a Jupyter notebook."""
@@ -299,8 +303,8 @@ def _to_png(self, delay=3):
299303
300304
Examples
301305
--------
302-
>>> map._to_png()
303-
>>> map._to_png(time=10) # Wait 10 seconds between render and snapshot.
306+
>>> m._to_png()
307+
>>> m._to_png(time=10) # Wait 10 seconds between render and snapshot.
304308
305309
"""
306310
if self._png_image is None:
@@ -329,24 +333,6 @@ def _repr_png_(self):
329333
return None
330334
return self._to_png()
331335

332-
def add_tile_layer(self, tiles='OpenStreetMap', name=None,
333-
API_key=None, max_zoom=18, min_zoom=0,
334-
max_native_zoom=None, attr=None, active=False,
335-
detect_retina=False, no_wrap=False, subdomains='abc',
336-
**kwargs):
337-
"""
338-
Add a tile layer to the map. See TileLayer for options.
339-
340-
"""
341-
tile_layer = TileLayer(tiles=tiles, name=name,
342-
min_zoom=min_zoom, max_zoom=max_zoom,
343-
max_native_zoom=max_native_zoom,
344-
attr=attr, API_key=API_key,
345-
detect_retina=detect_retina,
346-
subdomains=subdomains,
347-
no_wrap=no_wrap)
348-
self.add_child(tile_layer, name=tile_layer.tile_name)
349-
350336
def render(self, **kwargs):
351337
"""Renders the HTML representation of the element."""
352338
figure = self.get_root()
@@ -408,7 +394,7 @@ def fit_bounds(self, bounds, padding_top_left=None,
408394
409395
Examples
410396
--------
411-
>>> map.fit_bounds([[52.193636, -2.221575], [52.636878, -1.139759]])
397+
>>> m.fit_bounds([[52.193636, -2.221575], [52.636878, -1.139759]])
412398
413399
"""
414400
self.add_child(FitBounds(bounds,

folium/plugins/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"""
1010

1111
from folium.plugins.antpath import AntPath
12+
from folium.plugins.polyline_offset import PolyLineOffset
1213
from folium.plugins.beautify_icon import BeautifyIcon
1314
from folium.plugins.boat_marker import BoatMarker
1415
from folium.plugins.draw import Draw
@@ -50,6 +51,7 @@
5051
'MiniMap',
5152
'MousePosition',
5253
'PolyLineTextPath',
54+
'PolyLineOffset',
5355
'ScrollZoomToggler',
5456
'Search',
5557
'StripePattern',

folium/plugins/draw.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class Draw(MacroElement):
7676
'href', 'data:' + convertedData
7777
);
7878
document.getElementById('export').setAttribute(
79-
'download', {{ this.filename|tojson }}"
79+
'download', {{ this.filename|tojson }}
8080
);
8181
}
8282
{% endmacro %}

folium/plugins/polyline_offset.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# -*- coding: utf-8 -*-
2+
3+
from __future__ import absolute_import, division, print_function
4+
5+
from branca.element import JavascriptLink
6+
7+
from folium.vector_layers import PolyLine
8+
9+
10+
class PolyLineOffset(PolyLine):
11+
"""
12+
Add offset capabilities to the PolyLine class.
13+
14+
This plugin adds to folium Polylines the ability to be drawn with a
15+
relative pixel offset, without modifying their actual coordinates. The offset
16+
value can be either negative or positive, for left- or right-side offset,
17+
and remains constant across zoom levels.
18+
19+
See :func:`folium.vector_layers.path_options` for the `Path` options.
20+
21+
Parameters
22+
----------
23+
locations: list of points (latitude, longitude)
24+
Latitude and Longitude of line (Northing, Easting)
25+
popup: str or folium.Popup, default None
26+
Input text or visualization for object displayed when clicking.
27+
tooltip: str or folium.Tooltip, optional
28+
Display a text when hovering over the object.
29+
offset: int, default 0
30+
Relative pixel offset to draw a line parallel to an existant one,
31+
at a fixed distance.
32+
**kwargs:
33+
Polyline options. See their Github page for the
34+
available parameters.
35+
36+
See https://github.com/bbecquet/Leaflet.PolylineOffset
37+
38+
Examples
39+
--------
40+
>>> plugins.PolyLineOffset([[58, -28], [53, -23]], color="#f00", opacity=1, offset=-5).add_to(m)
41+
>>> plugins.PolyLineOffset([[58, -28], [53, -23]], color="#080", opacity=1, offset=10).add_to(m)
42+
43+
"""
44+
45+
def __init__(self, locations, popup=None, tooltip=None, offset=0, **kwargs):
46+
super(PolyLineOffset, self).__init__(
47+
locations=locations, popup=popup, tooltip=tooltip, **kwargs
48+
)
49+
self._name = "PolyLineOffset"
50+
# Add PolyLineOffset offset.
51+
self.options.update({"offset": offset})
52+
53+
def render(self, **kwargs):
54+
super(PolyLineOffset, self).render()
55+
figure = self.get_root()
56+
figure.header.add_child(
57+
JavascriptLink("https://cdn.jsdelivr.net/npm/[email protected]/leaflet.polylineoffset.min.js"), # noqa
58+
name="polylineoffset",
59+
)

0 commit comments

Comments
 (0)