batplot 1.8.4__py3-none-any.whl → 1.8.5__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/args.py +22 -4
- batplot/batch.py +12 -0
- batplot/batplot.py +215 -73
- batplot/converters.py +170 -122
- batplot/cpc_interactive.py +33 -21
- batplot/data/USER_MANUAL.md +49 -0
- batplot/electrochem_interactive.py +63 -36
- batplot/interactive.py +1547 -73
- batplot/operando.py +22 -0
- batplot/operando_ec_interactive.py +232 -2
- batplot/session.py +24 -0
- batplot/style.py +89 -2
- {batplot-1.8.4.dist-info → batplot-1.8.5.dist-info}/METADATA +1 -1
- {batplot-1.8.4.dist-info → batplot-1.8.5.dist-info}/RECORD +19 -19
- {batplot-1.8.4.dist-info → batplot-1.8.5.dist-info}/WHEEL +1 -1
- {batplot-1.8.4.dist-info → batplot-1.8.5.dist-info}/licenses/LICENSE +0 -0
- {batplot-1.8.4.dist-info → batplot-1.8.5.dist-info}/entry_points.txt +0 -0
- {batplot-1.8.4.dist-info → batplot-1.8.5.dist-info}/top_level.txt +0 -0
batplot/operando.py
CHANGED
|
@@ -296,6 +296,28 @@ def plot_operando_folder(folder: str, args) -> Tuple[plt.Figure, plt.Axes, Dict[
|
|
|
296
296
|
# Result shape: (n_scans, n_x_points)
|
|
297
297
|
# Example: 50 scans × 1000 points = (50, 1000) array
|
|
298
298
|
Z = np.vstack(stack) # shape (n_scans, n_x)
|
|
299
|
+
|
|
300
|
+
# STEP 5.5: Apply first derivative if --1d or --2d flag is set
|
|
301
|
+
# This calculates dy/dx for each scan using np.gradient
|
|
302
|
+
if getattr(args, 'derivative_1d', False) or getattr(args, 'derivative_2d', False):
|
|
303
|
+
print("[operando] Applying first derivative (dy/dx) to each scan...")
|
|
304
|
+
Z_deriv = np.zeros_like(Z)
|
|
305
|
+
for i in range(Z.shape[0]):
|
|
306
|
+
row = Z[i, :]
|
|
307
|
+
# Calculate derivative using gradient (handles NaN gracefully in numpy 1.20+)
|
|
308
|
+
# Use the grid spacing for proper derivative calculation
|
|
309
|
+
dx = grid_x[1] - grid_x[0] if len(grid_x) > 1 else 1.0
|
|
310
|
+
# Replace NaN with interpolated values for gradient, then mask back
|
|
311
|
+
valid_mask = ~np.isnan(row)
|
|
312
|
+
if np.sum(valid_mask) > 1:
|
|
313
|
+
# For valid regions, calculate gradient
|
|
314
|
+
deriv = np.gradient(row, dx)
|
|
315
|
+
# Keep NaN where original was NaN
|
|
316
|
+
deriv[~valid_mask] = np.nan
|
|
317
|
+
Z_deriv[i, :] = deriv
|
|
318
|
+
else:
|
|
319
|
+
Z_deriv[i, :] = np.nan
|
|
320
|
+
Z = Z_deriv
|
|
299
321
|
|
|
300
322
|
# Detect an electrochemistry .mpt file in the same folder (if any)
|
|
301
323
|
# Filter out macOS resource fork files (starting with ._)
|
|
@@ -832,7 +832,8 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
832
832
|
"ox: X range",
|
|
833
833
|
"oy: Y range",
|
|
834
834
|
"oz: intensity range",
|
|
835
|
-
"or: rename"
|
|
835
|
+
"or: rename",
|
|
836
|
+
"pk: peak search"
|
|
836
837
|
]
|
|
837
838
|
col3 = [
|
|
838
839
|
"et: time range",
|
|
@@ -885,7 +886,8 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
885
886
|
"ox: X range",
|
|
886
887
|
"oy: Y range",
|
|
887
888
|
"oz: intensity range",
|
|
888
|
-
"or: rename"
|
|
889
|
+
"or: rename",
|
|
890
|
+
"pk: peak search"
|
|
889
891
|
]
|
|
890
892
|
col3 = [
|
|
891
893
|
"n: crosshair",
|
|
@@ -2285,6 +2287,234 @@ def operando_ec_interactive_menu(fig, ax, im, cbar, ec_ax, file_paths=None):
|
|
|
2285
2287
|
except Exception as e:
|
|
2286
2288
|
print(f"Save failed: {e}")
|
|
2287
2289
|
print_menu(); continue
|
|
2290
|
+
if cmd == 'pk':
|
|
2291
|
+
try:
|
|
2292
|
+
import os
|
|
2293
|
+
from .utils import choose_save_path
|
|
2294
|
+
try:
|
|
2295
|
+
from scipy.signal import find_peaks
|
|
2296
|
+
except ImportError:
|
|
2297
|
+
print("Error: scipy is required for peak finding. Install with: pip install scipy")
|
|
2298
|
+
print_menu(); continue
|
|
2299
|
+
|
|
2300
|
+
# Get operando data
|
|
2301
|
+
data_array = np.asarray(im.get_array(), dtype=float)
|
|
2302
|
+
if data_array.ndim != 2 or data_array.size == 0:
|
|
2303
|
+
print("Error: No operando data available.")
|
|
2304
|
+
print_menu(); continue
|
|
2305
|
+
|
|
2306
|
+
extent = im.get_extent() # (left, right, bottom, top)
|
|
2307
|
+
x0, x1, y0, y1 = extent
|
|
2308
|
+
x_min, x_max = (x0, x1) if x0 <= x1 else (x1, x0)
|
|
2309
|
+
y_min, y_max = (y0, y1) if y0 <= y1 else (y1, y0)
|
|
2310
|
+
|
|
2311
|
+
n_scans, n_x_points = data_array.shape
|
|
2312
|
+
|
|
2313
|
+
# Create x-axis array
|
|
2314
|
+
x_axis = np.linspace(x_min, x_max, n_x_points)
|
|
2315
|
+
|
|
2316
|
+
print("\nPeak Search Menu:")
|
|
2317
|
+
print(" 1: Find peaks in X range")
|
|
2318
|
+
print(" e: Explanation of peak searching")
|
|
2319
|
+
print(" q: Back to main menu")
|
|
2320
|
+
sub = _safe_input("Choose option: ").strip().lower()
|
|
2321
|
+
|
|
2322
|
+
if sub == 'e':
|
|
2323
|
+
print("\n" + "="*70)
|
|
2324
|
+
print("PEAK SEARCHING EXPLANATION")
|
|
2325
|
+
print("="*70)
|
|
2326
|
+
print("\nPeak searching identifies local maxima in diffraction patterns.")
|
|
2327
|
+
print("This is useful for tracking how peak positions change over time")
|
|
2328
|
+
print("(or scan number) in operando experiments.\n")
|
|
2329
|
+
print("HOW IT WORKS:")
|
|
2330
|
+
print("1. Select X range: Choose the region where you want to find peaks")
|
|
2331
|
+
print("2. For each scan (file):")
|
|
2332
|
+
print(" - Extract intensity profile in the selected X range")
|
|
2333
|
+
print(" - Find local maxima (peaks) using scipy.signal.find_peaks")
|
|
2334
|
+
print(" - Refine peak positions using quadratic interpolation")
|
|
2335
|
+
print("3. Export results: Peak positions vs file number saved to .txt file\n")
|
|
2336
|
+
print("PARAMETERS:")
|
|
2337
|
+
print("- Prominence: Minimum height of peak relative to surrounding baseline")
|
|
2338
|
+
print(" (Higher = fewer, stronger peaks)")
|
|
2339
|
+
print("- Distance: Minimum separation between peaks (in data points)")
|
|
2340
|
+
print(" (Larger = peaks must be further apart)")
|
|
2341
|
+
print("- Width: Minimum width of peak at half maximum")
|
|
2342
|
+
print(" (Larger = broader peaks only)\n")
|
|
2343
|
+
print("OUTPUT FORMAT:")
|
|
2344
|
+
print("The exported .txt file contains:")
|
|
2345
|
+
print(" Column 1: File number (scan index, 0-based)")
|
|
2346
|
+
print(" Column 2: Peak position (X-axis value)")
|
|
2347
|
+
print(" Column 3: Peak intensity (optional, if enabled)\n")
|
|
2348
|
+
print("="*70 + "\n")
|
|
2349
|
+
print_menu(); continue
|
|
2350
|
+
|
|
2351
|
+
if sub == 'q':
|
|
2352
|
+
print_menu(); continue
|
|
2353
|
+
|
|
2354
|
+
if sub == '1' or sub == '':
|
|
2355
|
+
# Get X range
|
|
2356
|
+
print(f"\nCurrent X range: {x_min:.6g} to {x_max:.6g}")
|
|
2357
|
+
print("Enter X range for peak search (min max), or press Enter to use full range:")
|
|
2358
|
+
x_range_input = _safe_input("X range: ").strip()
|
|
2359
|
+
|
|
2360
|
+
if x_range_input:
|
|
2361
|
+
try:
|
|
2362
|
+
parts = x_range_input.split()
|
|
2363
|
+
if len(parts) >= 2:
|
|
2364
|
+
x_range_min = float(parts[0])
|
|
2365
|
+
x_range_max = float(parts[1])
|
|
2366
|
+
else:
|
|
2367
|
+
print("Invalid format. Use: min max")
|
|
2368
|
+
print_menu(); continue
|
|
2369
|
+
except ValueError:
|
|
2370
|
+
print("Invalid number format.")
|
|
2371
|
+
print_menu(); continue
|
|
2372
|
+
else:
|
|
2373
|
+
x_range_min = x_min
|
|
2374
|
+
x_range_max = x_max
|
|
2375
|
+
|
|
2376
|
+
# Clamp to valid range
|
|
2377
|
+
x_range_min = max(x_min, min(x_max, x_range_min))
|
|
2378
|
+
x_range_max = max(x_min, min(x_max, x_range_max))
|
|
2379
|
+
if x_range_min >= x_range_max:
|
|
2380
|
+
print("Invalid range: min must be < max")
|
|
2381
|
+
print_menu(); continue
|
|
2382
|
+
|
|
2383
|
+
# Find column indices for X range
|
|
2384
|
+
col_min = int(np.argmin(np.abs(x_axis - x_range_min)))
|
|
2385
|
+
col_max = int(np.argmin(np.abs(x_axis - x_range_max)))
|
|
2386
|
+
if col_min > col_max:
|
|
2387
|
+
col_min, col_max = col_max, col_min
|
|
2388
|
+
col_max = min(col_max + 1, n_x_points) # Include endpoint
|
|
2389
|
+
|
|
2390
|
+
# Get parameters for peak finding
|
|
2391
|
+
print("\nPeak finding parameters:")
|
|
2392
|
+
prominence_input = _safe_input("Prominence (relative to max, default 0.1): ").strip()
|
|
2393
|
+
prominence = float(prominence_input) if prominence_input else 0.1
|
|
2394
|
+
|
|
2395
|
+
distance_input = _safe_input("Minimum distance between peaks (data points, default 5): ").strip()
|
|
2396
|
+
distance = int(distance_input) if distance_input else 5
|
|
2397
|
+
|
|
2398
|
+
width_input = _safe_input("Minimum peak width (data points, default 1, 0=disabled): ").strip()
|
|
2399
|
+
width = int(width_input) if width_input else 1
|
|
2400
|
+
|
|
2401
|
+
include_intensity = _safe_input("Include peak intensity in output? (y/n, default n): ").strip().lower() == 'y'
|
|
2402
|
+
|
|
2403
|
+
# Find peaks for each scan
|
|
2404
|
+
print(f"\nFinding peaks in X range [{x_range_min:.6g}, {x_range_max:.6g}]...")
|
|
2405
|
+
results = []
|
|
2406
|
+
|
|
2407
|
+
for scan_idx in range(n_scans):
|
|
2408
|
+
# Extract intensity profile for this scan in X range
|
|
2409
|
+
intensity_profile = data_array[scan_idx, col_min:col_max]
|
|
2410
|
+
x_profile = x_axis[col_min:col_max]
|
|
2411
|
+
|
|
2412
|
+
if len(intensity_profile) < 3:
|
|
2413
|
+
continue
|
|
2414
|
+
|
|
2415
|
+
# Find peaks
|
|
2416
|
+
try:
|
|
2417
|
+
# Calculate prominence threshold
|
|
2418
|
+
max_intensity = np.max(intensity_profile)
|
|
2419
|
+
min_intensity = np.min(intensity_profile)
|
|
2420
|
+
prominence_abs = (max_intensity - min_intensity) * prominence
|
|
2421
|
+
|
|
2422
|
+
peak_kwargs = {
|
|
2423
|
+
'prominence': prominence_abs if prominence_abs > 0 else None,
|
|
2424
|
+
'distance': max(1, distance),
|
|
2425
|
+
}
|
|
2426
|
+
if width > 0:
|
|
2427
|
+
peak_kwargs['width'] = width
|
|
2428
|
+
|
|
2429
|
+
# Remove None values
|
|
2430
|
+
peak_kwargs = {k: v for k, v in peak_kwargs.items() if v is not None}
|
|
2431
|
+
|
|
2432
|
+
peak_indices, peak_properties = find_peaks(intensity_profile, **peak_kwargs)
|
|
2433
|
+
|
|
2434
|
+
# Refine peak positions using quadratic interpolation
|
|
2435
|
+
for peak_idx in peak_indices:
|
|
2436
|
+
if peak_idx == 0 or peak_idx == len(intensity_profile) - 1:
|
|
2437
|
+
peak_x = x_profile[peak_idx]
|
|
2438
|
+
peak_intensity = intensity_profile[peak_idx]
|
|
2439
|
+
else:
|
|
2440
|
+
# Quadratic interpolation for sub-pixel accuracy
|
|
2441
|
+
y1 = intensity_profile[peak_idx - 1]
|
|
2442
|
+
y2 = intensity_profile[peak_idx]
|
|
2443
|
+
y3 = intensity_profile[peak_idx + 1]
|
|
2444
|
+
x1 = x_profile[peak_idx - 1]
|
|
2445
|
+
x2 = x_profile[peak_idx]
|
|
2446
|
+
x3 = x_profile[peak_idx + 1]
|
|
2447
|
+
|
|
2448
|
+
denom = (y1 - 2*y2 + y3)
|
|
2449
|
+
if abs(denom) > 1e-12:
|
|
2450
|
+
dx = 0.5 * (y1 - y3) / denom
|
|
2451
|
+
if -0.6 < dx < 0.6:
|
|
2452
|
+
peak_x = x2 + dx * (x3 - x1) / 2.0
|
|
2453
|
+
peak_intensity = y2 + 0.5 * dx * (y3 - y1)
|
|
2454
|
+
else:
|
|
2455
|
+
peak_x = x2
|
|
2456
|
+
peak_intensity = y2
|
|
2457
|
+
else:
|
|
2458
|
+
peak_x = x2
|
|
2459
|
+
peak_intensity = y2
|
|
2460
|
+
|
|
2461
|
+
if include_intensity:
|
|
2462
|
+
results.append((scan_idx, peak_x, peak_intensity))
|
|
2463
|
+
else:
|
|
2464
|
+
results.append((scan_idx, peak_x))
|
|
2465
|
+
except Exception as e:
|
|
2466
|
+
# Skip this scan if peak finding fails
|
|
2467
|
+
continue
|
|
2468
|
+
|
|
2469
|
+
if not results:
|
|
2470
|
+
print("No peaks found in the selected X range.")
|
|
2471
|
+
print_menu(); continue
|
|
2472
|
+
|
|
2473
|
+
# Save results
|
|
2474
|
+
folder = choose_save_path(file_paths, purpose="peak search export")
|
|
2475
|
+
if not folder:
|
|
2476
|
+
print_menu(); continue
|
|
2477
|
+
|
|
2478
|
+
print(f"\nChosen path: {folder}")
|
|
2479
|
+
fname = _safe_input("Export filename (default: peaks.txt): ").strip()
|
|
2480
|
+
if not fname:
|
|
2481
|
+
fname = "peaks.txt"
|
|
2482
|
+
if not fname.endswith('.txt'):
|
|
2483
|
+
fname += '.txt'
|
|
2484
|
+
|
|
2485
|
+
target = fname if os.path.isabs(fname) else os.path.join(folder, fname)
|
|
2486
|
+
if os.path.exists(target):
|
|
2487
|
+
yn = _safe_input(f"'{os.path.basename(target)}' exists. Overwrite? (y/n): ").strip().lower()
|
|
2488
|
+
if yn != 'y':
|
|
2489
|
+
print_menu(); continue
|
|
2490
|
+
|
|
2491
|
+
# Write results
|
|
2492
|
+
try:
|
|
2493
|
+
with open(target, 'w') as f:
|
|
2494
|
+
if include_intensity:
|
|
2495
|
+
f.write("# File number\tPeak position\tPeak intensity\n")
|
|
2496
|
+
for scan_idx, peak_x, peak_intensity in results:
|
|
2497
|
+
f.write(f"{scan_idx}\t{peak_x:.6f}\t{peak_intensity:.6f}\n")
|
|
2498
|
+
else:
|
|
2499
|
+
f.write("# File number\tPeak position\n")
|
|
2500
|
+
for result in results:
|
|
2501
|
+
if len(result) == 2:
|
|
2502
|
+
scan_idx, peak_x = result
|
|
2503
|
+
f.write(f"{scan_idx}\t{peak_x:.6f}\n")
|
|
2504
|
+
else:
|
|
2505
|
+
scan_idx, peak_x, _ = result
|
|
2506
|
+
f.write(f"{scan_idx}\t{peak_x:.6f}\n")
|
|
2507
|
+
print(f"Peak positions exported to {target}")
|
|
2508
|
+
print(f"Found {len(results)} peaks across {len(set(r[0] for r in results))} scans")
|
|
2509
|
+
except Exception as e:
|
|
2510
|
+
print(f"Error saving file: {e}")
|
|
2511
|
+
else:
|
|
2512
|
+
print("Invalid option.")
|
|
2513
|
+
except Exception as e:
|
|
2514
|
+
print(f"Error in peak search: {e}")
|
|
2515
|
+
import traceback
|
|
2516
|
+
traceback.print_exc()
|
|
2517
|
+
print_menu(); continue
|
|
2288
2518
|
if cmd == 'h':
|
|
2289
2519
|
# Always read fresh value from attribute to avoid stale cached value
|
|
2290
2520
|
ax_h_in = getattr(ax, '_fixed_ax_h_in', ax_h_in)
|
batplot/session.py
CHANGED
|
@@ -500,6 +500,30 @@ def dump_session(
|
|
|
500
500
|
'orig_y': [np.array(a) for a in orig_y],
|
|
501
501
|
'offsets': list(offsets_list),
|
|
502
502
|
'labels': list(labels),
|
|
503
|
+
# Processed data (for smooth/reduce operations)
|
|
504
|
+
'original_x_data_list': ([np.array(a) for a in getattr(fig, '_original_x_data_list', [])]
|
|
505
|
+
if hasattr(fig, '_original_x_data_list') else None),
|
|
506
|
+
'original_y_data_list': ([np.array(a) for a in getattr(fig, '_original_y_data_list', [])]
|
|
507
|
+
if hasattr(fig, '_original_y_data_list') else None),
|
|
508
|
+
'full_processed_x_data_list': ([np.array(a) for a in getattr(fig, '_full_processed_x_data_list', [])]
|
|
509
|
+
if hasattr(fig, '_full_processed_x_data_list') else None),
|
|
510
|
+
'full_processed_y_data_list': ([np.array(a) for a in getattr(fig, '_full_processed_y_data_list', [])]
|
|
511
|
+
if hasattr(fig, '_full_processed_y_data_list') else None),
|
|
512
|
+
'smooth_settings': (dict(getattr(fig, '_smooth_settings', {}))
|
|
513
|
+
if hasattr(fig, '_smooth_settings') else None),
|
|
514
|
+
'last_smooth_settings': (dict(getattr(fig, '_last_smooth_settings', {}))
|
|
515
|
+
if hasattr(fig, '_last_smooth_settings') else None),
|
|
516
|
+
# Derivative data (for derivative operations)
|
|
517
|
+
'pre_derivative_x_data_list': ([np.array(a) for a in getattr(fig, '_pre_derivative_x_data_list', [])]
|
|
518
|
+
if hasattr(fig, '_pre_derivative_x_data_list') else None),
|
|
519
|
+
'pre_derivative_y_data_list': ([np.array(a) for a in getattr(fig, '_pre_derivative_y_data_list', [])]
|
|
520
|
+
if hasattr(fig, '_pre_derivative_y_data_list') else None),
|
|
521
|
+
'pre_derivative_ylabel': (str(getattr(fig, '_pre_derivative_ylabel', ''))
|
|
522
|
+
if hasattr(fig, '_pre_derivative_ylabel') else None),
|
|
523
|
+
'derivative_order': (int(getattr(fig, '_derivative_order', 0))
|
|
524
|
+
if hasattr(fig, '_derivative_order') else None),
|
|
525
|
+
'derivative_reversed': (bool(getattr(fig, '_derivative_reversed', False))
|
|
526
|
+
if hasattr(fig, '_derivative_reversed') else None),
|
|
503
527
|
'line_styles': [
|
|
504
528
|
{
|
|
505
529
|
'color': ln.get_color(),
|
batplot/style.py
CHANGED
|
@@ -451,7 +451,19 @@ def print_style_info(
|
|
|
451
451
|
except Exception:
|
|
452
452
|
pass
|
|
453
453
|
|
|
454
|
-
#
|
|
454
|
+
# CIF hkl label visibility
|
|
455
|
+
if show_cif_hkl is not None:
|
|
456
|
+
print(f"CIF hkl labels: {'shown' if show_cif_hkl else 'hidden'}")
|
|
457
|
+
elif cif_tick_series:
|
|
458
|
+
# Try to read from __main__ module if not provided
|
|
459
|
+
try:
|
|
460
|
+
import sys
|
|
461
|
+
_bp_module = sys.modules.get('__main__')
|
|
462
|
+
if _bp_module is not None and hasattr(_bp_module, 'show_cif_hkl'):
|
|
463
|
+
hkl_state = bool(getattr(_bp_module, 'show_cif_hkl', False))
|
|
464
|
+
print(f"CIF hkl labels: {'shown' if hkl_state else 'hidden'}")
|
|
465
|
+
except Exception:
|
|
466
|
+
pass
|
|
455
467
|
|
|
456
468
|
# Omit non-style global flags (mode/raw/autoscale/delta)
|
|
457
469
|
|
|
@@ -670,6 +682,14 @@ def export_style_config(
|
|
|
670
682
|
# Save CIF title visibility
|
|
671
683
|
if show_cif_titles is not None:
|
|
672
684
|
cfg["show_cif_titles"] = bool(show_cif_titles)
|
|
685
|
+
# Save CIF hkl label visibility (read from __main__ module if available)
|
|
686
|
+
try:
|
|
687
|
+
import sys
|
|
688
|
+
_bp_module = sys.modules.get('__main__')
|
|
689
|
+
if _bp_module is not None and hasattr(_bp_module, 'show_cif_hkl'):
|
|
690
|
+
cfg["show_cif_hkl"] = bool(getattr(_bp_module, 'show_cif_hkl', False))
|
|
691
|
+
except Exception:
|
|
692
|
+
pass
|
|
673
693
|
if cif_tick_series:
|
|
674
694
|
cfg["cif_ticks"] = [
|
|
675
695
|
{"index": i, "color": color}
|
|
@@ -692,6 +712,20 @@ def export_style_config(
|
|
|
692
712
|
if serialized_palettes:
|
|
693
713
|
cfg['curve_palettes'] = serialized_palettes
|
|
694
714
|
|
|
715
|
+
# Store smooth settings (metadata only, not full arrays)
|
|
716
|
+
if hasattr(fig, '_smooth_settings'):
|
|
717
|
+
cfg['smooth_settings'] = dict(fig._smooth_settings)
|
|
718
|
+
if hasattr(fig, '_last_smooth_settings'):
|
|
719
|
+
cfg['last_smooth_settings'] = dict(fig._last_smooth_settings)
|
|
720
|
+
# Store derivative order (metadata only)
|
|
721
|
+
if hasattr(fig, '_derivative_order'):
|
|
722
|
+
cfg['derivative_order'] = int(fig._derivative_order)
|
|
723
|
+
if hasattr(fig, '_derivative_reversed'):
|
|
724
|
+
cfg['derivative_reversed'] = bool(fig._derivative_reversed)
|
|
725
|
+
# Note: We don't store original_x_data_list/original_y_data_list or pre_derivative data in style files
|
|
726
|
+
# as style files are for styling only, and the data would be specific
|
|
727
|
+
# to the dataset. Session files (pickle) store this data instead.
|
|
728
|
+
|
|
695
729
|
# If overwrite_path is provided, determine export type from existing file
|
|
696
730
|
if overwrite_path:
|
|
697
731
|
try:
|
|
@@ -1230,8 +1264,61 @@ def apply_style_config(
|
|
|
1230
1264
|
setattr(_bp_module, 'show_cif_titles', bool(cfg["show_cif_titles"]))
|
|
1231
1265
|
except Exception:
|
|
1232
1266
|
pass
|
|
1267
|
+
# Restore CIF hkl label visibility
|
|
1268
|
+
if "show_cif_hkl" in cfg:
|
|
1269
|
+
try:
|
|
1270
|
+
_bp_module = sys.modules.get('__main__')
|
|
1271
|
+
if _bp_module is not None:
|
|
1272
|
+
setattr(_bp_module, 'show_cif_hkl', bool(cfg["show_cif_hkl"]))
|
|
1273
|
+
# Also update _bp object if available
|
|
1274
|
+
if cif_tick_series is not None:
|
|
1275
|
+
# Try to update via interactive menu's _bp object
|
|
1276
|
+
try:
|
|
1277
|
+
import sys
|
|
1278
|
+
_bp_obj = getattr(sys.modules.get('__main__'), '_bp', None)
|
|
1279
|
+
if _bp_obj is not None:
|
|
1280
|
+
setattr(_bp_obj, 'show_cif_hkl', bool(cfg["show_cif_hkl"]))
|
|
1281
|
+
except Exception:
|
|
1282
|
+
pass
|
|
1283
|
+
except Exception:
|
|
1284
|
+
pass
|
|
1285
|
+
# Restore smooth settings (metadata only, not full arrays)
|
|
1286
|
+
if "smooth_settings" in cfg:
|
|
1287
|
+
try:
|
|
1288
|
+
fig._smooth_settings = dict(cfg["smooth_settings"])
|
|
1289
|
+
except Exception:
|
|
1290
|
+
pass
|
|
1291
|
+
elif hasattr(fig, '_smooth_settings'):
|
|
1292
|
+
delattr(fig, '_smooth_settings')
|
|
1293
|
+
if "last_smooth_settings" in cfg:
|
|
1294
|
+
try:
|
|
1295
|
+
fig._last_smooth_settings = dict(cfg["last_smooth_settings"])
|
|
1296
|
+
except Exception:
|
|
1297
|
+
pass
|
|
1298
|
+
elif hasattr(fig, '_last_smooth_settings'):
|
|
1299
|
+
delattr(fig, '_last_smooth_settings')
|
|
1300
|
+
# Restore derivative order (metadata only)
|
|
1301
|
+
if "derivative_order" in cfg:
|
|
1302
|
+
try:
|
|
1303
|
+
order = int(cfg["derivative_order"])
|
|
1304
|
+
fig._derivative_order = order
|
|
1305
|
+
is_reversed = cfg.get("derivative_reversed", False)
|
|
1306
|
+
if "derivative_reversed" in cfg:
|
|
1307
|
+
fig._derivative_reversed = bool(cfg["derivative_reversed"])
|
|
1308
|
+
# Update y-axis label based on derivative order
|
|
1309
|
+
from .interactive import _update_ylabel_for_derivative
|
|
1310
|
+
current_ylabel = ax.get_ylabel() or ""
|
|
1311
|
+
new_ylabel = _update_ylabel_for_derivative(order, current_ylabel, is_reversed=is_reversed)
|
|
1312
|
+
ax.set_ylabel(new_ylabel)
|
|
1313
|
+
except Exception:
|
|
1314
|
+
pass
|
|
1315
|
+
elif hasattr(fig, '_derivative_order'):
|
|
1316
|
+
delattr(fig, '_derivative_order')
|
|
1317
|
+
# Note: We don't restore original_x_data_list/original_y_data_list or pre_derivative data from style files
|
|
1318
|
+
# as style files are for styling only, and the data would be specific
|
|
1319
|
+
# to the dataset. Session files (pickle) store this data instead.
|
|
1233
1320
|
# Redraw CIF ticks after applying changes
|
|
1234
|
-
if (cif_cfg and cif_tick_series is not None) or "show_cif_titles" in cfg:
|
|
1321
|
+
if (cif_cfg and cif_tick_series is not None) or "show_cif_titles" in cfg or "show_cif_hkl" in cfg:
|
|
1235
1322
|
if hasattr(ax, "_cif_draw_func"):
|
|
1236
1323
|
try:
|
|
1237
1324
|
ax._cif_draw_func()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: batplot
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.5
|
|
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=
|
|
2
|
-
batplot/args.py,sha256=
|
|
3
|
-
batplot/batch.py,sha256=
|
|
4
|
-
batplot/batplot.py,sha256
|
|
1
|
+
batplot/__init__.py,sha256=6mfbpfSzbSfjCLrvmBzBMKmDyiFSBUJlcB8Qqv6o26s,118
|
|
2
|
+
batplot/args.py,sha256=DGTe2PKmJnI8Iq12QgO76V8lZvWhMOqY14gsyE5SgEs,37001
|
|
3
|
+
batplot/batch.py,sha256=hqLNvd88OLd0PLo_ot6JjC3FM6wwxCJ1jO2J63f9Zyg,55899
|
|
4
|
+
batplot/batplot.py,sha256=-mAf1aW7bniyfQ5DCorqyOr-OcRtUgRtq6TZHKk5xCU,184599
|
|
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
|
-
batplot/converters.py,sha256=
|
|
10
|
-
batplot/cpc_interactive.py,sha256
|
|
11
|
-
batplot/electrochem_interactive.py,sha256=
|
|
12
|
-
batplot/interactive.py,sha256=
|
|
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
|
|
13
13
|
batplot/manual.py,sha256=pbRI6G4Pm12pOW8LrOLWWu7IEOtqWN3tRHtgge50LlA,11556
|
|
14
14
|
batplot/modes.py,sha256=qE2OsOQQKhwOWene5zxJeuuewTrZxubtahQuz5je7ok,37252
|
|
15
|
-
batplot/operando.py,sha256=
|
|
16
|
-
batplot/operando_ec_interactive.py,sha256=
|
|
15
|
+
batplot/operando.py,sha256=h09xu1BsdR68YlzhWeUSypYX83DzjJABIQQS2noQzPI,29400
|
|
16
|
+
batplot/operando_ec_interactive.py,sha256=YExiuKn-qQksW3YFYCTpvumuCit4cc4YiiaSRWGa0og,317833
|
|
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=sgcJyCj00lOhmIRdDxGSqu2vEpOm7WSFZzLXxukYNL0,144936
|
|
20
|
+
batplot/style.py,sha256=3XnWlU9aTb1b-aiq5BQOuAREE5nOEYZ0b75v_LS0xDM,67790
|
|
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
|
-
batplot/data/USER_MANUAL.md,sha256=
|
|
25
|
-
batplot-1.8.
|
|
24
|
+
batplot/data/USER_MANUAL.md,sha256=w6pmDXoLINFkCWWh3zay7uNIxUaDxSOrocnPIZwu2uA,19542
|
|
25
|
+
batplot-1.8.5.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.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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|