batplot 1.8.28__tar.gz → 1.8.29__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.28/batplot.egg-info → batplot-1.8.29}/PKG-INFO +15 -2
- {batplot-1.8.28 → batplot-1.8.29}/README.md +14 -1
- {batplot-1.8.28 → batplot-1.8.29}/batplot/__init__.py +1 -1
- {batplot-1.8.28 → batplot-1.8.29}/batplot/args.py +11 -2
- {batplot-1.8.28 → batplot-1.8.29}/batplot/batplot.py +23 -12
- {batplot-1.8.28 → batplot-1.8.29}/batplot/converters.py +114 -6
- {batplot-1.8.28 → batplot-1.8.29}/batplot/data/CHANGELOG.md +6 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot/data/USER_MANUAL.md +15 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot/plotting.py +21 -7
- {batplot-1.8.28 → batplot-1.8.29}/batplot/version_check.py +5 -2
- {batplot-1.8.28 → batplot-1.8.29/batplot.egg-info}/PKG-INFO +15 -2
- {batplot-1.8.28 → batplot-1.8.29}/batplot.egg-info/SOURCES.txt +0 -1
- {batplot-1.8.28 → batplot-1.8.29}/pyproject.toml +1 -1
- batplot-1.8.28/USER_MANUAL.md +0 -723
- {batplot-1.8.28 → batplot-1.8.29}/LICENSE +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/MANIFEST.in +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/NOTICE +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot/batch.py +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot/cif.py +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot/cli.py +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot/color_utils.py +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot/config.py +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot/cpc_interactive.py +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot/dev_upgrade.py +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot/electrochem_interactive.py +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot/interactive.py +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot/manual.py +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot/modes.py +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot/operando.py +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot/operando_ec_interactive.py +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot/readers.py +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot/session.py +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot/style.py +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot/ui.py +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot/utils.py +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot.egg-info/dependency_links.txt +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot.egg-info/entry_points.txt +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot.egg-info/requires.txt +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/batplot.egg-info/top_level.txt +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/setup.cfg +0 -0
- {batplot-1.8.28 → batplot-1.8.29}/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.29
|
|
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
|
|
@@ -112,6 +112,10 @@ batplot scan1.brml:1.5406 scan2.xye:0.7093
|
|
|
112
112
|
# Convert and export to converted/ subfolder (q and Q equivalent)
|
|
113
113
|
batplot data.xye --convert 1.54 q
|
|
114
114
|
batplot data.qye --convert q 1.54
|
|
115
|
+
|
|
116
|
+
# With --readcol for custom column layout (e.g. 2θ in col 3, intensity in col 4)
|
|
117
|
+
batplot data.csv --readcol 3 4 --convert 1.54 q
|
|
118
|
+
batplot f1.txt --readcol 2 3 f2.txt --readcol 5 6 --convert 1.54 q
|
|
115
119
|
```
|
|
116
120
|
|
|
117
121
|
### Stacking and normalization
|
|
@@ -152,6 +156,9 @@ batplot data.xy --readcol 1 2 1 3
|
|
|
152
156
|
|
|
153
157
|
# Range: col 1 as x, cols 2–20 as 19 y-curves
|
|
154
158
|
batplot file.txt --readcol 1 2-20
|
|
159
|
+
|
|
160
|
+
# With --convert: use custom columns when converting XRD data
|
|
161
|
+
batplot data.csv --readcol 3 4 --convert 1.54 q
|
|
155
162
|
```
|
|
156
163
|
|
|
157
164
|
### Derivatives and EXAFS
|
|
@@ -186,6 +193,8 @@ batplot allfiles --xaxis 2theta --xrange 15 75 --interactive
|
|
|
186
193
|
|
|
187
194
|
### Galvanostatic cycling (GC)
|
|
188
195
|
|
|
196
|
+
GC mode plots potential vs. capacity for each charge/discharge cycle—the primary visualization for battery cycling data. Batplot automatically detects cycles from Neware `.csv` or Biologic `.mpt` files, assigns each cycle a distinct color, and supports both specific capacity (mAh/g) and raw capacity. For `.mpt` files, pass `--mass` (mg) to compute specific capacity. Discontinuous or paused experiments are handled by splitting data into contiguous charge/discharge segments. Use the interactive menu to customize colors, visibility, and export.
|
|
197
|
+
|
|
189
198
|
```bash
|
|
190
199
|
# From .csv (capacity in file)
|
|
191
200
|
batplot battery.csv --gc
|
|
@@ -278,13 +287,17 @@ batplot file1.xye file2.qye structure.cif:1.54 --stack --interactive
|
|
|
278
287
|
|
|
279
288
|
## Batch export (--all)
|
|
280
289
|
|
|
281
|
-
Export each file as a separate figure to `
|
|
290
|
+
Export each file as a separate figure to `Figures/`:
|
|
282
291
|
|
|
283
292
|
```bash
|
|
284
293
|
batplot --all
|
|
285
294
|
batplot --all --format png
|
|
286
295
|
batplot --all --xaxis 2theta --xrange 10 80
|
|
287
296
|
batplot --all style.bps --gc --mass 7
|
|
297
|
+
|
|
298
|
+
# With --readcol for custom columns (put --readcol before style file)
|
|
299
|
+
batplot --all --readcol 2 3 --xaxis 2theta
|
|
300
|
+
batplot --all --readcol 2 3 style.bps --xaxis 2theta
|
|
288
301
|
```
|
|
289
302
|
|
|
290
303
|
---
|
|
@@ -61,6 +61,10 @@ batplot scan1.brml:1.5406 scan2.xye:0.7093
|
|
|
61
61
|
# Convert and export to converted/ subfolder (q and Q equivalent)
|
|
62
62
|
batplot data.xye --convert 1.54 q
|
|
63
63
|
batplot data.qye --convert q 1.54
|
|
64
|
+
|
|
65
|
+
# With --readcol for custom column layout (e.g. 2θ in col 3, intensity in col 4)
|
|
66
|
+
batplot data.csv --readcol 3 4 --convert 1.54 q
|
|
67
|
+
batplot f1.txt --readcol 2 3 f2.txt --readcol 5 6 --convert 1.54 q
|
|
64
68
|
```
|
|
65
69
|
|
|
66
70
|
### Stacking and normalization
|
|
@@ -101,6 +105,9 @@ batplot data.xy --readcol 1 2 1 3
|
|
|
101
105
|
|
|
102
106
|
# Range: col 1 as x, cols 2–20 as 19 y-curves
|
|
103
107
|
batplot file.txt --readcol 1 2-20
|
|
108
|
+
|
|
109
|
+
# With --convert: use custom columns when converting XRD data
|
|
110
|
+
batplot data.csv --readcol 3 4 --convert 1.54 q
|
|
104
111
|
```
|
|
105
112
|
|
|
106
113
|
### Derivatives and EXAFS
|
|
@@ -135,6 +142,8 @@ batplot allfiles --xaxis 2theta --xrange 15 75 --interactive
|
|
|
135
142
|
|
|
136
143
|
### Galvanostatic cycling (GC)
|
|
137
144
|
|
|
145
|
+
GC mode plots potential vs. capacity for each charge/discharge cycle—the primary visualization for battery cycling data. Batplot automatically detects cycles from Neware `.csv` or Biologic `.mpt` files, assigns each cycle a distinct color, and supports both specific capacity (mAh/g) and raw capacity. For `.mpt` files, pass `--mass` (mg) to compute specific capacity. Discontinuous or paused experiments are handled by splitting data into contiguous charge/discharge segments. Use the interactive menu to customize colors, visibility, and export.
|
|
146
|
+
|
|
138
147
|
```bash
|
|
139
148
|
# From .csv (capacity in file)
|
|
140
149
|
batplot battery.csv --gc
|
|
@@ -227,13 +236,17 @@ batplot file1.xye file2.qye structure.cif:1.54 --stack --interactive
|
|
|
227
236
|
|
|
228
237
|
## Batch export (--all)
|
|
229
238
|
|
|
230
|
-
Export each file as a separate figure to `
|
|
239
|
+
Export each file as a separate figure to `Figures/`:
|
|
231
240
|
|
|
232
241
|
```bash
|
|
233
242
|
batplot --all
|
|
234
243
|
batplot --all --format png
|
|
235
244
|
batplot --all --xaxis 2theta --xrange 10 80
|
|
236
245
|
batplot --all style.bps --gc --mass 7
|
|
246
|
+
|
|
247
|
+
# With --readcol for custom columns (put --readcol before style file)
|
|
248
|
+
batplot --all --readcol 2 3 --xaxis 2theta
|
|
249
|
+
batplot --all --readcol 2 3 style.bps --xaxis 2theta
|
|
237
250
|
```
|
|
238
251
|
|
|
239
252
|
---
|
|
@@ -227,6 +227,9 @@ def _print_xy_help() -> None:
|
|
|
227
227
|
" - <wl1> <wl2> : convert 2θ from wavelength1 to wavelength2\n"
|
|
228
228
|
" - <wl> q or Q : convert 2θ (with wavelength) to Q space (q and Q equivalent)\n"
|
|
229
229
|
" - q or Q <wl> : convert Q space to 2θ (with wavelength)\n"
|
|
230
|
+
" Works with --readcol for custom column layout (per-file, per-ext, or global):\n"
|
|
231
|
+
" batplot data.csv --readcol 3 4 --convert 1.54 q\n"
|
|
232
|
+
" batplot f1.txt --readcol 2 3 f2.txt --readcol 5 6 --convert 1.54 q\n"
|
|
230
233
|
" Examples:\n"
|
|
231
234
|
" batplot file.xye --convert 1.54 0.25\n"
|
|
232
235
|
" batplot file.xye --convert 1.54 q\n"
|
|
@@ -244,6 +247,7 @@ def _print_xy_help() -> None:
|
|
|
244
247
|
" Multi-curve: file.xy --readcol 1 2 1 3 (plot cols 1,2 and 1,3 as two curves)\n"
|
|
245
248
|
" Range: file.txt --readcol 1 2-20 (col 1 as x, cols 2..20 as 19 y-curves)\n"
|
|
246
249
|
" With wavelength: file.xy:1.54 --readcol 2 3 (col 2 as 2θ, convert to Q using λ=1.54 Å)\n"
|
|
250
|
+
" With --convert: file.csv --readcol 3 4 --convert 1.54 q (custom cols for conversion)\n"
|
|
247
251
|
" --readcolxy <x> <y> : read columns for .xy files only\n"
|
|
248
252
|
" --readcolxye <x> <y> : read columns for .xye files only\n"
|
|
249
253
|
" --readcolqye <x> <y> : read columns for .qye files only\n"
|
|
@@ -574,17 +578,22 @@ def parse_args(argv=None):
|
|
|
574
578
|
# does not consume it. When --readcol appears before any file (global),
|
|
575
579
|
# store in global_readcol_expanded for post-parse.
|
|
576
580
|
# Keys use the exact file token (e.g. "file.xy:1.54") for wavelength match.
|
|
581
|
+
# Style files (.bps, .bpsg, .bpcfg) are NOT treated as file tokens so that
|
|
582
|
+
# "batplot --all style.bps --readcol 2 3" uses global readcol, not per-file.
|
|
577
583
|
# ====================================================================
|
|
578
584
|
readcol_by_file = {}
|
|
579
585
|
global_readcol_expanded = None
|
|
580
586
|
filtered_argv = []
|
|
581
587
|
last_file_token = None
|
|
588
|
+
_STYLE_EXTENSIONS = ('.bps', '.bpsg', '.bpcfg')
|
|
582
589
|
i = 0
|
|
583
590
|
while i < len(argv):
|
|
584
591
|
arg = argv[i]
|
|
585
|
-
# Track non-option tokens as potential file specs
|
|
592
|
+
# Track non-option tokens as potential file specs (exclude style files)
|
|
586
593
|
if not arg.startswith('-'):
|
|
587
|
-
|
|
594
|
+
arg_lower = arg.lower()
|
|
595
|
+
if not arg_lower.endswith(_STYLE_EXTENSIONS):
|
|
596
|
+
last_file_token = arg
|
|
588
597
|
if arg == '--readcol' and i + 1 < len(argv):
|
|
589
598
|
tokens = []
|
|
590
599
|
j = i + 1
|
|
@@ -3416,7 +3416,7 @@ def batplot_main() -> int: # type: ignore
|
|
|
3416
3416
|
print("Error: --convert requires file(s) to convert")
|
|
3417
3417
|
exit(1)
|
|
3418
3418
|
from_param, to_param = args.convert
|
|
3419
|
-
convert_xrd_data(args.files, from_param, to_param)
|
|
3419
|
+
convert_xrd_data(args.files, from_param, to_param, args=args)
|
|
3420
3420
|
exit()
|
|
3421
3421
|
|
|
3422
3422
|
# ---------------- Plotting ----------------
|
|
@@ -4035,7 +4035,17 @@ def batplot_main() -> int: # type: ignore
|
|
|
4035
4035
|
y_plotted = y_plot_offset
|
|
4036
4036
|
|
|
4037
4037
|
target_ax = ax2 if is_right_y else ax
|
|
4038
|
-
|
|
4038
|
+
# With --ry: assign explicit colors so plot, Colors menu (c), labels, and p/i/s/b stay consistent.
|
|
4039
|
+
# Matplotlib twinx uses a separate color cycle; explicit colors avoid mismatch across axes.
|
|
4040
|
+
if right_y_data_indices:
|
|
4041
|
+
try:
|
|
4042
|
+
curve_idx = len(y_data_list)
|
|
4043
|
+
curve_color = plt.cm.tab10(curve_idx % 10)
|
|
4044
|
+
target_ax.plot(x_plotted, y_plotted, "-", lw=1, alpha=0.8, color=curve_color)
|
|
4045
|
+
except Exception:
|
|
4046
|
+
target_ax.plot(x_plotted, y_plotted, "-", lw=1, alpha=0.8)
|
|
4047
|
+
else:
|
|
4048
|
+
target_ax.plot(x_plotted, y_plotted, "-", lw=1, alpha=0.8)
|
|
4039
4049
|
x_data_list.append(x_plotted)
|
|
4040
4050
|
y_data_list.append(y_plotted.copy())
|
|
4041
4051
|
labels_list.append(curve_label)
|
|
@@ -4102,19 +4112,11 @@ def batplot_main() -> int: # type: ignore
|
|
|
4102
4112
|
transform=ax.transAxes)
|
|
4103
4113
|
label_text_objects.append(txt)
|
|
4104
4114
|
|
|
4105
|
-
#
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
# Initialize curve names visibility (default to visible)
|
|
4109
|
-
fig._curve_names_visible = True
|
|
4110
|
-
# Initialize stack label position (default to top/max)
|
|
4111
|
-
fig._stack_label_at_bottom = False
|
|
4112
|
-
fig._label_anchor_left = False
|
|
4113
|
-
# Right y-axis state (--ry): ax2, curve indices, and curve->line mapping
|
|
4115
|
+
# Right y-axis state (--ry): build curve->line mapping BEFORE first update_labels
|
|
4116
|
+
# so label colors correctly match curves on both axes (plotting.py uses fig._xy_lines_by_curve)
|
|
4114
4117
|
fig._xy_ax2 = ax2
|
|
4115
4118
|
fig._xy_use_top_x = bool(getattr(args, 'txaxis', False))
|
|
4116
4119
|
fig._xy_right_y_curve_indices = frozenset(right_y_curve_indices)
|
|
4117
|
-
# Build curve index -> line mapping for interactive (ax.lines vs ax2.lines)
|
|
4118
4120
|
_lines_by_curve = []
|
|
4119
4121
|
_left_indices = sorted(i for i in range(len(y_data_list)) if i not in right_y_curve_indices)
|
|
4120
4122
|
_right_sorted = sorted(right_y_curve_indices)
|
|
@@ -4127,6 +4129,15 @@ def batplot_main() -> int: # type: ignore
|
|
|
4127
4129
|
_lines_by_curve.append(ax.lines[k] if k < len(ax.lines) else None)
|
|
4128
4130
|
fig._xy_lines_by_curve = _lines_by_curve
|
|
4129
4131
|
|
|
4132
|
+
# Ensure consistent initial placement (especially for stacked mode)
|
|
4133
|
+
update_labels(ax, y_data_list, label_text_objects, args.stack, False)
|
|
4134
|
+
|
|
4135
|
+
# Initialize curve names visibility (default to visible)
|
|
4136
|
+
fig._curve_names_visible = True
|
|
4137
|
+
# Initialize stack label position (default to top/max)
|
|
4138
|
+
fig._stack_label_at_bottom = False
|
|
4139
|
+
fig._label_anchor_left = False
|
|
4140
|
+
|
|
4130
4141
|
# ---------------- CIF tick overlay (after labels placed) ----------------
|
|
4131
4142
|
def _ensure_wavelength_for_2theta():
|
|
4132
4143
|
"""Ensure wavelength assigned to all CIF tick sets without prompting.
|
|
@@ -46,10 +46,85 @@ Physical meaning:
|
|
|
46
46
|
from __future__ import annotations
|
|
47
47
|
|
|
48
48
|
import os
|
|
49
|
+
from typing import Any, Optional
|
|
50
|
+
|
|
49
51
|
import numpy as np
|
|
50
52
|
|
|
51
53
|
|
|
52
|
-
def
|
|
54
|
+
def _resolve_readcol_for_file(
|
|
55
|
+
fname: str,
|
|
56
|
+
readcol_by_file: Optional[dict[str, Any]] = None,
|
|
57
|
+
readcol_by_ext: Optional[dict[str, tuple[int, int]]] = None,
|
|
58
|
+
readcol_global: Optional[Any] = None,
|
|
59
|
+
) -> Optional[tuple[int, int, Optional[int]]]:
|
|
60
|
+
"""
|
|
61
|
+
Resolve which columns to use for a file (x_col, y_col, e_col).
|
|
62
|
+
Returns (x_col, y_col, e_col) 1-indexed, or None to use defaults (1, 2, 3).
|
|
63
|
+
e_col is optional; if None, no error column. Uses first pair for multi-curve.
|
|
64
|
+
"""
|
|
65
|
+
if not readcol_by_file and not readcol_by_ext and not readcol_global:
|
|
66
|
+
return None
|
|
67
|
+
|
|
68
|
+
# Try per-file match (multiple strategies for cross-platform path matching)
|
|
69
|
+
rc = None
|
|
70
|
+
if readcol_by_file:
|
|
71
|
+
norm_fname = os.path.normpath(fname)
|
|
72
|
+
abs_fname = os.path.abspath(fname)
|
|
73
|
+
base_fname = os.path.basename(fname)
|
|
74
|
+
for key in readcol_by_file:
|
|
75
|
+
key_norm = os.path.normpath(key)
|
|
76
|
+
key_abs = os.path.abspath(key)
|
|
77
|
+
key_base = os.path.basename(key)
|
|
78
|
+
# Prefer exact/normpath/abspath match; use basename only as last resort
|
|
79
|
+
if fname == key or norm_fname == key_norm or abs_fname == key_abs:
|
|
80
|
+
rc = readcol_by_file[key]
|
|
81
|
+
break
|
|
82
|
+
# Basename fallback only if no match and exactly one key has this basename
|
|
83
|
+
if rc is None and base_fname:
|
|
84
|
+
matches = [k for k in readcol_by_file if os.path.basename(k) == base_fname]
|
|
85
|
+
if len(matches) == 1:
|
|
86
|
+
rc = readcol_by_file[matches[0]]
|
|
87
|
+
|
|
88
|
+
# Fall back to per-extension
|
|
89
|
+
if rc is None and readcol_by_ext:
|
|
90
|
+
_, ext = os.path.splitext(fname)
|
|
91
|
+
ext_lower = ext.lower() if ext else ""
|
|
92
|
+
rc = readcol_by_ext.get(ext_lower)
|
|
93
|
+
|
|
94
|
+
# Fall back to global
|
|
95
|
+
if rc is None and readcol_global is not None:
|
|
96
|
+
rc = readcol_global
|
|
97
|
+
|
|
98
|
+
if rc is None:
|
|
99
|
+
return None
|
|
100
|
+
|
|
101
|
+
# Normalize to single (x, y) pair; for multi-curve use first pair
|
|
102
|
+
if isinstance(rc, (list, tuple)) and len(rc) >= 2:
|
|
103
|
+
first = rc[0]
|
|
104
|
+
if isinstance(first, (list, tuple)) and len(first) >= 2:
|
|
105
|
+
x_col, y_col = int(first[0]), int(first[1])
|
|
106
|
+
else:
|
|
107
|
+
x_col, y_col = int(rc[0]), int(rc[1])
|
|
108
|
+
elif isinstance(rc, (list, tuple)) and len(rc) == 1:
|
|
109
|
+
first = rc[0]
|
|
110
|
+
if isinstance(first, (list, tuple)) and len(first) >= 2:
|
|
111
|
+
x_col, y_col = int(first[0]), int(first[1])
|
|
112
|
+
else:
|
|
113
|
+
return None
|
|
114
|
+
else:
|
|
115
|
+
return None
|
|
116
|
+
|
|
117
|
+
# Optional error column: use y_col + 1 if user might have x, y, e layout
|
|
118
|
+
e_col = y_col + 1
|
|
119
|
+
return (x_col, y_col, e_col)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def convert_xrd_data(
|
|
123
|
+
filenames,
|
|
124
|
+
from_param: str,
|
|
125
|
+
to_param: str,
|
|
126
|
+
args: Optional[Any] = None,
|
|
127
|
+
):
|
|
53
128
|
"""
|
|
54
129
|
Convert XRD data files between different representations.
|
|
55
130
|
|
|
@@ -85,6 +160,9 @@ def convert_xrd_data(filenames, from_param: str, to_param: str):
|
|
|
85
160
|
filenames: List of file paths to convert (e.g., ['data.xy', 'pattern.xye'])
|
|
86
161
|
from_param: Source parameter - either a wavelength (float as string) or 'q'
|
|
87
162
|
to_param: Target parameter - either a wavelength (float as string) or 'q'
|
|
163
|
+
args: Optional parsed args with readcol_by_file, readcol_by_ext, readcol for
|
|
164
|
+
column selection (1-indexed). When provided, uses these instead of
|
|
165
|
+
default columns 1, 2, 3. Compatible with --readcol, --readcolxy, etc.
|
|
88
166
|
|
|
89
167
|
Output:
|
|
90
168
|
Creates converted files in a 'converted' subfolder within the directory
|
|
@@ -137,6 +215,7 @@ def convert_xrd_data(filenames, from_param: str, to_param: str):
|
|
|
137
215
|
return
|
|
138
216
|
|
|
139
217
|
# Process each file
|
|
218
|
+
output_dirs = set()
|
|
140
219
|
for fname in filenames:
|
|
141
220
|
# Validate file exists
|
|
142
221
|
if not os.path.isfile(fname):
|
|
@@ -158,11 +237,35 @@ def convert_xrd_data(filenames, from_param: str, to_param: str):
|
|
|
158
237
|
if data.shape[1] < 2:
|
|
159
238
|
print(f"Invalid data format in {fname}: need at least 2 columns (x, y)")
|
|
160
239
|
continue
|
|
161
|
-
|
|
162
|
-
#
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
240
|
+
|
|
241
|
+
# Resolve column selection (--readcol, --readcolxy, etc.)
|
|
242
|
+
readcol_by_file = getattr(args, "readcol_by_file", None) or {}
|
|
243
|
+
readcol_by_ext = getattr(args, "readcol_by_ext", None) or {}
|
|
244
|
+
readcol_global = getattr(args, "readcol", None)
|
|
245
|
+
resolved = _resolve_readcol_for_file(
|
|
246
|
+
fname, readcol_by_file, readcol_by_ext, readcol_global
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
if resolved:
|
|
250
|
+
x_col, y_col, e_col = resolved
|
|
251
|
+
# Convert 1-indexed to 0-indexed
|
|
252
|
+
x_idx, y_idx = x_col - 1, y_col - 1
|
|
253
|
+
if x_idx < 0 or y_idx < 0 or x_idx >= data.shape[1] or y_idx >= data.shape[1]:
|
|
254
|
+
print(f"Error in {fname}: --readcol columns {x_col}, {y_col} out of range (file has {data.shape[1]} columns)")
|
|
255
|
+
continue
|
|
256
|
+
x = data[:, x_idx]
|
|
257
|
+
y = data[:, y_idx]
|
|
258
|
+
# Use error column if specified and exists
|
|
259
|
+
if e_col is not None and e_col <= data.shape[1]:
|
|
260
|
+
e_idx = e_col - 1
|
|
261
|
+
e = data[:, e_idx] if e_idx >= 0 else None
|
|
262
|
+
else:
|
|
263
|
+
e = None
|
|
264
|
+
else:
|
|
265
|
+
# Default: columns 0, 1, 2 (1-indexed: 1, 2, 3)
|
|
266
|
+
x = data[:, 0]
|
|
267
|
+
y = data[:, 1]
|
|
268
|
+
e = data[:, 2] if data.shape[1] >= 3 else None
|
|
166
269
|
|
|
167
270
|
# Perform conversion based on type
|
|
168
271
|
if conversion_type == "wavelength_to_wavelength":
|
|
@@ -227,9 +330,14 @@ def convert_xrd_data(filenames, from_param: str, to_param: str):
|
|
|
227
330
|
# Use UTF-8 encoding to support Greek letters (θ) in headers on all platforms
|
|
228
331
|
np.savetxt(output_fname, out_data, fmt="% .6f", header=header, encoding='utf-8')
|
|
229
332
|
print(f"Saved {output_fname}")
|
|
333
|
+
output_dirs.add(output_dir)
|
|
230
334
|
except Exception as e:
|
|
231
335
|
print(f"Error saving {output_fname}: {e}")
|
|
232
336
|
|
|
337
|
+
if output_dirs:
|
|
338
|
+
dirs_str = ", ".join(sorted(output_dirs))
|
|
339
|
+
print(f"Exported to: {dirs_str}")
|
|
340
|
+
|
|
233
341
|
|
|
234
342
|
def convert_to_qye(filenames, wavelength: float):
|
|
235
343
|
"""
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.8.29] - 2026-03-10
|
|
4
|
+
- Improved compatibility of `--convert` with `--readcol`: conversion now respects per-file, per-extension, and global column selection
|
|
5
|
+
- Use custom columns when converting XRD data: `batplot data.csv --readcol 3 4 --convert 1.54 q`
|
|
6
|
+
- Per-file columns for convert: `batplot f1.txt --readcol 2 3 f2.txt --readcol 5 6 --convert 1.54 q`
|
|
7
|
+
- Fixed `--all style.bps --readcol 2 3`: style files (.bps, .bpsg, .bpcfg) no longer steal readcol; global readcol now applies to all data files
|
|
8
|
+
|
|
3
9
|
## [1.8.16] - 2026-03-09
|
|
4
10
|
- GC and dQdV modes now support multiple files
|
|
5
11
|
|
|
@@ -231,6 +231,21 @@ All converted files are saved in a `converted` subfolder within the directory co
|
|
|
231
231
|
- Q-space files: `.qye` extension
|
|
232
232
|
- 2θ files: `.xy` or original extension
|
|
233
233
|
|
|
234
|
+
### Custom columns with --readcol
|
|
235
|
+
|
|
236
|
+
When your file has 2θ or Q in non-standard columns, use `--readcol` with `--convert`:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
# 2θ in column 3, intensity in column 4
|
|
240
|
+
batplot data.csv --readcol 3 4 --convert 1.54 q
|
|
241
|
+
|
|
242
|
+
# Per-file columns
|
|
243
|
+
batplot f1.txt --readcol 2 3 f2.txt --readcol 5 6 --convert 1.54 q
|
|
244
|
+
|
|
245
|
+
# Extension-specific: --readcoldat, --readcolcsv, etc.
|
|
246
|
+
batplot file.dat --readcoldat 2 4 --convert 1.54 q
|
|
247
|
+
```
|
|
248
|
+
|
|
234
249
|
### Examples
|
|
235
250
|
|
|
236
251
|
```bash
|
|
@@ -73,6 +73,18 @@ def update_labels(ax, y_data_list: List, label_text_objects: List, stack_mode: b
|
|
|
73
73
|
fig = getattr(ax, 'figure', None)
|
|
74
74
|
label_anchor_left = bool(getattr(fig, '_label_anchor_left', False)) if fig is not None else False
|
|
75
75
|
|
|
76
|
+
# Line lookup for dual y-axis (--ry): curve index -> Line2D (ax or ax2)
|
|
77
|
+
# When --ry is used, curves are split between ax and ax2; _xy_lines_by_curve maps correctly.
|
|
78
|
+
def _line_for_curve(i):
|
|
79
|
+
lines_src = getattr(fig, '_xy_lines_by_curve', None) if fig else None
|
|
80
|
+
if lines_src is not None and 0 <= i < len(lines_src):
|
|
81
|
+
ln = lines_src[i]
|
|
82
|
+
if ln is not None:
|
|
83
|
+
return ln
|
|
84
|
+
if i < len(ax.lines):
|
|
85
|
+
return ax.lines[i]
|
|
86
|
+
return None
|
|
87
|
+
|
|
76
88
|
# ====================================================================
|
|
77
89
|
if stack_mode:
|
|
78
90
|
# Get plot edges in data coordinates
|
|
@@ -118,9 +130,9 @@ def update_labels(ax, y_data_list: List, label_text_objects: List, stack_mode: b
|
|
|
118
130
|
|
|
119
131
|
# Set label color to match curve color (makes identification easier)
|
|
120
132
|
try:
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
txt.set_color(
|
|
133
|
+
ln = _line_for_curve(i)
|
|
134
|
+
if ln is not None:
|
|
135
|
+
txt.set_color(ln.get_color())
|
|
124
136
|
except Exception:
|
|
125
137
|
# If color matching fails, keep default color
|
|
126
138
|
pass
|
|
@@ -182,8 +194,9 @@ def update_labels(ax, y_data_list: List, label_text_objects: List, stack_mode: b
|
|
|
182
194
|
|
|
183
195
|
# Match label color to curve color
|
|
184
196
|
try:
|
|
185
|
-
|
|
186
|
-
|
|
197
|
+
ln = _line_for_curve(i)
|
|
198
|
+
if ln is not None:
|
|
199
|
+
txt.set_color(ln.get_color())
|
|
187
200
|
except Exception:
|
|
188
201
|
pass
|
|
189
202
|
else:
|
|
@@ -213,8 +226,9 @@ def update_labels(ax, y_data_list: List, label_text_objects: List, stack_mode: b
|
|
|
213
226
|
|
|
214
227
|
# Match label color to curve color
|
|
215
228
|
try:
|
|
216
|
-
|
|
217
|
-
|
|
229
|
+
ln = _line_for_curve(i)
|
|
230
|
+
if ln is not None:
|
|
231
|
+
txt.set_color(ln.get_color())
|
|
218
232
|
except Exception:
|
|
219
233
|
pass
|
|
220
234
|
|
|
@@ -101,10 +101,13 @@ def _wrap_line(text: str, width: int) -> List[str]:
|
|
|
101
101
|
UPDATE_INFO = {
|
|
102
102
|
# Custom message to include in update notification
|
|
103
103
|
# (Auto-filled from RELEASE_NOTES.txt when using batplot --dev-upgrade)
|
|
104
|
-
'custom_message': '-
|
|
104
|
+
'custom_message': '- Improved compatibility of --convert with --readcol: conversion now respects per-file, per-extension, and global column selection',
|
|
105
105
|
# Additional notes (auto-filled from RELEASE_NOTES.txt)
|
|
106
106
|
'update_notes': [
|
|
107
|
-
'-
|
|
107
|
+
'- Improved compatibility of --convert with --readcol: conversion now respects per-file, per-extension, and global column selection',
|
|
108
|
+
'- Use custom columns when converting XRD data: batplot data.csv --readcol 3 4 --convert 1.54 q',
|
|
109
|
+
'- Per-file columns for convert: batplot f1.txt --readcol 2 3 f2.txt --readcol 5 6 --convert 1.54 q',
|
|
110
|
+
'- Fixed --all style.bps --readcol 2 3: style files no longer steal readcol; global readcol applies to all data files'
|
|
108
111
|
],
|
|
109
112
|
'show_update_notes': True,
|
|
110
113
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: batplot
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.29
|
|
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
|
|
@@ -112,6 +112,10 @@ batplot scan1.brml:1.5406 scan2.xye:0.7093
|
|
|
112
112
|
# Convert and export to converted/ subfolder (q and Q equivalent)
|
|
113
113
|
batplot data.xye --convert 1.54 q
|
|
114
114
|
batplot data.qye --convert q 1.54
|
|
115
|
+
|
|
116
|
+
# With --readcol for custom column layout (e.g. 2θ in col 3, intensity in col 4)
|
|
117
|
+
batplot data.csv --readcol 3 4 --convert 1.54 q
|
|
118
|
+
batplot f1.txt --readcol 2 3 f2.txt --readcol 5 6 --convert 1.54 q
|
|
115
119
|
```
|
|
116
120
|
|
|
117
121
|
### Stacking and normalization
|
|
@@ -152,6 +156,9 @@ batplot data.xy --readcol 1 2 1 3
|
|
|
152
156
|
|
|
153
157
|
# Range: col 1 as x, cols 2–20 as 19 y-curves
|
|
154
158
|
batplot file.txt --readcol 1 2-20
|
|
159
|
+
|
|
160
|
+
# With --convert: use custom columns when converting XRD data
|
|
161
|
+
batplot data.csv --readcol 3 4 --convert 1.54 q
|
|
155
162
|
```
|
|
156
163
|
|
|
157
164
|
### Derivatives and EXAFS
|
|
@@ -186,6 +193,8 @@ batplot allfiles --xaxis 2theta --xrange 15 75 --interactive
|
|
|
186
193
|
|
|
187
194
|
### Galvanostatic cycling (GC)
|
|
188
195
|
|
|
196
|
+
GC mode plots potential vs. capacity for each charge/discharge cycle—the primary visualization for battery cycling data. Batplot automatically detects cycles from Neware `.csv` or Biologic `.mpt` files, assigns each cycle a distinct color, and supports both specific capacity (mAh/g) and raw capacity. For `.mpt` files, pass `--mass` (mg) to compute specific capacity. Discontinuous or paused experiments are handled by splitting data into contiguous charge/discharge segments. Use the interactive menu to customize colors, visibility, and export.
|
|
197
|
+
|
|
189
198
|
```bash
|
|
190
199
|
# From .csv (capacity in file)
|
|
191
200
|
batplot battery.csv --gc
|
|
@@ -278,13 +287,17 @@ batplot file1.xye file2.qye structure.cif:1.54 --stack --interactive
|
|
|
278
287
|
|
|
279
288
|
## Batch export (--all)
|
|
280
289
|
|
|
281
|
-
Export each file as a separate figure to `
|
|
290
|
+
Export each file as a separate figure to `Figures/`:
|
|
282
291
|
|
|
283
292
|
```bash
|
|
284
293
|
batplot --all
|
|
285
294
|
batplot --all --format png
|
|
286
295
|
batplot --all --xaxis 2theta --xrange 10 80
|
|
287
296
|
batplot --all style.bps --gc --mass 7
|
|
297
|
+
|
|
298
|
+
# With --readcol for custom columns (put --readcol before style file)
|
|
299
|
+
batplot --all --readcol 2 3 --xaxis 2theta
|
|
300
|
+
batplot --all --readcol 2 3 style.bps --xaxis 2theta
|
|
288
301
|
```
|
|
289
302
|
|
|
290
303
|
---
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "batplot"
|
|
7
|
-
version = "1.8.
|
|
7
|
+
version = "1.8.29"
|
|
8
8
|
description = "Interactive plotting tool for material science (1D plot) and electrochemistry (GC, CV, dQ/dV, CPC, operando) with batch processing"
|
|
9
9
|
authors = [
|
|
10
10
|
{ name = "Tian Dai", email = "tianda@uio.no" }
|