batplot 1.7.25__py3-none-any.whl → 1.7.26__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.

@@ -1684,6 +1684,13 @@ def electrochem_interactive_menu(fig, ax, cycle_lines: Dict[int, Dict[str, Optio
1684
1684
  if not already_confirmed and os.path.exists(target):
1685
1685
  target = _confirm_overwrite(target)
1686
1686
  if target:
1687
+ # Save current legend position before export (savefig can change layout)
1688
+ saved_legend_pos = None
1689
+ try:
1690
+ saved_legend_pos = getattr(fig, '_ec_legend_xy_in', None)
1691
+ except Exception:
1692
+ pass
1693
+
1687
1694
  # If exporting SVG, make background transparent for PowerPoint
1688
1695
  _, ext2 = os.path.splitext(target)
1689
1696
  ext2 = ext2.lower()
@@ -1727,6 +1734,15 @@ def electrochem_interactive_menu(fig, ax, cycle_lines: Dict[int, Dict[str, Optio
1727
1734
  fig.savefig(target, bbox_inches='tight')
1728
1735
  print(f"Exported figure to {target}")
1729
1736
  fig._last_figure_export_path = target
1737
+
1738
+ # Restore legend position after savefig (which may have changed layout)
1739
+ if saved_legend_pos is not None:
1740
+ try:
1741
+ fig._ec_legend_xy_in = saved_legend_pos
1742
+ _rebuild_legend(ax)
1743
+ fig.canvas.draw_idle()
1744
+ except Exception:
1745
+ pass
1730
1746
  except Exception as e:
1731
1747
  print(f"Export failed: {e}")
1732
1748
  except Exception as e:
@@ -3283,8 +3299,10 @@ def electrochem_interactive_menu(fig, ax, cycle_lines: Dict[int, Dict[str, Optio
3283
3299
  continue
3284
3300
  elif key == 'f':
3285
3301
  # Font submenu with numbered options
3302
+ cur_family = plt.rcParams.get('font.sans-serif', [''])[0]
3303
+ cur_size = plt.rcParams.get('font.size', None)
3286
3304
  while True:
3287
- print("\nFont menu: f=font family, s=size, q=back")
3305
+ print(f"\nFont menu (current: family='{cur_family}', size={cur_size}): f=font family, s=size, q=back")
3288
3306
  sub = input("Font> ").strip().lower()
3289
3307
  if not sub:
3290
3308
  continue
@@ -3298,7 +3316,7 @@ def electrochem_interactive_menu(fig, ax, cycle_lines: Dict[int, Dict[str, Optio
3298
3316
  for i, font in enumerate(fonts, 1):
3299
3317
  print(f" {i}: {font}")
3300
3318
  print("Or enter custom font name directly.")
3301
- choice = input("Font family (number or name): ").strip()
3319
+ choice = input(f"Font family (current: '{cur_family}', number or name): ").strip()
3302
3320
  if not choice:
3303
3321
  continue
3304
3322
  # Check if it's a number
batplot/interactive.py CHANGED
@@ -963,7 +963,7 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
963
963
  txt = ax.text(1.0, 1.0, "",
964
964
  ha='right', va='bottom',
965
965
  transform=ax.transAxes,
966
- fontsize=max(9, int(0.6 * plt.rcParams.get('font.size', 12))),
966
+ fontsize=max(9, int(0.6 * plt.rcParams.get('font.size', 16))),
967
967
  color='0.15',
968
968
  bbox=dict(boxstyle='round,pad=0.25', fc='white', ec='0.7', alpha=0.8))
969
969
 
@@ -3130,15 +3130,18 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
3130
3130
  except Exception as e:
3131
3131
  print(f"Error setting widths: {e}")
3132
3132
  elif key == 'f':
3133
+ cur_family = plt.rcParams.get('font.sans-serif', [''])[0]
3134
+ cur_size = plt.rcParams.get('font.size', None)
3133
3135
  while True:
3134
- subkey = input(colorize_prompt("Font submenu (s=size, f=family, q=return): ")).strip().lower()
3136
+ subkey = input(colorize_prompt(f"Font submenu (current: family='{cur_family}', size={cur_size}) - s=size, f=family, q=return: ")).strip().lower()
3135
3137
  if subkey == 'q':
3136
3138
  break
3137
3139
  if subkey == '':
3138
3140
  continue
3139
3141
  if subkey == 's':
3140
3142
  try:
3141
- fs = input("Enter new font size (q=cancel): ").strip()
3143
+ cur_size = plt.rcParams.get('font.size', None)
3144
+ fs = input(f"Enter new font size (current: {cur_size}, q=cancel): ").strip()
3142
3145
  if not fs or fs.lower() == 'q':
3143
3146
  print("Canceled.")
3144
3147
  else:
@@ -3153,13 +3156,14 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
3153
3156
  print(f"Error changing font size: {e}")
3154
3157
  elif subkey == 'f':
3155
3158
  try:
3159
+ cur_family = plt.rcParams.get('font.sans-serif', [''])[0]
3156
3160
  print("Common publication fonts:")
3157
3161
  print(" 1) Arial")
3158
3162
  print(" 2) Helvetica")
3159
3163
  print(" 3) Times New Roman")
3160
3164
  print(" 4) STIXGeneral")
3161
3165
  print(" 5) DejaVu Sans")
3162
- ft_raw = input("Enter font number or family name (q=cancel): ").strip()
3166
+ ft_raw = input(f"Enter font number or family name (current: '{cur_family}', q=cancel): ").strip()
3163
3167
  if not ft_raw or ft_raw.lower() == 'q':
3164
3168
  print("Canceled.")
3165
3169
  else:
@@ -1553,7 +1553,7 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
1553
1553
  # Create text annotations for coordinates
1554
1554
  coord_text = fig.text(0.02, 0.98, '', transform=fig.transFigure,
1555
1555
  verticalalignment='top',
1556
- fontsize=max(9, int(0.6 * mpl_plt.rcParams.get('font.size', 12))),
1556
+ fontsize=max(9, int(0.6 * mpl_plt.rcParams.get('font.size', 16))),
1557
1557
  color='0.15',
1558
1558
  bbox=dict(boxstyle='round,pad=0.25', fc='white', ec='0.7', alpha=0.8))
1559
1559
  except Exception as e:
batplot/session.py CHANGED
@@ -2868,15 +2868,23 @@ def load_cpc_session(filename: str):
2868
2868
  fw, fh = fig.get_size_inches()
2869
2869
  fx = 0.5 + float(xy_in[0]) / float(fw)
2870
2870
  fy = 0.5 + float(xy_in[1]) / float(fh)
2871
- leg = ax.legend(H, L, loc='center', bbox_to_anchor=(fx, fy), bbox_transform=fig.transFigure, borderaxespad=1.0)
2871
+ # Use same spacing parameters as _legend_no_frame for consistent legend appearance
2872
+ leg = ax.legend(H, L, loc='center', bbox_to_anchor=(fx, fy), bbox_transform=fig.transFigure,
2873
+ handlelength=1.0, handletextpad=0.35, labelspacing=0.25,
2874
+ borderaxespad=0.5, borderpad=0.3, columnspacing=0.6,
2875
+ labelcolor='linecolor', frameon=False)
2872
2876
  # persist inches on fig for interactive menu
2873
2877
  try:
2874
2878
  fig._cpc_legend_xy_in = (float(xy_in[0]), float(xy_in[1]))
2875
2879
  except Exception:
2876
2880
  pass
2877
2881
  else:
2878
- leg = ax.legend(H, L, loc='best', borderaxespad=1.0)
2879
- # Always hide legend frame to match interactive export behavior
2882
+ # Use same spacing parameters as _legend_no_frame for consistent legend appearance
2883
+ leg = ax.legend(H, L, loc='best',
2884
+ handlelength=1.0, handletextpad=0.35, labelspacing=0.25,
2885
+ borderaxespad=0.5, borderpad=0.3, columnspacing=0.6,
2886
+ labelcolor='linecolor', frameon=False)
2887
+ # Ensure legend frame is off (redundant but safe)
2880
2888
  try:
2881
2889
  if leg is not None:
2882
2890
  leg.set_frame_on(False)
batplot/ui.py CHANGED
@@ -611,7 +611,7 @@ def resize_plot_frame(fig, ax, y_data_list: List, label_text_objects: List, args
611
611
  ax_bbox = ax.get_position()
612
612
  cur_ax_w_in = ax_bbox.width * fig_w_in
613
613
  cur_ax_h_in = ax_bbox.height * fig_h_in
614
- print(f"Current canvas (fixed): {fig_w_in:.2f} x {fig_h_in:.2f} in")
614
+ print(f"Current canvas: {fig_w_in:.2f} x {fig_h_in:.2f} in")
615
615
  print(f"Current plot frame: {cur_ax_w_in:.2f} x {cur_ax_h_in:.2f} in (W x H)")
616
616
  try:
617
617
  spec = input("Enter new plot frame size (e.g. '6 4', '6x4', 'w=6 h=4', 'scale=1.2', single width, q=back): ").strip().lower()
@@ -651,16 +651,9 @@ def resize_plot_frame(fig, ax, y_data_list: List, label_text_objects: List, args
651
651
  print("Could not parse specification.")
652
652
  continue
653
653
  req_w_in, req_h_in = new_w_in, new_h_in
654
- min_margin_frac = 0.05
655
- max_w_in = fig_w_in * (1 - 2 * min_margin_frac)
656
- max_h_in = fig_h_in * (1 - 2 * min_margin_frac)
657
- if new_w_in > max_w_in:
658
- print(f"Requested width {new_w_in:.2f} exceeds max {max_w_in:.2f}; clamped.")
659
- new_w_in = max_w_in
660
- if new_h_in > max_h_in:
661
- print(f"Requested height {new_h_in:.2f} exceeds max {max_h_in:.2f}; clamped.")
662
- new_h_in = max_h_in
663
- min_ax_in = 0.25
654
+ # Apply exact requested size without any clamping
655
+ # Only enforce minimum size to prevent division by zero
656
+ min_ax_in = 0.01
664
657
  new_w_in = max(min_ax_in, new_w_in)
665
658
  new_h_in = max(min_ax_in, new_h_in)
666
659
  tol = 1e-3
@@ -676,33 +669,24 @@ def resize_plot_frame(fig, ax, y_data_list: List, label_text_objects: List, args
676
669
  lm, bm, rm, tm = fig._last_user_margins
677
670
  fig.subplots_adjust(left=lm, bottom=bm, right=rm, top=tm)
678
671
  update_labels_func(ax, y_data_list, label_text_objects, args.stack)
679
- if not ensure_text_visibility(fig, ax, label_text_objects, check_only=True):
680
- fig.canvas.draw_idle()
681
- print(f"Plot frame unchanged ({new_w_in:.2f} x {new_h_in:.2f} in); layout preserved.")
682
- continue
672
+ fig.canvas.draw_idle()
673
+ print(f"Plot frame unchanged ({new_w_in:.2f} x {new_h_in:.2f} in); layout preserved.")
674
+ continue
683
675
  left = (1 - w_frac) / 2
684
676
  right = left + w_frac
685
677
  bottom = (1 - h_frac) / 2
686
678
  top = bottom + h_frac
687
- left = max(min_margin_frac, left)
688
- bottom = max(min_margin_frac, bottom)
689
- right = min(1 - min_margin_frac, right)
690
- top = min(1 - min_margin_frac, top)
691
- if right - left < 0.05 or top - bottom < 0.05:
692
- print("Requested frame too small after safety clamps; aborting.")
693
- else:
694
- fig.subplots_adjust(left=left, right=right, bottom=bottom, top=top)
679
+ # Apply exact size without margin clamping
680
+ fig.subplots_adjust(left=left, right=right, bottom=bottom, top=top)
695
681
  update_labels_func(ax, y_data_list, label_text_objects, args.stack)
696
- ensure_text_visibility(fig, ax, label_text_objects)
682
+ # Store the final size (exactly as requested, no text visibility adjustments)
697
683
  sp = fig.subplotpars
698
- fig._last_user_axes_inches = (((sp.right - sp.left) * fig_w_in), ((sp.top - sp.bottom) * fig_h_in))
684
+ fig._last_user_axes_inches = (new_w_in, new_h_in)
699
685
  fig._last_user_margins = (sp.left, sp.bottom, sp.right, sp.top)
700
686
  final_w_in = (sp.right - sp.left) * fig_w_in
701
687
  final_h_in = (sp.top - sp.bottom) * fig_h_in
702
- if requesting_full_canvas:
703
- print(f"Requested full-canvas frame. Canvas remains {fig_w_in:.2f} x {fig_h_in:.2f} in; frame now {final_w_in:.2f} x {final_h_in:.2f} in (maximum with minimum margins {min_margin_frac*100:.0f}%).")
704
- else:
705
- print(f"Plot frame set to {final_w_in:.2f} x {final_h_in:.2f} in inside fixed canvas {fig_w_in:.2f} x {fig_h_in:.2f} in.")
688
+ # Show the requested size (which is what was applied)
689
+ print(f"Plot frame set to {req_w_in:.2f} x {req_h_in:.2f} in inside canvas {fig_w_in:.2f} x {fig_h_in:.2f} in.")
706
690
  except KeyboardInterrupt:
707
691
  print("Canceled.")
708
692
  return
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: batplot
3
- Version: 1.7.25
3
+ Version: 1.7.26
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=2qXM_ch4J6g2wG6kjsgmtes4tumgb-iIPYbAIvlfOM0,119
1
+ batplot/__init__.py,sha256=l-iAn_Q1KA7sJv2vOZzjjw4K2UWfntwGpQk9Z3lyuRw,119
2
2
  batplot/args.py,sha256=6g1eHVsycDSAenwrXuCTcyuXCy_-30zy1lWtdguBG2s,34983
3
3
  batplot/batch.py,sha256=YQ7obCIqLCObwDbM7TXpOBh7g7BO95wZNsa2Fy84c6o,53858
4
- batplot/batplot.py,sha256=8cSAOZphoecINZMpYuetq-rrSyg_zmRfV08VtvX4_B8,170723
4
+ batplot/batplot.py,sha256=40lU1nY1NqeAOpzNG_vLF_L34COKhiA19pMpbvA3SJc,171885
5
5
  batplot/cif.py,sha256=JfHwNf3SHrcpALc_F5NjJmQ3lg71MBRSaIUJjGYPTx8,30120
6
6
  batplot/cli.py,sha256=ScDb2je8VQ0mz_z0SLCHEigiTuFPY5pb1snnzCouKms,5828
7
- batplot/color_utils.py,sha256=ow2ElqjIWFLRdrnLwQvrnfa3w3IEB0FodPFdoDQR_Dc,19990
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=90c-Rd9zcLIsL7mBb3gBDw4AnaWd9KnDtln9mhVKhNo,225252
11
- batplot/electrochem_interactive.py,sha256=S7UmgZAMCD0sRGPW7xRxwOaHV5_vkuwxZSegWJHxJxI,217258
12
- batplot/interactive.py,sha256=u0rDbxfjL3LHpAPUL3t6zUp94e-fJEA5_ApXTFfHflA,203616
10
+ batplot/cpc_interactive.py,sha256=YGt-TLfO5W_YyUdIInfW6y6bZxQJyfeGX7JGBv1kNbs,232634
11
+ batplot/electrochem_interactive.py,sha256=n_Jc9shH4LIL3r6z3MXnx02ZddMKZoh4dg25hHhfJRw,218297
12
+ batplot/interactive.py,sha256=johjaK8Er1y3rc5Cvg0C3Lv8Cqf2IliOyYrSnSrCzW4,203997
13
13
  batplot/manual.py,sha256=pbRI6G4Pm12pOW8LrOLWWu7IEOtqWN3tRHtgge50LlA,11556
14
14
  batplot/modes.py,sha256=qE2OsOQQKhwOWene5zxJeuuewTrZxubtahQuz5je7ok,37252
15
15
  batplot/operando.py,sha256=CdTZJa6Cr1wNczFEbwAido2mc7C_h1xxoQ5b045ktSk,28105
16
- batplot/operando_ec_interactive.py,sha256=a9OpAguBznUf9p642OyIzya-1AQJKWUO4pqjo7JNHEQ,293096
16
+ batplot/operando_ec_interactive.py,sha256=BOFj1E7H7b1wW0_pNwYCf7e2E70HemYzl1UjHihxB68,293096
17
17
  batplot/plotting.py,sha256=hG2_EdDhF1Qpn1XfZKdCQ5-w_m9gUYFbr804UQ5QjsU,10841
18
18
  batplot/readers.py,sha256=kAI0AvYrdfGRZkvADJ4riN96IWtrH24aAoZpBtONTbw,112960
19
- batplot/session.py,sha256=1DxwzxnTD_w9nrUWi-aIsBd_3bgfo4xchQGe0nd71Dg,131533
19
+ batplot/session.py,sha256=FEWYHu1XUIrWxD3an5m7HB57pHst2CHgJ_brAmCBk38,132199
20
20
  batplot/style.py,sha256=ZeRJ15fneSQqCYN_SGap-9Y2J8UkzRxYmf6qLJA6zMo,62058
21
- batplot/ui.py,sha256=MIY2x_ghCYxjdYhjMUZsMMnQEUBLgrIT37hfPGZf_cs,36320
21
+ batplot/ui.py,sha256=ifpbK74juUzLMCt-sJGVaWtpDb1NMRJzs2YyiwwafzY,35302
22
22
  batplot/utils.py,sha256=3dBZALWiCu5c6uc5MBII7n8329BZjieTEw4qithTlow,33939
23
23
  batplot/version_check.py,sha256=OG4LuHo5-rSqLLHQo5nWbX9lbNq6NyxRdvVUUcJRBqQ,6219
24
24
  batplot/data/USER_MANUAL.md,sha256=VYPvNZt3Fy8Z4Izr2FnQBw9vEaFTPkybhHDnF-OuKws,17694
25
- batplot-1.7.25.dist-info/licenses/LICENSE,sha256=2PAnHeCiTfgI7aKZLWr0G56HI9fGKQ0CEbQ02H-yExQ,1065
25
+ batplot-1.7.26.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
@@ -45,8 +45,8 @@ batplot_backup_20251121_223043/style.py,sha256=xg-tj6bEbFUVjjxYMokiLehS4tSfKanLI
45
45
  batplot_backup_20251121_223043/ui.py,sha256=K0XZWyiuBRNkFod9mgZyJ9CLN78GR1-hh6EznnIb5S8,31208
46
46
  batplot_backup_20251121_223043/utils.py,sha256=jydA0JxsCWWAudXEwSjlxTG17y2F8U6hIAukAzi1P0g,32526
47
47
  batplot_backup_20251121_223043/version_check.py,sha256=vlHkGkgUJcD_Z4KZmwonxZvKZh0MwHLaBSxaLPc66AQ,4555
48
- batplot-1.7.25.dist-info/METADATA,sha256=AyVvcD6JyoG0Bl2AAvNtw0YVI9P6vHZAhqFJQQu-KYM,7407
49
- batplot-1.7.25.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
50
- batplot-1.7.25.dist-info/entry_points.txt,sha256=73GgH3Zs-qGIvgiyQLgGsSW-ryOwPPKHveOW6TDIR5Q,82
51
- batplot-1.7.25.dist-info/top_level.txt,sha256=CgqK4RpsYnUFAcqO4bLOnEhCoPY4IPEGLPkiDlzLIxg,39
52
- batplot-1.7.25.dist-info/RECORD,,
48
+ batplot-1.7.26.dist-info/METADATA,sha256=nuvFZX39gTf0X-Dxff9jzQur4tLBTpRPuE55CPiYEdA,7407
49
+ batplot-1.7.26.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
50
+ batplot-1.7.26.dist-info/entry_points.txt,sha256=73GgH3Zs-qGIvgiyQLgGsSW-ryOwPPKHveOW6TDIR5Q,82
51
+ batplot-1.7.26.dist-info/top_level.txt,sha256=CgqK4RpsYnUFAcqO4bLOnEhCoPY4IPEGLPkiDlzLIxg,39
52
+ batplot-1.7.26.dist-info/RECORD,,