batplot 1.1.8__tar.gz → 1.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {batplot-1.1.8 → batplot-1.2.0}/PKG-INFO +1 -1
- batplot-1.2.0/batplot/cli.py +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/batplot/cpc_interactive.py +1 -2
- {batplot-1.1.8 → batplot-1.2.0}/batplot/electrochem_interactive.py +72 -10
- {batplot-1.1.8 → batplot-1.2.0}/batplot/operando_ec_interactive.py +22 -12
- {batplot-1.1.8 → batplot-1.2.0}/batplot/style.py +121 -10
- {batplot-1.1.8 → batplot-1.2.0}/batplot/ui.py +2 -2
- {batplot-1.1.8 → batplot-1.2.0}/batplot.egg-info/PKG-INFO +1 -1
- {batplot-1.1.8 → batplot-1.2.0}/pyproject.toml +1 -1
- batplot-1.1.8/batplot/cli.py +0 -34
- {batplot-1.1.8 → batplot-1.2.0}/LICENSE +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/README.md +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/batplot/__init__.py +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/batplot/args.py +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/batplot/batch.py +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/batplot/batplot.py +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/batplot/batplot_new.py +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/batplot/cif.py +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/batplot/converters.py +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/batplot/interactive.py +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/batplot/modes.py +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/batplot/operando.py +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/batplot/plotting.py +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/batplot/readers.py +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/batplot/session.py +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/batplot/utils.py +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/batplot.egg-info/SOURCES.txt +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/batplot.egg-info/dependency_links.txt +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/batplot.egg-info/entry_points.txt +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/batplot.egg-info/requires.txt +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/batplot.egg-info/top_level.txt +0 -0
- {batplot-1.1.8 → batplot-1.2.0}/setup.cfg +0 -0
|
File without changes
|
|
@@ -259,7 +259,6 @@ def _style_snapshot(fig, ax, ax2, sc_charge, sc_discharge, sc_eff, file_data=Non
|
|
|
259
259
|
'position_inches': legend_xy_in # [x, y] offset from canvas center in inches
|
|
260
260
|
},
|
|
261
261
|
'ticks': {
|
|
262
|
-
'visibility': tick_vis,
|
|
263
262
|
'widths': {
|
|
264
263
|
'x_major': _tick_width(ax.xaxis, 'major'),
|
|
265
264
|
'x_minor': _tick_width(ax.xaxis, 'minor'),
|
|
@@ -1316,7 +1315,6 @@ def cpc_interactive_menu(fig, ax, ax2, sc_charge, sc_discharge, sc_eff, file_dat
|
|
|
1316
1315
|
_print_menu(); continue
|
|
1317
1316
|
elif key == 'i':
|
|
1318
1317
|
try:
|
|
1319
|
-
push_state("import-style")
|
|
1320
1318
|
try:
|
|
1321
1319
|
files = sorted([f for f in os.listdir(os.getcwd()) if f.lower().endswith('.bpcfg')])
|
|
1322
1320
|
except Exception:
|
|
@@ -1328,6 +1326,7 @@ def cpc_interactive_menu(fig, ax, ax2, sc_charge, sc_discharge, sc_eff, file_dat
|
|
|
1328
1326
|
inp = input("Enter number to open or filename (.bpcfg; q=cancel): ").strip()
|
|
1329
1327
|
if not inp or inp.lower() == 'q':
|
|
1330
1328
|
_print_menu(); continue
|
|
1329
|
+
push_state("import-style")
|
|
1331
1330
|
if inp.isdigit() and files:
|
|
1332
1331
|
idx = int(inp)
|
|
1333
1332
|
if 1 <= idx <= len(files):
|
|
@@ -570,10 +570,10 @@ def electrochem_interactive_menu(fig, ax, cycle_lines: Dict[int, Dict[str, Optio
|
|
|
570
570
|
except Exception:
|
|
571
571
|
pass
|
|
572
572
|
|
|
573
|
-
# Convert to points and add gap (match matplotlib's labelpad =
|
|
573
|
+
# Convert to points and add gap (match matplotlib's labelpad = 8pt)
|
|
574
574
|
if max_w_px > 0:
|
|
575
575
|
tick_width_pts = max_w_px * 72.0 / dpi
|
|
576
|
-
dx_pts = tick_width_pts +
|
|
576
|
+
dx_pts = tick_width_pts + 8.0 # 8pt gap to match left labelpad
|
|
577
577
|
else:
|
|
578
578
|
dx_pts = 6.0 # Minimal spacing when no tick labels (match small labelpad)
|
|
579
579
|
|
|
@@ -981,7 +981,6 @@ def electrochem_interactive_menu(fig, ax, cycle_lines: Dict[int, Dict[str, Optio
|
|
|
981
981
|
elif key == 'i':
|
|
982
982
|
# Import style from .bpcfg (with numbered list)
|
|
983
983
|
try:
|
|
984
|
-
push_state("import-style")
|
|
985
984
|
try:
|
|
986
985
|
_bpcfg_files = sorted([f for f in os.listdir(os.getcwd()) if f.lower().endswith('.bpcfg')])
|
|
987
986
|
except Exception:
|
|
@@ -993,6 +992,7 @@ def electrochem_interactive_menu(fig, ax, cycle_lines: Dict[int, Dict[str, Optio
|
|
|
993
992
|
inp = input("Enter number to open or filename (.bpcfg, q=cancel): ").strip()
|
|
994
993
|
if not inp or inp.lower() == 'q':
|
|
995
994
|
_print_menu(len(all_cycles), is_dqdv); continue
|
|
995
|
+
push_state("import-style")
|
|
996
996
|
if inp.isdigit() and _bpcfg_files:
|
|
997
997
|
_idx = int(inp)
|
|
998
998
|
if 1 <= _idx <= len(_bpcfg_files):
|
|
@@ -1031,17 +1031,79 @@ def electrochem_interactive_menu(fig, ax, cycle_lines: Dict[int, Dict[str, Optio
|
|
|
1031
1031
|
_apply_font_family(ax, font_cfg['family'])
|
|
1032
1032
|
if font_cfg.get('size') is not None:
|
|
1033
1033
|
_apply_font_size(ax, float(font_cfg['size']))
|
|
1034
|
-
except Exception:
|
|
1034
|
+
except Exception as e:
|
|
1035
|
+
print(f"Warning: Could not apply figure/font settings: {e}")
|
|
1035
1036
|
|
|
1036
1037
|
# WASD state and dependent components
|
|
1037
1038
|
try:
|
|
1038
1039
|
wasd_state = cfg.get('wasd_state')
|
|
1039
1040
|
if wasd_state and isinstance(wasd_state, dict):
|
|
1040
|
-
#
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1041
|
+
# Apply spines
|
|
1042
|
+
for name in ('top','bottom','left','right'):
|
|
1043
|
+
side = wasd_state.get(name, {})
|
|
1044
|
+
if name in ax.spines and 'spine' in side:
|
|
1045
|
+
ax.spines[name].set_visible(bool(side['spine']))
|
|
1046
|
+
|
|
1047
|
+
# Apply major ticks & labels
|
|
1048
|
+
top_s = wasd_state.get('top', {})
|
|
1049
|
+
bot_s = wasd_state.get('bottom', {})
|
|
1050
|
+
left_s = wasd_state.get('left', {})
|
|
1051
|
+
right_s = wasd_state.get('right', {})
|
|
1052
|
+
|
|
1053
|
+
ax.tick_params(axis='x',
|
|
1054
|
+
top=bool(top_s.get('ticks', False)),
|
|
1055
|
+
bottom=bool(bot_s.get('ticks', True)),
|
|
1056
|
+
labeltop=bool(top_s.get('labels', False)),
|
|
1057
|
+
labelbottom=bool(bot_s.get('labels', True)))
|
|
1058
|
+
ax.tick_params(axis='y',
|
|
1059
|
+
left=bool(left_s.get('ticks', True)),
|
|
1060
|
+
right=bool(right_s.get('ticks', False)),
|
|
1061
|
+
labelleft=bool(left_s.get('labels', True)),
|
|
1062
|
+
labelright=bool(right_s.get('labels', False)))
|
|
1063
|
+
|
|
1064
|
+
# Apply minor ticks
|
|
1065
|
+
if top_s.get('minor') or bot_s.get('minor'):
|
|
1066
|
+
ax.xaxis.set_minor_locator(AutoMinorLocator())
|
|
1067
|
+
ax.xaxis.set_minor_formatter(NullFormatter())
|
|
1068
|
+
ax.tick_params(axis='x', which='minor',
|
|
1069
|
+
top=bool(top_s.get('minor', False)),
|
|
1070
|
+
bottom=bool(bot_s.get('minor', False)),
|
|
1071
|
+
labeltop=False, labelbottom=False)
|
|
1072
|
+
|
|
1073
|
+
if left_s.get('minor') or right_s.get('minor'):
|
|
1074
|
+
ax.yaxis.set_minor_locator(AutoMinorLocator())
|
|
1075
|
+
ax.yaxis.set_minor_formatter(NullFormatter())
|
|
1076
|
+
ax.tick_params(axis='y', which='minor',
|
|
1077
|
+
left=bool(left_s.get('minor', False)),
|
|
1078
|
+
right=bool(right_s.get('minor', False)),
|
|
1079
|
+
labelleft=False, labelright=False)
|
|
1080
|
+
|
|
1081
|
+
# Apply axis titles
|
|
1082
|
+
ax._top_xlabel_on = bool(top_s.get('title', False))
|
|
1083
|
+
ax._right_ylabel_on = bool(right_s.get('title', False))
|
|
1084
|
+
|
|
1085
|
+
# Update tick_state for consistency
|
|
1086
|
+
tick_state['t_ticks'] = bool(top_s.get('ticks', False))
|
|
1087
|
+
tick_state['t_labels'] = bool(top_s.get('labels', False))
|
|
1088
|
+
tick_state['b_ticks'] = bool(bot_s.get('ticks', True))
|
|
1089
|
+
tick_state['b_labels'] = bool(bot_s.get('labels', True))
|
|
1090
|
+
tick_state['l_ticks'] = bool(left_s.get('ticks', True))
|
|
1091
|
+
tick_state['l_labels'] = bool(left_s.get('labels', True))
|
|
1092
|
+
tick_state['r_ticks'] = bool(right_s.get('ticks', False))
|
|
1093
|
+
tick_state['r_labels'] = bool(right_s.get('labels', False))
|
|
1094
|
+
tick_state['mtx'] = bool(top_s.get('minor', False))
|
|
1095
|
+
tick_state['mbx'] = bool(bot_s.get('minor', False))
|
|
1096
|
+
tick_state['mly'] = bool(left_s.get('minor', False))
|
|
1097
|
+
tick_state['mry'] = bool(right_s.get('minor', False))
|
|
1098
|
+
|
|
1099
|
+
# Reposition titles
|
|
1100
|
+
_ui_position_top_xlabel(ax, fig, tick_state)
|
|
1101
|
+
_ui_position_bottom_xlabel(ax, fig, tick_state)
|
|
1102
|
+
_ui_position_left_ylabel(ax, fig, tick_state)
|
|
1103
|
+
_ui_position_right_ylabel(ax, fig, tick_state)
|
|
1104
|
+
|
|
1105
|
+
except Exception as e:
|
|
1106
|
+
print(f"Warning: Could not apply tick visibility: {e}")
|
|
1045
1107
|
|
|
1046
1108
|
# Spines and Ticks (widths)
|
|
1047
1109
|
try:
|
|
@@ -1903,7 +1965,7 @@ def _get_style_snapshot(fig, ax, cycle_lines: Dict, tick_state: Dict) -> Dict:
|
|
|
1903
1965
|
},
|
|
1904
1966
|
'font': {'family': font_fam0, 'size': font_size},
|
|
1905
1967
|
'spines': spines,
|
|
1906
|
-
'ticks': {'widths': tick_widths
|
|
1968
|
+
'ticks': {'widths': tick_widths},
|
|
1907
1969
|
'wasd_state': wasd_state,
|
|
1908
1970
|
'curve_linewidth': curve_linewidth,
|
|
1909
1971
|
'curve_markers': curve_marker_props,
|
|
@@ -534,6 +534,15 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax):
|
|
|
534
534
|
# Crosshair state for both axes
|
|
535
535
|
# Undo history
|
|
536
536
|
state_history = []
|
|
537
|
+
|
|
538
|
+
def _get_spine_visible(axis, which: str) -> bool:
|
|
539
|
+
"""Helper to get spine visibility status"""
|
|
540
|
+
sp = axis.spines.get(which)
|
|
541
|
+
try:
|
|
542
|
+
return bool(sp.get_visible()) if sp is not None else False
|
|
543
|
+
except Exception:
|
|
544
|
+
return False
|
|
545
|
+
|
|
537
546
|
def _snapshot(note: str = ""):
|
|
538
547
|
try:
|
|
539
548
|
fig_w, fig_h = _get_fig_size(fig)
|
|
@@ -561,37 +570,37 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax):
|
|
|
561
570
|
# WASD state for both panes
|
|
562
571
|
op_wasd = {
|
|
563
572
|
'top': {'spine': _get_spine_visible(ax, 'top'), 'ticks': ax.xaxis._major_tick_kw.get('tick1On', True),
|
|
564
|
-
'minor': bool(ax.xaxis.
|
|
573
|
+
'minor': bool(ax.xaxis._minor_tick_kw.get('tick1On', False)),
|
|
565
574
|
'labels': ax.xaxis._major_tick_kw.get('label1On', True),
|
|
566
575
|
'title': bool(getattr(ax, '_top_xlabel_on', False))},
|
|
567
576
|
'bottom': {'spine': _get_spine_visible(ax, 'bottom'), 'ticks': ax.xaxis._major_tick_kw.get('tick2On', True),
|
|
568
|
-
'minor': bool(ax.xaxis.
|
|
577
|
+
'minor': bool(ax.xaxis._minor_tick_kw.get('tick2On', False)),
|
|
569
578
|
'labels': ax.xaxis._major_tick_kw.get('label2On', True),
|
|
570
579
|
'title': bool(ax.get_xlabel())},
|
|
571
580
|
'left': {'spine': _get_spine_visible(ax, 'left'), 'ticks': ax.yaxis._major_tick_kw.get('tick1On', True),
|
|
572
|
-
'minor': bool(ax.yaxis.
|
|
581
|
+
'minor': bool(ax.yaxis._minor_tick_kw.get('tick1On', False)),
|
|
573
582
|
'labels': ax.yaxis._major_tick_kw.get('label1On', True),
|
|
574
583
|
'title': bool(ax.get_ylabel())},
|
|
575
584
|
'right': {'spine': _get_spine_visible(ax, 'right'), 'ticks': ax.yaxis._major_tick_kw.get('tick2On', False),
|
|
576
|
-
'minor': bool(ax.yaxis.
|
|
585
|
+
'minor': bool(ax.yaxis._minor_tick_kw.get('tick2On', False)),
|
|
577
586
|
'labels': ax.yaxis._major_tick_kw.get('label2On', False),
|
|
578
587
|
'title': bool(getattr(ax, '_right_ylabel_on', False))},
|
|
579
588
|
}
|
|
580
589
|
ec_wasd = {
|
|
581
590
|
'top': {'spine': _get_spine_visible(ec_ax, 'top'), 'ticks': ec_ax.xaxis._major_tick_kw.get('tick1On', True),
|
|
582
|
-
'minor': bool(ec_ax.xaxis.
|
|
591
|
+
'minor': bool(ec_ax.xaxis._minor_tick_kw.get('tick1On', False)),
|
|
583
592
|
'labels': ec_ax.xaxis._major_tick_kw.get('label1On', True),
|
|
584
593
|
'title': bool(getattr(ec_ax, '_top_xlabel_on', False))},
|
|
585
594
|
'bottom': {'spine': _get_spine_visible(ec_ax, 'bottom'), 'ticks': ec_ax.xaxis._major_tick_kw.get('tick2On', True),
|
|
586
|
-
'minor': bool(ec_ax.xaxis.
|
|
595
|
+
'minor': bool(ec_ax.xaxis._minor_tick_kw.get('tick2On', False)),
|
|
587
596
|
'labels': ec_ax.xaxis._major_tick_kw.get('label2On', True),
|
|
588
597
|
'title': bool(ec_ax.get_xlabel())},
|
|
589
598
|
'left': {'spine': _get_spine_visible(ec_ax, 'left'), 'ticks': ec_ax.yaxis._major_tick_kw.get('tick1On', False),
|
|
590
|
-
'minor': bool(ec_ax.yaxis.
|
|
599
|
+
'minor': bool(ec_ax.yaxis._minor_tick_kw.get('tick1On', False)),
|
|
591
600
|
'labels': ec_ax.yaxis._major_tick_kw.get('label1On', False),
|
|
592
601
|
'title': bool(ec_ax.get_ylabel())},
|
|
593
602
|
'right': {'spine': _get_spine_visible(ec_ax, 'right'), 'ticks': ec_ax.yaxis._major_tick_kw.get('tick2On', True),
|
|
594
|
-
'minor': bool(ec_ax.yaxis.
|
|
603
|
+
'minor': bool(ec_ax.yaxis._minor_tick_kw.get('tick2On', False)),
|
|
595
604
|
'labels': ec_ax.yaxis._major_tick_kw.get('label2On', True),
|
|
596
605
|
'title': bool(ec_ax.get_ylabel())},
|
|
597
606
|
}
|
|
@@ -615,8 +624,8 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax):
|
|
|
615
624
|
})
|
|
616
625
|
if len(state_history) > 40:
|
|
617
626
|
state_history.pop(0)
|
|
618
|
-
except Exception:
|
|
619
|
-
|
|
627
|
+
except Exception as e:
|
|
628
|
+
print(f"Warning: snapshot failed: {e}")
|
|
620
629
|
def _restore():
|
|
621
630
|
if not state_history:
|
|
622
631
|
print("No undo history."); return
|
|
@@ -1284,7 +1293,6 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax):
|
|
|
1284
1293
|
axis.yaxis.set_major_locator(MaxNLocator(nbins='auto', steps=[1, 2, 5], min_n_ticks=4))
|
|
1285
1294
|
except Exception:
|
|
1286
1295
|
pass
|
|
1287
|
-
_snapshot("toggle-ticks")
|
|
1288
1296
|
while True:
|
|
1289
1297
|
print("Choose pane: o=operando, e=ec, q=back")
|
|
1290
1298
|
pane = input("ot> ").strip().lower()
|
|
@@ -1544,6 +1552,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax):
|
|
|
1544
1552
|
if side == 'right' and key == 'minor':
|
|
1545
1553
|
ts['mry'] = bool(wasd['right']['minor'])
|
|
1546
1554
|
if changed:
|
|
1555
|
+
_snapshot("toggle-ticks")
|
|
1547
1556
|
_apply_wasd_axis(target, wasd)
|
|
1548
1557
|
try:
|
|
1549
1558
|
target._saved_tick_state = dict(ts)
|
|
@@ -1912,7 +1921,6 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax):
|
|
|
1912
1921
|
# Load a .bpcfg style and apply
|
|
1913
1922
|
# Applies style properties from commands: oc, ow, ew, h, el, t, l, f, g, r
|
|
1914
1923
|
try:
|
|
1915
|
-
_snapshot("import-style")
|
|
1916
1924
|
try:
|
|
1917
1925
|
_bpcfg_files = sorted([f for f in os.listdir(os.getcwd()) if f.lower().endswith('.bpcfg')])
|
|
1918
1926
|
except Exception:
|
|
@@ -1924,6 +1932,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax):
|
|
|
1924
1932
|
inp = input("Enter number to open or filename (.bpcfg): ").strip()
|
|
1925
1933
|
if not inp:
|
|
1926
1934
|
print_menu(); continue
|
|
1935
|
+
_snapshot("import-style")
|
|
1927
1936
|
if inp.isdigit() and _bpcfg_files:
|
|
1928
1937
|
_idx = int(inp)
|
|
1929
1938
|
if 1 <= _idx <= len(_bpcfg_files):
|
|
@@ -2737,6 +2746,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax):
|
|
|
2737
2746
|
print("Canvas: only figure size will change; panel widths/gaps are not altered.")
|
|
2738
2747
|
line = input("New canvas size 'W H' (blank=cancel): ").strip()
|
|
2739
2748
|
if line:
|
|
2749
|
+
_snapshot("canvas-size")
|
|
2740
2750
|
try:
|
|
2741
2751
|
parts = line.split()
|
|
2742
2752
|
if len(parts) == 2:
|
|
@@ -166,6 +166,46 @@ def export_style_config(
|
|
|
166
166
|
bbox = ax.get_position()
|
|
167
167
|
frame_w_in = bbox.width * fw
|
|
168
168
|
frame_h_in = bbox.height * fh
|
|
169
|
+
|
|
170
|
+
# Build WASD state (20 parameters: 4 sides × 5 properties each)
|
|
171
|
+
def _get_spine_visible(which: str) -> bool:
|
|
172
|
+
sp = ax.spines.get(which)
|
|
173
|
+
try:
|
|
174
|
+
return bool(sp.get_visible()) if sp is not None else False
|
|
175
|
+
except Exception:
|
|
176
|
+
return False
|
|
177
|
+
|
|
178
|
+
wasd_state = {
|
|
179
|
+
'top': {
|
|
180
|
+
'spine': _get_spine_visible('top'),
|
|
181
|
+
'ticks': bool(tick_state.get('t_ticks', tick_state.get('tx', False))),
|
|
182
|
+
'minor': bool(tick_state.get('mtx', False)),
|
|
183
|
+
'labels': bool(tick_state.get('t_labels', tick_state.get('tx', False))),
|
|
184
|
+
'title': bool(getattr(ax, '_top_xlabel_on', False))
|
|
185
|
+
},
|
|
186
|
+
'bottom': {
|
|
187
|
+
'spine': _get_spine_visible('bottom'),
|
|
188
|
+
'ticks': bool(tick_state.get('b_ticks', tick_state.get('bx', True))),
|
|
189
|
+
'minor': bool(tick_state.get('mbx', False)),
|
|
190
|
+
'labels': bool(tick_state.get('b_labels', tick_state.get('bx', True))),
|
|
191
|
+
'title': bool(ax.get_xlabel())
|
|
192
|
+
},
|
|
193
|
+
'left': {
|
|
194
|
+
'spine': _get_spine_visible('left'),
|
|
195
|
+
'ticks': bool(tick_state.get('l_ticks', tick_state.get('ly', True))),
|
|
196
|
+
'minor': bool(tick_state.get('mly', False)),
|
|
197
|
+
'labels': bool(tick_state.get('l_labels', tick_state.get('ly', True))),
|
|
198
|
+
'title': bool(ax.get_ylabel())
|
|
199
|
+
},
|
|
200
|
+
'right': {
|
|
201
|
+
'spine': _get_spine_visible('right'),
|
|
202
|
+
'ticks': bool(tick_state.get('r_ticks', tick_state.get('ry', False))),
|
|
203
|
+
'minor': bool(tick_state.get('mry', False)),
|
|
204
|
+
'labels': bool(tick_state.get('r_labels', tick_state.get('ry', False))),
|
|
205
|
+
'title': bool(getattr(ax, '_right_ylabel_on', False))
|
|
206
|
+
},
|
|
207
|
+
}
|
|
208
|
+
|
|
169
209
|
cfg = {
|
|
170
210
|
"figure": {
|
|
171
211
|
"size": [fw, fh],
|
|
@@ -184,12 +224,12 @@ def export_style_config(
|
|
|
184
224
|
"family_chain": plt.rcParams.get("font.sans-serif"),
|
|
185
225
|
},
|
|
186
226
|
"ticks": {
|
|
187
|
-
"visibility": tick_state.copy(),
|
|
188
227
|
"x_major_width": axis_tick_width(ax.xaxis, "major"),
|
|
189
228
|
"x_minor_width": axis_tick_width(ax.xaxis, "minor"),
|
|
190
229
|
"y_major_width": axis_tick_width(ax.yaxis, "major"),
|
|
191
230
|
"y_minor_width": axis_tick_width(ax.yaxis, "minor"),
|
|
192
231
|
},
|
|
232
|
+
"wasd_state": wasd_state,
|
|
193
233
|
"spines": {
|
|
194
234
|
name: {
|
|
195
235
|
"linewidth": spn.get_linewidth(),
|
|
@@ -403,17 +443,88 @@ def apply_style_config(
|
|
|
403
443
|
|
|
404
444
|
# Tick visibility + widths
|
|
405
445
|
ticks_cfg = cfg.get("ticks", {})
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
changed_visibility = True
|
|
412
|
-
if changed_visibility:
|
|
446
|
+
|
|
447
|
+
# Try wasd_state first (version 2), fall back to visibility dict (version 1)
|
|
448
|
+
wasd = cfg.get("wasd_state", {})
|
|
449
|
+
if wasd:
|
|
450
|
+
# Apply WASD state (20 parameters)
|
|
413
451
|
try:
|
|
414
|
-
|
|
452
|
+
# Apply spines from wasd
|
|
453
|
+
for side in ('top', 'bottom', 'left', 'right'):
|
|
454
|
+
side_cfg = wasd.get(side, {})
|
|
455
|
+
if 'spine' in side_cfg and side in ax.spines:
|
|
456
|
+
ax.spines[side].set_visible(bool(side_cfg['spine']))
|
|
457
|
+
|
|
458
|
+
# Apply ticks and labels
|
|
459
|
+
top_cfg = wasd.get('top', {})
|
|
460
|
+
bot_cfg = wasd.get('bottom', {})
|
|
461
|
+
left_cfg = wasd.get('left', {})
|
|
462
|
+
right_cfg = wasd.get('right', {})
|
|
463
|
+
|
|
464
|
+
ax.tick_params(axis='x',
|
|
465
|
+
top=bool(top_cfg.get('ticks', False)),
|
|
466
|
+
bottom=bool(bot_cfg.get('ticks', True)),
|
|
467
|
+
labeltop=bool(top_cfg.get('labels', False)),
|
|
468
|
+
labelbottom=bool(bot_cfg.get('labels', True)))
|
|
469
|
+
ax.tick_params(axis='y',
|
|
470
|
+
left=bool(left_cfg.get('ticks', True)),
|
|
471
|
+
right=bool(right_cfg.get('ticks', False)),
|
|
472
|
+
labelleft=bool(left_cfg.get('labels', True)),
|
|
473
|
+
labelright=bool(right_cfg.get('labels', False)))
|
|
474
|
+
|
|
475
|
+
# Apply minor ticks
|
|
476
|
+
if top_cfg.get('minor') or bot_cfg.get('minor'):
|
|
477
|
+
from matplotlib.ticker import AutoMinorLocator, NullFormatter
|
|
478
|
+
ax.xaxis.set_minor_locator(AutoMinorLocator())
|
|
479
|
+
ax.xaxis.set_minor_formatter(NullFormatter())
|
|
480
|
+
ax.tick_params(axis='x', which='minor',
|
|
481
|
+
top=bool(top_cfg.get('minor', False)),
|
|
482
|
+
bottom=bool(bot_cfg.get('minor', False)),
|
|
483
|
+
labeltop=False, labelbottom=False)
|
|
484
|
+
|
|
485
|
+
if left_cfg.get('minor') or right_cfg.get('minor'):
|
|
486
|
+
from matplotlib.ticker import AutoMinorLocator, NullFormatter
|
|
487
|
+
ax.yaxis.set_minor_locator(AutoMinorLocator())
|
|
488
|
+
ax.yaxis.set_minor_formatter(NullFormatter())
|
|
489
|
+
ax.tick_params(axis='y', which='minor',
|
|
490
|
+
left=bool(left_cfg.get('minor', False)),
|
|
491
|
+
right=bool(right_cfg.get('minor', False)),
|
|
492
|
+
labelleft=False, labelright=False)
|
|
493
|
+
|
|
494
|
+
# Apply titles
|
|
495
|
+
ax._top_xlabel_on = bool(top_cfg.get('title', False))
|
|
496
|
+
ax._right_ylabel_on = bool(right_cfg.get('title', False))
|
|
497
|
+
|
|
498
|
+
# Update tick_state for consistency
|
|
499
|
+
tick_state['t_ticks'] = bool(top_cfg.get('ticks', False))
|
|
500
|
+
tick_state['t_labels'] = bool(top_cfg.get('labels', False))
|
|
501
|
+
tick_state['b_ticks'] = bool(bot_cfg.get('ticks', True))
|
|
502
|
+
tick_state['b_labels'] = bool(bot_cfg.get('labels', True))
|
|
503
|
+
tick_state['l_ticks'] = bool(left_cfg.get('ticks', True))
|
|
504
|
+
tick_state['l_labels'] = bool(left_cfg.get('labels', True))
|
|
505
|
+
tick_state['r_ticks'] = bool(right_cfg.get('ticks', False))
|
|
506
|
+
tick_state['r_labels'] = bool(right_cfg.get('labels', False))
|
|
507
|
+
tick_state['mtx'] = bool(top_cfg.get('minor', False))
|
|
508
|
+
tick_state['mbx'] = bool(bot_cfg.get('minor', False))
|
|
509
|
+
tick_state['mly'] = bool(left_cfg.get('minor', False))
|
|
510
|
+
tick_state['mry'] = bool(right_cfg.get('minor', False))
|
|
511
|
+
|
|
415
512
|
except Exception as e:
|
|
416
|
-
print(f"
|
|
513
|
+
print(f"Warning: Could not apply WASD tick visibility: {e}")
|
|
514
|
+
else:
|
|
515
|
+
# Fall back to old visibility dict
|
|
516
|
+
vis_cfg = ticks_cfg.get("visibility", {})
|
|
517
|
+
changed_visibility = False
|
|
518
|
+
for k, v in vis_cfg.items():
|
|
519
|
+
if k in tick_state and isinstance(v, bool):
|
|
520
|
+
tick_state[k] = v
|
|
521
|
+
changed_visibility = True
|
|
522
|
+
if changed_visibility:
|
|
523
|
+
try:
|
|
524
|
+
_ui_update_tick_visibility(ax, tick_state)
|
|
525
|
+
except Exception as e:
|
|
526
|
+
print(f"[DEBUG] Exception updating tick visibility: {e}")
|
|
527
|
+
|
|
417
528
|
|
|
418
529
|
xmaj = ticks_cfg.get("x_major_width")
|
|
419
530
|
xminr = ticks_cfg.get("x_minor_width")
|
|
@@ -250,7 +250,7 @@ def position_bottom_xlabel(ax, fig, tick_state: Dict[str, bool]):
|
|
|
250
250
|
pass
|
|
251
251
|
return
|
|
252
252
|
# Otherwise choose pad based on current tick label visibility
|
|
253
|
-
pad =
|
|
253
|
+
pad = 8 if bool(tick_state.get('b_labels', tick_state.get('bx', False))) else 6
|
|
254
254
|
try:
|
|
255
255
|
ax.xaxis.labelpad = pad
|
|
256
256
|
except Exception:
|
|
@@ -280,7 +280,7 @@ def position_left_ylabel(ax, fig, tick_state: Dict[str, bool]):
|
|
|
280
280
|
except Exception:
|
|
281
281
|
pass
|
|
282
282
|
return
|
|
283
|
-
pad =
|
|
283
|
+
pad = 8 if bool(tick_state.get('l_labels', tick_state.get('ly', False))) else 6
|
|
284
284
|
try:
|
|
285
285
|
ax.yaxis.labelpad = pad
|
|
286
286
|
except Exception:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "batplot"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.2.0"
|
|
8
8
|
description = "Interactive plotting for XRD, PDF, and XAS data (.xye, .xy, .qye, .dat, .csv, .gr, .nor, .chik, .chir)"
|
|
9
9
|
authors = [
|
|
10
10
|
{ name = "Tian Dai", email = "tianda@uio.no" }
|
batplot-1.1.8/batplot/cli.py
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
"""CLI entry for batplot.
|
|
2
|
-
|
|
3
|
-
Clean entry point that delegates to mode handlers without import-time side effects.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
from __future__ import annotations
|
|
7
|
-
|
|
8
|
-
import sys
|
|
9
|
-
from typing import Optional
|
|
10
|
-
|
|
11
|
-
def main(argv: Optional[list] = None) -> int:
|
|
12
|
-
"""Main CLI entry point for batplot.
|
|
13
|
-
|
|
14
|
-
Args:
|
|
15
|
-
argv: Optional command line arguments (defaults to sys.argv)
|
|
16
|
-
|
|
17
|
-
Returns:
|
|
18
|
-
Exit code (0 for success, non-zero for error)
|
|
19
|
-
"""
|
|
20
|
-
# Import here to avoid side effects at module import time
|
|
21
|
-
if argv is not None:
|
|
22
|
-
# Temporarily replace sys.argv for argument parsing
|
|
23
|
-
old_argv = sys.argv
|
|
24
|
-
sys.argv = ['batplot'] + list(argv)
|
|
25
|
-
|
|
26
|
-
try:
|
|
27
|
-
# Import the main batplot function (now refactored to be safe)
|
|
28
|
-
from .batplot import batplot_main
|
|
29
|
-
return batplot_main()
|
|
30
|
-
finally:
|
|
31
|
-
if argv is not None:
|
|
32
|
-
sys.argv = old_argv
|
|
33
|
-
|
|
34
|
-
__all__ = ["main"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|