admin管理员组文章数量:1336563
Im currently trying to collect some weather data from an API, and to reduce the amount of API calls im trying to batch the calls on 0.5degree longitude and latitude chunks due to its resolution. I had this code
def round_to_grid_center(coordinate,grid_spacing=0.5 ):
offset = grid_spacing / 2
return round(((coordinate - offset) / grid_spacing)) * grid_spacing + offset
but this function rounded values at 0.5 down to 0.25 instead of up to 0.75, so i added this fix. It works for me, but I'm sure there is a better more efficient method to round the coordinates to their closest grid square centre. Please let me know!
def round_to_grid_center(coordinate,grid_spacing=0.5 ):
#temp fix for round down error
if ((coordinate % 0.5)== 0 and (coordinate % 1 )!= 0):
offset = grid_spacing / 2
return round(((coordinate + 0.01 - offset) / grid_spacing)) * grid_spacing + offset
else:
offset = grid_spacing / 2
return round(((coordinate - offset) / grid_spacing)) * grid_spacing + offset
Im currently trying to collect some weather data from an API, and to reduce the amount of API calls im trying to batch the calls on 0.5degree longitude and latitude chunks due to its resolution. I had this code
def round_to_grid_center(coordinate,grid_spacing=0.5 ):
offset = grid_spacing / 2
return round(((coordinate - offset) / grid_spacing)) * grid_spacing + offset
but this function rounded values at 0.5 down to 0.25 instead of up to 0.75, so i added this fix. It works for me, but I'm sure there is a better more efficient method to round the coordinates to their closest grid square centre. Please let me know!
def round_to_grid_center(coordinate,grid_spacing=0.5 ):
#temp fix for round down error
if ((coordinate % 0.5)== 0 and (coordinate % 1 )!= 0):
offset = grid_spacing / 2
return round(((coordinate + 0.01 - offset) / grid_spacing)) * grid_spacing + offset
else:
offset = grid_spacing / 2
return round(((coordinate - offset) / grid_spacing)) * grid_spacing + offset
Share
Improve this question
asked Nov 20, 2024 at 2:49
SchliemannSchliemann
551 silver badge6 bronze badges
2 Answers
Reset to default 3Given: round half to even
The round()
function uses "round half to even" rounding mode, as mentioned in the Built-in Types doc, section Numeric types (emphasis by me):
Operation Result round(x[, n])
x rounded to n digits, rounding half to even. If n is omitted, it defaults to 0.
"Rounding half to even" means that a floating point number with a decimal part of .5 is rounded towards the closest even integer rather than the closest greater integer. For example, both round(1.5)
and round(2.5)
will produce 2
. In entry 5 (coordinate=38.5
, grid_spacing=0.5
, offset=0.25
), you will consequently get round((38.5-0.25)/0.5))
= round(76.5)
= 76
, and thus a rounded-down result for the part of your calculation before spacing and offset correction.
The Wikipedia article on rounding provides as motivation for this rounding mode:
This function minimizes the expected error when summing over rounded figures, even when the inputs are mostly positive or mostly negative, provided they are neither mostly even nor mostly odd.
If one needs further convincing that this rounding mode makes sense, one might want to have a look at the very detailed answer to this question ("rounding half to even" is called "banker's rounding" there).
Required: round half up
In any case, what you want is round half up instead. You can follow the answers to this question for potential solutions, e.g. rather than using round(x)
, you could use int(x + .5)
or float(Decimal(x).to_integral_value(rounding=ROUND_HALF_UP))
.
Altogether, this could look as follows:
from decimal import Decimal, ROUND_HALF_UP
values = [(33.87, 151.21), (33.85, 151.22), ( 38.75, 149.85),
(35.15, 150.85), (38.50, 149.87), (-38.50, 149.95)]
def round_to_grid_center(coordinate, grid_spacing=0.5):
offset = grid_spacing / 2
return round((coordinate - offset) / grid_spacing) * grid_spacing + offset
def round_with_int(coordinate, grid_spacing=0.5):
offset = grid_spacing / 2
return int(.5 + ((coordinate - offset) / grid_spacing)) * grid_spacing + offset
def round_with_decimal(coordinate, grid_spacing=0.5):
offset = grid_spacing / 2
return float(Decimal((coordinate - offset) / grid_spacing).to_integral_value(rounding=ROUND_HALF_UP)) * grid_spacing + offset
for round_current in [round_to_grid_center, round_with_int, round_with_decimal]:
print(f"\n{round_current.__name__}():")
for i, (v1, v2) in enumerate(values):
print(f"{i+1}: {v1}→{round_current(v1)}, {v2}→{round_current(v2)}")
Which prints:
round_to_grid_center():
1: 33.87→33.75, 151.21→151.25
2: 33.85→33.75, 151.22→151.25
3: 38.75→38.75, 149.85→149.75
4: 35.15→35.25, 150.85→150.75
5: 38.5→38.25, 149.87→149.75
6: -38.5→-38.75, 149.95→149.75
round_with_int():
1: 33.87→33.75, 151.21→151.25
2: 33.85→33.75, 151.22→151.25
3: 38.75→38.75, 149.85→149.75
4: 35.15→35.25, 150.85→150.75
5: 38.5→38.75, 149.87→149.75
6: -38.5→-38.25, 149.95→149.75
round_with_decimal():
1: 33.87→33.75, 151.21→151.25
2: 33.85→33.75, 151.22→151.25
3: 38.75→38.75, 149.85→149.75
4: 35.15→35.25, 150.85→150.75
5: 38.5→38.75, 149.87→149.75
6: -38.5→-38.75, 149.95→149.75
Note how the values differ for negative numbers though (which I included as entry 6): with int()
, "up" means "towards positive infinity"; with Decimal
, "up" means "away from zero".
Last but not least – be aware of numerical imprecision in floating point representation and arithmetic: depending on the size of coordinate
and the value of grid_spacing
, round-off error may lead to unexpected results.
Try using this:
def round_to_grid_center(coordinate,grid_spacing=0.5 ):
offset = grid_spacing / 2
return round(((coordinate - offset) / grid_spacing)) * grid_spacing + offset
the offset grid_spacing / 2 to shift the coordinate so that the rounding happens around the grid center (ex., 0.25, 0.75 for a 0.5 degree grid).
we round to the nearest multiple of grid_spacing
finally, subtract the offset to return the coordinate to its correct center position
When you round (coordinate + offset) / grid_spacing, you ensure the rounding happens at the center of each grid cell. This way will handle all cases better, including those where the coordinate is exactly on a boundary (like 5.0, 5.5), without causing errors or inconsistences.
本文标签: pythonrounding coordinates to centre of grid squareStack Overflow
版权声明:本文标题:python - rounding coordinates to centre of grid square - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742385714a2464990.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论