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/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
- try:
732
- with open(overwrite_path, 'r', encoding='utf-8') as f:
733
- old_cfg = json.load(f)
734
- old_kind = old_cfg.get('kind', '')
735
- if old_kind == 'xy_style_geom':
736
- exp_choice = 'psg'
737
- else:
738
- exp_choice = 'ps'
739
- except Exception:
740
- exp_choice = 'ps' # Default to style-only if can't read
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
- if "offset" in entry and offsets_list is not None and orig_y is not None and x_data_list is not None:
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
- # Reapply offset to the curve
1222
- if idx < len(orig_y) and idx < len(y_data_list) and idx < len(x_data_list):
1223
- y_norm = orig_y[idx]
1224
- y_with_offset = y_norm + offset_val
1225
- y_data_list[idx] = y_with_offset
1226
- ln.set_data(x_data_list[idx], y_with_offset)
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.5
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=6mfbpfSzbSfjCLrvmBzBMKmDyiFSBUJlcB8Qqv6o26s,118
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=-mAf1aW7bniyfQ5DCorqyOr-OcRtUgRtq6TZHKk5xCU,184599
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=-9etN342VqLbY9pLP7cyBcSzgVHuWpDwEZHkXzShl7E,240683
11
- batplot/electrochem_interactive.py,sha256=a3ocYQEfi0FsiMq9B4_0GY97td00e8uyzlHc3Sr6EKE,225211
12
- batplot/interactive.py,sha256=b-0xeza_Rs4S59ve-pyWVq_-FvTpqDIy1tu4M3tT3Eg,300447
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=qE2OsOQQKhwOWene5zxJeuuewTrZxubtahQuz5je7ok,37252
14
+ batplot/modes.py,sha256=BajbnDzzYRD-FRr5Hoft0TyQ5CTWyggJjKa9yrM6iy4,37376
15
15
  batplot/operando.py,sha256=h09xu1BsdR68YlzhWeUSypYX83DzjJABIQQS2noQzPI,29400
16
- batplot/operando_ec_interactive.py,sha256=YExiuKn-qQksW3YFYCTpvumuCit4cc4YiiaSRWGa0og,317833
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=sgcJyCj00lOhmIRdDxGSqu2vEpOm7WSFZzLXxukYNL0,144936
20
- batplot/style.py,sha256=3XnWlU9aTb1b-aiq5BQOuAREE5nOEYZ0b75v_LS0xDM,67790
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.5.dist-info/licenses/LICENSE,sha256=2PAnHeCiTfgI7aKZLWr0G56HI9fGKQ0CEbQ02H-yExQ,1065
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.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,,
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,,