batplot 1.8.2__py3-none-any.whl → 1.8.3__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/batch.py +23 -0
- batplot/batplot.py +57 -8
- batplot/cpc_interactive.py +15 -3
- batplot/electrochem_interactive.py +20 -4
- batplot/interactive.py +9 -15
- batplot/session.py +201 -0
- batplot/style.py +21 -2
- {batplot-1.8.2.dist-info → batplot-1.8.3.dist-info}/METADATA +1 -1
- {batplot-1.8.2.dist-info → batplot-1.8.3.dist-info}/RECORD +14 -14
- {batplot-1.8.2.dist-info → batplot-1.8.3.dist-info}/WHEEL +0 -0
- {batplot-1.8.2.dist-info → batplot-1.8.3.dist-info}/entry_points.txt +0 -0
- {batplot-1.8.2.dist-info → batplot-1.8.3.dist-info}/licenses/LICENSE +0 -0
- {batplot-1.8.2.dist-info → batplot-1.8.3.dist-info}/top_level.txt +0 -0
batplot/__init__.py
CHANGED
batplot/batch.py
CHANGED
|
@@ -157,6 +157,18 @@ def _apply_xy_style(fig, ax, cfg: dict):
|
|
|
157
157
|
except Exception:
|
|
158
158
|
pass
|
|
159
159
|
|
|
160
|
+
# Enforce compatibility between style/geom ro state and current figure ro state.
|
|
161
|
+
# Styles saved from a plot using --ro (swapped x/y) must not be applied to a non-ro plot, and vice versa.
|
|
162
|
+
file_ro = bool(cfg.get('ro_active', False))
|
|
163
|
+
current_ro = bool(getattr(fig, '_ro_active', False))
|
|
164
|
+
if file_ro != current_ro:
|
|
165
|
+
if file_ro:
|
|
166
|
+
print("Warning: XY style/geometry file was saved with --ro (swapped x/y axes); batch plot is not using --ro.")
|
|
167
|
+
else:
|
|
168
|
+
print("Warning: XY style/geometry file was saved without --ro; batch plot is treated as non-ro.")
|
|
169
|
+
print("Skipping style/geometry in batch mode to avoid corrupting axis orientation.")
|
|
170
|
+
return
|
|
171
|
+
|
|
160
172
|
# Apply WASD state (tick visibility)
|
|
161
173
|
wasd_cfg = cfg.get('wasd_state', {})
|
|
162
174
|
if wasd_cfg:
|
|
@@ -223,6 +235,17 @@ def _apply_ec_style(fig, ax, cfg: dict):
|
|
|
223
235
|
cfg: Style configuration dictionary
|
|
224
236
|
"""
|
|
225
237
|
try:
|
|
238
|
+
# Enforce compatibility between style/geom ro state and current figure ro state.
|
|
239
|
+
file_ro = bool(cfg.get('ro_active', False))
|
|
240
|
+
current_ro = bool(getattr(fig, '_ro_active', False))
|
|
241
|
+
if file_ro != current_ro:
|
|
242
|
+
if file_ro:
|
|
243
|
+
print("Warning: EC style/geometry file was saved with --ro (swapped x/y axes); batch EC plot is not using --ro.")
|
|
244
|
+
else:
|
|
245
|
+
print("Warning: EC style/geometry file was saved without --ro; batch EC plot is treated as non-ro.")
|
|
246
|
+
print("Skipping EC style/geometry in batch mode to avoid corrupting axis orientation.")
|
|
247
|
+
return
|
|
248
|
+
|
|
226
249
|
# Apply fonts
|
|
227
250
|
font_cfg = cfg.get('font', {})
|
|
228
251
|
if font_cfg:
|
batplot/batplot.py
CHANGED
|
@@ -507,6 +507,11 @@ def batplot_main() -> int:
|
|
|
507
507
|
except Exception:
|
|
508
508
|
pass
|
|
509
509
|
_plt.show(block=False)
|
|
510
|
+
# Track whether data axes were swapped via --ro for this EC figure
|
|
511
|
+
try:
|
|
512
|
+
fig._ro_active = bool(getattr(args, "ro", False))
|
|
513
|
+
except Exception:
|
|
514
|
+
pass
|
|
510
515
|
try:
|
|
511
516
|
fig._bp_source_paths = [_os.path.abspath(ec_file)]
|
|
512
517
|
except Exception:
|
|
@@ -1785,9 +1790,40 @@ def batplot_main() -> int:
|
|
|
1785
1790
|
if not isinstance(sess, dict) or 'version' not in sess:
|
|
1786
1791
|
print("Not a valid batplot session file.")
|
|
1787
1792
|
exit(1)
|
|
1793
|
+
except ModuleNotFoundError as e:
|
|
1794
|
+
# Handle numpy._core and other module import errors
|
|
1795
|
+
if '_core' in str(e) or 'numpy' in str(e).lower():
|
|
1796
|
+
print(f"\nERROR: NumPy version mismatch detected when loading: {sess_path}")
|
|
1797
|
+
print("This session was saved with a different NumPy version.")
|
|
1798
|
+
print("The error 'No module named numpy._core' indicates:")
|
|
1799
|
+
print(" - Session saved with NumPy 2.0+ but loading with NumPy <2.0, OR")
|
|
1800
|
+
print(" - Session saved with NumPy <2.0 but loading with NumPy 2.0+")
|
|
1801
|
+
print("\nSolutions:")
|
|
1802
|
+
print(" 1. Check NumPy version: python3 -c 'import numpy; print(numpy.__version__)'")
|
|
1803
|
+
print(" 2. Install matching version:")
|
|
1804
|
+
print(" - If session was saved with NumPy 2.0+: pip install 'numpy>=2.0'")
|
|
1805
|
+
print(" - If session was saved with NumPy <2.0: pip install 'numpy<2.0'")
|
|
1806
|
+
print(" 3. Recreate the session from original data files")
|
|
1807
|
+
else:
|
|
1808
|
+
print(f"\nERROR: Module import error when loading: {sess_path}")
|
|
1809
|
+
print(f"Error: {e}")
|
|
1810
|
+
print("This usually indicates a package version mismatch.")
|
|
1811
|
+
print("Try installing matching package versions or recreate the session.")
|
|
1812
|
+
exit(1)
|
|
1788
1813
|
except Exception as e:
|
|
1789
1814
|
print(f"Failed to load session: {e}")
|
|
1790
1815
|
exit(1)
|
|
1816
|
+
|
|
1817
|
+
# Check package version compatibility (if version info is available)
|
|
1818
|
+
try:
|
|
1819
|
+
from .session import _get_package_versions, _check_package_compatibility
|
|
1820
|
+
saved_versions = sess.get('package_versions', {})
|
|
1821
|
+
current_versions = _get_package_versions()
|
|
1822
|
+
if saved_versions and not _check_package_compatibility(saved_versions, current_versions, sess_path):
|
|
1823
|
+
exit(1)
|
|
1824
|
+
except Exception:
|
|
1825
|
+
# If compatibility checking fails, continue anyway (backward compatibility)
|
|
1826
|
+
pass
|
|
1791
1827
|
# If it's an EC GC session, load and open EC interactive menu directly
|
|
1792
1828
|
if isinstance(sess, dict) and sess.get('kind') == 'ec_gc':
|
|
1793
1829
|
try:
|
|
@@ -1882,6 +1918,11 @@ def batplot_main() -> int:
|
|
|
1882
1918
|
# Reconstruct minimal state and go to interactive if requested
|
|
1883
1919
|
plt.ion() if args.interactive else None
|
|
1884
1920
|
fig, ax = plt.subplots(figsize=(8,6))
|
|
1921
|
+
# Restore ro flag from session (if present) so style/geom imports can enforce compatibility
|
|
1922
|
+
try:
|
|
1923
|
+
fig._ro_active = bool(sess.get('ro_active', False))
|
|
1924
|
+
except Exception:
|
|
1925
|
+
pass
|
|
1885
1926
|
y_data_list = []
|
|
1886
1927
|
x_data_list = []
|
|
1887
1928
|
labels_list = []
|
|
@@ -2973,19 +3014,21 @@ def batplot_main() -> int:
|
|
|
2973
3014
|
offset += increment
|
|
2974
3015
|
|
|
2975
3016
|
# ---- Plot curve ----
|
|
2976
|
-
# Swap x and y if --ro flag is set
|
|
3017
|
+
# Swap x and y if --ro flag is set (and keep lists aligned once)
|
|
2977
3018
|
if getattr(args, 'ro', False):
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
x_data_list.append(y_plot_offset)
|
|
3019
|
+
x_plotted = y_plot_offset # goes on x-axis when rotated
|
|
3020
|
+
y_plotted = x_plot # goes on y-axis when rotated
|
|
2981
3021
|
else:
|
|
3022
|
+
x_plotted = x_plot
|
|
3023
|
+
y_plotted = y_plot_offset
|
|
2982
3024
|
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
3025
|
+
ax.plot(x_plotted, y_plotted, "-", lw=1, alpha=0.8)
|
|
3026
|
+
x_data_list.append(x_plotted)
|
|
3027
|
+
y_data_list.append(y_plotted.copy())
|
|
2986
3028
|
labels_list.append(label)
|
|
2987
3029
|
# Store current normalized (subset) (used by rearrange logic)
|
|
2988
|
-
orig_y.
|
|
3030
|
+
# Keep orig_y aligned with the plotted y data to avoid length mismatch on undo/relabel.
|
|
3031
|
+
orig_y.append(y_plotted.copy())
|
|
2989
3032
|
|
|
2990
3033
|
# ---------------- Force axis to fit all data before labels ----------------
|
|
2991
3034
|
ax.relim()
|
|
@@ -3498,6 +3541,12 @@ def batplot_main() -> int:
|
|
|
3498
3541
|
fig.set_tight_layout(False)
|
|
3499
3542
|
except Exception:
|
|
3500
3543
|
pass
|
|
3544
|
+
|
|
3545
|
+
# Track whether data axes were swapped via --ro for this figure
|
|
3546
|
+
try:
|
|
3547
|
+
fig._ro_active = bool(getattr(args, "ro", False))
|
|
3548
|
+
except Exception:
|
|
3549
|
+
pass
|
|
3501
3550
|
|
|
3502
3551
|
# Build CIF globals dict for explicit passing
|
|
3503
3552
|
cif_globals = {
|
batplot/cpc_interactive.py
CHANGED
|
@@ -564,6 +564,8 @@ def _style_snapshot(fig, ax, ax2, sc_charge, sc_discharge, sc_eff, file_data=Non
|
|
|
564
564
|
'frame_size': [frame_w_in, frame_h_in],
|
|
565
565
|
'axes_fraction': [ax_bbox.x0, ax_bbox.y0, ax_bbox.width, ax_bbox.height]
|
|
566
566
|
},
|
|
567
|
+
# Track whether data axes were swapped via --ro when this style was saved
|
|
568
|
+
'ro_active': bool(getattr(fig, '_ro_active', False)),
|
|
567
569
|
'font': {'family': fam0, 'size': fsize},
|
|
568
570
|
'legend': {
|
|
569
571
|
'visible': legend_visible,
|
|
@@ -1533,9 +1535,8 @@ def cpc_interactive_menu(fig, ax, ax2, sc_charge, sc_discharge, sc_eff, file_dat
|
|
|
1533
1535
|
ax2.tick_params(axis='y', which='minor', right=True, labelright=False)
|
|
1534
1536
|
else:
|
|
1535
1537
|
ax2.tick_params(axis='y', which='minor', right=False, labelright=False)
|
|
1536
|
-
#
|
|
1537
|
-
|
|
1538
|
-
_ui_position_left_ylabel(ax, fig, tick_state)
|
|
1538
|
+
# Note: Do NOT call position functions during undo restore as it causes title drift
|
|
1539
|
+
# Title offsets are already restored from snapshot in restore_state()
|
|
1539
1540
|
try:
|
|
1540
1541
|
for spine_name, color in getattr(fig, '_cpc_spine_colors', {}).items():
|
|
1541
1542
|
_set_spine_color(spine_name, color)
|
|
@@ -2683,6 +2684,17 @@ def cpc_interactive_menu(fig, ax, ax2, sc_charge, sc_discharge, sc_eff, file_dat
|
|
|
2683
2684
|
kind = cfg.get('kind', '')
|
|
2684
2685
|
if kind not in ('cpc_style', 'cpc_style_geom'):
|
|
2685
2686
|
print("Not a CPC style file."); _print_menu(); continue
|
|
2687
|
+
|
|
2688
|
+
# Enforce compatibility between style/geom ro state and current figure ro state
|
|
2689
|
+
file_ro = bool(cfg.get('ro_active', False))
|
|
2690
|
+
current_ro = bool(getattr(fig, '_ro_active', False))
|
|
2691
|
+
if file_ro != current_ro:
|
|
2692
|
+
if file_ro:
|
|
2693
|
+
print("Warning: Style/geometry file was saved with --ro (swapped x/y axes); current plot is not using --ro.")
|
|
2694
|
+
else:
|
|
2695
|
+
print("Warning: Style/geometry file was saved without --ro; current plot was created with --ro.")
|
|
2696
|
+
print("Not applying CPC style/geometry to avoid corrupting axis orientation.")
|
|
2697
|
+
_print_menu(); continue
|
|
2686
2698
|
|
|
2687
2699
|
has_geometry = (kind == 'cpc_style_geom' and 'geometry' in cfg)
|
|
2688
2700
|
|
|
@@ -1551,10 +1551,8 @@ def electrochem_interactive_menu(fig, ax, cycle_lines: Dict[int, Dict[str, Optio
|
|
|
1551
1551
|
ax._right_ylabel_manual_offset_y_pts = 0.0
|
|
1552
1552
|
ax._top_xlabel_on = bool(snap.get('titles',{}).get('top_x', False))
|
|
1553
1553
|
ax._right_ylabel_on = bool(snap.get('titles',{}).get('right_y', False))
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
_ui_position_left_ylabel(ax, fig, tick_state)
|
|
1557
|
-
_ui_position_right_ylabel(ax, fig, tick_state)
|
|
1554
|
+
# Note: Do NOT call position functions during undo restore as it causes title drift
|
|
1555
|
+
# Title offsets are already restored from snapshot above
|
|
1558
1556
|
except Exception:
|
|
1559
1557
|
pass
|
|
1560
1558
|
# Restore labelpads (for title positioning)
|
|
@@ -2091,6 +2089,18 @@ def electrochem_interactive_menu(fig, ax, cycle_lines: Dict[int, Dict[str, Optio
|
|
|
2091
2089
|
print("Not an EC style file.")
|
|
2092
2090
|
_print_menu(len(all_cycles), is_dqdv)
|
|
2093
2091
|
continue
|
|
2092
|
+
|
|
2093
|
+
# Enforce compatibility between style/geom ro state and current figure ro state
|
|
2094
|
+
file_ro = bool(cfg.get('ro_active', False))
|
|
2095
|
+
current_ro = bool(getattr(fig, '_ro_active', False))
|
|
2096
|
+
if file_ro != current_ro:
|
|
2097
|
+
if file_ro:
|
|
2098
|
+
print("Warning: EC style/geometry file was saved with --ro (swapped x/y axes); current plot is not using --ro.")
|
|
2099
|
+
else:
|
|
2100
|
+
print("Warning: EC style/geometry file was saved without --ro; current plot was created with --ro.")
|
|
2101
|
+
print("Not applying EC style/geometry to avoid corrupting axis orientation.")
|
|
2102
|
+
_print_menu(len(all_cycles), is_dqdv)
|
|
2103
|
+
continue
|
|
2094
2104
|
|
|
2095
2105
|
has_geometry = (kind == 'ec_style_geom' and 'geometry' in cfg)
|
|
2096
2106
|
|
|
@@ -4231,6 +4241,8 @@ def _get_style_snapshot(fig, ax, cycle_lines: Dict, tick_state: Dict) -> Dict:
|
|
|
4231
4241
|
'curve_markers': curve_marker_props,
|
|
4232
4242
|
'rotation_angle': getattr(fig, '_ec_rotation_angle', 0),
|
|
4233
4243
|
'cycle_styles': cycle_styles,
|
|
4244
|
+
# Track whether data axes were swapped via --ro when this style was saved
|
|
4245
|
+
'ro_active': bool(getattr(fig, '_ro_active', False)),
|
|
4234
4246
|
}
|
|
4235
4247
|
|
|
4236
4248
|
|
|
@@ -4322,6 +4334,10 @@ def _print_style_snapshot(cfg: Dict):
|
|
|
4322
4334
|
if rotation_angle != 0:
|
|
4323
4335
|
print(f"Rotation angle: {rotation_angle}°")
|
|
4324
4336
|
|
|
4337
|
+
# ro / axis-swap state
|
|
4338
|
+
ro_active = bool(cfg.get('ro_active', False))
|
|
4339
|
+
print(f"Data axes swapped via --ro: {'YES' if ro_active else 'no'}")
|
|
4340
|
+
|
|
4325
4341
|
# Per-side matrix summary (spine, major, minor, labels, title)
|
|
4326
4342
|
def _onoff(v):
|
|
4327
4343
|
return 'ON ' if bool(v) else 'off'
|
batplot/interactive.py
CHANGED
|
@@ -1218,8 +1218,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
1218
1218
|
fig.set_size_inches(snap["fig_size"][0], snap["fig_size"][1], forward=True)
|
|
1219
1219
|
except Exception:
|
|
1220
1220
|
pass
|
|
1221
|
-
|
|
1222
|
-
print("(Canvas fixed) Ignoring undo figure size restore.")
|
|
1221
|
+
# No message needed - canvas size is managed by system
|
|
1223
1222
|
# Don't restore DPI from undo - use system default to avoid display-dependent issues
|
|
1224
1223
|
|
|
1225
1224
|
# Restore axes (plot frame) via stored bbox if present
|
|
@@ -1287,15 +1286,9 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
1287
1286
|
position_right_ylabel()
|
|
1288
1287
|
except Exception:
|
|
1289
1288
|
pass
|
|
1290
|
-
#
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
except Exception:
|
|
1294
|
-
pass
|
|
1295
|
-
try:
|
|
1296
|
-
position_left_ylabel()
|
|
1297
|
-
except Exception:
|
|
1298
|
-
pass
|
|
1289
|
+
# Note: Do NOT call position_bottom_xlabel() / position_left_ylabel() here
|
|
1290
|
+
# as it causes title drift when combined with fig.canvas.draw() below.
|
|
1291
|
+
# Title offsets are already restored from snapshot above.
|
|
1299
1292
|
|
|
1300
1293
|
# Spines (linewidth, color, visibility)
|
|
1301
1294
|
for name, spec in snap.get("spines", {}).items():
|
|
@@ -1737,7 +1730,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
1737
1730
|
show_cif_titles=(bool(getattr(_bp,'show_cif_titles', True)) if _bp is not None else True),
|
|
1738
1731
|
skip_confirm=skip_confirm,
|
|
1739
1732
|
)
|
|
1740
|
-
|
|
1733
|
+
# Message already printed by dump_session
|
|
1741
1734
|
fig._last_session_save_path = target_path
|
|
1742
1735
|
continue
|
|
1743
1736
|
else:
|
|
@@ -1777,7 +1770,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
1777
1770
|
show_cif_titles=(bool(getattr(_bp,'show_cif_titles', True)) if _bp is not None else True),
|
|
1778
1771
|
skip_confirm=skip_confirm,
|
|
1779
1772
|
)
|
|
1780
|
-
|
|
1773
|
+
# Message already printed by dump_session
|
|
1781
1774
|
fig._last_session_save_path = target_path
|
|
1782
1775
|
except Exception as e:
|
|
1783
1776
|
print(f"Error saving session: {e}")
|
|
@@ -2697,10 +2690,11 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
2697
2690
|
eps = abs(y_min)*1e-6 if y_min != 0 else 1e-6
|
|
2698
2691
|
y_min -= eps
|
|
2699
2692
|
y_max += eps
|
|
2700
|
-
|
|
2693
|
+
ax.set_ylim(y_min, y_max)
|
|
2701
2694
|
update_labels(ax, y_data_list, label_text_objects, args.stack, getattr(fig, '_stack_label_at_bottom', False))
|
|
2702
2695
|
fig.canvas.draw_idle()
|
|
2703
|
-
|
|
2696
|
+
ymin, ymax = ax.get_ylim()
|
|
2697
|
+
print(f"Y range set to ({float(ymin)}, {float(ymax)})")
|
|
2704
2698
|
except Exception as e:
|
|
2705
2699
|
print(f"Error setting Y-axis range: {e}")
|
|
2706
2700
|
elif key == 'd': # <-- DELTA / OFFSET HANDLER (now only reachable if not args.stack)
|
batplot/session.py
CHANGED
|
@@ -36,11 +36,116 @@ import os
|
|
|
36
36
|
|
|
37
37
|
import matplotlib.pyplot as plt
|
|
38
38
|
import numpy as np
|
|
39
|
+
import sys
|
|
39
40
|
|
|
40
41
|
from .utils import _confirm_overwrite
|
|
41
42
|
from .color_utils import ensure_colormap
|
|
42
43
|
|
|
43
44
|
|
|
45
|
+
def _get_package_versions():
|
|
46
|
+
"""Get versions of critical packages for compatibility checking.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
dict: Package name -> version string mapping
|
|
50
|
+
"""
|
|
51
|
+
versions = {}
|
|
52
|
+
critical_packages = ['numpy', 'matplotlib', 'scipy']
|
|
53
|
+
|
|
54
|
+
for pkg_name in critical_packages:
|
|
55
|
+
try:
|
|
56
|
+
mod = __import__(pkg_name)
|
|
57
|
+
versions[pkg_name] = getattr(mod, '__version__', 'unknown')
|
|
58
|
+
except ImportError:
|
|
59
|
+
versions[pkg_name] = 'not_installed'
|
|
60
|
+
except Exception:
|
|
61
|
+
versions[pkg_name] = 'unknown'
|
|
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
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _check_package_compatibility(saved_versions, current_versions, filename):
|
|
70
|
+
"""Check if package versions are compatible and warn/error if not.
|
|
71
|
+
|
|
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
|
+
Returns:
|
|
78
|
+
bool: True if compatible (or can proceed), False if should abort
|
|
79
|
+
"""
|
|
80
|
+
if not saved_versions:
|
|
81
|
+
# Old session file without version info - allow but warn
|
|
82
|
+
print("Warning: Session file does not contain package version information.")
|
|
83
|
+
print("This may cause compatibility issues. Consider recreating the session.")
|
|
84
|
+
return True
|
|
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
|
|
135
|
+
|
|
136
|
+
if mismatches:
|
|
137
|
+
print(f"\nWarning: Package version differences detected for session: {filename}")
|
|
138
|
+
print("Minor version differences may be okay, but proceed with caution:")
|
|
139
|
+
for pkg, saved, current in mismatches:
|
|
140
|
+
print(f" {pkg}: saved with {saved}, current is {current}")
|
|
141
|
+
print("If you encounter errors, try matching the saved versions.")
|
|
142
|
+
response = input("Continue loading session? (y/n): ").strip().lower()
|
|
143
|
+
if response != 'y':
|
|
144
|
+
return False
|
|
145
|
+
|
|
146
|
+
return True
|
|
147
|
+
|
|
148
|
+
|
|
44
149
|
def _current_tick_width(axis_obj, which: str):
|
|
45
150
|
"""
|
|
46
151
|
Return the configured tick width for the given X/Y axis.
|
|
@@ -431,8 +536,12 @@ def dump_session(
|
|
|
431
536
|
wasd_state = _capture_wasd_state(ax)
|
|
432
537
|
|
|
433
538
|
try:
|
|
539
|
+
# Get current package versions for compatibility checking
|
|
540
|
+
package_versions = _get_package_versions()
|
|
541
|
+
|
|
434
542
|
sess = {
|
|
435
543
|
'version': 3,
|
|
544
|
+
'package_versions': package_versions, # Track versions for compatibility checking
|
|
436
545
|
'x_data': [np.array(a) for a in x_data_list],
|
|
437
546
|
'y_data': [np.array(a) for a in y_data_list],
|
|
438
547
|
'orig_y': [np.array(a) for a in orig_y],
|
|
@@ -507,6 +616,8 @@ def dump_session(
|
|
|
507
616
|
}
|
|
508
617
|
# Save curve names visibility
|
|
509
618
|
sess['curve_names_visible'] = bool(getattr(fig, '_curve_names_visible', True))
|
|
619
|
+
# Save whether data were plotted with swapped axes via --ro
|
|
620
|
+
sess['ro_active'] = bool(getattr(fig, '_ro_active', False))
|
|
510
621
|
# Save stack/legend anchor preferences
|
|
511
622
|
sess['stack_label_at_bottom'] = bool(getattr(fig, '_stack_label_at_bottom', False))
|
|
512
623
|
sess['label_anchor_left'] = bool(getattr(fig, '_label_anchor_left', False))
|
|
@@ -752,9 +863,13 @@ def dump_operando_session(
|
|
|
752
863
|
cb_h_offset = getattr(cbar.ax, '_cb_h_offset_in', 0.0)
|
|
753
864
|
ec_h_offset = getattr(ec_ax, '_ec_h_offset_in', 0.0) if ec_ax is not None else None
|
|
754
865
|
|
|
866
|
+
# Get current package versions for compatibility checking
|
|
867
|
+
package_versions = _get_package_versions()
|
|
868
|
+
|
|
755
869
|
sess = {
|
|
756
870
|
'kind': 'operando_ec',
|
|
757
871
|
'version': 2,
|
|
872
|
+
'package_versions': package_versions, # Track versions for compatibility checking
|
|
758
873
|
'figure': {'size': (fig_w, fig_h), 'dpi': dpi},
|
|
759
874
|
'layout_inches': {
|
|
760
875
|
'cb_w_in': cb_w_in,
|
|
@@ -819,6 +934,26 @@ def load_operando_session(filename: str):
|
|
|
819
934
|
try:
|
|
820
935
|
with open(filename, 'rb') as f:
|
|
821
936
|
sess = pickle.load(f)
|
|
937
|
+
except ModuleNotFoundError as e:
|
|
938
|
+
# Handle numpy._core and other module import errors
|
|
939
|
+
if '_core' in str(e) or 'numpy' in str(e).lower():
|
|
940
|
+
print(f"\nERROR: NumPy version mismatch detected when loading: {filename}")
|
|
941
|
+
print("This session was saved with a different NumPy version.")
|
|
942
|
+
print("The error 'No module named numpy._core' indicates:")
|
|
943
|
+
print(" - Session saved with NumPy 2.0+ but loading with NumPy <2.0, OR")
|
|
944
|
+
print(" - Session saved with NumPy <2.0 but loading with NumPy 2.0+")
|
|
945
|
+
print("\nSolutions:")
|
|
946
|
+
print(" 1. Check NumPy version: python3 -c 'import numpy; print(numpy.__version__)'")
|
|
947
|
+
print(" 2. Install matching version:")
|
|
948
|
+
print(" - If session was saved with NumPy 2.0+: pip install 'numpy>=2.0'")
|
|
949
|
+
print(" - If session was saved with NumPy <2.0: pip install 'numpy<2.0'")
|
|
950
|
+
print(" 3. Recreate the session from original data files")
|
|
951
|
+
else:
|
|
952
|
+
print(f"\nERROR: Module import error when loading: {filename}")
|
|
953
|
+
print(f"Error: {e}")
|
|
954
|
+
print("This usually indicates a package version mismatch.")
|
|
955
|
+
print("Try installing matching package versions or recreate the session.")
|
|
956
|
+
return None
|
|
822
957
|
except Exception as e:
|
|
823
958
|
print(f"Failed to load session: {e}")
|
|
824
959
|
return None
|
|
@@ -826,6 +961,12 @@ def load_operando_session(filename: str):
|
|
|
826
961
|
if not isinstance(sess, dict) or sess.get('kind') != 'operando_ec':
|
|
827
962
|
print("Not an operando+EC session file.")
|
|
828
963
|
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
|
|
829
970
|
|
|
830
971
|
# Use standard DPI of 100 instead of saved DPI to avoid display-dependent issues
|
|
831
972
|
# (Retina displays, Windows scaling, etc. can cause saved DPI to differ)
|
|
@@ -1605,9 +1746,13 @@ def dump_ec_session(
|
|
|
1605
1746
|
legend_xy_in = (float(xy[0]), float(xy[1]))
|
|
1606
1747
|
except Exception:
|
|
1607
1748
|
legend_xy_in = None
|
|
1749
|
+
# Get current package versions for compatibility checking
|
|
1750
|
+
package_versions = _get_package_versions()
|
|
1751
|
+
|
|
1608
1752
|
sess = {
|
|
1609
1753
|
'kind': 'ec_gc',
|
|
1610
1754
|
'version': 2,
|
|
1755
|
+
'package_versions': package_versions, # Track versions for compatibility checking
|
|
1611
1756
|
'figure': {'size': (fig_w, fig_h), 'dpi': dpi},
|
|
1612
1757
|
'axis': axis,
|
|
1613
1758
|
'subplot_margins': subplot_margins,
|
|
@@ -1657,6 +1802,26 @@ def load_ec_session(filename: str):
|
|
|
1657
1802
|
try:
|
|
1658
1803
|
with open(filename, 'rb') as f:
|
|
1659
1804
|
sess = pickle.load(f)
|
|
1805
|
+
except ModuleNotFoundError as e:
|
|
1806
|
+
# Handle numpy._core and other module import errors
|
|
1807
|
+
if '_core' in str(e) or 'numpy' in str(e).lower():
|
|
1808
|
+
print(f"\nERROR: NumPy version mismatch detected when loading: {filename}")
|
|
1809
|
+
print("This session was saved with a different NumPy version.")
|
|
1810
|
+
print("The error 'No module named numpy._core' indicates:")
|
|
1811
|
+
print(" - Session saved with NumPy 2.0+ but loading with NumPy <2.0, OR")
|
|
1812
|
+
print(" - Session saved with NumPy <2.0 but loading with NumPy 2.0+")
|
|
1813
|
+
print("\nSolutions:")
|
|
1814
|
+
print(" 1. Check NumPy version: python3 -c 'import numpy; print(numpy.__version__)'")
|
|
1815
|
+
print(" 2. Install matching version:")
|
|
1816
|
+
print(" - If session was saved with NumPy 2.0+: pip install 'numpy>=2.0'")
|
|
1817
|
+
print(" - If session was saved with NumPy <2.0: pip install 'numpy<2.0'")
|
|
1818
|
+
print(" 3. Recreate the session from original data files")
|
|
1819
|
+
else:
|
|
1820
|
+
print(f"\nERROR: Module import error when loading: {filename}")
|
|
1821
|
+
print(f"Error: {e}")
|
|
1822
|
+
print("This usually indicates a package version mismatch.")
|
|
1823
|
+
print("Try installing matching package versions or recreate the session.")
|
|
1824
|
+
return None
|
|
1660
1825
|
except Exception as e:
|
|
1661
1826
|
print(f"Failed to load EC session: {e}")
|
|
1662
1827
|
return None
|
|
@@ -1664,6 +1829,12 @@ def load_ec_session(filename: str):
|
|
|
1664
1829
|
if not isinstance(sess, dict) or sess.get('kind') != 'ec_gc':
|
|
1665
1830
|
print("Not an EC GC session file.")
|
|
1666
1831
|
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
|
|
1667
1838
|
|
|
1668
1839
|
# Use standard DPI of 100 instead of saved DPI to avoid display-dependent issues
|
|
1669
1840
|
# (Retina displays, Windows scaling, etc. can cause saved DPI to differ)
|
|
@@ -2368,9 +2539,13 @@ def dump_cpc_session(
|
|
|
2368
2539
|
'right_y': float(getattr(ax2, '_right_ylabel_manual_offset_y_pts', 0.0) or 0.0),
|
|
2369
2540
|
}
|
|
2370
2541
|
|
|
2542
|
+
# Get current package versions for compatibility checking
|
|
2543
|
+
package_versions = _get_package_versions()
|
|
2544
|
+
|
|
2371
2545
|
meta = {
|
|
2372
2546
|
'kind': 'cpc',
|
|
2373
2547
|
'version': 2, # Incremented version for new format
|
|
2548
|
+
'package_versions': package_versions, # Track versions for compatibility checking
|
|
2374
2549
|
'figure': {
|
|
2375
2550
|
'size': (fig_w, fig_h),
|
|
2376
2551
|
'dpi': dpi,
|
|
@@ -2526,12 +2701,38 @@ def load_cpc_session(filename: str):
|
|
|
2526
2701
|
try:
|
|
2527
2702
|
with open(filename, 'rb') as f:
|
|
2528
2703
|
sess = pickle.load(f)
|
|
2704
|
+
except ModuleNotFoundError as e:
|
|
2705
|
+
# Handle numpy._core and other module import errors
|
|
2706
|
+
if '_core' in str(e) or 'numpy' in str(e).lower():
|
|
2707
|
+
print(f"\nERROR: NumPy version mismatch detected when loading: {filename}")
|
|
2708
|
+
print("This session was saved with a different NumPy version.")
|
|
2709
|
+
print("The error 'No module named numpy._core' indicates:")
|
|
2710
|
+
print(" - Session saved with NumPy 2.0+ but loading with NumPy <2.0, OR")
|
|
2711
|
+
print(" - Session saved with NumPy <2.0 but loading with NumPy 2.0+")
|
|
2712
|
+
print("\nSolutions:")
|
|
2713
|
+
print(" 1. Check NumPy version: python3 -c 'import numpy; print(numpy.__version__)'")
|
|
2714
|
+
print(" 2. Install matching version:")
|
|
2715
|
+
print(" - If session was saved with NumPy 2.0+: pip install 'numpy>=2.0'")
|
|
2716
|
+
print(" - If session was saved with NumPy <2.0: pip install 'numpy<2.0'")
|
|
2717
|
+
print(" 3. Recreate the session from original data files")
|
|
2718
|
+
else:
|
|
2719
|
+
print(f"\nERROR: Module import error when loading: {filename}")
|
|
2720
|
+
print(f"Error: {e}")
|
|
2721
|
+
print("This usually indicates a package version mismatch.")
|
|
2722
|
+
print("Try installing matching package versions or recreate the session.")
|
|
2723
|
+
return None
|
|
2529
2724
|
except Exception as e:
|
|
2530
2725
|
print(f"Failed to load session: {e}")
|
|
2531
2726
|
return None
|
|
2532
2727
|
if not isinstance(sess, dict) or sess.get('kind') != 'cpc':
|
|
2533
2728
|
print("Not a CPC session file.")
|
|
2534
2729
|
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
|
|
2535
2736
|
try:
|
|
2536
2737
|
# Use standard DPI of 100 instead of saved DPI to avoid display-dependent issues
|
|
2537
2738
|
# (Retina displays, Windows scaling, etc. can cause saved DPI to differ)
|
batplot/style.py
CHANGED
|
@@ -358,6 +358,13 @@ def print_style_info(
|
|
|
358
358
|
print(f"Font family chain (rcParams['font.sans-serif']): {plt.rcParams.get('font.sans-serif')}")
|
|
359
359
|
print(f"Mathtext fontset: {plt.rcParams.get('mathtext.fontset')}")
|
|
360
360
|
|
|
361
|
+
# Report whether data axes were swapped via --ro when this figure was created
|
|
362
|
+
try:
|
|
363
|
+
ro_active = bool(getattr(fig, "_ro_active", False))
|
|
364
|
+
except Exception:
|
|
365
|
+
ro_active = False
|
|
366
|
+
print(f"Data axes swapped via --ro: {'YES' if ro_active else 'no'}")
|
|
367
|
+
|
|
361
368
|
# Rotation angle
|
|
362
369
|
rotation_angle = getattr(ax, '_rotation_angle', 0)
|
|
363
370
|
if rotation_angle != 0:
|
|
@@ -646,6 +653,8 @@ def export_style_config(
|
|
|
646
653
|
}
|
|
647
654
|
# Save rotation angle
|
|
648
655
|
cfg["rotation_angle"] = getattr(ax, '_rotation_angle', 0)
|
|
656
|
+
# Track whether data axes were swapped via --ro when this style was saved
|
|
657
|
+
cfg["ro_active"] = bool(getattr(fig, '_ro_active', False))
|
|
649
658
|
|
|
650
659
|
# Save curve names visibility
|
|
651
660
|
cfg["curve_names_visible"] = True # Default to visible
|
|
@@ -853,6 +862,17 @@ def apply_style_config(
|
|
|
853
862
|
except Exception as e:
|
|
854
863
|
print(f"Could not read config: {e}")
|
|
855
864
|
return
|
|
865
|
+
# Enforce compatibility between style/geometry ro state and current figure ro state.
|
|
866
|
+
# Styles saved from a plot using --ro (swapped x/y) must not be applied to a non-ro plot, and vice versa.
|
|
867
|
+
file_ro = bool(cfg.get("ro_active", False))
|
|
868
|
+
current_ro = bool(getattr(fig, "_ro_active", False))
|
|
869
|
+
if file_ro != current_ro:
|
|
870
|
+
if file_ro:
|
|
871
|
+
print("Warning: Style/geometry file was saved with --ro (swapped x/y axes); current plot is not using --ro.")
|
|
872
|
+
else:
|
|
873
|
+
print("Warning: Style/geometry file was saved without --ro; current plot was created with --ro.")
|
|
874
|
+
print("Not applying style/geometry to avoid corrupting axis orientation.")
|
|
875
|
+
return
|
|
856
876
|
# Save current labelpad values BEFORE any style changes
|
|
857
877
|
saved_xlabelpad = None
|
|
858
878
|
saved_ylabelpad = None
|
|
@@ -878,8 +898,7 @@ def apply_style_config(
|
|
|
878
898
|
if not keep_canvas_fixed:
|
|
879
899
|
# Use forward=False to prevent automatic subplot adjustment that can shift the plot
|
|
880
900
|
fig.set_size_inches(fw, fh, forward=False)
|
|
881
|
-
|
|
882
|
-
print("(Canvas fixed) Ignoring style figure size request.")
|
|
901
|
+
# No message needed when canvas is fixed - this is normal behavior
|
|
883
902
|
except Exception as e:
|
|
884
903
|
print(f"Warning: could not parse figure size: {e}")
|
|
885
904
|
try:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: batplot
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.3
|
|
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=
|
|
1
|
+
batplot/__init__.py,sha256=RAScNSaXpWIGw1hbfjWc2RDcKAf-ftvoSfY-3DOZTF0,118
|
|
2
2
|
batplot/args.py,sha256=mrDjMURp_OQnXrAwl9WnE_FW4HJu940O7NmL9QWQnD4,35189
|
|
3
|
-
batplot/batch.py,sha256=
|
|
4
|
-
batplot/batplot.py,sha256=
|
|
3
|
+
batplot/batch.py,sha256=P2HNBYqrSzDr2fruYz8BFKwNFX6vdJpHDZpaG_hmEc8,55253
|
|
4
|
+
batplot/batplot.py,sha256=Yd6wyMTRgu65BY9ousd_3Zxoauce99vYqzeSgqhxv8U,177164
|
|
5
5
|
batplot/cif.py,sha256=JfHwNf3SHrcpALc_F5NjJmQ3lg71MBRSaIUJjGYPTx8,30120
|
|
6
6
|
batplot/cli.py,sha256=ScDb2je8VQ0mz_z0SLCHEigiTuFPY5pb1snnzCouKms,5828
|
|
7
7
|
batplot/color_utils.py,sha256=7InQLVo1XTg7sgAbltM2KeDSFJgr787YEaV9vJbIoWY,20460
|
|
8
8
|
batplot/config.py,sha256=6nGY7fKN4T5KZUGQS2ArUBgEkLAL0j37XwG5SCVQgKA,6420
|
|
9
9
|
batplot/converters.py,sha256=rR2WMPM0nR5E3eZI3gWbaJf_AfbdQx3urVSbJmZXNzo,8237
|
|
10
|
-
batplot/cpc_interactive.py,sha256=
|
|
11
|
-
batplot/electrochem_interactive.py,sha256=
|
|
12
|
-
batplot/interactive.py,sha256=
|
|
10
|
+
batplot/cpc_interactive.py,sha256=qadWV2PaQMsqM16mSp5r1-WP7di0JCnzNI4RJy27alo,239616
|
|
11
|
+
batplot/electrochem_interactive.py,sha256=8mFr5vtWb_ZDiJmZWXjkARq21D2GflT8-J2xvCGvDIc,222769
|
|
12
|
+
batplot/interactive.py,sha256=5u2ulhTzRr7fA-INc5hfcz7xaHObnnigiXjrgdtE7XE,206728
|
|
13
13
|
batplot/manual.py,sha256=pbRI6G4Pm12pOW8LrOLWWu7IEOtqWN3tRHtgge50LlA,11556
|
|
14
14
|
batplot/modes.py,sha256=qE2OsOQQKhwOWene5zxJeuuewTrZxubtahQuz5je7ok,37252
|
|
15
15
|
batplot/operando.py,sha256=p2Ug1mFUQxaU702cTBGgJKb3_v1C2p3LLUwfXaVBpPY,28311
|
|
16
16
|
batplot/operando_ec_interactive.py,sha256=8GQ47-I8SLTS88sFEk8m3vDxFEjSfD3hao62Qke7SxA,305137
|
|
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=5eZLJHE66wtZPwNsnR1I2iyEvxY3cLTl3aY7HNxpX6U,145772
|
|
20
|
+
batplot/style.py,sha256=jXtFaJR1aa6vIHupmDNqY2NY5Rgtw49UxF7cS4y8fCA,63375
|
|
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
24
|
batplot/data/USER_MANUAL.md,sha256=VYPvNZt3Fy8Z4Izr2FnQBw9vEaFTPkybhHDnF-OuKws,17694
|
|
25
|
-
batplot-1.8.
|
|
25
|
+
batplot-1.8.3.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.3.dist-info/METADATA,sha256=BNWy96koh0Pcj9CDJYuJ6Xp44krYa8Wg9SM1T4qhYhA,7406
|
|
72
|
+
batplot-1.8.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
73
|
+
batplot-1.8.3.dist-info/entry_points.txt,sha256=73GgH3Zs-qGIvgiyQLgGsSW-ryOwPPKHveOW6TDIR5Q,82
|
|
74
|
+
batplot-1.8.3.dist-info/top_level.txt,sha256=Z5Q4sAiT_FDqZqhlLsYn9avRTuFAEEf3AVfkswxOb18,70
|
|
75
|
+
batplot-1.8.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|