Skip to content

Commit 11776d4

Browse files
committed
Fix HeatMap crash on integer numpy weight arrays
HeatMap's docstring documents numpy arrays of shape (n, 2) or (n, 3) as valid input, but an all-integer array (dtype int64) crashes at render time with "Object of type int64 is not JSON serializable". validate_location coerces the lat/lon columns to Python float, while the weight column (line[2:]) was passed through unchanged. np.float64 is a subclass of float so json.dumps tolerates float weights, but np.int64 is not a subclass of int, so integer weights fail. This is common in practice, e.g. HeatMap(df[["lat", "lon", "count"]].values) where the count column has an integer dtype. Coerce the weight column to float, mirroring the lat/lon normalization.
1 parent f15eff3 commit 11776d4

2 files changed

Lines changed: 42 additions & 1 deletion

File tree

folium/plugins/heat_map.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ def __init__(
7979
self._name = "HeatMap"
8080
data = if_pandas_df_convert_to_numpy(data)
8181
self.data = [
82-
[*validate_location(line[:2]), *line[2:]] for line in data # noqa: E999
82+
[*validate_location(line[:2]), *[float(w) for w in line[2:]]]
83+
for line in data # noqa: E999
8384
]
8485
if np.any(np.isnan(self.data)):
8586
raise ValueError("data may not contain NaNs.")

tests/plugins/test_heat_map.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,43 @@ def test_heat_map_exception():
6666
HeatMap(np.array([[4, 5, 1], [3, 6, np.nan]]))
6767
with pytest.raises(Exception):
6868
HeatMap(np.array([3, 4, 5]))
69+
70+
71+
def test_heatmap_integer_numpy_weights():
72+
"""Integer numpy arrays of shape (n, 3) are documented as supported input.
73+
74+
``np.float64`` is a subclass of ``float`` so JSON serialization tolerates
75+
float weights, but ``np.int64`` is not a subclass of ``int``, so an
76+
all-integer array (dtype ``int64``) used to crash rendering with
77+
"Object of type int64 is not JSON serializable". The weight column must be
78+
coerced to ``float`` the same way ``validate_location`` coerces lat/lon.
79+
"""
80+
data = np.array([[3, 4, 1], [5, 6, 2]])
81+
assert data.dtype == np.int64
82+
83+
hm = HeatMap(data)
84+
85+
# Weights must be normalized to plain Python floats, matching lat/lon.
86+
for point in hm.data:
87+
assert len(point) == 3
88+
for value in point:
89+
assert type(value) is float
90+
91+
# Rendering must not raise (the JSON serialization used to fail here).
92+
m = folium.Map()
93+
hm.add_to(m)
94+
out = m.get_root().render()
95+
assert "L.heatLayer" in out
96+
97+
# Integer and float weights must produce identical serialized data.
98+
hm_float = HeatMap(np.array([[3, 4, 1.0], [5, 6, 2.0]]))
99+
assert hm.data == hm_float.data
100+
101+
102+
def test_heatmap_integer_numpy_no_weight():
103+
"""Integer numpy arrays of shape (n, 2) (no weight column) also render."""
104+
data = np.array([[3, 4], [5, 6]])
105+
assert data.dtype == np.int64
106+
m = folium.Map()
107+
HeatMap(data).add_to(m)
108+
assert "L.heatLayer" in m.get_root().render()

0 commit comments

Comments
 (0)