Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated val2idx to fix bounds warning #134

Merged
merged 2 commits into from
Sep 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 33 additions & 27 deletions src/PseudoNetCDF/core/_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,26 +557,28 @@ def val2idx(
raise ValueError(
'val2idx is only implemented for 1-D coordinate variables'
)
if method == 'bounds':
bounds_keys = [dim + '_bounds', dim + '_bnds']
if hasattr(dimv, 'bounds'):
bounds_keys.insert(0, dimv.bounds)

for dimbk in bounds_keys:
if dimbk not in self.variables:
continue
dimbv = self.variables[dimbk]
if dimbv.ndim == 1:
dimevals = dimbv[:]
elif dimbv.ndim == 2 and dimbv.shape[1] == 2:
dimevals = np.append(dimbv[:, 0], dimbv[-1, 1])
else:
raise ValueError(
'val2idx is only implemented for 1-D or 2-D bounds' +
'; {} has {}'.format(dimbk, dimbv.shape)
)
break
bounds_keys = [dim + '_bounds', dim + '_bnds']
if hasattr(dimv, 'bounds'):
bounds_keys.insert(0, dimv.bounds)

dimevals = dimvals
for dimbk in bounds_keys:
if dimbk not in self.variables:
continue
dimbv = self.variables[dimbk]
if dimbv.ndim == 1:
dimevals = dimbv[:]
elif dimbv.ndim == 2 and dimbv.shape[1] == 2:
dimevals = np.append(dimbv[:, 0], dimbv[-1, 1])
else:
raise ValueError(
'val2idx is only implemented for 1-D or 2-D bounds' +
'; {} has {}'.format(dimbk, dimbv.shape)
)
break
else:
if method == 'bounds':
warn('Approximating bounds for val2idx {}'.format(dim))
dval = np.diff(dimvals) / 2
start = dimvals[:1]
Expand All @@ -590,10 +592,11 @@ def val2idx(
dimvals[1:] - dval,
end
])
else:
dimevals = dimvals

idx = np.arange(dimevals.size)
if method == 'bounds':
idx = np.arange(dimevals.size)
else:
idx = np.arange(dimvals.size)
ddimevals = np.diff(dimevals)

if (ddimevals < 0).all():
Expand All @@ -607,10 +610,12 @@ def val2idx(
# import pdb; pdb.set_trace()
# left = dimevals[0] - 1
# right = dimevals[-1] + 1
fidx = np.interp(val, dimevals, idx, left=left, right=right)
if method == 'bounds':
fidx = np.interp(val, dimevals, idx, left=left, right=right)
if right is None or right == dimevals[-1]:
fidx = np.minimum(fidx, dimvals.size - 1)
else:
fidx = np.interp(val, dimvals, idx, left=left, right=right)

if method == 'exact':
fidx = np.ma.masked_where(~np.in1d(val, dimvals), fidx)
Expand All @@ -624,11 +629,12 @@ def val2idx(
isleft = val < dimevals[0]
isright = val > dimevals[-1]
isout = isleft | isright
outmesg = 'Values are out of bounds:\n{}'.format(val[isout])
if bounds == 'warn':
warn(outmesg)
elif bounds == 'error':
raise ValueError(bounds)
if isout.any():
outmesg = 'Values are out of bounds:\n{}'.format(val[isout])
if bounds == 'warn':
warn(outmesg)
elif bounds == 'error':
raise ValueError(outmesg)

if method == 'nearest':
outidx = np.round(outfidx, 0).astype('i')
Expand Down
25 changes: 25 additions & 0 deletions src/PseudoNetCDF/test/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,31 @@ def _makencf(self):
22.748563023301763, 22.748560872681754]]]
return tncf

def testVal2idxBounds(self):
lon = np.linspace(-179.5, 179.5, 360)
f = PseudoNetCDFFile.from_arrays(
lon=lon, dims=('lon',), attrs=dict(bounds='lon_bounds')
)
with self.assertRaises(ValueError):
f.val2idx('lon', -179.9, bounds='error')

with self.assertRaises(ValueError):
f.val2idx('lon', 179.9, bounds='error')

iidx = f.val2idx('lon', -179.9, bounds='ignore')
assert (iidx == 0)
f.createVariable(
'lon_bounds', 'd', ('lon', 'nv'),
values=np.array([lon - 0.5, lon + 0.5]).T
)
iidx = f.val2idx('lon', -179.9, bounds='error')
assert (iidx == 0)
f.createVariable(
'lon_bounds', 'd', ('lonedges'), values=np.linspace(-180, 180, 361)
)
iidx = f.val2idx('lon', -179.9, bounds='error')
assert (iidx == 0)

def testVal2idx(self):
ncf = PseudoNetCDFFile()
coorde = np.arange(9, dtype='f')
Expand Down