Skip to content

Commit 34ed7e5

Browse files
authored
Merge pull request #704 from ocefpaf/refactor_marker_cluster
Refactor marker cluster
2 parents 5e96485 + 39a6a1e commit 34ed7e5

File tree

10 files changed

+354
-357
lines changed

10 files changed

+354
-357
lines changed

examples/1000_MarkerCluster.ipynb

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

examples/FastMarkerCluster.ipynb

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

examples/Features.ipynb

Lines changed: 32 additions & 85 deletions
Large diffs are not rendered by default.

folium/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
from folium._version import get_versions
1010

1111
from folium.features import (
12-
Circle, CircleMarker, ClickForMarker, CustomIcon, DivIcon, GeoJson, LatLngPopup,
13-
MarkerCluster, PolyLine, RegularPolygonMarker, TopoJson, Vega, VegaLite,
12+
Circle, CircleMarker, ClickForMarker, CustomIcon, DivIcon, GeoJson,
13+
LatLngPopup, PolyLine, RegularPolygonMarker, TopoJson, Vega, VegaLite,
1414
WmsTileLayer,
1515
)
1616

folium/features.py

Lines changed: 1 addition & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from branca.element import (CssLink, Element, Figure, JavascriptLink, MacroElement) # noqa
1717
from branca.utilities import (_locations_tolist, _parse_size, image_to_url, iter_points, none_max, none_min) # noqa
1818

19-
from folium.map import FeatureGroup, Icon, Layer, Marker
19+
from folium.map import FeatureGroup, Icon, Layer, Popup, Marker
2020
from folium.utilities import _parse_path, _parse_wms
2121

2222
from jinja2 import Template
@@ -744,74 +744,6 @@ def _get_self_bounds(self):
744744
]
745745

746746

