Skip to content

Commit df71c48

Browse files
committed
Merge pull request #151 from BibMartin/plugins
Plugins object and a few plugins
2 parents 1c4d25a + 521c0c5 commit df71c48

14 files changed

+6605
-131
lines changed

examples/plugins_examples.ipynb

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

folium/folium.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,7 @@ def add_plugin(self, plugin):
661661
A plugin to be added to the map. It has to implement the methods
662662
`render_html`, `render_css` and `render_js`.
663663
"""
664-
self.plugins[plugin.name] = plugin
664+
plugin.add_to_map(self)
665665

666666
def _auto_bounds(self):
667667
if 'fit_bounds' in self.template_vars:

folium/plugins/__init__.py

Lines changed: 12 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,124 +1,13 @@
11
# -*- coding: utf-8 -*-
2-
3-
from uuid import uuid4
4-
import json
5-
6-
class Plugin():
7-
"""Basic plugin object that does nothing.
8-
Other plugins may inherit from this one."""
9-
def __init__(self):
10-
"""Creates a plugin to append into a map with Map.add_plugin. """
11-
self.name = "Plugin_"+uuid4().hex
12-
13-
def render_html(self):
14-
"""Generates the HTML part of the plugin."""
15-
return ""
16-
17-
def render_css(self):
18-
"""Generates the CSS part of the plugin."""
19-
return ""
20-
21-
def render_js(self):
22-
"""Generates the Javascript part of the plugin."""
23-
return ""
24-
def render_header(self):
25-
"""Generates the Header part of the plugin."""
26-
return ""
27-
28-
29-
class ScrollZoomToggler(Plugin):
30-
"""Adds a button to enable/disable zoom scrolling."""
31-
def __init__(self, zoom_enabled=False):
32-
"""Creates a ScrollZoomToggler plugin to append into a map with
33-
Map.add_plugin.
34-
35-
Parameters
36-
----------
37-
zoom_enabled: bool, default False
38-
Whether the zoom scrolling shall be enabled at display.
39-
"""
40-
self.zoom_enabled = zoom_enabled
41-
self.name = "ScrollZoomToggler_"+uuid4().hex
42-
43-
def render_html(self):
44-
"""Generates the HTML part of the plugin."""
45-
return """<img id="{}" alt="scroll"
46-
src="https://cdnjs.cloudflare.com/ajax/libs/ionicons/1.5.2/png/512/arrow-move.png"
47-
onclick="toggleScroll()"></img>""".format(self.name)
48-
49-
def render_css(self):
50-
"""Generates the CSS part of the plugin."""
51-
return """
52-
#"""+self.name+""" {
53-
position:absolute;
54-
width:35px;
55-
bottom:10px;
56-
height:35px;
57-
left:10px;
58-
background-color:#fff;
59-
text-align:center;
60-
line-height:35px;
61-
vertical-align: middle;
62-
}
63-
"""
64-
65-
def render_js(self):
66-
"""Generates the Javascript part of the plugin."""
67-
out = """
68-
map.scrollEnabled = true;
69-
70-
var toggleScroll = function() {
71-
if (map.scrollEnabled) {
72-
map.scrollEnabled = false;
73-
map.scrollWheelZoom.disable();
74-
}
75-
else {
76-
map.scrollEnabled = true;
77-
map.scrollWheelZoom.enable();
78-
}
79-
};
80-
"""
81-
if not self.zoom_enabled:
82-
out += "\n toggleScroll();"
83-
return out
84-
85-
class MarkerCluster(Plugin):
86-
"""Adds a MarkerCluster layer on the map."""
87-
def __init__(self, data):
88-
"""Creates a MarkerCluster plugin to append into a map with
89-
Map.add_plugin.
90-
91-
Parameters
92-
----------
93-
data: list of list or array of shape (n,3).
94-
Data points of the form [[lat, lng, popup]].
95-
"""
96-
self.data = [tuple(x) for x in data]
97-
self.name = "MarkerCluster_"+uuid4().hex
98-
99-
def render_header(self):
100-
"""Generates the HTML part of the plugin."""
101-
return """
102-
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/0.4.0/MarkerCluster.css" />
103-
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/0.4.0/MarkerCluster.Default.css" />
104-
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/0.4.0/leaflet.markercluster.js"></script>
105-
"""
106-
107-
def render_js(self):
108-
"""Generates the Javascript part of the plugin."""
109-
out = """
110-
var addressPoints = """+json.dumps(self.data)+""";
111-
112-
var markers = L.markerClusterGroup();
113-
114-
for (var i = 0; i < addressPoints.length; i++) {
115-
var a = addressPoints[i];
116-
var title = a[2];
117-
var marker = L.marker(new L.LatLng(a[0], a[1]), { title: title });
118-
marker.bindPopup(title);
119-
markers.addLayer(marker);
120-
}
121-
122-
map.addLayer(markers);
123-
"""
124-
return out
2+
"""
3+
Folium plugins
4+
--------------
5+
6+
Add different objetcs/effects on a folium map.
7+
"""
8+
from .marker_cluster import MarkerCluster
9+
from .scroll_zoom_toggler import ScrollZoomToggler
10+
from .terminator import Terminator
11+
from .boat_marker import BoatMarker
12+
from .layer import Layer, LayerControl
13+
from .geo_json import GeoJson

folium/plugins/boat_marker.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
Boat marker
4+
-----------
5+
6+
Creates a marker shaped like a boat. Optionally you can append a wind direction.
7+
"""
8+
import json
9+
10+
from .plugin import Plugin
11+
12+
class BoatMarker(Plugin):
13+
"""Adds a BoatMarker layer on the map."""
14+
def __init__(self, position=None, heading=0, wind_heading=None, wind_speed=0, **kwargs):
15+
"""Creates a BoatMarker plugin to append into a map with
16+
Map.add_plugin.
17+
18+
Parameters
19+
----------
20+
position: tuple of length 2, default None
21+
The latitude and longitude of the marker.
22+
If None, then the middle of the map is used.
23+
24+
heading: int, default 0
25+
Heading of the boat to an angle value between 0 and 360 degrees
26+
27+
wind_heading: int, default None
28+
Heading of the wind to an angle value between 0 and 360 degrees
29+
If None, then no wind is represented.
30+
31+
wind_speed: int, default 0
32+
Speed of the wind in knots.
33+
"""
34+
super(BoatMarker, self).__init__()
35+
self.plugin_name = 'BoatMarker'
36+
self.position = None if position is None else tuple(position)
37+
self.heading = heading
38+
self.wind_heading = wind_heading
39+
self.wind_speed = wind_speed
40+
self.kwargs = kwargs.copy()
41+
42+
def render_header(self, nb):
43+
"""Generates the HTML part of the plugin."""
44+
return """
45+
<script src="https://thomasbrueggemann.github.io/leaflet.boatmarker/js/leaflet.boatmarker.min.js"></script>
46+
""" if nb==0 else ""
47+
48+
def render_js(self, nb):
49+
"""Generates the Javascript part of the plugin."""
50+
kwargs_str = "{%s}" % ",".join(["%s : %s" % (key,json.dumps(val)) for (key,val) in self.kwargs.items()])
51+
position_str = "map.getCenter()" if self.position is None else "[%.12f,%.12f]"%self.position
52+
out = 'var boatMarker_%s = L.boatMarker(%s, %s).addTo(map);' % (nb,position_str,kwargs_str)
53+
54+
if self.wind_heading is None:
55+
out += "boatMarker_%s.setHeading(%s);" % (nb,int(self.heading))
56+
else:
57+
out += "boatMarker_%s.setHeadingWind(%s, %s, %s);"%(nb,int(self.heading),
58+
int(self.wind_speed),
59+
int(self.wind_heading),
60+
)
61+
return out

