Mathematical operationsο
[1]:
import numpy as np
import spectrochempy as scp
from spectrochempy import MASKED
from spectrochempy import DimensionalityError
from spectrochempy import error_
|
SpectroChemPy's API - v.0.8.2.dev7 Β©Copyright 2014-2025 - A.Travert & C.Fernandez @ LCS |
Running on GitHub Actions
MPL Configuration directory: /home/runner/.config/matplotlib
Stylelib directory: /home/runner/.config/matplotlib/stylelib
Ufuncs (Universal Numpyβs functions)ο
A universal function (or ufunc
in short) is a function that operates on numpy arrays in an element-by-element fashion, supporting array broadcasting, type casting, and several other standard features. That is, a ufunc
is a βvectorizedβ wrapper for a function that takes a fixed number of specific inputs and produces a fixed number of specific outputs.
For instance, in numpy to calculate the square root of each element of a given nd-array, we can write something like this using the np.sqrt
functions :
[2]:
x = np.array([1.0, 2.0, 3.0, 4.0, 6.0])
np.sqrt(x)
[2]:
array([1. , 1.41421356, 1.73205081, 2. , 2.44948974])
As seen above, np.sqrt(x)
return a numpy array.
The interesting thing, it that ufunc
βs can also work with NDDataset
.
[3]:
dx = scp.NDDataset(x)
np.sqrt(dx)
[3]:
NDDataset: [float64] unitless (size: 5)[NDDataset_98165d3b]
Summary
Data
List of UFuncs working on NDDataset
:ο
Functions affecting magnitudes of the number but keeping unitsο
negative(x, **kwargs): Numerical negative, element-wise.
absolute(x, **kwargs): Calculate the absolute value, element-wise. Alias: abs
fabs(x, **kwargs): Calculate the absolute value, element-wise. Complex values are not handled, use absolute to find the absolute values of complex data.
conj(x, **kwargs): Return the complex conjugate, element-wise.
rint(x, **kwargs) :Round to the nearest integer, element-wise.
floor(x, **kwargs): Return the floor of the input, element-wise.
ceil(x, **kwargs): Return the ceiling of the input, element-wise.
trunc(x, **kwargs): Return the truncated value of the input, element-wise.
Functions affecting magnitudes of the number but also unitsο
sqrt(x, **kwargs): Return the non-negative square-root of an array, element-wise.
square(x, **kwargs): Return the element-wise square of the input.
cbrt(x, **kwargs): Return the cube-root of an array, element-wise.
reciprocal(x, **kwargs): Return the reciprocal of the argument, element-wise.
Functions that require no units or dimensionless units for inputs. Returns dimensionless objects.ο
exp(x, **kwargs): Calculate the exponential of all elements in the input array.
exp2(x, kwargs): Calculate 2p for all p in the input array.
expm1(x, **kwargs): Calculate
exp(x) - 1
for all elements in the array.log(x, **kwargs): Natural logarithm, element-wise.
log2(x, **kwargs): Base-2 logarithm of x.
log10(x, **kwargs): Return the base 10 logarithm of the input array, element-wise.
log1p(x, **kwargs): Return
log(x + 1)
, element-wise.
Functions that return numpy arrays (Work only for NDDataset)ο
sign(x): Returns an element-wise indication of the sign of a number.
logical_not(x): Compute the truth value of NOT x element-wise.
isfinite(x): Test element-wise for finiteness.
isinf(x): Test element-wise for positive or negative infinity.
isnan(x): Test element-wise for
NaN
and return result as a boolean array.signbit(x): Returns element-wise
True
where signbit is set.
Trigonometric functions. Require unitless data or radian units.ο
sin(x, **kwargs): Trigonometric sine, element-wise.
cos(x, **kwargs): Trigonometric cosine element-wise.
tan(x, **kwargs): Compute tangent element-wise.
arcsin(x, **kwargs): Inverse sine, element-wise.
arccos(x, **kwargs): Trigonometric inverse cosine, element-wise.
arctan(x, **kwargs): Trigonometric inverse tangent, element-wise.
Hyperbolic functionsο
sinh(x, **kwargs): Hyperbolic sine, element-wise.
cosh(x, **kwargs): Hyperbolic cosine, element-wise.
tanh(x, **kwargs): Compute hyperbolic tangent element-wise.
arcsinh(x, **kwargs): Inverse hyperbolic sine element-wise.
arccosh(x, **kwargs): Inverse hyperbolic cosine, element-wise.
arctanh(x, **kwargs): Inverse hyperbolic tangent element-wise.
Unit conversionsο
Binary Ufuncsο
add(x1, x2, **kwargs): Add arguments element-wise.
subtract(x1, x2, **kwargs): Subtract arguments, element-wise.
multiply(x1, x2, **kwargs): Multiply arguments element-wise.
divide or true_divide(x1, x2, **kwargs): Returns a true division of the inputs, element-wise.
floor_divide(x1, x2, **kwargs): Return the largest integer smaller or equal to the division of the inputs.
Usageο
To demonstrate the use of mathematical operations on spectrochempy object, we will first load an experimental 2D dataset.
[4]:
d2D = scp.read_omnic("irdata/nh4y-activation.spg")
prefs = scp.preferences
prefs.colormap = "magma"
prefs.colorbar = False
prefs.figure.figsize = (6, 3)
d2D.plot()
[4]:

