20
20
from tobac .utils .datetime import to_cftime , to_datetime64
21
21
22
22
23
- def test_calculate_distance ():
23
+ def test_calculate_distance_xy ():
24
+ """
25
+ Test for tobac.analysis.spatial.calculate_distance with cartesian coordinates
26
+ """
24
27
test_features = pd .DataFrame (
25
28
{
26
29
"feature" : [1 , 2 ],
@@ -36,6 +39,13 @@ def test_calculate_distance():
36
39
37
40
assert calculate_distance (test_features .iloc [0 ], test_features .iloc [1 ]) == 1000
38
41
42
+
43
+ def test_calculate_distance_latlon ():
44
+ """
45
+ Test for tobac.analysis.spatial.calculate_distance with latitude/longitude
46
+ coordinates
47
+ """
48
+
39
49
test_features = pd .DataFrame (
40
50
{
41
51
"feature" : [1 , 2 ],
@@ -53,6 +63,27 @@ def test_calculate_distance():
53
63
test_features .iloc [0 ], test_features .iloc [1 ]
54
64
) == pytest .approx (1.11e5 , rel = 1e4 )
55
65
66
+
67
+ def test_calculate_distance_latlon_wrong_order ():
68
+ """
69
+ Test for tobac.analysis.spatial.calculate_distance with latitude/longitude
70
+ coordinates provided in the wrong order. When lat/lon are provided with
71
+ standard naming the function should detect this and switch their order to
72
+ ensure that haversine distances are calculated correctly.
73
+ """
74
+
75
+ test_features = pd .DataFrame (
76
+ {
77
+ "feature" : [1 , 2 ],
78
+ "frame" : [0 , 0 ],
79
+ "time" : [
80
+ datetime (2000 , 1 , 1 ),
81
+ datetime (2000 , 1 , 1 ),
82
+ ],
83
+ "longitude" : [0 , 1 ],
84
+ "latitude" : [0 , 0 ],
85
+ }
86
+ )
56
87
# Test that if latitude and longitude coord names are given in the wrong order, then they are swapped:
57
88
# (expectation is hdim1=y=latitude, hdim2=x=longitude, doesn't matter for x/y but does matter for lat/lon)
58
89
assert calculate_distance (
@@ -64,14 +95,16 @@ def test_calculate_distance():
64
95
) == pytest .approx (1.11e5 , rel = 1e4 )
65
96
66
97
67
- def test_calculate_distance_errors ():
68
- # Test invalid method_distance
98
+ def test_calculate_distance_error_invalid_method ():
99
+ """ Test invalid method_distance"""
69
100
with pytest .raises (ValueError , match = "method_distance invalid*" ):
70
101
calculate_distance (
71
102
pd .DataFrame (), pd .DataFrame (), method_distance = "invalid_method_distance"
72
103
)
73
104
74
- # Test no horizontal coordinates"
105
+
106
+ def test_calculate_distance_error_no_coords ():
107
+ """Test no horizontal coordinates in input dataframe"""
75
108
test_features = pd .DataFrame (
76
109
{
77
110
"feature" : [1 , 2 ],
@@ -86,7 +119,9 @@ def test_calculate_distance_errors():
86
119
with pytest .raises (ValueError ):
87
120
calculate_distance (test_features .iloc [0 ], test_features .iloc [1 ])
88
121
89
- # Test dataframes with mismatching coordinates:
122
+
123
+ def test_calculate_distance_error_mismatched_coords ():
124
+ """Test dataframes with mismatching coordinates"""
90
125
with pytest .raises (ValueError , match = "Discovered coordinates*" ):
91
126
calculate_distance (
92
127
pd .DataFrame (
@@ -109,7 +144,9 @@ def test_calculate_distance_errors():
109
144
),
110
145
)
111
146
112
- # Test invalid method:
147
+
148
+ def test_calculate_distance_error_no_method ():
149
+ """Test hdim1_coord/hdim2_coord specified but no method_distance"""
113
150
test_features = pd .DataFrame (
114
151
{
115
152
"feature" : [1 , 2 ],
@@ -122,30 +159,31 @@ def test_calculate_distance_errors():
122
159
"projection_y_coordinate" : [0 , 0 ],
123
160
}
124
161
)
125
- with pytest .raises (ValueError ):
126
- calculate_distance (
127
- test_features .iloc [0 ],
128
- test_features .iloc [1 ],
129
- method_distance = "invalid_method" ,
130
- )
131
162
132
- # Test hdim1_coord/hdim2_coord specified but no method_distance
133
- with pytest .raises (ValueError ):
163
+ with pytest .raises (ValueError , match = "method_distance parameter must*" ):
134
164
calculate_distance (
135
165
test_features .iloc [0 ],
136
166
test_features .iloc [1 ],
137
167
hdim1_coord = "projection_y_coordinate" ,
138
168
)
139
169
140
- with pytest .raises (ValueError ):
170
+ with pytest .raises (ValueError , match = "method_distance parameter must*" ):
141
171
calculate_distance (
142
172
test_features .iloc [0 ],
143
173
test_features .iloc [1 ],
144
174
hdim2_coord = "projection_x_coordinate" ,
145
175
)
146
176
147
177
148
- def test_calculate_velocity_individual_xy ():
178
+ @pytest .mark .parametrize (
179
+ "x_coord, y_coord" ,
180
+ [("x" , "y" ), ("projection_x_coordinate" , "projection_y_coordinate" )],
181
+ )
182
+ def test_calculate_velocity_individual_xy (x_coord , y_coord ):
183
+ """
184
+ Test calculate_velocity_individual gives the correct result for a single
185
+ track woth different x/y coordinate names
186
+ """
149
187
test_features = pd .DataFrame (
150
188
{
151
189
"feature" : [1 , 2 ],
@@ -154,8 +192,8 @@ def test_calculate_velocity_individual_xy():
154
192
datetime (2000 , 1 , 1 , 0 , 0 ),
155
193
datetime (2000 , 1 , 1 , 0 , 10 ),
156
194
],
157
- "projection_x_coordinate" : [0 , 6000 ],
158
- "projection_y_coordinate" : [0 , 0 ],
195
+ x_coord : [0 , 6000 ],
196
+ y_coord : [0 , 0 ],
159
197
}
160
198
)
161
199
@@ -164,29 +202,40 @@ def test_calculate_velocity_individual_xy():
164
202
== 10
165
203
)
166
204
205
+
206
+ @pytest .mark .parametrize (
207
+ "lat_coord, lon_coord" , [("lat" , "lon" ), ("latitude" , "longitude" )]
208
+ )
209
+ def test_calculate_velocity_individual_latlon (lat_coord , lon_coord ):
210
+ """
211
+ Test calculate_velocity_individual gives the correct result for a single
212
+ track woth different lat/lon coordinate names
213
+ """
167
214
test_features = pd .DataFrame (
168
215
{
169
216
"feature" : [1 , 2 ],
170
- "frame" : [0 , 1 ],
217
+ "frame" : [0 , 0 ],
171
218
"time" : [
172
219
datetime (2000 , 1 , 1 , 0 , 0 ),
173
220
datetime (2000 , 1 , 1 , 0 , 10 ),
174
221
],
175
- "x" : [0 , 6000 ],
176
- "y" : [0 , 0 ],
222
+ lon_coord : [0 , 1 ],
223
+ lat_coord : [0 , 0 ],
177
224
}
178
225
)
179
226
180
- assert (
181
- calculate_velocity_individual (test_features .iloc [0 ], test_features .iloc [1 ])
182
- == 10
183
- )
227
+ assert calculate_velocity_individual (
228
+ test_features .iloc [0 ], test_features .iloc [1 ]
229
+ ) == pytest .approx (1.11e5 / 600 , rel = 1e2 )
184
230
185
231
186
232
@pytest .mark .parametrize (
187
233
"time_format" , ("datetime" , "datetime64" , "proleptic_gregorian" , "360_day" )
188
234
)
189
235
def test_calculate_velocity (time_format ):
236
+ """
237
+ Test velocity calculation using different time formats
238
+ """
190
239
test_features = pd .DataFrame (
191
240
{
192
241
"feature" : [1 , 2 , 3 , 4 ],
0 commit comments