batplot 1.8.0__py3-none-any.whl → 1.8.2__py3-none-any.whl
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.
Potentially problematic release.
This version of batplot might be problematic. Click here for more details.
- batplot/__init__.py +1 -1
- batplot/args.py +5 -3
- batplot/batplot.py +44 -4
- batplot/cpc_interactive.py +96 -3
- batplot/electrochem_interactive.py +28 -0
- batplot/interactive.py +18 -2
- batplot/modes.py +12 -12
- batplot/operando.py +2 -0
- batplot/operando_ec_interactive.py +112 -11
- batplot/session.py +35 -1
- batplot/utils.py +40 -0
- batplot/version_check.py +85 -6
- {batplot-1.8.0.dist-info → batplot-1.8.2.dist-info}/METADATA +1 -1
- batplot-1.8.2.dist-info/RECORD +75 -0
- {batplot-1.8.0.dist-info → batplot-1.8.2.dist-info}/top_level.txt +1 -0
- batplot_backup_20251221_101150/__init__.py +5 -0
- batplot_backup_20251221_101150/args.py +625 -0
- batplot_backup_20251221_101150/batch.py +1176 -0
- batplot_backup_20251221_101150/batplot.py +3589 -0
- batplot_backup_20251221_101150/cif.py +823 -0
- batplot_backup_20251221_101150/cli.py +149 -0
- batplot_backup_20251221_101150/color_utils.py +547 -0
- batplot_backup_20251221_101150/config.py +198 -0
- batplot_backup_20251221_101150/converters.py +204 -0
- batplot_backup_20251221_101150/cpc_interactive.py +4409 -0
- batplot_backup_20251221_101150/electrochem_interactive.py +4520 -0
- batplot_backup_20251221_101150/interactive.py +3894 -0
- batplot_backup_20251221_101150/manual.py +323 -0
- batplot_backup_20251221_101150/modes.py +799 -0
- batplot_backup_20251221_101150/operando.py +603 -0
- batplot_backup_20251221_101150/operando_ec_interactive.py +5487 -0
- batplot_backup_20251221_101150/plotting.py +228 -0
- batplot_backup_20251221_101150/readers.py +2607 -0
- batplot_backup_20251221_101150/session.py +2951 -0
- batplot_backup_20251221_101150/style.py +1441 -0
- batplot_backup_20251221_101150/ui.py +790 -0
- batplot_backup_20251221_101150/utils.py +1046 -0
- batplot_backup_20251221_101150/version_check.py +253 -0
- batplot-1.8.0.dist-info/RECORD +0 -52
- {batplot-1.8.0.dist-info → batplot-1.8.2.dist-info}/WHEEL +0 -0
- {batplot-1.8.0.dist-info → batplot-1.8.2.dist-info}/entry_points.txt +0 -0
- {batplot-1.8.0.dist-info → batplot-1.8.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,625 @@
|
|
|
1
|
+
"""Argument parsing for batplot CLI.
|
|
2
|
+
|
|
3
|
+
This module handles all command-line argument parsing for batplot. It defines
|
|
4
|
+
the command-line interface, including:
|
|
5
|
+
- All command-line flags and options
|
|
6
|
+
- Help text for each mode (XY, EC, Operando)
|
|
7
|
+
- Argument validation and conversion
|
|
8
|
+
- Colored help output (if rich library is available)
|
|
9
|
+
|
|
10
|
+
HOW COMMAND-LINE ARGUMENTS WORK:
|
|
11
|
+
--------------------------------
|
|
12
|
+
When you run (for example) 'batplot --xaxis 2theta file.xy --i', Python's argparse library:
|
|
13
|
+
1. Parses the command line into structured arguments
|
|
14
|
+
2. Validates that required arguments are present
|
|
15
|
+
3. Converts string arguments to appropriate types (int, float, bool, etc.)
|
|
16
|
+
4. Groups related arguments together
|
|
17
|
+
5. Provides helpful error messages if arguments are invalid
|
|
18
|
+
|
|
19
|
+
This module defines all the valid arguments and their meanings.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import argparse
|
|
25
|
+
import sys
|
|
26
|
+
import re
|
|
27
|
+
|
|
28
|
+
# ====================================================================
|
|
29
|
+
# COLORED HELP OUTPUT
|
|
30
|
+
# ====================================================================
|
|
31
|
+
# The 'rich' library provides colored terminal output. If available,
|
|
32
|
+
# we use it to make help text more readable by highlighting:
|
|
33
|
+
# - Command-line flags in cyan
|
|
34
|
+
# - File extensions in yellow
|
|
35
|
+
# - Example commands in green
|
|
36
|
+
# - Section headers in blue
|
|
37
|
+
#
|
|
38
|
+
# If rich is not installed, we fall back to plain text (still works fine).
|
|
39
|
+
# ====================================================================
|
|
40
|
+
try:
|
|
41
|
+
from rich.console import Console
|
|
42
|
+
from rich.markup import escape
|
|
43
|
+
_console = Console()
|
|
44
|
+
_HAS_RICH = True
|
|
45
|
+
except ImportError:
|
|
46
|
+
_console = None
|
|
47
|
+
_HAS_RICH = False
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _colorize_help(text: str) -> str:
|
|
51
|
+
"""
|
|
52
|
+
Add colors to help text by highlighting flags and special elements.
|
|
53
|
+
|
|
54
|
+
HOW IT WORKS:
|
|
55
|
+
------------
|
|
56
|
+
Uses regular expressions to find patterns in help text and wrap them
|
|
57
|
+
with rich markup codes for colored output.
|
|
58
|
+
|
|
59
|
+
Patterns colored:
|
|
60
|
+
- Command-line flags: --flag or -f → cyan
|
|
61
|
+
- File extensions: .xy, .csv, etc. → yellow
|
|
62
|
+
- Example commands: batplot ... → green
|
|
63
|
+
- Section headers: lines ending with : → bold blue
|
|
64
|
+
- Bullet points: • → bold
|
|
65
|
+
|
|
66
|
+
Example:
|
|
67
|
+
Input: "batplot file.qye --i"
|
|
68
|
+
Output: "[green]batplot[/green] [yellow]file.qye[/yellow] [cyan]--i[/cyan]"
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
text: Plain help text (uncolored)
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
Text with rich markup codes for colored output
|
|
75
|
+
(or original text if rich is not available)
|
|
76
|
+
"""
|
|
77
|
+
if not _HAS_RICH:
|
|
78
|
+
return text # No coloring available, return as-is
|
|
79
|
+
|
|
80
|
+
# STEP 1: Escape any existing markup to prevent conflicts
|
|
81
|
+
# This ensures that if the help text already contains rich markup,
|
|
82
|
+
# we don't accidentally break it
|
|
83
|
+
text = escape(text)
|
|
84
|
+
|
|
85
|
+
# STEP 2: Color command-line flags
|
|
86
|
+
# Pattern: --flag-name or -f (single letter flag)
|
|
87
|
+
# Example: "--interactive" → "[cyan]--interactive[/cyan]"
|
|
88
|
+
text = re.sub(r'(--[\w-]+)', r'[cyan]\1[/cyan]', text) # Long flags (--flag)
|
|
89
|
+
text = re.sub(r'(\s-[a-zA-Z]\b)', r'[cyan]\1[/cyan]', text) # Short flags (-f)
|
|
90
|
+
|
|
91
|
+
# STEP 3: Color file extensions
|
|
92
|
+
# Pattern: .extension (2-4 characters)
|
|
93
|
+
# Example: ".xy" → "[yellow].xy[/yellow]"
|
|
94
|
+
text = re.sub(r'(\.\w{2,4}\b)', r'[yellow]\1[/yellow]', text)
|
|
95
|
+
|
|
96
|
+
# STEP 4: Color example commands
|
|
97
|
+
# Pattern: "batplot" followed by arguments
|
|
98
|
+
# Example: "batplot file.xy --i" → "[green]batplot file.xy --i[/green]"
|
|
99
|
+
text = re.sub(r'(batplot\s+[^\n]+)', r'[green]\1[/green]', text)
|
|
100
|
+
|
|
101
|
+
# STEP 5: Color section headers
|
|
102
|
+
# Pattern: Lines that start with capital letter and end with colon
|
|
103
|
+
# Example: "Examples:" → "[bold blue]Examples:[/bold blue]"
|
|
104
|
+
text = re.sub(r'^([A-Z][\w\s/()]+:)$', r'[bold blue]\1[/bold blue]', text, flags=re.MULTILINE)
|
|
105
|
+
|
|
106
|
+
# STEP 6: Make bullet points bold
|
|
107
|
+
text = text.replace('•', '[bold]•[/bold]')
|
|
108
|
+
|
|
109
|
+
return text
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _print_help(text: str) -> None:
|
|
113
|
+
"""Print help text with optional coloring.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
text: Help text to print
|
|
117
|
+
"""
|
|
118
|
+
if _HAS_RICH and _console:
|
|
119
|
+
colored_text = _colorize_help(text)
|
|
120
|
+
_console.print(colored_text)
|
|
121
|
+
else:
|
|
122
|
+
print(text)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _print_general_help() -> None:
|
|
126
|
+
# Import version here to avoid circular imports
|
|
127
|
+
try:
|
|
128
|
+
from . import __version__
|
|
129
|
+
version_str = f"batplot v{__version__} — quick plotting for lab data\n\n"
|
|
130
|
+
except ImportError:
|
|
131
|
+
version_str = "batplot — quick plotting for lab data\n\n"
|
|
132
|
+
|
|
133
|
+
msg = (
|
|
134
|
+
version_str +
|
|
135
|
+
"What it does:\n"
|
|
136
|
+
" • XY: XRD/PDF/XAS/User defined curves\n"
|
|
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 maps from a folder of .xy/.xye/.dat/.txt and optional file as side panel\n"
|
|
139
|
+
" • Batch: export vector plots for all files in a directory\n\n"
|
|
140
|
+
" • Interactive mode: --i / --interactive flag opens a menu for styling, ranges, export, and save\n\n"
|
|
141
|
+
"How to run (basics):\n"
|
|
142
|
+
" [1D(XY) curves]\n"
|
|
143
|
+
" batplot file1.xy file2.qye [option1] [option2] # 1D curves, read the first two columns as X and Y axis by default\n"
|
|
144
|
+
" batplot allfiles # Plot all files in current directory on same figure\n"
|
|
145
|
+
" batplot allfiles /path/to/dir # Plot all files in specified directory\n"
|
|
146
|
+
" batplot allfiles --i # Plot all files with interactive menu\n"
|
|
147
|
+
" batplot allxyfiles # Plot only .xy files (natural sorted)\n"
|
|
148
|
+
" batplot /path/to/data allnorfiles --i # Plot only .nor files from a directory\n"
|
|
149
|
+
" batplot --all # Batch mode: all XY files → Figures/ as .svg\n"
|
|
150
|
+
" batplot --all --format png # Batch mode: export as .png files\n"
|
|
151
|
+
" batplot --all --xaxis 2theta --xrange 10 80 # Batch mode with custom axis and range\n"
|
|
152
|
+
" batplot --all style.bps # Batch with style: apply style.bps to all files\n"
|
|
153
|
+
" batplot --all ./Style/style.bps # Batch with style: use relative path to style file\n"
|
|
154
|
+
" batplot --all config.bpsg # Batch with style+geom: apply to all XY files\n"
|
|
155
|
+
" batplot file1.xy:1.54 file2.qye --stack # Stack mode: stack all files vertically\n"
|
|
156
|
+
" batplot file1.xy:1.54 file2.qye structure.cif --stack --i # Stack mode: stack all files vertically with cif ticks\n"
|
|
157
|
+
" batplot file1.qye file2.qye style.bps # Apply style to multiple files and export\n"
|
|
158
|
+
" batplot file1.xy file2.xye ./Style/style.bps # Apply style from relative path\n\n"
|
|
159
|
+
" [Electrochemistry]\n"
|
|
160
|
+
" batplot --gc file.mpt --mass 7.0 # EC GC from .mpt (requires --mass mg)\n"
|
|
161
|
+
" batplot --gc file.csv --i # EC GC from supported .csv (no mass required) with interactive menu\n"
|
|
162
|
+
" batplot --gc --all --mass 7.0 # Batch: all .mpt/.csv → Figures/ as .svg\n"
|
|
163
|
+
" batplot --gc --all --mass 7 --format png # Batch: export as .png files\n"
|
|
164
|
+
" batplot --all --dqdv style.bps --mass 7 # Batch with style: apply style.bps to all GC files\n"
|
|
165
|
+
" batplot --all --gc ./Style/style.bps --mass 7 # Batch with style: use relative path\n"
|
|
166
|
+
" batplot --all --cpc config.bpsg # Batch with style+geom: apply to all CV files\n"
|
|
167
|
+
" batplot --all --cv ./Style/config.bpsg # Batch with style+geom: use relative path\n"
|
|
168
|
+
" batplot --dqdv FILE.csv # EC dQ/dV from supported .csv\n"
|
|
169
|
+
" batplot --dqdv --all # Batch: all .csv in directory (dQdV mode)\n"
|
|
170
|
+
" batplot --cv FILE.mpt # EC CV (cyclic voltammetry) from .mpt\n"
|
|
171
|
+
" batplot --cv FILE.txt # EC CV (cyclic voltammetry) from .txt\n"
|
|
172
|
+
" batplot --cv --all # Batch: all .mpt/.txt in directory (CV mode)\n\n"
|
|
173
|
+
" [Operando]\n"
|
|
174
|
+
" batplot --operando --i [FOLDER] # Operando contour (with or without .mpt file)\n\n"
|
|
175
|
+
"Features:\n"
|
|
176
|
+
" • Quick plotting with sensible defaults, no config files needed\n"
|
|
177
|
+
" • Supports many common file formats (see -h xy/ec/op)\n"
|
|
178
|
+
" • Interactive menus (--interactive): styling, ranges, fonts, export, sessions\n"
|
|
179
|
+
" • Batch processing: use 'allfiles' / 'all<ext>files' to plot together, or --all for separate files\n"
|
|
180
|
+
" • Batch exports saved to Figures/ subdirectory (default: .svg format)\n"
|
|
181
|
+
" • Batch styling: apply .bps/.bpsg files to all exports (use --all flag)\n"
|
|
182
|
+
" • Format option: use --format png/pdf/jpg/etc to change export format\n\n"
|
|
183
|
+
|
|
184
|
+
"More help:\n"
|
|
185
|
+
" batplot -h xy # XY file plotting guide\n"
|
|
186
|
+
" batplot -h ec # Electrochemistry (GC/dQdV/CV/CPC) guide\n"
|
|
187
|
+
" batplot -h op # Operando guide\n"
|
|
188
|
+
" batplot -m # Open the illustrated txt manual with highlights\n\n"
|
|
189
|
+
|
|
190
|
+
"Contact & Updates:\n"
|
|
191
|
+
" Subscribe to batplot-lab@kjemi.uio.no for updates\n"
|
|
192
|
+
" (If you are not from UiO, send an email to sympa@kjemi.uio.no with the subject line \"subscribe batplot-lab@kjemi.uio.no your-name\")\n"
|
|
193
|
+
" Kindly cite the pypi package page (https://pypi.org/project/batplot/) if the plot is used for publication\n"
|
|
194
|
+
" Email: tianda@uio.no\n"
|
|
195
|
+
" Personal page: https://www.mn.uio.no/kjemi/english/people/aca/tianda/\n"
|
|
196
|
+
)
|
|
197
|
+
_print_help(msg)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def _print_xy_help() -> None:
|
|
201
|
+
msg = (
|
|
202
|
+
"XY plots (XRD/PDF/XAS and many more)\n\n"
|
|
203
|
+
"Supported files: .xye .xy .qye .dat .csv .gr .nor .chik .chir .txt and other user specified formats. CIF overlays supported.\n\n"
|
|
204
|
+
"Axis detection: .qye→Q, .gr→r, .nor→energy, .chik→k, .chir→r, else use --xaxis (Q, 2theta, r, k, energy, time or user defined).\n"
|
|
205
|
+
"If mixing 2θ data in Q, give wavelength per-file (file.xye:1.5406) or global flag --wl.\n"
|
|
206
|
+
"A wavelength can be converted into a different wave length by file.xye:1.54:0.709.\n"
|
|
207
|
+
"For electrochemistry CSV/MPT time-voltage plots, use --xaxis time.\n\n"
|
|
208
|
+
"Examples:\n"
|
|
209
|
+
" batplot a.xye:1.5406 b.qye --stack --i\n"
|
|
210
|
+
" batplot a.dat b.xy --wl 1.54 --i\n"
|
|
211
|
+
" batplot pattern.qye ticks.cif:1.54 --i\n\n"
|
|
212
|
+
"Plot all files together:\n"
|
|
213
|
+
" batplot allfiles # Plot all XY files on same figure\n"
|
|
214
|
+
" batplot allfiles /path/to/dir # Plot all XY files in specified directory\n"
|
|
215
|
+
" batplot allfiles --stack --interactive # Stack all files with interactive menu\n"
|
|
216
|
+
" batplot allfiles --xaxis 2theta --xrange 10 80 # All files with custom axis and range\n"
|
|
217
|
+
" batplot allfiles --wl 1.5406 --delta 0.2 # All files with wavelength and spacing\n"
|
|
218
|
+
" batplot allxyfiles # Only plot .xy files (natural sorting)\n"
|
|
219
|
+
" batplot \"/path with spaces\" allnorfiles --interactive # Restrict to .nor files in a folder\n\n"
|
|
220
|
+
"Batch mode (separate file for each, saved to Figures/ subdirectory):\n"
|
|
221
|
+
" batplot --all # Export all XY files as .svg (default)\n"
|
|
222
|
+
" batplot --all --format png # Export all XY files as .png\n"
|
|
223
|
+
" batplot --all --xaxis 2theta # Batch mode with custom axis type\n"
|
|
224
|
+
" batplot --all --xrange 10 80 # Batch mode with X-axis range\n"
|
|
225
|
+
" batplot --all --wl 1.5406 # Batch mode with wavelength conversion\n"
|
|
226
|
+
" batplot --all style.bps # Apply style.bps to all XY files\n"
|
|
227
|
+
" batplot --all ./Style/style.bps # Apply style from relative path (e.g., ./Style/style.bps)\n"
|
|
228
|
+
" batplot --all config.bpsg # Apply style+geometry to all XY files\n"
|
|
229
|
+
" batplot --all ./Style/config.bpsg # Apply style+geometry from relative path\n\n"
|
|
230
|
+
"Normal mode with style files (apply style to multiple files and export):\n"
|
|
231
|
+
" batplot file1.xy file2.xye style.bps --out output.svg # Apply style and export\n"
|
|
232
|
+
" batplot file1.xy file2.xye ./Style/style.bps --out output.svg # Style from relative path\n"
|
|
233
|
+
" batplot file1.xy file2.xye style.bpsg --xaxis 2theta # Apply style+geometry\n"
|
|
234
|
+
" batplot file1.xy file2.xye ./Style/style.bpsg --xaxis 2theta # Style+geom from relative path\n\n"
|
|
235
|
+
"Tips and options:\n"
|
|
236
|
+
"[XY plot]\n"
|
|
237
|
+
" --interactive / -i : open interactive menu for styling, ranges, fonts, export, sessions\n"
|
|
238
|
+
" --delta/-d <float> : spacing between curves, e.g. --delta 0.1\n"
|
|
239
|
+
" --norm : normalize intensity to 0-1 range. Stack mode (--stack) auto-normalizes\n"
|
|
240
|
+
" --chik : EXAFS χ(k) plot (sets labels to k (Å⁻¹) vs χ(k))\n"
|
|
241
|
+
" --kchik : multiply y by x for EXAFS kχ(k) plots (sets labels to k (Å⁻¹) vs kχ(k) (Å⁻¹))\n"
|
|
242
|
+
" --k2chik : multiply y by x² for EXAFS k²χ(k) plots (sets labels to k (Å⁻¹) vs k²χ(k) (Å⁻²))\n"
|
|
243
|
+
" --k3chik : multiply y by x³ for EXAFS k³χ(k) plots (sets labels to k (Å⁻¹) vs k³χ(k) (Å⁻³))\n"
|
|
244
|
+
" --xrange/-r <min> <max> : set x-axis range, e.g. --xrange 0 10\n"
|
|
245
|
+
" --out/-o <filename> : save figure to file, e.g. --out file.svg\n"
|
|
246
|
+
" --xaxis <type> : set x-axis type (Q, 2theta, r, k, energy, rft, time, or user defined)\n"
|
|
247
|
+
" e.g. --xaxis 2theta, or --xaxis time for electrochemistry CSV/MPT time-voltage plots\n"
|
|
248
|
+
" --ro : swap x and y axes (exchange x and y values before plotting)\n"
|
|
249
|
+
" e.g. --xaxis time --ro plots time as y-axis and voltage as x-axis\n"
|
|
250
|
+
" --wl <float> : set wavelength for Q conversion for all files, e.g. --wl 1.5406\n"
|
|
251
|
+
" File wavelength syntax : specify wavelength(s) per file using colon syntax:\n"
|
|
252
|
+
" - file:wl : single wavelength (for Q conversion or CIF 2theta calculation)\n"
|
|
253
|
+
" - file:wl1:wl2 : dual wavelength (convert 2theta→Q using wl1, then Q→2theta using wl2)\n"
|
|
254
|
+
" - file.cif:wl : CIF file with wavelength for 2theta tick calculation\n"
|
|
255
|
+
" Examples:\n"
|
|
256
|
+
" batplot data.xye:1.5406 --xaxis 2theta\n"
|
|
257
|
+
" batplot data.xye:0.25:1.54 --xaxis 2theta\n"
|
|
258
|
+
" batplot data.xye pattern.cif:0.25448 --xaxis 2theta\n"
|
|
259
|
+
" --readcol <x_col> <y_col> : specify which columns to read as x and y (1-indexed), e.g. --readcol 2 3\n"
|
|
260
|
+
" --readcolxy <x> <y> : read columns for .xy files only\n"
|
|
261
|
+
" --readcolxye <x> <y> : read columns for .xye files only\n"
|
|
262
|
+
" --readcolqye <x> <y> : read columns for .qye files only\n"
|
|
263
|
+
" --readcolnor <x> <y> : read columns for .nor files only\n"
|
|
264
|
+
" --readcoldat <x> <y> : read columns for .dat files only\n"
|
|
265
|
+
" --readcolcsv <x> <y> : read columns for .csv files only\n"
|
|
266
|
+
" --readcol<ext> <x> <y> : read columns for custom extension (e.g., --readcolafes 2 3 for .afes files)\n"
|
|
267
|
+
" --fullprof <args> : FullProf overlay options\n"
|
|
268
|
+
" --stack : stack curves vertically (auto-enables normalization)\n"
|
|
269
|
+
)
|
|
270
|
+
_print_help(msg)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def _print_ec_help() -> None:
|
|
274
|
+
msg = (
|
|
275
|
+
"Electrochemistry (GC, dQ/dV, CV, and CPC)\n\n"
|
|
276
|
+
"Use --interactive for styling, colors, line widths, axis scales, etc.\n"
|
|
277
|
+
"GC from .mpt: requires active mass in mg to compute mAh g⁻¹.\n"
|
|
278
|
+
" batplot --gc file.mpt --mass 6.5 --interactive\n\n"
|
|
279
|
+
"GC from supported .csv: specific capacity is read directly (no --mass).\n"
|
|
280
|
+
" batplot --gc file.csv\n\n"
|
|
281
|
+
"dQ/dV from supported .csv:\n"
|
|
282
|
+
" batplot --dqdv file.csv\n\n"
|
|
283
|
+
"Cyclic voltammetry (CV) from .mpt or .txt: plots voltage vs current for each cycle.\n"
|
|
284
|
+
" batplot --cv file.mpt\n"
|
|
285
|
+
" batplot --cv file.txt\n\n"
|
|
286
|
+
"Capacity-per-cycle (CPC) with coulombic efficiency from .csv, .xlsx, or .mpt.\n"
|
|
287
|
+
"Supports multiple files with individual color customization:\n"
|
|
288
|
+
" batplot --cpc file.csv # Neware CSV\n"
|
|
289
|
+
" batplot --cpc file.xlsx # Landt/Lanhe Excel (Chinese tester)\n"
|
|
290
|
+
" batplot --cpc file.mpt --mass 1.2 # Biologic MPT\n"
|
|
291
|
+
" batplot --cpc file1.csv file2.xlsx file3.mpt --mass 1.2 --interactive\n\n"
|
|
292
|
+
"Excel support: Landt/Lanhe (蓝电/蓝河) .xlsx files with Chinese headers:\n"
|
|
293
|
+
" Expected structure: Row 1=filename, Row 2=headers, Row 3+=data\n"
|
|
294
|
+
"Batch mode: Process all files and export to Figures/ subdirectory (default: .svg).\n"
|
|
295
|
+
" batplot --gc --all --mass 7.0 # All .mpt/.csv files (.mpt requires --mass)\n"
|
|
296
|
+
" batplot --gc --all --mass 7 --format png # Export as .png instead of .svg\n"
|
|
297
|
+
" batplot --cv --all # All .mpt/.txt files (CV mode)\n"
|
|
298
|
+
" batplot --dqdv --all # All .csv files (dQdV mode)\n"
|
|
299
|
+
" batplot --cpc --all --mass 5.4 # All .mpt/.csv/.xlsx (.mpt requires --mass)\n"
|
|
300
|
+
" batplot --gc /path/to/folder --mass 6 # Process specific directory\n\n"
|
|
301
|
+
"Batch mode with style/geometry: Apply .bps/.bpsg files to all batch exports.\n"
|
|
302
|
+
" batplot --all style.bps --gc --mass 7 # Apply style to all GC plots\n"
|
|
303
|
+
" batplot --all ./Style/style.bps --gc --mass 7 # Apply style from relative path\n"
|
|
304
|
+
" batplot --all config.bpsg --cv # Apply style+geometry to all CV plots\n"
|
|
305
|
+
" batplot --all ./Style/config.bpsg --cv # Apply style+geometry from relative path\n"
|
|
306
|
+
" batplot --all my.bps --dqdv # Apply style to all dQdV plots\n"
|
|
307
|
+
" batplot --all ./Style/my.bps --dqdv # Apply style from relative path\n"
|
|
308
|
+
" batplot --all geom.bpsg --cpc --mass 6 # Apply style+geom to all CPC plots\n"
|
|
309
|
+
" batplot --all ./Style/geom.bpsg --cpc --mass 6 # Apply style+geom from relative path\n\n"
|
|
310
|
+
"Normal mode with style files: Apply style to multiple files and export.\n"
|
|
311
|
+
" batplot file1.csv file2.mpt style.bps --gc --mass 7 --out output.svg # GC mode\n"
|
|
312
|
+
" batplot file1.csv file2.mpt ./Style/style.bps --gc --mass 7 --out output.svg # Style from relative path\n"
|
|
313
|
+
" batplot file1.mpt file2.txt style.bpsg --cv # CV mode\n"
|
|
314
|
+
" batplot file1.mpt file2.txt ./Style/style.bpsg --cv # Style+geom from relative path\n"
|
|
315
|
+
" batplot file1.csv file2.csv style.bps --dqdv # dQdV mode\n"
|
|
316
|
+
" batplot file1.csv file2.csv ./Style/style.bps --dqdv # Style from relative path\n"
|
|
317
|
+
" batplot file1.csv file2.mpt style.bpsg --cpc --mass 6 # CPC mode\n"
|
|
318
|
+
" batplot file1.csv file2.mpt ./Style/style.bpsg --cpc --mass 6 # Style+geom from relative path\n\n"
|
|
319
|
+
"Interactive (--interactive): choose cycles, colors/palettes, line widths, axis scales (linear/log/symlog),\n"
|
|
320
|
+
"rename axes, toggle ticks/titles/spines, print/export/import style (.bps/.bpsg), save session (.pkl).\n"
|
|
321
|
+
"Note: Batch mode (--all) exports SVG files automatically; --interactive is for single-file plotting only.\n\n"
|
|
322
|
+
"Axis swapping:\n"
|
|
323
|
+
" --ro : swap x and y axes (exchange x and y values before plotting)\n"
|
|
324
|
+
" e.g. --gc --ro plots voltage as x-axis and capacity as y-axis\n"
|
|
325
|
+
" e.g. --xaxis time --ro plots time as y-axis and voltage as x-axis\n"
|
|
326
|
+
)
|
|
327
|
+
_print_help(msg)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def _print_op_help() -> None:
|
|
331
|
+
msg = (
|
|
332
|
+
"Operando contour plots\n\n"
|
|
333
|
+
"Example usage:\n"
|
|
334
|
+
" batplot --operando --interactive --wl 0.25995 # Interactive mode with Q conversion\n"
|
|
335
|
+
" batplot --operando --xaxis 2theta # Using 2theta axis\n\n"
|
|
336
|
+
" • Folder should contain XY files (.xy/.xye/.qye/.dat).\n"
|
|
337
|
+
" • Intensity scale is auto-adjusted between min/max values.\n"
|
|
338
|
+
" • If no .qye present, provide --xaxis 2theta or set --wl for Q conversion.\n"
|
|
339
|
+
" • If a .mpt file is present, an EC side panel is added for dual-panel mode.\n"
|
|
340
|
+
" • Without a .mpt file, operando-only mode shows the contour plot alone.\n\n"
|
|
341
|
+
"Interactive (--interactive): resize axes/canvas, change colormap, set intensity range (oz),\n"
|
|
342
|
+
"EC y-axis options (time ↔ ions), geometry tweaks, toggle spines/ticks/labels,\n"
|
|
343
|
+
"print/export/import style, save session.\n"
|
|
344
|
+
)
|
|
345
|
+
_print_help(msg)
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
349
|
+
"""
|
|
350
|
+
Build the argument parser for batplot command-line interface.
|
|
351
|
+
|
|
352
|
+
HOW ARGUMENT PARSING WORKS:
|
|
353
|
+
--------------------------
|
|
354
|
+
This function creates an ArgumentParser object that defines all valid
|
|
355
|
+
command-line arguments for batplot. When you run 'batplot file.xy --interactive',
|
|
356
|
+
argparse uses this parser to:
|
|
357
|
+
1. Recognize which arguments are valid
|
|
358
|
+
2. Extract values from the command line
|
|
359
|
+
3. Convert them to appropriate Python types (int, float, bool, etc.)
|
|
360
|
+
4. Store them in a namespace object (args.files, args.interactive, etc.)
|
|
361
|
+
|
|
362
|
+
ARGUMENT TYPES:
|
|
363
|
+
--------------
|
|
364
|
+
- Positional arguments: 'files' - list of file paths (can be 0 or more)
|
|
365
|
+
- Flags (boolean): '--interactive' - True if present, False if absent
|
|
366
|
+
- Options with values: '--mass 7.0' - requires a value (float in this case)
|
|
367
|
+
- Optional arguments: '--help xy' - can have optional value
|
|
368
|
+
|
|
369
|
+
WHY add_help=False?
|
|
370
|
+
-------------------
|
|
371
|
+
We use a custom help system that supports topic-specific help:
|
|
372
|
+
- 'batplot -h' → general help
|
|
373
|
+
- 'batplot -h xy' → XY mode help
|
|
374
|
+
- 'batplot -h ec' → EC mode help
|
|
375
|
+
- 'batplot -h op' → Operando mode help
|
|
376
|
+
|
|
377
|
+
This gives users more targeted help instead of one giant help page.
|
|
378
|
+
|
|
379
|
+
Returns:
|
|
380
|
+
Configured ArgumentParser object ready to parse command-line arguments
|
|
381
|
+
"""
|
|
382
|
+
# Create parser with custom help system (we handle help ourselves)
|
|
383
|
+
parser = argparse.ArgumentParser(add_help=False)
|
|
384
|
+
|
|
385
|
+
# ====================================================================
|
|
386
|
+
# TOPIC-AWARE HELP SYSTEM
|
|
387
|
+
# ====================================================================
|
|
388
|
+
# Instead of standard --help, we support topic-specific help:
|
|
389
|
+
# batplot -h → general help
|
|
390
|
+
# batplot -h xy → XY mode help
|
|
391
|
+
# batplot -h ec → EC mode help
|
|
392
|
+
# batplot -h op → Operando mode help
|
|
393
|
+
#
|
|
394
|
+
# nargs="?" means the argument is optional:
|
|
395
|
+
# - If not provided: const="" (empty string)
|
|
396
|
+
# - If provided: uses the value (e.g., "xy", "ec", "op")
|
|
397
|
+
# ====================================================================
|
|
398
|
+
parser.add_argument("--help", "-h", nargs="?", const="", metavar="topic",
|
|
399
|
+
help=argparse.SUPPRESS) # SUPPRESS hides from auto-generated help
|
|
400
|
+
parser.add_argument("--manual", "-m", action="store_true", help=argparse.SUPPRESS)
|
|
401
|
+
|
|
402
|
+
# ====================================================================
|
|
403
|
+
# POSITIONAL ARGUMENTS (FILE PATHS)
|
|
404
|
+
# ====================================================================
|
|
405
|
+
# 'files' is a positional argument, meaning it doesn't need a flag.
|
|
406
|
+
# nargs="*" means it accepts 0 or more values (list).
|
|
407
|
+
# Examples:
|
|
408
|
+
# batplot file1.xy file2.xy → args.files = ['file1.xy', 'file2.xy']
|
|
409
|
+
# batplot allfiles → args.files = ['allfiles']
|
|
410
|
+
# batplot --interactive → args.files = [] (empty list)
|
|
411
|
+
# ====================================================================
|
|
412
|
+
parser.add_argument("files", nargs="*", help=argparse.SUPPRESS)
|
|
413
|
+
parser.add_argument("--delta", "-d", type=float, default=None, help=argparse.SUPPRESS)
|
|
414
|
+
parser.add_argument("--autoscale", action="store_true", help=argparse.SUPPRESS)
|
|
415
|
+
parser.add_argument("--xrange", "-r", nargs=2, type=float, help=argparse.SUPPRESS)
|
|
416
|
+
parser.add_argument("--out", "-o", type=str, help=argparse.SUPPRESS)
|
|
417
|
+
parser.add_argument("--errors", action="store_true", help=argparse.SUPPRESS)
|
|
418
|
+
parser.add_argument("--xaxis", type=str, help=argparse.SUPPRESS)
|
|
419
|
+
parser.add_argument("--convert", "-c", nargs="+", help=argparse.SUPPRESS)
|
|
420
|
+
parser.add_argument("--wl", type=float, help=argparse.SUPPRESS)
|
|
421
|
+
parser.add_argument("--fullprof", nargs="+", type=float, help=argparse.SUPPRESS)
|
|
422
|
+
parser.add_argument("--norm", action="store_true", help=argparse.SUPPRESS)
|
|
423
|
+
parser.add_argument("--chik", action="store_true", help=argparse.SUPPRESS)
|
|
424
|
+
parser.add_argument("--kchik", action="store_true", help=argparse.SUPPRESS)
|
|
425
|
+
parser.add_argument("--k2chik", action="store_true", help=argparse.SUPPRESS)
|
|
426
|
+
parser.add_argument("--k3chik", action="store_true", help=argparse.SUPPRESS)
|
|
427
|
+
parser.add_argument("-i", "--interactive", action="store_true", dest="interactive", help=argparse.SUPPRESS)
|
|
428
|
+
parser.add_argument("--savefig", type=str, help=argparse.SUPPRESS)
|
|
429
|
+
parser.add_argument("--stack", action="store_true", help=argparse.SUPPRESS)
|
|
430
|
+
parser.add_argument("--operando", action="store_true", help=argparse.SUPPRESS)
|
|
431
|
+
parser.add_argument("--gc", action="store_true", help=argparse.SUPPRESS)
|
|
432
|
+
parser.add_argument("--mass", type=float, help=argparse.SUPPRESS)
|
|
433
|
+
parser.add_argument("--dqdv", action="store_true", help=argparse.SUPPRESS)
|
|
434
|
+
parser.add_argument("--cv", action="store_true", help=argparse.SUPPRESS)
|
|
435
|
+
parser.add_argument("--cpc", action="store_true", help=argparse.SUPPRESS)
|
|
436
|
+
parser.add_argument("--ro", action="store_true", help=argparse.SUPPRESS)
|
|
437
|
+
parser.add_argument("--all", type=str, nargs='?', const='all', help=argparse.SUPPRESS)
|
|
438
|
+
parser.add_argument("--format", type=str, default='svg',
|
|
439
|
+
choices=['svg', 'png', 'pdf', 'jpg', 'jpeg', 'eps', 'tif', 'tiff'],
|
|
440
|
+
help=argparse.SUPPRESS)
|
|
441
|
+
parser.add_argument("--readcol", nargs=2, type=int, metavar=('X_COL', 'Y_COL'),
|
|
442
|
+
help=argparse.SUPPRESS)
|
|
443
|
+
# Add extension-specific readcol arguments
|
|
444
|
+
parser.add_argument("--readcolxy", nargs=2, type=int, metavar=('X_COL', 'Y_COL'),
|
|
445
|
+
help=argparse.SUPPRESS)
|
|
446
|
+
parser.add_argument("--readcolxye", nargs=2, type=int, metavar=('X_COL', 'Y_COL'),
|
|
447
|
+
help=argparse.SUPPRESS)
|
|
448
|
+
parser.add_argument("--readcolqye", nargs=2, type=int, metavar=('X_COL', 'Y_COL'),
|
|
449
|
+
help=argparse.SUPPRESS)
|
|
450
|
+
parser.add_argument("--readcolnor", nargs=2, type=int, metavar=('X_COL', 'Y_COL'),
|
|
451
|
+
help=argparse.SUPPRESS)
|
|
452
|
+
parser.add_argument("--readcoldat", nargs=2, type=int, metavar=('X_COL', 'Y_COL'),
|
|
453
|
+
help=argparse.SUPPRESS)
|
|
454
|
+
parser.add_argument("--readcolcsv", nargs=2, type=int, metavar=('X_COL', 'Y_COL'),
|
|
455
|
+
help=argparse.SUPPRESS)
|
|
456
|
+
return parser
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def parse_args(argv=None):
|
|
460
|
+
"""
|
|
461
|
+
Parse command-line arguments with support for dynamic --readcol<ext> flags.
|
|
462
|
+
|
|
463
|
+
HOW IT WORKS:
|
|
464
|
+
------------
|
|
465
|
+
This function:
|
|
466
|
+
1. Scans command line for custom --readcol<ext> flags (e.g., --readcolafes)
|
|
467
|
+
2. Dynamically adds them to the parser (so argparse recognizes them)
|
|
468
|
+
3. Parses all arguments using the parser
|
|
469
|
+
4. Handles topic-specific help requests
|
|
470
|
+
|
|
471
|
+
WHY DYNAMIC ARGUMENTS?
|
|
472
|
+
---------------------
|
|
473
|
+
We support custom file extensions (e.g., .afes files). Users can specify
|
|
474
|
+
which columns to read using --readcol<ext> syntax:
|
|
475
|
+
batplot file.afes --readcolafes 2 3
|
|
476
|
+
|
|
477
|
+
We can't know all possible extensions ahead of time, so we:
|
|
478
|
+
1. Scan the command line first to find --readcol<ext> patterns
|
|
479
|
+
2. Add them to the parser dynamically
|
|
480
|
+
3. Then parse normally
|
|
481
|
+
|
|
482
|
+
Args:
|
|
483
|
+
argv: Optional list of command-line arguments (for testing).
|
|
484
|
+
If None, uses sys.argv[1:] (skips program name).
|
|
485
|
+
|
|
486
|
+
Returns:
|
|
487
|
+
Parsed arguments namespace object with all arguments as attributes.
|
|
488
|
+
Example: args.files, args.interactive, args.mass, etc.
|
|
489
|
+
"""
|
|
490
|
+
import re
|
|
491
|
+
|
|
492
|
+
# ====================================================================
|
|
493
|
+
# STEP 1: SCAN FOR CUSTOM --readcol<ext> FLAGS
|
|
494
|
+
# ====================================================================
|
|
495
|
+
# Before parsing, we need to find any custom --readcol<ext> flags
|
|
496
|
+
# (e.g., --readcolafes) and add them to the parser dynamically.
|
|
497
|
+
#
|
|
498
|
+
# Why? We support arbitrary file extensions, and users can specify
|
|
499
|
+
# column selection for any extension using --readcol<ext> syntax.
|
|
500
|
+
#
|
|
501
|
+
# Example:
|
|
502
|
+
# batplot file.afes --readcolafes 2 3
|
|
503
|
+
# This means: for .afes files, read column 2 as x, column 3 as y
|
|
504
|
+
# ====================================================================
|
|
505
|
+
|
|
506
|
+
# Get command-line arguments (skip program name 'batplot')
|
|
507
|
+
if argv is None:
|
|
508
|
+
argv = sys.argv[1:]
|
|
509
|
+
|
|
510
|
+
# Find all --readcol<ext> patterns in command line
|
|
511
|
+
# Pattern: --readcol followed by lowercase letters/numbers
|
|
512
|
+
# Example: --readcolafes → ext = 'afes'
|
|
513
|
+
custom_readcol_exts = set()
|
|
514
|
+
i = 0
|
|
515
|
+
while i < len(argv):
|
|
516
|
+
arg = argv[i]
|
|
517
|
+
# Match pattern: --readcol<extension>
|
|
518
|
+
match = re.match(r'^--readcol([a-z0-9]+)$', arg)
|
|
519
|
+
if match:
|
|
520
|
+
ext = match.group(1) # Extract extension name
|
|
521
|
+
# Skip predefined extensions (already in parser)
|
|
522
|
+
if ext not in ['xy', 'xye', 'qye', 'nor', 'dat', 'csv']:
|
|
523
|
+
custom_readcol_exts.add(ext)
|
|
524
|
+
i += 1
|
|
525
|
+
|
|
526
|
+
# ====================================================================
|
|
527
|
+
# STEP 2: BUILD PARSER AND ADD DYNAMIC ARGUMENTS
|
|
528
|
+
# ====================================================================
|
|
529
|
+
# Create the base parser (with all standard arguments)
|
|
530
|
+
parser = build_parser()
|
|
531
|
+
|
|
532
|
+
# Add custom --readcol<ext> arguments dynamically
|
|
533
|
+
# This allows argparse to recognize and parse them
|
|
534
|
+
for ext in custom_readcol_exts:
|
|
535
|
+
parser.add_argument(f"--readcol{ext}", nargs=2, type=int, metavar=('X_COL', 'Y_COL'),
|
|
536
|
+
help=argparse.SUPPRESS)
|
|
537
|
+
|
|
538
|
+
# ====================================================================
|
|
539
|
+
# STEP 3: HANDLE HELP REQUESTS (TOPIC-SPECIFIC HELP)
|
|
540
|
+
# ====================================================================
|
|
541
|
+
# We use parse_known_args() first to handle help requests without
|
|
542
|
+
# complaining about unknown arguments. This allows:
|
|
543
|
+
# batplot -h xy → XY mode help
|
|
544
|
+
# batplot -h ec → EC mode help
|
|
545
|
+
# batplot -h op → Operando mode help
|
|
546
|
+
#
|
|
547
|
+
# If help is requested, we print it and exit immediately (don't continue parsing).
|
|
548
|
+
# ====================================================================
|
|
549
|
+
|
|
550
|
+
# Parse with known_args_only=True to avoid errors from unknown arguments
|
|
551
|
+
# This is needed because we might have custom --readcol<ext> flags that
|
|
552
|
+
# weren't in the parser yet when we built it
|
|
553
|
+
ns, _unknown = parser.parse_known_args(argv)
|
|
554
|
+
if getattr(ns, "manual", False):
|
|
555
|
+
try:
|
|
556
|
+
from .manual import show_manual # Lazy import avoids matplotlib startup unless needed
|
|
557
|
+
pdf_path = show_manual(open_viewer=True)
|
|
558
|
+
if _HAS_RICH and _console:
|
|
559
|
+
_console.print(f"\n[green]Opened manual:[/green] {pdf_path}")
|
|
560
|
+
else:
|
|
561
|
+
print(f"\nOpened manual: {pdf_path}")
|
|
562
|
+
except Exception as exc: # pragma: no cover - rendering is best effort
|
|
563
|
+
if _HAS_RICH and _console:
|
|
564
|
+
_console.print(f"\n[red]Failed to open manual:[/red] {exc}")
|
|
565
|
+
else:
|
|
566
|
+
print(f"\nFailed to open manual: {exc}")
|
|
567
|
+
sys.exit(0)
|
|
568
|
+
|
|
569
|
+
topic = getattr(ns, 'help', None)
|
|
570
|
+
|
|
571
|
+
if topic is not None:
|
|
572
|
+
# Help was requested, print topic-specific help and exit
|
|
573
|
+
t = (topic or '').strip().lower()
|
|
574
|
+
if t in ("", "help"):
|
|
575
|
+
_print_general_help() # General help (no topic specified)
|
|
576
|
+
elif t in ("xy",):
|
|
577
|
+
_print_xy_help() # XY mode help
|
|
578
|
+
elif t in ("ec", "gc", "dqdv"):
|
|
579
|
+
_print_ec_help() # EC mode help (GC, dQ/dV, CV, CPC)
|
|
580
|
+
elif t in ("op", "operando"):
|
|
581
|
+
_print_op_help() # Operando mode help
|
|
582
|
+
else:
|
|
583
|
+
# Unknown topic, show general help with warning
|
|
584
|
+
_print_general_help()
|
|
585
|
+
if _HAS_RICH and _console:
|
|
586
|
+
_console.print("\n[yellow]Unknown help topic. Use: xy, ec, op[/yellow]")
|
|
587
|
+
else:
|
|
588
|
+
print("\nUnknown help topic. Use: xy, ec, op")
|
|
589
|
+
sys.exit(0) # Exit after showing help (don't continue to actual plotting)
|
|
590
|
+
|
|
591
|
+
# ====================================================================
|
|
592
|
+
# STEP 4: PARSE ALL ARGUMENTS (NORMAL OPERATION)
|
|
593
|
+
# ====================================================================
|
|
594
|
+
# No help requested, so parse all arguments normally.
|
|
595
|
+
# This will raise an error if required arguments are missing or invalid.
|
|
596
|
+
# ====================================================================
|
|
597
|
+
args = parser.parse_args(argv)
|
|
598
|
+
|
|
599
|
+
# ====================================================================
|
|
600
|
+
# STEP 5: BUILD readcol_by_ext DICTIONARY
|
|
601
|
+
# ====================================================================
|
|
602
|
+
# Collect all --readcol<ext> arguments into a convenient dictionary
|
|
603
|
+
# mapping file extension to (x_col, y_col) tuple.
|
|
604
|
+
#
|
|
605
|
+
# Example:
|
|
606
|
+
# User runs: batplot file.xy --readcolxy 2 3 file.afes --readcolafes 4 5
|
|
607
|
+
# Result: args.readcol_by_ext = {'.xy': (2, 3), '.afes': (4, 5)}
|
|
608
|
+
#
|
|
609
|
+
# This makes it easy to look up column specification for any file extension.
|
|
610
|
+
# ====================================================================
|
|
611
|
+
args.readcol_by_ext = {}
|
|
612
|
+
|
|
613
|
+
# Check all predefined and custom extensions
|
|
614
|
+
for ext in ['xy', 'xye', 'qye', 'nor', 'dat', 'csv'] + list(custom_readcol_exts):
|
|
615
|
+
attr_name = f'readcol{ext}' # e.g., 'readcolxy', 'readcolafes'
|
|
616
|
+
if hasattr(args, attr_name):
|
|
617
|
+
val = getattr(args, attr_name) # Get (x_col, y_col) tuple or None
|
|
618
|
+
if val is not None:
|
|
619
|
+
# Store with dot prefix (e.g., '.xy' not 'xy') for easy matching
|
|
620
|
+
args.readcol_by_ext[f'.{ext}'] = val
|
|
621
|
+
|
|
622
|
+
return args
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
__all__ = ["build_parser", "parse_args"]
|