batplot 1.7.26__tar.gz → 1.7.27__tar.gz
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-1.7.26/batplot.egg-info → batplot-1.7.27}/PKG-INFO +1 -1
- {batplot-1.7.26 → batplot-1.7.27}/batplot/__init__.py +1 -1
- {batplot-1.7.26 → batplot-1.7.27}/batplot/cpc_interactive.py +4 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot/electrochem_interactive.py +4 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot/interactive.py +4 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot/operando.py +3 -3
- {batplot-1.7.26 → batplot-1.7.27}/batplot/operando_ec_interactive.py +21 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot/session.py +18 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot/style.py +4 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot/utils.py +48 -0
- {batplot-1.7.26 → batplot-1.7.27/batplot.egg-info}/PKG-INFO +1 -1
- {batplot-1.7.26 → batplot-1.7.27}/pyproject.toml +1 -1
- {batplot-1.7.26 → batplot-1.7.27}/LICENSE +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/MANIFEST.in +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/README.md +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/USER_MANUAL.md +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot/args.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot/batch.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot/batplot.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot/cif.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot/cli.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot/color_utils.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot/config.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot/converters.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot/data/USER_MANUAL.md +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot/manual.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot/modes.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot/plotting.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot/readers.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot/ui.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot/version_check.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot.egg-info/SOURCES.txt +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot.egg-info/dependency_links.txt +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot.egg-info/entry_points.txt +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot.egg-info/requires.txt +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot.egg-info/top_level.txt +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/__init__.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/args.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/batch.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/batplot.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/cif.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/cli.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/color_utils.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/config.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/converters.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/cpc_interactive.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/electrochem_interactive.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/interactive.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/modes.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/operando.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/operando_ec_interactive.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/plotting.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/readers.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/session.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/style.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/ui.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/utils.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/batplot_backup_20251121_223043/version_check.py +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/setup.cfg +0 -0
- {batplot-1.7.26 → batplot-1.7.27}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: batplot
|
|
3
|
-
Version: 1.7.
|
|
3
|
+
Version: 1.7.27
|
|
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
|
|
@@ -2090,6 +2090,10 @@ def cpc_interactive_menu(fig, ax, ax2, sc_charge, sc_discharge, sc_eff, file_dat
|
|
|
2090
2090
|
if yn != 'y':
|
|
2091
2091
|
_print_menu(); continue
|
|
2092
2092
|
if target:
|
|
2093
|
+
# Ensure exact case is preserved (important for macOS case-insensitive filesystem)
|
|
2094
|
+
from .utils import ensure_exact_case_filename
|
|
2095
|
+
target = ensure_exact_case_filename(target)
|
|
2096
|
+
|
|
2093
2097
|
# Save current legend position before export (savefig can change layout)
|
|
2094
2098
|
saved_legend_pos = None
|
|
2095
2099
|
try:
|
|
@@ -1684,6 +1684,10 @@ 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
|
+
# Ensure exact case is preserved (important for macOS case-insensitive filesystem)
|
|
1688
|
+
from .utils import ensure_exact_case_filename
|
|
1689
|
+
target = ensure_exact_case_filename(target)
|
|
1690
|
+
|
|
1687
1691
|
# Save current legend position before export (savefig can change layout)
|
|
1688
1692
|
saved_legend_pos = None
|
|
1689
1693
|
try:
|
|
@@ -3709,6 +3709,10 @@ def interactive_menu(fig, ax, y_data_list, x_data_list, labels, orig_y,
|
|
|
3709
3709
|
if not export_target:
|
|
3710
3710
|
print("Export canceled.")
|
|
3711
3711
|
else:
|
|
3712
|
+
# Ensure exact case is preserved (important for macOS case-insensitive filesystem)
|
|
3713
|
+
from .utils import ensure_exact_case_filename
|
|
3714
|
+
export_target = ensure_exact_case_filename(export_target)
|
|
3715
|
+
|
|
3712
3716
|
# Temporarily remove numbering for export
|
|
3713
3717
|
for i, txt in enumerate(label_text_objects):
|
|
3714
3718
|
txt.set_text(labels[i])
|
|
@@ -386,7 +386,7 @@ def plot_operando_folder(folder: str, args) -> Tuple[plt.Figure, plt.Axes, Dict[
|
|
|
386
386
|
x_data, y_data, current_mA, x_label, y_label = result
|
|
387
387
|
# For EC-Lab files: x_label='Time (h)', y_label='Voltage (V)'
|
|
388
388
|
# For simple files: x_label could be 'Time(h)', 'time', etc.
|
|
389
|
-
# EC-Lab
|
|
389
|
+
# EC-Lab files: read_mpt_file already converts time from seconds to hours
|
|
390
390
|
# operando plots with voltage on X-axis and time on Y-axis
|
|
391
391
|
|
|
392
392
|
# Check if labels indicate time/voltage data (flexible matching)
|
|
@@ -400,8 +400,8 @@ def plot_operando_folder(folder: str, args) -> Tuple[plt.Figure, plt.Axes, Dict[
|
|
|
400
400
|
is_time_voltage = (has_time_in_x or has_time_in_y) and (has_voltage_in_x or has_voltage_in_y)
|
|
401
401
|
|
|
402
402
|
if x_label == 'Time (h)' and y_label == 'Voltage (V)':
|
|
403
|
-
# EC-Lab file:
|
|
404
|
-
time_h = np.asarray(x_data, float)
|
|
403
|
+
# EC-Lab file: time is already in hours from read_mpt_file, just swap axes
|
|
404
|
+
time_h = np.asarray(x_data, float) # Already in hours, no conversion needed
|
|
405
405
|
voltage_v = np.asarray(y_data, float)
|
|
406
406
|
x_data = voltage_v
|
|
407
407
|
y_data = time_h
|
|
@@ -1765,6 +1765,10 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
1765
1765
|
target = _co(target)
|
|
1766
1766
|
if not target:
|
|
1767
1767
|
print_menu(); continue
|
|
1768
|
+
# Ensure exact case is preserved (important for macOS case-insensitive filesystem)
|
|
1769
|
+
from .utils import ensure_exact_case_filename
|
|
1770
|
+
target = ensure_exact_case_filename(target)
|
|
1771
|
+
|
|
1768
1772
|
_, ext = os.path.splitext(target)
|
|
1769
1773
|
if ext.lower() == '.svg':
|
|
1770
1774
|
try:
|
|
@@ -2052,6 +2056,19 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2052
2056
|
print_menu(); continue
|
|
2053
2057
|
dump_operando_session(target, fig=fig, ax=ax, im=im, cbar=cbar, ec_ax=ec_ax, skip_confirm=True)
|
|
2054
2058
|
fig._last_session_save_path = target
|
|
2059
|
+
# Show the actual filename that was saved (in case of case differences on macOS)
|
|
2060
|
+
actual_name = os.path.basename(target)
|
|
2061
|
+
if os.path.exists(target):
|
|
2062
|
+
# Get the actual filename as stored on disk (for case-sensitive display)
|
|
2063
|
+
try:
|
|
2064
|
+
dir_files = os.listdir(folder)
|
|
2065
|
+
for f in dir_files:
|
|
2066
|
+
if f.lower() == actual_name.lower():
|
|
2067
|
+
actual_name = f
|
|
2068
|
+
break
|
|
2069
|
+
except Exception:
|
|
2070
|
+
pass
|
|
2071
|
+
print(f"Operando session saved to {os.path.join(folder, actual_name)}")
|
|
2055
2072
|
except Exception as e:
|
|
2056
2073
|
print(f"Save failed: {e}")
|
|
2057
2074
|
print_menu(); continue
|
|
@@ -3777,6 +3794,10 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
3777
3794
|
if yn != 'y':
|
|
3778
3795
|
target = None
|
|
3779
3796
|
if target:
|
|
3797
|
+
# Ensure exact case is preserved (important for macOS case-insensitive filesystem)
|
|
3798
|
+
from .utils import ensure_exact_case_filename
|
|
3799
|
+
target = ensure_exact_case_filename(target)
|
|
3800
|
+
|
|
3780
3801
|
with open(target, 'w', encoding='utf-8') as f:
|
|
3781
3802
|
json.dump(cfg, f, indent=2)
|
|
3782
3803
|
print(f"Exported style to {target}")
|
|
@@ -519,6 +519,10 @@ def dump_session(
|
|
|
519
519
|
if not target:
|
|
520
520
|
print("Session save canceled.")
|
|
521
521
|
return
|
|
522
|
+
# Ensure exact case is preserved (important for macOS case-insensitive filesystem)
|
|
523
|
+
from .utils import ensure_exact_case_filename
|
|
524
|
+
target = ensure_exact_case_filename(target)
|
|
525
|
+
|
|
522
526
|
with open(target, 'wb') as f:
|
|
523
527
|
pickle.dump(sess, f)
|
|
524
528
|
print(f"Session saved to {target}")
|
|
@@ -663,6 +667,16 @@ def dump_operando_session(
|
|
|
663
667
|
# Capture operando WASD state, spines, and tick widths
|
|
664
668
|
op_wasd_state = _capture_wasd_state(ax)
|
|
665
669
|
op_spines, op_ticks = _capture_spine_tick_widths(ax)
|
|
670
|
+
|
|
671
|
+
# Capture operando title offsets
|
|
672
|
+
op_title_offsets = {
|
|
673
|
+
'top_y': float(getattr(ax, '_top_xlabel_manual_offset_y_pts', 0.0) or 0.0),
|
|
674
|
+
'top_x': float(getattr(ax, '_top_xlabel_manual_offset_x_pts', 0.0) or 0.0),
|
|
675
|
+
'bottom_y': float(getattr(ax, '_bottom_xlabel_manual_offset_y_pts', 0.0) or 0.0),
|
|
676
|
+
'left_x': float(getattr(ax, '_left_ylabel_manual_offset_x_pts', 0.0) or 0.0),
|
|
677
|
+
'right_x': float(getattr(ax, '_right_ylabel_manual_offset_x_pts', 0.0) or 0.0),
|
|
678
|
+
'right_y': float(getattr(ax, '_right_ylabel_manual_offset_y_pts', 0.0) or 0.0),
|
|
679
|
+
}
|
|
666
680
|
|
|
667
681
|
# EC panel (optional)
|
|
668
682
|
ec_state = None
|
|
@@ -783,6 +797,10 @@ def dump_operando_session(
|
|
|
783
797
|
if not target:
|
|
784
798
|
print("Session save canceled.")
|
|
785
799
|
return
|
|
800
|
+
# Ensure exact case is preserved (important for macOS case-insensitive filesystem)
|
|
801
|
+
from .utils import ensure_exact_case_filename
|
|
802
|
+
target = ensure_exact_case_filename(target)
|
|
803
|
+
|
|
786
804
|
with open(target, 'wb') as f:
|
|
787
805
|
pickle.dump(sess, f)
|
|
788
806
|
print(f"Operando session saved to {target}")
|
|
@@ -787,6 +787,10 @@ def export_style_config(
|
|
|
787
787
|
print("Style export canceled.")
|
|
788
788
|
return None
|
|
789
789
|
|
|
790
|
+
# Ensure exact case is preserved (important for macOS case-insensitive filesystem)
|
|
791
|
+
from .utils import ensure_exact_case_filename
|
|
792
|
+
target_path = ensure_exact_case_filename(target_path)
|
|
793
|
+
|
|
790
794
|
with open(target_path, "w", encoding="utf-8") as f:
|
|
791
795
|
json.dump(cfg, f, indent=2)
|
|
792
796
|
print(f"Exported style to {target_path}")
|
|
@@ -777,6 +777,54 @@ def choose_save_path(file_paths: list, purpose: str = "saving") -> Optional[str]
|
|
|
777
777
|
return os.getcwd()
|
|
778
778
|
|
|
779
779
|
|
|
780
|
+
def ensure_exact_case_filename(target_path: str) -> str:
|
|
781
|
+
"""Ensure a file is saved with the exact case specified, even on case-insensitive filesystems.
|
|
782
|
+
|
|
783
|
+
This function handles case-insensitive filesystems (macOS, Windows) by ensuring that
|
|
784
|
+
if a file exists with different case, it is removed first so the new file can be created
|
|
785
|
+
with the exact case specified by the user.
|
|
786
|
+
|
|
787
|
+
On case-sensitive filesystems (Linux, Unix), this function is safe but has no effect
|
|
788
|
+
since files with different case are treated as different files.
|
|
789
|
+
|
|
790
|
+
Args:
|
|
791
|
+
target_path: The desired file path with exact case
|
|
792
|
+
|
|
793
|
+
Returns:
|
|
794
|
+
The same path (for compatibility)
|
|
795
|
+
"""
|
|
796
|
+
folder = os.path.dirname(target_path)
|
|
797
|
+
desired_basename = os.path.basename(target_path)
|
|
798
|
+
|
|
799
|
+
if not folder or not desired_basename:
|
|
800
|
+
return target_path
|
|
801
|
+
|
|
802
|
+
try:
|
|
803
|
+
# Check if file already exists with exact case
|
|
804
|
+
if os.path.exists(target_path):
|
|
805
|
+
# Check if the actual filename on disk matches the desired case
|
|
806
|
+
existing_files = os.listdir(folder)
|
|
807
|
+
for existing_file in existing_files:
|
|
808
|
+
# If same name (case-insensitive) but different case, we need to fix it
|
|
809
|
+
if existing_file.lower() == desired_basename.lower() and existing_file != desired_basename:
|
|
810
|
+
existing_path = os.path.join(folder, existing_file)
|
|
811
|
+
# Delete the existing file with wrong case
|
|
812
|
+
# This is safe on case-insensitive filesystems and has no effect on case-sensitive ones
|
|
813
|
+
try:
|
|
814
|
+
if os.path.exists(existing_path):
|
|
815
|
+
os.remove(existing_path)
|
|
816
|
+
except Exception:
|
|
817
|
+
# Ignore errors (e.g., permission issues, file in use)
|
|
818
|
+
pass
|
|
819
|
+
break
|
|
820
|
+
except Exception:
|
|
821
|
+
# If we can't check/list the directory, just return the path as-is
|
|
822
|
+
# This is safe and ensures we don't break on permission errors
|
|
823
|
+
pass
|
|
824
|
+
|
|
825
|
+
return target_path
|
|
826
|
+
|
|
827
|
+
|
|
780
828
|
def _normalize_extension(ext: str) -> str:
|
|
781
829
|
if not ext:
|
|
782
830
|
return ext
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: batplot
|
|
3
|
-
Version: 1.7.
|
|
3
|
+
Version: 1.7.27
|
|
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
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "batplot"
|
|
7
|
-
version = "1.7.
|
|
7
|
+
version = "1.7.27"
|
|
8
8
|
description = "Interactive plotting tool for material science (1D plot) and electrochemistry (GC, CV, dQ/dV, CPC, operando) with batch processing"
|
|
9
9
|
authors = [
|
|
10
10
|
{ name = "Tian Dai", email = "tianda@uio.no" }
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|