batplot 1.8.4__py3-none-any.whl → 1.8.6__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.
- batplot/__init__.py +1 -1
- batplot/args.py +22 -4
- batplot/batch.py +12 -0
- batplot/batplot.py +340 -126
- batplot/converters.py +170 -122
- batplot/cpc_interactive.py +319 -161
- batplot/data/USER_MANUAL.md +49 -0
- batplot/electrochem_interactive.py +120 -80
- batplot/interactive.py +1763 -75
- batplot/modes.py +12 -11
- batplot/operando.py +22 -0
- batplot/operando_ec_interactive.py +390 -16
- batplot/session.py +85 -9
- batplot/style.py +198 -21
- {batplot-1.8.4.dist-info → batplot-1.8.6.dist-info}/METADATA +1 -1
- {batplot-1.8.4.dist-info → batplot-1.8.6.dist-info}/RECORD +20 -20
- {batplot-1.8.4.dist-info → batplot-1.8.6.dist-info}/WHEEL +1 -1
- {batplot-1.8.4.dist-info → batplot-1.8.6.dist-info}/licenses/LICENSE +0 -0
- {batplot-1.8.4.dist-info → batplot-1.8.6.dist-info}/entry_points.txt +0 -0
- {batplot-1.8.4.dist-info → batplot-1.8.6.dist-info}/top_level.txt +0 -0
batplot/session.py
CHANGED
|
@@ -500,6 +500,30 @@ def dump_session(
|
|
|
500
500
|
'orig_y': [np.array(a) for a in orig_y],
|
|
501
501
|
'offsets': list(offsets_list),
|
|
502
502
|
'labels': list(labels),
|
|
503
|
+
# Processed data (for smooth/reduce operations)
|
|
504
|
+
'original_x_data_list': ([np.array(a) for a in getattr(fig, '_original_x_data_list', [])]
|
|
505
|
+
if hasattr(fig, '_original_x_data_list') else None),
|
|
506
|
+
'original_y_data_list': ([np.array(a) for a in getattr(fig, '_original_y_data_list', [])]
|
|
507
|
+
if hasattr(fig, '_original_y_data_list') else None),
|
|
508
|
+
'full_processed_x_data_list': ([np.array(a) for a in getattr(fig, '_full_processed_x_data_list', [])]
|
|
509
|
+
if hasattr(fig, '_full_processed_x_data_list') else None),
|
|
510
|
+
'full_processed_y_data_list': ([np.array(a) for a in getattr(fig, '_full_processed_y_data_list', [])]
|
|
511
|
+
if hasattr(fig, '_full_processed_y_data_list') else None),
|
|
512
|
+
'smooth_settings': (dict(getattr(fig, '_smooth_settings', {}))
|
|
513
|
+
if hasattr(fig, '_smooth_settings') else None),
|
|
514
|
+
'last_smooth_settings': (dict(getattr(fig, '_last_smooth_settings', {}))
|
|
515
|
+
if hasattr(fig, '_last_smooth_settings') else None),
|
|
516
|
+
# Derivative data (for derivative operations)
|
|
517
|
+
'pre_derivative_x_data_list': ([np.array(a) for a in getattr(fig, '_pre_derivative_x_data_list', [])]
|
|
518
|
+
if hasattr(fig, '_pre_derivative_x_data_list') else None),
|
|
519
|
+
'pre_derivative_y_data_list': ([np.array(a) for a in getattr(fig, '_pre_derivative_y_data_list', [])]
|
|
520
|
+
if hasattr(fig, '_pre_derivative_y_data_list') else None),
|
|
521
|
+
'pre_derivative_ylabel': (str(getattr(fig, '_pre_derivative_ylabel', ''))
|
|
522
|
+
if hasattr(fig, '_pre_derivative_ylabel') else None),
|
|
523
|
+
'derivative_order': (int(getattr(fig, '_derivative_order', 0))
|
|
524
|
+
if hasattr(fig, '_derivative_order') else None),
|
|
525
|
+
'derivative_reversed': (bool(getattr(fig, '_derivative_reversed', False))
|
|
526
|
+
if hasattr(fig, '_derivative_reversed') else None),
|
|
503
527
|
'line_styles': [
|
|
504
528
|
{
|
|
505
529
|
'color': ln.get_color(),
|
|
@@ -540,6 +564,7 @@ def dump_session(
|
|
|
540
564
|
'tick_state': dict(tick_state),
|
|
541
565
|
'tick_widths': tick_widths,
|
|
542
566
|
'tick_lengths': tick_lengths,
|
|
567
|
+
'tick_direction': getattr(fig, '_tick_direction', 'out'),
|
|
543
568
|
'font': {
|
|
544
569
|
'size': plt.rcParams.get('font.size'),
|
|
545
570
|
'chain': list(plt.rcParams.get('font.sans-serif', [])),
|
|
@@ -685,20 +710,34 @@ def dump_operando_session(
|
|
|
685
710
|
def _capture_wasd_state(axis):
|
|
686
711
|
ts = getattr(axis, '_saved_tick_state', {})
|
|
687
712
|
wasd = {}
|
|
713
|
+
# Check if ylabel is positioned on right (typical for EC axis)
|
|
714
|
+
ylabel_on_right = False
|
|
715
|
+
try:
|
|
716
|
+
ylabel_on_right = (axis.yaxis.get_label_position() == 'right')
|
|
717
|
+
except Exception:
|
|
718
|
+
pass
|
|
719
|
+
|
|
688
720
|
for side in ('top', 'bottom', 'left', 'right'):
|
|
689
721
|
sp = axis.spines.get(side)
|
|
690
722
|
prefix = {'top': 't', 'bottom': 'b', 'left': 'l', 'right': 'r'}[side]
|
|
691
|
-
#
|
|
692
|
-
# If hidden but has stored text, the title state should be False (hidden)
|
|
723
|
+
# Title state logic
|
|
693
724
|
if side == 'left':
|
|
694
|
-
|
|
695
|
-
|
|
725
|
+
# If ylabel is positioned on right (EC axis), left has no title
|
|
726
|
+
if ylabel_on_right:
|
|
727
|
+
title_state = False
|
|
728
|
+
else:
|
|
729
|
+
ylabel_text = axis.get_ylabel()
|
|
730
|
+
title_state = bool(ylabel_text) # True only if currently visible with text
|
|
696
731
|
elif side == 'bottom':
|
|
697
732
|
title_state = bool(axis.get_xlabel())
|
|
698
733
|
elif side == 'top':
|
|
699
734
|
title_state = bool(getattr(axis, '_top_xlabel_on', False))
|
|
700
735
|
elif side == 'right':
|
|
701
|
-
|
|
736
|
+
# If ylabel is positioned on right (EC axis), check if ylabel is visible (not empty)
|
|
737
|
+
if ylabel_on_right:
|
|
738
|
+
title_state = bool(axis.get_ylabel()) # Empty string = hidden by user
|
|
739
|
+
else:
|
|
740
|
+
title_state = bool(getattr(axis, '_right_ylabel_on', False))
|
|
702
741
|
else:
|
|
703
742
|
title_state = False
|
|
704
743
|
|
|
@@ -925,6 +964,11 @@ def load_operando_session(filename: str):
|
|
|
925
964
|
# Use standard DPI of 100 instead of saved DPI to avoid display-dependent issues
|
|
926
965
|
# (Retina displays, Windows scaling, etc. can cause saved DPI to differ)
|
|
927
966
|
fig = plt.figure(figsize=tuple(sess['figure']['size']), dpi=100)
|
|
967
|
+
# Seed last-session path so 'os' overwrite command is available immediately
|
|
968
|
+
try:
|
|
969
|
+
fig._last_session_save_path = os.path.abspath(filename)
|
|
970
|
+
except Exception:
|
|
971
|
+
pass
|
|
928
972
|
# Disable automatic layout adjustments to preserve saved geometry
|
|
929
973
|
try:
|
|
930
974
|
fig.set_layout_engine('none')
|
|
@@ -1211,11 +1255,33 @@ def load_operando_session(filename: str):
|
|
|
1211
1255
|
bottom=bool(ec_wasd.get('bottom', {}).get('ticks', True)),
|
|
1212
1256
|
labeltop=bool(ec_wasd.get('top', {}).get('labels', False)),
|
|
1213
1257
|
labelbottom=bool(ec_wasd.get('bottom', {}).get('labels', True)))
|
|
1258
|
+
# For EC: ticks and labels are on RIGHT by default, not left!
|
|
1259
|
+
# CRITICAL: EC y-axis defaults are: left=False, right=True (both ticks and labels)
|
|
1260
|
+
# Old sessions may have saved wrong values, so we need to sanitize them
|
|
1261
|
+
|
|
1262
|
+
# EC left side should ALWAYS be False (EC uses right side for y-axis)
|
|
1263
|
+
left_ticks = False
|
|
1264
|
+
left_labels = False
|
|
1265
|
+
|
|
1266
|
+
# EC right side should be True when ylabel is visible
|
|
1267
|
+
right_title = ec_wasd.get('right', {}).get('title', True)
|
|
1268
|
+
|
|
1269
|
+
# If right title is ON, ticks/labels should also be ON
|
|
1270
|
+
if right_title:
|
|
1271
|
+
right_ticks = True
|
|
1272
|
+
right_labels = True
|
|
1273
|
+
else:
|
|
1274
|
+
# Title is hidden - respect the saved tick/label state or use False
|
|
1275
|
+
right_ticks_val = ec_wasd.get('right', {}).get('ticks')
|
|
1276
|
+
right_labels_val = ec_wasd.get('right', {}).get('labels')
|
|
1277
|
+
right_ticks = bool(right_ticks_val) if right_ticks_val is not None else False
|
|
1278
|
+
right_labels = bool(right_labels_val) if right_labels_val is not None else False
|
|
1279
|
+
|
|
1214
1280
|
ec_ax.tick_params(axis='y',
|
|
1215
|
-
left=
|
|
1216
|
-
right=
|
|
1217
|
-
labelleft=
|
|
1218
|
-
labelright=
|
|
1281
|
+
left=left_ticks,
|
|
1282
|
+
right=right_ticks,
|
|
1283
|
+
labelleft=left_labels,
|
|
1284
|
+
labelright=right_labels)
|
|
1219
1285
|
# Apply minor ticks
|
|
1220
1286
|
if ec_wasd.get('top', {}).get('minor') or ec_wasd.get('bottom', {}).get('minor'):
|
|
1221
1287
|
ec_ax.xaxis.set_minor_locator(AutoMinorLocator())
|
|
@@ -1794,6 +1860,11 @@ def load_ec_session(filename: str):
|
|
|
1794
1860
|
# Use standard DPI of 100 instead of saved DPI to avoid display-dependent issues
|
|
1795
1861
|
# (Retina displays, Windows scaling, etc. can cause saved DPI to differ)
|
|
1796
1862
|
fig = plt.figure(figsize=tuple(sess['figure']['size']), dpi=100)
|
|
1863
|
+
# Seed last-session path so 'os' overwrite command is available immediately
|
|
1864
|
+
try:
|
|
1865
|
+
fig._last_session_save_path = os.path.abspath(filename)
|
|
1866
|
+
except Exception:
|
|
1867
|
+
pass
|
|
1797
1868
|
# Preserve saved geometry by disabling auto layout
|
|
1798
1869
|
try:
|
|
1799
1870
|
fig.set_layout_engine('none')
|
|
@@ -2693,6 +2764,11 @@ def load_cpc_session(filename: str):
|
|
|
2693
2764
|
# Use standard DPI of 100 instead of saved DPI to avoid display-dependent issues
|
|
2694
2765
|
# (Retina displays, Windows scaling, etc. can cause saved DPI to differ)
|
|
2695
2766
|
fig = plt.figure(figsize=tuple(sess['figure']['size']), dpi=100)
|
|
2767
|
+
# Seed last-session path so 'os' overwrite command is available immediately
|
|
2768
|
+
try:
|
|
2769
|
+
fig._last_session_save_path = os.path.abspath(filename)
|
|
2770
|
+
except Exception:
|
|
2771
|
+
pass
|
|
2696
2772
|
# Disable auto layout
|
|
2697
2773
|
try:
|
|
2698
2774
|
fig.set_layout_engine('none')
|
batplot/style.py
CHANGED
|
@@ -8,6 +8,7 @@ from __future__ import annotations
|
|
|
8
8
|
from typing import List, Dict, Any, Callable, Optional
|
|
9
9
|
import json
|
|
10
10
|
import importlib
|
|
11
|
+
import os
|
|
11
12
|
import sys
|
|
12
13
|
import numpy as np
|
|
13
14
|
import matplotlib.pyplot as plt
|
|
@@ -451,7 +452,19 @@ def print_style_info(
|
|
|
451
452
|
except Exception:
|
|
452
453
|
pass
|
|
453
454
|
|
|
454
|
-
#
|
|
455
|
+
# CIF hkl label visibility
|
|
456
|
+
if show_cif_hkl is not None:
|
|
457
|
+
print(f"CIF hkl labels: {'shown' if show_cif_hkl else 'hidden'}")
|
|
458
|
+
elif cif_tick_series:
|
|
459
|
+
# Try to read from __main__ module if not provided
|
|
460
|
+
try:
|
|
461
|
+
import sys
|
|
462
|
+
_bp_module = sys.modules.get('__main__')
|
|
463
|
+
if _bp_module is not None and hasattr(_bp_module, 'show_cif_hkl'):
|
|
464
|
+
hkl_state = bool(getattr(_bp_module, 'show_cif_hkl', False))
|
|
465
|
+
print(f"CIF hkl labels: {'shown' if hkl_state else 'hidden'}")
|
|
466
|
+
except Exception:
|
|
467
|
+
pass
|
|
455
468
|
|
|
456
469
|
# Omit non-style global flags (mode/raw/autoscale/delta)
|
|
457
470
|
|
|
@@ -508,6 +521,7 @@ def export_style_config(
|
|
|
508
521
|
base_path: Optional[str] = None,
|
|
509
522
|
show_cif_titles: Optional[bool] = None,
|
|
510
523
|
overwrite_path: Optional[str] = None,
|
|
524
|
+
force_kind: Optional[str] = None,
|
|
511
525
|
) -> Optional[str]:
|
|
512
526
|
"""Export style configuration after displaying a summary and prompting the user.
|
|
513
527
|
|
|
@@ -592,6 +606,8 @@ def export_style_config(
|
|
|
592
606
|
"x_minor_width": axis_tick_width(ax.xaxis, "minor"),
|
|
593
607
|
"y_major_width": axis_tick_width(ax.yaxis, "major"),
|
|
594
608
|
"y_minor_width": axis_tick_width(ax.yaxis, "minor"),
|
|
609
|
+
"lengths": dict(getattr(fig, '_tick_lengths', {})),
|
|
610
|
+
"direction": getattr(fig, '_tick_direction', 'out'),
|
|
595
611
|
},
|
|
596
612
|
"wasd_state": wasd_state,
|
|
597
613
|
"spines": {
|
|
@@ -670,6 +686,14 @@ def export_style_config(
|
|
|
670
686
|
# Save CIF title visibility
|
|
671
687
|
if show_cif_titles is not None:
|
|
672
688
|
cfg["show_cif_titles"] = bool(show_cif_titles)
|
|
689
|
+
# Save CIF hkl label visibility (read from __main__ module if available)
|
|
690
|
+
try:
|
|
691
|
+
import sys
|
|
692
|
+
_bp_module = sys.modules.get('__main__')
|
|
693
|
+
if _bp_module is not None and hasattr(_bp_module, 'show_cif_hkl'):
|
|
694
|
+
cfg["show_cif_hkl"] = bool(getattr(_bp_module, 'show_cif_hkl', False))
|
|
695
|
+
except Exception:
|
|
696
|
+
pass
|
|
673
697
|
if cif_tick_series:
|
|
674
698
|
cfg["cif_ticks"] = [
|
|
675
699
|
{"index": i, "color": color}
|
|
@@ -692,18 +716,36 @@ def export_style_config(
|
|
|
692
716
|
if serialized_palettes:
|
|
693
717
|
cfg['curve_palettes'] = serialized_palettes
|
|
694
718
|
|
|
695
|
-
#
|
|
719
|
+
# Store smooth settings (metadata only, not full arrays)
|
|
720
|
+
if hasattr(fig, '_smooth_settings'):
|
|
721
|
+
cfg['smooth_settings'] = dict(fig._smooth_settings)
|
|
722
|
+
if hasattr(fig, '_last_smooth_settings'):
|
|
723
|
+
cfg['last_smooth_settings'] = dict(fig._last_smooth_settings)
|
|
724
|
+
# Store derivative order (metadata only)
|
|
725
|
+
if hasattr(fig, '_derivative_order'):
|
|
726
|
+
cfg['derivative_order'] = int(fig._derivative_order)
|
|
727
|
+
if hasattr(fig, '_derivative_reversed'):
|
|
728
|
+
cfg['derivative_reversed'] = bool(fig._derivative_reversed)
|
|
729
|
+
# Note: We don't store original_x_data_list/original_y_data_list or pre_derivative data in style files
|
|
730
|
+
# as style files are for styling only, and the data would be specific
|
|
731
|
+
# to the dataset. Session files (pickle) store this data instead.
|
|
732
|
+
|
|
733
|
+
# If overwrite_path is provided, determine export type from existing file,
|
|
734
|
+
# unless the caller explicitly forces style-only or style+geometry.
|
|
696
735
|
if overwrite_path:
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
736
|
+
if force_kind in ('ps', 'psg'):
|
|
737
|
+
exp_choice = force_kind
|
|
738
|
+
else:
|
|
739
|
+
try:
|
|
740
|
+
with open(overwrite_path, 'r', encoding='utf-8') as f:
|
|
741
|
+
old_cfg = json.load(f)
|
|
742
|
+
old_kind = old_cfg.get('kind', '')
|
|
743
|
+
if old_kind == 'xy_style_geom':
|
|
744
|
+
exp_choice = 'psg'
|
|
745
|
+
else:
|
|
746
|
+
exp_choice = 'ps'
|
|
747
|
+
except Exception:
|
|
748
|
+
exp_choice = 'ps' # Default to style-only if can't read
|
|
707
749
|
else:
|
|
708
750
|
# Ask user for style-only or style+geometry
|
|
709
751
|
print("\nExport options:")
|
|
@@ -873,6 +915,34 @@ def apply_style_config(
|
|
|
873
915
|
print("Warning: Style/geometry file was saved without --ro; current plot was created with --ro.")
|
|
874
916
|
print("Not applying style/geometry to avoid corrupting axis orientation.")
|
|
875
917
|
return
|
|
918
|
+
|
|
919
|
+
# --- Style-import check messages (to debug y-axis / curve visibility after import)
|
|
920
|
+
# Disabled by default; set BATPLOT_STYLE_DEBUG=1 to enable. ---
|
|
921
|
+
_style_debug = os.environ.get("BATPLOT_STYLE_DEBUG", "0") == "1"
|
|
922
|
+
if _style_debug:
|
|
923
|
+
kind = cfg.get("kind", "")
|
|
924
|
+
has_geom = "geometry" in cfg and isinstance(cfg.get("geometry"), dict)
|
|
925
|
+
geom_ylim = cfg.get("geometry", {}).get("ylim") if has_geom else None
|
|
926
|
+
print("[style-import check] BEFORE applying style:")
|
|
927
|
+
print(f" kind={kind!r} has_geometry={has_geom} geom_ylim={geom_ylim}")
|
|
928
|
+
try:
|
|
929
|
+
xlim0, xlim1 = ax.get_xlim()
|
|
930
|
+
ylim0, ylim1 = ax.get_ylim()
|
|
931
|
+
print(f" ax xlim=({xlim0}, {xlim1}) ylim=({ylim0}, {ylim1})")
|
|
932
|
+
except Exception as e:
|
|
933
|
+
print(f" ax get_xlim/get_ylim failed: {e}")
|
|
934
|
+
nlines = len(ax.lines)
|
|
935
|
+
print(f" n_ax.lines={nlines} n_cfg.lines={len(cfg.get('lines', []))}")
|
|
936
|
+
if orig_y is not None:
|
|
937
|
+
print(f" len(orig_y)={len(orig_y)} len(offsets_list)={len(offsets_list) if offsets_list else 0}")
|
|
938
|
+
for i in range(nlines):
|
|
939
|
+
ln = ax.lines[i]
|
|
940
|
+
xd, yd = ln.get_data()
|
|
941
|
+
ymn = float(yd.min()) if yd.size else float("nan")
|
|
942
|
+
ymx = float(yd.max()) if yd.size else float("nan")
|
|
943
|
+
print(f" line[{i}] y_range=({ymn}, {ymx}) n_pts={len(yd)}")
|
|
944
|
+
# --- end check ---
|
|
945
|
+
|
|
876
946
|
# Save current labelpad values BEFORE any style changes
|
|
877
947
|
saved_xlabelpad = None
|
|
878
948
|
saved_ylabelpad = None
|
|
@@ -921,6 +991,12 @@ def apply_style_config(
|
|
|
921
991
|
fig.subplots_adjust(left=left, right=left + w_frac, bottom=bottom, top=bottom + h_frac)
|
|
922
992
|
except Exception as e:
|
|
923
993
|
print(f"[DEBUG] Exception in frame/axes fraction adjustment: {e}")
|
|
994
|
+
if _style_debug:
|
|
995
|
+
try:
|
|
996
|
+
ylim0, ylim1 = ax.get_ylim()
|
|
997
|
+
print(f"[style-import check] AFTER figure size/axes_frac: ax ylim=({ylim0}, {ylim1})")
|
|
998
|
+
except Exception:
|
|
999
|
+
pass
|
|
924
1000
|
# Don't restore DPI from style - use system default to avoid display-dependent issues
|
|
925
1001
|
# (Retina displays, Windows scaling, etc. can cause saved DPI to differ)
|
|
926
1002
|
|
|
@@ -1101,6 +1177,32 @@ def apply_style_config(
|
|
|
1101
1177
|
ax.tick_params(axis="y", which="minor", width=yminr)
|
|
1102
1178
|
except Exception as e:
|
|
1103
1179
|
print(f"[DEBUG] Exception setting tick widths: {e}")
|
|
1180
|
+
# Tick lengths (t submenu)
|
|
1181
|
+
tick_lengths = ticks_cfg.get("lengths") or {}
|
|
1182
|
+
if isinstance(tick_lengths, dict):
|
|
1183
|
+
try:
|
|
1184
|
+
major_len = tick_lengths.get("major")
|
|
1185
|
+
minor_len = tick_lengths.get("minor")
|
|
1186
|
+
if major_len is not None:
|
|
1187
|
+
ax.tick_params(axis="both", which="major", length=float(major_len))
|
|
1188
|
+
if not hasattr(fig, '_tick_lengths'):
|
|
1189
|
+
fig._tick_lengths = {}
|
|
1190
|
+
fig._tick_lengths['major'] = float(major_len)
|
|
1191
|
+
if minor_len is not None:
|
|
1192
|
+
ax.tick_params(axis="both", which="minor", length=float(minor_len))
|
|
1193
|
+
if not hasattr(fig, '_tick_lengths'):
|
|
1194
|
+
fig._tick_lengths = {}
|
|
1195
|
+
fig._tick_lengths['minor'] = float(minor_len)
|
|
1196
|
+
except Exception as e:
|
|
1197
|
+
print(f"Warning: Could not restore tick lengths: {e}")
|
|
1198
|
+
# Tick direction (t submenu)
|
|
1199
|
+
tick_direction = ticks_cfg.get("direction")
|
|
1200
|
+
if tick_direction:
|
|
1201
|
+
try:
|
|
1202
|
+
setattr(fig, '_tick_direction', tick_direction)
|
|
1203
|
+
ax.tick_params(axis="both", which="both", direction=tick_direction)
|
|
1204
|
+
except Exception as e:
|
|
1205
|
+
print(f"Warning: Could not restore tick direction: {e}")
|
|
1104
1206
|
|
|
1105
1207
|
# Spines
|
|
1106
1208
|
for name, sp_dict in cfg.get("spines", {}).items():
|
|
@@ -1179,19 +1281,33 @@ def apply_style_config(
|
|
|
1179
1281
|
except Exception:
|
|
1180
1282
|
pass
|
|
1181
1283
|
# Restore offset if available
|
|
1182
|
-
|
|
1284
|
+
# Use current displayed y and current offset to get baseline, then apply file offset.
|
|
1285
|
+
# (orig_y can be wrong in stacked sessions—e.g. already offset—so we derive baseline here.)
|
|
1286
|
+
if "offset" in entry and offsets_list is not None and x_data_list is not None:
|
|
1183
1287
|
try:
|
|
1184
1288
|
offset_val = float(entry["offset"])
|
|
1185
|
-
if idx < len(offsets_list):
|
|
1289
|
+
if idx < len(offsets_list) and idx < len(y_data_list) and idx < len(x_data_list):
|
|
1290
|
+
current_y = y_data_list[idx]
|
|
1291
|
+
current_offset = offsets_list[idx]
|
|
1292
|
+
baseline = current_y - current_offset
|
|
1293
|
+
y_with_offset = baseline + offset_val
|
|
1186
1294
|
offsets_list[idx] = offset_val
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1295
|
+
y_data_list[idx] = y_with_offset
|
|
1296
|
+
ln.set_data(x_data_list[idx], y_with_offset)
|
|
1297
|
+
if orig_y is not None and idx < len(orig_y):
|
|
1298
|
+
orig_y[idx] = np.asarray(baseline, dtype=float)
|
|
1299
|
+
if _style_debug:
|
|
1300
|
+
bmin, bmax = (float(baseline.min()), float(baseline.max())) if getattr(baseline, "size", 0) else (float("nan"), float("nan"))
|
|
1301
|
+
ymin, ymax = (float(y_with_offset.min()), float(y_with_offset.max())) if getattr(y_with_offset, "size", 0) else (float("nan"), float("nan"))
|
|
1302
|
+
print(f"[style-import check] line[{idx}] offset_from_file={offset_val} baseline=({bmin}, {bmax}) y_with_offset=({ymin}, {ymax})")
|
|
1193
1303
|
except Exception as e:
|
|
1194
1304
|
print(f"Warning: Could not restore offset for curve {idx+1}: {e}")
|
|
1305
|
+
if _style_debug:
|
|
1306
|
+
try:
|
|
1307
|
+
ylim0, ylim1 = ax.get_ylim()
|
|
1308
|
+
print(f"[style-import check] AFTER lines/offset restore: ax ylim=({ylim0}, {ylim1})")
|
|
1309
|
+
except Exception as e:
|
|
1310
|
+
print(f"[style-import check] AFTER lines: get_ylim failed: {e}")
|
|
1195
1311
|
palette_cfg = cfg.get("curve_palettes", [])
|
|
1196
1312
|
if palette_cfg:
|
|
1197
1313
|
sanitized_history = []
|
|
@@ -1230,8 +1346,61 @@ def apply_style_config(
|
|
|
1230
1346
|
setattr(_bp_module, 'show_cif_titles', bool(cfg["show_cif_titles"]))
|
|
1231
1347
|
except Exception:
|
|
1232
1348
|
pass
|
|
1349
|
+
# Restore CIF hkl label visibility
|
|
1350
|
+
if "show_cif_hkl" in cfg:
|
|
1351
|
+
try:
|
|
1352
|
+
_bp_module = sys.modules.get('__main__')
|
|
1353
|
+
if _bp_module is not None:
|
|
1354
|
+
setattr(_bp_module, 'show_cif_hkl', bool(cfg["show_cif_hkl"]))
|
|
1355
|
+
# Also update _bp object if available
|
|
1356
|
+
if cif_tick_series is not None:
|
|
1357
|
+
# Try to update via interactive menu's _bp object
|
|
1358
|
+
try:
|
|
1359
|
+
import sys
|
|
1360
|
+
_bp_obj = getattr(sys.modules.get('__main__'), '_bp', None)
|
|
1361
|
+
if _bp_obj is not None:
|
|
1362
|
+
setattr(_bp_obj, 'show_cif_hkl', bool(cfg["show_cif_hkl"]))
|
|
1363
|
+
except Exception:
|
|
1364
|
+
pass
|
|
1365
|
+
except Exception:
|
|
1366
|
+
pass
|
|
1367
|
+
# Restore smooth settings (metadata only, not full arrays)
|
|
1368
|
+
if "smooth_settings" in cfg:
|
|
1369
|
+
try:
|
|
1370
|
+
fig._smooth_settings = dict(cfg["smooth_settings"])
|
|
1371
|
+
except Exception:
|
|
1372
|
+
pass
|
|
1373
|
+
elif hasattr(fig, '_smooth_settings'):
|
|
1374
|
+
delattr(fig, '_smooth_settings')
|
|
1375
|
+
if "last_smooth_settings" in cfg:
|
|
1376
|
+
try:
|
|
1377
|
+
fig._last_smooth_settings = dict(cfg["last_smooth_settings"])
|
|
1378
|
+
except Exception:
|
|
1379
|
+
pass
|
|
1380
|
+
elif hasattr(fig, '_last_smooth_settings'):
|
|
1381
|
+
delattr(fig, '_last_smooth_settings')
|
|
1382
|
+
# Restore derivative order (metadata only)
|
|
1383
|
+
if "derivative_order" in cfg:
|
|
1384
|
+
try:
|
|
1385
|
+
order = int(cfg["derivative_order"])
|
|
1386
|
+
fig._derivative_order = order
|
|
1387
|
+
is_reversed = cfg.get("derivative_reversed", False)
|
|
1388
|
+
if "derivative_reversed" in cfg:
|
|
1389
|
+
fig._derivative_reversed = bool(cfg["derivative_reversed"])
|
|
1390
|
+
# Update y-axis label based on derivative order
|
|
1391
|
+
from .interactive import _update_ylabel_for_derivative
|
|
1392
|
+
current_ylabel = ax.get_ylabel() or ""
|
|
1393
|
+
new_ylabel = _update_ylabel_for_derivative(order, current_ylabel, is_reversed=is_reversed)
|
|
1394
|
+
ax.set_ylabel(new_ylabel)
|
|
1395
|
+
except Exception:
|
|
1396
|
+
pass
|
|
1397
|
+
elif hasattr(fig, '_derivative_order'):
|
|
1398
|
+
delattr(fig, '_derivative_order')
|
|
1399
|
+
# Note: We don't restore original_x_data_list/original_y_data_list or pre_derivative data from style files
|
|
1400
|
+
# as style files are for styling only, and the data would be specific
|
|
1401
|
+
# to the dataset. Session files (pickle) store this data instead.
|
|
1233
1402
|
# Redraw CIF ticks after applying changes
|
|
1234
|
-
if (cif_cfg and cif_tick_series is not None) or "show_cif_titles" in cfg:
|
|
1403
|
+
if (cif_cfg and cif_tick_series is not None) or "show_cif_titles" in cfg or "show_cif_hkl" in cfg:
|
|
1235
1404
|
if hasattr(ax, "_cif_draw_func"):
|
|
1236
1405
|
try:
|
|
1237
1406
|
ax._cif_draw_func()
|
|
@@ -1338,11 +1507,19 @@ def apply_style_config(
|
|
|
1338
1507
|
if 'xlim' in geom and isinstance(geom['xlim'], list) and len(geom['xlim']) == 2:
|
|
1339
1508
|
ax.set_xlim(geom['xlim'][0], geom['xlim'][1])
|
|
1340
1509
|
if 'ylim' in geom and isinstance(geom['ylim'], list) and len(geom['ylim']) == 2:
|
|
1510
|
+
if _style_debug:
|
|
1511
|
+
print(f"[style-import check] Applying geometry ylim=({geom['ylim'][0]}, {geom['ylim'][1]})")
|
|
1341
1512
|
ax.set_ylim(geom['ylim'][0], geom['ylim'][1])
|
|
1342
1513
|
print("Applied geometry (labels and limits)")
|
|
1343
1514
|
except Exception as e:
|
|
1344
1515
|
print(f"Warning: Could not apply geometry: {e}")
|
|
1345
1516
|
|
|
1517
|
+
if _style_debug:
|
|
1518
|
+
try:
|
|
1519
|
+
ylim0, ylim1 = ax.get_ylim()
|
|
1520
|
+
print(f"[style-import check] FINAL (before draw_idle): ax ylim=({ylim0}, {ylim1})")
|
|
1521
|
+
except Exception as e:
|
|
1522
|
+
print(f"[style-import check] FINAL get_ylim failed: {e}")
|
|
1346
1523
|
try:
|
|
1347
1524
|
fig.canvas.draw_idle()
|
|
1348
1525
|
except Exception as e:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: batplot
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.6
|
|
4
4
|
Summary: Interactive plotting tool for material science (1D plot) and electrochemistry (GC, CV, dQ/dV, CPC, operando) with batch processing
|
|
5
5
|
Author-email: Tian Dai <tianda@uio.no>
|
|
6
6
|
License: MIT License
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
batplot/__init__.py,sha256=
|
|
2
|
-
batplot/args.py,sha256=
|
|
3
|
-
batplot/batch.py,sha256=
|
|
4
|
-
batplot/batplot.py,sha256=
|
|
1
|
+
batplot/__init__.py,sha256=Fy71HWPcaheFTg920KgEZ7reiHA27RQ-B6mxzpc8ZbI,118
|
|
2
|
+
batplot/args.py,sha256=DGTe2PKmJnI8Iq12QgO76V8lZvWhMOqY14gsyE5SgEs,37001
|
|
3
|
+
batplot/batch.py,sha256=hqLNvd88OLd0PLo_ot6JjC3FM6wwxCJ1jO2J63f9Zyg,55899
|
|
4
|
+
batplot/batplot.py,sha256=zD9kTLMKzYf73Ptn8jTOSeYZbxFzxlKxtrAE6bFHHNQ,187980
|
|
5
5
|
batplot/cif.py,sha256=JfHwNf3SHrcpALc_F5NjJmQ3lg71MBRSaIUJjGYPTx8,30120
|
|
6
6
|
batplot/cli.py,sha256=2-7NtxBlyOUfzHVwP7vZK7OZlyKyPVy-3daKN-MPWyU,6657
|
|
7
7
|
batplot/color_utils.py,sha256=7InQLVo1XTg7sgAbltM2KeDSFJgr787YEaV9vJbIoWY,20460
|
|
8
8
|
batplot/config.py,sha256=6nGY7fKN4T5KZUGQS2ArUBgEkLAL0j37XwG5SCVQgKA,6420
|
|
9
|
-
batplot/converters.py,sha256=
|
|
10
|
-
batplot/cpc_interactive.py,sha256=
|
|
11
|
-
batplot/electrochem_interactive.py,sha256=
|
|
12
|
-
batplot/interactive.py,sha256=
|
|
9
|
+
batplot/converters.py,sha256=c4qhgN9zHUiBZhXVAdf0zGtPPoktD3JjMLkhjjYEwlk,9787
|
|
10
|
+
batplot/cpc_interactive.py,sha256=pPx6B8IN9YYnc7TWJnTV_2ZxcotCBXD29Db7G7ool-4,247355
|
|
11
|
+
batplot/electrochem_interactive.py,sha256=Ui1_E-oTNvk7bKossx1MyULNHosFMFnl2a_EAOE550E,225991
|
|
12
|
+
batplot/interactive.py,sha256=BTcr8ZtmWdID4uKiDA7KW72p9tfaC6sNhMZvhVA6py0,311985
|
|
13
13
|
batplot/manual.py,sha256=pbRI6G4Pm12pOW8LrOLWWu7IEOtqWN3tRHtgge50LlA,11556
|
|
14
|
-
batplot/modes.py,sha256=
|
|
15
|
-
batplot/operando.py,sha256=
|
|
16
|
-
batplot/operando_ec_interactive.py,sha256=
|
|
14
|
+
batplot/modes.py,sha256=BajbnDzzYRD-FRr5Hoft0TyQ5CTWyggJjKa9yrM6iy4,37376
|
|
15
|
+
batplot/operando.py,sha256=h09xu1BsdR68YlzhWeUSypYX83DzjJABIQQS2noQzPI,29400
|
|
16
|
+
batplot/operando_ec_interactive.py,sha256=at0ZTk5jSLc2Tm5NEtXl8_neyFJayp8aSrtJEM3vIqc,326058
|
|
17
17
|
batplot/plotting.py,sha256=hG2_EdDhF1Qpn1XfZKdCQ5-w_m9gUYFbr804UQ5QjsU,10841
|
|
18
18
|
batplot/readers.py,sha256=kAI0AvYrdfGRZkvADJ4riN96IWtrH24aAoZpBtONTbw,112960
|
|
19
|
-
batplot/session.py,sha256=
|
|
20
|
-
batplot/style.py,sha256=
|
|
19
|
+
batplot/session.py,sha256=6kVDR_7Lm6vUdxt9DaeI_UBV6uNqVaFqKveegrSaXyk,147407
|
|
20
|
+
batplot/style.py,sha256=RZKoRO77lxHZhxJ8q2mjEPJoCXvv8pYu-Z2-H-_YeoA,72826
|
|
21
21
|
batplot/ui.py,sha256=ifpbK74juUzLMCt-sJGVaWtpDb1NMRJzs2YyiwwafzY,35302
|
|
22
22
|
batplot/utils.py,sha256=LY2-Axr3DsQMTxuXe48vSjrLJKEnkzkZjdSFdQizbpg,37599
|
|
23
23
|
batplot/version_check.py,sha256=--U_74DKgHbGtVdBsg9DfUJ10S5-OMXT-rzaYjK0JBc,9997
|
|
24
|
-
batplot/data/USER_MANUAL.md,sha256=
|
|
25
|
-
batplot-1.8.
|
|
24
|
+
batplot/data/USER_MANUAL.md,sha256=w6pmDXoLINFkCWWh3zay7uNIxUaDxSOrocnPIZwu2uA,19542
|
|
25
|
+
batplot-1.8.6.dist-info/licenses/LICENSE,sha256=2PAnHeCiTfgI7aKZLWr0G56HI9fGKQ0CEbQ02H-yExQ,1065
|
|
26
26
|
batplot_backup_20251121_223043/__init__.py,sha256=3s2DUQuTbWs65hoN9cQQ8IiJbaFJY8fNxiCpwRBYoOA,118
|
|
27
27
|
batplot_backup_20251121_223043/args.py,sha256=OH-h84QhN-IhMS8sPAsSEqccHD3wpeMgmXa_fqv5xtg,21215
|
|
28
28
|
batplot_backup_20251121_223043/batch.py,sha256=oI7PONJyciHDOqNPq-8fnOQMyn9CpAdVznKaEdsy0ig,48650
|
|
@@ -68,8 +68,8 @@ batplot_backup_20251221_101150/style.py,sha256=ig1ozX4dhEsXf5JKaPZOvgVS3CWx-BTFS
|
|
|
68
68
|
batplot_backup_20251221_101150/ui.py,sha256=ifpbK74juUzLMCt-sJGVaWtpDb1NMRJzs2YyiwwafzY,35302
|
|
69
69
|
batplot_backup_20251221_101150/utils.py,sha256=LY2-Axr3DsQMTxuXe48vSjrLJKEnkzkZjdSFdQizbpg,37599
|
|
70
70
|
batplot_backup_20251221_101150/version_check.py,sha256=ztTHwqgWd8OlS9PLLY5A_TabWxBASDA_-5yyN15PZC8,9996
|
|
71
|
-
batplot-1.8.
|
|
72
|
-
batplot-1.8.
|
|
73
|
-
batplot-1.8.
|
|
74
|
-
batplot-1.8.
|
|
75
|
-
batplot-1.8.
|
|
71
|
+
batplot-1.8.6.dist-info/METADATA,sha256=3vYzKlIUX7G_DynQgFBh-Weezl7GTs6u1a3vb2-Ir9w,7175
|
|
72
|
+
batplot-1.8.6.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
73
|
+
batplot-1.8.6.dist-info/entry_points.txt,sha256=73GgH3Zs-qGIvgiyQLgGsSW-ryOwPPKHveOW6TDIR5Q,82
|
|
74
|
+
batplot-1.8.6.dist-info/top_level.txt,sha256=Z5Q4sAiT_FDqZqhlLsYn9avRTuFAEEf3AVfkswxOb18,70
|
|
75
|
+
batplot-1.8.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|