Skip to content

Commit 6c87d75

Browse files
authored
Merge pull request #490 from joshuacano/highlight
Fix #341: Added highlight function for Choropleth
2 parents 6bc71ab + de57eac commit 6c87d75

File tree

6 files changed

+217
-26
lines changed

6 files changed

+217
-26
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- Added options to LayerControl (qingkaikong #473)
99
- Added text path (talespaiva #451 and #474)
1010
- Update font-awesome to 4.6.3 (ocefpaf #478)
11+
- Add highlight function to GeoJSON, and Chrorpleth (JoshuaCano #341)
1112

1213
Bug Fixes
1314

examples/GeoJSON_and_choropleth.ipynb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,37 @@
783783
"m"
784784
]
785785
},
786+
{
787+
"cell_type": "markdown",
788+
"metadata": {},
789+
"source": [
790+
"You can also enable the highlight function, to enable highlight functionality when you hover over each area."
791+
]
792+
},
793+
{
794+
"cell_type": "code",
795+
"execution_count": null,
796+
"metadata": {
797+
"collapsed": true
798+
},
799+
"outputs": [],
800+
"source": [
801+
"state_geo = r'us-states.json'\n",
802+
"state_unemployment = r'US_Unemployment_Oct2012.csv'\n",
803+
"\n",
804+
"state_data = pd.read_csv(state_unemployment)\n",
805+
"\n",
806+
"#Let Folium determine the scale\n",
807+
"states = folium.Map(location=[48, -102], zoom_start=3)\n",
808+
"states.choropleth(geo_path=state_geo, data=state_data,\n",
809+
" columns=['State', 'Unemployment'],\n",
810+
" key_on='feature.id',\n",
811+
" fill_color='YlGn', fill_opacity=0.7, line_opacity=0.2,\n",
812+
" legend_name='Unemployment Rate (%)', highlight=True)\n",
813+
"\n",
814+
"states"
815+
]
816+
},
786817
{
787818
"cell_type": "markdown",
788819
"metadata": {},

examples/folium_examples.ipynb

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"cells": [
33
{
44
"cell_type": "code",
5-
"execution_count": 1,
5+
"execution_count": null,
66
"metadata": {
77
"collapsed": false
88
},
@@ -23,7 +23,7 @@
2323
},
2424
{
2525
"cell_type": "code",
26-
"execution_count": 2,
26+
"execution_count": null,
2727
"metadata": {
2828
"collapsed": false
2929
},
@@ -50,7 +50,7 @@
5050
},
5151
{
5252
"cell_type": "code",
53-
"execution_count": 3,
53+
"execution_count": null,
5454
"metadata": {
5555
"collapsed": false
5656
},
@@ -77,7 +77,7 @@
7777
},
7878
{
7979
"cell_type": "code",
80-
"execution_count": 4,
80+
"execution_count": null,
8181
"metadata": {
8282
"collapsed": false
8383
},
@@ -106,7 +106,7 @@
106106
},
107107
{
108108
"cell_type": "code",
109-
"execution_count": 5,
109+
"execution_count": null,
110110
"metadata": {
111111
"collapsed": false
112112
},
@@ -137,7 +137,7 @@
137137
},
138138
{
139139
"cell_type": "code",
140-
"execution_count": 6,
140+
"execution_count": null,
141141
"metadata": {
142142
"collapsed": false
143143
},
@@ -165,10 +165,11 @@
165165
},
166166
{
167167
"cell_type": "code",
168-
"execution_count": 7,
168+
"execution_count": null,
169169
"metadata": {
170170
"collapsed": false
171171
},
172+
<<<<<<< HEAD
172173
"outputs": [
173174
{
174175
"data": {
@@ -194,7 +195,7 @@
194195
},
195196
{
196197
"cell_type": "code",
197-
"execution_count": 8,
198+
"execution_count": null,
198199
"metadata": {
199200
"collapsed": false
200201
},
@@ -229,7 +230,7 @@
229230
},
230231
{
231232
"cell_type": "code",
232-
"execution_count": 9,
233+
"execution_count": null,
233234
"metadata": {
234235
"collapsed": false
235236
},
@@ -322,7 +323,7 @@
322323
},
323324
{
324325
"cell_type": "code",
325-
"execution_count": 10,
326+
"execution_count": null,
326327
"metadata": {
327328
"collapsed": false
328329
},
@@ -367,7 +368,31 @@
367368
},
368369
{
369370
"cell_type": "code",
370-
"execution_count": 11,
371+
"execution_count": null,
372+
"metadata": {
373+
"collapsed": true
374+
},
375+
"outputs": [],
376+
"source": [
377+
"state_geo = r'us-states.json'\n",
378+
"state_unemployment = r'US_Unemployment_Oct2012.csv'\n",
379+
"\n",
380+
"state_data = pd.read_csv(state_unemployment)\n",
381+
"\n",
382+
"#Enable Highlighting function, to allow hover highlight function\n",
383+
"states = folium.Map(location=[48, -102], zoom_start=3)\n",
384+
"states.choropleth(geo_path=state_geo, data=state_data,\n",
385+
" columns=['State', 'Unemployment'],\n",
386+
" key_on='feature.id',\n",
387+
" fill_color='YlGn', fill_opacity=0.7, line_opacity=0.2,\n",
388+
" legend_name='Unemployment Rate (%)', highlight=True)\n",
389+
"\n",
390+
"states"
391+
]
392+
},
393+
{
394+
"cell_type": "code",
395+
"execution_count": null,
371396
"metadata": {
372397
"collapsed": false
373398
},
@@ -394,13 +419,13 @@
394419
" key_on='feature.id',\n",
395420
" fill_color='BuPu', fill_opacity=0.7, line_opacity=0.5,\n",
396421
" legend_name='Unemployment Rate (%)',\n",
397-
" reset=True)\n",
422+
" reset=True, highli)\n",
398423
"states2"
399424
]
400425
},
401426
{
402427
"cell_type": "code",
403-
"execution_count": 12,
428+
"execution_count": null,
404429
"metadata": {
405430
"collapsed": false
406431
},
@@ -453,7 +478,7 @@
453478
},
454479
{
455480
"cell_type": "code",
456-
"execution_count": 13,
481+
"execution_count": null,
457482
"metadata": {
458483
"collapsed": false
459484
},
@@ -497,7 +522,7 @@
497522
},
498523
{
499524
"cell_type": "code",
500-
"execution_count": 14,
525+
"execution_count": null,
501526
"metadata": {
502527
"collapsed": false
503528
},

folium/features.py

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,8 @@ class GeoJson(Layer):
299299
>>> GeoJson(geojson, style_function=style_function)
300300
"""
301301
def __init__(self, data, style_function=None, name=None,
302-
overlay=True, control=True, smooth_factor=None):
302+
overlay=True, control=True, smooth_factor=None,
303+
highlight_function=None):
303304
super(GeoJson, self).__init__(name=name, overlay=overlay,
304305
control=control)
305306
self._name = 'GeoJson'
@@ -332,19 +333,55 @@ def __init__(self, data, style_function=None, name=None,
332333

333334
if style_function is None:
334335
def style_function(x):
335-
return {}
336+
return {}
337+
336338
self.style_function = style_function
337339

340+
self.highlight = highlight_function is not None
341+
342+
if highlight_function is None:
343+
def highlight_function(x):
344+
return {}
345+
346+
self.highlight_function = highlight_function
347+
338348
self.smooth_factor = smooth_factor
339349

340350
self._template = Template(u"""
341351
{% macro script(this, kwargs) %}
352+
353+
{% if this.highlight %}
354+
{{this.get_name()}}_onEachFeature = function onEachFeature(feature, layer) {
355+
layer.on({
356+
mouseout: function(e) {
357+
e.target.setStyle(e.target.feature.properties.style);},
358+
mouseover: function(e) {
359+
e.target.setStyle(e.target.feature.properties.highlight);},
360+
click: function(e) {
361+
{{this._parent.get_name()}}.fitBounds(e.target.getBounds());}
362+
});
363+
};
364+
{% endif %}
365+
342366
var {{this.get_name()}} = L.geoJson(
343367
{% if this.embed %}{{this.style_data()}}{% else %}"{{this.data}}"{% endif %}
344-
{% if this.smooth_factor is not none %}
345-
, {smoothFactor:{{this.smooth_factor}}}
346-
{% endif %}).addTo({{this._parent.get_name()}});
368+
{% if this.smooth_factor is not none or this.highlight %}
369+
, {
370+
{% if this.smooth_factor is not none %}
371+
smoothFactor:{{this.smooth_factor}}
372+
{% endif %}
373+
374+
{% if this.highlight %}
375+
{% if this.smooth_factor is not none %}
376+
,
377+
{% endif %}
378+
onEachFeature: {{this.get_name()}}_onEachFeature
379+
{% endif %}
380+
}
381+
{% endif %}
382+
).addTo({{this._parent.get_name()}});
347383
{{this.get_name()}}.setStyle(function(feature) {return feature.properties.style;});
384+
348385
{% endmacro %}
349386
""") # noqa
350387

@@ -363,6 +400,7 @@ def style_data(self):
363400

364401
for feature in self.data['features']:
365402
feature.setdefault('properties', {}).setdefault('style', {}).update(self.style_function(feature)) # noqa
403+
feature.setdefault('properties', {}).setdefault('highlight', {}).update(self.highlight_function(feature)) # noqa
366404
return json.dumps(self.data, sort_keys=True)
367405

368406
def _get_self_bounds(self):

folium/folium.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,13 @@
2222
ClickForMarker, TopoJson, PolyLine, MultiPolyLine,
2323
)
2424

25-
2625
def initialize_notebook():
2726
"""Initialize the IPython notebook display elements."""
2827
warnings.warn("%s is deprecated and no longer required." %
2928
("initialize_notebook",),
3029
FutureWarning, stacklevel=2)
3130
pass
3231

33-
3432
class Map(LegacyMap):
3533
"""Create a Map with Folium and Leaflet.js
3634
@@ -510,7 +508,8 @@ def choropleth(self, geo_path=None, geo_str=None, data_out='data.json',
510508
data=None, columns=None, key_on=None, threshold_scale=None,
511509
fill_color='blue', fill_opacity=0.6, line_color='black',
512510
line_weight=1, line_opacity=1, legend_name="",
513-
topojson=None, reset=False, smooth_factor=None):
511+
topojson=None, reset=False, smooth_factor=None,
512+
highlight=None):
514513
"""
515514
Apply a GeoJSON overlay to the map.
516515
@@ -582,6 +581,8 @@ def choropleth(self, geo_path=None, geo_str=None, data_out='data.json',
582581
How much to simplify the polyline on each zoom level. More means
583582
better performance and smoother look, and less means more accurate
584583
representation. Leaflet defaults to 1.0.
584+
highlight: boolean, default False
585+
Enable highlight functionality when hovering over a GeoJSON area.
585586
586587
Returns
587588
-------
@@ -598,6 +599,12 @@ def choropleth(self, geo_path=None, geo_str=None, data_out='data.json',
598599
... threshold_scale=[0, 20, 30, 40, 50, 60])
599600
>>> m.choropleth(geo_path='countries.json',
600601
... topojson='objects.countries')
602+
>>> m.choropleth(geo_path='geo.json', data=df,
603+
... columns=['Data 1', 'Data 2'],
604+
... key_on='feature.properties.myvalue',
605+
... fill_color='PuBu',
606+
... threshold_scale=[0, 20, 30, 40, 50, 60],
607+
... highlight=True)
601608
602609
"""
603610
if threshold_scale and len(threshold_scale) > 6:
@@ -679,6 +686,13 @@ def style_function(x):
679686
"fillColor": color_scale_fun(x)
680687
}
681688

689+
690+
def highlight_function(x):
691+
return {
692+
"weight": line_weight + 2,
693+
"fillOpacity": fill_opacity + .2
694+
}
695+
682696
if topojson:
683697
geo_json = TopoJson(
684698
geo_data,
@@ -689,7 +703,8 @@ def style_function(x):
689703
geo_json = GeoJson(
690704
geo_data,
691705
style_function=style_function,
692-
smooth_factor=smooth_factor)
706+
smooth_factor=smooth_factor,
707+
highlight_function=highlight_function if highlight else None)
693708

694709
self.add_child(geo_json)
695710

0 commit comments

Comments
 (0)