folium/plugins/geo_json.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
GeoJson plugin
4+
--------------
5+
6+
Add a geojson feature collection on a folium map.
7+
"""
8+
import json
9+
10+
from .plugin import Plugin
11+
12+
class GeoJson(Plugin):
13+
"""Adds a GeoJson layer on the map."""
14+
def __init__(self, data):
15+
"""Creates a GeoJson plugin to append into a map with
16+
Map.add_plugin.
17+
18+
Parameters
19+
----------
20+
data: file, dict or str.
21+
The geo-json data you want to plot.
22+
If file, then data will be read in the file and fully embeded in Leaflet's javascript.
23+
If dict, then data will be converted to json and embeded in the javascript.
24+
If str, then data will be passed to the javascript as-is.
25+
26+
examples :
27+
# providing file
28+
GeoJson(open('foo.json'))
29+
30+
# providing dict
31+
GeoJson(json.load(open('foo.json')))
32+
33+
# providing string
34+
GeoJson(open('foo.json').read())
35+
"""
36+
super(GeoJson, self).__init__()
37+
self.plugin_name = 'GeoJson'
38+
if 'read' in dir(data):
39+
self.data = data.read()
40+
elif type(data) is dict:
41+
self.data = json.dumps(data)
42+
else:
43+
self.data = data
44+
45+
def render_js(self, nb):
46+
"""Generates the Javascript part of the plugin."""
47+
out = """
48+
var geojson_{nb} = L.geoJson({data}).addTo(map);
49+
""".format(nb=nb, data = self.data)
50+
return out

folium/plugins/layer.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
Layer plugin
4+
------------
5+
6+
Add layers and layer control to the map.
7+
"""
8+
from .plugin import Plugin
9+
10+
class Layer(Plugin):
11+
"""Adds a layer to the map."""
12+
def __init__(self, url=None, layer_name = None, min_zoom=1, max_zoom=18, attribution=''):
13+
"""Crates a layer object to be added on a folium map.
14+
15+
Parameters
16+
----------
17+
url : str
18+
The url of the layer service, in the classical leaflet form.
19+
example: url='//otile1.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png'
20+
layer_name : str
21+
Tha name of the layer that will be displayed in the layer control.
22+
If None, a random hexadecimal string will be created.
23+
min_zoom : int, default 1
24+
The minimal zoom allowed for this layer
25+
max_zoom : int, default 18
26+
The maximal zoom allowed for this layer
27+
attribution : str, default ''
28+
Tha atribution string for the layer.
29+
"""
30+
super(Layer, self).__init__()
31+
self.plugin_name = 'Layer'
32+
self.tile_url = url
33+
self.attribution = attribution
34+
self.min_zoom = min_zoom
35+
self.max_zoom = max_zoom
36+
self.object_id = self.object_name
37+
if layer_name is not None:
38+
self.object_name = layer_name
39+
40+
def render_js(self, nb):
41+
"""Generates the JS part of the plugin."""
42+
return """
43+
var layer_"""+self.object_id+""" = L.tileLayer('"""+self.tile_url+"""', {
44+
maxZoom: """+str(self.max_zoom)+""",
45+
minZoom: """+str(self.min_zoom)+""",
46+
attribution: '"""+str(self.attribution)+"""'
47+
});
48+
layer_"""+self.object_id+""".addTo(map);
49+
"""
50+
51+
class LayerControl(Plugin):
52+
"""Adds a layer control to the map."""
53+
def __init__(self, base_layer_name="Base Layer"):
54+
"""Creates a LayerControl object to be added on a folium map.
55+
56+
Parameters
57+
----------
58+
base_layer_name : str, default "Base Layer"
59+
The name of the base layer that you want to see on the control.
60+
"""
61+
super(LayerControl, self).__init__()
62+
self.plugin_name = 'LayerControl'
63+
self.base_layer_name = base_layer_name
64+
65+
def render_js(self, nb):
66+
"""Generates the JS part of the plugin."""
67+
return """
68+
var baseLayer = {
69+
"%s": base_tile,"""% self.base_layer_name+\
70+
",".join(['"%s" : layer_%s ' % (x.object_name,x.object_id) for x in self.map.plugins['Layer']])+\
71+
"""};
72+
73+
L.control.layers(baseLayer, layer_list).addTo(map);
74+
"""
75+
76+
77+

