batplot 1.8.5__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/batplot.py +125 -53
- batplot/cpc_interactive.py +286 -140
- batplot/electrochem_interactive.py +57 -44
- batplot/interactive.py +216 -2
- batplot/modes.py +12 -11
- batplot/operando_ec_interactive.py +158 -14
- batplot/session.py +61 -9
- batplot/style.py +109 -19
- {batplot-1.8.5.dist-info → batplot-1.8.6.dist-info}/METADATA +1 -1
- {batplot-1.8.5.dist-info → batplot-1.8.6.dist-info}/RECORD +15 -15
- {batplot-1.8.5.dist-info → batplot-1.8.6.dist-info}/WHEEL +0 -0
- {batplot-1.8.5.dist-info → batplot-1.8.6.dist-info}/entry_points.txt +0 -0
- {batplot-1.8.5.dist-info → batplot-1.8.6.dist-info}/licenses/LICENSE +0 -0
- {batplot-1.8.5.dist-info → batplot-1.8.6.dist-info}/top_level.txt +0 -0
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
|
|
@@ -520,6 +521,7 @@ def export_style_config(
|
|
|
520
521
|
base_path: Optional[str] = None,
|
|
521
522
|
show_cif_titles: Optional[bool] = None,
|
|
522
523
|
overwrite_path: Optional[str] = None,
|
|
524
|
+
force_kind: Optional[str] = None,
|
|
523
525
|
) -> Optional[str]:
|
|
524
526
|
"""Export style configuration after displaying a summary and prompting the user.
|
|
525
527
|
|
|
@@ -604,6 +606,8 @@ def export_style_config(
|
|
|
604
606
|
"x_minor_width": axis_tick_width(ax.xaxis, "minor"),
|
|
605
607
|
"y_major_width": axis_tick_width(ax.yaxis, "major"),
|
|
606
608
|
"y_minor_width": axis_tick_width(ax.yaxis, "minor"),
|
|
609
|
+
"lengths": dict(getattr(fig, '_tick_lengths', {})),
|
|
610
|
+
"direction": getattr(fig, '_tick_direction', 'out'),
|
|
607
611
|
},
|
|
608
612
|
"wasd_state": wasd_state,
|
|
609
613
|
"spines": {
|
|
@@ -726,18 +730,22 @@ def export_style_config(
|
|
|
726
730
|
# as style files are for styling only, and the data would be specific
|
|
727
731
|
# to the dataset. Session files (pickle) store this data instead.
|
|
728
732
|
|
|
729
|
-
# If overwrite_path is provided, determine export type from existing file
|
|
733
|
+
# If overwrite_path is provided, determine export type from existing file,
|
|
734
|
+
# unless the caller explicitly forces style-only or style+geometry.
|
|
730
735
|
if overwrite_path:
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
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
|
|
741
749
|
else:
|
|
742
750
|
# Ask user for style-only or style+geometry
|
|
743
751
|
print("\nExport options:")
|
|
@@ -907,6 +915,34 @@ def apply_style_config(
|
|
|
907
915
|
print("Warning: Style/geometry file was saved without --ro; current plot was created with --ro.")
|
|
908
916
|
print("Not applying style/geometry to avoid corrupting axis orientation.")
|
|
909
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
|
+
|
|
910
946
|
# Save current labelpad values BEFORE any style changes
|
|
911
947
|
saved_xlabelpad = None
|
|
912
948
|
saved_ylabelpad = None
|
|
@@ -955,6 +991,12 @@ def apply_style_config(
|
|
|
955
991
|
fig.subplots_adjust(left=left, right=left + w_frac, bottom=bottom, top=bottom + h_frac)
|
|
956
992
|
except Exception as e:
|
|
957
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
|
|
958
1000
|
# Don't restore DPI from style - use system default to avoid display-dependent issues
|
|
959
1001
|
# (Retina displays, Windows scaling, etc. can cause saved DPI to differ)
|
|
960
1002
|
|
|
@@ -1135,6 +1177,32 @@ def apply_style_config(
|
|
|
1135
1177
|
ax.tick_params(axis="y", which="minor", width=yminr)
|
|
1136
1178
|
except Exception as e:
|
|
1137
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}")
|
|
1138
1206
|
|
|
1139
1207
|
# Spines
|
|
1140
1208
|
for name, sp_dict in cfg.get("spines", {}).items():
|
|
@@ -1213,19 +1281,33 @@ def apply_style_config(
|
|
|
1213
1281
|
except Exception:
|
|
1214
1282
|
pass
|
|
1215
1283
|
# Restore offset if available
|
|
1216
|
-
|
|
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:
|
|
1217
1287
|
try:
|
|
1218
1288
|
offset_val = float(entry["offset"])
|
|
1219
|
-
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
|
|
1220
1294
|
offsets_list[idx] = offset_val
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
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})")
|
|
1227
1303
|
except Exception as e:
|
|
1228
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}")
|
|
1229
1311
|
palette_cfg = cfg.get("curve_palettes", [])
|
|
1230
1312
|
if palette_cfg:
|
|
1231
1313
|
sanitized_history = []
|
|
@@ -1425,11 +1507,19 @@ def apply_style_config(
|
|
|
1425
1507
|
if 'xlim' in geom and isinstance(geom['xlim'], list) and len(geom['xlim']) == 2:
|
|
1426
1508
|
ax.set_xlim(geom['xlim'][0], geom['xlim'][1])
|
|
1427
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]})")
|
|
1428
1512
|
ax.set_ylim(geom['ylim'][0], geom['ylim'][1])
|
|
1429
1513
|
print("Applied geometry (labels and limits)")
|
|
1430
1514
|
except Exception as e:
|
|
1431
1515
|
print(f"Warning: Could not apply geometry: {e}")
|
|
1432
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}")
|
|
1433
1523
|
try:
|
|
1434
1524
|
fig.canvas.draw_idle()
|
|
1435
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=
|
|
1
|
+
batplot/__init__.py,sha256=Fy71HWPcaheFTg920KgEZ7reiHA27RQ-B6mxzpc8ZbI,118
|
|
2
2
|
batplot/args.py,sha256=DGTe2PKmJnI8Iq12QgO76V8lZvWhMOqY14gsyE5SgEs,37001
|
|
3
3
|
batplot/batch.py,sha256=hqLNvd88OLd0PLo_ot6JjC3FM6wwxCJ1jO2J63f9Zyg,55899
|
|
4
|
-
batplot/batplot.py,sha256
|
|
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
9
|
batplot/converters.py,sha256=c4qhgN9zHUiBZhXVAdf0zGtPPoktD3JjMLkhjjYEwlk,9787
|
|
10
|
-
batplot/cpc_interactive.py,sha256
|
|
11
|
-
batplot/electrochem_interactive.py,sha256=
|
|
12
|
-
batplot/interactive.py,sha256=
|
|
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=
|
|
14
|
+
batplot/modes.py,sha256=BajbnDzzYRD-FRr5Hoft0TyQ5CTWyggJjKa9yrM6iy4,37376
|
|
15
15
|
batplot/operando.py,sha256=h09xu1BsdR68YlzhWeUSypYX83DzjJABIQQS2noQzPI,29400
|
|
16
|
-
batplot/operando_ec_interactive.py,sha256=
|
|
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
24
|
batplot/data/USER_MANUAL.md,sha256=w6pmDXoLINFkCWWh3zay7uNIxUaDxSOrocnPIZwu2uA,19542
|
|
25
|
-
batplot-1.8.
|
|
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
|
|
File without changes
|