747-
class MarkerCluster(Layer):
748-
"""
749-
Creates a MarkerCluster element to append into a map with
750-
Map.add_child.
751-
752-
Parameters
753-
----------
754-
name : string, default None
755-
The name of the Layer, as it will appear in LayerControls
756-
overlay : bool, default False
757-
Adds the layer as an optional overlay (True) or the base layer (False).
758-
control : bool, default True
759-
Whether the Layer will be included in LayerControls
760-
icon_create_function : string, default None
761-
Override the default behaviour, making possible to customize markers colors and sizes
762-
763-
Example
764-
-------
765-
>>> icon_create_function = '''
766-
... function (cluster) {
767-
... var childCount = cluster.getChildCount();
768-
... var c = ' marker-cluster-small';
769-
... return new L.DivIcon({ html: '<div><span>' + childCount + '</span></div>',
770-
className: 'marker-cluster' + c,
771-
iconSize: new L.Point(40, 40) });
772-
... }
773-
... '''
774-
"""
775-
def __init__(self, name=None, overlay=True, control=True, icon_create_function=None):
776-
super(MarkerCluster, self).__init__(name=name, overlay=overlay,
777-
control=control)
778-
self._name = 'MarkerCluster'
779-
self._icon_create_function = icon_create_function.strip()
780-
self._template = Template(u"""
781-
{% macro script(this, kwargs) %}
782-
var {{this.get_name()}} = L.markerClusterGroup({
783-
{% if this._icon_create_function %}
784-
iconCreateFunction: {{this._icon_create_function}}
785-
{% endif %}
786-
});
787-
{{this._parent.get_name()}}.addLayer({{this.get_name()}});
788-
{% endmacro %}
789-
""")
790-
791-
def render(self, **kwargs):
792-
"""Renders the HTML representation of the element."""
793-
super(MarkerCluster, self).render()
794-
795-
figure = self.get_root()
796-
assert isinstance(figure, Figure), ('You cannot render this Element '
797-
'if it is not in a Figure.')
798-
figure.header.add_child(
799-
JavascriptLink('https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.0.0/leaflet.markercluster-src.js'), # noqa
800-
name='marker_cluster_src')
801-
802-
figure.header.add_child(
803-
JavascriptLink('https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.0.0/leaflet.markercluster.js'), # noqa
804-
name='marker_cluster')
805-
806-
figure.header.add_child(
807-
CssLink('https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.0.0/MarkerCluster.css'), # noqa
808-
name='marker_cluster_css')
809-
810-
figure.header.add_child(
811-
CssLink('https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.0.0/MarkerCluster.Default.css'), # noqa
812-
name='marker_cluster_default_css')
813-
814-
815747
class DivIcon(MacroElement):
816748
"""
817749
Represents a lightweight icon for markers that uses a simple `div`

folium/map.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@
3737
'https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js'),
3838
('awesome_markers',
3939
'https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.js'), # noqa
40-
('marker_cluster',
41-
'https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.0.0/leaflet.markercluster.js'), # noqa
4240
]
4341

4442
_default_css = [
@@ -52,10 +50,6 @@
5250
'https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css'), # noqa
5351
('awesome_markers_css',
5452
'https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css'), # noqa
55-
('marker_cluster_default_css',
56-
'https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.0.0/MarkerCluster.Default.css'), # noqa
57-
('marker_cluster_css',
58-
'https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.0.0/MarkerCluster.css'), # noqa
5953
('awesome_rotate_css',
6054
'https://rawgit.com/python-visualization/folium/master/folium/templates/leaflet.awesome.rotate.css'), # noqa
6155
]

folium/plugins/marker_cluster.py

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,54 +2,70 @@
22

33
from __future__ import (absolute_import, division, print_function)
44

5-
from branca.element import CssLink, Figure, JavascriptLink, MacroElement
5+
from branca.element import CssLink, Figure, JavascriptLink
66

7-
from folium.map import Icon, Marker, Popup
7+
from folium.map import Icon, Layer, Marker, Popup
88

99
from jinja2 import Template
1010

1111

12-
class MarkerCluster(MacroElement):
12+
class MarkerCluster(Layer):
1313
"""
14-
Creates a MarkerCluster plugin to append into a map with
15-
Map.add_child.
14+
Provides Beautiful Animated Marker Clustering functionality for maps.
1615
1716
Parameters
1817
----------
19-
locations: list of list or array of shape (n,2).
18+
name : string, default None
19+
The name of the Layer, as it will appear in LayerControls
20+
overlay : bool, default False
21+
Adds the layer as an optional overlay (True) or the base layer (False).
22+
control : bool, default True
23+
Whether the Layer will be included in LayerControls
24+
icon_create_function : string, default None
25+
Override the default behaviour, making possible to customize
26+
markers colors and sizes.
27+
28+
locations: list of list or array of shape (n, 2).
2029
Data points of the form [[lat, lng]].
21-
2230
popups: list of length n.
2331
Popup for each marker.
24-
2532
icons: list of length n.
2633
Icon for each marker.
2734
28-
"""
29-
def __init__(self, locations, popups=None, icons=None):
30-
super(MarkerCluster, self).__init__()
31-
self._name = 'MarkerCluster'
35+
Example
36+
-------
37+
>>> icon_create_function = '''
38+
... function(cluster) {
39+
... return L.divIcon({html: '<b>' + cluster.getChildCount() + '</b>',
40+
... className: 'marker-cluster marker-cluster-small',
41+
... iconSize: new L.Point(20, 20)});
42+
}'''
3243
33-
if popups is None:
34-
popups = [None]*len(locations)
35-
if icons is None:
36-
icons = [None]*len(locations)
37-
38-
for location, popup, icon in zip(locations, popups, icons):
39-
if popup is None or isinstance(popup, Popup):
40-
p = popup
41-
else:
42-
p = Popup(popup)
43-
if icon is None or isinstance(icon, Icon):
44-
i = icon
45-
else:
46-
i = Icon(icon)
47-
self.add_child(Marker(location, popup=p, icon=i))
44+
"""
45+
def __init__(self, locations=None, popups=None, icons=None, name=None,
46+
overlay=True, control=True, icon_create_function=None):
47+
super(MarkerCluster, self).__init__(name=name, overlay=overlay, control=control) # noqa
48+
49+
if locations is not None:
50+
if popups is None:
51+
popups = [None]*len(locations)
52+
if icons is None:
53+
icons = [None]*len(locations)
54+
for location, popup, icon in zip(locations, popups, icons):
55+
p = popup if popup is None or isinstance(popup, Popup) else Popup(popup) # noqa
56+
i = icon if icon is None or isinstance(icon, Icon) else Icon(icon) # noqa
57+
self.add_child(Marker(location, popup=p, icon=i))
4858

