Replies: 3 comments 1 reply
-
Hello @tomchor , unfortunately, I don`t quite understand your example: You draw values from a normal distribution, therefore you will never get exactly zero? Let`s assume you want to set all regions around sufficiently close-to-zero values to zero as well. (Do I understand this correctly?) import numpy as np
import xarray as xr
np.random.seed(123)
x = np.logspace(0, 2, 30)
y = np.linspace(0, 100, 30)
da = xr.DataArray(np.random.randn(30, 30), dims=["x", "y"], coords=dict(x=x, y=y))
da_near_zero=da.where(abs(da)<0.01)
da_zero=da_near_zero*0
da_zero.plot() If the region size is just a fixed number of grid cells, you could probably use a rolling maximum to expand the non-nan regions in da_zero at this point. However, if you have a irregular grid and the region size is defined based on coordinates, things are more difficult. The interpolate_na() function in xarray has a from xarray.core.missing import _get_gap_masks
#%% X direction
limit_mask,_,_=_get_gap_masks(da_zero, 'x', limit=20, limit_use_coordinate=True)
zero_exanded=xr.zeros_like(da).where(limit_mask)
zero_exanded.plot()
# %% Y direction
limit_mask,_,_=_get_gap_masks(zero_exanded, 'y', limit=20, limit_use_coordinate=True)
zero_exanded=xr.zeros_like(da).where(limit_mask)
zero_exanded.plot()
# %%
result=xr.where(zero_exanded==0, 0, da)
result.plot() Best, |
Beta Was this translation helpful? Give feedback.
-
Thanks @tomchor for the interesting problem. Agreed, would be great to clarify if you 1. have a single continuous 'zero' region and 2. have irregular coordinate spacing in different dimensions and 3. do in face have >2D datasets
Just want to add that this sounds like a 'dilation' or 'buffer' methods for vector geometries which take into consideration CRS and therefore distance, but as far as I know only work for the 2D case. Scipy also has https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.binary_dilation.html but not sure about making this aware of irregular grid spacing (perhaps what @Ockenfuss has implemented is the way forward for something like this!) |
Beta Was this translation helpful? Give feedback.
-
I actually came up with an algorithm that does what I described in 2D but unfortunately it doesn't generalize super well (I think). Basically it identifies the borders in a given dimension (by Here's a snippet of my code (the snippet by itself is non-working). The DataArray x_boundary_locations = ds.xC.where(ds.land_mask.astype(float).diff("xC")).max("xC")
x_boundary_locations = x_boundary_locations.where(np.isfinite(x_boundary_locations), other=400)
x_squared_distances = (ds.xC - x_boundary_locations)**2
squared_distances.append(x_squared_distances)
y_boundary_locations_north = ds.yC.where(ds.land_mask.astype(float).diff("yC")).max("yC")
y_boundary_locations_north = y_boundary_locations_north.where(np.isfinite(y_boundary_locations_north), other=0)
y_boundary_locations_south = ds.yC.where(ds.land_mask.astype(float).diff("yC")).min("yC")
y_boundary_locations_south = y_boundary_locations_south.where(np.isfinite(y_boundary_locations_south), other=0)
y_squared_distances = np.sqrt(xr.concat([(ds.yC - y_boundary_locations_south)**2, (ds.yC - y_boundary_locations_north)**2], dim="aux").min("aux"))
squared_distances.append(y_squared_distances)
ds["distance_from_boundary"] = np.sqrt(xr.concat(squared_distances, dim="aux").sum("aux")).where(ds.water_mask, other=0)
ds["distance_from_boundary"] = xr.concat([np.sqrt(x_squared_distances), ds.distance_from_boundary], dim="aux").min("aux").where(ds.water_mask, other=0) it seems to work okay. Here's my region expanding as you go left (I also included the distance from the left boundary in the expansion): |
Beta Was this translation helpful? Give feedback.
-
I'd like to create a mask based on distance from points in given DataArray that have a specific value.
To clarify: consider the example below where I create a random DataArray on an irregularly-spaced
x
direction and then set all the values betweenx=40
andx=60
to 0:I'd like to create a mask or something to eventually zero out all values at a distance (say 20 units) from any exactly-zero values here. Since I know that zero values appear between
[40, 60]
I know I can just set everything to zero between[20, 80]
in this particular MWE.But assuming I don't know where the zero values are, what's a good way to do this?
The way I've been doing this is by doing a convolution kernel with the distance I want (re-utilizing the code from here) but as the directions get larger, the convolution starts getting really expensive. I'm positive there's a better way to do this but I haven't been able to find it 😬.
Thanks in advance!
PS: this needs to work in n-dimentional DataArrays! So in a way I guess my MWE is kinda misleading since this is a much easier problem in 1D...
Here's an equivalent MWE but in 2D that's more similar to my actual situation:
Beta Was this translation helpful? Give feedback.
All reactions