batplot 1.7.28__py3-none-any.whl → 1.8.1__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 +3 -3
- batplot/cpc_interactive.py +89 -3
- batplot/electrochem_interactive.py +118 -55
- batplot/interactive.py +100 -63
- batplot/modes.py +12 -12
- batplot/operando.py +2 -0
- batplot/operando_ec_interactive.py +260 -89
- batplot/session.py +18 -1
- batplot/utils.py +40 -0
- batplot/version_check.py +85 -6
- {batplot-1.7.28.dist-info → batplot-1.8.1.dist-info}/METADATA +1 -1
- {batplot-1.7.28.dist-info → batplot-1.8.1.dist-info}/RECORD +17 -17
- {batplot-1.7.28.dist-info → batplot-1.8.1.dist-info}/WHEEL +0 -0
- {batplot-1.7.28.dist-info → batplot-1.8.1.dist-info}/entry_points.txt +0 -0
- {batplot-1.7.28.dist-info → batplot-1.8.1.dist-info}/licenses/LICENSE +0 -0
- {batplot-1.7.28.dist-info → batplot-1.8.1.dist-info}/top_level.txt +0 -0
batplot/interactive.py
CHANGED
|
@@ -25,6 +25,7 @@ from .utils import (
|
|
|
25
25
|
choose_save_path,
|
|
26
26
|
choose_style_file,
|
|
27
27
|
list_files_in_subdirectory,
|
|
28
|
+
convert_label_shortcuts,
|
|
28
29
|
get_organized_path,
|
|
29
30
|
)
|
|
30
31
|
import time
|
|
@@ -58,6 +59,37 @@ from .color_utils import (
|
|
|
58
59
|
)
|
|
59
60
|
|
|
60
61
|
|
|
62
|
+
class _FilterIMKWarning:
|
|
63
|
+
"""Filter that suppresses macOS IMKCFRunLoopWakeUpReliable warnings while preserving other errors."""
|
|
64
|
+
def __init__(self, original_stderr):
|
|
65
|
+
self.original_stderr = original_stderr
|
|
66
|
+
|
|
67
|
+
def write(self, message):
|
|
68
|
+
# Filter out the harmless macOS IMK warning
|
|
69
|
+
if 'IMKCFRunLoopWakeUpReliable' not in message:
|
|
70
|
+
self.original_stderr.write(message)
|
|
71
|
+
|
|
72
|
+
def flush(self):
|
|
73
|
+
self.original_stderr.flush()
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _safe_input(prompt: str = "") -> str:
|
|
77
|
+
"""Wrapper around input() that suppresses macOS IMKCFRunLoopWakeUpReliable warnings.
|
|
78
|
+
|
|
79
|
+
This is a harmless macOS system message that appears when using input() in terminals.
|
|
80
|
+
"""
|
|
81
|
+
# Filter stderr to hide macOS IMK warnings while preserving other errors
|
|
82
|
+
original_stderr = sys.stderr
|
|
83
|
+
sys.stderr = _FilterIMKWarning(original_stderr)
|
|
84
|
+
try:
|
|
85
|
+
result = input(prompt)
|
|
86
|
+
return result
|
|
87
|
+
except (KeyboardInterrupt, EOFError):
|
|
88
|
+
raise
|
|
89
|
+
finally:
|
|
90
|
+
sys.stderr = original_stderr
|
|
91
|
+
|
|
92
|
+
|
|
61
93
|
def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
62
94
|
label_text_objects, delta, x_label, args,
|
|
63
95
|
x_full_list, raw_y_full_list, offsets_list,
|
|
@@ -363,7 +395,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
363
395
|
current_y_px = _px_value('_top_xlabel_manual_offset_y_pts')
|
|
364
396
|
current_x_px = _px_value('_top_xlabel_manual_offset_x_pts')
|
|
365
397
|
print(f"Top title offset: Y={current_y_px:+.2f} px (positive=up), X={current_x_px:+.2f} px (positive=right)")
|
|
366
|
-
sub =
|
|
398
|
+
sub = _safe_input(colorize_prompt("top (w=up, s=down, a=left, d=right, 0=reset, q=back): ")).strip().lower()
|
|
367
399
|
if not sub:
|
|
368
400
|
continue
|
|
369
401
|
if sub == 'q':
|
|
@@ -401,7 +433,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
401
433
|
current_x_px = _px_value('_right_ylabel_manual_offset_x_pts')
|
|
402
434
|
current_y_px = _px_value('_right_ylabel_manual_offset_y_pts')
|
|
403
435
|
print(f"Right title offset: X={current_x_px:+.2f} px (positive=right), Y={current_y_px:+.2f} px (positive=up)")
|
|
404
|
-
sub =
|
|
436
|
+
sub = _safe_input(colorize_prompt("right (d=right, a=left, w=up, s=down, 0=reset, q=back): ")).strip().lower()
|
|
405
437
|
if not sub:
|
|
406
438
|
continue
|
|
407
439
|
if sub == 'q':
|
|
@@ -438,7 +470,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
438
470
|
while True:
|
|
439
471
|
current_y_px = _px_value('_bottom_xlabel_manual_offset_y_pts')
|
|
440
472
|
print(f"Bottom title offset: Y={current_y_px:+.2f} px (positive=down)")
|
|
441
|
-
sub =
|
|
473
|
+
sub = _safe_input(colorize_prompt("bottom (s=down, w=up, 0=reset, q=back): ")).strip().lower()
|
|
442
474
|
if not sub:
|
|
443
475
|
continue
|
|
444
476
|
if sub == 'q':
|
|
@@ -468,7 +500,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
468
500
|
while True:
|
|
469
501
|
current_x_px = _px_value('_left_ylabel_manual_offset_x_pts')
|
|
470
502
|
print(f"Left title offset: X={current_x_px:+.2f} px (positive=left)")
|
|
471
|
-
sub =
|
|
503
|
+
sub = _safe_input(colorize_prompt("left (a=left, d=right, 0=reset, q=back): ")).strip().lower()
|
|
472
504
|
if not sub:
|
|
473
505
|
continue
|
|
474
506
|
if sub == 'q':
|
|
@@ -499,7 +531,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
499
531
|
print(" " + colorize_menu('d : adjust right title (d=right, a=left, w=up, s=down)'))
|
|
500
532
|
print(" " + colorize_menu('r : reset all offsets'))
|
|
501
533
|
print(" " + colorize_menu('q : back to toggle menu'))
|
|
502
|
-
choice =
|
|
534
|
+
choice = _safe_input(colorize_prompt("p> ")).strip().lower()
|
|
503
535
|
if not choice:
|
|
504
536
|
continue
|
|
505
537
|
if choice == 'q':
|
|
@@ -618,7 +650,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
618
650
|
|
|
619
651
|
while True:
|
|
620
652
|
render()
|
|
621
|
-
cmd =
|
|
653
|
+
cmd = _safe_input("> ").strip().lower()
|
|
622
654
|
if cmd == 'q':
|
|
623
655
|
print("Exited game. Returning to interactive menu.\n")
|
|
624
656
|
break
|
|
@@ -947,7 +979,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
947
979
|
# Only ask for wavelength if it's diffraction data, not using Q, and no file wavelength info
|
|
948
980
|
if is_diffraction and not use_Q and not file_wavelength_info:
|
|
949
981
|
try:
|
|
950
|
-
wl_in =
|
|
982
|
+
wl_in = _safe_input("Enter wavelength in Å for Q,d display (blank=skip, q=cancel): ").strip()
|
|
951
983
|
if wl_in.lower() == 'q':
|
|
952
984
|
print("Canceled.")
|
|
953
985
|
return
|
|
@@ -1445,7 +1477,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
1445
1477
|
while True:
|
|
1446
1478
|
try:
|
|
1447
1479
|
print_main_menu()
|
|
1448
|
-
key =
|
|
1480
|
+
key = _safe_input("Press a key: ").strip().lower()
|
|
1449
1481
|
except (KeyboardInterrupt, EOFError):
|
|
1450
1482
|
print("\n\nExiting interactive menu...")
|
|
1451
1483
|
break
|
|
@@ -1460,7 +1492,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
1460
1492
|
|
|
1461
1493
|
if key == 'q':
|
|
1462
1494
|
try:
|
|
1463
|
-
confirm =
|
|
1495
|
+
confirm = _safe_input(colorize_prompt("Quit interactive? Remember to save (e=export, s=save). Quit now? (y/n): ")).strip().lower()
|
|
1464
1496
|
except (KeyboardInterrupt, EOFError):
|
|
1465
1497
|
print("\nExiting interactive menu...")
|
|
1466
1498
|
break
|
|
@@ -1514,7 +1546,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
1514
1546
|
current_pos = _current_label_position()
|
|
1515
1547
|
print(f" {colorize_menu(f's: legend position (current: {current_pos})')}")
|
|
1516
1548
|
print(f" {colorize_menu('q: back to main menu')}")
|
|
1517
|
-
sub_key =
|
|
1549
|
+
sub_key = _safe_input("Choose: ").strip().lower()
|
|
1518
1550
|
|
|
1519
1551
|
if sub_key == 'q':
|
|
1520
1552
|
break
|
|
@@ -1536,7 +1568,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
1536
1568
|
print(" 2: top-left")
|
|
1537
1569
|
print(" 3: bottom-right")
|
|
1538
1570
|
print(" 4: bottom-left")
|
|
1539
|
-
choice =
|
|
1571
|
+
choice = _safe_input("Position (1-4, q=cancel): ").strip().lower()
|
|
1540
1572
|
options = {
|
|
1541
1573
|
'1': (False, False),
|
|
1542
1574
|
'2': (False, True),
|
|
@@ -1638,7 +1670,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
1638
1670
|
prompt = "Enter new filename (no ext needed), number to overwrite, or o to overwrite last (q=cancel): "
|
|
1639
1671
|
else:
|
|
1640
1672
|
prompt = "Enter new filename (no ext needed) or number to overwrite (q=cancel): "
|
|
1641
|
-
choice =
|
|
1673
|
+
choice = _safe_input(prompt).strip()
|
|
1642
1674
|
if not choice or choice.lower() == 'q':
|
|
1643
1675
|
print("Canceled.")
|
|
1644
1676
|
continue
|
|
@@ -1650,7 +1682,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
1650
1682
|
if not os.path.exists(last_session_path):
|
|
1651
1683
|
print(f"Previous save file not found: {last_session_path}")
|
|
1652
1684
|
continue
|
|
1653
|
-
yn =
|
|
1685
|
+
yn = _safe_input(f"Overwrite '{os.path.basename(last_session_path)}'? (y/n): ").strip().lower()
|
|
1654
1686
|
if yn != 'y':
|
|
1655
1687
|
continue
|
|
1656
1688
|
_bp_dump_session(
|
|
@@ -1680,7 +1712,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
1680
1712
|
idx = int(choice)
|
|
1681
1713
|
if 1 <= idx <= len(files):
|
|
1682
1714
|
name = files[idx-1]
|
|
1683
|
-
yn =
|
|
1715
|
+
yn = _safe_input(f"Overwrite '{name}'? (y/n): ").strip().lower()
|
|
1684
1716
|
if yn != 'y':
|
|
1685
1717
|
print("Canceled.")
|
|
1686
1718
|
continue
|
|
@@ -1720,7 +1752,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
1720
1752
|
target_path = name if os.path.isabs(name) else os.path.join(folder, name)
|
|
1721
1753
|
skip_confirm = False # Let dump_session ask
|
|
1722
1754
|
if os.path.exists(target_path):
|
|
1723
|
-
yn =
|
|
1755
|
+
yn = _safe_input(f"'{os.path.basename(target_path)}' exists. Overwrite? (y/n): ").strip().lower()
|
|
1724
1756
|
if yn != 'y':
|
|
1725
1757
|
print("Canceled.")
|
|
1726
1758
|
continue
|
|
@@ -1772,7 +1804,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
1772
1804
|
print(f" {colorize_menu('t : change CIF tick set color (e.g., 1:red 2:#888888)')}")
|
|
1773
1805
|
print(f" {colorize_menu('u : manage saved colors (use in m/p via number or u#)')}")
|
|
1774
1806
|
print(f" {colorize_menu('q : return to main menu')}")
|
|
1775
|
-
sub =
|
|
1807
|
+
sub = _safe_input(colorize_prompt("Choose (m/p/s/t/u/q): ")).strip().lower()
|
|
1776
1808
|
if sub == 'q':
|
|
1777
1809
|
break
|
|
1778
1810
|
if sub == '':
|
|
@@ -1790,7 +1822,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
1790
1822
|
print("\nSaved colors (refer as number or u#):")
|
|
1791
1823
|
for idx, color in enumerate(user_colors, 1):
|
|
1792
1824
|
print(f" {idx}: {color_block(color)} {color}")
|
|
1793
|
-
color_input =
|
|
1825
|
+
color_input = _safe_input("Enter curve+color pairs (e.g., 1 red 2:u3) or q: ").strip()
|
|
1794
1826
|
if not color_input or color_input.lower() == 'q':
|
|
1795
1827
|
print("Canceled.")
|
|
1796
1828
|
else:
|
|
@@ -1844,7 +1876,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
1844
1876
|
for idx, color in enumerate(user_colors, 1):
|
|
1845
1877
|
print(f" {idx}: {color_block(color)} {color}")
|
|
1846
1878
|
print("Type 'u' to edit saved colors.")
|
|
1847
|
-
line =
|
|
1879
|
+
line = _safe_input("Enter mappings (e.g., w red a u3) or q: ").strip()
|
|
1848
1880
|
if line.lower() == 'u':
|
|
1849
1881
|
manage_user_colors(fig)
|
|
1850
1882
|
continue
|
|
@@ -1900,7 +1932,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
1900
1932
|
print("Current CIF tick sets:")
|
|
1901
1933
|
for i,(lab, fname, *_rest) in enumerate(cts):
|
|
1902
1934
|
print(f" {i+1}: {lab} ({os.path.basename(fname)})")
|
|
1903
|
-
line =
|
|
1935
|
+
line = _safe_input("Enter mappings (e.g., 1:red 2:#555555) or q: ").strip()
|
|
1904
1936
|
if not line or line.lower()=='q':
|
|
1905
1937
|
print("Canceled.")
|
|
1906
1938
|
else:
|
|
@@ -1924,12 +1956,11 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
1924
1956
|
ax._cif_draw_func()
|
|
1925
1957
|
fig.canvas.draw()
|
|
1926
1958
|
elif sub == 'p':
|
|
1959
|
+
# Show current palette if one is applied
|
|
1927
1960
|
history = getattr(fig, '_curve_palette_history', [])
|
|
1928
1961
|
current_palette = history[-1]['palette'] if history else None
|
|
1929
1962
|
if current_palette:
|
|
1930
1963
|
print(f"Current palette: {current_palette}")
|
|
1931
|
-
else:
|
|
1932
|
-
print("Current palette: manual/custom")
|
|
1933
1964
|
base_palettes = ['viridis', 'cividis', 'plasma', 'inferno', 'magma', 'batlow']
|
|
1934
1965
|
extras = []
|
|
1935
1966
|
def _palette_available(name: str) -> bool:
|
|
@@ -1966,7 +1997,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
1966
1997
|
if bar:
|
|
1967
1998
|
print(f" {bar}")
|
|
1968
1999
|
print(colorize_inline_commands("Example: 1-4 viridis or: all magma_r or: 1-3,5 plasma, _r for reverse"))
|
|
1969
|
-
line =
|
|
2000
|
+
line = _safe_input("Enter range(s) and palette (number or name, e.g., '1-3 2' or 'all 1_r') or q: ").strip()
|
|
1970
2001
|
if not line or line.lower() == 'q':
|
|
1971
2002
|
print("Canceled.")
|
|
1972
2003
|
else:
|
|
@@ -2171,7 +2202,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2171
2202
|
if has_cif:
|
|
2172
2203
|
rename_opts += ", t=cif tick label"
|
|
2173
2204
|
rename_opts += ", x=x-axis, y=y-axis, q=return"
|
|
2174
|
-
mode =
|
|
2205
|
+
mode = _safe_input(f"Rename ({rename_opts}): ").strip().lower()
|
|
2175
2206
|
if mode == 'q':
|
|
2176
2207
|
break
|
|
2177
2208
|
if mode == '':
|
|
@@ -2180,7 +2211,8 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2180
2211
|
print("Tip: Use LaTeX/mathtext for special characters:")
|
|
2181
2212
|
print(" Subscript: H$_2$O → H₂O | Superscript: m$^2$ → m²")
|
|
2182
2213
|
print(" Bullet: $\\bullet$ → • | Greek: $\\alpha$, $\\beta$ | Angstrom: $\\AA$ → Å")
|
|
2183
|
-
|
|
2214
|
+
print(" Shortcuts: g{super(-1)} → g$^{\\mathrm{-1}}$ | Li{sub(2)}O → Li$_{\\mathrm{2}}$O")
|
|
2215
|
+
idx_in = _safe_input("Curve number to rename (q=cancel): ").strip()
|
|
2184
2216
|
if not idx_in or idx_in.lower() == 'q':
|
|
2185
2217
|
print("Canceled.")
|
|
2186
2218
|
continue
|
|
@@ -2192,10 +2224,11 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2192
2224
|
if not (0 <= idx < len(labels)):
|
|
2193
2225
|
print("Invalid index.")
|
|
2194
2226
|
continue
|
|
2195
|
-
new_label =
|
|
2227
|
+
new_label = _safe_input("New curve label (q=cancel): ")
|
|
2196
2228
|
if not new_label or new_label.lower() == 'q':
|
|
2197
2229
|
print("Canceled.")
|
|
2198
2230
|
continue
|
|
2231
|
+
new_label = convert_label_shortcuts(new_label)
|
|
2199
2232
|
push_state("rename-curve")
|
|
2200
2233
|
labels[idx] = new_label
|
|
2201
2234
|
label_text_objects[idx].set_text(f"{idx+1}: {new_label}")
|
|
@@ -2207,7 +2240,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2207
2240
|
continue
|
|
2208
2241
|
for i,(lab, fname, *_rest) in enumerate(cts):
|
|
2209
2242
|
print(f" {i+1}: {lab} ({os.path.basename(fname)})")
|
|
2210
|
-
s =
|
|
2243
|
+
s = _safe_input("CIF tick number to rename (q=cancel): ").strip()
|
|
2211
2244
|
if not s or s.lower()=='q':
|
|
2212
2245
|
print("Canceled."); continue
|
|
2213
2246
|
try:
|
|
@@ -2219,9 +2252,11 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2219
2252
|
print("Tip: Use LaTeX/mathtext for special characters:")
|
|
2220
2253
|
print(" Subscript: H$_2$O → H₂O | Superscript: m$^2$ → m²")
|
|
2221
2254
|
print(" Greek: $\\alpha$, $\\beta$ | Angstrom: $\\AA$ → Å")
|
|
2222
|
-
|
|
2255
|
+
print(" Shortcuts: g{super(-1)} → g$^{\\mathrm{-1}}$ | Li{sub(2)}O → Li$_{\\mathrm{2}}$O")
|
|
2256
|
+
new_name = _safe_input("New CIF tick label (q=cancel): ")
|
|
2223
2257
|
if not new_name or new_name.lower()=='q':
|
|
2224
2258
|
print("Canceled."); continue
|
|
2259
|
+
new_name = convert_label_shortcuts(new_name)
|
|
2225
2260
|
lab,fname,peaksQ,wl,qmax_sim,color = cts[idx]
|
|
2226
2261
|
# Suspend extension while updating label
|
|
2227
2262
|
if _bp is not None:
|
|
@@ -2247,10 +2282,12 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2247
2282
|
print("Tip: Use LaTeX/mathtext for special characters:")
|
|
2248
2283
|
print(" Subscript: H$_2$O → H₂O | Superscript: m$^2$ → m²")
|
|
2249
2284
|
print(" Greek: $\\alpha$, $\\beta$ | Angstrom: $\\AA$ → Å")
|
|
2250
|
-
|
|
2285
|
+
print(" Shortcuts: g{super(-1)} → g$^{\\mathrm{-1}}$ | Li{sub(2)}O → Li$_{\\mathrm{2}}$O")
|
|
2286
|
+
new_axis = _safe_input("New axis label: ")
|
|
2251
2287
|
if not new_axis or new_axis.lower() == 'q':
|
|
2252
2288
|
print("Canceled.")
|
|
2253
2289
|
continue
|
|
2290
|
+
new_axis = convert_label_shortcuts(new_axis)
|
|
2254
2291
|
new_axis = normalize_label_text(new_axis)
|
|
2255
2292
|
push_state("rename-axis")
|
|
2256
2293
|
# Freeze layout and preserve current pad via one-shot pending to avoid drift
|
|
@@ -2296,7 +2333,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2296
2333
|
print("Current curve order:")
|
|
2297
2334
|
for idx, label in enumerate(labels):
|
|
2298
2335
|
print(f"{idx+1}: {label}")
|
|
2299
|
-
new_order_str =
|
|
2336
|
+
new_order_str = _safe_input("Enter new order (space-separated indices, q=cancel): ").strip()
|
|
2300
2337
|
if not new_order_str or new_order_str.lower() == 'q':
|
|
2301
2338
|
print("Canceled.")
|
|
2302
2339
|
continue
|
|
@@ -2386,7 +2423,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2386
2423
|
try:
|
|
2387
2424
|
current_xlim = ax.get_xlim()
|
|
2388
2425
|
print(f"Current X range: {current_xlim[0]:.6g} to {current_xlim[1]:.6g}")
|
|
2389
|
-
rng =
|
|
2426
|
+
rng = _safe_input("Enter new X range (min max), w=upper only, s=lower only, 'full', or 'a'=auto (restore original) (q=back): ").strip()
|
|
2390
2427
|
if not rng or rng.lower() == 'q':
|
|
2391
2428
|
break
|
|
2392
2429
|
if rng.lower() == 'w':
|
|
@@ -2394,7 +2431,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2394
2431
|
while True:
|
|
2395
2432
|
current_xlim = ax.get_xlim()
|
|
2396
2433
|
print(f"Current X range: {current_xlim[0]:.6g} to {current_xlim[1]:.6g}")
|
|
2397
|
-
val =
|
|
2434
|
+
val = _safe_input(f"Enter new upper X limit (current lower: {current_xlim[0]:.6g}, q=back): ").strip()
|
|
2398
2435
|
if not val or val.lower() == 'q':
|
|
2399
2436
|
break
|
|
2400
2437
|
try:
|
|
@@ -2425,7 +2462,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2425
2462
|
while True:
|
|
2426
2463
|
current_xlim = ax.get_xlim()
|
|
2427
2464
|
print(f"Current X range: {current_xlim[0]:.6g} to {current_xlim[1]:.6g}")
|
|
2428
|
-
val =
|
|
2465
|
+
val = _safe_input(f"Enter new lower X limit (current upper: {current_xlim[1]:.6g}, q=back): ").strip()
|
|
2429
2466
|
if not val or val.lower() == 'q':
|
|
2430
2467
|
break
|
|
2431
2468
|
try:
|
|
@@ -2560,7 +2597,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2560
2597
|
try:
|
|
2561
2598
|
current_ylim = ax.get_ylim()
|
|
2562
2599
|
print(f"Current Y range: {current_ylim[0]:.6g} to {current_ylim[1]:.6g}")
|
|
2563
|
-
rng =
|
|
2600
|
+
rng = _safe_input("Enter new Y range (min max), w=upper only, s=lower only, 'auto', 'a'=auto (restore original), or 'full' (q=back): ").strip().lower()
|
|
2564
2601
|
if not rng or rng == 'q':
|
|
2565
2602
|
break
|
|
2566
2603
|
if rng == 'w':
|
|
@@ -2568,7 +2605,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2568
2605
|
while True:
|
|
2569
2606
|
current_ylim = ax.get_ylim()
|
|
2570
2607
|
print(f"Current Y range: {current_ylim[0]:.6g} to {current_ylim[1]:.6g}")
|
|
2571
|
-
val =
|
|
2608
|
+
val = _safe_input(f"Enter new upper Y limit (current lower: {current_ylim[0]:.6g}, q=back): ").strip()
|
|
2572
2609
|
if not val or val.lower() == 'q':
|
|
2573
2610
|
break
|
|
2574
2611
|
try:
|
|
@@ -2590,7 +2627,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2590
2627
|
while True:
|
|
2591
2628
|
current_ylim = ax.get_ylim()
|
|
2592
2629
|
print(f"Current Y range: {current_ylim[0]:.6g} to {current_ylim[1]:.6g}")
|
|
2593
|
-
val =
|
|
2630
|
+
val = _safe_input(f"Enter new lower Y limit (current upper: {current_ylim[1]:.6g}, q=back): ").strip()
|
|
2594
2631
|
if not val or val.lower() == 'q':
|
|
2595
2632
|
break
|
|
2596
2633
|
try:
|
|
@@ -2675,7 +2712,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2675
2712
|
print(f" {colorize_menu('q: back to main menu')}")
|
|
2676
2713
|
|
|
2677
2714
|
while True:
|
|
2678
|
-
offset_cmd =
|
|
2715
|
+
offset_cmd = _safe_input("Offset> ").strip().lower()
|
|
2679
2716
|
|
|
2680
2717
|
if offset_cmd == 'q' or offset_cmd == '':
|
|
2681
2718
|
break
|
|
@@ -2725,7 +2762,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2725
2762
|
if spacing_diffs:
|
|
2726
2763
|
current_spacing = sum(spacing_diffs) / len(spacing_diffs)
|
|
2727
2764
|
|
|
2728
|
-
spacing_input =
|
|
2765
|
+
spacing_input = _safe_input("Enter spacing value between curves (current avg: {:.4g}): ".format(current_spacing)).strip()
|
|
2729
2766
|
if not spacing_input:
|
|
2730
2767
|
print("Canceled.")
|
|
2731
2768
|
continue
|
|
@@ -2784,7 +2821,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2784
2821
|
if len(labels) <= 1:
|
|
2785
2822
|
print("Warning: Only one curve loaded; applying an offset is not recommended.")
|
|
2786
2823
|
try:
|
|
2787
|
-
new_delta_str =
|
|
2824
|
+
new_delta_str = _safe_input(f"Enter new offset spacing (current={delta}): ").strip()
|
|
2788
2825
|
if not new_delta_str:
|
|
2789
2826
|
print("Canceled.")
|
|
2790
2827
|
continue
|
|
@@ -2847,7 +2884,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2847
2884
|
|
|
2848
2885
|
current_offset = offsets_list[idx] if idx < len(offsets_list) else 0.0
|
|
2849
2886
|
|
|
2850
|
-
individual_offset_input =
|
|
2887
|
+
individual_offset_input = _safe_input("Enter offset for curve {} (current: {:.4g}): ".format(
|
|
2851
2888
|
curve_num, current_offset)).strip()
|
|
2852
2889
|
if not individual_offset_input:
|
|
2853
2890
|
print("Canceled.")
|
|
@@ -2887,7 +2924,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2887
2924
|
print("No curves to modify.")
|
|
2888
2925
|
return []
|
|
2889
2926
|
print(f"Total curves available: {total}")
|
|
2890
|
-
raw =
|
|
2927
|
+
raw = _safe_input(prompt_text + " ").strip().lower()
|
|
2891
2928
|
if not raw or raw in ('all', '*'):
|
|
2892
2929
|
return list(range(total))
|
|
2893
2930
|
import re as _re
|
|
@@ -2906,7 +2943,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2906
2943
|
return selected
|
|
2907
2944
|
|
|
2908
2945
|
def _prompt_float(prompt_text):
|
|
2909
|
-
raw =
|
|
2946
|
+
raw = _safe_input(prompt_text).strip()
|
|
2910
2947
|
if not raw:
|
|
2911
2948
|
return None
|
|
2912
2949
|
if raw.lower() == 'q':
|
|
@@ -2919,10 +2956,10 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2919
2956
|
|
|
2920
2957
|
def _prompt_dash_pattern(kind='dash'):
|
|
2921
2958
|
if kind == 'dashdot':
|
|
2922
|
-
raw =
|
|
2959
|
+
raw = _safe_input("Dash-dot pattern 'dash gap dot gap' (blank=6 3 1 3, q=cancel): ").strip().lower()
|
|
2923
2960
|
default = (6.0, 3.0, 1.0, 3.0)
|
|
2924
2961
|
else:
|
|
2925
|
-
raw =
|
|
2962
|
+
raw = _safe_input("Dash pattern 'length gap' (blank=6 3, q=cancel): ").strip().lower()
|
|
2926
2963
|
default = (6.0, 3.0)
|
|
2927
2964
|
if not raw:
|
|
2928
2965
|
return default
|
|
@@ -2962,13 +2999,13 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2962
2999
|
print(f" {colorize_menu('da : dashed line for selected curves')}")
|
|
2963
3000
|
print(f" {colorize_menu('dd : dashed line + dots for selected curves')}")
|
|
2964
3001
|
print(f" {colorize_menu('q : return')}")
|
|
2965
|
-
sub =
|
|
3002
|
+
sub = _safe_input(colorize_prompt("Choose (c/f/g/l/ld/d/da/dd/q): ")).strip().lower()
|
|
2966
3003
|
if sub == 'q':
|
|
2967
3004
|
break
|
|
2968
3005
|
if sub == '':
|
|
2969
3006
|
continue
|
|
2970
3007
|
if sub == 'c':
|
|
2971
|
-
spec =
|
|
3008
|
+
spec = _safe_input("Curve widths (single value OR mappings like '1:1.2 3:2', q=cancel): ").strip()
|
|
2972
3009
|
if not spec or spec.lower() == 'q':
|
|
2973
3010
|
print("Canceled.")
|
|
2974
3011
|
else:
|
|
@@ -2998,7 +3035,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2998
3035
|
print("Invalid width value.")
|
|
2999
3036
|
fig.canvas.draw()
|
|
3000
3037
|
elif sub == 'f':
|
|
3001
|
-
fw_in =
|
|
3038
|
+
fw_in = _safe_input("Enter frame/tick width (e.g., 1.5) or 'm M' (major minor) or q: ").strip()
|
|
3002
3039
|
if not fw_in or fw_in.lower() == 'q':
|
|
3003
3040
|
print("Canceled.")
|
|
3004
3041
|
else:
|
|
@@ -3133,7 +3170,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
3133
3170
|
cur_family = plt.rcParams.get('font.sans-serif', [''])[0]
|
|
3134
3171
|
cur_size = plt.rcParams.get('font.size', None)
|
|
3135
3172
|
while True:
|
|
3136
|
-
subkey =
|
|
3173
|
+
subkey = _safe_input(colorize_prompt(f"Font submenu (current: family='{cur_family}', size={cur_size}) - s=size, f=family, q=return: ")).strip().lower()
|
|
3137
3174
|
if subkey == 'q':
|
|
3138
3175
|
break
|
|
3139
3176
|
if subkey == '':
|
|
@@ -3141,7 +3178,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
3141
3178
|
if subkey == 's':
|
|
3142
3179
|
try:
|
|
3143
3180
|
cur_size = plt.rcParams.get('font.size', None)
|
|
3144
|
-
fs =
|
|
3181
|
+
fs = _safe_input(f"Enter new font size (current: {cur_size}, q=cancel): ").strip()
|
|
3145
3182
|
if not fs or fs.lower() == 'q':
|
|
3146
3183
|
print("Canceled.")
|
|
3147
3184
|
else:
|
|
@@ -3163,7 +3200,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
3163
3200
|
print(" 3) Times New Roman")
|
|
3164
3201
|
print(" 4) STIXGeneral")
|
|
3165
3202
|
print(" 5) DejaVu Sans")
|
|
3166
|
-
ft_raw =
|
|
3203
|
+
ft_raw = _safe_input(f"Enter font number or family name (current: '{cur_family}', q=cancel): ").strip()
|
|
3167
3204
|
if not ft_raw or ft_raw.lower() == 'q':
|
|
3168
3205
|
print("Canceled.")
|
|
3169
3206
|
else:
|
|
@@ -3189,7 +3226,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
3189
3226
|
elif key == 'g':
|
|
3190
3227
|
try:
|
|
3191
3228
|
while True:
|
|
3192
|
-
choice =
|
|
3229
|
+
choice = _safe_input(colorize_prompt("Resize submenu: (p=plot frame, c=canvas, q=cancel): ")).strip().lower()
|
|
3193
3230
|
if not choice:
|
|
3194
3231
|
continue
|
|
3195
3232
|
if choice == 'q':
|
|
@@ -3214,7 +3251,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
3214
3251
|
current_pos = "bottom-right" if getattr(fig, '_stack_label_at_bottom', False) else "top-right"
|
|
3215
3252
|
print(f" s: legend position (current: {current_pos})")
|
|
3216
3253
|
print(" q: back to main menu")
|
|
3217
|
-
sub_key =
|
|
3254
|
+
sub_key = _safe_input("Choose: ").strip().lower()
|
|
3218
3255
|
|
|
3219
3256
|
if sub_key == 'q':
|
|
3220
3257
|
break
|
|
@@ -3272,7 +3309,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
3272
3309
|
print(colorize_inline_commands(" Combine letter+number to toggle, e.g. 's2 w5 a4' (case-insensitive)"))
|
|
3273
3310
|
print(colorize_inline_commands(" i = invert tick direction, l = change tick length, list = show state, q = return"))
|
|
3274
3311
|
print(colorize_inline_commands(" p = adjust title offsets (w=top, s=bottom, a=left, d=right)"))
|
|
3275
|
-
cmd =
|
|
3312
|
+
cmd = _safe_input(colorize_prompt("Enter code(s): ")).strip().lower()
|
|
3276
3313
|
if not cmd:
|
|
3277
3314
|
continue
|
|
3278
3315
|
if cmd == 'q':
|
|
@@ -3299,7 +3336,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
3299
3336
|
# Get current major tick length from axes
|
|
3300
3337
|
current_major = ax.xaxis.get_major_ticks()[0].tick1line.get_markersize() if ax.xaxis.get_major_ticks() else 4.0
|
|
3301
3338
|
print(f"Current major tick length: {current_major}")
|
|
3302
|
-
new_length_str =
|
|
3339
|
+
new_length_str = _safe_input("Enter new major tick length (e.g., 6.0): ").strip()
|
|
3303
3340
|
if not new_length_str:
|
|
3304
3341
|
continue
|
|
3305
3342
|
new_major = float(new_length_str)
|
|
@@ -3582,9 +3619,9 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
3582
3619
|
print(f" {_i}: {fname}")
|
|
3583
3620
|
last_style_path = getattr(fig, '_last_style_export_path', None)
|
|
3584
3621
|
if last_style_path:
|
|
3585
|
-
sub =
|
|
3622
|
+
sub = _safe_input(colorize_prompt("Style submenu: (e=export, o=overwrite last, q=return, r=refresh): ")).strip().lower()
|
|
3586
3623
|
else:
|
|
3587
|
-
sub =
|
|
3624
|
+
sub = _safe_input(colorize_prompt("Style submenu: (e=export, q=return, r=refresh): ")).strip().lower()
|
|
3588
3625
|
if sub == 'q':
|
|
3589
3626
|
break
|
|
3590
3627
|
if sub == 'r' or sub == '':
|
|
@@ -3597,7 +3634,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
3597
3634
|
if not os.path.exists(last_style_path):
|
|
3598
3635
|
print(f"Previous export file not found: {last_style_path}")
|
|
3599
3636
|
continue
|
|
3600
|
-
yn =
|
|
3637
|
+
yn = _safe_input(f"Overwrite '{os.path.basename(last_style_path)}'? (y/n): ").strip().lower()
|
|
3601
3638
|
if yn != 'y':
|
|
3602
3639
|
continue
|
|
3603
3640
|
# Call export_style_config with overwrite_path to skip dialog
|
|
@@ -3655,9 +3692,9 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
3655
3692
|
|
|
3656
3693
|
last_figure_path = getattr(fig, '_last_figure_export_path', None)
|
|
3657
3694
|
if last_figure_path:
|
|
3658
|
-
filename =
|
|
3695
|
+
filename = _safe_input("Enter filename (default SVG if no extension), number to overwrite, or o to overwrite last (q=cancel): ").strip()
|
|
3659
3696
|
else:
|
|
3660
|
-
filename =
|
|
3697
|
+
filename = _safe_input("Enter filename (default SVG if no extension) or number to overwrite (q=cancel): ").strip()
|
|
3661
3698
|
if not filename or filename.lower() == 'q':
|
|
3662
3699
|
print("Canceled.")
|
|
3663
3700
|
continue
|
|
@@ -3671,7 +3708,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
3671
3708
|
if not os.path.exists(last_figure_path):
|
|
3672
3709
|
print(f"Previous export file not found: {last_figure_path}")
|
|
3673
3710
|
continue
|
|
3674
|
-
yn =
|
|
3711
|
+
yn = _safe_input(f"Overwrite '{os.path.basename(last_figure_path)}'? (y/n): ").strip().lower()
|
|
3675
3712
|
if yn != 'y':
|
|
3676
3713
|
print("Canceled.")
|
|
3677
3714
|
continue
|
|
@@ -3683,7 +3720,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
3683
3720
|
idx = int(filename)
|
|
3684
3721
|
if 1 <= idx <= len(files):
|
|
3685
3722
|
name = files[idx-1]
|
|
3686
|
-
yn =
|
|
3723
|
+
yn = _safe_input(f"Overwrite '{name}'? (y/n): ").strip().lower()
|
|
3687
3724
|
if yn != 'y':
|
|
3688
3725
|
print("Canceled.")
|
|
3689
3726
|
continue
|
|
@@ -3759,7 +3796,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
3759
3796
|
elif key == 'v':
|
|
3760
3797
|
while True:
|
|
3761
3798
|
try:
|
|
3762
|
-
rng_in =
|
|
3799
|
+
rng_in = _safe_input("Peak X range (min max, 'current' for axes limits, q=back): ").strip().lower()
|
|
3763
3800
|
if not rng_in or rng_in == 'q':
|
|
3764
3801
|
break
|
|
3765
3802
|
if rng_in == 'current':
|
|
@@ -3773,12 +3810,12 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
3773
3810
|
if x_min > x_max:
|
|
3774
3811
|
x_min, x_max = x_max, x_min
|
|
3775
3812
|
|
|
3776
|
-
frac_in =
|
|
3813
|
+
frac_in = _safe_input("Min relative peak height (0–1, default 0.1): ").strip()
|
|
3777
3814
|
min_frac = float(frac_in) if frac_in else 0.1
|
|
3778
3815
|
if min_frac < 0: min_frac = 0.0
|
|
3779
3816
|
if min_frac > 1: min_frac = 1.0
|
|
3780
3817
|
|
|
3781
|
-
swin =
|
|
3818
|
+
swin = _safe_input("Smoothing window (odd int >=3, blank=none): ").strip()
|
|
3782
3819
|
if swin:
|
|
3783
3820
|
try:
|
|
3784
3821
|
win = int(swin)
|