folium/plugins/marker_cluster.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
Marker Cluster plugin
4+
---------------------
5+
6+
Creates a MarkerCluster plugin to add on a folium map.
7+
"""
8+
import json
9+
10+
from .plugin import Plugin
11+
12+
class MarkerCluster(Plugin):
13+
"""Adds a MarkerCluster layer on the map."""
14+
def __init__(self, data):
15+
"""Creates a MarkerCluster plugin to append into a map with
16+
Map.add_plugin.
17+
18+
Parameters
19+
----------
20+
data: list of list or array of shape (n,3).
21+
Data points of the form [[lat, lng, popup]].
22+
"""
23+
super(MarkerCluster, self).__init__()
24+
self.plugin_name = 'MarkerCluster'
25+
self.data = [tuple(x) for x in data]
26+
27+
def render_header(self, nb):
28+
"""Generates the HTML part of the plugin."""
29+
return """
30+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/0.4.0/MarkerCluster.css" />
31+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/0.4.0/MarkerCluster.Default.css" />
32+
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.markercluster/0.4.0/leaflet.markercluster.js"></script>
33+
""" if nb==0 else ""
34+
35+
def render_js(self, nb):
36+
"""Generates the Javascript part of the plugin."""
37+
out = """
38+
var addressPoints = """+json.dumps(self.data)+""";
39+
40+
var markers = L.markerClusterGroup();
41+
42+
for (var i = 0; i < addressPoints.length; i++) {
43+
var a = addressPoints[i];
44+
var title = a[2];
45+
var marker = L.marker(new L.LatLng(a[0], a[1]), { title: title });
46+
marker.bindPopup(title);
47+
markers.addLayer(marker);
48+
}
49+
50+
map.addLayer(markers);
51+
"""
52+
return out

0 commit comments

Comments
 (0)