batplot 1.7.28__py3-none-any.whl → 1.8.0__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/cpc_interactive.py +3 -0
- batplot/electrochem_interactive.py +90 -55
- batplot/interactive.py +92 -61
- batplot/modes.py +12 -12
- batplot/operando_ec_interactive.py +144 -74
- {batplot-1.7.28.dist-info → batplot-1.8.0.dist-info}/METADATA +1 -1
- {batplot-1.7.28.dist-info → batplot-1.8.0.dist-info}/RECORD +12 -12
- {batplot-1.7.28.dist-info → batplot-1.8.0.dist-info}/WHEEL +0 -0
- {batplot-1.7.28.dist-info → batplot-1.8.0.dist-info}/entry_points.txt +0 -0
- {batplot-1.7.28.dist-info → batplot-1.8.0.dist-info}/licenses/LICENSE +0 -0
- {batplot-1.7.28.dist-info → batplot-1.8.0.dist-info}/top_level.txt +0 -0
|
@@ -18,6 +18,7 @@ from typing import Tuple, Dict, Optional, Any
|
|
|
18
18
|
import json
|
|
19
19
|
import os
|
|
20
20
|
import time
|
|
21
|
+
import sys
|
|
21
22
|
|
|
22
23
|
import matplotlib.pyplot as plt
|
|
23
24
|
from matplotlib.colors import LinearSegmentedColormap
|
|
@@ -41,6 +42,37 @@ from .color_utils import (
|
|
|
41
42
|
from .utils import choose_style_file
|
|
42
43
|
|
|
43
44
|
|
|
45
|
+
class _FilterIMKWarning:
|
|
46
|
+
"""Filter that suppresses macOS IMKCFRunLoopWakeUpReliable warnings while preserving other errors."""
|
|
47
|
+
def __init__(self, original_stderr):
|
|
48
|
+
self.original_stderr = original_stderr
|
|
49
|
+
|
|
50
|
+
def write(self, message):
|
|
51
|
+
# Filter out the harmless macOS IMK warning
|
|
52
|
+
if 'IMKCFRunLoopWakeUpReliable' not in message:
|
|
53
|
+
self.original_stderr.write(message)
|
|
54
|
+
|
|
55
|
+
def flush(self):
|
|
56
|
+
self.original_stderr.flush()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _safe_input(prompt: str = "") -> str:
|
|
60
|
+
"""Wrapper around input() that suppresses macOS IMKCFRunLoopWakeUpReliable warnings.
|
|
61
|
+
|
|
62
|
+
This is a harmless macOS system message that appears when using input() in terminals.
|
|
63
|
+
"""
|
|
64
|
+
# Filter stderr to hide macOS IMK warnings while preserving other errors
|
|
65
|
+
original_stderr = sys.stderr
|
|
66
|
+
sys.stderr = _FilterIMKWarning(original_stderr)
|
|
67
|
+
try:
|
|
68
|
+
result = input(prompt)
|
|
69
|
+
return result
|
|
70
|
+
except (KeyboardInterrupt, EOFError):
|
|
71
|
+
raise
|
|
72
|
+
finally:
|
|
73
|
+
sys.stderr = original_stderr
|
|
74
|
+
|
|
75
|
+
|
|
44
76
|
def _axis_tick_width(axis_obj, which: str = 'major'):
|
|
45
77
|
"""Return tick line width from axis tick params or rc defaults."""
|
|
46
78
|
try:
|
|
@@ -363,7 +395,7 @@ def _detach_mpl_colorbar_callbacks(cbar, im) -> None:
|
|
|
363
395
|
if cax is not None and getattr(cax, '_bp_detached_mpl_colorbar', False):
|
|
364
396
|
return
|
|
365
397
|
|
|
366
|
-
#
|
|
398
|
+
# APPROACH 1: Try to find and disconnect the callback ID
|
|
367
399
|
cid = None
|
|
368
400
|
for attr in ('_cid', '_cid_colorbar', 'cid'):
|
|
369
401
|
try:
|
|
@@ -374,7 +406,6 @@ def _detach_mpl_colorbar_callbacks(cbar, im) -> None:
|
|
|
374
406
|
except Exception:
|
|
375
407
|
pass
|
|
376
408
|
|
|
377
|
-
# Disconnect from the ScalarMappable callback registry.
|
|
378
409
|
if cid is not None:
|
|
379
410
|
try:
|
|
380
411
|
cbreg = getattr(im, 'callbacksSM', None)
|
|
@@ -383,7 +414,38 @@ def _detach_mpl_colorbar_callbacks(cbar, im) -> None:
|
|
|
383
414
|
except Exception:
|
|
384
415
|
pass
|
|
385
416
|
|
|
386
|
-
#
|
|
417
|
+
# APPROACH 2: Disconnect ALL callbacks from the image (nuclear option)
|
|
418
|
+
try:
|
|
419
|
+
cbreg = getattr(im, 'callbacksSM', None)
|
|
420
|
+
if cbreg is not None:
|
|
421
|
+
# Try to clear all callbacks
|
|
422
|
+
if hasattr(cbreg, 'callbacks'):
|
|
423
|
+
try:
|
|
424
|
+
cbreg.callbacks.clear()
|
|
425
|
+
except Exception:
|
|
426
|
+
pass
|
|
427
|
+
# Also try the _signals dict if it exists
|
|
428
|
+
if hasattr(cbreg, '_signals'):
|
|
429
|
+
try:
|
|
430
|
+
for signal_dict in cbreg._signals.values():
|
|
431
|
+
if hasattr(signal_dict, 'clear'):
|
|
432
|
+
signal_dict.clear()
|
|
433
|
+
except Exception:
|
|
434
|
+
pass
|
|
435
|
+
except Exception:
|
|
436
|
+
pass
|
|
437
|
+
|
|
438
|
+
# APPROACH 3: Monkey-patch the update_normal method to be a no-op
|
|
439
|
+
# This is the most reliable approach for preventing the callback
|
|
440
|
+
try:
|
|
441
|
+
if hasattr(cbar, 'update_normal'):
|
|
442
|
+
def _noop_update(*args, **kwargs):
|
|
443
|
+
pass
|
|
444
|
+
cbar.update_normal = _noop_update
|
|
445
|
+
except Exception:
|
|
446
|
+
pass
|
|
447
|
+
|
|
448
|
+
# APPROACH 4: Prevent future built-in updates by nulling internal state
|
|
387
449
|
try:
|
|
388
450
|
if hasattr(cbar, 'mappable'):
|
|
389
451
|
cbar.mappable = None
|
|
@@ -1733,7 +1795,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
1733
1795
|
print("Crosshair OFF.")
|
|
1734
1796
|
while True:
|
|
1735
1797
|
try:
|
|
1736
|
-
cmd =
|
|
1798
|
+
cmd = _safe_input("Press a key: ").strip().lower()
|
|
1737
1799
|
except (KeyboardInterrupt, EOFError):
|
|
1738
1800
|
print("\n\nExiting interactive menu...")
|
|
1739
1801
|
break
|
|
@@ -1741,7 +1803,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
1741
1803
|
continue
|
|
1742
1804
|
if cmd == 'q':
|
|
1743
1805
|
try:
|
|
1744
|
-
ans =
|
|
1806
|
+
ans = _safe_input("Quit interactive? Remember to save (e=export, s=save). Quit now? (y/n): ").strip().lower()
|
|
1745
1807
|
except Exception:
|
|
1746
1808
|
ans = 'y'
|
|
1747
1809
|
if ans == 'y':
|
|
@@ -1784,9 +1846,9 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
1784
1846
|
|
|
1785
1847
|
last_figure_path = getattr(fig, '_last_figure_export_path', None)
|
|
1786
1848
|
if last_figure_path:
|
|
1787
|
-
fname =
|
|
1849
|
+
fname = _safe_input("Export filename (default .svg if no extension), number to overwrite, or o to overwrite last (q=cancel): ").strip()
|
|
1788
1850
|
else:
|
|
1789
|
-
fname =
|
|
1851
|
+
fname = _safe_input("Export filename (default .svg if no extension) or number to overwrite (q=cancel): ").strip()
|
|
1790
1852
|
if not fname or fname.lower() == 'q':
|
|
1791
1853
|
print_menu(); continue
|
|
1792
1854
|
|
|
@@ -1799,7 +1861,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
1799
1861
|
if not os.path.exists(last_figure_path):
|
|
1800
1862
|
print(f"Previous export file not found: {last_figure_path}")
|
|
1801
1863
|
print_menu(); continue
|
|
1802
|
-
yn =
|
|
1864
|
+
yn = _safe_input(f"Overwrite '{os.path.basename(last_figure_path)}'? (y/n): ").strip().lower()
|
|
1803
1865
|
if yn != 'y':
|
|
1804
1866
|
print_menu(); continue
|
|
1805
1867
|
target = last_figure_path
|
|
@@ -1810,7 +1872,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
1810
1872
|
idx = int(fname)
|
|
1811
1873
|
if 1 <= idx <= len(files):
|
|
1812
1874
|
name = files[idx-1]
|
|
1813
|
-
yn =
|
|
1875
|
+
yn = _safe_input(f"Overwrite '{name}'? (y/n): ").strip().lower()
|
|
1814
1876
|
if yn != 'y':
|
|
1815
1877
|
print_menu(); continue
|
|
1816
1878
|
target = file_list[idx-1][1] # Full path from list
|
|
@@ -1889,7 +1951,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
1889
1951
|
cb_h_offset = getattr(cbar.ax, '_cb_h_offset_in', 0.0)
|
|
1890
1952
|
ec_h_offset = getattr(ec_ax, '_ec_h_offset_in', 0.0)
|
|
1891
1953
|
print(f"Toggle: 1=colorbar, 2=EC panel, 3=both, 4=colorbar label mode, 5=colorbar label text, m=move horizontal position (cb:{cb_h_offset:.3f}\", ec:{ec_h_offset:.3f}\"), q=cancel")
|
|
1892
|
-
choice =
|
|
1954
|
+
choice = _safe_input("v> ").strip().lower()
|
|
1893
1955
|
if choice == '1':
|
|
1894
1956
|
# Toggle colorbar
|
|
1895
1957
|
cb_vis = cbar.ax.get_visible()
|
|
@@ -1923,7 +1985,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
1923
1985
|
# Change colorbar label text
|
|
1924
1986
|
current_label = getattr(cbar.ax, '_colorbar_label', 'Intensity')
|
|
1925
1987
|
print(f"Current colorbar label: {current_label}")
|
|
1926
|
-
new_label =
|
|
1988
|
+
new_label = _safe_input("New colorbar label (blank to keep): ").strip()
|
|
1927
1989
|
if new_label:
|
|
1928
1990
|
cbar.ax._colorbar_label = new_label
|
|
1929
1991
|
try:
|
|
@@ -1944,12 +2006,12 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
1944
2006
|
if ec_ax is not None:
|
|
1945
2007
|
print(f" EC panel offset: {ec_h_offset:.3f}\" (positive=right, negative=left)")
|
|
1946
2008
|
print("Commands: c=colorbar, e=EC panel, q=back")
|
|
1947
|
-
sub =
|
|
2009
|
+
sub = _safe_input("m> ").strip().lower()
|
|
1948
2010
|
if not sub or sub == 'q':
|
|
1949
2011
|
break
|
|
1950
2012
|
if sub == 'c':
|
|
1951
2013
|
try:
|
|
1952
|
-
new_offset =
|
|
2014
|
+
new_offset = _safe_input(f"Enter colorbar horizontal offset in inches (current: {cb_h_offset:.3f}\"): ").strip()
|
|
1953
2015
|
if new_offset:
|
|
1954
2016
|
cb_h_offset = float(new_offset)
|
|
1955
2017
|
setattr(cbar.ax, '_cb_h_offset_in', cb_h_offset)
|
|
@@ -1957,6 +2019,8 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
1957
2019
|
_apply_group_layout_inches(fig, ax, cbar.ax, ec_ax, ax_w_in, ax_h_in, cb_w_in, cb_gap_in, ec_gap_in, ec_w_in)
|
|
1958
2020
|
fig.canvas.draw_idle()
|
|
1959
2021
|
print(f"Colorbar horizontal offset set to {cb_h_offset:.3f}\"")
|
|
2022
|
+
# Continue in loop to show menu again
|
|
2023
|
+
continue
|
|
1960
2024
|
except ValueError:
|
|
1961
2025
|
print("Invalid input. Enter a number.")
|
|
1962
2026
|
except Exception as e:
|
|
@@ -1966,7 +2030,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
1966
2030
|
print("EC panel not available.")
|
|
1967
2031
|
continue
|
|
1968
2032
|
try:
|
|
1969
|
-
new_offset =
|
|
2033
|
+
new_offset = _safe_input(f"Enter EC panel horizontal offset in inches (current: {ec_h_offset:.3f}\"): ").strip()
|
|
1970
2034
|
if new_offset:
|
|
1971
2035
|
ec_h_offset = float(new_offset)
|
|
1972
2036
|
setattr(ec_ax, '_ec_h_offset_in', ec_h_offset)
|
|
@@ -1974,6 +2038,8 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
1974
2038
|
_apply_group_layout_inches(fig, ax, cbar.ax, ec_ax, ax_w_in, ax_h_in, cb_w_in, cb_gap_in, ec_gap_in, ec_w_in)
|
|
1975
2039
|
fig.canvas.draw_idle()
|
|
1976
2040
|
print(f"EC panel horizontal offset set to {ec_h_offset:.3f}\"")
|
|
2041
|
+
# Continue in loop to show menu again
|
|
2042
|
+
continue
|
|
1977
2043
|
except ValueError:
|
|
1978
2044
|
print("Invalid input. Enter a number.")
|
|
1979
2045
|
except Exception as e:
|
|
@@ -1986,7 +2052,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
1986
2052
|
# Operando-only mode: toggle colorbar or change label mode
|
|
1987
2053
|
cb_h_offset = getattr(cbar.ax, '_cb_h_offset_in', 0.0)
|
|
1988
2054
|
print(f"Toggle: 1=colorbar visibility, 2=colorbar label mode, 3=colorbar label text, m=move horizontal position (cb:{cb_h_offset:.3f}\"), q=cancel")
|
|
1989
|
-
choice =
|
|
2055
|
+
choice = _safe_input("v> ").strip().lower()
|
|
1990
2056
|
if choice == '1':
|
|
1991
2057
|
cb_vis = cbar.ax.get_visible()
|
|
1992
2058
|
cbar.ax.set_visible(not cb_vis)
|
|
@@ -2006,7 +2072,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2006
2072
|
# Change colorbar label text
|
|
2007
2073
|
current_label = getattr(cbar.ax, '_colorbar_label', 'Intensity')
|
|
2008
2074
|
print(f"Current colorbar label: {current_label}")
|
|
2009
|
-
new_label =
|
|
2075
|
+
new_label = _safe_input("New colorbar label (blank to keep): ").strip()
|
|
2010
2076
|
if new_label:
|
|
2011
2077
|
cbar.ax._colorbar_label = new_label
|
|
2012
2078
|
try:
|
|
@@ -2024,12 +2090,12 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2024
2090
|
print(f"\nHorizontal position (relative to canvas center):")
|
|
2025
2091
|
print(f" Colorbar offset: {cb_h_offset:.3f}\" (positive=right, negative=left)")
|
|
2026
2092
|
print("Commands: c=colorbar, q=back")
|
|
2027
|
-
sub =
|
|
2093
|
+
sub = _safe_input("m> ").strip().lower()
|
|
2028
2094
|
if not sub or sub == 'q':
|
|
2029
2095
|
break
|
|
2030
2096
|
if sub == 'c':
|
|
2031
2097
|
try:
|
|
2032
|
-
new_offset =
|
|
2098
|
+
new_offset = _safe_input(f"Enter colorbar horizontal offset in inches (current: {cb_h_offset:.3f}\"): ").strip()
|
|
2033
2099
|
if new_offset:
|
|
2034
2100
|
cb_h_offset = float(new_offset)
|
|
2035
2101
|
setattr(cbar.ax, '_cb_h_offset_in', cb_h_offset)
|
|
@@ -2037,6 +2103,8 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2037
2103
|
_apply_group_layout_inches(fig, ax, cbar.ax, ec_ax, ax_w_in, ax_h_in, cb_w_in, cb_gap_in, ec_gap_in, ec_w_in)
|
|
2038
2104
|
fig.canvas.draw_idle()
|
|
2039
2105
|
print(f"Colorbar horizontal offset set to {cb_h_offset:.3f}\"")
|
|
2106
|
+
# Continue in loop to show menu again
|
|
2107
|
+
continue
|
|
2040
2108
|
except ValueError:
|
|
2041
2109
|
print("Invalid input. Enter a number.")
|
|
2042
2110
|
except Exception as e:
|
|
@@ -2079,7 +2147,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2079
2147
|
prompt = "Enter new filename (no ext needed), number to overwrite, or o to overwrite last (q=cancel): "
|
|
2080
2148
|
else:
|
|
2081
2149
|
prompt = "Enter new filename (no ext needed) or number to overwrite (q=cancel): "
|
|
2082
|
-
choice =
|
|
2150
|
+
choice = _safe_input(prompt).strip()
|
|
2083
2151
|
if not choice or choice.lower() == 'q':
|
|
2084
2152
|
print_menu(); continue
|
|
2085
2153
|
if choice.lower() == 'o':
|
|
@@ -2090,7 +2158,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2090
2158
|
if not os.path.exists(last_session_path):
|
|
2091
2159
|
print(f"Previous save file not found: {last_session_path}")
|
|
2092
2160
|
print_menu(); continue
|
|
2093
|
-
yn =
|
|
2161
|
+
yn = _safe_input(f"Overwrite '{os.path.basename(last_session_path)}'? (y/n): ").strip().lower()
|
|
2094
2162
|
if yn != 'y':
|
|
2095
2163
|
print_menu(); continue
|
|
2096
2164
|
dump_operando_session(last_session_path, fig=fig, ax=ax, im=im, cbar=cbar, ec_ax=ec_ax, skip_confirm=True)
|
|
@@ -2100,7 +2168,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2100
2168
|
idx = int(choice)
|
|
2101
2169
|
if 1 <= idx <= len(files):
|
|
2102
2170
|
name = files[idx-1]
|
|
2103
|
-
yn =
|
|
2171
|
+
yn = _safe_input(f"Overwrite '{name}'? (y/n): ").strip().lower()
|
|
2104
2172
|
if yn != 'y':
|
|
2105
2173
|
print_menu(); continue
|
|
2106
2174
|
target = os.path.join(folder, name)
|
|
@@ -2117,7 +2185,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2117
2185
|
name = name + '.pkl'
|
|
2118
2186
|
target = name if os.path.isabs(name) else os.path.join(folder, name)
|
|
2119
2187
|
if os.path.exists(target):
|
|
2120
|
-
yn =
|
|
2188
|
+
yn = _safe_input(f"'{os.path.basename(target)}' exists. Overwrite? (y/n): ").strip().lower()
|
|
2121
2189
|
if yn != 'y':
|
|
2122
2190
|
print_menu(); continue
|
|
2123
2191
|
dump_operando_session(target, fig=fig, ax=ax, im=im, cbar=cbar, ec_ax=ec_ax, skip_confirm=True)
|
|
@@ -2142,7 +2210,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2142
2210
|
# Always read fresh value from attribute to avoid stale cached value
|
|
2143
2211
|
ax_h_in = getattr(ax, '_fixed_ax_h_in', ax_h_in)
|
|
2144
2212
|
print(f"Current height: {ax_h_in:.2f} in")
|
|
2145
|
-
val =
|
|
2213
|
+
val = _safe_input("New height (inches): ").strip()
|
|
2146
2214
|
if val:
|
|
2147
2215
|
_snapshot("height")
|
|
2148
2216
|
try:
|
|
@@ -2182,7 +2250,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2182
2250
|
print(f"\nFont submenu (current: family='{cur_family}', size={cur_size})")
|
|
2183
2251
|
print(" f: change family | s: change size | q: back")
|
|
2184
2252
|
while True:
|
|
2185
|
-
sub =
|
|
2253
|
+
sub = _safe_input("Font> ").strip().lower()
|
|
2186
2254
|
if not sub:
|
|
2187
2255
|
continue
|
|
2188
2256
|
if sub == 'q':
|
|
@@ -2195,7 +2263,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2195
2263
|
for i, font in enumerate(fonts, 1):
|
|
2196
2264
|
print(f" {i}: {font}")
|
|
2197
2265
|
print("Or enter custom font name directly.")
|
|
2198
|
-
choice =
|
|
2266
|
+
choice = _safe_input("Font family (number or name): ").strip()
|
|
2199
2267
|
if not choice:
|
|
2200
2268
|
continue
|
|
2201
2269
|
_snapshot("font-family")
|
|
@@ -2215,7 +2283,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2215
2283
|
elif sub == 's':
|
|
2216
2284
|
# Show current size and accept direct input
|
|
2217
2285
|
cur_size = plt.rcParams.get('font.size', None)
|
|
2218
|
-
choice =
|
|
2286
|
+
choice = _safe_input(f"Font size (current: {cur_size}): ").strip()
|
|
2219
2287
|
if not choice:
|
|
2220
2288
|
continue
|
|
2221
2289
|
_snapshot("font-size")
|
|
@@ -2238,7 +2306,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2238
2306
|
print(_colorize_inline_commands(" 1.5 2.5 - set frame=1.5, ticks=2.5"))
|
|
2239
2307
|
print(_colorize_inline_commands(" q - cancel"))
|
|
2240
2308
|
|
|
2241
|
-
inp =
|
|
2309
|
+
inp = _safe_input("Line widths> ").strip().lower()
|
|
2242
2310
|
if not inp or inp == 'q':
|
|
2243
2311
|
print_menu()
|
|
2244
2312
|
continue
|
|
@@ -2301,6 +2369,8 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2301
2369
|
# Unified WASD ticks/labels/spines submenu for either pane
|
|
2302
2370
|
# Import here to avoid scoping issues with nested functions
|
|
2303
2371
|
from matplotlib.ticker import AutoMinorLocator, NullFormatter, MaxNLocator, NullLocator
|
|
2372
|
+
# Import UI positioning functions locally to ensure they're accessible in nested functions
|
|
2373
|
+
from .ui import position_top_xlabel as _ui_position_top_xlabel, position_bottom_xlabel as _ui_position_bottom_xlabel, position_left_ylabel as _ui_position_left_ylabel, position_right_ylabel as _ui_position_right_ylabel
|
|
2304
2374
|
|
|
2305
2375
|
def _get_tick_state(a):
|
|
2306
2376
|
# Unified keys with fallbacks for legacy combined flags
|
|
@@ -2386,7 +2456,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2386
2456
|
print(_colorize_inline_commands("Choose pane: o=operando, e=ec, q=back"))
|
|
2387
2457
|
else:
|
|
2388
2458
|
print(_colorize_inline_commands("Choose pane: o=operando, q=back"))
|
|
2389
|
-
pane =
|
|
2459
|
+
pane = _safe_input("ot> ").strip().lower()
|
|
2390
2460
|
if not pane:
|
|
2391
2461
|
continue
|
|
2392
2462
|
if pane == 'q':
|
|
@@ -2605,7 +2675,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2605
2675
|
print(_colorize_inline_commands("Type 'i' to invert tick direction, 'l' to change tick length, 'list' for state, 'q' to return."))
|
|
2606
2676
|
print(_colorize_inline_commands(" p = adjust title offsets (w=top, s=bottom, a=left, d=right)"))
|
|
2607
2677
|
while True:
|
|
2608
|
-
cmd2 =
|
|
2678
|
+
cmd2 = _safe_input(_colorize_prompt("Toggle> ")).strip().lower()
|
|
2609
2679
|
if not cmd2:
|
|
2610
2680
|
continue
|
|
2611
2681
|
if cmd2 == 'q':
|
|
@@ -2630,7 +2700,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2630
2700
|
# Get current major tick length from axes
|
|
2631
2701
|
current_major = ax.xaxis.get_major_ticks()[0].tick1line.get_markersize() if ax.xaxis.get_major_ticks() else 4.0
|
|
2632
2702
|
print(f"Current major tick length: {current_major}")
|
|
2633
|
-
new_length_str =
|
|
2703
|
+
new_length_str = _safe_input("Enter new major tick length (e.g., 6.0): ").strip()
|
|
2634
2704
|
if not new_length_str:
|
|
2635
2705
|
continue
|
|
2636
2706
|
new_major = float(new_length_str)
|
|
@@ -2723,7 +2793,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2723
2793
|
current_y_px = _px_value('_top_xlabel_manual_offset_y_pts', target)
|
|
2724
2794
|
current_x_px = _px_value('_top_xlabel_manual_offset_x_pts', target)
|
|
2725
2795
|
print(f"Top title offset: Y={current_y_px:+.2f} px (positive=up), X={current_x_px:+.2f} px (positive=right)")
|
|
2726
|
-
sub =
|
|
2796
|
+
sub = _safe_input(_colorize_prompt("top (w=up, s=down, a=left, d=right, 0=reset, q=back): ")).strip().lower()
|
|
2727
2797
|
if not sub:
|
|
2728
2798
|
continue
|
|
2729
2799
|
if sub == 'q':
|
|
@@ -2760,7 +2830,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2760
2830
|
while True:
|
|
2761
2831
|
current_y_px = _px_value('_bottom_xlabel_manual_offset_y_pts', target)
|
|
2762
2832
|
print(f"Bottom title offset: Y={current_y_px:+.2f} px (positive=down)")
|
|
2763
|
-
sub =
|
|
2833
|
+
sub = _safe_input(_colorize_prompt("bottom (s=down, w=up, 0=reset, q=back): ")).strip().lower()
|
|
2764
2834
|
if not sub:
|
|
2765
2835
|
continue
|
|
2766
2836
|
if sub == 'q':
|
|
@@ -2790,7 +2860,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2790
2860
|
while True:
|
|
2791
2861
|
current_x_px = _px_value('_left_ylabel_manual_offset_x_pts', target)
|
|
2792
2862
|
print(f"Left title offset: X={current_x_px:+.2f} px (positive=left)")
|
|
2793
|
-
sub =
|
|
2863
|
+
sub = _safe_input(_colorize_prompt("left (a=left, d=right, 0=reset, q=back): ")).strip().lower()
|
|
2794
2864
|
if not sub:
|
|
2795
2865
|
continue
|
|
2796
2866
|
if sub == 'q':
|
|
@@ -2827,7 +2897,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2827
2897
|
current_x_px = _px_value('_right_ylabel_manual_offset_x_pts', target)
|
|
2828
2898
|
current_y_px = _px_value('_right_ylabel_manual_offset_y_pts', target)
|
|
2829
2899
|
print(f"Right title offset: X={current_x_px:+.2f} px (positive=right), Y={current_y_px:+.2f} px (positive=up)")
|
|
2830
|
-
sub =
|
|
2900
|
+
sub = _safe_input(_colorize_prompt("right (d=right, a=left, w=up, s=down, 0=reset, q=back): ")).strip().lower()
|
|
2831
2901
|
if not sub:
|
|
2832
2902
|
continue
|
|
2833
2903
|
if sub == 'q':
|
|
@@ -2866,7 +2936,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2866
2936
|
print(" " + _colorize_menu('d : adjust right title (d=right, a=left, w=up, s=down)'))
|
|
2867
2937
|
print(" " + _colorize_menu('r : reset all offsets'))
|
|
2868
2938
|
print(" " + _colorize_menu('q : return'))
|
|
2869
|
-
choice =
|
|
2939
|
+
choice = _safe_input(_colorize_prompt("p> ")).strip().lower()
|
|
2870
2940
|
if not choice:
|
|
2871
2941
|
continue
|
|
2872
2942
|
if choice == 'q':
|
|
@@ -2982,7 +3052,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2982
3052
|
elif cmd == 'ox':
|
|
2983
3053
|
while True:
|
|
2984
3054
|
cur = ax.get_xlim(); print(f"Current operando X: {cur[0]:.4g} {cur[1]:.4g}")
|
|
2985
|
-
line =
|
|
3055
|
+
line = _safe_input("New X range (min max), w=upper only, s=lower only, a=auto (restore original), q=back: ").strip()
|
|
2986
3056
|
if not line or line.lower() == 'q':
|
|
2987
3057
|
break
|
|
2988
3058
|
if line.lower() == 'w':
|
|
@@ -2990,7 +3060,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2990
3060
|
while True:
|
|
2991
3061
|
cur = ax.get_xlim()
|
|
2992
3062
|
print(f"Current operando X: {cur[0]:.4g} {cur[1]:.4g}")
|
|
2993
|
-
val =
|
|
3063
|
+
val = _safe_input(f"Enter new upper X limit (current lower: {cur[0]:.4g}, q=back): ").strip()
|
|
2994
3064
|
if not val or val.lower() == 'q':
|
|
2995
3065
|
break
|
|
2996
3066
|
try:
|
|
@@ -3009,7 +3079,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
3009
3079
|
while True:
|
|
3010
3080
|
cur = ax.get_xlim()
|
|
3011
3081
|
print(f"Current operando X: {cur[0]:.4g} {cur[1]:.4g}")
|
|
3012
|
-
val =
|
|
3082
|
+
val = _safe_input(f"Enter new lower X limit (current upper: {cur[1]:.4g}, q=back): ").strip()
|
|
3013
3083
|
if not val or val.lower() == 'q':
|
|
3014
3084
|
break
|
|
3015
3085
|
try:
|
|
@@ -3055,7 +3125,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
3055
3125
|
elif cmd == 'oy':
|
|
3056
3126
|
while True:
|
|
3057
3127
|
cur = ax.get_ylim(); print(f"Current operando Y: {cur[0]:.4g} {cur[1]:.4g}")
|
|
3058
|
-
line =
|
|
3128
|
+
line = _safe_input("New Y range (min max), w=upper only, s=lower only, a=auto (restore original), q=back: ").strip()
|
|
3059
3129
|
if not line or line.lower() == 'q':
|
|
3060
3130
|
break
|
|
3061
3131
|
if line.lower() == 'w':
|
|
@@ -3063,7 +3133,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
3063
3133
|
while True:
|
|
3064
3134
|
cur = ax.get_ylim()
|
|
3065
3135
|
print(f"Current operando Y: {cur[0]:.4g} {cur[1]:.4g}")
|
|
3066
|
-
val =
|
|
3136
|
+
val = _safe_input(f"Enter new upper Y limit (current lower: {cur[0]:.4g}, q=back): ").strip()
|
|
3067
3137
|
if not val or val.lower() == 'q':
|
|
3068
3138
|
break
|
|
3069
3139
|
try:
|
|
@@ -3082,7 +3152,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
3082
3152
|
while True:
|
|
3083
3153
|
cur = ax.get_ylim()
|
|
3084
3154
|
print(f"Current operando Y: {cur[0]:.4g} {cur[1]:.4g}")
|
|
3085
|
-
val =
|
|
3155
|
+
val = _safe_input(f"Enter new lower Y limit (current upper: {cur[1]:.4g}, q=back): ").strip()
|
|
3086
3156
|
if not val or val.lower() == 'q':
|
|
3087
3157
|
break
|
|
3088
3158
|
try:
|
|
@@ -3185,9 +3255,9 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
3185
3255
|
auto_available = False
|
|
3186
3256
|
|
|
3187
3257
|
if auto_available:
|
|
3188
|
-
line =
|
|
3258
|
+
line = _safe_input("New intensity range (min max, w=upper only, s=lower only, a=auto-fit to visible, q=back): ").strip()
|
|
3189
3259
|
else:
|
|
3190
|
-
line =
|
|
3260
|
+
line = _safe_input("New intensity range (min max, w=upper only, s=lower only, q=back): ").strip()
|
|
3191
3261
|
|
|
3192
3262
|
if not line or line.lower() == 'q':
|
|
3193
3263
|
break
|
|
@@ -3201,7 +3271,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
3201
3271
|
except Exception:
|
|
3202
3272
|
print("Could not retrieve current color scale range")
|
|
3203
3273
|
break
|
|
3204
|
-
val =
|
|
3274
|
+
val = _safe_input(f"Enter new upper intensity limit (current lower: {cur[0]:.4g}, q=back): ").strip()
|
|
3205
3275
|
if not val or val.lower() == 'q':
|
|
3206
3276
|
break
|
|
3207
3277
|
try:
|
|
@@ -3227,7 +3297,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
3227
3297
|
except Exception:
|
|
3228
3298
|
print("Could not retrieve current color scale range")
|
|
3229
3299
|
break
|
|
3230
|
-
val =
|
|
3300
|
+
val = _safe_input(f"Enter new lower intensity limit (current upper: {cur[1]:.4g}, q=back): ").strip()
|
|
3231
3301
|
if not val or val.lower() == 'q':
|
|
3232
3302
|
break
|
|
3233
3303
|
try:
|
|
@@ -3278,7 +3348,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
3278
3348
|
while True:
|
|
3279
3349
|
ax_w_in = getattr(ax, '_fixed_ax_w_in', ax_w_in)
|
|
3280
3350
|
print(f"Current operando width: {ax_w_in:.2f} in")
|
|
3281
|
-
val =
|
|
3351
|
+
val = _safe_input("New width (inches, q=back): ").strip()
|
|
3282
3352
|
if not val or val.lower() == 'q':
|
|
3283
3353
|
break
|
|
3284
3354
|
_snapshot("operando-width")
|
|
@@ -3298,7 +3368,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
3298
3368
|
while True:
|
|
3299
3369
|
ec_w_in = getattr(ec_ax, '_fixed_ec_w_in', ec_w_in)
|
|
3300
3370
|
print(f"Current EC width: {ec_w_in:.2f} in")
|
|
3301
|
-
val =
|
|
3371
|
+
val = _safe_input("New EC width (inches, q=back): ").strip()
|
|
3302
3372
|
if not val or val.lower() == 'q':
|
|
3303
3373
|
break
|
|
3304
3374
|
_snapshot("ec-width")
|
|
@@ -3341,7 +3411,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
3341
3411
|
if optional:
|
|
3342
3412
|
print("\nOther available: " + ", ".join(optional))
|
|
3343
3413
|
print(_colorize_inline_commands("Append _r to reverse (e.g., viridis_r or 1_r). Blank to cancel."))
|
|
3344
|
-
choice =
|
|
3414
|
+
choice = _safe_input(f"Palette name or number (1-{len(rec_palettes)}): ").strip()
|
|
3345
3415
|
if not choice:
|
|
3346
3416
|
print_menu(); continue
|
|
3347
3417
|
try:
|
|
@@ -3590,7 +3660,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
3590
3660
|
last_style_path = getattr(fig, '_last_style_export_path', None)
|
|
3591
3661
|
if ec_ax is None:
|
|
3592
3662
|
print("\nNote: Style export (.bps/.bpsg) is only available in dual-pane mode (with EC file).")
|
|
3593
|
-
sub =
|
|
3663
|
+
sub = _safe_input("Style submenu: (q=return, r=refresh): ").strip().lower()
|
|
3594
3664
|
if sub == 'q':
|
|
3595
3665
|
break
|
|
3596
3666
|
if sub == 'r' or sub == '':
|
|
@@ -3600,9 +3670,9 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
3600
3670
|
continue
|
|
3601
3671
|
else:
|
|
3602
3672
|
if last_style_path:
|
|
3603
|
-
sub =
|
|
3673
|
+
sub = _safe_input("Style submenu: (e=export, o=overwrite last, q=return, r=refresh): ").strip().lower()
|
|
3604
3674
|
else:
|
|
3605
|
-
sub =
|
|
3675
|
+
sub = _safe_input("Style submenu: (e=export, q=return, r=refresh): ").strip().lower()
|
|
3606
3676
|
if sub == 'q':
|
|
3607
3677
|
break
|
|
3608
3678
|
if sub == 'r' or sub == '':
|
|
@@ -3615,7 +3685,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
3615
3685
|
if not os.path.exists(last_style_path):
|
|
3616
3686
|
print(f"Previous export file not found: {last_style_path}")
|
|
3617
3687
|
continue
|
|
3618
|
-
yn =
|
|
3688
|
+
yn = _safe_input(f"Overwrite '{os.path.basename(last_style_path)}'? (y/n): ").strip().lower()
|
|
3619
3689
|
if yn != 'y':
|
|
3620
3690
|
continue
|
|
3621
3691
|
# Determine export type from existing file and rebuild config
|
|
@@ -3636,7 +3706,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
3636
3706
|
print("Export options:")
|
|
3637
3707
|
print(" ps = style only (.bps)")
|
|
3638
3708
|
print(" psg = style + geometry (.bpsg)")
|
|
3639
|
-
exp_choice =
|
|
3709
|
+
exp_choice = _safe_input("Export choice (ps/psg, q=cancel): ").strip().lower()
|
|
3640
3710
|
if not exp_choice or exp_choice == 'q':
|
|
3641
3711
|
print("Style export canceled.")
|
|
3642
3712
|
continue
|
|
@@ -3830,7 +3900,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
3830
3900
|
else:
|
|
3831
3901
|
print(f" {_i}: {fname}")
|
|
3832
3902
|
|
|
3833
|
-
choice_name =
|
|
3903
|
+
choice_name = _safe_input("Enter new filename or number to overwrite (q=cancel): ").strip()
|
|
3834
3904
|
if not choice_name or choice_name.lower() == 'q':
|
|
3835
3905
|
print("Style export canceled.")
|
|
3836
3906
|
continue
|
|
@@ -3839,7 +3909,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
3839
3909
|
_idx = int(choice_name)
|
|
3840
3910
|
if 1 <= _idx <= len(_style_files):
|
|
3841
3911
|
name = _style_files[_idx-1]
|
|
3842
|
-
yn =
|
|
3912
|
+
yn = _safe_input(f"Overwrite '{name}'? (y/n): ").strip().lower()
|
|
3843
3913
|
if yn == 'y':
|
|
3844
3914
|
target = file_list[_idx-1][1] # Full path from list
|
|
3845
3915
|
else:
|
|
@@ -3856,7 +3926,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
3856
3926
|
else:
|
|
3857
3927
|
target = get_organized_path(name, 'style', base_path=save_base)
|
|
3858
3928
|
if os.path.exists(target):
|
|
3859
|
-
yn =
|
|
3929
|
+
yn = _safe_input(f"'{os.path.basename(target)}' exists. Overwrite? (y/n): ").strip().lower()
|
|
3860
3930
|
if yn != 'y':
|
|
3861
3931
|
target = None
|
|
3862
3932
|
if target:
|
|
@@ -4554,14 +4624,14 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
4554
4624
|
print(" Subscript: H$_2$O → H₂O | Superscript: m$^2$ → m²")
|
|
4555
4625
|
print(" Bullet: $\\bullet$ → • | Greek: $\\alpha$, $\\beta$ | Angstrom: $\\AA$ → Å")
|
|
4556
4626
|
while True:
|
|
4557
|
-
sub =
|
|
4627
|
+
sub = _safe_input("or> ").strip().lower()
|
|
4558
4628
|
if not sub:
|
|
4559
4629
|
continue
|
|
4560
4630
|
if sub == 'q':
|
|
4561
4631
|
break
|
|
4562
4632
|
if sub == 'x':
|
|
4563
4633
|
cur = ax.get_xlabel() or ''
|
|
4564
|
-
lab =
|
|
4634
|
+
lab = _safe_input(f"New operando X label (blank=cancel, current='{cur}'): ")
|
|
4565
4635
|
if lab:
|
|
4566
4636
|
_snapshot("rename-op-x")
|
|
4567
4637
|
try:
|
|
@@ -4574,7 +4644,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
4574
4644
|
pass
|
|
4575
4645
|
elif sub == 'y':
|
|
4576
4646
|
cur = ax.get_ylabel() or ''
|
|
4577
|
-
lab =
|
|
4647
|
+
lab = _safe_input(f"New operando Y label (blank=cancel, current='{cur}'): ")
|
|
4578
4648
|
if lab:
|
|
4579
4649
|
_snapshot("rename-op-y")
|
|
4580
4650
|
try:
|
|
@@ -4606,14 +4676,14 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
4606
4676
|
print(" Subscript: H$_2$O → H₂O | Superscript: m$^2$ → m²")
|
|
4607
4677
|
print(" Greek: $\\alpha$, $\\beta$ | Angstrom: $\\AA$ → Å")
|
|
4608
4678
|
while True:
|
|
4609
|
-
sub =
|
|
4679
|
+
sub = _safe_input("er> ").strip().lower()
|
|
4610
4680
|
if not sub:
|
|
4611
4681
|
continue
|
|
4612
4682
|
if sub == 'q':
|
|
4613
4683
|
break
|
|
4614
4684
|
if sub == 'x':
|
|
4615
4685
|
cur = ec_ax.get_xlabel() or ''
|
|
4616
|
-
lab =
|
|
4686
|
+
lab = _safe_input(f"New EC X label (blank=cancel, current='{cur}'): ")
|
|
4617
4687
|
if lab:
|
|
4618
4688
|
_snapshot("rename-ec-x")
|
|
4619
4689
|
try:
|
|
@@ -4625,7 +4695,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
4625
4695
|
pass
|
|
4626
4696
|
elif sub == 'y':
|
|
4627
4697
|
cur = ec_ax.get_ylabel() or ''
|
|
4628
|
-
lab =
|
|
4698
|
+
lab = _safe_input(f"New EC Y label (blank=cancel, current='{cur}'): ")
|
|
4629
4699
|
if lab:
|
|
4630
4700
|
_snapshot("rename-ec-y")
|
|
4631
4701
|
try:
|
|
@@ -4663,7 +4733,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
4663
4733
|
print_menu(); continue
|
|
4664
4734
|
print("EC line submenu: c=color, l=linewidth, q=back")
|
|
4665
4735
|
while True:
|
|
4666
|
-
sub =
|
|
4736
|
+
sub = _safe_input("el> ").strip().lower()
|
|
4667
4737
|
if not sub:
|
|
4668
4738
|
continue
|
|
4669
4739
|
if sub == 'q':
|
|
@@ -4679,7 +4749,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
4679
4749
|
else:
|
|
4680
4750
|
print("\nNo saved colors. Type 'u' to manage saved colors.")
|
|
4681
4751
|
print(" (Enter color name/hex, saved color number, or 'u' to manage)")
|
|
4682
|
-
val =
|
|
4752
|
+
val = _safe_input(f"Color (current={cur}, blank=cancel): ").strip()
|
|
4683
4753
|
if not val:
|
|
4684
4754
|
continue
|
|
4685
4755
|
if val.lower() == 'u':
|
|
@@ -4696,7 +4766,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
4696
4766
|
print(f"Invalid color: {e}")
|
|
4697
4767
|
elif sub == 'l':
|
|
4698
4768
|
cur = ln.get_linewidth()
|
|
4699
|
-
val =
|
|
4769
|
+
val = _safe_input(f"Line width (current={cur}, blank=cancel): ").strip()
|
|
4700
4770
|
if not val:
|
|
4701
4771
|
continue
|
|
4702
4772
|
_snapshot("ec-line-width")
|
|
@@ -4721,7 +4791,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
4721
4791
|
continue
|
|
4722
4792
|
while True:
|
|
4723
4793
|
cur = ec_ax.get_ylim(); print(f"Current EC time range (Y): {cur[0]:.4g} {cur[1]:.4g}")
|
|
4724
|
-
line =
|
|
4794
|
+
line = _safe_input("New time range (min max), w=upper only, s=lower only, a=auto (restore original), q=back: ").strip()
|
|
4725
4795
|
if not line or line.lower() == 'q':
|
|
4726
4796
|
break
|
|
4727
4797
|
if line.lower() == 'w':
|
|
@@ -4729,7 +4799,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
4729
4799
|
while True:
|
|
4730
4800
|
cur = ec_ax.get_ylim()
|
|
4731
4801
|
print(f"Current EC time range (Y): {cur[0]:.4g} {cur[1]:.4g}")
|
|
4732
|
-
val =
|
|
4802
|
+
val = _safe_input(f"Enter new upper time limit (current lower: {cur[0]:.4g}, q=back): ").strip()
|
|
4733
4803
|
if not val or val.lower() == 'q':
|
|
4734
4804
|
break
|
|
4735
4805
|
try:
|
|
@@ -4747,7 +4817,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
4747
4817
|
while True:
|
|
4748
4818
|
cur = ec_ax.get_ylim()
|
|
4749
4819
|
print(f"Current EC time range (Y): {cur[0]:.4g} {cur[1]:.4g}")
|
|
4750
|
-
val =
|
|
4820
|
+
val = _safe_input(f"Enter new lower time limit (current upper: {cur[1]:.4g}, q=back): ").strip()
|
|
4751
4821
|
if not val or val.lower() == 'q':
|
|
4752
4822
|
break
|
|
4753
4823
|
try:
|
|
@@ -4861,7 +4931,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
4861
4931
|
print("The .mpt file must contain the '<I>/mA' column to use this feature.")
|
|
4862
4932
|
print_menu(); continue
|
|
4863
4933
|
while True:
|
|
4864
|
-
sub =
|
|
4934
|
+
sub = _safe_input("ey submenu: n=ions, t=time, q=back: ").strip().lower()
|
|
4865
4935
|
if not sub:
|
|
4866
4936
|
continue
|
|
4867
4937
|
if sub == 'q':
|
|
@@ -4878,7 +4948,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
4878
4948
|
prompt = "Enter mass(mg), capacity-per-ion(mAh g^-1), start-ions (e.g. 4.5 26.8 0), q=cancel: "
|
|
4879
4949
|
else:
|
|
4880
4950
|
prompt = f"Enter mass,cap-per-ion,start-ions (blank=reuse {mass_mg} {cap_per_ion} {start_ions}; q=cancel): "
|
|
4881
|
-
s =
|
|
4951
|
+
s = _safe_input(prompt).strip()
|
|
4882
4952
|
if not s:
|
|
4883
4953
|
if need_input:
|
|
4884
4954
|
continue
|
|
@@ -5164,7 +5234,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
5164
5234
|
while True:
|
|
5165
5235
|
cur = ec_ax.get_xlim()
|
|
5166
5236
|
print(f"Current EC X range: {cur[0]:.4g} {cur[1]:.4g}")
|
|
5167
|
-
line =
|
|
5237
|
+
line = _safe_input("New EC X range (min max), w=upper only, s=lower only, a=auto (restore original), q=back: ").strip()
|
|
5168
5238
|
if not line or line.lower() == 'q':
|
|
5169
5239
|
break
|
|
5170
5240
|
if line.lower() == 'w':
|
|
@@ -5172,7 +5242,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
5172
5242
|
while True:
|
|
5173
5243
|
cur = ec_ax.get_xlim()
|
|
5174
5244
|
print(f"Current EC X range: {cur[0]:.4g} {cur[1]:.4g}")
|
|
5175
|
-
val =
|
|
5245
|
+
val = _safe_input(f"Enter new upper EC X limit (current lower: {cur[0]:.4g}, q=back): ").strip()
|
|
5176
5246
|
if not val or val.lower() == 'q':
|
|
5177
5247
|
break
|
|
5178
5248
|
try:
|
|
@@ -5191,7 +5261,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
5191
5261
|
while True:
|
|
5192
5262
|
cur = ec_ax.get_xlim()
|
|
5193
5263
|
print(f"Current EC X range: {cur[0]:.4g} {cur[1]:.4g}")
|
|
5194
|
-
val =
|
|
5264
|
+
val = _safe_input(f"Enter new lower EC X limit (current upper: {cur[1]:.4g}, q=back): ").strip()
|
|
5195
5265
|
if not val or val.lower() == 'q':
|
|
5196
5266
|
break
|
|
5197
5267
|
try:
|
|
@@ -5253,7 +5323,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
5253
5323
|
cur_w, cur_h = _get_fig_size(fig)
|
|
5254
5324
|
print(f"Current canvas size: {cur_w:.2f} x {cur_h:.2f} in (W x H)")
|
|
5255
5325
|
print("Canvas: only figure size will change; panel widths/gaps are not altered.")
|
|
5256
|
-
line =
|
|
5326
|
+
line = _safe_input("New canvas size 'W H' (blank=cancel): ").strip()
|
|
5257
5327
|
if line:
|
|
5258
5328
|
_snapshot("canvas-size")
|
|
5259
5329
|
try:
|