Data parsing
Individual impedance spectra are represented in pyimpspec as DataSet
objects.
The parse_data()
function acts as a wrapper for the various parsing functions available for different file formats such as:
BioLogic:
.mpt
Eco Chemie:
.dfr
Gamry:
.dta
Ivium:
.idf
and.ids
PalmSens:
.pssession
ZView:
.z
Spreadsheets:
.xlsx
and.ods
Plain-text character-separated values (CSV)
The parsing functions and parse_data()
always return a list of DataSet
objects since some files may contain multiple impedance spectra:
>>> from pyimpspec import DataSet, Frequencies, ComplexImpedances, parse_data
>>>
>>> data: DataSet
>>> for data in parse_data("./tests/data.dta"):
... # Do something with 'data'.
... f: Frequencies = data.get_frequencies()
... Z: ComplexImpedances = data.get_impedances()
Note
The data points are sorted from highest to lowest frequency when a DataSet
instance is created.
If a file contains multiple frequency sweeps, then they are returned as separate DataSet
instances.
Plotting data
A number of functions are included for plotting data (and various analysis results) using matplotlib as the backend. Below is a Nyquist plot of some example data (test circuit 1 or TC-1 from Boukamp (1995)).
>>> from pyimpspec import DataSet, parse_data
>>> from pyimpspec import mpl
>>>
>>> data: DataSet
>>> for data in parse_data("./tests/data.dta"):
... figure, axes = mpl.plot_nyquist(data)
>>>
>>> mpl.show()
Note
The figure
and axes
values can be reused if one wishes to plot multiple immittance spectra in the same figure: mpl.plot_nyquist(data, figure=figure, axes=axes)
More information and examples about these functions can be found in the API documentation (Plotting - matplotlib).
Masking data points
DataSet
objects support non-destructive masking of data points.
Masking a data point means that the data point will not be processed when analyzing or plotting the DataSet
object.
>>> from pyimpspec import DataSet, parse_data
>>> from typing import Dict
>>>
>>> data: DataSet = parse_data("./tests/data.dta")[0]
>>> data.get_num_points() # Included points
29
>>> # Apply a low-pass filter
>>> data.low_pass(1e3)
>>> data.get_num_points()
22
>>> # Apply a high-pass filter as well on top of the low-pass filter
>>> data.high_pass(1e1)
>>> data.get_num_points()
15
>>> # Check how many points are included or excluded
>>> data.get_num_points(masked=False) # Included points
15
>>> data.get_num_points(masked=True) # Excluded points
14
>>> data.get_num_points(masked=None) # All points
29
>>> # Get the current mask
>>> mask: Dict[int, bool] = data.get_mask()
>>> # Include the highest frequency point again
>>> mask[0] = False
>>> data.set_mask(mask)
>>> data.get_num_points()
16
>>> # Clear the mask
>>> data.set_mask({})
>>> data.get_num_points()
29
DataSet
objects have various methods for getting certain types of values while taking the applied mask into account (e.g., get_frequencies()
or get_phases()
).
Below are two Bode plots of the example above before and after the low- and high-pass filters were applied.
Custom parsers
Adding support for parsing additional file formats is quite easy.
Simply write a function that parses a file and returns a pandas.DataFrame object, and then pass that object to the dataframe_to_data_sets()
function.
The pandas.read_json function is used in the example below, but one could also turn a dictionary into a DataFrame using the pandas.DataFrame.from_dict method.
>>> from pyimpspec import DataSet, dataframe_to_data_sets
>>> from pandas import read_json
>>> from typing import List
>>>
>>> def parse_json(path: str) -> List[DataSet]:
... return dataframe_to_data_sets(df=read_json(path), path=path)
>>>
>>> data: DataSet = parse_json("./tests/data.json")[0]
>>> data.get_num_points()
29
>>> print(data.to_dataframe().to_markdown(index=False))
| f (Hz) | Re(Z) (ohm) | Im(Z) (ohm) | Mod(Z) (ohm) | Phase(Z) (deg.) |
|------------:|--------------:|--------------:|---------------:|------------------:|
| 10000 | 109.009 | -26.5557 | 112.197 | -13.6911 |
| 7196.86 | 112.058 | -35.1662 | 117.446 | -17.423 |
| 5179.47 | 116.906 | -46.4664 | 125.802 | -21.6762 |
| 3727.59 | 124.835 | -60.8523 | 138.876 | -25.9875 |
| 2682.7 | 137.77 | -78.0894 | 158.362 | -29.5449 |
| 1930.7 | 157.972 | -96.4806 | 185.104 | -31.4143 |
| 1389.5 | 186.637 | -112.205 | 217.769 | -31.014 |
| 1000 | 221.691 | -120.399 | 252.275 | -28.5062 |
| 719.686 | 257.437 | -118.651 | 283.464 | -24.7446 |
| 517.947 | 288.118 | -109.31 | 308.157 | -20.7764 |
| 372.759 | 311.563 | -97.2957 | 326.402 | -17.3427 |
| 268.27 | 328.959 | -86.554 | 340.155 | -14.7413 |
| 193.07 | 342.639 | -78.8887 | 351.603 | -12.9657 |
| 138.95 | 354.649 | -74.5879 | 362.408 | -11.877 |
| 100 | 366.4 | -73.2559 | 373.651 | -11.3063 |
| 71.9686 | 378.778 | -74.2957 | 385.996 | -11.0974 |
| 51.7947 | 392.326 | -77.1022 | 399.831 | -11.1184 |
| 37.2759 | 407.37 | -81.1148 | 415.368 | -11.2613 |
| 26.827 | 424.086 | -85.8173 | 432.682 | -11.4398 |
| 19.307 | 442.528 | -90.7275 | 451.733 | -11.5863 |
| 13.895 | 462.638 | -95.3932 | 472.371 | -11.6508 |
| 10 | 484.246 | -99.3993 | 494.342 | -11.5998 |
| 7.19686 | 507.068 | -102.385 | 517.302 | -11.4155 |
| 5.17947 | 530.727 | -104.069 | 540.835 | -11.0943 |
| 3.72759 | 554.773 | -104.271 | 564.487 | -10.6447 |
| 2.6827 | 578.721 | -102.924 | 587.802 | -10.0845 |
| 1.9307 | 602.093 | -100.083 | 610.354 | -9.43768 |
| 1.3895 | 624.462 | -95.9026 | 631.783 | -8.73106 |
| 1 | 645.479 | -90.6181 | 651.809 | -7.99147 |
If you wish for pyimpspec to include support for additional file formats, then you can either: