Source code for pylablib.core.dataproc.interpolate

import numpy as np
import scipy.interpolate

from . import utils
from .table_wrap import wrap


def _data_range(data):
    return (np.min(data),np.max(data))

[docs] def interpolate1D_func(x, y, kind="linear", axis=-1, copy=True, bounds_error=True, fill_values=np.nan, assume_sorted=False): """ 1D interpolation. Simply a wrapper around :class:`scipy.interpolate.interp1d`. Args: x: 1D arrays of x coordinates for the points at which to find the values. y: array of values corresponding to x points (can have more than 1 dimension, in which case the output values are (N-1)-dimensional) kind: Interpolation method. axis: axis in y-data over which to interpolate. copy: if ``True``, make internal copies of `x` and `y`. bounds_error: if ``True``, raise error if interpolation function arguments are outside of `x` bounds. fill_values: values to fill the outside-bounds regions if ``bounds_error==False``. assume_sorted: if ``True``, assume that `data` is sorted. Returns: A 1D array with interpolated data. """ if fill_values=="bounds": fill_values=tuple(np.take(y,[x.argmin(),x.argmax()],axis=axis)) bounds_error=False return scipy.interpolate.interp1d(x,y,kind=kind,axis=axis,copy=copy,bounds_error=bounds_error,fill_value=fill_values,assume_sorted=assume_sorted)
[docs] def interpolate1D(data, x, kind="linear", bounds_error=True, fill_values=np.nan, assume_sorted=False): """ 1D interpolation. Args: data: 2-column array [(x,y)], where ``y`` is a function of ``x``. x: Arrays of x coordinates for the points at which to find the values. kind: Interpolation method. bounds_error: if ``True``, raise error if `x` values are outside of `data` bounds. fill_values: values to fill the outside-bounds regions if ``bounds_error==False`` assume_sorted: if ``True``, assume that `data` is sorted. Returns: A 1D array with interpolated data. """ return interpolate1D_func(data[:,0],data[:,1],kind=kind,bounds_error=bounds_error,fill_values=fill_values,assume_sorted=assume_sorted)(x)
[docs] def interpolate2D(data, x, y, method="linear", fill_value=np.nan): """ Interpolate data in 2D. Simply a wrapper around :func:`scipy.interpolate.griddata`. Args: data: 3-column array [(x,y,z)], where ``z`` is a function of ``x`` and ``y``. x/y: Arrays of x and y coordinates for the points at which to find the values. method: Interpolation method. Returns: A 2D array with interpolated data. """ interp_data=scipy.interpolate.griddata((data[:,0],data[:,1]),data[:,2],(x,y),method=method,fill_value=fill_value) return interp_data
[docs] def interpolateND(data, xs, method="linear"): """ Interpolate data in N dimensions. Simply a wrapper around :func:`scipy.interpolate.griddata`. Args: data: ``(N+1)``-column array ``[(x_1,..,x_N,y)]``, where ``y`` is a function of ``x_1, ... ,x_N``. xs: ``N``-tuple of arrays of coordinates for the points at which to find the values. method: Interpolation method. Returns: An ND array with interpolated data. """ coords=tuple([data[:,n] for n in range(data.shape[1]-1)]) interp_data=scipy.interpolate.griddata(coords,data[:,-1],xs,method=method) return interp_data
[docs] def regular_grid_from_scatter(data, x_points, y_points, x_range=None, y_range=None, method="nearest"): """ Turn irregular scatter-points data into a regular 2D grid function. Args: data: 3-column array ``[(x,y,z)]``, where ``z`` is a function of ``x`` and ``y``. x_points/y_points: Number of points along x/y axes. x_range/y_range: If not ``None``, a tuple specifying the desired range of the data (all points in `data` outside the range are excluded). method: Interpolation method (see :func:`scipy.interpolate.griddata` for options). Returns: A nested tuple ``(data, (x_grid, y_grid))``, where all entries are 2D arrays (either with data or with gridpoint locations). """ if x_range is not None: data=utils.cut_to_range(data,x_range,0) else: x_range=_data_range(data[:,0]) if y_range is not None: data=utils.cut_to_range(data,y_range,1) else: y_range=_data_range(data[:,1]) x_grid=np.linspace(x_range[0],x_range[1],x_points) y_grid=np.linspace(y_range[0],y_range[1],y_points) xi,yi=np.meshgrid(x_grid,y_grid) interp_data=scipy.interpolate.griddata((data[:,0],data[:,1]),data[:,2],(xi,yi),method=method) return interp_data,(x_grid,y_grid)
[docs] def interpolate_trace(trace, step, rng=None, x_column=0, select_columns=None, kind="linear", assume_sorted=False,): """ Interpolate trace data over a regular grid with the given step. `rng` specifies interpolation range (by default, whole data range). `x_column` specifies column index for x-data. `select_column` specifies which columns to interpolate and keep at the output (by default, all data). If ``assume_sorted==True``, assume that x-data is sorted. `kind` specifies interpolation method. """ wtrace=wrap(trace) src_column=utils.get_x_column(trace,x_column=x_column) select_columns=select_columns or list(range(wtrace.shape()[1])) rng_min,rng_max=rng or (None,None) rng_min=src_column.min() if (rng_min is None) else rng_min rng_max=src_column.max() if (rng_max is None) else rng_max start=(rng_min//step)*step stop=(rng_max//step)*step pts=np.arange(start,stop+step/2.,step) xidx=wtrace.c.get_column_index(x_column) columns=[ pts if wtrace.c.get_column_index(c)==xidx else interpolate1D_func(src_column,wtrace[:,c],kind=kind,bounds_error=False,fill_values="bounds",assume_sorted=assume_sorted)(pts) for c in select_columns] return wtrace.subtable((slice(None),select_columns),wrapped=True).columns_replaced(columns)
[docs] def average_interpolate_1D(data, step, rng=None, avg_kernel=1, min_weight=0, kind="linear"): """ 1D interpolation combined with pre-averaging. Args: data: 2-column array [(x,y)], where ``y`` is a function of ``x``. step: distance between the points in the interpolated data (all resulting x-coordinates are multiples of `step`). rng: if not ``None``, specifies interpolation range (by default, whole data range). avg_kernel: kernel used for initial averaging. Can be either a 1D array, where each point corresponds to the relative bin weight, or an integer, which specifies simple rectangular kernel of the given width. min_weight: minimal accumulated weight in the bin to consider it 'valid' (if the bin is invalid, its accumulated value is ignored, and its value is obtained by the interpolation step). `min_weight` of 0 implies any non-zero weight; otherwise, weight ``>=min_weight``. kind: Interpolation method. Returns: A 2-column array with the interpolated data. """ if isinstance(avg_kernel,(int,float)): avg_kernel=max(int(avg_kernel)//2,0)*2+1 avg_kernel=np.ones(avg_kernel) rng_min,rng_max=rng or (None,None) rng_min=data[:,0].min() if (rng_min is None) else rng_min rng_max=data[:,0].max() if (rng_max is None) else rng_max rng=(rng_min,rng_max) rng=[(l//step)*step for l in rng] bins=np.linspace(rng[0],rng[1],int((rng[1]-rng[0])/step)+1) locs=bins.searchsorted(data[:,0]) locs[locs==len(bins)]-=1 bindiffs=data[:,0]-bins[locs] locs[(locs>0)&(bindiffs<-step/2.)]-=1 sums=np.zeros((len(bins))) np.add.at(sums,locs,data[:,1]) weights=np.zeros((len(bins))) np.add.at(weights,locs,1) sums=np.convolve(sums,avg_kernel,mode="same") weights=np.convolve(weights,avg_kernel,mode="same") filled=weights>min_weight if min_weight==0 else weights>=min_weight intx=bins[filled] inty=sums[filled]/weights[filled] data=interpolate1D_func(intx,inty,kind=kind,bounds_error=False,fill_values="bounds",assume_sorted=True)(bins) return np.column_stack((bins,data))