batplot 1.7.22__tar.gz → 1.7.24__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.
Potentially problematic release.
This version of batplot might be problematic. Click here for more details.
- {batplot-1.7.22/batplot.egg-info → batplot-1.7.24}/PKG-INFO +26 -3
- {batplot-1.7.22 → batplot-1.7.24}/README.md +3 -1
- {batplot-1.7.22/batplot/data → batplot-1.7.24}/USER_MANUAL.md +2 -2
- {batplot-1.7.22 → batplot-1.7.24}/batplot/__init__.py +1 -1
- {batplot-1.7.22 → batplot-1.7.24}/batplot/args.py +1 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot/cpc_interactive.py +168 -11
- {batplot-1.7.22 → batplot-1.7.24}/batplot/electrochem_interactive.py +152 -14
- {batplot-1.7.22 → batplot-1.7.24}/batplot/interactive.py +156 -30
- {batplot-1.7.22 → batplot-1.7.24}/batplot/operando_ec_interactive.py +198 -21
- {batplot-1.7.22 → batplot-1.7.24}/batplot/session.py +92 -1
- {batplot-1.7.22 → batplot-1.7.24}/batplot/style.py +109 -47
- {batplot-1.7.22 → batplot-1.7.24/batplot.egg-info}/PKG-INFO +26 -3
- {batplot-1.7.22 → batplot-1.7.24}/pyproject.toml +2 -3
- {batplot-1.7.22 → batplot-1.7.24}/LICENSE +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/MANIFEST.in +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot/batch.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot/batplot.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot/cif.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot/cli.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot/color_utils.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot/config.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot/converters.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24/batplot/data}/USER_MANUAL.md +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot/manual.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot/modes.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot/operando.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot/plotting.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot/readers.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot/ui.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot/utils.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot/version_check.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot.egg-info/SOURCES.txt +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot.egg-info/dependency_links.txt +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot.egg-info/entry_points.txt +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot.egg-info/requires.txt +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot.egg-info/top_level.txt +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/__init__.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/args.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/batch.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/batplot.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/cif.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/cli.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/color_utils.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/config.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/converters.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/cpc_interactive.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/electrochem_interactive.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/interactive.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/modes.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/operando.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/operando_ec_interactive.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/plotting.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/readers.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/session.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/style.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/ui.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/utils.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/batplot_backup_20251121_223043/version_check.py +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/setup.cfg +0 -0
- {batplot-1.7.22 → batplot-1.7.24}/setup.py +0 -0
|
@@ -1,9 +1,30 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: batplot
|
|
3
|
-
Version: 1.7.
|
|
3
|
+
Version: 1.7.24
|
|
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
|
-
License
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2025 Tian Dai
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
7
28
|
Project-URL: Homepage, https://github.com/TianDai1729/batplot
|
|
8
29
|
Project-URL: Repository, https://github.com/TianDai1729/batplot
|
|
9
30
|
Project-URL: Issues, https://github.com/TianDai1729/batplot/issues
|
|
@@ -171,7 +192,9 @@ See [LICENSE](LICENSE)
|
|
|
171
192
|
|
|
172
193
|
## Author & Contact
|
|
173
194
|
|
|
174
|
-
Tian Dai
|
|
195
|
+
Tian Dai
|
|
196
|
+
tianda@uio.no
|
|
175
197
|
University of Oslo
|
|
198
|
+
https://www.mn.uio.no/kjemi/english/people/aca/tianda/
|
|
176
199
|
|
|
177
200
|
**Subscribe for Updates**: Join batplot-lab@kjemi.uio.no for updates, feature announcements, and community feedback. If you are not from UiO, send an email to sympa@kjemi.uio.no with the exact subject line with your name: "subscribe batplot-lab@kjemi.uio.no your-name"
|
|
@@ -141,7 +141,9 @@ See [LICENSE](LICENSE)
|
|
|
141
141
|
|
|
142
142
|
## Author & Contact
|
|
143
143
|
|
|
144
|
-
Tian Dai
|
|
144
|
+
Tian Dai
|
|
145
|
+
tianda@uio.no
|
|
145
146
|
University of Oslo
|
|
147
|
+
https://www.mn.uio.no/kjemi/english/people/aca/tianda/
|
|
146
148
|
|
|
147
149
|
**Subscribe for Updates**: Join batplot-lab@kjemi.uio.no for updates, feature announcements, and community feedback. If you are not from UiO, send an email to sympa@kjemi.uio.no with the exact subject line with your name: "subscribe batplot-lab@kjemi.uio.no your-name"
|
|
@@ -456,8 +456,8 @@ If no `.mpt` file is present, operando mode displays only the contour plot. The
|
|
|
456
456
|
|
|
457
457
|
For questions, bug reports, or feature requests:
|
|
458
458
|
|
|
459
|
-
|
|
459
|
+
Tian Dai
|
|
460
460
|
- **Email**: tianda@uio.no
|
|
461
461
|
- **Mailing List**: Subscribe to batplot-lab@kjemi.uio.no for updates, feature announcements, and community discussions
|
|
462
462
|
|
|
463
|
-
Feel free to
|
|
463
|
+
Feel free to reach out via email!
|
|
@@ -190,6 +190,7 @@ def _print_general_help() -> None:
|
|
|
190
190
|
" (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"
|
|
191
191
|
" Kindly cite the pypi package page (https://pypi.org/project/batplot/) if the plot is used for publication\n"
|
|
192
192
|
" Email: tianda@uio.no\n"
|
|
193
|
+
" Personal page: https://www.mn.uio.no/kjemi/english/people/aca/tianda/\n"
|
|
193
194
|
)
|
|
194
195
|
_print_help(msg)
|
|
195
196
|
|
|
@@ -79,6 +79,46 @@ def _colorize_menu(text):
|
|
|
79
79
|
return f"\033[96m{cmd}\033[0m: {desc}" # Cyan for command, default for description
|
|
80
80
|
|
|
81
81
|
|
|
82
|
+
def _color_of(artist):
|
|
83
|
+
"""Return a representative color for a Line2D/PathCollection."""
|
|
84
|
+
try:
|
|
85
|
+
if artist is None:
|
|
86
|
+
return None
|
|
87
|
+
if hasattr(artist, 'get_color'):
|
|
88
|
+
c = artist.get_color()
|
|
89
|
+
if isinstance(c, (list, tuple)) and c and not isinstance(c, str):
|
|
90
|
+
return c[0]
|
|
91
|
+
return c
|
|
92
|
+
if hasattr(artist, 'get_facecolors'):
|
|
93
|
+
arr = artist.get_facecolors()
|
|
94
|
+
if arr is not None and len(arr):
|
|
95
|
+
from matplotlib.colors import to_hex
|
|
96
|
+
return to_hex(arr[0])
|
|
97
|
+
except Exception:
|
|
98
|
+
return None
|
|
99
|
+
return None
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _get_legend_title(fig, default: str = "Legend") -> str:
|
|
103
|
+
"""Fetch stored legend title, falling back to current legend text or default."""
|
|
104
|
+
try:
|
|
105
|
+
title = getattr(fig, '_cpc_legend_title', None)
|
|
106
|
+
if isinstance(title, str) and title:
|
|
107
|
+
return title
|
|
108
|
+
except Exception:
|
|
109
|
+
pass
|
|
110
|
+
try:
|
|
111
|
+
for ax in getattr(fig, 'axes', []):
|
|
112
|
+
leg = ax.get_legend()
|
|
113
|
+
if leg is not None:
|
|
114
|
+
t = leg.get_title().get_text()
|
|
115
|
+
if t:
|
|
116
|
+
return t
|
|
117
|
+
except Exception:
|
|
118
|
+
pass
|
|
119
|
+
return default
|
|
120
|
+
|
|
121
|
+
|
|
82
122
|
def _colorize_prompt(text):
|
|
83
123
|
"""Colorize commands within input prompts. Handles formats like (s=size, f=family, q=return) or (y/n)."""
|
|
84
124
|
import re
|
|
@@ -234,7 +274,7 @@ def _rebuild_legend(ax, ax2, file_data):
|
|
|
234
274
|
h_all.append(h)
|
|
235
275
|
l_all.append(l)
|
|
236
276
|
if h_all:
|
|
237
|
-
_legend_no_frame(ax, h_all, l_all, loc='best', borderaxespad=1.0)
|
|
277
|
+
_legend_no_frame(ax, h_all, l_all, loc='best', borderaxespad=1.0, title=_get_legend_title(ax.figure))
|
|
238
278
|
else:
|
|
239
279
|
leg = ax.get_legend()
|
|
240
280
|
if leg:
|
|
@@ -398,7 +438,8 @@ def _style_snapshot(fig, ax, ax2, sc_charge, sc_discharge, sc_eff, file_data=Non
|
|
|
398
438
|
'font': {'family': fam0, 'size': fsize},
|
|
399
439
|
'legend': {
|
|
400
440
|
'visible': legend_visible,
|
|
401
|
-
'position_inches': legend_xy_in # [x, y] offset from canvas center in inches
|
|
441
|
+
'position_inches': legend_xy_in, # [x, y] offset from canvas center in inches
|
|
442
|
+
'title': _get_legend_title(fig),
|
|
402
443
|
},
|
|
403
444
|
'ticks': {
|
|
404
445
|
'widths': {
|
|
@@ -671,6 +712,8 @@ def _apply_style(fig, ax, ax2, sc_charge, sc_discharge, sc_eff, cfg: Dict, file_
|
|
|
671
712
|
if leg_cfg:
|
|
672
713
|
leg_visible = leg_cfg.get('visible', True)
|
|
673
714
|
leg_xy_in = leg_cfg.get('position_inches')
|
|
715
|
+
if 'title' in leg_cfg:
|
|
716
|
+
fig._cpc_legend_title = leg_cfg.get('title') or _get_legend_title(fig)
|
|
674
717
|
if leg_xy_in is not None:
|
|
675
718
|
fig._cpc_legend_xy_in = _sanitize_legend_offset(tuple(leg_xy_in))
|
|
676
719
|
leg = ax.get_legend()
|
|
@@ -1197,7 +1240,7 @@ def cpc_interactive_menu(fig, ax, ax2, sc_charge, sc_discharge, sc_eff, file_dat
|
|
|
1197
1240
|
try:
|
|
1198
1241
|
xy_in = _sanitize_legend_offset(getattr(fig, '_cpc_legend_xy_in', None))
|
|
1199
1242
|
leg = ax.get_legend()
|
|
1200
|
-
if xy_in is None
|
|
1243
|
+
if xy_in is None:
|
|
1201
1244
|
return
|
|
1202
1245
|
# Compute figure-fraction anchor from inches
|
|
1203
1246
|
fw, fh = fig.get_size_inches()
|
|
@@ -1209,7 +1252,16 @@ def cpc_interactive_menu(fig, ax, ax2, sc_charge, sc_discharge, sc_eff, file_dat
|
|
|
1209
1252
|
h1, l1 = ax.get_legend_handles_labels()
|
|
1210
1253
|
h2, l2 = ax2.get_legend_handles_labels()
|
|
1211
1254
|
if h1 or h2:
|
|
1212
|
-
_legend_no_frame(
|
|
1255
|
+
_legend_no_frame(
|
|
1256
|
+
ax,
|
|
1257
|
+
h1 + h2,
|
|
1258
|
+
l1 + l2,
|
|
1259
|
+
loc='center',
|
|
1260
|
+
bbox_to_anchor=(fx, fy),
|
|
1261
|
+
bbox_transform=fig.transFigure,
|
|
1262
|
+
borderaxespad=1.0,
|
|
1263
|
+
title=_get_legend_title(fig),
|
|
1264
|
+
)
|
|
1213
1265
|
except Exception:
|
|
1214
1266
|
pass
|
|
1215
1267
|
|
|
@@ -1680,12 +1732,28 @@ def cpc_interactive_menu(fig, ax, ax2, sc_charge, sc_discharge, sc_eff, file_dat
|
|
|
1680
1732
|
else:
|
|
1681
1733
|
print(f" {i}: {fname}")
|
|
1682
1734
|
|
|
1683
|
-
|
|
1735
|
+
last_figure_path = getattr(fig, '_last_figure_export_path', None)
|
|
1736
|
+
if last_figure_path:
|
|
1737
|
+
fname = input("Export filename (default .svg if no extension), number to overwrite, or o to overwrite last (q=cancel): ").strip()
|
|
1738
|
+
else:
|
|
1739
|
+
fname = input("Export filename (default .svg if no extension) or number to overwrite (q=cancel): ").strip()
|
|
1684
1740
|
if not fname or fname.lower() == 'q':
|
|
1685
1741
|
_print_menu(); continue
|
|
1686
1742
|
|
|
1743
|
+
# Check for 'o' option
|
|
1744
|
+
if fname.lower() == 'o':
|
|
1745
|
+
if not last_figure_path:
|
|
1746
|
+
print("No previous export found.")
|
|
1747
|
+
_print_menu(); continue
|
|
1748
|
+
if not os.path.exists(last_figure_path):
|
|
1749
|
+
print(f"Previous export file not found: {last_figure_path}")
|
|
1750
|
+
_print_menu(); continue
|
|
1751
|
+
yn = input(f"Overwrite '{os.path.basename(last_figure_path)}'? (y/n): ").strip().lower()
|
|
1752
|
+
if yn != 'y':
|
|
1753
|
+
_print_menu(); continue
|
|
1754
|
+
target = last_figure_path
|
|
1687
1755
|
# Check if user selected a number
|
|
1688
|
-
|
|
1756
|
+
elif fname.isdigit() and files:
|
|
1689
1757
|
idx = int(fname)
|
|
1690
1758
|
if 1 <= idx <= len(files):
|
|
1691
1759
|
name = files[idx-1]
|
|
@@ -1734,6 +1802,7 @@ def cpc_interactive_menu(fig, ax, ax2, sc_charge, sc_discharge, sc_eff, file_dat
|
|
|
1734
1802
|
# Export the figure
|
|
1735
1803
|
fig.savefig(target, bbox_inches='tight')
|
|
1736
1804
|
print(f"Exported figure to {target}")
|
|
1805
|
+
fig._last_figure_export_path = target
|
|
1737
1806
|
|
|
1738
1807
|
# Restore original labels
|
|
1739
1808
|
if is_multi_file and original_labels:
|
|
@@ -1767,10 +1836,28 @@ def cpc_interactive_menu(fig, ax, ax2, sc_charge, sc_discharge, sc_eff, file_dat
|
|
|
1767
1836
|
print(f" {i}: {f} ({timestamp})")
|
|
1768
1837
|
else:
|
|
1769
1838
|
print(f" {i}: {f}")
|
|
1770
|
-
|
|
1839
|
+
last_session_path = getattr(fig, '_last_session_save_path', None)
|
|
1840
|
+
if last_session_path:
|
|
1841
|
+
prompt = "Enter new filename (no ext needed), number to overwrite, or o to overwrite last (q=cancel): "
|
|
1842
|
+
else:
|
|
1843
|
+
prompt = "Enter new filename (no ext needed) or number to overwrite (q=cancel): "
|
|
1771
1844
|
choice = input(prompt).strip()
|
|
1772
1845
|
if not choice or choice.lower() == 'q':
|
|
1773
1846
|
_print_menu(); continue
|
|
1847
|
+
if choice.lower() == 'o':
|
|
1848
|
+
# Overwrite last saved session
|
|
1849
|
+
if not last_session_path:
|
|
1850
|
+
print("No previous save found.")
|
|
1851
|
+
_print_menu(); continue
|
|
1852
|
+
if not os.path.exists(last_session_path):
|
|
1853
|
+
print(f"Previous save file not found: {last_session_path}")
|
|
1854
|
+
_print_menu(); continue
|
|
1855
|
+
yn = input(f"Overwrite '{os.path.basename(last_session_path)}'? (y/n): ").strip().lower()
|
|
1856
|
+
if yn != 'y':
|
|
1857
|
+
_print_menu(); continue
|
|
1858
|
+
dump_cpc_session(last_session_path, fig=fig, ax=ax, ax2=ax2, sc_charge=sc_charge, sc_discharge=sc_discharge, sc_eff=sc_eff, file_data=file_data, skip_confirm=True)
|
|
1859
|
+
print(f"Overwritten session to {last_session_path}")
|
|
1860
|
+
_print_menu(); continue
|
|
1774
1861
|
if choice.isdigit() and files:
|
|
1775
1862
|
idx = int(choice)
|
|
1776
1863
|
if 1 <= idx <= len(files):
|
|
@@ -1779,10 +1866,13 @@ def cpc_interactive_menu(fig, ax, ax2, sc_charge, sc_discharge, sc_eff, file_dat
|
|
|
1779
1866
|
if yn != 'y':
|
|
1780
1867
|
_print_menu(); continue
|
|
1781
1868
|
target = os.path.join(folder, name)
|
|
1869
|
+
dump_cpc_session(target, fig=fig, ax=ax, ax2=ax2, sc_charge=sc_charge, sc_discharge=sc_discharge, sc_eff=sc_eff, file_data=file_data, skip_confirm=True)
|
|
1870
|
+
fig._last_session_save_path = target
|
|
1871
|
+
_print_menu(); continue
|
|
1782
1872
|
else:
|
|
1783
1873
|
print("Invalid number.")
|
|
1784
1874
|
_print_menu(); continue
|
|
1785
|
-
|
|
1875
|
+
if choice.lower() != 'o':
|
|
1786
1876
|
name = choice
|
|
1787
1877
|
root, ext = os.path.splitext(name)
|
|
1788
1878
|
if ext == '':
|
|
@@ -1792,7 +1882,8 @@ def cpc_interactive_menu(fig, ax, ax2, sc_charge, sc_discharge, sc_eff, file_dat
|
|
|
1792
1882
|
yn = input(f"'{os.path.basename(target)}' exists. Overwrite? (y/n): ").strip().lower()
|
|
1793
1883
|
if yn != 'y':
|
|
1794
1884
|
_print_menu(); continue
|
|
1795
|
-
|
|
1885
|
+
dump_cpc_session(target, fig=fig, ax=ax, ax2=ax2, sc_charge=sc_charge, sc_discharge=sc_discharge, sc_eff=sc_eff, file_data=file_data, skip_confirm=True)
|
|
1886
|
+
fig._last_session_save_path = target
|
|
1796
1887
|
except Exception as e:
|
|
1797
1888
|
print(f"Save failed: {e}")
|
|
1798
1889
|
_print_menu(); continue
|
|
@@ -1916,11 +2007,44 @@ def cpc_interactive_menu(fig, ax, ax2, sc_charge, sc_discharge, sc_eff, file_dat
|
|
|
1916
2007
|
else:
|
|
1917
2008
|
print(f" {_i}: {fname}")
|
|
1918
2009
|
|
|
1919
|
-
|
|
2010
|
+
last_style_path = getattr(fig, '_last_style_export_path', None)
|
|
2011
|
+
if last_style_path:
|
|
2012
|
+
sub = input(_colorize_prompt("Style submenu: (e=export, o=overwrite last, q=return, r=refresh): ")).strip().lower()
|
|
2013
|
+
else:
|
|
2014
|
+
sub = input(_colorize_prompt("Style submenu: (e=export, q=return, r=refresh): ")).strip().lower()
|
|
1920
2015
|
if sub == 'q':
|
|
1921
2016
|
break
|
|
1922
2017
|
if sub == 'r' or sub == '':
|
|
1923
2018
|
continue
|
|
2019
|
+
if sub == 'o':
|
|
2020
|
+
# Overwrite last exported style file
|
|
2021
|
+
if not last_style_path:
|
|
2022
|
+
print("No previous export found.")
|
|
2023
|
+
continue
|
|
2024
|
+
if not os.path.exists(last_style_path):
|
|
2025
|
+
print(f"Previous export file not found: {last_style_path}")
|
|
2026
|
+
continue
|
|
2027
|
+
yn = input(f"Overwrite '{os.path.basename(last_style_path)}'? (y/n): ").strip().lower()
|
|
2028
|
+
if yn != 'y':
|
|
2029
|
+
continue
|
|
2030
|
+
# Rebuild config based on current state
|
|
2031
|
+
snap = _style_snapshot(fig, ax, ax2, sc_charge, sc_discharge, sc_eff, file_data)
|
|
2032
|
+
# Determine if last export was style-only or style+geometry
|
|
2033
|
+
try:
|
|
2034
|
+
with open(last_style_path, 'r', encoding='utf-8') as f:
|
|
2035
|
+
old_cfg = json.load(f)
|
|
2036
|
+
if old_cfg.get('kind') == 'cpc_style_geom':
|
|
2037
|
+
snap['kind'] = 'cpc_style_geom'
|
|
2038
|
+
snap['geometry'] = _get_geometry_snapshot(ax, ax2)
|
|
2039
|
+
else:
|
|
2040
|
+
snap['kind'] = 'cpc_style'
|
|
2041
|
+
except Exception:
|
|
2042
|
+
snap['kind'] = 'cpc_style'
|
|
2043
|
+
with open(last_style_path, 'w', encoding='utf-8') as f:
|
|
2044
|
+
json.dump(snap, f, indent=2)
|
|
2045
|
+
print(f"Overwritten style to {last_style_path}")
|
|
2046
|
+
style_menu_active = False
|
|
2047
|
+
break
|
|
1924
2048
|
if sub == 'e':
|
|
1925
2049
|
# Ask for ps or psg
|
|
1926
2050
|
print("Export options:")
|
|
@@ -1978,10 +2102,42 @@ def cpc_interactive_menu(fig, ax, ax2, sc_charge, sc_discharge, sc_eff, file_dat
|
|
|
1978
2102
|
print(f" {i}: {fname} ({timestamp})")
|
|
1979
2103
|
else:
|
|
1980
2104
|
print(f" {i}: {fname}")
|
|
1981
|
-
|
|
2105
|
+
if last_style_path:
|
|
2106
|
+
choice = input("Enter new filename, number to overwrite, or o to overwrite last (q=cancel): ").strip()
|
|
2107
|
+
else:
|
|
2108
|
+
choice = input("Enter new filename or number to overwrite (q=cancel): ").strip()
|
|
1982
2109
|
if not choice or choice.lower() == 'q':
|
|
1983
2110
|
print("Style export canceled.")
|
|
1984
2111
|
continue
|
|
2112
|
+
if choice.lower() == 'o':
|
|
2113
|
+
# Overwrite last exported style file
|
|
2114
|
+
if not last_style_path:
|
|
2115
|
+
print("No previous export found.")
|
|
2116
|
+
continue
|
|
2117
|
+
if not os.path.exists(last_style_path):
|
|
2118
|
+
print(f"Previous export file not found: {last_style_path}")
|
|
2119
|
+
continue
|
|
2120
|
+
yn = input(f"Overwrite '{os.path.basename(last_style_path)}'? (y/n): ").strip().lower()
|
|
2121
|
+
if yn != 'y':
|
|
2122
|
+
continue
|
|
2123
|
+
# Rebuild config based on current state
|
|
2124
|
+
snap = _style_snapshot(fig, ax, ax2, sc_charge, sc_discharge, sc_eff, file_data)
|
|
2125
|
+
# Determine if last export was style-only or style+geometry
|
|
2126
|
+
try:
|
|
2127
|
+
with open(last_style_path, 'r', encoding='utf-8') as f:
|
|
2128
|
+
old_cfg = json.load(f)
|
|
2129
|
+
if old_cfg.get('kind') == 'cpc_style_geom':
|
|
2130
|
+
snap['kind'] = 'cpc_style_geom'
|
|
2131
|
+
snap['geometry'] = _get_geometry_snapshot(ax, ax2)
|
|
2132
|
+
else:
|
|
2133
|
+
snap['kind'] = 'cpc_style'
|
|
2134
|
+
except Exception:
|
|
2135
|
+
snap['kind'] = 'cpc_style'
|
|
2136
|
+
with open(last_style_path, 'w', encoding='utf-8') as f:
|
|
2137
|
+
json.dump(snap, f, indent=2)
|
|
2138
|
+
print(f"Overwritten style to {last_style_path}")
|
|
2139
|
+
style_menu_active = False
|
|
2140
|
+
break
|
|
1985
2141
|
target = None
|
|
1986
2142
|
if choice.isdigit() and files:
|
|
1987
2143
|
idx = int(choice)
|
|
@@ -2011,6 +2167,7 @@ def cpc_interactive_menu(fig, ax, ax2, sc_charge, sc_discharge, sc_eff, file_dat
|
|
|
2011
2167
|
with open(target, 'w', encoding='utf-8') as f:
|
|
2012
2168
|
json.dump(snap, f, indent=2)
|
|
2013
2169
|
print(f"Exported CPC style to {target}")
|
|
2170
|
+
fig._last_style_export_path = target
|
|
2014
2171
|
style_menu_active = False # Exit style submenu and return to main menu
|
|
2015
2172
|
break
|
|
2016
2173
|
else:
|