From 1fd47fd12af1dc9db8f8a9f7144462b6b2e8fd7b Mon Sep 17 00:00:00 2001 From: Leonardo Uieda Date: Wed, 3 May 2023 13:47:16 +0100 Subject: [PATCH] Fix behavior if spacing >= 2 * interval This was a bug caused by the rounding when calculating the number of nodes in `spacing_to_size`. For the case where the spacing is larger than twice the interval, the size calculating rounded to zero which meant that we were getting a single value for the number of nodes. This is clearly wrong since our behavior is to change the spacing or the region to make sure we always produce at least 2 nodes in the interval. --- verde/coordinates.py | 18 +++++++++++++++--- verde/tests/test_coordinates.py | 17 ++++++++++++++++- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/verde/coordinates.py b/verde/coordinates.py index f9a2a9cd5..3d582a8c4 100644 --- a/verde/coordinates.py +++ b/verde/coordinates.py @@ -249,6 +249,10 @@ def line_coordinates( The spacing is adjusted to fit the interval by default but this can be changed to adjusting the interval/region instead: + >>> print(line_coordinates(0, 10, spacing=2.4)) + [ 0. 2.5 5. 7.5 10. ] + >>> print(line_coordinates(0, 10, spacing=2.4, adjust="region")) + [0. 2.4 4.8 7.2 9.6] >>> print(line_coordinates(0, 10, spacing=2.6)) [ 0. 2.5 5. 7.5 10. ] >>> print(line_coordinates(0, 10, spacing=2.6, adjust="region")) @@ -277,9 +281,9 @@ def line_coordinates( size, stop = spacing_to_size(start, stop, spacing, adjust) elif pixel_register: # Starts by generating grid-line registered coordinates and shifting - # them to the center of the pixel. Need 1 more point if given a shape - # so that we can do that because we discard the last point when - # shifting the coordinates. + # them to the center of the pixel. Need 1 more point if given a size + # instead of spacing so that we can do that because we discard the last + # point when shifting the coordinates. size = size + 1 values = np.linspace(start, stop, size) if pixel_register: @@ -626,6 +630,14 @@ def spacing_to_size(start, stop, spacing, adjust): ) # Add 1 to get the number of nodes, not segments size = int(round((stop - start) / spacing)) + 1 + # If the spacing >= 2 * (stop - start), it rounds to zero so we'd be + # generating a single point, which isn't equivalent to adjusting the + # spacing or the region. To get the appropriate behaviour of decreasing the + # spacing until it fits the region or increasing the region until it fits + # at least 1 spacing, we need to always round to at least 1 in the code + # above. + if size == 1: + size += 1 if adjust == "region": # The size is the same but we adjust the interval so that the spacing # isn't altered when we do the linspace. diff --git a/verde/tests/test_coordinates.py b/verde/tests/test_coordinates.py index 86cceaef6..f7d7a7ef0 100644 --- a/verde/tests/test_coordinates.py +++ b/verde/tests/test_coordinates.py @@ -136,13 +136,28 @@ def test_line_coordinates_fails(): # Make sure it doesn't fail for these parameters line_coordinates(start, stop, size=size) line_coordinates(start, stop, spacing=spacing) - with pytest.raises(ValueError): line_coordinates(start, stop) with pytest.raises(ValueError): line_coordinates(start, stop, size=size, spacing=spacing) +def test_line_coordinates_spacing_larger_than_twice_interval(): + "Check if pixel_register works when the spacing is greater than the limits" + start, stop = 0, 1 + spacing = 3 + coordinates = line_coordinates(start, stop, spacing=spacing) + npt.assert_allclose(coordinates, [0, 1]) + coordinates = line_coordinates(start, stop, spacing=spacing, pixel_register=True) + npt.assert_allclose(coordinates, [0.5]) + coordinates = line_coordinates(start, stop, spacing=spacing, adjust="region") + npt.assert_allclose(coordinates, [0, 3]) + coordinates = line_coordinates( + start, stop, spacing=spacing, pixel_register=True, adjust="region" + ) + npt.assert_allclose(coordinates, [1.5]) + + def test_grid_coordinates_fails(): "Check failures for invalid arguments" region = (0, 1, 0, 10)