Letβs select only the first row of the 2D dataset ( the squeeze
method is used to remove the residual size 1 dimension). In addition, we mask the saturated region.
[5]:
dataset = d2D[0].squeeze()
dataset.plot()
[5]:

This dataset will be artificially modified already using some mathematical operation (subtraction with a scalar) to present negative values, and we will also mask some data
[6]:
dataset -= 2.0 # add an offset to make that some of the values become negative
dataset[1290.0:890.0] = scp.MASKED # additionally we mask some data
dataset.plot()
[6]:

Unary functionsο
Functions affecting magnitudes of the number but keeping unitsο
negativeο
Numerical negative, element-wise, keep units
[7]:
out = np.negative(dataset) # the same results is obtained using out=-dataset
out.plot(figsize=(6, 2.5), show_mask=True)
[7]:

absο
absolute (alias of abs)ο
fabs (absolute for float arrays)ο
Numerical absolute value element-wise, element-wise, keep units
[8]:
out = np.abs(dataset)
out.plot(figsize=(6, 2.5))
[8]:

rintο
Round elements of the array to the nearest integer, element-wise, keep units
[9]:
out = np.rint(dataset)
out.plot(figsize=(6, 2.5)) # not that title is not modified for this ufunc
[9]:

floorο
Return the floor of the input, element-wise.
[10]:
out = np.floor(dataset)
out.plot(figsize=(6, 2.5))
[10]:

ceilο
Return the ceiling of the input, element-wise.
[11]:
out = np.ceil(dataset)
out.plot(figsize=(6, 2.5))
[11]:

truncο
Return the truncated value of the input, element-wise.
[12]:
out = np.trunc(dataset)
out.plot(figsize=(6, 2.5))
[12]:

Functions affecting magnitudes of the number but also unitsο
sqrtο
Return the non-negative square-root of an array, element-wise.
[13]:
out = np.sqrt(
dataset
) # as they are some negative elements, return dataset has complex dtype.
out.plot_1D(show_complex=True, figsize=(6, 2.5))
WARNING | (UserWarning) Given trait value dtype "float64" does not match required type "float64". A coerced copy has been created.
[13]:

squareο
Return the element-wise square of the input.
[14]:
out = np.square(dataset)
out.plot(figsize=(6, 2.5))
[14]:

cbrtο
Return the cube-root of an array, element-wise.
[15]:
out = np.cbrt(dataset)
out.plot(figsize=(6, 2.5))
[15]:

reciprocalο
Return the reciprocal of the argument, element-wise.
[16]:
out = np.reciprocal(dataset + 3.0)
out.plot(figsize=(6, 2.5))
[16]:

Functions that require no units or dimensionless units for inputs. Returns dimensionless objects.ο
expο
Exponential of all elements in the input array, element-wise
[17]:
out = np.exp(dataset)
out.plot(figsize=(6, 2.5))
[17]:

Obviously numpy exponential functions applies only to dimensionless array. Else an error is generated.
[18]:
x = scp.NDDataset(np.arange(5), units="m")
try:
np.exp(x) # A dimensionality error will be generated
except DimensionalityError as e:
error_(DimensionalityError, e)
ERROR | DimensionalityError: Cannot convert from 'm' to ''
Function `exp` requires DIMENSIONLESS input
exp2ο
Calculate 2**p for all p in the input array.
[19]:
out = np.exp2(dataset)
out.plot(figsize=(6, 2.5))
[19]:

expm1ο
Calculate exp(x) - 1
for all elements in the array.
[20]:
out = np.expm1(dataset)
out.plot(figsize=(6, 2.5))
[20]:

logο
Natural logarithm, element-wise.
This doesnβt generate un error for negative numbrs, but the output is masked for those values
[21]:
out = np.log(dataset)
ax = out.plot(figsize=(6, 2.5), show_mask=True)
WARNING | (UserWarning) Given trait value dtype "float64" does not match required type "float64". A coerced copy has been created.

[22]:
out = np.log(dataset - dataset.min())
out.plot(figsize=(6, 2.5))
WARNING | (UserWarning) Given trait value dtype "float64" does not match required type "float64". A coerced copy has been created.
[22]:

