Parse Gamry EXPLAIN (DTA) files into polars DataFrames.
Version 1.0 replaces the 0.x API: gp.read(path) replaces GamryParser(...).load(), and curves are polars
DataFrames instead of pandas. See Migrating from 0.x, or pin gamry-parser<1 to keep the old API.
pip install gamry-parser
# or
uv add gamry-parsergamry-parser 1.x requires Python 3.12 or newer. To convert curves to pandas, install the pandas extra:
pip install "gamry-parser[pandas]".
import gamry_parser as gp
exp = gp.read("path/to/experiment.dta")
exp.experiment_type # header TAG, e.g. "CV"
exp.header["DATE"] # every header field, typed
exp.start_time # datetime from DATE and TIME
exp.curve_count
exp.curve(0) # polars DataFrame
exp.curves # every curve with every column, including PtHeader values are typed from the file's field types: str, float, int, bool, or, for TWOPARAM fields such as
CONDIT, a frozen TwoParam dataclass with enable, start and finish. header and units are read-only
mappings; json.dumps(exp.header, default=dataclasses.asdict) serializes a header, and TwoParam(**value) rebuilds
a field from the loaded JSON.
read() returns the class registered for the file's TAG:
| TAG | Class | curve() columns |
Properties |
|---|---|---|---|
CV |
CyclicVoltammetry |
Vf, Im | v_range, scan_rate |
CHRONOA |
ChronoAmperometry |
T, Vf, Im | sample_time |
EISPOT |
Impedance |
Freq, Zreal, Zimag, Zmod, Zphz | |
CORPOT |
OpenCircuitPotential |
T, Vf | |
SQUARE_WAVE |
SquareWaveVoltammetry |
T, Vfwd, Vrev, Vstep, Ifwd, Irev, Idif | step_size, pulse_size, pulse_width, frequency, v_range, cycles |
VFP600 |
VFP600 |
T, Voltage, Current | sample_time |
| anything else | Experiment |
all columns |
Every class also has ocv (the EOC header field), ocv_curve (the OCVCURVE table, if the file has one) and
sample_count (rows across all curves).
Properties return None when the header field is missing.
To require one experiment type, call read on its class. It raises GamryParseError for any other TAG:
cv = gp.CyclicVoltammetry.read("cv.dta")
cv.scan_rate, cv.v_rangeT is seconds since the start of the experiment. timestamps=True converts it to datetimes using the DATE and TIME
header fields:
gp.read("chronoa.dta").curve(timestamps=True)read() detects files written with a decimal comma (5,00000E-001), whatever the locale of the machine reading
them. To override detection, pass decimal_comma=True or decimal_comma=False.
df = exp.curve(0).to_pandas() # needs gamry-parser[pandas]read() raises FileNotFoundError for a missing file and GamryParseError (a ValueError) for a file it cannot
parse, including any file without a TAG header line. curve(i) raises IndexError when i is out of range.
| 0.x | 1.x |
|---|---|
p = GamryParser(filename=f); p.load() |
exp = gp.read(f) |
CyclicVoltammetry(filename=f).load() |
gp.CyclicVoltammetry.read(f) |
to_timestamp=True |
exp.curve(i, timestamps=True) |
p.curve(i) returns pandas with Pt as the index |
exp.curve(i) returns polars; Pt is a column of exp.curves[i] |
p.curves (list) |
exp.curves (tuple) |
p.curve_indices, p.curve_numbers |
range(exp.curve_count) |
p.fname, p.loaded |
exp.path |
AssertionError |
GamryParseError, IndexError, FileNotFoundError |
Calling a 0.x constructor raises a TypeError that names read() as the replacement.
python usage.py reads a cyclic voltammetry file. The notebooks in demo/ cover chronoamperometry, cyclic
voltammetry, CV peak detection, and EIS with an equivalent-circuit fit. They run in Jupyter or Google Colab:
uv run --group demo --with jupyterlab jupyter lab demo/git clone git@github.com:bcliang/gamry-parser.git
cd gamry-parser
uv sync # create .venv with the dev dependencies
uv run pytest --cov
uvx ruff check
uvx ruff format
uv build # sdist and wheel in dist/src/gamry_parser/
_dta.py file bytes -> header, units, curves
experiment.py Experiment and read()
techniques.py technique subclasses
tests/ pytest suite; fixtures in tests/data/
demo/ example notebooks
Propose changes as pull requests against master. CI runs ruff and the tests on Python 3.12 to 3.14, and the test
run fails if total branch coverage drops below 90%.
For equivalent-circuit modeling of EIS data, see impedance.py and PyEIS.
See CHANGELOG.md.