This will show you how to create a simple, custom unit system and apply it to a skspec Spectra. For designing your own unit-conversion system (ie.* ft --> in --> cm*), see the related custom unit system tutorial.
Configure notebook style (see NBCONFIG.ipynb), add imports and paths. The %run magic used below requires IPython 2.0 or higher.
%run NBCONFIG.ipynb
Populating the interactive namespace from numpy and matplotlib ['dti', 'd', 'h', 'm', 'us', 's', 'ms', 'intvl', 'ns']
In spectroscopy, there are so many interesting research projects going on that we knew our Spectra and TimeSpectra objects would only be useful to a small subset of users. Therefore, we made it really easy to apply your own units to a skspec object and have it persist through subsequent operations. Our only constraint is that your unit needs to be a subclass of our Unit
class. This will ensure consistency in plotting, serialization and so on...
Let's create a unit that might correspond to the polarization angle of a beam:
from skspec.units import Unit
polarization = Unit(
short = 'polar',
full = 'Polarization',
symbol = r'$\theta$',
)
The required attributes of a Unit
are:
short
: Symbolic description, like 'm' for 'meter'full
: Full word, like 'meter'symbol
: Used in some plotting functions to represent the data type.The symbol is the least important, and right now is only used in correlation spectroscopy plots. For example, a cross-plot of polarization and wavelength would have symbols, $\theta$ vs. $\lambda$. The "r" in front of the string means raw-literal and prevents python from reading the \t in \theta as a tab.
from skspec import Spectra
s = Spectra(np.random.rand(100,100)) #Some random noise
s.specunit = 'nm'
s.varunit = polarization
s.plot(kind='waterfall', cmap='hsv'); #3d Plot
plt.title('Random noise: nanometers vs. polarization');
WARNING:skspec.core.spectra:Spectrum does not have subtracted baseline; could affect result in specious absorbance data.
We've assigned the polarization to our perturbation variable (varunit), which overwrites the columns of the spectra.
print 'Perturbation short: "%s"\nPerturbation full: "%s"' % (s.varunit, s.full_varunit)
print s.columns[0:6]
Perturbation short: "polar" Perturbation full: "Polarization" CustomIndex[polar]([0, 1, 2, 3, 4, 5], dtype='int64')
print s.columns.unit
<skspec.units.abcunits.Unit object at 0x7ffc098689d0>
s.columns.unit.foo = 'FOOSTRING'
squared = s**2
squared.columns.unit.foo
'FOOSTRING'
These could have also been set when initiating Unit
; that is, Unit(short='polar', foo='FOOSTRING')
Certain spectra are strictly typed. For example the TimeSpectra
will assume your data is time vs. wavelength, and auto-convert accordingly. In terms of Indexes, this requires:
TimeSpectra
: columns is TimeIndex, index is SpecIndex.The Spectra
only types your row data. You can have any type of column index (time, pressure, polarization etc...)
Spectra
: columns is ANY, index is SpecIndexThe AnyFrame
types neither index nor columns:
AnyFrame
: columns is ANY, index is ANYfrom skspec import AnyFrame
anyframe = AnyFrame(np.random.randn(100,100))
anyframe.specunit = polarization
anyframe.varunit = polarization
anyframe.plot(kind='waterfall')
plt.title('AnyFrame: custom index AND custom columns');
WARNING:skspec.core.spectra:Spectrum does not have subtracted baseline; could affect result in specious absorbance data.
AnyFrame
is simply a convenience, but imagine you want to create a TimeByTime object where the rows and columns are both a TimeIndex
, strictly. All you have to do is:
from skspec.core.timeindex import TimeIndex
class TimeByTime(Spectra):
""" Demo class that enforces PressureIndex as Index and TimeIndex as columns"""
def __init__(self, *dfargs, **dfkwargs):
dfkwargs['strict_index'] = TimeIndex
dfkwargs['strict_columns'] = TimeIndex
super(Spectra, self).__init__(*dfargs, **dfkwargs)
You can also overwrite the typeing of pre-existing objects through the private API attributes _strict_index/columns
. EG spectra._strict_index = False
, but please don't do this as this won't trigger any internal changes to the current indexes on the object. Just make a new class as shown in the prior cell.