log2ο
Base-2 logarithm of x.
[23]:
out = np.log2(dataset)
out.plot(figsize=(6, 2.5))
WARNING | (UserWarning) Given trait value dtype "float64" does not match required type "float64". A coerced copy has been created.
[23]:

log10ο
Return the base 10 logarithm of the input array, element-wise.
[24]:
out = np.log10(dataset)
out.plot(figsize=(6, 2.5))
WARNING | (UserWarning) Given trait value dtype "float64" does not match required type "float64". A coerced copy has been created.
[24]:

log1pο
Return log(x + 1)
, element-wise.
[25]:
out = np.log1p(dataset)
out.plot(figsize=(6, 2.5))
WARNING | (UserWarning) Given trait value dtype "float64" does not match required type "float64". A coerced copy has been created.
[25]:

Functions that return numpy arrays (Work only for NDDataset)ο
signο
Returns an element-wise indication of the sign of a number. Returned object is a ndarray
[26]:
np.sign(dataset)
[26]:
masked_array(data=[ 1, 1, ..., 1, 1],
mask=[ False, False, ..., False, False],
fill_value=1e+20)
logical_notο
Compute the truth value of NOT x element-wise. Returned object is a ndarray
[27]:
np.logical_not(dataset < 0)
[27]:
masked_array(data=[ 1, 1, ..., 1, 1],
mask=[ False, False, ..., False, False],
fill_value=True)
isfiniteο
Test element-wise for finiteness.
[28]:
np.isfinite(dataset)
[28]:
masked_array(data=[ 1, 1, ..., 1, 1],
mask=[ False, False, ..., False, False],
fill_value=True)
isinfο
Test element-wise for positive or negative infinity.
[29]:
np.isinf(dataset)
[29]:
masked_array(data=[ 0, 0, ..., 0, 0],
mask=[ False, False, ..., False, False],
fill_value=True)
isnanο
Test element-wise for NaN
and return result as a boolean array.
[30]:
np.isnan(dataset)
[30]:
masked_array(data=[ 0, 0, ..., 0, 0],
mask=[ False, False, ..., False, False],
fill_value=True)
signbitο
Returns element-wise True
where signbit is set.
[31]:
np.signbit(dataset)
[31]:
masked_array(data=[ 0, 0, ..., 0, 0],
mask=[ False, False, ..., False, False],
fill_value=True)
Trigonometric functions. Require dimensionless/unitless dataset or radians.ο
In the below examples, unit of data in dataset is absorbance (then dimensionless)
sinο
Trigonometric sine, element-wise.
[32]:
out = np.sin(dataset)
out.plot(figsize=(6, 2.5))
[32]:

cosο
Trigonometric cosine element-wise.
[33]:
out = np.cos(dataset)
out.plot(figsize=(6, 2.5))
[33]:

tanο
Compute tangent element-wise.
[34]:
out = np.tan(dataset / np.max(dataset))
out.plot(figsize=(6, 2.5))
[34]:

arcsinο
Inverse sine, element-wise.
[35]:
out = np.arcsin(dataset)
out.plot(figsize=(6, 2.5))
WARNING | (RuntimeWarning) invalid value encountered in arcsin
WARNING | (UserWarning) Given trait value dtype "float64" does not match required type "float64". A coerced copy has been created.
[35]:

arccosο
Trigonometric inverse cosine, element-wise.
[36]:
out = np.arccos(dataset)
out.plot(figsize=(6, 2.5))
WARNING | (RuntimeWarning) invalid value encountered in arccos
WARNING | (UserWarning) Given trait value dtype "float64" does not match required type "float64". A coerced copy has been created.
[36]:

arctanο
Trigonometric inverse tangent, element-wise.
[37]:
out = np.arctan(dataset)
out.plot(figsize=(6, 2.5))
[37]:

Angle units conversionο
rad2degο
Convert angles from radians to degrees (warning: unitless or dimensionless are assumed to be radians, so no error will be issued).
for instance, if we take the z axis (the data magnitude) in the figure above, itβs expressed in radians. We can change to degrees easily.
[38]:
out = np.rad2deg(dataset)
out.title = "data" # just to avoid a too long title
out.plot(figsize=(6, 2.5))
[38]:

deg2radο
Convert angles from degrees to radians.
[39]:
out = np.deg2rad(out)
out.title = "data"
out.plot(figsize=(6, 2.5))
[39]:

Hyperbolic functionsο
sinhο
Hyperbolic sine, element-wise.
[40]:
out = np.sinh(dataset)
out.plot(figsize=(6, 2.5))
[40]:

