Skip to content

Commit 079ee97

Browse files
Make it possible to use Choropleth layer with data containing NaNs. The NaN regions have a dedicated color referred to as nan_color (black is set as default value) and a dedicated opacity referred to as nan_opacity (set to 0.4 as default value).
1 parent 201be19 commit 079ee97

File tree

6 files changed

+178
-20
lines changed

6 files changed

+178
-20
lines changed

examples/Choropleth.ipynb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@
162162
],
163163
"metadata": {
164164
"kernelspec": {
165-
"display_name": "Python 3",
165+
"display_name": "Python 3 (ipykernel)",
166166
"language": "python",
167167
"name": "python3"
168168
},
@@ -176,9 +176,9 @@
176176
"name": "python",
177177
"nbconvert_exporter": "python",
178178
"pygments_lexer": "ipython3",
179-
"version": "3.8.2"
179+
"version": "3.9.12"
180180
}
181181
},
182182
"nbformat": 4,
183-
"nbformat_minor": 2
183+
"nbformat_minor": 4
184184
}

examples/Choropleth_with_NANS.ipynb

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"metadata": {},
7+
"outputs": [],
8+
"source": [
9+
"import ipyleaflet\n",
10+
"from ipyleaflet import Map, LegendControl\n",
11+
"import json\n",
12+
"import pandas as pd\n",
13+
"from ipywidgets import link, FloatSlider\n",
14+
"from branca.colormap import linear\n",
15+
"import random\n",
16+
"\n",
17+
"colormap_choice = linear.YlOrRd_04\n",
18+
"geo_json_data = json.load(open(\"us-states.json\"))\n",
19+
"m = ipyleaflet.Map(center=(43, -100), zoom=4)\n",
20+
"unemployment = pd.read_csv(\"US_Unemployment_Oct2012_with_NANS.csv\")"
21+
]
22+
},
23+
{
24+
"cell_type": "code",
25+
"execution_count": null,
26+
"metadata": {},
27+
"outputs": [],
28+
"source": [
29+
"data_unemployment = dict(\n",
30+
" zip(unemployment[\"State\"].tolist(), unemployment[\"Unemployment\"].tolist())\n",
31+
")"
32+
]
33+
},
34+
{
35+
"cell_type": "code",
36+
"execution_count": null,
37+
"metadata": {},
38+
"outputs": [],
39+
"source": [
40+
"layer = ipyleaflet.Choropleth(\n",
41+
" geo_data=geo_json_data,\n",
42+
" choro_data=data_unemployment,\n",
43+
" colormap=colormap_choice,\n",
44+
" style={\"dashArray\": \"5, 5\"}\n",
45+
")"
46+
]
47+
},
48+
{
49+
"cell_type": "code",
50+
"execution_count": null,
51+
"metadata": {},
52+
"outputs": [],
53+
"source": [
54+
"# To display the colormap bar on the map\n",
55+
"from ipywidgets import Output\n",
56+
"from ipyleaflet import WidgetControl\n",
57+
"\n",
58+
"out = Output()\n",
59+
"\n",
60+
"with out:\n",
61+
" colormap = colormap_choice.scale(layer.value_min,layer.value_max)\n",
62+
" display(colormap)"
63+
]
64+
},
65+
{
66+
"cell_type": "code",
67+
"execution_count": null,
68+
"metadata": {},
69+
"outputs": [],
70+
"source": [
71+
"m.add_layer(layer)\n",
72+
"m.add_control(WidgetControl(widget=out, position='topright'))\n",
73+
"m"
74+
]
75+
}
76+
],
77+
"metadata": {
78+
"kernelspec": {
79+
"display_name": "Python 3 (ipykernel)",
80+
"language": "python",
81+
"name": "python3"
82+
},
83+
"language_info": {
84+
"codemirror_mode": {
85+
"name": "ipython",
86+
"version": 3
87+
},
88+
"file_extension": ".py",
89+
"mimetype": "text/x-python",
90+
"name": "python",
91+
"nbconvert_exporter": "python",
92+
"pygments_lexer": "ipython3",
93+
"version": "3.9.12"
94+
}
95+
},
96+
"nbformat": 4,
97+
"nbformat_minor": 4
98+
}

examples/LegendControl.ipynb

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
{
22
"cells": [
33
{
4-
"cell_type": "markdown",
4+
"cell_type": "code",
5+
"execution_count": null,
56
"metadata": {},
7+
"outputs": [],
68
"source": [
79
"# Legend: How to use"
810
]
@@ -145,18 +147,11 @@
145147
"a_legend.positioning = \"topright\" # set positioning : possible values are topleft, topright, bottomleft, bottomright\n",
146148
"a_legend.positioning # get current positioning"
147149
]
148-
},
149-
{
150-
"cell_type": "code",
151-
"execution_count": null,
152-
"metadata": {},
153-
"outputs": [],
154-
"source": []
155150
}
156151
],
157152
"metadata": {
158153
"kernelspec": {
159-
"display_name": "Python 3",
154+
"display_name": "Python 3 (ipykernel)",
160155
"language": "python",
161156
"name": "python3"
162157
},
@@ -170,7 +165,7 @@
170165
"name": "python",
171166
"nbconvert_exporter": "python",
172167
"pygments_lexer": "ipython3",
173-
"version": "3.6.9"
168+
"version": "3.9.12"
174169
}
175170
},
176171
"nbformat": 4,
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
State,Unemployment
2+
AL,7.1
3+
AK,6.8
4+
AZ,8.1
5+
AR,7.2
6+
CA,nan
7+
CO,7.7
8+
CT,8.4
9+
DE,7.1
10+
FL,8.2
11+
GA,8.8
12+
HI,nan
13+
ID,6.6
14+
IL,8.8
15+
IN,8.4
16+
IA,nan
17+
KS,5.6
18+
KY,8.1
19+
LA,5.9
20+
ME,7.2
21+
MD,nan
22+
MA,6.7
23+
MI,9.1
24+
MN,5.6
25+
MS,9.1
26+
MO,nan
27+
MT,5.8
28+
NE,3.9
29+
NV,10.3
30+
NH,5.7
31+
NJ,nan
32+
NM,6.8
33+
NY,8.4
34+
NC,9.4
35+
ND,3.2
36+
OH,6.9
37+
OK,5.2
38+
OR,8.5
39+
PA,8
40+
RI,10.1
41+
SC,8.8
42+
SD,4.4
43+
TN,7.8
44+
TX,nan
45+
UT,5.5
46+
VT,5
47+
VA,nan
48+
WA,7.8
49+
WV,7.5
50+
WI,6.8
51+
WY,5.1

examples/WidgetControl.ipynb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@
9797
],
9898
"metadata": {
9999
"kernelspec": {
100-
"display_name": "Python 3",
100+
"display_name": "Python 3 (ipykernel)",
101101
"language": "python",
102102
"name": "python3"
103103
},
@@ -111,9 +111,9 @@
111111
"name": "python",
112112
"nbconvert_exporter": "python",
113113
"pygments_lexer": "ipython3",
114-
"version": "3.7.1"
114+
"version": "3.9.12"
115115
}
116116
},
117117
"nbformat": 4,
118-
"nbformat_minor": 2
118+
"nbformat_minor": 4
119119
}

ipyleaflet/leaflet.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import json
88
import xyzservices
99
from datetime import date, timedelta
10+
from math import isnan
1011

1112
from ipywidgets import (
1213
Widget, DOMWidget, Box, Color, CallbackDispatcher, widget_serialization,
@@ -1330,6 +1331,12 @@ class Choropleth(GeoJSON):
13301331
The colormap used for the effect.
13311332
key_on: string, default "id"
13321333
The feature key to use for the colormap effect.
1334+
nan_color: string, default "black"
1335+
The color used for filling polygons with NaN-values data.
1336+
nan_opacity : float, default 0.4
1337+
The opacity used for NaN data polygons, between 0. (fully transparent) and 1. (fully opaque).
1338+
default_opacity: float, default 1.0
1339+
The opacity used for well-defined data (non-NaN values), between 0. (fully transparent) and 1. (fully opaque).
13331340
"""
13341341

13351342
geo_data = Dict()
@@ -1338,8 +1345,11 @@ class Choropleth(GeoJSON):
13381345
value_max = CFloat(None, allow_none=True)
13391346
colormap = Any()
13401347
key_on = Unicode('id')
1348+
nan_color = Unicode('black')
1349+
nan_opacity = CFloat(0.4)
1350+
default_opacity = CFloat(1.0)
13411351

1342-
@observe('style', 'style_callback', 'value_min', 'value_max', 'geo_data', 'choro_data', 'colormap')
1352+
@observe('style', 'style_callback', 'value_min', 'value_max', 'nan_color', 'nan_opacity', 'default_opacity', 'geo_data', 'choro_data', 'colormap')
13431353
def _update_data(self, change):
13441354
self.data = self._get_data()
13451355

@@ -1355,7 +1365,8 @@ def _default_colormap(self):
13551365
def _default_style_callback(self):
13561366
def compute_style(feature, colormap, choro_data):
13571367
return dict(
1358-
fillColor=colormap(choro_data),
1368+
fillColor=self.nan_color if isnan(choro_data) else colormap(choro_data),
1369+
fillOpacity=self.nan_opacity if isnan(choro_data) else self.default_opacity,
13591370
color='black',
13601371
weight=0.9
13611372
)
@@ -1366,12 +1377,15 @@ def _get_data(self):
13661377
if not self.geo_data:
13671378
return {}
13681379

1380+
choro_data_values_list = [x for x in self.choro_data.values() if not math.isnan(x)]
1381+
13691382
if self.value_min is None:
1370-
self.value_min = min(self.choro_data.items(), key=lambda x: x[1])[1]
1383+
self.value_min = min(choro_data_values_list)
13711384
if self.value_max is None:
1372-
self.value_max = max(self.choro_data.items(), key=lambda x: x[1])[1]
1385+
self.value_max = max(choro_data_values_list)
13731386

13741387
colormap = self.colormap.scale(self.value_min, self.value_max)
1388+
13751389
data = copy.deepcopy(self.geo_data)
13761390

13771391
for feature in data['features']:

0 commit comments

Comments
 (0)