59+
self._name = 'MarkerCluster'
60+
self._icon_create_function = icon_create_function.strip() if icon_create_function else '' # noqa
4961
self._template = Template(u"""
5062
{% macro script(this, kwargs) %}
51-
var {{this.get_name()}} = L.markerClusterGroup();
52-
{{this._parent.get_name()}}.addLayer({{this.get_name()}});
63+
var {{this.get_name()}} = L.markerClusterGroup({
64+
{% if this._icon_create_function %}
65+
iconCreateFunction: {{this._icon_create_function}}
66+
{% endif %}
67+
});
68+
{{this._parent.get_name()}}.addLayer({{this.get_name()}});
5369
{% endmacro %}
5470
""")
5571

@@ -61,13 +77,13 @@ def render(self, **kwargs):
6177
'if it is not in a Figure.')
6278

6379
figure.header.add_child(
64-
JavascriptLink('https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.0.0/leaflet.markercluster.js'), # noqa
80+
JavascriptLink('https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.1.0/leaflet.markercluster.js'), # noqa
6581
name='markerclusterjs')
6682

6783
figure.header.add_child(
68-
CssLink('https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.0.0/MarkerCluster.css'), # noqa
84+
CssLink('https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.1.0/MarkerCluster.css'), # noqa
6985
name='markerclustercss')
7086

7187
figure.header.add_child(
72-
CssLink('https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.0.0/MarkerCluster.Default.css'), # noqa
88+
CssLink('https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.1.0/MarkerCluster.Default.css'), # noqa
7389
name='markerclusterdefaultcss')

folium/templates/fol_template.html

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,12 @@
66
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
77
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
88
<script src="https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.js"></script>
9-
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.0.0/leaflet.markercluster.js"></script>
109

1110
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/leaflet.css" />
1211
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"/>
1312
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"/>
1413
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css"/>
1514
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css"/>
16-
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.0.0/MarkerCluster.Default.css"/>
17-
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.0.0/MarkerCluster.css"/>
1815
<link rel="stylesheet" href="https://rawgit.com/python-visualization/folium/master/folium/templates/leaflet.awesome.rotate.css"/>
1916

2017
<style>

tests/plugins/test_fast_marker_cluster.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,9 @@ def test_fast_marker_cluster():
3232
out = m._parent.render()
3333

3434
# We verify that imports
35-
assert ('<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.'
36-
'markercluster/1.0.0/leaflet.markercluster.js"></script>') in out
37-
assert ('<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/'
38-
'libs/leaflet.markercluster/1.0.0/MarkerCluster.css" />') in out
39-
assert ('<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/'
40-
'libs/leaflet.markercluster/1.0.0/MarkerCluster.Default.css" />'
41-
) in out
35+
assert '<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.1.0/leaflet.markercluster.js"></script>' in out # noqa
36+
assert '<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.1.0/MarkerCluster.css" />' in out # noqa
37+
assert '<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.1.0/MarkerCluster.Default.css" />' in out # noqa
4238

4339
# Verify the script part is okay.
4440
tmpl = Template("""

tests/plugins/test_marker_cluster.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,17 @@ def test_marker_cluster():
3232
out = m._parent.render()
3333

3434
# We verify that imports
35-
assert ('<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.'
36-
'markercluster/1.0.0/leaflet.markercluster.js"></script>') in out
37-
assert ('<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/'
38-
'libs/leaflet.markercluster/1.0.0/MarkerCluster.css" />') in out
39-
assert ('<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/'
40-
'libs/leaflet.markercluster/1.0.0/MarkerCluster.Default.css" />'
41-
) in out
35+
assert '<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.1.0/leaflet.markercluster.js"></script>' in out # noqa
36+
assert '<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.1.0/MarkerCluster.css" />' in out # noqa
37+
assert '<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/1.1.0/MarkerCluster.Default.css" />' in out # noqa
4238

4339
# Verify the script part is okay.
4440
tmpl = Template("""
45-
var {{this.get_name()}} = L.markerClusterGroup();
41+
var {{this.get_name()}} = L.markerClusterGroup({
42+
{% if this._icon_create_function %}
43+
iconCreateFunction: {{this._icon_create_function}}
44+
{% endif %}
45+
});
4646
{{this._parent.get_name()}}.addLayer({{this.get_name()}});
4747
4848
{% for marker in this._children.values() %}

0 commit comments

Comments
 (0)