batplot 1.8.3__py3-none-any.whl → 1.8.5__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 +22 -4
- batplot/batch.py +12 -0
- batplot/batplot.py +234 -91
- batplot/cli.py +14 -0
- batplot/converters.py +170 -122
- batplot/cpc_interactive.py +33 -21
- batplot/data/USER_MANUAL.md +49 -0
- batplot/electrochem_interactive.py +63 -36
- batplot/interactive.py +1547 -73
- batplot/operando.py +22 -0
- batplot/operando_ec_interactive.py +232 -2
- batplot/session.py +128 -148
- batplot/style.py +89 -2
- {batplot-1.8.3.dist-info → batplot-1.8.5.dist-info}/METADATA +4 -9
- {batplot-1.8.3.dist-info → batplot-1.8.5.dist-info}/RECORD +20 -20
- {batplot-1.8.3.dist-info → batplot-1.8.5.dist-info}/WHEEL +1 -1
- {batplot-1.8.3.dist-info → batplot-1.8.5.dist-info}/licenses/LICENSE +0 -0
- {batplot-1.8.3.dist-info → batplot-1.8.5.dist-info}/entry_points.txt +0 -0
- {batplot-1.8.3.dist-info → batplot-1.8.5.dist-info}/top_level.txt +0 -0
batplot/session.py
CHANGED
|
@@ -36,114 +36,71 @@ import os
|
|
|
36
36
|
|
|
37
37
|
import matplotlib.pyplot as plt
|
|
38
38
|
import numpy as np
|
|
39
|
-
import sys
|
|
40
39
|
|
|
41
40
|
from .utils import _confirm_overwrite
|
|
42
41
|
from .color_utils import ensure_colormap
|
|
43
42
|
|
|
44
43
|
|
|
45
|
-
def
|
|
46
|
-
"""
|
|
44
|
+
def _try_extract_version_from_pickle(filename: str) -> Dict[str, str]:
|
|
45
|
+
"""Try to extract package_versions from a pickle file even if it fails to fully load.
|
|
46
|
+
|
|
47
|
+
Note: This may not work if pickle.load() fails completely due to missing modules.
|
|
48
|
+
In that case, we can't extract version info, but we can still show current version.
|
|
47
49
|
|
|
48
50
|
Returns:
|
|
49
|
-
dict
|
|
51
|
+
dict with package versions, or empty dict if extraction fails
|
|
50
52
|
"""
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
# Also track Python version
|
|
64
|
-
versions['python'] = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
|
|
65
|
-
|
|
66
|
-
return versions
|
|
53
|
+
try:
|
|
54
|
+
with open(filename, 'rb') as f:
|
|
55
|
+
# Try to load the pickle
|
|
56
|
+
# This will fail if numpy._core is missing, but we try anyway
|
|
57
|
+
sess = pickle.load(f)
|
|
58
|
+
if isinstance(sess, dict):
|
|
59
|
+
return sess.get('package_versions', {})
|
|
60
|
+
except Exception:
|
|
61
|
+
# If loading fails completely (e.g., ModuleNotFoundError for numpy._core),
|
|
62
|
+
# we can't extract version info. This is expected in version mismatch cases.
|
|
63
|
+
pass
|
|
64
|
+
return {}
|
|
67
65
|
|
|
68
66
|
|
|
69
|
-
def
|
|
70
|
-
"""
|
|
67
|
+
def _get_current_numpy_version() -> str:
|
|
68
|
+
"""Get current numpy version, even if import fails.
|
|
69
|
+
|
|
70
|
+
Tries multiple methods:
|
|
71
|
+
1. Direct import (fastest)
|
|
72
|
+
2. pip show (works even if import fails)
|
|
73
|
+
3. Returns 'unknown' if all fail
|
|
71
74
|
|
|
72
|
-
Args:
|
|
73
|
-
saved_versions: dict of package -> version from saved session
|
|
74
|
-
current_versions: dict of package -> version currently installed
|
|
75
|
-
filename: session filename for error messages
|
|
76
|
-
|
|
77
75
|
Returns:
|
|
78
|
-
|
|
76
|
+
Version string or 'unknown'
|
|
79
77
|
"""
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
mismatches = []
|
|
87
|
-
critical_mismatches = []
|
|
88
|
-
|
|
89
|
-
for pkg in ['numpy', 'matplotlib', 'python']:
|
|
90
|
-
saved_ver = saved_versions.get(pkg, 'unknown')
|
|
91
|
-
current_ver = current_versions.get(pkg, 'unknown')
|
|
92
|
-
|
|
93
|
-
if saved_ver == 'unknown' or current_ver == 'unknown':
|
|
94
|
-
continue
|
|
95
|
-
|
|
96
|
-
if saved_ver != current_ver:
|
|
97
|
-
# Check for critical incompatibilities
|
|
98
|
-
if pkg == 'numpy':
|
|
99
|
-
# numpy 2.0+ uses _core, <2.0 doesn't - this is a breaking change
|
|
100
|
-
try:
|
|
101
|
-
saved_major = int(saved_ver.split('.')[0])
|
|
102
|
-
current_major = int(current_ver.split('.')[0])
|
|
103
|
-
if saved_major != current_major:
|
|
104
|
-
critical_mismatches.append((pkg, saved_ver, current_ver))
|
|
105
|
-
else:
|
|
106
|
-
mismatches.append((pkg, saved_ver, current_ver))
|
|
107
|
-
except (ValueError, IndexError):
|
|
108
|
-
mismatches.append((pkg, saved_ver, current_ver))
|
|
109
|
-
elif pkg == 'python':
|
|
110
|
-
# Python major version changes are critical
|
|
111
|
-
try:
|
|
112
|
-
saved_major = int(saved_ver.split('.')[0])
|
|
113
|
-
current_major = int(current_ver.split('.')[0])
|
|
114
|
-
if saved_major != current_major:
|
|
115
|
-
critical_mismatches.append((pkg, saved_ver, current_ver))
|
|
116
|
-
else:
|
|
117
|
-
mismatches.append((pkg, saved_ver, current_ver))
|
|
118
|
-
except (ValueError, IndexError):
|
|
119
|
-
mismatches.append((pkg, saved_ver, current_ver))
|
|
120
|
-
else:
|
|
121
|
-
mismatches.append((pkg, saved_ver, current_ver))
|
|
122
|
-
|
|
123
|
-
if critical_mismatches:
|
|
124
|
-
print(f"\nERROR: Critical package version mismatch detected for session: {filename}")
|
|
125
|
-
print("The following packages have incompatible major version changes:")
|
|
126
|
-
for pkg, saved, current in critical_mismatches:
|
|
127
|
-
print(f" {pkg}: saved with {saved}, current is {current}")
|
|
128
|
-
print("\nThis will likely cause pickle loading to fail.")
|
|
129
|
-
print("Solutions:")
|
|
130
|
-
print(" 1. Install matching package versions:")
|
|
131
|
-
for pkg, saved, current in critical_mismatches:
|
|
132
|
-
print(f" pip install '{pkg}=={saved}' # or use conda")
|
|
133
|
-
print(" 2. Recreate the session from original data files")
|
|
134
|
-
return False
|
|
78
|
+
# Method 1: Try direct import
|
|
79
|
+
try:
|
|
80
|
+
import numpy
|
|
81
|
+
return numpy.__version__
|
|
82
|
+
except Exception:
|
|
83
|
+
pass
|
|
135
84
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
85
|
+
# Method 2: Try pip show
|
|
86
|
+
try:
|
|
87
|
+
import subprocess
|
|
88
|
+
import sys
|
|
89
|
+
result = subprocess.run(
|
|
90
|
+
[sys.executable, '-m', 'pip', 'show', 'numpy'],
|
|
91
|
+
capture_output=True,
|
|
92
|
+
text=True,
|
|
93
|
+
timeout=5,
|
|
94
|
+
check=False
|
|
95
|
+
)
|
|
96
|
+
if result.returncode == 0:
|
|
97
|
+
for line in result.stdout.split('\n'):
|
|
98
|
+
if line.startswith('Version:'):
|
|
99
|
+
return line.split(':', 1)[1].strip()
|
|
100
|
+
except Exception:
|
|
101
|
+
pass
|
|
145
102
|
|
|
146
|
-
return
|
|
103
|
+
return 'unknown'
|
|
147
104
|
|
|
148
105
|
|
|
149
106
|
def _current_tick_width(axis_obj, which: str):
|
|
@@ -536,17 +493,37 @@ def dump_session(
|
|
|
536
493
|
wasd_state = _capture_wasd_state(ax)
|
|
537
494
|
|
|
538
495
|
try:
|
|
539
|
-
# Get current package versions for compatibility checking
|
|
540
|
-
package_versions = _get_package_versions()
|
|
541
|
-
|
|
542
496
|
sess = {
|
|
543
497
|
'version': 3,
|
|
544
|
-
'package_versions': package_versions, # Track versions for compatibility checking
|
|
545
498
|
'x_data': [np.array(a) for a in x_data_list],
|
|
546
499
|
'y_data': [np.array(a) for a in y_data_list],
|
|
547
500
|
'orig_y': [np.array(a) for a in orig_y],
|
|
548
501
|
'offsets': list(offsets_list),
|
|
549
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),
|
|
550
527
|
'line_styles': [
|
|
551
528
|
{
|
|
552
529
|
'color': ln.get_color(),
|
|
@@ -863,13 +840,9 @@ def dump_operando_session(
|
|
|
863
840
|
cb_h_offset = getattr(cbar.ax, '_cb_h_offset_in', 0.0)
|
|
864
841
|
ec_h_offset = getattr(ec_ax, '_ec_h_offset_in', 0.0) if ec_ax is not None else None
|
|
865
842
|
|
|
866
|
-
# Get current package versions for compatibility checking
|
|
867
|
-
package_versions = _get_package_versions()
|
|
868
|
-
|
|
869
843
|
sess = {
|
|
870
844
|
'kind': 'operando_ec',
|
|
871
845
|
'version': 2,
|
|
872
|
-
'package_versions': package_versions, # Track versions for compatibility checking
|
|
873
846
|
'figure': {'size': (fig_w, fig_h), 'dpi': dpi},
|
|
874
847
|
'layout_inches': {
|
|
875
848
|
'cb_w_in': cb_w_in,
|
|
@@ -937,22 +910,33 @@ def load_operando_session(filename: str):
|
|
|
937
910
|
except ModuleNotFoundError as e:
|
|
938
911
|
# Handle numpy._core and other module import errors
|
|
939
912
|
if '_core' in str(e) or 'numpy' in str(e).lower():
|
|
913
|
+
# Try to extract version info before the error
|
|
914
|
+
saved_versions = _try_extract_version_from_pickle(filename)
|
|
915
|
+
current_numpy = _get_current_numpy_version()
|
|
916
|
+
|
|
917
|
+
saved_numpy = saved_versions.get('numpy', 'unknown')
|
|
918
|
+
|
|
940
919
|
print(f"\nERROR: NumPy version mismatch detected when loading: {filename}")
|
|
941
920
|
print("This session was saved with a different NumPy version.")
|
|
921
|
+
print()
|
|
922
|
+
print(f"Session was saved with: NumPy {saved_numpy}")
|
|
923
|
+
print(f"Currently installed: NumPy {current_numpy}")
|
|
924
|
+
print()
|
|
942
925
|
print("The error 'No module named numpy._core' indicates:")
|
|
943
926
|
print(" - Session saved with NumPy 2.0+ but loading with NumPy <2.0, OR")
|
|
944
927
|
print(" - Session saved with NumPy <2.0 but loading with NumPy 2.0+")
|
|
945
|
-
print(
|
|
946
|
-
print("
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
928
|
+
print()
|
|
929
|
+
print("Solutions:")
|
|
930
|
+
if saved_numpy != 'unknown':
|
|
931
|
+
print(f" 1. Install matching version: pip install 'numpy=={saved_numpy}'")
|
|
932
|
+
else:
|
|
933
|
+
print(" 1. Try installing NumPy <2.0: pip install 'numpy<2.0'")
|
|
934
|
+
print(" OR try installing NumPy 2.0+: pip install 'numpy>=2.0'")
|
|
935
|
+
print(" 2. Recreate the session from original data files")
|
|
951
936
|
else:
|
|
952
937
|
print(f"\nERROR: Module import error when loading: {filename}")
|
|
953
938
|
print(f"Error: {e}")
|
|
954
939
|
print("This usually indicates a package version mismatch.")
|
|
955
|
-
print("Try installing matching package versions or recreate the session.")
|
|
956
940
|
return None
|
|
957
941
|
except Exception as e:
|
|
958
942
|
print(f"Failed to load session: {e}")
|
|
@@ -961,12 +945,6 @@ def load_operando_session(filename: str):
|
|
|
961
945
|
if not isinstance(sess, dict) or sess.get('kind') != 'operando_ec':
|
|
962
946
|
print("Not an operando+EC session file.")
|
|
963
947
|
return None
|
|
964
|
-
|
|
965
|
-
# Check package version compatibility
|
|
966
|
-
saved_versions = sess.get('package_versions', {})
|
|
967
|
-
current_versions = _get_package_versions()
|
|
968
|
-
if not _check_package_compatibility(saved_versions, current_versions, filename):
|
|
969
|
-
return None
|
|
970
948
|
|
|
971
949
|
# Use standard DPI of 100 instead of saved DPI to avoid display-dependent issues
|
|
972
950
|
# (Retina displays, Windows scaling, etc. can cause saved DPI to differ)
|
|
@@ -1746,13 +1724,9 @@ def dump_ec_session(
|
|
|
1746
1724
|
legend_xy_in = (float(xy[0]), float(xy[1]))
|
|
1747
1725
|
except Exception:
|
|
1748
1726
|
legend_xy_in = None
|
|
1749
|
-
# Get current package versions for compatibility checking
|
|
1750
|
-
package_versions = _get_package_versions()
|
|
1751
|
-
|
|
1752
1727
|
sess = {
|
|
1753
1728
|
'kind': 'ec_gc',
|
|
1754
1729
|
'version': 2,
|
|
1755
|
-
'package_versions': package_versions, # Track versions for compatibility checking
|
|
1756
1730
|
'figure': {'size': (fig_w, fig_h), 'dpi': dpi},
|
|
1757
1731
|
'axis': axis,
|
|
1758
1732
|
'subplot_margins': subplot_margins,
|
|
@@ -1805,22 +1779,33 @@ def load_ec_session(filename: str):
|
|
|
1805
1779
|
except ModuleNotFoundError as e:
|
|
1806
1780
|
# Handle numpy._core and other module import errors
|
|
1807
1781
|
if '_core' in str(e) or 'numpy' in str(e).lower():
|
|
1782
|
+
# Try to extract version info before the error
|
|
1783
|
+
saved_versions = _try_extract_version_from_pickle(filename)
|
|
1784
|
+
current_numpy = _get_current_numpy_version()
|
|
1785
|
+
|
|
1786
|
+
saved_numpy = saved_versions.get('numpy', 'unknown')
|
|
1787
|
+
|
|
1808
1788
|
print(f"\nERROR: NumPy version mismatch detected when loading: {filename}")
|
|
1809
1789
|
print("This session was saved with a different NumPy version.")
|
|
1790
|
+
print()
|
|
1791
|
+
print(f"Session was saved with: NumPy {saved_numpy}")
|
|
1792
|
+
print(f"Currently installed: NumPy {current_numpy}")
|
|
1793
|
+
print()
|
|
1810
1794
|
print("The error 'No module named numpy._core' indicates:")
|
|
1811
1795
|
print(" - Session saved with NumPy 2.0+ but loading with NumPy <2.0, OR")
|
|
1812
1796
|
print(" - Session saved with NumPy <2.0 but loading with NumPy 2.0+")
|
|
1813
|
-
print(
|
|
1814
|
-
print("
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1797
|
+
print()
|
|
1798
|
+
print("Solutions:")
|
|
1799
|
+
if saved_numpy != 'unknown':
|
|
1800
|
+
print(f" 1. Install matching version: pip install 'numpy=={saved_numpy}'")
|
|
1801
|
+
else:
|
|
1802
|
+
print(" 1. Try installing NumPy <2.0: pip install 'numpy<2.0'")
|
|
1803
|
+
print(" OR try installing NumPy 2.0+: pip install 'numpy>=2.0'")
|
|
1804
|
+
print(" 2. Recreate the session from original data files")
|
|
1819
1805
|
else:
|
|
1820
1806
|
print(f"\nERROR: Module import error when loading: {filename}")
|
|
1821
1807
|
print(f"Error: {e}")
|
|
1822
1808
|
print("This usually indicates a package version mismatch.")
|
|
1823
|
-
print("Try installing matching package versions or recreate the session.")
|
|
1824
1809
|
return None
|
|
1825
1810
|
except Exception as e:
|
|
1826
1811
|
print(f"Failed to load EC session: {e}")
|
|
@@ -1829,12 +1814,6 @@ def load_ec_session(filename: str):
|
|
|
1829
1814
|
if not isinstance(sess, dict) or sess.get('kind') != 'ec_gc':
|
|
1830
1815
|
print("Not an EC GC session file.")
|
|
1831
1816
|
return None
|
|
1832
|
-
|
|
1833
|
-
# Check package version compatibility
|
|
1834
|
-
saved_versions = sess.get('package_versions', {})
|
|
1835
|
-
current_versions = _get_package_versions()
|
|
1836
|
-
if not _check_package_compatibility(saved_versions, current_versions, filename):
|
|
1837
|
-
return None
|
|
1838
1817
|
|
|
1839
1818
|
# Use standard DPI of 100 instead of saved DPI to avoid display-dependent issues
|
|
1840
1819
|
# (Retina displays, Windows scaling, etc. can cause saved DPI to differ)
|
|
@@ -2539,13 +2518,9 @@ def dump_cpc_session(
|
|
|
2539
2518
|
'right_y': float(getattr(ax2, '_right_ylabel_manual_offset_y_pts', 0.0) or 0.0),
|
|
2540
2519
|
}
|
|
2541
2520
|
|
|
2542
|
-
# Get current package versions for compatibility checking
|
|
2543
|
-
package_versions = _get_package_versions()
|
|
2544
|
-
|
|
2545
2521
|
meta = {
|
|
2546
2522
|
'kind': 'cpc',
|
|
2547
2523
|
'version': 2, # Incremented version for new format
|
|
2548
|
-
'package_versions': package_versions, # Track versions for compatibility checking
|
|
2549
2524
|
'figure': {
|
|
2550
2525
|
'size': (fig_w, fig_h),
|
|
2551
2526
|
'dpi': dpi,
|
|
@@ -2704,22 +2679,33 @@ def load_cpc_session(filename: str):
|
|
|
2704
2679
|
except ModuleNotFoundError as e:
|
|
2705
2680
|
# Handle numpy._core and other module import errors
|
|
2706
2681
|
if '_core' in str(e) or 'numpy' in str(e).lower():
|
|
2682
|
+
# Try to extract version info before the error
|
|
2683
|
+
saved_versions = _try_extract_version_from_pickle(filename)
|
|
2684
|
+
current_numpy = _get_current_numpy_version()
|
|
2685
|
+
|
|
2686
|
+
saved_numpy = saved_versions.get('numpy', 'unknown')
|
|
2687
|
+
|
|
2707
2688
|
print(f"\nERROR: NumPy version mismatch detected when loading: {filename}")
|
|
2708
2689
|
print("This session was saved with a different NumPy version.")
|
|
2690
|
+
print()
|
|
2691
|
+
print(f"Session was saved with: NumPy {saved_numpy}")
|
|
2692
|
+
print(f"Currently installed: NumPy {current_numpy}")
|
|
2693
|
+
print()
|
|
2709
2694
|
print("The error 'No module named numpy._core' indicates:")
|
|
2710
2695
|
print(" - Session saved with NumPy 2.0+ but loading with NumPy <2.0, OR")
|
|
2711
2696
|
print(" - Session saved with NumPy <2.0 but loading with NumPy 2.0+")
|
|
2712
|
-
print(
|
|
2713
|
-
print("
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2697
|
+
print()
|
|
2698
|
+
print("Solutions:")
|
|
2699
|
+
if saved_numpy != 'unknown':
|
|
2700
|
+
print(f" 1. Install matching version: pip install 'numpy=={saved_numpy}'")
|
|
2701
|
+
else:
|
|
2702
|
+
print(" 1. Try installing NumPy <2.0: pip install 'numpy<2.0'")
|
|
2703
|
+
print(" OR try installing NumPy 2.0+: pip install 'numpy>=2.0'")
|
|
2704
|
+
print(" 2. Recreate the session from original data files")
|
|
2718
2705
|
else:
|
|
2719
2706
|
print(f"\nERROR: Module import error when loading: {filename}")
|
|
2720
2707
|
print(f"Error: {e}")
|
|
2721
2708
|
print("This usually indicates a package version mismatch.")
|
|
2722
|
-
print("Try installing matching package versions or recreate the session.")
|
|
2723
2709
|
return None
|
|
2724
2710
|
except Exception as e:
|
|
2725
2711
|
print(f"Failed to load session: {e}")
|
|
@@ -2727,12 +2713,6 @@ def load_cpc_session(filename: str):
|
|
|
2727
2713
|
if not isinstance(sess, dict) or sess.get('kind') != 'cpc':
|
|
2728
2714
|
print("Not a CPC session file.")
|
|
2729
2715
|
return None
|
|
2730
|
-
|
|
2731
|
-
# Check package version compatibility
|
|
2732
|
-
saved_versions = sess.get('package_versions', {})
|
|
2733
|
-
current_versions = _get_package_versions()
|
|
2734
|
-
if not _check_package_compatibility(saved_versions, current_versions, filename):
|
|
2735
|
-
return None
|
|
2736
2716
|
try:
|
|
2737
2717
|
# Use standard DPI of 100 instead of saved DPI to avoid display-dependent issues
|
|
2738
2718
|
# (Retina displays, Windows scaling, etc. can cause saved DPI to differ)
|
batplot/style.py
CHANGED
|
@@ -451,7 +451,19 @@ def print_style_info(
|
|
|
451
451
|
except Exception:
|
|
452
452
|
pass
|
|
453
453
|
|
|
454
|
-
#
|
|
454
|
+
# CIF hkl label visibility
|
|
455
|
+
if show_cif_hkl is not None:
|
|
456
|
+
print(f"CIF hkl labels: {'shown' if show_cif_hkl else 'hidden'}")
|
|
457
|
+
elif cif_tick_series:
|
|
458
|
+
# Try to read from __main__ module if not provided
|
|
459
|
+
try:
|
|
460
|
+
import sys
|
|
461
|
+
_bp_module = sys.modules.get('__main__')
|
|
462
|
+
if _bp_module is not None and hasattr(_bp_module, 'show_cif_hkl'):
|
|
463
|
+
hkl_state = bool(getattr(_bp_module, 'show_cif_hkl', False))
|
|
464
|
+
print(f"CIF hkl labels: {'shown' if hkl_state else 'hidden'}")
|
|
465
|
+
except Exception:
|
|
466
|
+
pass
|
|
455
467
|
|
|
456
468
|
# Omit non-style global flags (mode/raw/autoscale/delta)
|
|
457
469
|
|
|
@@ -670,6 +682,14 @@ def export_style_config(
|
|
|
670
682
|
# Save CIF title visibility
|
|
671
683
|
if show_cif_titles is not None:
|
|
672
684
|
cfg["show_cif_titles"] = bool(show_cif_titles)
|
|
685
|
+
# Save CIF hkl label visibility (read from __main__ module if available)
|
|
686
|
+
try:
|
|
687
|
+
import sys
|
|
688
|
+
_bp_module = sys.modules.get('__main__')
|
|
689
|
+
if _bp_module is not None and hasattr(_bp_module, 'show_cif_hkl'):
|
|
690
|
+
cfg["show_cif_hkl"] = bool(getattr(_bp_module, 'show_cif_hkl', False))
|
|
691
|
+
except Exception:
|
|
692
|
+
pass
|
|
673
693
|
if cif_tick_series:
|
|
674
694
|
cfg["cif_ticks"] = [
|
|
675
695
|
{"index": i, "color": color}
|
|
@@ -692,6 +712,20 @@ def export_style_config(
|
|
|
692
712
|
if serialized_palettes:
|
|
693
713
|
cfg['curve_palettes'] = serialized_palettes
|
|
694
714
|
|
|
715
|
+
# Store smooth settings (metadata only, not full arrays)
|
|
716
|
+
if hasattr(fig, '_smooth_settings'):
|
|
717
|
+
cfg['smooth_settings'] = dict(fig._smooth_settings)
|
|
718
|
+
if hasattr(fig, '_last_smooth_settings'):
|
|
719
|
+
cfg['last_smooth_settings'] = dict(fig._last_smooth_settings)
|
|
720
|
+
# Store derivative order (metadata only)
|
|
721
|
+
if hasattr(fig, '_derivative_order'):
|
|
722
|
+
cfg['derivative_order'] = int(fig._derivative_order)
|
|
723
|
+
if hasattr(fig, '_derivative_reversed'):
|
|
724
|
+
cfg['derivative_reversed'] = bool(fig._derivative_reversed)
|
|
725
|
+
# Note: We don't store original_x_data_list/original_y_data_list or pre_derivative data in style files
|
|
726
|
+
# as style files are for styling only, and the data would be specific
|
|
727
|
+
# to the dataset. Session files (pickle) store this data instead.
|
|
728
|
+
|
|
695
729
|
# If overwrite_path is provided, determine export type from existing file
|
|
696
730
|
if overwrite_path:
|
|
697
731
|
try:
|
|
@@ -1230,8 +1264,61 @@ def apply_style_config(
|
|
|
1230
1264
|
setattr(_bp_module, 'show_cif_titles', bool(cfg["show_cif_titles"]))
|
|
1231
1265
|
except Exception:
|
|
1232
1266
|
pass
|
|
1267
|
+
# Restore CIF hkl label visibility
|
|
1268
|
+
if "show_cif_hkl" in cfg:
|
|
1269
|
+
try:
|
|
1270
|
+
_bp_module = sys.modules.get('__main__')
|
|
1271
|
+
if _bp_module is not None:
|
|
1272
|
+
setattr(_bp_module, 'show_cif_hkl', bool(cfg["show_cif_hkl"]))
|
|
1273
|
+
# Also update _bp object if available
|
|
1274
|
+
if cif_tick_series is not None:
|
|
1275
|
+
# Try to update via interactive menu's _bp object
|
|
1276
|
+
try:
|
|
1277
|
+
import sys
|
|
1278
|
+
_bp_obj = getattr(sys.modules.get('__main__'), '_bp', None)
|
|
1279
|
+
if _bp_obj is not None:
|
|
1280
|
+
setattr(_bp_obj, 'show_cif_hkl', bool(cfg["show_cif_hkl"]))
|
|
1281
|
+
except Exception:
|
|
1282
|
+
pass
|
|
1283
|
+
except Exception:
|
|
1284
|
+
pass
|
|
1285
|
+
# Restore smooth settings (metadata only, not full arrays)
|
|
1286
|
+
if "smooth_settings" in cfg:
|
|
1287
|
+
try:
|
|
1288
|
+
fig._smooth_settings = dict(cfg["smooth_settings"])
|
|
1289
|
+
except Exception:
|
|
1290
|
+
pass
|
|
1291
|
+
elif hasattr(fig, '_smooth_settings'):
|
|
1292
|
+
delattr(fig, '_smooth_settings')
|
|
1293
|
+
if "last_smooth_settings" in cfg:
|
|
1294
|
+
try:
|
|
1295
|
+
fig._last_smooth_settings = dict(cfg["last_smooth_settings"])
|
|
1296
|
+
except Exception:
|
|
1297
|
+
pass
|
|
1298
|
+
elif hasattr(fig, '_last_smooth_settings'):
|
|
1299
|
+
delattr(fig, '_last_smooth_settings')
|
|
1300
|
+
# Restore derivative order (metadata only)
|
|
1301
|
+
if "derivative_order" in cfg:
|
|
1302
|
+
try:
|
|
1303
|
+
order = int(cfg["derivative_order"])
|
|
1304
|
+
fig._derivative_order = order
|
|
1305
|
+
is_reversed = cfg.get("derivative_reversed", False)
|
|
1306
|
+
if "derivative_reversed" in cfg:
|
|
1307
|
+
fig._derivative_reversed = bool(cfg["derivative_reversed"])
|
|
1308
|
+
# Update y-axis label based on derivative order
|
|
1309
|
+
from .interactive import _update_ylabel_for_derivative
|
|
1310
|
+
current_ylabel = ax.get_ylabel() or ""
|
|
1311
|
+
new_ylabel = _update_ylabel_for_derivative(order, current_ylabel, is_reversed=is_reversed)
|
|
1312
|
+
ax.set_ylabel(new_ylabel)
|
|
1313
|
+
except Exception:
|
|
1314
|
+
pass
|
|
1315
|
+
elif hasattr(fig, '_derivative_order'):
|
|
1316
|
+
delattr(fig, '_derivative_order')
|
|
1317
|
+
# Note: We don't restore original_x_data_list/original_y_data_list or pre_derivative data from style files
|
|
1318
|
+
# as style files are for styling only, and the data would be specific
|
|
1319
|
+
# to the dataset. Session files (pickle) store this data instead.
|
|
1233
1320
|
# Redraw CIF ticks after applying changes
|
|
1234
|
-
if (cif_cfg and cif_tick_series is not None) or "show_cif_titles" in cfg:
|
|
1321
|
+
if (cif_cfg and cif_tick_series is not None) or "show_cif_titles" in cfg or "show_cif_hkl" in cfg:
|
|
1235
1322
|
if hasattr(ax, "_cif_draw_func"):
|
|
1236
1323
|
try:
|
|
1237
1324
|
ax._cif_draw_func()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: batplot
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.5
|
|
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
|
|
@@ -31,20 +31,15 @@ Project-URL: Issues, https://github.com/TianDai1729/batplot/issues
|
|
|
31
31
|
Classifier: Programming Language :: Python
|
|
32
32
|
Classifier: Programming Language :: Python :: 3
|
|
33
33
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
34
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
35
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
36
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
37
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
38
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
39
34
|
Classifier: Programming Language :: Python :: 3.13
|
|
40
35
|
Classifier: Operating System :: OS Independent
|
|
41
36
|
Classifier: Intended Audience :: Science/Research
|
|
42
37
|
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
43
|
-
Requires-Python:
|
|
38
|
+
Requires-Python: <3.14,>=3.13
|
|
44
39
|
Description-Content-Type: text/markdown
|
|
45
40
|
License-File: LICENSE
|
|
46
|
-
Requires-Dist: numpy
|
|
47
|
-
Requires-Dist: matplotlib
|
|
41
|
+
Requires-Dist: numpy==2.3.4
|
|
42
|
+
Requires-Dist: matplotlib==3.10.7
|
|
48
43
|
Requires-Dist: rich>=10.0.0
|
|
49
44
|
Requires-Dist: openpyxl>=3.0.0
|
|
50
45
|
Dynamic: license-file
|
|
@@ -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=6mfbpfSzbSfjCLrvmBzBMKmDyiFSBUJlcB8Qqv6o26s,118
|
|
2
|
+
batplot/args.py,sha256=DGTe2PKmJnI8Iq12QgO76V8lZvWhMOqY14gsyE5SgEs,37001
|
|
3
|
+
batplot/batch.py,sha256=hqLNvd88OLd0PLo_ot6JjC3FM6wwxCJ1jO2J63f9Zyg,55899
|
|
4
|
+
batplot/batplot.py,sha256=-mAf1aW7bniyfQ5DCorqyOr-OcRtUgRtq6TZHKk5xCU,184599
|
|
5
5
|
batplot/cif.py,sha256=JfHwNf3SHrcpALc_F5NjJmQ3lg71MBRSaIUJjGYPTx8,30120
|
|
6
|
-
batplot/cli.py,sha256=
|
|
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=-9etN342VqLbY9pLP7cyBcSzgVHuWpDwEZHkXzShl7E,240683
|
|
11
|
+
batplot/electrochem_interactive.py,sha256=a3ocYQEfi0FsiMq9B4_0GY97td00e8uyzlHc3Sr6EKE,225211
|
|
12
|
+
batplot/interactive.py,sha256=b-0xeza_Rs4S59ve-pyWVq_-FvTpqDIy1tu4M3tT3Eg,300447
|
|
13
13
|
batplot/manual.py,sha256=pbRI6G4Pm12pOW8LrOLWWu7IEOtqWN3tRHtgge50LlA,11556
|
|
14
14
|
batplot/modes.py,sha256=qE2OsOQQKhwOWene5zxJeuuewTrZxubtahQuz5je7ok,37252
|
|
15
|
-
batplot/operando.py,sha256=
|
|
16
|
-
batplot/operando_ec_interactive.py,sha256=
|
|
15
|
+
batplot/operando.py,sha256=h09xu1BsdR68YlzhWeUSypYX83DzjJABIQQS2noQzPI,29400
|
|
16
|
+
batplot/operando_ec_interactive.py,sha256=YExiuKn-qQksW3YFYCTpvumuCit4cc4YiiaSRWGa0og,317833
|
|
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=sgcJyCj00lOhmIRdDxGSqu2vEpOm7WSFZzLXxukYNL0,144936
|
|
20
|
+
batplot/style.py,sha256=3XnWlU9aTb1b-aiq5BQOuAREE5nOEYZ0b75v_LS0xDM,67790
|
|
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.5.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.5.dist-info/METADATA,sha256=WTflN9nVzAXg4xPnjpjfJeRNhuyUaXaJKBLyjhjVxko,7175
|
|
72
|
+
batplot-1.8.5.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
73
|
+
batplot-1.8.5.dist-info/entry_points.txt,sha256=73GgH3Zs-qGIvgiyQLgGsSW-ryOwPPKHveOW6TDIR5Q,82
|
|
74
|
+
batplot-1.8.5.dist-info/top_level.txt,sha256=Z5Q4sAiT_FDqZqhlLsYn9avRTuFAEEf3AVfkswxOb18,70
|
|
75
|
+
batplot-1.8.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|