Repository: Unidata/MetPy

Issue:
reduce_point_density and bad points
Make `reduce_point_density` handle points (e.g. nans and infinities) by automatically setting their mask to `False`. These points can result from the lat/lon location not being valid in the projected space.

Discussion:

Patch:
diff --git a/src/metpy/calc/tools.py b/src/metpy/calc/tools.py
index 19e5fac426..3e7c0d53fc 100644
--- a/src/metpy/calc/tools.py
+++ b/src/metpy/calc/tools.py
@@ -248,6 +248,9 @@ def reduce_point_density(points, radius, priority=None):
     stations with higher precipitation remain in the mask). The points and radius can be
     specified with units. If none are provided, meters are assumed.
 
+    Points with at least one non-finite (i.e. NaN or Inf) value are ignored and returned with
+    a value of ``False`` (meaning don't keep).
+
     Parameters
     ----------
     points : (N, K) array-like
@@ -283,6 +286,11 @@ def reduce_point_density(points, radius, priority=None):
     if points.ndim < 2:
         points = points.reshape(-1, 1)
 
+    # Identify good points--finite values (e.g. not NaN or inf). Set bad 0, but we're going to
+    # ignore anyway. It's easier for managing indices to keep the original points in the group.
+    good_vals = np.isfinite(points)
+    points = np.where(good_vals, points, 0)
+
     # Make a kd-tree to speed searching of data.
     tree = cKDTree(points)
 
@@ -295,8 +303,8 @@ def reduce_point_density(points, radius, priority=None):
         # Take advantage of iterator nature of range here to avoid making big lists
         sorted_indices = range(len(points))
 
-    # Keep all points initially
-    keep = np.ones(len(points), dtype=bool)
+    # Keep all good points initially
+    keep = np.logical_and.reduce(good_vals, axis=-1)
 
     # Loop over all the potential points
     for ind in sorted_indices:


Test patch:
diff --git a/tests/calc/test_calc_tools.py b/tests/calc/test_calc_tools.py
index eb5ca3b28e..2984e547a7 100644
--- a/tests/calc/test_calc_tools.py
+++ b/tests/calc/test_calc_tools.py
@@ -150,6 +150,15 @@ def test_reduce_point_density(thin_point_data, radius, truth):
     assert_array_equal(reduce_point_density(thin_point_data, radius=radius), truth)
 
 
+def test_reduce_point_density_nonfinite():
+    """Test that non-finite point values are properly marked not to keep."""
+    points = np.array(
+        [(np.nan, np.nan), (np.nan, 5), (5, 5), (5, np.nan),
+         (10, 10), (np.inf, 10), (10, np.inf), (np.inf, np.inf)])
+    mask = reduce_point_density(points, 1)
+    assert_array_equal(mask, [False, False, True, False, True, False, False, False])
+
+
 @pytest.mark.parametrize('radius, truth',
                          [(2.0, np.array([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                                           0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=bool)),