batplot 1.8.44__tar.gz → 1.8.46__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.
- {batplot-1.8.44 → batplot-1.8.46}/DEVELOPING.md +15 -1
- batplot-1.8.46/MANIFEST.in +4 -0
- {batplot-1.8.44 → batplot-1.8.46}/PKG-INFO +87 -5
- {batplot-1.8.44 → batplot-1.8.46}/README.md +86 -4
- {batplot-1.8.44 → batplot-1.8.46}/batplot/__init__.py +1 -1
- batplot-1.8.46/batplot/_mpl_backend.py +280 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/args.py +73 -5
- {batplot-1.8.44 → batplot-1.8.46}/batplot/batch.py +261 -12
- {batplot-1.8.44 → batplot-1.8.46}/batplot/batplot.py +33 -74
- {batplot-1.8.44 → batplot-1.8.46}/batplot/canvas_interactive.py +6 -2
- {batplot-1.8.44 → batplot-1.8.46}/batplot/cli.py +12 -0
- batplot-1.8.46/batplot/cli_save.py +375 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/color_utils.py +6 -21
- {batplot-1.8.44 → batplot-1.8.46}/batplot/converters.py +3 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/data/CHANGELOG.md +8 -0
- batplot-1.8.46/batplot/data/latest_release_notes.json +7 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/dev_upgrade.py +457 -142
- batplot-1.8.46/batplot/plot_modes/batch_session/__init__.py +5 -0
- batplot-1.8.46/batplot/plot_modes/batch_session/batch_commands.py +128 -0
- batplot-1.8.46/batplot/plot_modes/batch_session/batch_io.py +178 -0
- batplot-1.8.46/batplot/plot_modes/batch_session/common.py +139 -0
- batplot-1.8.46/batplot/plot_modes/batch_session/kinds.py +45 -0
- batplot-1.8.46/batplot/plot_modes/batch_session/load.py +204 -0
- batplot-1.8.46/batplot/plot_modes/batch_session/menu_cpc.py +291 -0
- batplot-1.8.46/batplot/plot_modes/batch_session/menu_ec.py +318 -0
- batplot-1.8.46/batplot/plot_modes/batch_session/menu_histo.py +407 -0
- batplot-1.8.46/batplot/plot_modes/batch_session/menu_operando.py +292 -0
- batplot-1.8.46/batplot/plot_modes/batch_session/menu_xy.py +429 -0
- batplot-1.8.46/batplot/plot_modes/batch_session/routing.py +77 -0
- batplot-1.8.46/batplot/plot_modes/batch_session/xy_batch_helpers.py +171 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/common/palettes.py +5 -3
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/common/spines.py +9 -2
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/cpc/colors.py +4 -3
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/cpc/interactive.py +2 -2
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/cpc/legend.py +2 -2
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/cpc/routing.py +62 -43
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/electrochem/colors.py +17 -10
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/electrochem/dqdv_2d.py +1 -1
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/electrochem/interactive.py +2 -2
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/electrochem/routing.py +129 -105
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/electrochem/style.py +2 -2
- batplot-1.8.46/batplot/plot_modes/histo/__init__.py +5 -0
- batplot-1.8.46/batplot/plot_modes/histo/actions.py +436 -0
- batplot-1.8.46/batplot/plot_modes/histo/colors.py +200 -0
- batplot-1.8.46/batplot/plot_modes/histo/density_curve.py +152 -0
- batplot-1.8.46/batplot/plot_modes/histo/fonts.py +77 -0
- batplot-1.8.46/batplot/plot_modes/histo/interactive.py +502 -0
- batplot-1.8.46/batplot/plot_modes/histo/labels.py +101 -0
- batplot-1.8.46/batplot/plot_modes/histo/load.py +208 -0
- batplot-1.8.46/batplot/plot_modes/histo/plot.py +239 -0
- batplot-1.8.46/batplot/plot_modes/histo/routing.py +353 -0
- batplot-1.8.46/batplot/plot_modes/histo/session.py +61 -0
- batplot-1.8.46/batplot/plot_modes/histo/spines.py +291 -0
- batplot-1.8.46/batplot/plot_modes/histo/toggles.py +174 -0
- batplot-1.8.46/batplot/plot_modes/histo/wizard.py +188 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/operando/colors.py +4 -5
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/operando/interactive.py +8 -6
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/operando/labels.py +1 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/operando/plot.py +24 -12
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/operando/routing.py +42 -34
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/operando/style.py +2 -2
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/session_routing.py +70 -56
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/xy/interactive.py +2 -2
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/xy/pipeline.py +59 -28
- {batplot-1.8.44 → batplot-1.8.46}/batplot/readers.py +26 -7
- {batplot-1.8.44 → batplot-1.8.46}/batplot/session.py +7 -7
- {batplot-1.8.44 → batplot-1.8.46}/batplot/version_check.py +8 -7
- {batplot-1.8.44 → batplot-1.8.46}/batplot.egg-info/PKG-INFO +87 -5
- {batplot-1.8.44 → batplot-1.8.46}/batplot.egg-info/SOURCES.txt +35 -0
- {batplot-1.8.44 → batplot-1.8.46}/pyproject.toml +8 -2
- batplot-1.8.46/tests/test_batch_session.py +241 -0
- batplot-1.8.46/tests/test_bruker_intensity.py +25 -0
- batplot-1.8.46/tests/test_cli_save.py +72 -0
- {batplot-1.8.44 → batplot-1.8.46}/tests/test_cli_smoke.py +42 -0
- {batplot-1.8.44 → batplot-1.8.46}/tests/test_cpc_roundtrip.py +9 -1
- {batplot-1.8.44 → batplot-1.8.46}/tests/test_dev_upgrade.py +108 -0
- {batplot-1.8.44 → batplot-1.8.46}/tests/test_ec_roundtrip.py +1 -1
- batplot-1.8.46/tests/test_histo.py +598 -0
- {batplot-1.8.44 → batplot-1.8.46}/tests/test_interactive_menu_smoke.py +2 -2
- batplot-1.8.46/tests/test_mpl_backend.py +143 -0
- {batplot-1.8.44 → batplot-1.8.46}/tests/test_operando_roundtrip.py +3 -3
- batplot-1.8.44/MANIFEST.in +0 -3
- {batplot-1.8.44 → batplot-1.8.46}/LICENSE +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/NOTICE +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/cif.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/config.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/ec_common.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/modes.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/__init__.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/common/__init__.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/common/axis_state.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/common/files.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/common/fonts.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/common/interactive_state.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/common/menu_rendering.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/common/menus.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/common/smoothing.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/common/sources.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/common/terminal.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/common/title_offsets.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/cpc/__init__.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/cpc/actions.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/cpc/labels.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/cpc/menu.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/cpc/session.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/cpc/snapshots.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/electrochem/__init__.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/electrochem/actions.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/electrochem/export.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/electrochem/labels.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/electrochem/legend.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/electrochem/legend_order.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/electrochem/line_style.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/electrochem/menu.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/electrochem/session.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/electrochem/spine_colors.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/operando/__init__.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/operando/actions.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/operando/grid.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/operando/ions_axis.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/operando/layout.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/operando/line_style.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/operando/menu.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/operando/peaks.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/operando/session.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/operando/visibility.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/xy/__init__.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/xy/actions.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/xy/arrange.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/xy/axis_range.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/xy/cif.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/xy/colors.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/xy/data_ops.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/xy/derivative.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/xy/game.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/xy/labels.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/xy/line_style.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/xy/menu.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/xy/peaks.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/xy/session.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/xy/smoothing.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plot_modes/xy/style.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/plotting.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/showcol.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/style.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/ui.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot/utils.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot.egg-info/dependency_links.txt +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot.egg-info/entry_points.txt +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot.egg-info/requires.txt +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/batplot.egg-info/top_level.txt +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/setup.cfg +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/setup.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/tests/test_color_utils.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/tests/test_common_files.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/tests/test_common_palettes.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/tests/test_contracts.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/tests/test_csv_readers.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/tests/test_interactive_state.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/tests/test_xy_modules.py +0 -0
- {batplot-1.8.44 → batplot-1.8.46}/tests/test_xy_roundtrip.py +0 -0
|
@@ -429,9 +429,23 @@ Before changing release behavior:
|
|
|
429
429
|
|
|
430
430
|
1. Read `batplot/dev_upgrade.py`.
|
|
431
431
|
2. Add or update tests in `tests/test_dev_upgrade.py`.
|
|
432
|
-
3. Confirm future files are included
|
|
432
|
+
3. Confirm future files are included automatically:
|
|
433
|
+
- Python modules: `packages.find include = ["batplot*"]` plus
|
|
434
|
+
`validate_distribution_contents()` (every `batplot/**/*.py` must be in the wheel).
|
|
435
|
+
- Package data: drop files into `batplot/data/` (except `USER_MANUAL.md`);
|
|
436
|
+
`--dev-upgrade` runs `sync_pyproject_package_data()` to refresh
|
|
437
|
+
`[tool.setuptools.package-data]`.
|
|
438
|
+
- Git: `_git_stage_release_snapshot()` stages tracked updates and all untracked
|
|
439
|
+
non-ignored paths (no hand-maintained file list).
|
|
433
440
|
4. Keep GitHub/PyPI conflict handling explicit and testable.
|
|
434
441
|
|
|
442
|
+
Canonical version files checked on every release:
|
|
443
|
+
|
|
444
|
+
- `batplot/__init__.py` (`__version__`)
|
|
445
|
+
- `pyproject.toml` (`[project] version`)
|
|
446
|
+
- `CITATION.cff` (`version: v…`)
|
|
447
|
+
- `batplot/data/latest_release_notes.json` (`version` field)
|
|
448
|
+
|
|
435
449
|
## Cross-Platform Checklist
|
|
436
450
|
|
|
437
451
|
Use this checklist before finishing code changes:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: batplot
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.46
|
|
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
|
|
@@ -64,9 +64,10 @@ With a single line of command to easily plot publication-ready plots with custom
|
|
|
64
64
|
- **Electrochemistry Plot**: Galvanostatic cycling (GC), cyclic voltammetry (CV), differential capacity (dQdV), capacity per cycle (CPC) with multi-file support
|
|
65
65
|
- **1D XY plot**: Designed for XRD, PDF, XAS (XANES/EXAFS) but also support other types
|
|
66
66
|
- **Operando Contour plot**: Correlate in-situ characterizations (XRD/PDF/XAS) with electrochemical data
|
|
67
|
+
- **Histogram mode**: Column histograms from tabular `.csv`/`.txt` data (e.g. particle-size lists)
|
|
67
68
|
- **Interactive plotting**: Real-time editing customized for each type of plottings
|
|
68
69
|
- **Session Persistence**: Save and reload complete plot states with `.pkl` files
|
|
69
|
-
- **Style Management**: Import/export plot styles as `.bps`/`.bpsg` files
|
|
70
|
+
- **Style Management**: Import/export plot styles as `.bps`/`.bpsg` files (histogram: `.bpsh`)
|
|
70
71
|
- **Batch Processing**: Export each file separately with `--all`
|
|
71
72
|
- **Column preview**: `--showcol` prints numbered columns, header names when found, and the first 10 values per column (CSV, Excel, text, .mpt, .brml, Bruker .raw, etc.)
|
|
72
73
|
|
|
@@ -190,6 +191,21 @@ batplot file1.xy file2.xy --stack --i
|
|
|
190
191
|
batplot allfiles --xaxis 2theta --xrange 15 75 --i
|
|
191
192
|
```
|
|
192
193
|
|
|
194
|
+
### Session save without interactive menu (`--save`)
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
# Single file: default .pkl name = data file stem; choose save folder when prompted
|
|
198
|
+
batplot pattern.xye --xaxis 2theta --save
|
|
199
|
+
|
|
200
|
+
# Batch: one session per file (default names), folder chosen once
|
|
201
|
+
batplot --all --xaxis 2theta --xrange 10 80 --save
|
|
202
|
+
|
|
203
|
+
# Combined plot (allfiles, operando, multi-file GC/CPC): you must name the session
|
|
204
|
+
batplot allfiles --xaxis q --save
|
|
205
|
+
batplot --operando --wl 0.25 --save
|
|
206
|
+
batplot file1.csv file2.csv --gc --save
|
|
207
|
+
```
|
|
208
|
+
|
|
193
209
|
---
|
|
194
210
|
|
|
195
211
|
## Electrochemistry Mode
|
|
@@ -296,16 +312,80 @@ Operando column selection:
|
|
|
296
312
|
|
|
297
313
|
---
|
|
298
314
|
|
|
315
|
+
## Histogram Mode
|
|
316
|
+
|
|
317
|
+
Histogram mode plots a single numeric column from tabular `.csv` or `.txt` files. It is designed for particle-size distributions and similar column data exported from spreadsheets or image-analysis tools.
|
|
318
|
+
|
|
319
|
+
### Basic usage
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
# Interactive wizard + styling menu
|
|
323
|
+
batplot sizes.csv --histo --i
|
|
324
|
+
|
|
325
|
+
# Non-interactive: column, range, bins, save figure
|
|
326
|
+
batplot data.txt --histo --histocol Length --xrange 0 16 --binwidth 1 --out hist.png
|
|
327
|
+
|
|
328
|
+
# Preview columns before choosing
|
|
329
|
+
batplot --showcol sizes.csv
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### Startup wizard (`--i`)
|
|
333
|
+
|
|
334
|
+
1. Choose the column to histogram (numbered list with preview)
|
|
335
|
+
2. Set histogram range (`xmin xmax` or `auto`)
|
|
336
|
+
3. Set bin width or `bins=N`
|
|
337
|
+
|
|
338
|
+
### Batch export
|
|
339
|
+
|
|
340
|
+
Export each CSV/TXT file in the folder as a separate figure under `Figures/`:
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
batplot --all --histo --histocol Length
|
|
344
|
+
batplot allfiles --histo --histocol 7 --binwidth 1
|
|
345
|
+
batplot histo_folder/ --histo --histocol Length
|
|
346
|
+
|
|
347
|
+
# Apply a shared histogram style (.bpsh)
|
|
348
|
+
batplot --all mystyle.bpsh --histo --histocol Length
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
`--histocol` is required for batch export (column number or header name).
|
|
352
|
+
|
|
353
|
+
### Batch interactive editing
|
|
354
|
+
|
|
355
|
+
Edit two or more histograms together (sync colors, fonts, export):
|
|
356
|
+
|
|
357
|
+
```bash
|
|
358
|
+
batplot allfiles --histo --i
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
If `--histocol` is omitted, the wizard runs on the first file and the same column/bin layout is reused for the rest.
|
|
362
|
+
|
|
363
|
+
### Flags
|
|
364
|
+
|
|
365
|
+
| Flag | Description |
|
|
366
|
+
|------|-------------|
|
|
367
|
+
| `--histo` | Launch histogram mode |
|
|
368
|
+
| `--histocol N` | Column to histogram (1-indexed or header name) |
|
|
369
|
+
| `--xrange A B` | Histogram display range |
|
|
370
|
+
| `--binwidth W` | Width of each bin |
|
|
371
|
+
| `--bins N` | Number of equal-width bins |
|
|
372
|
+
| `--all` | Batch export each CSV/TXT file (requires `--histocol`) |
|
|
373
|
+
| `allfiles` | Expand all CSV/TXT in folder (batch export or `--i` batch edit) |
|
|
374
|
+
|
|
375
|
+
Style files: `.bpsh` (export with `p` in the interactive menu).
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
299
379
|
## Plotting multiple files
|
|
300
380
|
|
|
301
381
|
```bash
|
|
302
382
|
# All XY files in current directory on same figure
|
|
303
|
-
batplot allfiles
|
|
304
|
-
batplot allfiles --stack --i
|
|
383
|
+
batplot allfiles --xaxis 2theta --i
|
|
384
|
+
batplot allfiles --stack --gc --i
|
|
305
385
|
|
|
306
386
|
# Only specific extension (natural-sorted)
|
|
307
387
|
batplot allxyfiles
|
|
308
|
-
batplot "/path/to/data" allnorfiles --i
|
|
388
|
+
batplot "/path/to/data" allnorfiles --xaxis energy --i
|
|
309
389
|
|
|
310
390
|
# Explicit file list
|
|
311
391
|
batplot file1.xye file2.qye structure.cif:1.54 --stack --i
|
|
@@ -351,6 +431,7 @@ With `--interactive`:
|
|
|
351
431
|
- **Styling**: Line widths, markers, fonts
|
|
352
432
|
- **Axes**: Labels, limits, ticks, spine styles
|
|
353
433
|
- **Export**: Sessions (`.pkl`), styles (`.bps`/`.bpsg`), high-res images. Colors persist via `p` (print style), `i` (import), `s` (save session), `b` (undo)
|
|
434
|
+
- **Non-interactive session save**: `--save` (without `--i`) prompts for folder and filename—the same `.pkl` sessions as interactive `s`, with default names for single-file and `--all` batch runs
|
|
354
435
|
- **Live Preview**: All changes update in real-time
|
|
355
436
|
|
|
356
437
|
---
|
|
@@ -362,6 +443,7 @@ batplot --h # General help
|
|
|
362
443
|
batplot --h xy # XY mode guide
|
|
363
444
|
batplot --h ec # Electrochemistry guide
|
|
364
445
|
batplot --h op # Operando guide
|
|
446
|
+
batplot --h histo # Histogram mode guide
|
|
365
447
|
batplot --v # Version and release notes
|
|
366
448
|
batplot --m # Open illustrated manual
|
|
367
449
|
```
|
|
@@ -10,9 +10,10 @@ With a single line of command to easily plot publication-ready plots with custom
|
|
|
10
10
|
- **Electrochemistry Plot**: Galvanostatic cycling (GC), cyclic voltammetry (CV), differential capacity (dQdV), capacity per cycle (CPC) with multi-file support
|
|
11
11
|
- **1D XY plot**: Designed for XRD, PDF, XAS (XANES/EXAFS) but also support other types
|
|
12
12
|
- **Operando Contour plot**: Correlate in-situ characterizations (XRD/PDF/XAS) with electrochemical data
|
|
13
|
+
- **Histogram mode**: Column histograms from tabular `.csv`/`.txt` data (e.g. particle-size lists)
|
|
13
14
|
- **Interactive plotting**: Real-time editing customized for each type of plottings
|
|
14
15
|
- **Session Persistence**: Save and reload complete plot states with `.pkl` files
|
|
15
|
-
- **Style Management**: Import/export plot styles as `.bps`/`.bpsg` files
|
|
16
|
+
- **Style Management**: Import/export plot styles as `.bps`/`.bpsg` files (histogram: `.bpsh`)
|
|
16
17
|
- **Batch Processing**: Export each file separately with `--all`
|
|
17
18
|
- **Column preview**: `--showcol` prints numbered columns, header names when found, and the first 10 values per column (CSV, Excel, text, .mpt, .brml, Bruker .raw, etc.)
|
|
18
19
|
|
|
@@ -136,6 +137,21 @@ batplot file1.xy file2.xy --stack --i
|
|
|
136
137
|
batplot allfiles --xaxis 2theta --xrange 15 75 --i
|
|
137
138
|
```
|
|
138
139
|
|
|
140
|
+
### Session save without interactive menu (`--save`)
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
# Single file: default .pkl name = data file stem; choose save folder when prompted
|
|
144
|
+
batplot pattern.xye --xaxis 2theta --save
|
|
145
|
+
|
|
146
|
+
# Batch: one session per file (default names), folder chosen once
|
|
147
|
+
batplot --all --xaxis 2theta --xrange 10 80 --save
|
|
148
|
+
|
|
149
|
+
# Combined plot (allfiles, operando, multi-file GC/CPC): you must name the session
|
|
150
|
+
batplot allfiles --xaxis q --save
|
|
151
|
+
batplot --operando --wl 0.25 --save
|
|
152
|
+
batplot file1.csv file2.csv --gc --save
|
|
153
|
+
```
|
|
154
|
+
|
|
139
155
|
---
|
|
140
156
|
|
|
141
157
|
## Electrochemistry Mode
|
|
@@ -242,16 +258,80 @@ Operando column selection:
|
|
|
242
258
|
|
|
243
259
|
---
|
|
244
260
|
|
|
261
|
+
## Histogram Mode
|
|
262
|
+
|
|
263
|
+
Histogram mode plots a single numeric column from tabular `.csv` or `.txt` files. It is designed for particle-size distributions and similar column data exported from spreadsheets or image-analysis tools.
|
|
264
|
+
|
|
265
|
+
### Basic usage
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
# Interactive wizard + styling menu
|
|
269
|
+
batplot sizes.csv --histo --i
|
|
270
|
+
|
|
271
|
+
# Non-interactive: column, range, bins, save figure
|
|
272
|
+
batplot data.txt --histo --histocol Length --xrange 0 16 --binwidth 1 --out hist.png
|
|
273
|
+
|
|
274
|
+
# Preview columns before choosing
|
|
275
|
+
batplot --showcol sizes.csv
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Startup wizard (`--i`)
|
|
279
|
+
|
|
280
|
+
1. Choose the column to histogram (numbered list with preview)
|
|
281
|
+
2. Set histogram range (`xmin xmax` or `auto`)
|
|
282
|
+
3. Set bin width or `bins=N`
|
|
283
|
+
|
|
284
|
+
### Batch export
|
|
285
|
+
|
|
286
|
+
Export each CSV/TXT file in the folder as a separate figure under `Figures/`:
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
batplot --all --histo --histocol Length
|
|
290
|
+
batplot allfiles --histo --histocol 7 --binwidth 1
|
|
291
|
+
batplot histo_folder/ --histo --histocol Length
|
|
292
|
+
|
|
293
|
+
# Apply a shared histogram style (.bpsh)
|
|
294
|
+
batplot --all mystyle.bpsh --histo --histocol Length
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
`--histocol` is required for batch export (column number or header name).
|
|
298
|
+
|
|
299
|
+
### Batch interactive editing
|
|
300
|
+
|
|
301
|
+
Edit two or more histograms together (sync colors, fonts, export):
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
batplot allfiles --histo --i
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
If `--histocol` is omitted, the wizard runs on the first file and the same column/bin layout is reused for the rest.
|
|
308
|
+
|
|
309
|
+
### Flags
|
|
310
|
+
|
|
311
|
+
| Flag | Description |
|
|
312
|
+
|------|-------------|
|
|
313
|
+
| `--histo` | Launch histogram mode |
|
|
314
|
+
| `--histocol N` | Column to histogram (1-indexed or header name) |
|
|
315
|
+
| `--xrange A B` | Histogram display range |
|
|
316
|
+
| `--binwidth W` | Width of each bin |
|
|
317
|
+
| `--bins N` | Number of equal-width bins |
|
|
318
|
+
| `--all` | Batch export each CSV/TXT file (requires `--histocol`) |
|
|
319
|
+
| `allfiles` | Expand all CSV/TXT in folder (batch export or `--i` batch edit) |
|
|
320
|
+
|
|
321
|
+
Style files: `.bpsh` (export with `p` in the interactive menu).
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
245
325
|
## Plotting multiple files
|
|
246
326
|
|
|
247
327
|
```bash
|
|
248
328
|
# All XY files in current directory on same figure
|
|
249
|
-
batplot allfiles
|
|
250
|
-
batplot allfiles --stack --i
|
|
329
|
+
batplot allfiles --xaxis 2theta --i
|
|
330
|
+
batplot allfiles --stack --gc --i
|
|
251
331
|
|
|
252
332
|
# Only specific extension (natural-sorted)
|
|
253
333
|
batplot allxyfiles
|
|
254
|
-
batplot "/path/to/data" allnorfiles --i
|
|
334
|
+
batplot "/path/to/data" allnorfiles --xaxis energy --i
|
|
255
335
|
|
|
256
336
|
# Explicit file list
|
|
257
337
|
batplot file1.xye file2.qye structure.cif:1.54 --stack --i
|
|
@@ -297,6 +377,7 @@ With `--interactive`:
|
|
|
297
377
|
- **Styling**: Line widths, markers, fonts
|
|
298
378
|
- **Axes**: Labels, limits, ticks, spine styles
|
|
299
379
|
- **Export**: Sessions (`.pkl`), styles (`.bps`/`.bpsg`), high-res images. Colors persist via `p` (print style), `i` (import), `s` (save session), `b` (undo)
|
|
380
|
+
- **Non-interactive session save**: `--save` (without `--i`) prompts for folder and filename—the same `.pkl` sessions as interactive `s`, with default names for single-file and `--all` batch runs
|
|
300
381
|
- **Live Preview**: All changes update in real-time
|
|
301
382
|
|
|
302
383
|
---
|
|
@@ -308,6 +389,7 @@ batplot --h # General help
|
|
|
308
389
|
batplot --h xy # XY mode guide
|
|
309
390
|
batplot --h ec # Electrochemistry guide
|
|
310
391
|
batplot --h op # Operando guide
|
|
392
|
+
batplot --h histo # Histogram mode guide
|
|
311
393
|
batplot --v # Version and release notes
|
|
312
394
|
batplot --m # Open illustrated manual
|
|
313
395
|
```
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
"""Matplotlib backend selection for batplot CLI and interactive sessions.
|
|
2
|
+
|
|
3
|
+
Imported early from :mod:`batplot.cli` so pytest/CI on Windows never fall back
|
|
4
|
+
to Tk when ``MPLBACKEND=Agg`` is set explicitly in the environment.
|
|
5
|
+
|
|
6
|
+
When the user has not set ``MPLBACKEND``, we start on Agg for safe imports but
|
|
7
|
+
may switch to a GUI backend before opening interactive windows (``.pkl`` reload,
|
|
8
|
+
``--gc --i``, ``--canvas``, etc.).
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import importlib.util
|
|
14
|
+
import os
|
|
15
|
+
import sys
|
|
16
|
+
|
|
17
|
+
_USER_SET_MPLBACKEND = "MPLBACKEND" in os.environ
|
|
18
|
+
_DEFAULT_BACKEND = os.environ.get("MPLBACKEND", "Agg")
|
|
19
|
+
|
|
20
|
+
import matplotlib as _mpl
|
|
21
|
+
|
|
22
|
+
_mpl.use(_DEFAULT_BACKEND, force=True)
|
|
23
|
+
|
|
24
|
+
_INTERACTIVE_BACKENDS = frozenset(
|
|
25
|
+
{
|
|
26
|
+
"macosx",
|
|
27
|
+
"tkagg",
|
|
28
|
+
"qt5agg",
|
|
29
|
+
"qt4agg",
|
|
30
|
+
"qtagg",
|
|
31
|
+
"wxagg",
|
|
32
|
+
"gtk3agg",
|
|
33
|
+
"gtk4agg",
|
|
34
|
+
"wx",
|
|
35
|
+
"qt",
|
|
36
|
+
"gtk",
|
|
37
|
+
"gtk3",
|
|
38
|
+
"gtk4",
|
|
39
|
+
}
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _is_noninteractive_backend(name: str | None) -> bool:
|
|
44
|
+
if not isinstance(name, str):
|
|
45
|
+
return False
|
|
46
|
+
low = name.lower()
|
|
47
|
+
if low in _INTERACTIVE_BACKENDS:
|
|
48
|
+
return False
|
|
49
|
+
return ("agg" in low) or ("inline" in low) or (low in {"pdf", "ps", "svg", "template"})
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def is_interactive_backend() -> bool:
|
|
53
|
+
"""Return True when the active Matplotlib backend can open a GUI window."""
|
|
54
|
+
try:
|
|
55
|
+
return not _is_noninteractive_backend(_mpl.get_backend())
|
|
56
|
+
except Exception:
|
|
57
|
+
return False
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _headless_context() -> bool:
|
|
61
|
+
"""True when batplot must stay on a non-interactive backend (CI/pytest)."""
|
|
62
|
+
if os.environ.get("BATPLOT_HEADLESS", "").lower() in ("1", "true", "yes"):
|
|
63
|
+
return True
|
|
64
|
+
if os.environ.get("CI", "").lower() in ("1", "true", "yes"):
|
|
65
|
+
return True
|
|
66
|
+
if os.environ.get("PYTEST_CURRENT_TEST"):
|
|
67
|
+
return True
|
|
68
|
+
if "pytest" in sys.modules:
|
|
69
|
+
return True
|
|
70
|
+
return False
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def running_headless() -> bool:
|
|
74
|
+
"""True under pytest, CI, or when ``BATPLOT_HEADLESS`` is set."""
|
|
75
|
+
return _headless_context()
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def wants_interactive_window(args) -> bool:
|
|
79
|
+
"""Return True when this CLI invocation should open an interactive figure."""
|
|
80
|
+
if args is None:
|
|
81
|
+
return False
|
|
82
|
+
if getattr(args, "all", None) is not None:
|
|
83
|
+
return False
|
|
84
|
+
files = getattr(args, "files", None) or []
|
|
85
|
+
if any(str(f).lower().endswith(".pkl") for f in files):
|
|
86
|
+
return True
|
|
87
|
+
if getattr(args, "canvas", False):
|
|
88
|
+
return True
|
|
89
|
+
if getattr(args, "interactive", False):
|
|
90
|
+
return True
|
|
91
|
+
# Headless export / session save: --out, --savefig, or --save (without --i).
|
|
92
|
+
if getattr(args, "savefig", False) or getattr(args, "out", None):
|
|
93
|
+
return False
|
|
94
|
+
if getattr(args, "save", False) and not getattr(args, "interactive", False):
|
|
95
|
+
return False
|
|
96
|
+
for attr in ("operando", "contour", "gc", "cv", "dqdv", "cpc", "epc", "histo"):
|
|
97
|
+
if getattr(args, attr, False):
|
|
98
|
+
return True
|
|
99
|
+
# Default XY / multi-file diffraction view (no --out, no --all).
|
|
100
|
+
if files:
|
|
101
|
+
return True
|
|
102
|
+
return False
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _should_respect_env_agg() -> bool:
|
|
106
|
+
"""Keep Agg when the environment requested it and we are in headless context."""
|
|
107
|
+
if not _USER_SET_MPLBACKEND:
|
|
108
|
+
return False
|
|
109
|
+
env_be = os.environ.get("MPLBACKEND")
|
|
110
|
+
if not env_be or not _is_noninteractive_backend(env_be):
|
|
111
|
+
return False
|
|
112
|
+
return _headless_context()
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _has_qt_bindings() -> bool:
|
|
116
|
+
for mod in ("PyQt6", "PyQt5", "PySide6", "PySide2"):
|
|
117
|
+
if importlib.util.find_spec(mod) is not None:
|
|
118
|
+
return True
|
|
119
|
+
return False
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _gui_backend_order() -> list[str]:
|
|
123
|
+
if sys.platform == "darwin":
|
|
124
|
+
return ["MacOSX", "TkAgg", "QtAgg"]
|
|
125
|
+
if sys.platform.startswith("win"):
|
|
126
|
+
return ["TkAgg", "QtAgg"]
|
|
127
|
+
return ["TkAgg", "QtAgg", "Gtk4Agg", "Gtk3Agg"]
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _backend_can_be_tried(name: str) -> bool:
|
|
131
|
+
if name == "TkAgg":
|
|
132
|
+
return importlib.util.find_spec("tkinter") is not None
|
|
133
|
+
if name == "QtAgg":
|
|
134
|
+
return _has_qt_bindings()
|
|
135
|
+
return True
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def ensure_gui_backend(args=None) -> bool:
|
|
139
|
+
"""Switch from Agg to a GUI backend when an interactive window is expected.
|
|
140
|
+
|
|
141
|
+
Returns True when the active backend is interactive (or was switched to one).
|
|
142
|
+
Honors ``MPLBACKEND=Agg`` only under pytest/CI; interactive CLI use (``--i``,
|
|
143
|
+
``.pkl`` reload) overrides an inherited Agg default from conda/shell profiles.
|
|
144
|
+
"""
|
|
145
|
+
if args is not None and not wants_interactive_window(args):
|
|
146
|
+
return is_interactive_backend()
|
|
147
|
+
|
|
148
|
+
if _should_respect_env_agg():
|
|
149
|
+
return False
|
|
150
|
+
|
|
151
|
+
if _USER_SET_MPLBACKEND:
|
|
152
|
+
env_be = os.environ.get("MPLBACKEND")
|
|
153
|
+
if env_be and not _is_noninteractive_backend(env_be):
|
|
154
|
+
return True
|
|
155
|
+
|
|
156
|
+
if is_interactive_backend():
|
|
157
|
+
return True
|
|
158
|
+
|
|
159
|
+
for cand in _gui_backend_order():
|
|
160
|
+
if not _backend_can_be_tried(cand):
|
|
161
|
+
continue
|
|
162
|
+
try:
|
|
163
|
+
_mpl.use(cand, force=True)
|
|
164
|
+
if is_interactive_backend():
|
|
165
|
+
return True
|
|
166
|
+
except Exception:
|
|
167
|
+
continue
|
|
168
|
+
return False
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _one_line_backend_workaround() -> str:
|
|
172
|
+
"""Return a copy-paste command prefix for the current platform."""
|
|
173
|
+
if sys.platform == "darwin":
|
|
174
|
+
return "MPLBACKEND=MacOSX batplot ..."
|
|
175
|
+
if sys.platform.startswith("win"):
|
|
176
|
+
return 'set MPLBACKEND=TkAgg (cmd) or $env:MPLBACKEND="TkAgg" (PowerShell), then batplot ...'
|
|
177
|
+
return "MPLBACKEND=TkAgg batplot ..."
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _print_interactive_backend_help(context: str = "interactive menu") -> None:
|
|
181
|
+
"""User-facing recovery steps when no GUI window can be opened."""
|
|
182
|
+
try:
|
|
183
|
+
backend = _mpl.get_backend()
|
|
184
|
+
except Exception:
|
|
185
|
+
backend = "unknown"
|
|
186
|
+
try:
|
|
187
|
+
from . import __version__ as _bp_version
|
|
188
|
+
except Exception:
|
|
189
|
+
_bp_version = "latest"
|
|
190
|
+
|
|
191
|
+
print()
|
|
192
|
+
print("Interactive plotting needs a display window, but batplot could not open one.")
|
|
193
|
+
print(f"(Matplotlib backend: {backend})")
|
|
194
|
+
if context:
|
|
195
|
+
print(f"This affects: {context}.")
|
|
196
|
+
print()
|
|
197
|
+
print("Try these steps, in order:")
|
|
198
|
+
print(" 1. Upgrade batplot (fixes most cases):")
|
|
199
|
+
print(" pip install --upgrade batplot")
|
|
200
|
+
print(f" You need the latest batplot release (installed: {_bp_version}).")
|
|
201
|
+
print(" 2. If you cannot upgrade yet, force a GUI backend for this session:")
|
|
202
|
+
print(f" {_one_line_backend_workaround()}")
|
|
203
|
+
print(" 3. To save a figure without the interactive menu:")
|
|
204
|
+
print(" batplot ... --out figure.png (omit --i)")
|
|
205
|
+
print()
|
|
206
|
+
print("Advanced: if MPLBACKEND=Agg is set in your shell or conda env, unset it or override")
|
|
207
|
+
print("as in step 2. On headless servers (SSH with no display), use --out instead of --i.")
|
|
208
|
+
print()
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def warn_if_noninteractive(context: str = "interactive menu") -> bool:
|
|
212
|
+
"""Print a helpful message when the backend cannot show a window."""
|
|
213
|
+
if is_interactive_backend():
|
|
214
|
+
return True
|
|
215
|
+
_print_interactive_backend_help(context)
|
|
216
|
+
return False
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def require_interactive_display(
|
|
220
|
+
args=None,
|
|
221
|
+
*,
|
|
222
|
+
context: str = "interactive menu",
|
|
223
|
+
export_hint: str | None = None,
|
|
224
|
+
) -> bool:
|
|
225
|
+
"""Ensure a GUI backend, warn if unavailable, return True when display is possible."""
|
|
226
|
+
ensure_gui_backend(args)
|
|
227
|
+
if is_interactive_backend():
|
|
228
|
+
return True
|
|
229
|
+
warn_if_noninteractive(context)
|
|
230
|
+
return False
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def show_figure_if_possible(args=None, *, block: bool = True) -> bool:
|
|
234
|
+
"""Show the current figure when the backend supports windows.
|
|
235
|
+
|
|
236
|
+
Defaults to ``block=True`` so the window stays open until the user closes it.
|
|
237
|
+
Non-interactive view mode (no ``--i``) relies on this; ``block=False`` would
|
|
238
|
+
return immediately and the process would exit before the figure is visible.
|
|
239
|
+
"""
|
|
240
|
+
ensure_gui_backend(args)
|
|
241
|
+
if not is_interactive_backend():
|
|
242
|
+
if args is not None and not (getattr(args, "savefig", False) or getattr(args, "out", None)):
|
|
243
|
+
print("No display window available. Save the figure with: batplot ... --out figure.png")
|
|
244
|
+
return False
|
|
245
|
+
import matplotlib.pyplot as plt
|
|
246
|
+
|
|
247
|
+
plt.show(block=block)
|
|
248
|
+
return True
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def prime_interactive_figure(fig=None) -> None:
|
|
252
|
+
"""Prepare a matplotlib window before an interactive menu (non-blocking)."""
|
|
253
|
+
import matplotlib.pyplot as plt
|
|
254
|
+
|
|
255
|
+
try:
|
|
256
|
+
plt.ion()
|
|
257
|
+
except Exception:
|
|
258
|
+
pass
|
|
259
|
+
if fig is not None:
|
|
260
|
+
try:
|
|
261
|
+
fig.canvas.draw_idle()
|
|
262
|
+
fig.canvas.flush_events()
|
|
263
|
+
except Exception:
|
|
264
|
+
pass
|
|
265
|
+
try:
|
|
266
|
+
plt.show(block=False)
|
|
267
|
+
except Exception:
|
|
268
|
+
pass
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def hold_figure_open() -> None:
|
|
272
|
+
"""Keep the current figure window open until the user closes it."""
|
|
273
|
+
if not is_interactive_backend():
|
|
274
|
+
return
|
|
275
|
+
import matplotlib.pyplot as plt
|
|
276
|
+
|
|
277
|
+
try:
|
|
278
|
+
plt.show()
|
|
279
|
+
except Exception:
|
|
280
|
+
pass
|