The measurement structure

The measurement (meas) is the central object in the pluggable structure of ixdat, and the main interface for user interaction. A measurement is an object of the generalized class main interface for user interaction. A measurement is an object of the generalized class Measurement, defined in the measurements module, or an inheriting *TechniqueMeasurement* class defined in a module of the techniques folder (see Techniques: ixdat’s measurement subclasses).

The general pluggable structure is defined by Measurement, connecting every measurement to a reader for importing from text, a backend for saving and loading in ixdat, a plotter for visualization, and an exporter for saving outside of ixdat. Each TechniqueMeasurement class will likely hav its own default reader, plotter, and exporter, while an ixdat session will typically work with one backend handled by the db model.

Design: pluggability

Classes for measurement techniques

Inheritance in TechniqueMeasurement classes makes it so that related techniques can share functionality. Here is an illustration of the role of inheritence, using EC, MS, and EC-MS as an example:

Design: inheritance

A full list of TechniqueMeasurements is in Techniques: ixdat’s measurement subclasses.

Initiating a measurement

A typical workflow is to start by reading a file. For convenience, most readers are accessible directly from Measurement. So, for example, to read a .mpt file exported by Biologic’s EC-Lab, one can type:

>>> from ixdat import Measurement
>>> ec_meas = Measurement.read("my_file.mpt", reader="biologic")

See readers for a description of the available readers.

The biologic reader (ixdat.readers.biologic.BiologicMPTReader) ensures that the object returned, ec_meas, is of type ECMeasurement.

Another workflow starts with loading a measurement from the active ixdat backend. This can also be done straight from Measurement, as follows:

>>> from ixdat import Measurement
>>> ec_meas = Measurement.get(3)

Where the row with id=3 of the measurements table represents an electrochemistry measurement. Here the column “technique” in the measurements table specifies which TechniqueMeasurement class is returned. Here, it for row three of the measurements table, the entry “technique” is “EC”, ensuring ec_meas is an object of type ECMeasurement.

What’s in a measurement

A measurement is basically a wrapper around a collection of data_series (see The data series structure).

There are several ways of interracting with a measurement’s data_series:

  • meas.grab() is the canonical way of getting numerical data out of a measurement. Given the name of a ValueSeries, it returns two numpy arrays, t and v where t is the time (wrt meas.tstamp) and v is the value as a function of that time vector. grab takes a series name as its first argument and can also take a tspan argument in which case it cuts the vectors to return data for the specific timespan of the measurement.
  • Indexing a measurement with the name of a data series returns that data series, with any time values tstamp’d at meas.tstamp
  • Most TechniqueMeasureemnts provide attribute-style access to essential DataSeries and data. For example, ECMeasurement has properties for potential and current series, as well as t, v, and j for data.
  • The names of the series are available in meas.series_names.
  • The raw series are available in meas.series_list.

The measurements module

Here is the full in-line documentation of the measurements module containing the Measurement class.

This module defines the Dataset class, the central data structure of ixdat

An ixdat Dataset is a collection of references to DataSeries with the metadata required to combine them, i.e. “build” the combined dataset. It has a number of general methods to visualize and analyze the combined dataset. Dataset is also the base class for a number of technique-specific Dataset-derived classes.

class ixdat.measurements.Measurement(name, technique=None, metadata=None, s_ids=None, series_list=None, m_ids=None, component_measurements=None, reader=None, plotter=None, exporter=None, sample=None, lablog=None, tstamp=None)[source]

The Measurement class

component_measurements

List of the component measurements of which this measurement is a combination

For a pure measurement (not a measurement set), this is itself in a list.

correct_data(value_name, new_data)[source]

