Data analysis
grid_catalogue(x, y, z, w=None, xlim=None, ylim=None, zlim=None, nx=None, ny=None, nz=None)
Bin a catalogue of 3D positions onto a regular grid.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
x, |
y, z (array_like |
3D positions of objects. |
required |
w |
array_like |
Weight assigned to each object. Can be |
None |
xlim, |
ylim, zlim (tuple |
Tuples of the minimum and maximum coordinate values of the grid in
each dimension, e.g. |
required |
nx, |
ny, nz (int |
Number of grid cells in each direction. |
required |
Source code in fastbox/analysis.py
def grid_catalogue(
x, y, z, w=None, xlim=None, ylim=None, zlim=None, nx=None, ny=None, nz=None
):
"""
Bin a catalogue of 3D positions onto a regular grid.
Parameters:
x, y, z (array_like):
3D positions of objects.
w (array_like):
Weight assigned to each object. Can be `None`.
xlim, ylim, zlim (tuple):
Tuples of the minimum and maximum coordinate values of the grid in
each dimension, e.g. `(xmin, xmax)`. If not specified, the ranges
of the data will be used.
nx, ny, nz (int):
Number of grid cells in each direction.
"""
assert (
(nx is not None) and (ny is not None) and (nz is not None)
), "nx, ny, and nz must be specified."
# Get ranges
if xlim is None:
xlim = (np.min(x), np.max(x))
if ylim is None:
ylim = (np.min(y), np.max(y))
if zlim is None:
zlim = (np.min(z), np.max(z))
xmin, xmax = xlim
ymin, ymax = ylim
zmin, zmax = zlim
# Define grid
xgrid = np.linspace(xmin, xmax, nx) # bin centres
ygrid = np.linspace(ymin, ymax, ny)
zgrid = np.linspace(zmin, zmax, nz)
# Grid catalogue
grid, _ = np.histogramdd(
np.vstack([x, y, z]).T,
bins=(nx, ny, nz),
range=[(xmin, xmax), (ymin, ymax), (zmin, zmax)],
weights=w,
)
return grid, (xgrid, ygrid, zgrid)
interpolate_onto_grid(field, coords_orig, coords_new)
Interpolate a 3D field onto a grid with a different pixel/channel spacing.
NOTE: The input set of coordinates should be in ascending order.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
field |
array_like |
3D array of data. |
required |
coords_orig |
tuple |
Tuple of coordinates of the original grid, in the order (x, y, z), corresponding to field axes (0, 1, 2). |
required |
coords_new |
tuple |
Tuple of coordinates of the new grid, in the order (x, y, z), corresponding to field axes (0, 1, 2). |
required |
Returns:
Type | Description |
---|---|
field_new (array_like) |
3D array of data interpolated onto new grid shape. |
Source code in fastbox/analysis.py
def interpolate_onto_grid(field, coords_orig, coords_new):
"""
Interpolate a 3D field onto a grid with a different pixel/channel spacing.
NOTE: The input set of coordinates should be in ascending order.
Parameters:
field (array_like):
3D array of data.
coords_orig (tuple):
Tuple of coordinates of the original grid, in the order (x, y, z),
corresponding to field axes (0, 1, 2).
coords_new (tuple):
Tuple of coordinates of the new grid, in the order (x, y, z),
corresponding to field axes (0, 1, 2).
Returns:
field_new (array_like):
3D array of data interpolated onto new grid shape.
"""
# Extract original and new coordinates
x, y, z = coords_orig
x_new, y_new, z_new = coords_new
# Replace NaN values in data
field_nonan = replace_nan_with_channel_mean(field)
# Construct interpolator for data
# (Each array in coords_orig has to be ascending order)
interp = scipy.interpolate.RegularGridInterpolator(
(x, y, z), field_nonan, method="linear", bounds_error=False, fill_value=np.nan
)
# Build new grid with chosen resolution
x3d, y3d, z3d = np.meshgrid(x_new, y_new, z_new)
pts = np.array([x3d.flatten(), y3d.flatten(), z3d.flatten()])
# Interpolate onto new fine grid
field_new = interp(pts.T).reshape(x3d.shape)
return field_new
replace_nan_with_channel_mean(field)
Replace NaN values in a datacube with the mean of the non-NaN values in each channel (frequency slice).
Parameters:
Name | Type | Description | Default |
---|---|---|---|
field |
array_like |
3D datacube. The -1 axis will be assumed to be the frequency direction. |
required |
Returns:
Type | Description |
---|---|
field_replaced (array_like) |
3D datacube with NaN values replaced. |
Source code in fastbox/analysis.py
def replace_nan_with_channel_mean(field):
"""
Replace NaN values in a datacube with the mean of the non-NaN values in
each channel (frequency slice).
Parameters:
field (array_like):
3D datacube. The -1 axis will be assumed to be the frequency
direction.
Returns:
field_replaced (array_like):
3D datacube with NaN values replaced.
"""
# Work on a copy
field_repl = field.copy().reshape((-1, field.shape[-1]))
# Loop over frequency channels
for j in range(field_repl.shape[-1]):
idxs = np.isnan(field_repl[:, j]) # idxs of NaN values
avg = np.mean(field_repl[~idxs, j])
field_repl[idxs, j] = avg
return field_repl.reshape(field.shape)