Skip to content

Commit 99449e2

Browse files
authored
Merge pull request #1127 from Conengmo/simplify-map
Clean-up Map
2 parents 9729c96 + 29a3f7d commit 99449e2

File tree

4 files changed

+77
-223
lines changed

4 files changed

+77
-223
lines changed

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/templates/fol_template.html

Lines changed: 0 additions & 72 deletions
This file was deleted.

tests/test_folium.py

Lines changed: 2 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,8 @@ def test_init(self):
9696
assert self.m.get_name() == 'map_00000000000000000000000000000000'
9797
assert self.m.get_root() == self.m._parent
9898
assert self.m.location == [45.5236, -122.6750]
99-
assert self.m.zoom_start == 4
100-
assert self.m.max_lat == 90
101-
assert self.m.min_lat == -90
102-
assert self.m.max_lon == 180
103-
assert self.m.min_lon == -180
99+
assert self.m.options['zoom'] == 4
100+
assert self.m.options['maxBounds'] == [[-90, -180], [90, 180]]
104101
assert self.m.position == 'relative'
105102
assert self.m.height == (400, 'px')
106103
assert self.m.width == (900, 'px')
@@ -121,19 +118,6 @@ def test_init(self):
121118
}
122119
}
123120

124-
def test_cloudmade(self):
125-
"""Test cloudmade tiles and the API key."""
126-
with pytest.raises(ValueError):
127-
folium.Map(location=[45.5236, -122.6750], tiles='cloudmade')
128-
129-
m = folium.Map(location=[45.5236, -122.6750], tiles='cloudmade',
130-
API_key='###')
131-
cloudmade = 'http://{s}.tile.cloudmade.com/###/997/256/{z}/{x}/{y}.png'
132-
assert m._children['cloudmade'].tiles == cloudmade
133-
134-
bounds = m.get_bounds()
135-
assert bounds == [[None, None], [None, None]], bounds
136-
137121
def test_builtin_tile(self):
138122
"""Test custom maptiles."""
139123

@@ -201,47 +185,6 @@ def test_topo_json_smooth_factor(self):
201185
topojson_str = topo_json._template.module.script(topo_json)
202186
assert ''.join(topojson_str.split())[:-1] in ''.join(out.split())
203187

204-
def test_map_build(self):
205-
"""Test map build."""
206-
207-
# Standard map.
208-
self.setup()
209-
rendered = self.m._parent.render()
210-
211-
html_templ = self.env.get_template('fol_template.html')
212-
attr = 'http://openstreetmap.org'
213-
tile_layers = [
214-
{'id': 'tile_layer_'+'0'*32,
215-
'address': 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
216-
'attr': attr,
217-
'max_native_zoom': 20,
218-
'max_zoom': 20,
219-
'min_zoom': 0,
220-
'detect_retina': False,
221-
'no_wrap': False,
222-
'tms': False,
223-
'opacity': 1,
224-
'subdomains': 'abc'
225-
}]
226-
tmpl = {'map_id': 'map_' + '0' * 32,
227-
'lat': 45.5236, 'lon': -122.675,
228-
'width': 'width: 900.0px;',
229-
'height': 'height: 400.0px;',
230-
'zoom_level': 4,
231-
'max_bounds': True,
232-
'min_lat': -90,
233-
'max_lat': 90,
234-
'min_lon': -180,
235-
'max_lon': 180,
236-
'tile_layers': tile_layers,
237-
'crs': 'EPSG3857',
238-
'world_copy_jump': False,
239-
'zoom_control': True
240-
}
241-
expected = html_templ.render(tmpl, plugins={})
242-
243-
assert normalize(rendered) == normalize(expected)
244-
245188
def test_choropleth_features(self):
246189
"""Test to make sure that Choropleth function doesn't allow
247190
values outside of the domain defined by bins.

0 commit comments

Comments
 (0)