Replace the old data for ´value_name´ (str) with ´new_data` (np array)

cut(tspan, t_zero=None)[source]

Return a new measurement with the data in the given time interval

Parameters:
  • tspan (iter of float) – The time interval to use, relative to self.tstamp tspan[0] is the start time of the interval, and tspan[-1] is the end time of the interval. Using tspan[-1] means you can directly use a long time vector that you have at hand to describe the time interval you’re looking for.
  • t_zero (float or str) – Where to put the tstamp of the returned measurement. Default is to keep it the same as the present tstamp. If instead it is a float, this adds the float to the present tstamp. If t_zero is “start”, tspan[0] is added to the present tstamp.
data_cols

Return a set of the names of all of the measurement’s VSeries and TSeries

data_objects

This is what the DB backend knows to save separately, here the series

export(*args, exporter=None, **kwargs)[source]

Export the measurement using its exporter (see its Exporter for details)

exporter

The default exporter for Measurement is CSVExporter.

classmethod from_component_measurements(component_measurements, keep_originals=True, sort=True, **kwargs)[source]

Return a measurement with the data contained in the component measurements

TODO: This function “builds” the resulting measurement, i.e. it appends series
of the same name rather than keeping all the original copies. This should be made more explicit, and a build() method should take over some of the work.
Parameters:
  • component_measurements (list of Measurement) –
  • keep_originals – Whether to keep a list of component_measurements referenced. This may result in redundant numpy arrays in RAM.
  • sort (bool) – Whether to sort the series according to time
  • kwargs – key-word arguments are added to the dictionary for cls.from_dict()

Returns cls: a Measurement object of the

classmethod from_dict(obj_as_dict)[source]

Return an object of the measurement class of the right technique

Parameters:obj_as_dict (dict) – The full serializaiton (rows from table and aux tables) of the measurement. obj_as_dict[“technique”] specifies the technique class to use, from TECHNIQUE_CLASSES
get_original_m_id_of_series(series)[source]

Return the id(s) of component measurements to which series belongs.

grab(item, tspan=None, include_endpoints=False, tspan_bg=None)[source]

Return a value vector with the corresponding time vector

Grab is the canonical way to retrieve numerical time-dependent data from a measurement in ixdat. The first argument is always the name of the value to get time-resolved data for (the name of a ValueSeries). The second, optional, argument is a timespan to select the data for. Two vectors are returned: first time (t), then value (v). They are of the same length so that v can be plotted against t, integrated over t, interpolated via t, etc. t and v are returned in the units of their DataSeries. TODO: option to specifiy desired units

Typical usage::
t, v = measurement.grab(potential, tspan=[0, 100])
Parameters:
  • item (str) – The name of the DataSeries to grab data for
  • tspan (iter of float) – Defines the timespan with its first and last values. Optional. By default the entire time of the measurement is included.
  • include_endpoints (bool) – Whether to add a points at t = tspan[0] and t = tspan[-1] to the data returned. This makes trapezoidal integration less dependent on the time resolution. Default is False.
  • tspan_bg (iterable) – Optional. A timespan defining when item is at its baseline level. The average value of item in this interval will be subtracted from the values returned.
grab_for_t(item, t, tspan_bg=None)[source]

Return a numpy array with the value of item interpolated to time t

Parameters:
  • item (str) – The name of the value to grab
  • t (np array) – The time vector to grab the value for
  • tspan_bg (iterable) – Optional. A timespan defining when item is at its baseline level. The average value of item in this interval will be subtracted from what is returned.
integrate(item, tspan=None, ax=None)[source]

Return the time integral of item in the specified timespan

join(other, join_on=None)[source]

Join two measurements based on a shared data series

This involves projecting all timeseries from other’s data series so that the variable named by join_on is shared between all data series. This is analogous to an explicit inner join.

Parameters:
  • other (Measurement) – a second measurement to join to self
  • join_on (str or tuple) – Either a string, if the value to join on is called the same thing in both measurements, or a tuple of two strings if it is not. The variable described by join_on must be monotonically increasing in both measurements.
m_ids

List of the id’s of a combined measurement’s component measurements

metadata_json_string

Measurement metadata as a JSON-formatted string

plotter

The default plotter for Measurement is ValuePlotter.

classmethod read(path_to_file, reader, **kwargs)[source]

Return a Measurement object from parsing a file with the specified reader

Parameters:
  • path_to_file (Path or str) – The path to the file to read
  • reader (str or Reader class) – The (name of the) reader to read the file with.
  • kwargs – key-word arguments are passed on to the reader’s read() method.
classmethod read_set(path_to_file_start, reader, suffix=None, file_list=None, **kwargs)[source]

Read and append a set of files.

Parameters:
  • path_to_file_start (Path or str) – The path to the files to read including the shared start of the file name: Path(path_to_file).parent is interpreted as the folder where the file are. Path(path_to_file).name is interpreted as the shared start of the files to be appended.
  • reader (str or Reader class) – The (name of the) reader to read the files with
  • file_list (list of Path) – As an alternative to path_to_file_start, the exact files to append can be specified in a list
  • suffix (str) – If a suffix is given, only files with the specified ending are added to the file list
  • kwargs – Key-word arguments are passed via cls.read() to the reader’s read() method, AND to cls.from_component_measurements()
classmethod read_url(url, reader, **kwargs)[source]

Read a url (via a temporary file) using the specified reader

s_ids

List of the id’s of the measurement’s DataSeries

sample_name

Name of the sample on which the measurement was conducted

select(*args, tspan=None, **kwargs)[source]

cut (with tspan) and select_values (with args and/or kwargs).

select_value(*args, **kwargs)[source]

Return a new Measurement with the time(s) meeting criteria.

Can only take one arg or kwarg! The series_name is self.sel_str if given an arg, kw if given a kwarg. Either way the argument is the value to be selected for.

The method finds all time intervals for which self[series_name] == value It then cuts the measurement according to each time interval and adds these segments together. TODO: This can be done better, i.e. without chopping series.

TODO: greater-than and less-than kwargs.
Ideally you should be able to say e.g., select(cycle=1, 0.5<potential<1)
select_values(*args, **kwargs)[source]

Return a new Measurement with the time(s) in the measurement meeting criteria

Any series can be selected for using the series name as a key-word. Arguments can be single acceptable values or lists of acceptable values. In the latter case, each acceptable value is selected for on its own and the resulting measurements added together. FIXME: That is sloppy because it multiplies the number of DataSeries FIXME: containing the same amount of data. If no key-word is given, the series name is assumed to be the default selector, which is named by self.sel_str. Multiple criteria are applied sequentially, i.e. you get the intersection of satisfying parts.

Parameters:
  • args (tuple) – Argument(s) given without key-word are understood as acceptable value(s) for the default selector (that named by self.sel_str)
  • kwargs (dict) – Each key-word arguments is understood as the name of a series and its acceptable value(s).
series_dict

Dictionary mapping the id’s of the measurement’s series to the DataSeries

series_list

List of the DataSeries containing the measurement’s data

series_names

List of the names of the series in the measurement

time_names

List of the names of the VSeries in the measurement’s DataSeries

time_series

List of the TSeries in the measurement’s DataSeries. NOT timeshifted!

tspan

Return (t_start, t_finish) interval including all data in the measurement

value_names

List of the names of the VSeries in the measurement’s DataSeries

value_series

List of the VSeries in the measurement’s DataSeries

ixdat.measurements.append_series(series_list, sort=True, tstamp=None)[source]

Return series appending series_list relative to series_list[0].tseries.tstamp

Parameters:
  • series_list (list of Series) – The series to append (must all be of same type)
  • sort (bool) – Whether to sort the data so that time only goes forward
  • tstamp (unix tstamp) – The t=0 of the returned series or its TimeSeries.
ixdat.measurements.append_tseries(series_list, sort=True, return_sort_indeces=False, tstamp=None)[source]

Return new TimeSeries with the data appended.

Parameters:
  • series_list (list of TimeSeries) – The time series to append
  • sort (bool) – Whether to sort the data so that time only goes forward
  • return_sort_indeces (bool) – Whether to return the indeces that sort the data
  • tstamp (unix tstamp) – The t=0 of the returned TimeSeries.
ixdat.measurements.append_vseries_by_time(series_list, sort=True, tstamp=None)[source]

Return new ValueSeries with the data in series_list appended

Parameters:
  • series_list (list of ValueSeries) – The value series to append
  • sort (bool) – Whether to sort the data so that time only goes forward
  • tstamp (unix tstamp) – The t=0 of the returned ValueSeries’ TimeSeries.
ixdat.measurements.fill_object_list(object_list, obj_ids, cls=None)[source]

Add PlaceHolderObjects to object_list for any unrepresented obj_ids.

Parameters:
  • object_list (list of objects or None) – The objects already known, in a list. This is the list to be appended to. If None, an empty list will be appended to.
  • obj_ids (list of ints or None) – The id’s of objects to ensure are in the list. Any id in obj_ids not already represented in object_list is added to the list as a PlaceHolderObject
  • cls (Saveable class) – the class remembered by any PlaceHolderObjects added to the object_list, so that eventually the right object will be loaded.
ixdat.measurements.get_combined_technique(technique_1, technique_2)[source]

Return the name of the technique resulting from adding two techniques

ixdat.measurements.time_shifted(series, tstamp=None)[source]

Return a series with the time shifted to be relative to tstamp