batplot 1.8.30__tar.gz → 1.8.31__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- batplot-1.8.31/MANIFEST.in +2 -0
- {batplot-1.8.30/batplot.egg-info → batplot-1.8.31}/PKG-INFO +27 -6
- {batplot-1.8.30 → batplot-1.8.31}/README.md +26 -5
- {batplot-1.8.30 → batplot-1.8.31}/batplot/__init__.py +1 -1
- {batplot-1.8.30 → batplot-1.8.31}/batplot/args.py +25 -10
- {batplot-1.8.30 → batplot-1.8.31}/batplot/batch.py +27 -8
- {batplot-1.8.30 → batplot-1.8.31}/batplot/batplot.py +98 -57
- {batplot-1.8.30 → batplot-1.8.31}/batplot/cpc_interactive.py +146 -8
- {batplot-1.8.30 → batplot-1.8.31}/batplot/data/CHANGELOG.md +15 -6
- batplot-1.8.31/batplot/data/USER_MANUAL.md +624 -0
- {batplot-1.8.30 → batplot-1.8.31}/batplot/electrochem_interactive.py +367 -126
- {batplot-1.8.30 → batplot-1.8.31}/batplot/manual.py +12 -1
- {batplot-1.8.30 → batplot-1.8.31}/batplot/modes.py +23 -3
- {batplot-1.8.30 → batplot-1.8.31}/batplot/operando.py +167 -147
- {batplot-1.8.30 → batplot-1.8.31}/batplot/operando_ec_interactive.py +14 -14
- {batplot-1.8.30 → batplot-1.8.31}/batplot/readers.py +390 -0
- {batplot-1.8.30 → batplot-1.8.31}/batplot/session.py +70 -0
- {batplot-1.8.30 → batplot-1.8.31}/batplot/version_check.py +2 -3
- {batplot-1.8.30 → batplot-1.8.31/batplot.egg-info}/PKG-INFO +27 -6
- {batplot-1.8.30 → batplot-1.8.31}/batplot.egg-info/SOURCES.txt +2 -1
- batplot-1.8.31/batplot.egg-info/top_level.txt +2 -0
- {batplot-1.8.30 → batplot-1.8.31}/pyproject.toml +1 -1
- batplot-1.8.30/MANIFEST.in +0 -2
- batplot-1.8.30/batplot.egg-info/top_level.txt +0 -1
- {batplot-1.8.30 → batplot-1.8.31}/LICENSE +0 -0
- {batplot-1.8.30 → batplot-1.8.31}/NOTICE +0 -0
- {batplot-1.8.30 → batplot-1.8.31}/batplot/cif.py +0 -0
- {batplot-1.8.30 → batplot-1.8.31}/batplot/cli.py +0 -0
- {batplot-1.8.30 → batplot-1.8.31}/batplot/color_utils.py +0 -0
- {batplot-1.8.30 → batplot-1.8.31}/batplot/config.py +0 -0
- {batplot-1.8.30 → batplot-1.8.31}/batplot/converters.py +0 -0
- {batplot-1.8.30 → batplot-1.8.31}/batplot/dev_upgrade.py +0 -0
- {batplot-1.8.30 → batplot-1.8.31}/batplot/interactive.py +0 -0
- {batplot-1.8.30 → batplot-1.8.31}/batplot/plotting.py +0 -0
- {batplot-1.8.30 → batplot-1.8.31}/batplot/style.py +0 -0
- {batplot-1.8.30 → batplot-1.8.31}/batplot/ui.py +0 -0
- {batplot-1.8.30 → batplot-1.8.31}/batplot/utils.py +0 -0
- {batplot-1.8.30 → batplot-1.8.31}/batplot.egg-info/dependency_links.txt +0 -0
- {batplot-1.8.30 → batplot-1.8.31}/batplot.egg-info/entry_points.txt +0 -0
- {batplot-1.8.30 → batplot-1.8.31}/batplot.egg-info/requires.txt +0 -0
- {batplot-1.8.30 → batplot-1.8.31}/setup.cfg +0 -0
- {batplot-1.8.30 → batplot-1.8.31}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: batplot
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.31
|
|
4
4
|
Summary: Interactive plotting tool for material science (1D plot) and electrochemistry (GC, CV, dQ/dV, CPC, operando) with batch processing
|
|
5
5
|
Author-email: Tian Dai <tianda@uio.no>
|
|
6
6
|
License: MIT License
|
|
@@ -57,9 +57,10 @@ Dynamic: license-file
|
|
|
57
57
|
|
|
58
58
|
## Features
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
- **
|
|
62
|
-
- **
|
|
60
|
+
With a single line of command to easily plot publication-ready plots with customized, intuitive interactive editing features such as:
|
|
61
|
+
- **Electrochemistry Plot**: Galvanostatic cycling (GC), cyclic voltammetry (CV), differential capacity (dQdV), capacity per cycle (CPC) with multi-file support
|
|
62
|
+
- **1D XY plot**: Designed for XRD, PDF, XAS (XANES/EXAFS) but also support other types
|
|
63
|
+
- **Operando Contour plot**: Correlate in-situ characterizations (XRD/PDF/XAS) with electrochemical data
|
|
63
64
|
- **Interactive plotting**: Real-time editing customized for each type of plottings
|
|
64
65
|
- **Session Persistence**: Save and reload complete plot states with `.pkl` files
|
|
65
66
|
- **Style Management**: Import/export plot styles as `.bps`/`.bpsg` files
|
|
@@ -249,6 +250,23 @@ batplot custom.mpt --gc --pw 0.01 3 --cd 0.2 --i
|
|
|
249
250
|
|
|
250
251
|
## Operando Mode
|
|
251
252
|
|
|
253
|
+
Contour plots from a folder of diffraction data, optionally with an electrochemistry side panel.
|
|
254
|
+
|
|
255
|
+
### Bruker operando (.brml)
|
|
256
|
+
|
|
257
|
+
For Bruker operando XRD (multi-scan .brml files named cyc1, cyc2, cyc3, etc.):
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
# Place .brml files (e.g. RA_O5_cyc1.brml, RA_O5_cyc2.brml) in the folder
|
|
261
|
+
# Use --wl for Q conversion (e.g. synchrotron λ=0.709 Å)
|
|
262
|
+
batplot RA_O5 --operando --wl 0.709 --i
|
|
263
|
+
|
|
264
|
+
# EC side panel: .mpt or Biologic DataLogger CSV (*--DataLogger.csv), sorted by cyc
|
|
265
|
+
# Time vs potential is concatenated across files (continuous time axis)
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Standard XY files
|
|
269
|
+
|
|
252
270
|
```bash
|
|
253
271
|
# Contour from folder of .xy/.xye/.qye/.dat
|
|
254
272
|
batplot --operando --wl 1.54 --i
|
|
@@ -313,8 +331,9 @@ batplot --all --readcol 2 3 style.bps --xaxis 2theta
|
|
|
313
331
|
|
|
314
332
|
| Type | Formats |
|
|
315
333
|
|------|---------|
|
|
316
|
-
| **Electrochemistry** | `.csv` (Neware), `.mpt` (Biologic), `.xlsx` (Landt/Lanhe CPC) |
|
|
334
|
+
| **Electrochemistry** | `.csv` (Neware, Biologic DataLogger), `.mpt` (Biologic), `.xlsx` (Landt/Lanhe CPC) |
|
|
317
335
|
| **XRD / PDF** | `.xye`, `.xy`, `.qye`, `.dat`, `.csv`, `.txt`; Bruker `.brml`, `.raw` |
|
|
336
|
+
| **Operando** | `.xy`, `.xye`, `.qye`, `.dat`; Bruker `.brml` (cyc1/cyc2/cyc3); EC: `.mpt` or DataLogger `.csv` |
|
|
318
337
|
| **XAS** | `.nor`, `.chik`, `.chir` |
|
|
319
338
|
| **Generic** | Use `--readcol` and `--xaxis` for custom formats |
|
|
320
339
|
|
|
@@ -324,9 +343,11 @@ batplot --all --readcol 2 3 style.bps --xaxis 2theta
|
|
|
324
343
|
|
|
325
344
|
With `--interactive`:
|
|
326
345
|
- **Cycle/Scan Control**: Toggle visibility, change colors
|
|
346
|
+
- **Multi-file palette (EC/CV/dQdV)**: Press `c`, then type `fall viridis` (all files), `f1-5 viridis` (files 1–5), or `f1 f3 f5 4` (each file gets one color)
|
|
347
|
+
- **CPC file palette**: In `ly`/`ry` color submenu, apply palette to file range: `1-5 viridis`, `1 3 5 4`
|
|
327
348
|
- **Styling**: Line widths, markers, fonts
|
|
328
349
|
- **Axes**: Labels, limits, ticks, spine styles
|
|
329
|
-
- **Export**: Sessions (`.pkl`), styles (`.bps`/`.bpsg`), high-res images
|
|
350
|
+
- **Export**: Sessions (`.pkl`), styles (`.bps`/`.bpsg`), high-res images. Colors persist via `p` (print style), `i` (import), `s` (save session), `b` (undo)
|
|
330
351
|
- **Live Preview**: All changes update in real-time
|
|
331
352
|
|
|
332
353
|
---
|
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
9
|
+
With a single line of command to easily plot publication-ready plots with customized, intuitive interactive editing features such as:
|
|
10
|
+
- **Electrochemistry Plot**: Galvanostatic cycling (GC), cyclic voltammetry (CV), differential capacity (dQdV), capacity per cycle (CPC) with multi-file support
|
|
11
|
+
- **1D XY plot**: Designed for XRD, PDF, XAS (XANES/EXAFS) but also support other types
|
|
12
|
+
- **Operando Contour plot**: Correlate in-situ characterizations (XRD/PDF/XAS) with electrochemical data
|
|
12
13
|
- **Interactive plotting**: Real-time editing customized for each type of plottings
|
|
13
14
|
- **Session Persistence**: Save and reload complete plot states with `.pkl` files
|
|
14
15
|
- **Style Management**: Import/export plot styles as `.bps`/`.bpsg` files
|
|
@@ -198,6 +199,23 @@ batplot custom.mpt --gc --pw 0.01 3 --cd 0.2 --i
|
|
|
198
199
|
|
|
199
200
|
## Operando Mode
|
|
200
201
|
|
|
202
|
+
Contour plots from a folder of diffraction data, optionally with an electrochemistry side panel.
|
|
203
|
+
|
|
204
|
+
### Bruker operando (.brml)
|
|
205
|
+
|
|
206
|
+
For Bruker operando XRD (multi-scan .brml files named cyc1, cyc2, cyc3, etc.):
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
# Place .brml files (e.g. RA_O5_cyc1.brml, RA_O5_cyc2.brml) in the folder
|
|
210
|
+
# Use --wl for Q conversion (e.g. synchrotron λ=0.709 Å)
|
|
211
|
+
batplot RA_O5 --operando --wl 0.709 --i
|
|
212
|
+
|
|
213
|
+
# EC side panel: .mpt or Biologic DataLogger CSV (*--DataLogger.csv), sorted by cyc
|
|
214
|
+
# Time vs potential is concatenated across files (continuous time axis)
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Standard XY files
|
|
218
|
+
|
|
201
219
|
```bash
|
|
202
220
|
# Contour from folder of .xy/.xye/.qye/.dat
|
|
203
221
|
batplot --operando --wl 1.54 --i
|
|
@@ -262,8 +280,9 @@ batplot --all --readcol 2 3 style.bps --xaxis 2theta
|
|
|
262
280
|
|
|
263
281
|
| Type | Formats |
|
|
264
282
|
|------|---------|
|
|
265
|
-
| **Electrochemistry** | `.csv` (Neware), `.mpt` (Biologic), `.xlsx` (Landt/Lanhe CPC) |
|
|
283
|
+
| **Electrochemistry** | `.csv` (Neware, Biologic DataLogger), `.mpt` (Biologic), `.xlsx` (Landt/Lanhe CPC) |
|
|
266
284
|
| **XRD / PDF** | `.xye`, `.xy`, `.qye`, `.dat`, `.csv`, `.txt`; Bruker `.brml`, `.raw` |
|
|
285
|
+
| **Operando** | `.xy`, `.xye`, `.qye`, `.dat`; Bruker `.brml` (cyc1/cyc2/cyc3); EC: `.mpt` or DataLogger `.csv` |
|
|
267
286
|
| **XAS** | `.nor`, `.chik`, `.chir` |
|
|
268
287
|
| **Generic** | Use `--readcol` and `--xaxis` for custom formats |
|
|
269
288
|
|
|
@@ -273,9 +292,11 @@ batplot --all --readcol 2 3 style.bps --xaxis 2theta
|
|
|
273
292
|
|
|
274
293
|
With `--interactive`:
|
|
275
294
|
- **Cycle/Scan Control**: Toggle visibility, change colors
|
|
295
|
+
- **Multi-file palette (EC/CV/dQdV)**: Press `c`, then type `fall viridis` (all files), `f1-5 viridis` (files 1–5), or `f1 f3 f5 4` (each file gets one color)
|
|
296
|
+
- **CPC file palette**: In `ly`/`ry` color submenu, apply palette to file range: `1-5 viridis`, `1 3 5 4`
|
|
276
297
|
- **Styling**: Line widths, markers, fonts
|
|
277
298
|
- **Axes**: Labels, limits, ticks, spine styles
|
|
278
|
-
- **Export**: Sessions (`.pkl`), styles (`.bps`/`.bpsg`), high-res images
|
|
299
|
+
- **Export**: Sessions (`.pkl`), styles (`.bps`/`.bpsg`), high-res images. Colors persist via `p` (print style), `i` (import), `s` (save session), `b` (undo)
|
|
279
300
|
- **Live Preview**: All changes update in real-time
|
|
280
301
|
|
|
281
302
|
---
|
|
@@ -135,7 +135,7 @@ def _print_general_help() -> None:
|
|
|
135
135
|
"What it does:\n"
|
|
136
136
|
" • XY: XRD/PDF/XAS/User defined curves\n"
|
|
137
137
|
" • EC: Galvanostatic cycling(GC)/Capacity per cycle(CPC)/Diffrential capacity(dQdV)/Cyclic Voltammetry(CV) from Neware (.csv) or Biologic (.mpt)\n"
|
|
138
|
-
" • Operando: contour
|
|
138
|
+
" • Operando: contour from .xy/.xye/.dat/.brml; Bruker .brml (cyc1/cyc2/cyc3) with optional .mpt or DataLogger CSV side panel\n"
|
|
139
139
|
" • Batch: export vector plots for all files in a directory\n"
|
|
140
140
|
" • Interactive mode: --i flag opens a menu for styling, ranges, export, and save\n\n"
|
|
141
141
|
"How to run (basics):\n"
|
|
@@ -156,7 +156,8 @@ def _print_general_help() -> None:
|
|
|
156
156
|
" batplot --cv file.mpt --i # Cyclic voltammetry\n"
|
|
157
157
|
" batplot --cpc file.csv --mass 3.52 --i # Capacity per cycle\n\n"
|
|
158
158
|
" [Operando]\n"
|
|
159
|
-
" batplot --operando --i [FOLDER] # Contour from folder\n
|
|
159
|
+
" batplot --operando --i [FOLDER] # Contour from folder\n"
|
|
160
|
+
" batplot Path/to/file --operando --wl 0.709 --i # Bruker .brml, Q conversion\n\n"
|
|
160
161
|
"Features:\n"
|
|
161
162
|
" • Interactive (--i): styling, ranges, fonts, export, sessions\n"
|
|
162
163
|
" • XRD wavelength: --wl 1.54 or file.xye:1.5406 for Q conversion\n"
|
|
@@ -313,8 +314,11 @@ def _print_ec_help() -> None:
|
|
|
313
314
|
" batplot file1.csv file2.csv ./Style/style.bps --dqdv # Style from relative path\n"
|
|
314
315
|
" batplot file1.csv file2.mpt style.bpsg --cpc --mass 6 # CPC mode\n"
|
|
315
316
|
" batplot file1.csv file2.mpt ./Style/style.bpsg --cpc --mass 6 # Style+geom from relative path\n\n"
|
|
317
|
+
"Multi-file (EC/CV/dQdV): Press c, then type fall viridis (all files), f1-5 viridis (files 1–5), or f1 f3 f5 4.\n"
|
|
318
|
+
"CPC (ly/ry): Type 1-5 viridis or 1 3 5 4 for file range. Exported via p, restored via i/s/b.\n\n"
|
|
316
319
|
"Interactive (--i): choose cycles, colors/palettes, line widths, axis scales (linear/log/symlog),\n"
|
|
317
320
|
"rename axes, toggle ticks/titles/spines, print/export/import style (.bps/.bpsg), save session (.pkl).\n"
|
|
321
|
+
"Multi-file: In c (cycles/colors), type fall viridis (all files), f1-5 viridis (files 1–5), or f1 f3 f5 4 (files 1,3,5).\n"
|
|
318
322
|
"Note: Batch mode (--all) exports SVG files automatically; --i is for single-file plotting only.\n\n"
|
|
319
323
|
"Axis swapping:\n"
|
|
320
324
|
" --ro : swap x and y axes (exchange x and y values before plotting)\n"
|
|
@@ -333,7 +337,14 @@ def _print_op_help() -> None:
|
|
|
333
337
|
" batplot --operando --xaxis 2theta # Using 2theta axis\n"
|
|
334
338
|
" batplot --operando --1d --i # Plot derivatives as contour with interactive menu\n"
|
|
335
339
|
" batplot --operando --2d --i # Plot derivatives (alias for --1d)\n\n"
|
|
336
|
-
"
|
|
340
|
+
"Bruker operando (.brml):\n"
|
|
341
|
+
" • Place .brml files (e.g. XX_cyc1.brml, XX_cyc2.brml) in the folder.\n"
|
|
342
|
+
" • Each .brml is expanded into per-scan rows; files sorted by cyc1/cyc2/cyc3.\n"
|
|
343
|
+
" • Use --wl for Q conversion: batplot RA_O5 --operando --wl 0.709 --i\n"
|
|
344
|
+
" • EC side panel: .mpt or Biologic DataLogger CSV (*--DataLogger.csv), sorted by cyc.\n"
|
|
345
|
+
" • Time vs potential is concatenated across files (continuous time axis).\n\n"
|
|
346
|
+
"Standard XY files:\n"
|
|
347
|
+
" • Folder should contain .xy/.xye/.qye/.dat files.\n"
|
|
337
348
|
" • Intensity scale is auto-adjusted between min/max values.\n"
|
|
338
349
|
" • If no .qye present, provide --xaxis 2theta or set --wl for Q conversion.\n"
|
|
339
350
|
" • If a .mpt file is present, a side panel is added for dual-panel mode (time/potential/temp/etc.).\n"
|
|
@@ -425,6 +436,8 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
425
436
|
parser.add_argument("--xaxis", type=str, help=argparse.SUPPRESS)
|
|
426
437
|
parser.add_argument("--convert", nargs=2, metavar=("FROM", "TO"),
|
|
427
438
|
help="Convert XRD data: wavelength-to-wavelength (e.g., 1.54 0.25), wavelength-to-Q (e.g., 1.54 q), or Q-to-wavelength (e.g., q 1.54). Exports to 'converted' subfolder.")
|
|
439
|
+
parser.add_argument("--extract-brml-scans", nargs="?", const="", metavar="OUT_DIR",
|
|
440
|
+
help="Extract each XRD scan from .brml file to separate .xy files. Optional OUT_DIR (default: <brml_stem>_scans).")
|
|
428
441
|
parser.add_argument("--wl", type=float, help=argparse.SUPPRESS)
|
|
429
442
|
parser.add_argument("--fullprof", nargs="+", type=float, help=argparse.SUPPRESS)
|
|
430
443
|
parser.add_argument("--norm", action="store_true", help=argparse.SUPPRESS)
|
|
@@ -530,9 +543,11 @@ def parse_args(argv=None):
|
|
|
530
543
|
if argv is None:
|
|
531
544
|
argv = sys.argv[1:]
|
|
532
545
|
|
|
533
|
-
# Normalize
|
|
546
|
+
# Normalize short forms to long forms (both -x and --x for common flags)
|
|
534
547
|
_SHORT_TO_LONG = {
|
|
535
|
-
'-h': '--help', '
|
|
548
|
+
'-h': '--help', '--h': '--help',
|
|
549
|
+
'-v': '--version', '-V': '--version', '--v': '--version',
|
|
550
|
+
'-m': '--manual', '--m': '--manual',
|
|
536
551
|
'-i': '--i', '-d': '--delta', '-r': '--xrange', '-o': '--out', '-c': '--convert',
|
|
537
552
|
'-b': '--b',
|
|
538
553
|
}
|
|
@@ -674,13 +689,13 @@ def parse_args(argv=None):
|
|
|
674
689
|
ns, _unknown = parser.parse_known_args(argv)
|
|
675
690
|
if getattr(ns, "manual", False):
|
|
676
691
|
try:
|
|
677
|
-
from .manual import
|
|
678
|
-
|
|
692
|
+
from .manual import open_manual_url # Lazy import avoids matplotlib startup unless needed
|
|
693
|
+
open_manual_url()
|
|
679
694
|
if _HAS_RICH and _console:
|
|
680
|
-
_console.print(
|
|
695
|
+
_console.print("\n[green]Opened manual in browser[/green]")
|
|
681
696
|
else:
|
|
682
|
-
print(
|
|
683
|
-
except Exception as exc: # pragma: no cover -
|
|
697
|
+
print("\nOpened manual in browser")
|
|
698
|
+
except Exception as exc: # pragma: no cover - best effort
|
|
684
699
|
if _HAS_RICH and _console:
|
|
685
700
|
_console.print(f"\n[red]Failed to open manual:[/red] {exc}")
|
|
686
701
|
else:
|
|
@@ -21,6 +21,9 @@ from .readers import (
|
|
|
21
21
|
read_ec_csv_dqdv_file,
|
|
22
22
|
compute_dqdv_numerical,
|
|
23
23
|
is_cs_b_format,
|
|
24
|
+
is_biologic_datalogger_csv,
|
|
25
|
+
read_biologic_datalogger_csv,
|
|
26
|
+
read_biologic_datalogger_dqdv_file,
|
|
24
27
|
_load_csv_header_and_rows,
|
|
25
28
|
read_biologic_txt_file,
|
|
26
29
|
)
|
|
@@ -1013,8 +1016,16 @@ def batch_process_ec(directory: str, args):
|
|
|
1013
1016
|
cap_x = specific_capacity
|
|
1014
1017
|
x_label = r'Specific Capacity (mAh g$^{-1}$)'
|
|
1015
1018
|
elif ext == '.csv':
|
|
1016
|
-
|
|
1017
|
-
|
|
1019
|
+
if is_biologic_datalogger_csv(fpath):
|
|
1020
|
+
if mass_mg is None:
|
|
1021
|
+
print(f" Skipped {fname}: GC mode (Biologic DataLogger CSV) requires --mass parameter")
|
|
1022
|
+
plt.close(fig_b)
|
|
1023
|
+
continue
|
|
1024
|
+
cap_x, voltage, cycle_numbers, charge_mask, discharge_mask = \
|
|
1025
|
+
read_biologic_datalogger_csv(fpath, mass_mg=mass_mg)
|
|
1026
|
+
else:
|
|
1027
|
+
cap_x, voltage, cycle_numbers, charge_mask, discharge_mask = \
|
|
1028
|
+
read_ec_csv_file(fpath, prefer_specific=True)
|
|
1018
1029
|
x_label = r'Specific Capacity (mAh g$^{-1}$)'
|
|
1019
1030
|
else:
|
|
1020
1031
|
raise ValueError(f"Unsupported file type for GC: {ext}")
|
|
@@ -1116,13 +1127,21 @@ def batch_process_ec(directory: str, args):
|
|
|
1116
1127
|
|
|
1117
1128
|
# Try to load pre-calculated dQ/dV columns; fall back to numerical computation
|
|
1118
1129
|
_b_dqdv_header = None
|
|
1119
|
-
try:
|
|
1120
|
-
_b_dqdv_header, _, _ = _load_csv_header_and_rows(fpath)
|
|
1121
|
-
except Exception:
|
|
1122
|
-
pass
|
|
1123
|
-
|
|
1124
1130
|
_b_loaded = False
|
|
1125
|
-
if
|
|
1131
|
+
if is_biologic_datalogger_csv(fpath):
|
|
1132
|
+
if mass_mg is None or mass_mg <= 0:
|
|
1133
|
+
print(f" Skipped {fname}: dQ/dV (Biologic DataLogger CSV) requires --mass parameter")
|
|
1134
|
+
plt.close(fig_b)
|
|
1135
|
+
continue
|
|
1136
|
+
voltage, dqdv, cycles, charge_mask, discharge_mask, y_label = \
|
|
1137
|
+
read_biologic_datalogger_dqdv_file(fpath, mass_mg=mass_mg, prefer_specific=True)
|
|
1138
|
+
_b_loaded = True
|
|
1139
|
+
else:
|
|
1140
|
+
try:
|
|
1141
|
+
_b_dqdv_header, _, _ = _load_csv_header_and_rows(fpath)
|
|
1142
|
+
except Exception:
|
|
1143
|
+
pass
|
|
1144
|
+
|
|
1126
1145
|
try:
|
|
1127
1146
|
voltage, dqdv, cycles, charge_mask, discharge_mask, y_label = \
|
|
1128
1147
|
read_ec_csv_dqdv_file(fpath, prefer_specific=True)
|
|
@@ -40,6 +40,10 @@ from .readers import (
|
|
|
40
40
|
read_mpt_time_voltage,
|
|
41
41
|
read_cs_b_csv_file,
|
|
42
42
|
is_cs_b_format,
|
|
43
|
+
is_biologic_datalogger_csv,
|
|
44
|
+
read_biologic_datalogger_csv,
|
|
45
|
+
read_biologic_datalogger_dqdv_file,
|
|
46
|
+
read_biologic_datalogger_time_voltage,
|
|
43
47
|
_load_csv_header_and_rows,
|
|
44
48
|
read_biologic_txt_file,
|
|
45
49
|
read_batx_file,
|
|
@@ -549,7 +553,7 @@ def batplot_main() -> int: # type: ignore
|
|
|
549
553
|
# If no files AND no special flags, nothing to do
|
|
550
554
|
if not args.files and not has_special_flag:
|
|
551
555
|
print("No input provided, nothing to do.")
|
|
552
|
-
print("Use 'batplot --
|
|
556
|
+
print("Use 'batplot --v' for version and release info, 'batplot --h' for CLI help, or 'batplot --m' to open the user manual.")
|
|
553
557
|
return 0 # Exit successfully (not an error, just nothing to do)
|
|
554
558
|
|
|
555
559
|
# ====================================================================
|
|
@@ -797,15 +801,23 @@ def batplot_main() -> int: # type: ignore
|
|
|
797
801
|
specific_capacity, voltage, cycle_numbers, charge_mask, discharge_mask = read_mpt_file(ec_file, mode='gc', mass_mg=mass_mg)
|
|
798
802
|
cap_x = specific_capacity
|
|
799
803
|
elif ec_file.lower().endswith('.csv'):
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
except Exception:
|
|
804
|
+
if is_biologic_datalogger_csv(ec_file):
|
|
805
|
+
if mass_mg is None:
|
|
806
|
+
continue
|
|
807
|
+
cap_x, voltage, cycle_numbers, charge_mask, discharge_mask = read_biologic_datalogger_csv(
|
|
808
|
+
ec_file, mass_mg=mass_mg
|
|
809
|
+
)
|
|
807
810
|
header = None
|
|
808
|
-
|
|
811
|
+
else:
|
|
812
|
+
try:
|
|
813
|
+
header, _, _ = _load_csv_header_and_rows(ec_file)
|
|
814
|
+
if is_cs_b_format(header):
|
|
815
|
+
cap_x, voltage, cycle_numbers, charge_mask, discharge_mask = read_cs_b_csv_file(ec_file, mode='gc')
|
|
816
|
+
else:
|
|
817
|
+
cap_x, voltage, cycle_numbers, charge_mask, discharge_mask = read_ec_csv_file(ec_file, prefer_specific=True)
|
|
818
|
+
except Exception:
|
|
819
|
+
header = None
|
|
820
|
+
cap_x, voltage, cycle_numbers, charge_mask, discharge_mask = read_ec_csv_file(ec_file, prefer_specific=True)
|
|
809
821
|
# If we only have absolute capacity and the user supplied --mass,
|
|
810
822
|
# convert Capacity(mAh) → Specific Capacity (mAh g⁻¹).
|
|
811
823
|
if header is not None:
|
|
@@ -1004,19 +1016,27 @@ def batplot_main() -> int: # type: ignore
|
|
|
1004
1016
|
x_label_gc = r'Specific Capacity (mAh g$^{-1}$)'
|
|
1005
1017
|
cap_x = specific_capacity
|
|
1006
1018
|
elif ec_file.lower().endswith('.csv'):
|
|
1007
|
-
# Check if this is CS-B format
|
|
1008
1019
|
header = None
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1020
|
+
if is_biologic_datalogger_csv(ec_file):
|
|
1021
|
+
if mass_mg is None:
|
|
1022
|
+
print("GC mode (Biologic DataLogger CSV): --mass parameter is required (active material mass in milligrams).")
|
|
1023
|
+
print("Example: batplot file.csv --gc --mass 7.0")
|
|
1024
|
+
if len(data_files) > 1:
|
|
1025
|
+
continue
|
|
1026
|
+
else:
|
|
1027
|
+
exit(1)
|
|
1028
|
+
cap_x, voltage, cycle_numbers, charge_mask, discharge_mask = read_biologic_datalogger_csv(
|
|
1029
|
+
ec_file, mass_mg=mass_mg
|
|
1030
|
+
)
|
|
1031
|
+
else:
|
|
1032
|
+
try:
|
|
1033
|
+
header, _, _ = _load_csv_header_and_rows(ec_file)
|
|
1034
|
+
if is_cs_b_format(header):
|
|
1035
|
+
cap_x, voltage, cycle_numbers, charge_mask, discharge_mask = read_cs_b_csv_file(ec_file, mode='gc')
|
|
1036
|
+
else:
|
|
1037
|
+
cap_x, voltage, cycle_numbers, charge_mask, discharge_mask = read_ec_csv_file(ec_file, prefer_specific=True)
|
|
1038
|
+
except Exception:
|
|
1016
1039
|
cap_x, voltage, cycle_numbers, charge_mask, discharge_mask = read_ec_csv_file(ec_file, prefer_specific=True)
|
|
1017
|
-
except Exception:
|
|
1018
|
-
# Fallback to standard reader
|
|
1019
|
-
cap_x, voltage, cycle_numbers, charge_mask, discharge_mask = read_ec_csv_file(ec_file, prefer_specific=True)
|
|
1020
1040
|
# Decide whether we should treat cap_x as absolute or specific capacity.
|
|
1021
1041
|
x_label_gc = r'Specific Capacity (mAh g$^{-1}$)'
|
|
1022
1042
|
# If the CSV only has absolute capacity and no specific capacity, rescale
|
|
@@ -1893,38 +1913,46 @@ def batplot_main() -> int: # type: ignore
|
|
|
1893
1913
|
voltage, dqdv, cycles, charge_mask, discharge_mask, y_label = read_mpt_dqdv_file(ec_file, mass_mg=_mf_mass, prefer_specific=True)
|
|
1894
1914
|
else:
|
|
1895
1915
|
_mf_dqdv_header = None
|
|
1896
|
-
try:
|
|
1897
|
-
_mf_dqdv_header, _, _ = _load_csv_header_and_rows(ec_file)
|
|
1898
|
-
except Exception:
|
|
1899
|
-
pass
|
|
1900
|
-
|
|
1901
1916
|
_mf_loaded = False
|
|
1902
|
-
if
|
|
1903
|
-
|
|
1917
|
+
if is_biologic_datalogger_csv(ec_file):
|
|
1918
|
+
if _mf_mass is None or _mf_mass <= 0:
|
|
1919
|
+
continue
|
|
1920
|
+
voltage, dqdv, cycles, charge_mask, discharge_mask, y_label = read_biologic_datalogger_dqdv_file(
|
|
1921
|
+
ec_file, mass_mg=_mf_mass, prefer_specific=True
|
|
1922
|
+
)
|
|
1904
1923
|
_mf_loaded = True
|
|
1905
|
-
|
|
1906
|
-
if not _mf_loaded:
|
|
1924
|
+
else:
|
|
1907
1925
|
try:
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
except ValueError:
|
|
1926
|
+
_mf_dqdv_header, _, _ = _load_csv_header_and_rows(ec_file)
|
|
1927
|
+
except Exception:
|
|
1911
1928
|
pass
|
|
1912
1929
|
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
_mf_gc_cap, _mf_gc_volt, _mf_gc_cyc, _mf_gc_chgm, _mf_gc_dchm
|
|
1926
|
-
|
|
1927
|
-
|
|
1930
|
+
if _mf_dqdv_header is not None and is_cs_b_format(_mf_dqdv_header):
|
|
1931
|
+
voltage, dqdv, cycles, charge_mask, discharge_mask, y_label = read_cs_b_csv_file(ec_file, mode='dqdv')
|
|
1932
|
+
_mf_loaded = True
|
|
1933
|
+
|
|
1934
|
+
if not _mf_loaded:
|
|
1935
|
+
try:
|
|
1936
|
+
voltage, dqdv, cycles, charge_mask, discharge_mask, y_label = read_ec_csv_dqdv_file(ec_file, prefer_specific=True)
|
|
1937
|
+
_mf_loaded = True
|
|
1938
|
+
except ValueError:
|
|
1939
|
+
pass
|
|
1940
|
+
|
|
1941
|
+
if not _mf_loaded:
|
|
1942
|
+
_mf_gc_cap, _mf_gc_volt, _mf_gc_cyc, _mf_gc_chgm, _mf_gc_dchm = read_ec_csv_file(ec_file, prefer_specific=True)
|
|
1943
|
+
if _mf_dqdv_header is not None:
|
|
1944
|
+
_mf_hdrs = [h.strip().replace('\t', '') for h in _mf_dqdv_header]
|
|
1945
|
+
_mf_has_spec = any('Spec. Cap.(mAh/g)' in h for h in _mf_hdrs)
|
|
1946
|
+
_mf_has_abs = any(h == 'Capacity(mAh)' for h in _mf_hdrs)
|
|
1947
|
+
if _mf_has_abs and not _mf_has_spec:
|
|
1948
|
+
if _mf_mass and _mf_mass > 0:
|
|
1949
|
+
_mf_gc_cap = _mf_gc_cap * (1000.0 / float(_mf_mass))
|
|
1950
|
+
else:
|
|
1951
|
+
print(f"dQ/dV mode: {os.path.basename(ec_file)!r} contains only Capacity(mAh) — pass --mass <mg>.")
|
|
1952
|
+
voltage, dqdv, cycles, charge_mask, discharge_mask, y_label = compute_dqdv_numerical(
|
|
1953
|
+
_mf_gc_cap, _mf_gc_volt, _mf_gc_cyc, _mf_gc_chgm, _mf_gc_dchm
|
|
1954
|
+
)
|
|
1955
|
+
print(f"dQ/dV mode: computing numerically from GC data for {os.path.basename(ec_file)!r}.")
|
|
1928
1956
|
if y_label_used is None:
|
|
1929
1957
|
y_label_used = y_label
|
|
1930
1958
|
segments = _mask_segments(charge_mask, 'charge') + _mask_segments(discharge_mask, 'discharge')
|
|
@@ -2058,15 +2086,25 @@ def batplot_main() -> int: # type: ignore
|
|
|
2058
2086
|
else:
|
|
2059
2087
|
# Load header for format detection and mass-scaling check
|
|
2060
2088
|
_dqdv_header = None
|
|
2061
|
-
try:
|
|
2062
|
-
_dqdv_header, _, _ = _load_csv_header_and_rows(ec_file)
|
|
2063
|
-
except Exception:
|
|
2064
|
-
pass
|
|
2065
|
-
|
|
2066
2089
|
_loaded_dqdv = False
|
|
2067
|
-
if
|
|
2068
|
-
|
|
2090
|
+
if is_biologic_datalogger_csv(ec_file):
|
|
2091
|
+
if _dqdv_mass is None or _dqdv_mass <= 0:
|
|
2092
|
+
print(f"dQ/dV mode (Biologic DataLogger CSV): --mass parameter is required.")
|
|
2093
|
+
print(f"Example: batplot {ec_file} --dqdv --mass 7.0")
|
|
2094
|
+
continue
|
|
2095
|
+
voltage, dqdv, cycles, charge_mask, discharge_mask, y_label = read_biologic_datalogger_dqdv_file(
|
|
2096
|
+
ec_file, mass_mg=_dqdv_mass, prefer_specific=True
|
|
2097
|
+
)
|
|
2069
2098
|
_loaded_dqdv = True
|
|
2099
|
+
else:
|
|
2100
|
+
try:
|
|
2101
|
+
_dqdv_header, _, _ = _load_csv_header_and_rows(ec_file)
|
|
2102
|
+
except Exception:
|
|
2103
|
+
pass
|
|
2104
|
+
|
|
2105
|
+
if _dqdv_header is not None and is_cs_b_format(_dqdv_header):
|
|
2106
|
+
voltage, dqdv, cycles, charge_mask, discharge_mask, y_label = read_cs_b_csv_file(ec_file, mode='dqdv')
|
|
2107
|
+
_loaded_dqdv = True
|
|
2070
2108
|
|
|
2071
2109
|
if not _loaded_dqdv:
|
|
2072
2110
|
try:
|
|
@@ -2086,11 +2124,11 @@ def batplot_main() -> int: # type: ignore
|
|
|
2086
2124
|
if _dqdv_mass and _dqdv_mass > 0:
|
|
2087
2125
|
_gc_cap = _gc_cap * (1000.0 / float(_dqdv_mass))
|
|
2088
2126
|
else:
|
|
2089
|
-
print(f"dQ/dV mode: {
|
|
2127
|
+
print(f"dQ/dV mode: {os.path.basename(ec_file)!r} contains only Capacity(mAh) — pass --mass <mg> for specific dQ/dV.")
|
|
2090
2128
|
voltage, dqdv, cycles, charge_mask, discharge_mask, y_label = compute_dqdv_numerical(
|
|
2091
2129
|
_gc_cap, _gc_volt, _gc_cyc, _gc_chgm, _gc_dchm
|
|
2092
2130
|
)
|
|
2093
|
-
print(f"dQ/dV mode: no dQ/dV column found — computing numerically from GC data for {
|
|
2131
|
+
print(f"dQ/dV mode: no dQ/dV column found — computing numerically from GC data for {os.path.basename(ec_file)!r}.")
|
|
2094
2132
|
|
|
2095
2133
|
# Create the plot
|
|
2096
2134
|
fig, ax = plt.subplots(figsize=(10, 6))
|
|
@@ -3689,7 +3727,10 @@ def batplot_main() -> int: # type: ignore
|
|
|
3689
3727
|
# Time mode: read time (h) vs potential (V) for electrochemistry files
|
|
3690
3728
|
try:
|
|
3691
3729
|
if file_ext == '.csv':
|
|
3692
|
-
|
|
3730
|
+
if is_biologic_datalogger_csv(fname):
|
|
3731
|
+
x, y = read_biologic_datalogger_time_voltage(fname)
|
|
3732
|
+
else:
|
|
3733
|
+
x, y = read_csv_time_voltage(fname)
|
|
3693
3734
|
elif file_ext == '.mpt':
|
|
3694
3735
|
x, y = read_mpt_time_voltage(fname)
|
|
3695
3736
|
e = None
|