batplot 1.8.39__tar.gz → 1.8.41__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.41/MANIFEST.in +3 -0
- {batplot-1.8.39/batplot.egg-info → batplot-1.8.41}/PKG-INFO +10 -8
- {batplot-1.8.39 → batplot-1.8.41}/README.md +6 -7
- batplot-1.8.41/batplot/__init__.py +74 -0
- {batplot-1.8.39 → batplot-1.8.41}/batplot/args.py +115 -89
- {batplot-1.8.39 → batplot-1.8.41}/batplot/batch.py +40 -19
- batplot-1.8.41/batplot/batplot.py +642 -0
- {batplot-1.8.39 → batplot-1.8.41}/batplot/canvas_interactive.py +7 -7
- {batplot-1.8.39 → batplot-1.8.41}/batplot/color_utils.py +33 -14
- {batplot-1.8.39 → batplot-1.8.41}/batplot/config.py +44 -0
- {batplot-1.8.39 → batplot-1.8.41}/batplot/data/CHANGELOG.md +13 -0
- {batplot-1.8.39 → batplot-1.8.41}/batplot/dev_upgrade.py +350 -103
- batplot-1.8.41/batplot/ec_common.py +103 -0
- batplot-1.8.41/batplot/modes.py +37 -0
- batplot-1.8.41/batplot/plot_modes/__init__.py +1 -0
- batplot-1.8.41/batplot/plot_modes/common/__init__.py +1 -0
- batplot-1.8.41/batplot/plot_modes/common/axis_state.py +128 -0
- batplot-1.8.41/batplot/plot_modes/common/files.py +42 -0
- batplot-1.8.41/batplot/plot_modes/common/fonts.py +132 -0
- batplot-1.8.41/batplot/plot_modes/common/interactive_state.py +99 -0
- batplot-1.8.41/batplot/plot_modes/common/menu_rendering.py +84 -0
- batplot-1.8.41/batplot/plot_modes/common/menus.py +437 -0
- batplot-1.8.41/batplot/plot_modes/common/palettes.py +215 -0
- batplot-1.8.41/batplot/plot_modes/common/smoothing.py +38 -0
- batplot-1.8.41/batplot/plot_modes/common/sources.py +68 -0
- batplot-1.8.41/batplot/plot_modes/common/spines.py +758 -0
- batplot-1.8.41/batplot/plot_modes/common/terminal.py +128 -0
- batplot-1.8.41/batplot/plot_modes/common/title_offsets.py +65 -0
- batplot-1.8.41/batplot/plot_modes/cpc/__init__.py +5 -0
- batplot-1.8.41/batplot/plot_modes/cpc/actions.py +963 -0
- batplot-1.8.41/batplot/plot_modes/cpc/colors.py +363 -0
- batplot-1.8.41/batplot/plot_modes/cpc/interactive.py +2822 -0
- batplot-1.8.41/batplot/plot_modes/cpc/labels.py +257 -0
- batplot-1.8.41/batplot/plot_modes/cpc/legend.py +480 -0
- batplot-1.8.41/batplot/plot_modes/cpc/menu.py +74 -0
- batplot-1.8.41/batplot/plot_modes/cpc/routing.py +516 -0
- batplot-1.8.41/batplot/plot_modes/cpc/session.py +15 -0
- batplot-1.8.41/batplot/plot_modes/cpc/snapshots.py +119 -0
- batplot-1.8.41/batplot/plot_modes/electrochem/__init__.py +5 -0
- batplot-1.8.41/batplot/plot_modes/electrochem/actions.py +1246 -0
- batplot-1.8.41/batplot/plot_modes/electrochem/colors.py +722 -0
- batplot-1.8.41/batplot/plot_modes/electrochem/dqdv_2d.py +689 -0
- batplot-1.8.41/batplot/plot_modes/electrochem/export.py +65 -0
- batplot-1.8.41/batplot/plot_modes/electrochem/interactive.py +3220 -0
- batplot-1.8.41/batplot/plot_modes/electrochem/labels.py +224 -0
- batplot-1.8.41/batplot/plot_modes/electrochem/legend.py +269 -0
- batplot-1.8.41/batplot/plot_modes/electrochem/legend_order.py +56 -0
- batplot-1.8.41/batplot/plot_modes/electrochem/line_style.py +269 -0
- batplot-1.8.41/batplot/plot_modes/electrochem/menu.py +111 -0
- batplot-1.8.41/batplot/plot_modes/electrochem/routing.py +1540 -0
- batplot-1.8.41/batplot/plot_modes/electrochem/session.py +15 -0
- batplot-1.8.41/batplot/plot_modes/electrochem/spine_colors.py +108 -0
- batplot-1.8.41/batplot/plot_modes/electrochem/style.py +651 -0
- batplot-1.8.41/batplot/plot_modes/operando/__init__.py +5 -0
- batplot-1.8.41/batplot/plot_modes/operando/actions.py +1565 -0
- batplot-1.8.41/batplot/plot_modes/operando/colors.py +174 -0
- batplot-1.8.41/batplot/plot_modes/operando/grid.py +127 -0
- batplot-1.8.41/batplot/plot_modes/operando/interactive.py +3761 -0
- batplot-1.8.41/batplot/plot_modes/operando/ions_axis.py +141 -0
- batplot-1.8.41/batplot/plot_modes/operando/labels.py +173 -0
- batplot-1.8.41/batplot/plot_modes/operando/layout.py +409 -0
- batplot-1.8.41/batplot/plot_modes/operando/line_style.py +103 -0
- batplot-1.8.41/batplot/plot_modes/operando/menu.py +114 -0
- batplot-1.8.41/batplot/plot_modes/operando/peaks.py +289 -0
- batplot-1.8.39/batplot/operando.py → batplot-1.8.41/batplot/plot_modes/operando/plot.py +58 -8
- batplot-1.8.41/batplot/plot_modes/operando/routing.py +148 -0
- batplot-1.8.41/batplot/plot_modes/operando/session.py +15 -0
- batplot-1.8.41/batplot/plot_modes/operando/style.py +389 -0
- batplot-1.8.41/batplot/plot_modes/operando/visibility.py +285 -0
- batplot-1.8.41/batplot/plot_modes/session_routing.py +1072 -0
- batplot-1.8.41/batplot/plot_modes/xy/__init__.py +5 -0
- batplot-1.8.41/batplot/plot_modes/xy/actions.py +483 -0
- batplot-1.8.41/batplot/plot_modes/xy/arrange.py +131 -0
- batplot-1.8.41/batplot/plot_modes/xy/axis_range.py +624 -0
- batplot-1.8.41/batplot/plot_modes/xy/cif.py +465 -0
- batplot-1.8.41/batplot/plot_modes/xy/colors.py +336 -0
- batplot-1.8.41/batplot/plot_modes/xy/data_ops.py +114 -0
- batplot-1.8.41/batplot/plot_modes/xy/derivative.py +128 -0
- batplot-1.8.41/batplot/plot_modes/xy/game.py +125 -0
- batplot-1.8.41/batplot/plot_modes/xy/interactive.py +2441 -0
- batplot-1.8.41/batplot/plot_modes/xy/labels.py +160 -0
- batplot-1.8.41/batplot/plot_modes/xy/line_style.py +257 -0
- batplot-1.8.41/batplot/plot_modes/xy/menu.py +49 -0
- batplot-1.8.41/batplot/plot_modes/xy/peaks.py +174 -0
- batplot-1.8.41/batplot/plot_modes/xy/pipeline.py +1470 -0
- batplot-1.8.41/batplot/plot_modes/xy/session.py +15 -0
- batplot-1.8.41/batplot/plot_modes/xy/smoothing.py +716 -0
- {batplot-1.8.39/batplot → batplot-1.8.41/batplot/plot_modes/xy}/style.py +76 -110
- {batplot-1.8.39 → batplot-1.8.41}/batplot/plotting.py +32 -1
- {batplot-1.8.39 → batplot-1.8.41}/batplot/readers.py +50 -2
- {batplot-1.8.39 → batplot-1.8.41}/batplot/session.py +773 -433
- {batplot-1.8.39 → batplot-1.8.41}/batplot/showcol.py +8 -7
- batplot-1.8.41/batplot/style.py +19 -0
- {batplot-1.8.39 → batplot-1.8.41}/batplot/ui.py +150 -3
- {batplot-1.8.39 → batplot-1.8.41}/batplot/utils.py +52 -0
- {batplot-1.8.39 → batplot-1.8.41}/batplot/version_check.py +3 -2
- {batplot-1.8.39 → batplot-1.8.41/batplot.egg-info}/PKG-INFO +10 -8
- batplot-1.8.41/batplot.egg-info/SOURCES.txt +121 -0
- {batplot-1.8.39 → batplot-1.8.41}/batplot.egg-info/entry_points.txt +0 -1
- {batplot-1.8.39 → batplot-1.8.41}/batplot.egg-info/requires.txt +4 -0
- batplot-1.8.41/batplot.egg-info/top_level.txt +1 -0
- {batplot-1.8.39 → batplot-1.8.41}/pyproject.toml +24 -2
- batplot-1.8.41/tests/test_cli_smoke.py +183 -0
- batplot-1.8.41/tests/test_common_files.py +60 -0
- batplot-1.8.41/tests/test_common_palettes.py +209 -0
- batplot-1.8.41/tests/test_contracts.py +402 -0
- batplot-1.8.41/tests/test_cpc_roundtrip.py +458 -0
- batplot-1.8.41/tests/test_csv_readers.py +38 -0
- batplot-1.8.41/tests/test_dev_upgrade.py +163 -0
- batplot-1.8.41/tests/test_ec_roundtrip.py +553 -0
- batplot-1.8.41/tests/test_interactive_menu_smoke.py +236 -0
- batplot-1.8.41/tests/test_interactive_state.py +822 -0
- batplot-1.8.41/tests/test_operando_roundtrip.py +696 -0
- batplot-1.8.41/tests/test_xy_modules.py +246 -0
- batplot-1.8.41/tests/test_xy_roundtrip.py +267 -0
- batplot-1.8.39/MANIFEST.in +0 -2
- batplot-1.8.39/batplot/__init__.py +0 -5
- batplot-1.8.39/batplot/batplot.py +0 -5070
- batplot-1.8.39/batplot/cpc_interactive.py +0 -5677
- batplot-1.8.39/batplot/data/USER_MANUAL.md +0 -624
- batplot-1.8.39/batplot/electrochem_interactive.py +0 -6831
- batplot-1.8.39/batplot/interactive.py +0 -6353
- batplot-1.8.39/batplot/manual.py +0 -342
- batplot-1.8.39/batplot/modes.py +0 -862
- batplot-1.8.39/batplot/operando_ec_interactive.py +0 -7104
- batplot-1.8.39/batplot.egg-info/SOURCES.txt +0 -40
- batplot-1.8.39/batplot.egg-info/top_level.txt +0 -2
- {batplot-1.8.39 → batplot-1.8.41}/LICENSE +0 -0
- {batplot-1.8.39 → batplot-1.8.41}/NOTICE +0 -0
- {batplot-1.8.39 → batplot-1.8.41}/batplot/cif.py +0 -0
- {batplot-1.8.39 → batplot-1.8.41}/batplot/cli.py +0 -0
- {batplot-1.8.39 → batplot-1.8.41}/batplot/converters.py +0 -0
- {batplot-1.8.39 → batplot-1.8.41}/batplot.egg-info/dependency_links.txt +0 -0
- {batplot-1.8.39 → batplot-1.8.41}/setup.cfg +0 -0
- {batplot-1.8.39 → batplot-1.8.41}/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.41
|
|
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
|
|
@@ -47,6 +47,9 @@ Requires-Dist: numpy>=1.21.0
|
|
|
47
47
|
Requires-Dist: matplotlib>=3.5.0
|
|
48
48
|
Requires-Dist: rich>=10.0.0
|
|
49
49
|
Requires-Dist: openpyxl>=3.0.0
|
|
50
|
+
Provides-Extra: test
|
|
51
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
52
|
+
Requires-Dist: basedpyright>=1.28.0; extra == "test"
|
|
50
53
|
Dynamic: license-file
|
|
51
54
|
|
|
52
55
|
# batplot
|
|
@@ -213,7 +216,6 @@ batplot battery.mpt --gc --mass 7.0 --i
|
|
|
213
216
|
|
|
214
217
|
```bash
|
|
215
218
|
batplot cyclic.mpt --cv --i
|
|
216
|
-
batplot cyclic.mpt --cv --i
|
|
217
219
|
```
|
|
218
220
|
|
|
219
221
|
### Differential capacity (dQ/dV)
|
|
@@ -356,12 +358,12 @@ With `--interactive`:
|
|
|
356
358
|
## Help & Documentation
|
|
357
359
|
|
|
358
360
|
```bash
|
|
359
|
-
batplot --
|
|
360
|
-
batplot --
|
|
361
|
-
batplot --
|
|
362
|
-
batplot --
|
|
363
|
-
batplot --
|
|
364
|
-
batplot --
|
|
361
|
+
batplot --h # General help
|
|
362
|
+
batplot --h xy # XY mode guide
|
|
363
|
+
batplot --h ec # Electrochemistry guide
|
|
364
|
+
batplot --h op # Operando guide
|
|
365
|
+
batplot --v # Version and release notes
|
|
366
|
+
batplot --m # Open illustrated manual
|
|
365
367
|
```
|
|
366
368
|
|
|
367
369
|
- [USER_MANUAL.md](USER_MANUAL.md) — Detailed usage and workflows
|
|
@@ -162,7 +162,6 @@ batplot battery.mpt --gc --mass 7.0 --i
|
|
|
162
162
|
|
|
163
163
|
```bash
|
|
164
164
|
batplot cyclic.mpt --cv --i
|
|
165
|
-
batplot cyclic.mpt --cv --i
|
|
166
165
|
```
|
|
167
166
|
|
|
168
167
|
### Differential capacity (dQ/dV)
|
|
@@ -305,12 +304,12 @@ With `--interactive`:
|
|
|
305
304
|
## Help & Documentation
|
|
306
305
|
|
|
307
306
|
```bash
|
|
308
|
-
batplot --
|
|
309
|
-
batplot --
|
|
310
|
-
batplot --
|
|
311
|
-
batplot --
|
|
312
|
-
batplot --
|
|
313
|
-
batplot --
|
|
307
|
+
batplot --h # General help
|
|
308
|
+
batplot --h xy # XY mode guide
|
|
309
|
+
batplot --h ec # Electrochemistry guide
|
|
310
|
+
batplot --h op # Operando guide
|
|
311
|
+
batplot --v # Version and release notes
|
|
312
|
+
batplot --m # Open illustrated manual
|
|
314
313
|
```
|
|
315
314
|
|
|
316
315
|
- [USER_MANUAL.md](USER_MANUAL.md) — Detailed usage and workflows
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""batplot: Interactive plotting for battery data visualization."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import importlib
|
|
6
|
+
import importlib.abc
|
|
7
|
+
import importlib.machinery
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
__version__ = "1.8.41"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
_LEGACY_MODULE_ALIASES = {
|
|
14
|
+
"batplot.interactive": "batplot.plot_modes.xy.interactive",
|
|
15
|
+
"batplot.electrochem_interactive": "batplot.plot_modes.electrochem.interactive",
|
|
16
|
+
"batplot.cpc_interactive": "batplot.plot_modes.cpc.interactive",
|
|
17
|
+
"batplot.cpc_menu": "batplot.plot_modes.cpc.menu",
|
|
18
|
+
"batplot.operando_ec_interactive": "batplot.plot_modes.operando.interactive",
|
|
19
|
+
"batplot.operando_layout": "batplot.plot_modes.operando.layout",
|
|
20
|
+
"batplot.operando_menu": "batplot.plot_modes.operando.menu",
|
|
21
|
+
"batplot.operando_style": "batplot.plot_modes.operando.style",
|
|
22
|
+
"batplot.interactive_state": "batplot.plot_modes.common.interactive_state",
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class _LegacyModuleAliasLoader(importlib.abc.Loader):
|
|
27
|
+
"""Lazy compatibility loader for mode modules moved under ``plot_modes``."""
|
|
28
|
+
|
|
29
|
+
def __init__(self, fullname: str, target_name: str):
|
|
30
|
+
self.fullname = fullname
|
|
31
|
+
self.target_name = target_name
|
|
32
|
+
|
|
33
|
+
def create_module(self, spec):
|
|
34
|
+
module = importlib.import_module(self.target_name)
|
|
35
|
+
self._apply_extra_exports(module)
|
|
36
|
+
sys.modules[self.fullname] = module
|
|
37
|
+
parent_name, _, child_name = self.fullname.rpartition(".")
|
|
38
|
+
parent = sys.modules.get(parent_name)
|
|
39
|
+
if parent is not None:
|
|
40
|
+
setattr(parent, child_name, module)
|
|
41
|
+
return module
|
|
42
|
+
|
|
43
|
+
def exec_module(self, module) -> None:
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
def _apply_extra_exports(self, module) -> None:
|
|
47
|
+
if self.fullname == "batplot.cpc_interactive":
|
|
48
|
+
menu = importlib.import_module("batplot.plot_modes.cpc.menu")
|
|
49
|
+
module.print_cpc_menu = menu.print_cpc_menu
|
|
50
|
+
module.build_cpc_menu_columns = menu.build_cpc_menu_columns
|
|
51
|
+
elif self.fullname == "batplot.operando_ec_interactive":
|
|
52
|
+
style = importlib.import_module("batplot.plot_modes.operando.style")
|
|
53
|
+
module.build_operando_ec_style_config_v2 = style.build_operando_ec_style_config_v2
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class _LegacyModuleAliasFinder(importlib.abc.MetaPathFinder):
|
|
57
|
+
def find_spec(self, fullname, path=None, target=None):
|
|
58
|
+
target_name = _LEGACY_MODULE_ALIASES.get(fullname)
|
|
59
|
+
if target_name is None:
|
|
60
|
+
return None
|
|
61
|
+
loader = _LegacyModuleAliasLoader(fullname, target_name)
|
|
62
|
+
spec = importlib.machinery.ModuleSpec(fullname, loader)
|
|
63
|
+
spec.origin = f"legacy-alias:{target_name}"
|
|
64
|
+
return spec
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _install_legacy_alias_finder() -> None:
|
|
68
|
+
if not any(isinstance(finder, _LegacyModuleAliasFinder) for finder in sys.meta_path):
|
|
69
|
+
sys.meta_path.insert(0, _LegacyModuleAliasFinder())
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
_install_legacy_alias_finder()
|
|
73
|
+
|
|
74
|
+
__all__ = ["__version__"]
|
|
@@ -24,6 +24,7 @@ from __future__ import annotations
|
|
|
24
24
|
import argparse
|
|
25
25
|
import sys
|
|
26
26
|
import re
|
|
27
|
+
import webbrowser
|
|
27
28
|
|
|
28
29
|
# ====================================================================
|
|
29
30
|
# HELP OUTPUT
|
|
@@ -37,6 +38,8 @@ import re
|
|
|
37
38
|
#
|
|
38
39
|
# If rich is not installed, we fall back to plain text (still works fine).
|
|
39
40
|
# ====================================================================
|
|
41
|
+
from .utils import parse_mass_mg_from_cli
|
|
42
|
+
|
|
40
43
|
try:
|
|
41
44
|
from rich.console import Console # type: ignore[import]
|
|
42
45
|
from rich.markup import escape # type: ignore[import]
|
|
@@ -167,13 +170,13 @@ def _print_general_help() -> None:
|
|
|
167
170
|
" • More: --help xy / --help ec / --help op\n\n"
|
|
168
171
|
|
|
169
172
|
"More help:\n"
|
|
170
|
-
" batplot --
|
|
173
|
+
" batplot --v # Version and release info (with option to show full release notes)\n"
|
|
171
174
|
" batplot --showcol FILE [FILE...] # Preview column names + first 10 values per column\n"
|
|
172
|
-
" batplot --
|
|
173
|
-
" batplot --
|
|
174
|
-
" batplot --
|
|
175
|
-
" batplot --
|
|
176
|
-
" batplot --
|
|
175
|
+
" batplot --h # This help\n"
|
|
176
|
+
" batplot --h xy # XY file plotting guide\n"
|
|
177
|
+
" batplot --h ec # Electrochemistry (GC/dQdV/CV/CPC) guide\n"
|
|
178
|
+
" batplot --h op # Operando contour guide (also: batplot --help contour)\n"
|
|
179
|
+
" batplot --m # Open the illustrated PDF manual\n\n"
|
|
177
180
|
|
|
178
181
|
"Contact & Updates:\n"
|
|
179
182
|
" Subscribe to batplot-lab@kjemi.uio.no for updates\n"
|
|
@@ -244,10 +247,14 @@ def _print_xy_help() -> None:
|
|
|
244
247
|
" - file:wl : single wavelength (for Q conversion or CIF 2theta calculation)\n"
|
|
245
248
|
" - file:wl1:wl2 : dual wavelength (convert 2theta→Q using wl1, then Q→2theta using wl2)\n"
|
|
246
249
|
" - file.cif:wl : CIF file with wavelength for 2theta tick calculation\n"
|
|
250
|
+
" - file:q : mark file as already in Q (no conversion; implies Q axis)\n"
|
|
251
|
+
" Any file:wl or file:q suffix implies Q mode automatically (no --xaxis q needed);\n"
|
|
252
|
+
" files without wavelength info are then assumed to be already in Q.\n"
|
|
247
253
|
" Examples:\n"
|
|
248
254
|
" batplot data.xye:1.5406 --xaxis 2theta\n"
|
|
249
255
|
" batplot data.xye:0.25:1.54 --xaxis 2theta\n"
|
|
250
256
|
" batplot data.xye pattern.cif:0.25448 --xaxis 2theta\n"
|
|
257
|
+
" batplot scan.xy:0.709 sim.csv:q --stack --i\n"
|
|
251
258
|
" --readcol <x_col> <y_col> : specify which columns to read as x and y (1-indexed)\n"
|
|
252
259
|
" Per-file: file1.xy --readcol 2 3 file2.xy --readcol 4 5 (different cols per file)\n"
|
|
253
260
|
" Multi-curve: file.xy --readcol 1 2 1 3 (plot cols 1,2 and 1,3 as two curves)\n"
|
|
@@ -278,8 +285,9 @@ def _print_ec_help() -> None:
|
|
|
278
285
|
" • Neware: Customized report — check all boxes\n"
|
|
279
286
|
" • Biologic: Export all info to .mpt file\n\n"
|
|
280
287
|
"Use --i for styling, colors, line widths, axis scales, etc.\n"
|
|
281
|
-
"GC from .mpt: requires active mass
|
|
282
|
-
" batplot --gc file.mpt --mass 6.5 --i\n
|
|
288
|
+
"GC from .mpt or .npt: requires active mass to compute mAh g⁻¹ (default unit: mg; use a ``g`` suffix for grams, e.g. --mass 0.0065g).\n"
|
|
289
|
+
" batplot --gc file.mpt --mass 6.5 --i\n"
|
|
290
|
+
" batplot --gc file.npt --mass 10g --i\n\n"
|
|
283
291
|
"GC from supported .csv: specific capacity read directly when available; use --mass for\n"
|
|
284
292
|
" Neware absolute-capacity files (Cycle Index / Step Index / DataPoint format).\n"
|
|
285
293
|
" batplot --gc file.csv\n"
|
|
@@ -289,9 +297,11 @@ def _print_ec_help() -> None:
|
|
|
289
297
|
" batplot f1.csv --mass 3.52 f2.mpt --mass 5.0 --cpc\n"
|
|
290
298
|
" # Files without --mass between them use the global --mass value (or none)\n"
|
|
291
299
|
" # Single --mass applies to all files: batplot f1.mpt f2.mpt --gc --mass 7.0\n\n"
|
|
292
|
-
"dQ/dV from supported .csv (pre-calculated column or computed from GC data):\n"
|
|
300
|
+
"dQ/dV from supported .csv (pre-calculated column or computed from GC data), or from Biologic .mpt/.npt (numerical dQ/dV from GC; requires --mass):\n"
|
|
293
301
|
" batplot --dqdv file.csv\n"
|
|
294
|
-
" batplot --dqdv file.csv --mass 3.52 # Neware absolute-capacity CSV\n
|
|
302
|
+
" batplot --dqdv file.csv --mass 3.52 # Neware absolute-capacity CSV\n"
|
|
303
|
+
" batplot --dqdv file.mpt --mass 6.5\n"
|
|
304
|
+
" batplot --dqdv file.npt --mass 0.01g\n\n"
|
|
295
305
|
"Cyclic voltammetry (CV) from .mpt or .txt: plots potential vs current for each cycle.\n"
|
|
296
306
|
" batplot --cv file.mpt\n"
|
|
297
307
|
" batplot --cv file.txt\n\n"
|
|
@@ -300,7 +310,7 @@ def _print_ec_help() -> None:
|
|
|
300
310
|
" batplot --cpc file.csv # Neware CSV (specific capacity)\n"
|
|
301
311
|
" batplot --cpc file.csv --mass 3.52 # Neware absolute-capacity CSV\n"
|
|
302
312
|
" batplot --cpc file.xlsx # Landt/Lanhe Excel (Chinese tester)\n"
|
|
303
|
-
" batplot --cpc file.mpt --mass 1.2 # Biologic
|
|
313
|
+
" batplot --cpc file.mpt --mass 1.2 # Biologic .mpt / .npt\n"
|
|
304
314
|
" batplot file1.csv --mass 3.52 file2.mpt --mass 1.2 --cpc # Per-file mass\n"
|
|
305
315
|
" batplot --cpc file1.csv file2.xlsx file3.mpt --mass 1.2 --i\n\n"
|
|
306
316
|
"Excel support: Landt/Lanhe (蓝电/蓝河) .xlsx files with Chinese headers:\n"
|
|
@@ -342,6 +352,8 @@ def _print_op_help() -> None:
|
|
|
342
352
|
" batplot --operando --xaxis 2theta # Using 2theta axis\n"
|
|
343
353
|
" batplot --operando --1d --i # Plot derivatives as contour with interactive menu\n"
|
|
344
354
|
" batplot --operando --2d --i # Plot derivatives (alias for --1d)\n\n"
|
|
355
|
+
" batplot --operando --average 2 --i # Average every 2 scans before contouring\n\n"
|
|
356
|
+
" batplot --operando --sum 2 --i # Sum every 2 scans to boost intensity\n\n"
|
|
345
357
|
"Bruker operando (.brml):\n"
|
|
346
358
|
" • Place .brml files (e.g. XX_cyc1.brml, XX_cyc2.brml) in the folder.\n"
|
|
347
359
|
" • Each .brml is expanded into per-scan rows; files sorted by cyc1/cyc2/cyc3.\n"
|
|
@@ -355,6 +367,8 @@ def _print_op_help() -> None:
|
|
|
355
367
|
" • If a .mpt file is present, a side panel is added for dual-panel mode (time/potential/temp/etc.).\n"
|
|
356
368
|
" • Without a .mpt file, operando-only mode shows the contour plot alone.\n"
|
|
357
369
|
" • --1d / --2d: plot the first derivative (dy/dx) of each scan as a contour plot.\n\n"
|
|
370
|
+
" • --average N: average every N consecutive scans to improve S/N (e.g., N=2 averages scans 1+2, 3+4, ...).\n\n"
|
|
371
|
+
" • --sum N: sum every N consecutive scans (same binning as --average, but without division by N).\n\n"
|
|
358
372
|
"Column selection (operando-specific):\n"
|
|
359
373
|
" --readcolc <x> <y> : columns for contour plot (x,y in .xy/.xye/.qye/.dat files)\n"
|
|
360
374
|
" --readcols <x> <y> : columns for side panel (x,y in .mpt file)\n"
|
|
@@ -366,58 +380,10 @@ def _print_op_help() -> None:
|
|
|
366
380
|
_print_help(msg)
|
|
367
381
|
|
|
368
382
|
|
|
369
|
-
def
|
|
370
|
-
"""
|
|
371
|
-
Build the argument parser for batplot command-line interface.
|
|
372
|
-
|
|
373
|
-
HOW ARGUMENT PARSING WORKS:
|
|
374
|
-
--------------------------
|
|
375
|
-
This function creates an ArgumentParser object that defines all valid
|
|
376
|
-
command-line arguments for batplot. When you run 'batplot file.xy --i',
|
|
377
|
-
argparse uses this parser to:
|
|
378
|
-
1. Recognize which arguments are valid
|
|
379
|
-
2. Extract values from the command line
|
|
380
|
-
3. Convert them to appropriate Python types (int, float, bool, etc.)
|
|
381
|
-
4. Store them in a namespace object (args.files, args.interactive, etc.)
|
|
382
|
-
|
|
383
|
-
ARGUMENT TYPES:
|
|
384
|
-
--------------
|
|
385
|
-
- Positional arguments: 'files' - list of file paths (can be 0 or more)
|
|
386
|
-
- Flags (boolean): '--i' - True if present, False if absent
|
|
387
|
-
- Options with values: '--mass 7.0' - requires a value (float in this case)
|
|
388
|
-
- Optional arguments: '--help xy' - can have optional value
|
|
389
|
-
|
|
390
|
-
WHY add_help=False?
|
|
391
|
-
-------------------
|
|
392
|
-
We use a custom help system that supports topic-specific help:
|
|
393
|
-
- 'batplot --help' → general help
|
|
394
|
-
- 'batplot --help xy' → XY mode help
|
|
395
|
-
- 'batplot --help ec' → EC mode help
|
|
396
|
-
- 'batplot --help op' → Operando mode help
|
|
397
|
-
|
|
398
|
-
This gives users more targeted help instead of one giant help page.
|
|
399
|
-
|
|
400
|
-
Returns:
|
|
401
|
-
Configured ArgumentParser object ready to parse command-line arguments
|
|
402
|
-
"""
|
|
403
|
-
# Create parser with custom help system (we handle help ourselves)
|
|
404
|
-
parser = argparse.ArgumentParser(add_help=False)
|
|
405
|
-
|
|
406
|
-
# ====================================================================
|
|
407
|
-
# TOPIC-AWARE HELP SYSTEM
|
|
408
|
-
# ====================================================================
|
|
409
|
-
# Instead of standard --help, we support topic-specific help:
|
|
410
|
-
# batplot --help → general help
|
|
411
|
-
# batplot --help xy → XY mode help
|
|
412
|
-
# batplot --help ec → EC mode help
|
|
413
|
-
# batplot --help op → Operando mode help
|
|
414
|
-
#
|
|
415
|
-
# nargs="?" means the argument is optional:
|
|
416
|
-
# - If not provided: const="" (empty string)
|
|
417
|
-
# - If provided: uses the value (e.g., "xy", "ec", "op")
|
|
418
|
-
# ====================================================================
|
|
383
|
+
def _add_help_and_entry_arguments(parser: argparse.ArgumentParser) -> None:
|
|
384
|
+
"""Register help/version/manual flags and positional file inputs."""
|
|
419
385
|
parser.add_argument("--help", nargs="?", const="", metavar="topic",
|
|
420
|
-
help=argparse.SUPPRESS)
|
|
386
|
+
help=argparse.SUPPRESS)
|
|
421
387
|
parser.add_argument("--version", action="store_true", dest="version",
|
|
422
388
|
help="Show version and current release info, then exit.")
|
|
423
389
|
parser.add_argument(
|
|
@@ -426,18 +392,11 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
426
392
|
help=argparse.SUPPRESS,
|
|
427
393
|
)
|
|
428
394
|
parser.add_argument("--manual", action="store_true", help=argparse.SUPPRESS)
|
|
429
|
-
|
|
430
|
-
# ====================================================================
|
|
431
|
-
# POSITIONAL ARGUMENTS (FILE PATHS)
|
|
432
|
-
# ====================================================================
|
|
433
|
-
# 'files' is a positional argument, meaning it doesn't need a flag.
|
|
434
|
-
# nargs="*" means it accepts 0 or more values (list).
|
|
435
|
-
# Examples:
|
|
436
|
-
# batplot file1.xy file2.xy → args.files = ['file1.xy', 'file2.xy']
|
|
437
|
-
# batplot allfiles → args.files = ['allfiles']
|
|
438
|
-
# batplot --i → args.files = [] (empty list)
|
|
439
|
-
# ====================================================================
|
|
440
395
|
parser.add_argument("files", nargs="*", help=argparse.SUPPRESS)
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def _add_xy_arguments(parser: argparse.ArgumentParser) -> None:
|
|
399
|
+
"""Register XY/general plotting arguments."""
|
|
441
400
|
parser.add_argument("--delta", type=float, default=None, help=argparse.SUPPRESS)
|
|
442
401
|
parser.add_argument("--autoscale", action="store_true", help=argparse.SUPPRESS)
|
|
443
402
|
parser.add_argument("--xrange", nargs=2, type=float, help=argparse.SUPPRESS)
|
|
@@ -455,15 +414,31 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
455
414
|
parser.add_argument("--kchik", action="store_true", help=argparse.SUPPRESS)
|
|
456
415
|
parser.add_argument("--k2chik", action="store_true", help=argparse.SUPPRESS)
|
|
457
416
|
parser.add_argument("--k3chik", action="store_true", help=argparse.SUPPRESS)
|
|
417
|
+
parser.add_argument("--1d", action="store_true", dest="derivative_1d", help=argparse.SUPPRESS)
|
|
418
|
+
parser.add_argument("--2d", action="store_true", dest="derivative_2d", help=argparse.SUPPRESS)
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def _add_interactive_export_arguments(parser: argparse.ArgumentParser) -> None:
|
|
422
|
+
"""Register interactive, export, and batch-output arguments."""
|
|
458
423
|
parser.add_argument("--i", "--interactive", action="store_true", dest="interactive", help=argparse.SUPPRESS)
|
|
459
424
|
parser.add_argument("--savefig", type=str, help=argparse.SUPPRESS)
|
|
460
425
|
parser.add_argument("--stack", action="store_true", help=argparse.SUPPRESS)
|
|
461
426
|
parser.add_argument("--ry", action="store_true", help=argparse.SUPPRESS)
|
|
462
427
|
parser.add_argument("--txaxis", action="store_true", help=argparse.SUPPRESS)
|
|
463
|
-
parser.add_argument("--operando", "--contour", action="store_true", dest="operando", help=argparse.SUPPRESS)
|
|
464
428
|
parser.add_argument("--debug", action="store_true", help=argparse.SUPPRESS)
|
|
429
|
+
parser.add_argument("--ro", action="store_true", help=argparse.SUPPRESS)
|
|
430
|
+
parser.add_argument("--all", type=str, nargs='?', const='all', help=argparse.SUPPRESS)
|
|
431
|
+
parser.add_argument("--format", type=str, default='svg',
|
|
432
|
+
choices=['svg', 'png', 'pdf', 'jpg', 'jpeg', 'eps', 'tif', 'tiff'],
|
|
433
|
+
help=argparse.SUPPRESS)
|
|
434
|
+
parser.add_argument("--canvas", action="store_true", dest="canvas",
|
|
435
|
+
help="Canvas mode: combine multiple .pkl sessions into one layout. Use numbers to edit each panel.")
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
def _add_electrochem_arguments(parser: argparse.ArgumentParser) -> None:
|
|
439
|
+
"""Register electrochemistry mode arguments."""
|
|
465
440
|
parser.add_argument("--gc", action="store_true", help=argparse.SUPPRESS)
|
|
466
|
-
parser.add_argument("--mass", type=
|
|
441
|
+
parser.add_argument("--mass", type=parse_mass_mg_from_cli, action='append', help=argparse.SUPPRESS)
|
|
467
442
|
parser.add_argument("--dqdv", action="store_true", help=argparse.SUPPRESS)
|
|
468
443
|
parser.add_argument("--cv", action="store_true", help=argparse.SUPPRESS)
|
|
469
444
|
parser.add_argument("--cpc", action="store_true", help=argparse.SUPPRESS)
|
|
@@ -475,14 +450,19 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
475
450
|
help=argparse.SUPPRESS)
|
|
476
451
|
parser.add_argument("--anode", action="store_true", help=argparse.SUPPRESS)
|
|
477
452
|
parser.add_argument("--cathode", action="store_true", help=argparse.SUPPRESS)
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
def _add_operando_arguments(parser: argparse.ArgumentParser) -> None:
|
|
456
|
+
"""Register operando contour arguments."""
|
|
457
|
+
parser.add_argument("--operando", "--contour", action="store_true", dest="operando", help=argparse.SUPPRESS)
|
|
458
|
+
parser.add_argument("--average", type=int, help=argparse.SUPPRESS)
|
|
459
|
+
parser.add_argument("--sum", dest="scan_sum", type=int, help=argparse.SUPPRESS)
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
def _add_read_column_arguments(parser: argparse.ArgumentParser) -> None:
|
|
463
|
+
"""Register column-selection arguments."""
|
|
483
464
|
parser.add_argument("--readcol", nargs=2, type=int, metavar=('X_COL', 'Y_COL'),
|
|
484
465
|
help=argparse.SUPPRESS)
|
|
485
|
-
# Add extension-specific readcol arguments
|
|
486
466
|
parser.add_argument("--readcolxy", nargs=2, type=int, metavar=('X_COL', 'Y_COL'),
|
|
487
467
|
help=argparse.SUPPRESS)
|
|
488
468
|
parser.add_argument("--readcolxye", nargs=2, type=int, metavar=('X_COL', 'Y_COL'),
|
|
@@ -499,10 +479,51 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
499
479
|
help=argparse.SUPPRESS)
|
|
500
480
|
parser.add_argument("--readcols", nargs=2, type=int, metavar=('X_COL', 'Y_COL'),
|
|
501
481
|
help=argparse.SUPPRESS)
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
485
|
+
"""
|
|
486
|
+
Build the argument parser for batplot command-line interface.
|
|
487
|
+
|
|
488
|
+
HOW ARGUMENT PARSING WORKS:
|
|
489
|
+
--------------------------
|
|
490
|
+
This function creates an ArgumentParser object that defines all valid
|
|
491
|
+
command-line arguments for batplot. When you run 'batplot file.xy --i',
|
|
492
|
+
argparse uses this parser to:
|
|
493
|
+
1. Recognize which arguments are valid
|
|
494
|
+
2. Extract values from the command line
|
|
495
|
+
3. Convert them to appropriate Python types (int, float, bool, etc.)
|
|
496
|
+
4. Store them in a namespace object (args.files, args.interactive, etc.)
|
|
497
|
+
|
|
498
|
+
ARGUMENT TYPES:
|
|
499
|
+
--------------
|
|
500
|
+
- Positional arguments: 'files' - list of file paths (can be 0 or more)
|
|
501
|
+
- Flags (boolean): '--i' - True if present, False if absent
|
|
502
|
+
- Options with values: '--mass 7.0' or '--mass 0.01g' - mass in mg, or grams with a ``g`` suffix
|
|
503
|
+
- Optional arguments: '--help xy' - can have optional value
|
|
504
|
+
|
|
505
|
+
WHY add_help=False?
|
|
506
|
+
-------------------
|
|
507
|
+
We use a custom help system that supports topic-specific help:
|
|
508
|
+
- 'batplot --help' → general help
|
|
509
|
+
- 'batplot --help xy' → XY mode help
|
|
510
|
+
- 'batplot --help ec' → EC mode help
|
|
511
|
+
- 'batplot --help op' → Operando mode help
|
|
512
|
+
|
|
513
|
+
This gives users more targeted help instead of one giant help page.
|
|
514
|
+
|
|
515
|
+
Returns:
|
|
516
|
+
Configured ArgumentParser object ready to parse command-line arguments
|
|
517
|
+
"""
|
|
518
|
+
# Create parser with custom help system (we handle help ourselves)
|
|
519
|
+
parser = argparse.ArgumentParser(add_help=False)
|
|
520
|
+
|
|
521
|
+
_add_help_and_entry_arguments(parser)
|
|
522
|
+
_add_xy_arguments(parser)
|
|
523
|
+
_add_interactive_export_arguments(parser)
|
|
524
|
+
_add_operando_arguments(parser)
|
|
525
|
+
_add_electrochem_arguments(parser)
|
|
526
|
+
_add_read_column_arguments(parser)
|
|
506
527
|
return parser
|
|
507
528
|
|
|
508
529
|
|
|
@@ -700,18 +721,23 @@ def parse_args(argv=None):
|
|
|
700
721
|
# weren't in the parser yet when we built it
|
|
701
722
|
ns, _unknown = parser.parse_known_args(argv)
|
|
702
723
|
if getattr(ns, "manual", False):
|
|
724
|
+
manual_url = "https://github.com/chem-plot/batplot/blob/main/batplot_user_manual.pdf"
|
|
703
725
|
try:
|
|
704
|
-
|
|
705
|
-
open_manual_url()
|
|
726
|
+
opened = webbrowser.open(manual_url)
|
|
706
727
|
if _HAS_RICH and _console:
|
|
707
|
-
|
|
728
|
+
if opened:
|
|
729
|
+
_console.print("\n[green]Opened PDF manual in browser[/green]")
|
|
730
|
+
else:
|
|
731
|
+
_console.print(f"\n[yellow]Manual PDF:[/yellow] {manual_url}")
|
|
708
732
|
else:
|
|
709
|
-
print("\nOpened manual in browser")
|
|
733
|
+
print("\nOpened PDF manual in browser" if opened else f"\nManual PDF: {manual_url}")
|
|
710
734
|
except Exception as exc: # pragma: no cover - best effort
|
|
711
735
|
if _HAS_RICH and _console:
|
|
712
736
|
_console.print(f"\n[red]Failed to open manual:[/red] {exc}")
|
|
737
|
+
_console.print(f"[yellow]Manual PDF:[/yellow] {manual_url}")
|
|
713
738
|
else:
|
|
714
739
|
print(f"\nFailed to open manual: {exc}")
|
|
740
|
+
print(f"Manual PDF: {manual_url}")
|
|
715
741
|
sys.exit(0)
|
|
716
742
|
|
|
717
743
|
topic = getattr(ns, 'help', None)
|
|
@@ -28,6 +28,13 @@ from .readers import (
|
|
|
28
28
|
read_biologic_txt_file,
|
|
29
29
|
)
|
|
30
30
|
|
|
31
|
+
# BioLogic EC-Lab ASCII exports use ``.mpt``; ``.npt`` is accepted as the same format.
|
|
32
|
+
_MPT_LIKE_EXTS = frozenset({'.mpt', '.npt'})
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _is_mpt_like_ext(ext: str) -> bool:
|
|
36
|
+
return (ext or '').lower() in _MPT_LIKE_EXTS
|
|
37
|
+
|
|
31
38
|
|
|
32
39
|
def _resolve_mass(mass_arg, file_idx: int = 0):
|
|
33
40
|
"""Return mass (mg) for file at file_idx from a --mass list or single value."""
|
|
@@ -488,7 +495,7 @@ def batch_process(directory: str, args):
|
|
|
488
495
|
known_ext = {'.xye', '.xy', '.qye', '.dat', '.csv', '.gr', '.nor', '.chik', '.chir', '.txt', '.brml', '.raw', '.xrdml', '.rasx'}
|
|
489
496
|
|
|
490
497
|
# Extensions to exclude (not data files, or require special handling)
|
|
491
|
-
excluded_ext = {'.cif', '.pkl', '.py', '.md', '.json', '.yml', '.yaml', '.sh', '.bat', '.mpt'}
|
|
498
|
+
excluded_ext = {'.cif', '.pkl', '.py', '.md', '.json', '.yml', '.yaml', '.sh', '.bat', '.mpt', '.npt'}
|
|
492
499
|
|
|
493
500
|
# Create output directory for saved plots
|
|
494
501
|
out_dir = ensure_subdirectory('Figures', directory)
|
|
@@ -842,7 +849,7 @@ def batch_process(directory: str, args):
|
|
|
842
849
|
def batch_process_ec(directory: str, args):
|
|
843
850
|
"""Batch process electrochemistry files in a directory.
|
|
844
851
|
|
|
845
|
-
Supports GC (.mpt/.csv), CV (.mpt),
|
|
852
|
+
Supports GC (.mpt/.npt/.csv), CV (.mpt/.npt/.txt), dQ/dV (.mpt/.npt/.csv), and CPC (.mpt/.npt/.csv) modes.
|
|
846
853
|
Exports SVG plots to batplot_svg subdirectory.
|
|
847
854
|
|
|
848
855
|
Can apply style/geometry from .bps/.bpsg files using --all flag:
|
|
@@ -852,7 +859,7 @@ def batch_process_ec(directory: str, args):
|
|
|
852
859
|
batplot --all --cpc config.bpsg # Apply to all CPC files
|
|
853
860
|
|
|
854
861
|
Note: For GC and CPC modes with .csv files, --mass is not required as the
|
|
855
|
-
capacity data is already in the file. For .mpt files, --mass is required.
|
|
862
|
+
capacity data is already in the file. For .mpt/.npt files, --mass is required (mg by default; use a ``g`` suffix for grams, e.g. ``--mass 0.01g``).
|
|
856
863
|
|
|
857
864
|
Args:
|
|
858
865
|
directory: Directory containing EC files
|
|
@@ -906,19 +913,19 @@ def batch_process_ec(directory: str, args):
|
|
|
906
913
|
mode = None
|
|
907
914
|
if getattr(args, 'gc', False):
|
|
908
915
|
mode = 'gc'
|
|
909
|
-
supported_ext = {'.mpt', '.csv'}
|
|
916
|
+
supported_ext = {'.mpt', '.npt', '.csv'}
|
|
910
917
|
elif getattr(args, 'cv', False):
|
|
911
918
|
mode = 'cv'
|
|
912
|
-
supported_ext = {'.mpt', '.txt'}
|
|
919
|
+
supported_ext = {'.mpt', '.npt', '.txt'}
|
|
913
920
|
elif getattr(args, 'dqdv', False):
|
|
914
921
|
mode = 'dqdv'
|
|
915
|
-
supported_ext = {'.csv'}
|
|
922
|
+
supported_ext = {'.mpt', '.npt', '.csv'}
|
|
916
923
|
elif getattr(args, 'cpc', False):
|
|
917
924
|
mode = 'cpc'
|
|
918
|
-
supported_ext = {'.mpt', '.csv'}
|
|
925
|
+
supported_ext = {'.mpt', '.npt', '.csv'}
|
|
919
926
|
elif getattr(args, 'epc', False):
|
|
920
927
|
mode = 'epc'
|
|
921
|
-
supported_ext = {'.mpt', '.csv'}
|
|
928
|
+
supported_ext = {'.mpt', '.npt', '.csv'}
|
|
922
929
|
else:
|
|
923
930
|
print("EC batch mode requires one of: --gc, --cv, --dqdv, or --cpc")
|
|
924
931
|
return
|
|
@@ -1007,9 +1014,9 @@ def batch_process_ec(directory: str, args):
|
|
|
1007
1014
|
|
|
1008
1015
|
# ---- GC Mode ----
|
|
1009
1016
|
if mode == 'gc':
|
|
1010
|
-
if ext
|
|
1017
|
+
if _is_mpt_like_ext(ext):
|
|
1011
1018
|
if mass_mg is None:
|
|
1012
|
-
print(f" Skipped {fname}: GC mode (.mpt) requires --mass parameter")
|
|
1019
|
+
print(f" Skipped {fname}: GC mode (.mpt/.npt) requires --mass parameter")
|
|
1013
1020
|
plt.close(fig_b)
|
|
1014
1021
|
continue
|
|
1015
1022
|
specific_capacity, voltage, cycle_numbers, charge_mask, discharge_mask = cast(
|
|
@@ -1089,13 +1096,13 @@ def batch_process_ec(directory: str, args):
|
|
|
1089
1096
|
elif mode == 'cv':
|
|
1090
1097
|
if ext == '.txt':
|
|
1091
1098
|
voltage, current, cycles = read_biologic_txt_file(fpath, mode='cv')
|
|
1092
|
-
elif ext
|
|
1099
|
+
elif _is_mpt_like_ext(ext):
|
|
1093
1100
|
voltage, current, cycles = cast(
|
|
1094
1101
|
Tuple[np.ndarray, np.ndarray, np.ndarray],
|
|
1095
1102
|
read_mpt_file(fpath, mode='cv'),
|
|
1096
1103
|
)
|
|
1097
1104
|
else:
|
|
1098
|
-
raise ValueError("CV mode requires .mpt or .txt file")
|
|
1105
|
+
raise ValueError("CV mode requires .mpt, .npt, or .txt file")
|
|
1099
1106
|
|
|
1100
1107
|
cyc_int_raw = np.array(np.rint(cycles), dtype=int)
|
|
1101
1108
|
if cyc_int_raw.size:
|
|
@@ -1125,13 +1132,27 @@ def batch_process_ec(directory: str, args):
|
|
|
1125
1132
|
|
|
1126
1133
|
# ---- dQdV Mode ----
|
|
1127
1134
|
elif mode == 'dqdv':
|
|
1128
|
-
if ext != '.csv':
|
|
1129
|
-
raise ValueError("dQdV mode requires .csv file")
|
|
1130
|
-
|
|
1131
1135
|
# Try to load pre-calculated dQ/dV columns; fall back to numerical computation
|
|
1132
1136
|
_b_dqdv_header = None
|
|
1133
1137
|
_b_loaded = False
|
|
1134
|
-
if
|
|
1138
|
+
if _is_mpt_like_ext(ext):
|
|
1139
|
+
if mass_mg is None or mass_mg <= 0:
|
|
1140
|
+
print(f" Skipped {fname}: dQ/dV (.mpt/.npt) requires --mass parameter")
|
|
1141
|
+
plt.close(fig_b)
|
|
1142
|
+
continue
|
|
1143
|
+
_b_gc_cap, _b_gc_volt, _b_gc_cyc, _b_gc_chgm, _b_gc_dchm = cast(
|
|
1144
|
+
Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray],
|
|
1145
|
+
read_mpt_file(fpath, mode='gc', mass_mg=mass_mg),
|
|
1146
|
+
)
|
|
1147
|
+
voltage, dqdv, cycles, charge_mask, discharge_mask, y_label = \
|
|
1148
|
+
compute_dqdv_numerical(
|
|
1149
|
+
_b_gc_cap, _b_gc_volt, _b_gc_cyc, _b_gc_chgm, _b_gc_dchm,
|
|
1150
|
+
)
|
|
1151
|
+
_b_loaded = True
|
|
1152
|
+
print(f"dQ/dV batch: computing numerically from GC data for {fname!r}.")
|
|
1153
|
+
elif ext != '.csv':
|
|
1154
|
+
raise ValueError(f"dQ/dV mode requires .csv or Biologic .mpt/.npt file, got {ext}")
|
|
1155
|
+
elif is_biologic_datalogger_csv(fpath):
|
|
1135
1156
|
if mass_mg is None or mass_mg <= 0:
|
|
1136
1157
|
print(f" Skipped {fname}: dQ/dV (Biologic DataLogger CSV) requires --mass parameter")
|
|
1137
1158
|
plt.close(fig_b)
|
|
@@ -1164,7 +1185,7 @@ def batch_process_ec(directory: str, args):
|
|
|
1164
1185
|
if _b_mass and _b_mass > 0:
|
|
1165
1186
|
_b_gc_cap = _b_gc_cap * (1000.0 / float(_b_mass))
|
|
1166
1187
|
else:
|
|
1167
|
-
print(f"dQ/dV batch: {fname!r} — pass --mass
|
|
1188
|
+
print(f"dQ/dV batch: {fname!r} — pass --mass (mg, or e.g. 0.01g) for specific dQ/dV.")
|
|
1168
1189
|
voltage, dqdv, cycles, charge_mask, discharge_mask, y_label = \
|
|
1169
1190
|
compute_dqdv_numerical(_b_gc_cap, _b_gc_volt, _b_gc_cyc, _b_gc_chgm, _b_gc_dchm)
|
|
1170
1191
|
print(f"dQ/dV batch: computing numerically from GC data for {fname!r}.")
|
|
@@ -1219,9 +1240,9 @@ def batch_process_ec(directory: str, args):
|
|
|
1219
1240
|
|
|
1220
1241
|
# ---- CPC / EPC Mode ----
|
|
1221
1242
|
elif mode in ('cpc', 'epc'):
|
|
1222
|
-
if ext
|
|
1243
|
+
if _is_mpt_like_ext(ext):
|
|
1223
1244
|
if mass_mg is None:
|
|
1224
|
-
print(f" Skipped {fname}: {mode.upper()} mode (.mpt) requires --mass parameter")
|
|
1245
|
+
print(f" Skipped {fname}: {mode.upper()} mode (.mpt/.npt) requires --mass parameter")
|
|
1225
1246
|
plt.close(fig_b)
|
|
1226
1247
|
continue
|
|
1227
1248
|
if mode == 'cpc':
|