coshο
Hyperbolic cosine, element-wise.
[41]:
out = np.cosh(dataset)
out.plot(figsize=(6, 2.5))
[41]:

tanhο
Compute hyperbolic tangent element-wise.
[42]:
out = np.tanh(dataset)
out.plot(figsize=(6, 2.5))
[42]:

arcsinhο
Inverse hyperbolic sine element-wise.
[43]:
out = np.arcsinh(dataset)
out.plot(figsize=(6, 2.5))
[43]:

arccoshο
Inverse hyperbolic cosine, element-wise.
[44]:
out = np.arccosh(dataset)
out.plot(figsize=(6, 2.5))
WARNING | (UserWarning) Given trait value dtype "float64" does not match required type "float64". A coerced copy has been created.
[44]:

arctanhο
Inverse hyperbolic tangent element-wise.
[45]:
out = np.arctanh(dataset)
out.plot(figsize=(6, 2.5))
WARNING | (RuntimeWarning) invalid value encountered in arctanh
WARNING | (UserWarning) Given trait value dtype "float64" does not match required type "float64". A coerced copy has been created.
[45]:

Binary functionsο
[46]:
dataset2 = np.reciprocal(dataset + 3) # create a second dataset
dataset2[5000.0:4000.0] = MASKED
dataset.plot(figsize=(6, 2.5))
dataset2.plot(figsize=(6, 2.5))
[46]:


Arithmeticο
addο
Add arguments element-wise.
[47]:
out = np.add(dataset, dataset2)
out.plot(figsize=(6, 2.5))
[47]:

subtractο
Subtract arguments, element-wise.
[48]:
out = np.subtract(dataset, dataset2)
out.plot(figsize=(6, 2.5))
[48]:

multiplyο
Multiply arguments element-wise.
[49]:
out = np.multiply(dataset, dataset2)
out.plot(figsize=(6, 2.5))
[49]:

divideο
or ##### true_divide Returns a true division of the inputs, element-wise.
[50]:
out = np.divide(dataset, dataset2)
out.plot(figsize=(6, 2.5))
[50]:

floor_divideο
Return the largest integer smaller or equal to the division of the inputs.
[51]:
out = np.floor_divide(dataset, dataset2)
out.plot(figsize=(6, 2.5))
[51]:

Complex or hypercomplex NDDatasetsο
NDDataset objects with complex data are handled differently than in numpy.ndarray
.
Instead, complex data are stored by interlacing the real and imaginary part. This allows the definition of data that can be complex in several axis, and e .g., allows 2D-hypercomplex array that can be transposed (useful for NMR data).
[52]:
da = scp.NDDataset(
[
[1.0 + 2.0j, 2.0 + 0j],
[1.3 + 2.0j, 2.0 + 0.5j],
[1.0 + 4.2j, 2.0 + 3j],
[5.0 + 4.2j, 2.0 + 3j],
]
)
da
[52]:
NDDataset: [complex128] unitless (shape: (y:4, x:2))[NDDataset_9d697806]
Summary
Data
[ 1.3 2]
[ 1 2]
[ 5 2]]
I[[ 2 0]
[ 2 0.5]
[ 4.2 3]
[ 4.2 3]]
A dataset of type float can be transformed into a complex dataset (using two consecutive rows to create a complex row)
[53]:
da = scp.NDDataset(np.arange(40).reshape(10, 4))
da
[53]:
NDDataset: [float64] unitless (shape: (y:10, x:4))[NDDataset_9d697809]
Summary
Data
[ 4 5 6 7]
...
[ 32 33 34 35]
[ 36 37 38 39]]
[54]:
dac = da.set_complex()
dac
[54]:
NDDataset: [complex128] unitless (shape: (y:10, x:2))[NDDataset_9d69780a]
Summary
Data
[ 4 6]
...
[ 32 34]
[ 36 38]]
I[[ 1 3]
[ 5 7]
...
[ 33 35]
[ 37 39]]
Note the x
dimension size is divided by a factor of two
A dataset which is complex in two dimensions is called hypercomplex (itβs datatype in SpectroChemPy is set to quaternion).
[55]:
daq = da.set_quaternion() # equivalently one can use the set_hypercomplex method
daq
[55]:
NDDataset: [quaternion] unitless (shape: (y:5, x:2))[NDDataset_9d69780d]
Summary
Data
[ 8 10]
...
[ 24 26]
[ 32 34]]
RI[[ 1 3]
[ 9 11]
...
[ 25 27]
[ 33 35]]
IR[[ 4 6]
[ 12 14]
...
[ 28 30]
[ 36 38]]
II[[ 5 7]
[ 13 15]
...
[ 29 31]
[ 37 39]]
[56]:
daq.dtype
[56]:
dtype(quaternion)