rainfallqc 0.2.2__tar.gz → 0.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/PKG-INFO +1 -1
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/pyproject.toml +1 -1
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/__init__.py +1 -1
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/checks/neighbourhood_checks.py +25 -12
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/core/all_qc_checks.py +10 -5
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/utils/spatial_utils.py +11 -8
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/LICENSE +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/README.rst +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/checks/__init__.py +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/checks/comparison_checks.py +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/checks/gauge_checks.py +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/checks/pypwsqc_filters.py +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/checks/timeseries_checks.py +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/core/__init__.py +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/data/ETCCDI/RawData_HADEX2_CDD_1951-2010_ANN_from-90to90_from-180to180.nc +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/data/ETCCDI/RawData_HADEX2_CWD_1951-2010_ANN_from-90to90_from-180to180.nc +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/data/ETCCDI/RawData_HADEX2_PRCPTOT_1951-2010_ANN_from-90to90_from-180to180.nc +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/data/ETCCDI/RawData_HADEX2_R99p_1951-2010_ANN_from-90to90_from-180to180.nc +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/data/ETCCDI/RawData_HADEX2_Rx1day_1951-2010_ANN_from-90to90_from-180to180.nc +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/data/ETCCDI/RawData_HADEX2_SDII_1951-2010_ANN_from-90to90_from-180to180.nc +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/data/ETCCDI/__init__.py +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/data/__init__.py +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/qc_frameworks/__init__.py +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/qc_frameworks/apply_qc_framework.py +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/qc_frameworks/inbuilt_qc_frameworks.py +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/utils/__init__.py +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/utils/data_readers.py +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/utils/data_utils.py +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/utils/neighbourhood_utils.py +0 -0
- {rainfallqc-0.2.2 → rainfallqc-0.2.4}/src/rainfallqc/utils/stats.py +0 -0
|
@@ -68,7 +68,7 @@ homepage = "https://github.com/thomasjkeel/RainfallQC"
|
|
|
68
68
|
target-version = ["py310", "py311", "py312", "py313"]
|
|
69
69
|
|
|
70
70
|
[tool.bumpversion]
|
|
71
|
-
current_version = "0.2.
|
|
71
|
+
current_version = "0.2.4"
|
|
72
72
|
commit = true
|
|
73
73
|
message = "Bump version: {current_version} → {new_version}"
|
|
74
74
|
commit_args = ""
|
|
@@ -80,11 +80,17 @@ def check_wet_neighbours(
|
|
|
80
80
|
)
|
|
81
81
|
|
|
82
82
|
# 2. Loop through each neighbour and get wet_flags
|
|
83
|
-
|
|
83
|
+
neighbouring_gauge_cols_iterable = neighbouring_gauge_cols_new.copy() # make copy again to allow removal in loop
|
|
84
|
+
for neighbouring_gauge_col in neighbouring_gauge_cols_iterable:
|
|
84
85
|
# 2.1 Flag data based on comparison of wet values in neighbours
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
try:
|
|
87
|
+
one_neighbour_data_wet_flags = flag_wet_day_errors_based_on_neighbours(
|
|
88
|
+
neighbour_data, target_gauge_col, neighbouring_gauge_col, wet_threshold
|
|
89
|
+
)
|
|
90
|
+
except ValueError as ve:
|
|
91
|
+
neighbouring_gauge_cols_new.remove(neighbouring_gauge_col)
|
|
92
|
+
print(f"Warning: removing '{neighbouring_gauge_col}' from neighbouring_gauge_cols because: {ve}")
|
|
93
|
+
continue
|
|
88
94
|
|
|
89
95
|
# 2.2 Join to all data
|
|
90
96
|
neighbour_data = neighbour_data.join(
|
|
@@ -197,15 +203,21 @@ def check_dry_neighbours(
|
|
|
197
203
|
neighbour_data, rain_cols=rain_cols, hour_offset=hour_offset
|
|
198
204
|
)
|
|
199
205
|
|
|
200
|
-
# 3. Loop through each neighbour and get
|
|
201
|
-
|
|
206
|
+
# 3. Loop through each neighbour and get dry_flags
|
|
207
|
+
neighbouring_gauge_cols_iterable = neighbouring_gauge_cols_new.copy() # make copy again to allow removal in loop
|
|
208
|
+
for neighbouring_gauge_col in neighbouring_gauge_cols_iterable:
|
|
202
209
|
# 3.1 Convert to dry spell fraction
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
210
|
+
try:
|
|
211
|
+
one_neighbour_data = get_dry_spell_fraction_col(
|
|
212
|
+
neighbour_data,
|
|
213
|
+
target_gauge_col=target_gauge_col,
|
|
214
|
+
dry_period_days=dry_period_days,
|
|
215
|
+
neighbouring_gauge_col=neighbouring_gauge_col,
|
|
216
|
+
)
|
|
217
|
+
except ValueError as ve:
|
|
218
|
+
neighbouring_gauge_cols_new.remove(neighbouring_gauge_col)
|
|
219
|
+
print(f"Warning: {ve}. Removing {neighbouring_gauge_col} from neighbouring_gauge_cols.")
|
|
220
|
+
continue
|
|
209
221
|
|
|
210
222
|
# 3.2 Flag dry spell fractions
|
|
211
223
|
one_neighbour_data_dry_flags = flag_dry_spell_fractions(
|
|
@@ -1092,6 +1104,7 @@ def flag_wet_day_errors_based_on_neighbours(
|
|
|
1092
1104
|
expon_percentiles = stats.fit_expon_and_get_percentile(
|
|
1093
1105
|
neighbour_data_filtered_diff[f"diff_{neighbouring_gauge_col}"], percentiles=[0.95, 0.99, 0.999]
|
|
1094
1106
|
)
|
|
1107
|
+
|
|
1095
1108
|
# 5. Assign flags
|
|
1096
1109
|
all_neighbour_data_wet_flags = add_wet_flags_to_data(
|
|
1097
1110
|
neighbour_data_diff, target_gauge_col, neighbouring_gauge_col, expon_percentiles, wet_threshold
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"""Registry of all the QC checks in RainfallQC."""
|
|
3
3
|
|
|
4
4
|
import functools
|
|
5
|
+
import inspect
|
|
5
6
|
import itertools
|
|
6
7
|
|
|
7
8
|
import polars as pl
|
|
@@ -37,16 +38,20 @@ def qc_check(name: str, require_non_negative: bool = False) -> callable:
|
|
|
37
38
|
def decorator(func: callable) -> callable:
|
|
38
39
|
@functools.wraps(func)
|
|
39
40
|
def wrapper(df: pl.DataFrame, *args, **kwargs) -> list:
|
|
40
|
-
#
|
|
41
|
+
# Bind args/kwargs to signature to include defaults
|
|
42
|
+
bound = inspect.signature(func).bind_partial(df, *args, **kwargs)
|
|
43
|
+
bound.apply_defaults()
|
|
44
|
+
full_kwargs = bound.arguments # dict including defaults
|
|
45
|
+
|
|
41
46
|
columns_to_check = []
|
|
42
47
|
columns_to_check = get_columns_in_kwargs(
|
|
43
|
-
|
|
48
|
+
full_kwargs, kwarg_name="target_gauge_col", column_list=columns_to_check, name=name
|
|
44
49
|
)
|
|
45
50
|
|
|
46
51
|
for kwarg_name in ["neighbouring_gauge_col", "neighbouring_gauge_cols"]:
|
|
47
|
-
if kwarg_name in
|
|
52
|
+
if kwarg_name in full_kwargs:
|
|
48
53
|
columns_to_check = get_columns_in_kwargs(
|
|
49
|
-
|
|
54
|
+
full_kwargs, kwarg_name=kwarg_name, column_list=columns_to_check, name=name
|
|
50
55
|
)
|
|
51
56
|
|
|
52
57
|
# flatten column list for neighbouring_gauge_cols
|
|
@@ -93,6 +98,6 @@ def get_columns_in_kwargs(kwargs: dict, kwarg_name: str, column_list: list, name
|
|
|
93
98
|
col_name = kwargs.get(kwarg_name) # user defined column name for that kwarg
|
|
94
99
|
|
|
95
100
|
if col_name is None:
|
|
96
|
-
raise ValueError(f"{name} requires '{kwarg_name}' to be
|
|
101
|
+
raise ValueError(f"The QC check '{name}' requires the '{kwarg_name}' to be set.")
|
|
97
102
|
column_list.append(col_name)
|
|
98
103
|
return column_list
|
|
@@ -42,19 +42,19 @@ def compute_spatial_mean_xr(data: xr.Dataset, var_name: str) -> xr.Dataset:
|
|
|
42
42
|
return data
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
def haversine(lon1:
|
|
45
|
+
def haversine(lon1: xr.DataArray, lat1: xr.DataArray, lon2: np.ndarray | float, lat2: np.ndarray | float) -> float:
|
|
46
46
|
"""
|
|
47
47
|
Great circle distance (km) between two points on Earth.
|
|
48
48
|
|
|
49
49
|
Parameters
|
|
50
50
|
----------
|
|
51
|
-
lon1 :
|
|
51
|
+
lon1 : xr.DataArray
|
|
52
52
|
Longitude of point 1
|
|
53
|
-
lat1 :
|
|
53
|
+
lat1 : xr.DataArray
|
|
54
54
|
Latitude of point 1
|
|
55
|
-
lon2 : float
|
|
55
|
+
lon2 : np.ndarray | float
|
|
56
56
|
Longitude of point 2
|
|
57
|
-
lat2 : float
|
|
57
|
+
lat2 : np.ndarray | float
|
|
58
58
|
Latitude of point 2
|
|
59
59
|
|
|
60
60
|
Returns
|
|
@@ -63,10 +63,13 @@ def haversine(lon1: float, lat1: float, lon2: float, lat2: float) -> float:
|
|
|
63
63
|
Distance between the two points in km
|
|
64
64
|
|
|
65
65
|
"""
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
# convert lat2 and lon2 to numpy arrays for safety
|
|
67
|
+
lon2 = np.asarray(lon2, dtype=np.float64)
|
|
68
|
+
lat2 = np.asarray(lat2, dtype=np.float64)
|
|
69
|
+
|
|
70
|
+
lon1, lat1, lon2, lat2 = map(np.radians, [lon1, lat1, lon2, lat2])
|
|
68
71
|
dlon = lon2 - lon1
|
|
69
72
|
dlat = lat2 - lat1
|
|
70
73
|
a = np.sin(dlat / 2) ** 2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon / 2) ** 2
|
|
71
74
|
c = 2 * np.arcsin(np.sqrt(a))
|
|
72
|
-
return
|
|
75
|
+
return EARTH_RADIUS_KM * c
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|