quantui 0.7.0__tar.gz → 0.8.2__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.
- {quantui-0.7.0 → quantui-0.8.2}/CHANGELOG.md +183 -0
- {quantui-0.7.0/quantui.egg-info → quantui-0.8.2}/PKG-INFO +87 -9
- {quantui-0.7.0 → quantui-0.8.2}/README.md +80 -6
- {quantui-0.7.0 → quantui-0.8.2}/pyproject.toml +20 -4
- {quantui-0.7.0 → quantui-0.8.2}/quantui/__init__.py +1 -1
- {quantui-0.7.0 → quantui-0.8.2}/quantui/analytics.py +28 -16
- {quantui-0.7.0 → quantui-0.8.2}/quantui/app.py +1433 -236
- {quantui-0.7.0 → quantui-0.8.2}/quantui/app_analysis.py +381 -40
- {quantui-0.7.0 → quantui-0.8.2}/quantui/app_builders.py +986 -116
- quantui-0.8.2/quantui/app_exports.py +916 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/app_formatters.py +244 -151
- {quantui-0.7.0 → quantui-0.8.2}/quantui/app_history.py +15 -2
- quantui-0.8.2/quantui/app_launcher.py +375 -0
- quantui-0.8.2/quantui/app_measurement.py +425 -0
- quantui-0.8.2/quantui/app_pes_pick.py +134 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/app_runflow.py +925 -103
- quantui-0.8.2/quantui/app_slurm.py +667 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/app_visualization.py +568 -57
- quantui-0.8.2/quantui/app_xyz_input.py +252 -0
- quantui-0.8.2/quantui/backends/__init__.py +37 -0
- quantui-0.8.2/quantui/backends/base.py +111 -0
- quantui-0.8.2/quantui/backends/cluster_config.py +159 -0
- quantui-0.8.2/quantui/backends/cluster_security.py +149 -0
- quantui-0.8.2/quantui/backends/dispatch.py +193 -0
- quantui-0.8.2/quantui/backends/local.py +46 -0
- quantui-0.8.2/quantui/backends/registry.py +206 -0
- quantui-0.8.2/quantui/backends/slurm.py +642 -0
- quantui-0.8.2/quantui/backends/slurm_errors.py +205 -0
- quantui-0.8.2/quantui/backends/slurm_ingest.py +242 -0
- quantui-0.8.2/quantui/backends/slurm_utils.py +184 -0
- quantui-0.8.2/quantui/backends/worker.py +479 -0
- quantui-0.8.2/quantui/backends/worker_payload.py +287 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/benchmarks.py +25 -4
- {quantui-0.7.0 → quantui-0.8.2}/quantui/calc_log.py +160 -18
- {quantui-0.7.0 → quantui-0.8.2}/quantui/calculator.py +8 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/checkpoint.py +93 -9
- {quantui-0.7.0 → quantui-0.8.2}/quantui/cli.py +68 -3
- {quantui-0.7.0 → quantui-0.8.2}/quantui/config.py +1 -0
- quantui-0.8.2/quantui/connectivity.py +294 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/data/library/library.sqlite +0 -0
- quantui-0.8.2/quantui/data/manifests/inorganic.json +1412 -0
- quantui-0.8.2/quantui/density_fitting.py +89 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/descriptor_cards.py +23 -10
- {quantui-0.7.0 → quantui-0.8.2}/quantui/estimator_eval.py +12 -8
- {quantui-0.7.0 → quantui-0.8.2}/quantui/freq_calc.py +220 -15
- {quantui-0.7.0 → quantui-0.8.2}/quantui/freq_ir_workers.py +50 -20
- quantui-0.8.2/quantui/freq_raman_workers.py +103 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/help_content.py +240 -14
- quantui-0.8.2/quantui/inorganic_guards.py +146 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/ir_plot.py +2 -1
- {quantui-0.7.0 → quantui-0.8.2}/quantui/live_log.py +1 -1
- {quantui-0.7.0 → quantui-0.8.2}/quantui/log_utils.py +43 -3
- quantui-0.8.2/quantui/measurement.py +80 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/molecule.py +14 -27
- quantui-0.8.2/quantui/mulliken_plot.py +58 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/nmr_calc.py +17 -0
- quantui-0.8.2/quantui/nmr_plot.py +118 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/optimizer.py +75 -1
- {quantui-0.7.0 → quantui-0.8.2}/quantui/orbital_visualization.py +215 -26
- {quantui-0.7.0 → quantui-0.8.2}/quantui/pes_scan.py +15 -1
- quantui-0.8.2/quantui/pes_scan_ui.py +384 -0
- quantui-0.8.2/quantui/populations_overlay.py +337 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/preopt.py +222 -11
- {quantui-0.7.0 → quantui-0.8.2}/quantui/progress.py +8 -5
- {quantui-0.7.0 → quantui-0.8.2}/quantui/pubchem.py +30 -4
- quantui-0.8.2/quantui/raman_calc.py +403 -0
- quantui-0.8.2/quantui/raman_plot.py +110 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/reorganization_energy.py +76 -1
- {quantui-0.7.0 → quantui-0.8.2}/quantui/results_storage.py +93 -3
- {quantui-0.7.0 → quantui-0.8.2}/quantui/session_calc.py +76 -10
- quantui-0.8.2/quantui/spin_presets.py +276 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/tddft_calc.py +17 -1
- quantui-0.8.2/quantui/theme.py +742 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/user_settings.py +114 -1
- {quantui-0.7.0 → quantui-0.8.2}/quantui/vib_cache.py +9 -2
- {quantui-0.7.0 → quantui-0.8.2}/quantui/visualization_py3dmol.py +240 -43
- quantui-0.8.2/quantui/xyz_input.py +211 -0
- {quantui-0.7.0 → quantui-0.8.2/quantui.egg-info}/PKG-INFO +87 -9
- {quantui-0.7.0 → quantui-0.8.2}/quantui.egg-info/SOURCES.txt +32 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui.egg-info/requires.txt +7 -2
- quantui-0.7.0/quantui/app_exports.py +0 -318
- quantui-0.7.0/quantui/theme.py +0 -125
- {quantui-0.7.0 → quantui-0.8.2}/LICENSE +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/MANIFEST.in +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/SECURITY.md +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/ase_bridge.py +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/c_stderr.py +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/cactus.py +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/cancellation.py +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/comparison.py +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/data/js/3Dmol-min.js +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/data/js/3Dmol-min.js.LICENSE.txt +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/data/manifests/bulk_qm9.json +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/data/manifests/curated.json +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/data/manifests/presets.json +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/gpu_offload.py +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/issue_tracker.py +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/molecule_library.py +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/security.py +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/structure_providers.py +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/utils.py +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/viz_assets.py +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui/viz_backend_router.py +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui.egg-info/dependency_links.txt +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui.egg-info/entry_points.txt +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/quantui.egg-info/top_level.txt +0 -0
- {quantui-0.7.0 → quantui-0.8.2}/setup.cfg +0 -0
|
@@ -7,6 +7,189 @@ and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.ht
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.8.2] - 2026-08-30
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **SLURM batch execution (M-CLUSTER2)** — optional cluster backend when
|
|
15
|
+
`QUANTUI_ENABLE_SLURM=1` and `sbatch` is on PATH: submit from the same UI,
|
|
16
|
+
monitor on the **Cluster Jobs** tab, hybrid `squeue`/`sacct` polling, submit
|
|
17
|
+
cooldown, and stale-registry cleanup. All Calculate-tab calc types supported
|
|
18
|
+
on the batch worker path.
|
|
19
|
+
- **`QUANTUI_ENABLE_SLURM` site gate** — SLURM batch stays hidden and
|
|
20
|
+
undispatchable until an operator sets this environment variable. Student CPU
|
|
21
|
+
images and JupyterHub profiles can omit it (default off); instructors enable
|
|
22
|
+
cluster testing with `QUANTUI_ENABLE_SLURM=1` without any extra student
|
|
23
|
+
command.
|
|
24
|
+
- **`quantui setup` and `quantui run app`** — writes `~/QuantUI.ipynb` for
|
|
25
|
+
NCShare/JupyterLab (Render with Voilà). `run app` detects Apptainer +
|
|
26
|
+
Jupyter and exits with Voilà instructions instead of opening an unreachable
|
|
27
|
+
second port.
|
|
28
|
+
- **Parallel IR intensity displacements (CPU)** — Settings checkbox
|
|
29
|
+
(`compute.freq_parallel`) plus `QUANTUI_FREQ_PARALLEL` env override fans out
|
|
30
|
+
the 6N finite-difference SCF loop on hosts with ≥4 cores and ≥2 atoms. The
|
|
31
|
+
**CPU teaching SIF** sets `QUANTUI_FREQ_PARALLEL=1` by default; the checkbox
|
|
32
|
+
reflects the deployment value and locks while the env var is set.
|
|
33
|
+
- **Imaginary-mode perturbation** for Frequency reruns seeded from History.
|
|
34
|
+
- **Stage-aware frequency cost estimate** and per-phase run status labels (NMR,
|
|
35
|
+
Hessian, post-HF).
|
|
36
|
+
- **Preset theme palettes** replacing the invert filter (M-THEME THEME.6).
|
|
37
|
+
- **Quantum engine registry** (`quantui/engines/`) and
|
|
38
|
+
`ComputeSettings.quantum_engine` field (M-PYFOCK PYF.1 groundwork).
|
|
39
|
+
- **Static Raman spectrum** on the Analysis tab (M-SPECTRA2).
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
|
|
43
|
+
- **Mulliken 3D viewer** could render blank after geometry persistence and lazy
|
|
44
|
+
panel activation (#103).
|
|
45
|
+
- **`apptainer/quantui-gpu.def` never installed the `xtb` extra**, so GFN-FF
|
|
46
|
+
metal-capable classical pre-optimization (DEC-018) was unavailable in every
|
|
47
|
+
GPU/HPC image — the app correctly reported the honest-failure message
|
|
48
|
+
("RDKit could not perceive bonds ... and the GFN-FF (xtb) metal backend is
|
|
49
|
+
not installed"), but the underlying cause was a container gap, not a
|
|
50
|
+
missing local install. Fixed by pinning the image's Python to 3.11 via the
|
|
51
|
+
deadsnakes PPA (Ubuntu 24.04's own repos ship 3.12 only, and `xtb`'s PyPI
|
|
52
|
+
wheels stop at `cp311`) and adding `xtb` to the pip extras. `quantui.def`
|
|
53
|
+
(the CPU teaching image) gained the equivalent `xtb-python` conda-forge
|
|
54
|
+
package, which it had also been missing despite `local-setup/environment.yml`
|
|
55
|
+
already carrying it for local conda installs.
|
|
56
|
+
|
|
57
|
+
## [0.8.1] - 2026-08-26
|
|
58
|
+
|
|
59
|
+
### Added
|
|
60
|
+
|
|
61
|
+
- **PNG export on the geometry-optimization trajectory, vibrational mode, and
|
|
62
|
+
molecule viewers** — the same camera-accurate Save-PNG capture already
|
|
63
|
+
available on the orbital isosurface and reorganization-energy geometry
|
|
64
|
+
viewers now covers every 3-D viewer in the app. The molecule viewer (shown
|
|
65
|
+
on the Calculate, Results, and Analysis tabs) captures only on the py3Dmol
|
|
66
|
+
backend, since Plotly already provides its own "download plot as PNG"
|
|
67
|
+
button; each of its three tabs gets an independent capture button so a
|
|
68
|
+
save from one tab can never be mislabeled with another tab's molecule or
|
|
69
|
+
overwrite another tab's file.
|
|
70
|
+
|
|
71
|
+
## [0.8.0] - 2026-08-25
|
|
72
|
+
|
|
73
|
+
### Added
|
|
74
|
+
|
|
75
|
+
- **Transition-metal and coordination-complex support.** QuantUI now
|
|
76
|
+
recognizes and handles metal centers throughout the pipeline instead of
|
|
77
|
+
erroring or silently mishandling them: a pre-run guard catches
|
|
78
|
+
basis-coverage and charge/multiplicity problems before a run starts (with a
|
|
79
|
+
one-click "Switch to def2-SVP" fix when that alone resolves it); a GFN-FF
|
|
80
|
+
(xtb) pre-optimization backend actually relaxes coordination complexes,
|
|
81
|
+
since RDKit's organic valence model can't; the 3D viewer falls back to
|
|
82
|
+
py3Dmol instead of showing a "Visualization failed" box; a fetched
|
|
83
|
+
structure that resolves to a disconnected salt (e.g. cisplatin as separate
|
|
84
|
+
NH₃/HCl/Pt fragments) is flagged before you compute the wrong geometry;
|
|
85
|
+
coordination bonds are drawn dashed since 3Dmol.js's own bond perception
|
|
86
|
+
draws none to a metal; and an oxidation-state → spin-state multiplicity
|
|
87
|
+
suggestion engine proposes — never auto-sets — physically reasonable
|
|
88
|
+
multiplicities, naming the strong- vs weak-field ligand ambiguity where one
|
|
89
|
+
exists.
|
|
90
|
+
- **14 bundled inorganic examples** (up from 3), GFN-FF-validated, spanning
|
|
91
|
+
octahedral (aqua and cyanide, high- and low-spin), tetrahedral, and
|
|
92
|
+
square-planar geometries — a teaching spread across spin states and
|
|
93
|
+
charges.
|
|
94
|
+
- **Density fitting (RI)** as an opt-in SCF speedup — a large win for TD-DFT
|
|
95
|
+
and larger systems, roughly neutral for small single points, so it defaults
|
|
96
|
+
off. Shown on/off in the run-header provenance banner and flagged on the
|
|
97
|
+
result card ("⚡ RI") whenever it was actually applied.
|
|
98
|
+
- **Mulliken Populations Analysis panel.** Per-atom Mulliken charges as a
|
|
99
|
+
table and bar chart after Single Point and Geometry Optimization runs, with
|
|
100
|
+
its own 3D viewer below the energy-level diagram: atoms colored by charge,
|
|
101
|
+
a center-of-mass dipole arrow, a color-vividness slider, and a
|
|
102
|
+
magnitude-only fallback when an older History result has ‖μ‖ but no saved
|
|
103
|
+
vector.
|
|
104
|
+
- **NMR stick plot** with a ¹H/¹³C nucleus toggle, mirroring the existing
|
|
105
|
+
IR/UV-Vis panels; UV-Vis gains λ min/max axis-bound inputs.
|
|
106
|
+
- **Click-to-measure atom selection** on the Analysis-tab viewer — click 2, 3,
|
|
107
|
+
or 4 atoms to read a bond length, angle, or dihedral, GaussView-style
|
|
108
|
+
(py3Dmol only for now; the Plotly viewer shows an explanatory message
|
|
109
|
+
instead of a silent no-op).
|
|
110
|
+
- **Interactive XYZ input.** An atom-row builder and a cleanup-coordinates
|
|
111
|
+
accept/reject preview on the Calculate tab. Loading no longer enforces
|
|
112
|
+
charge/multiplicity parity at parse time — an odd-electron geometry loads
|
|
113
|
+
with a note instead of an error — and charge/multiplicity now stay owned by
|
|
114
|
+
Calculation Setup.
|
|
115
|
+
- **Suggest charge & multiplicity from geometry** — a Calculation Setup
|
|
116
|
+
button proposes a neutral charge and a parity-compatible multiplicity from
|
|
117
|
+
the loaded structure, with an explicit Apply step rather than a silent
|
|
118
|
+
auto-fill.
|
|
119
|
+
- **Export provenance.** Cube, PNG, and XYZ exports now carry method, basis,
|
|
120
|
+
and resolution (plus charge/multiplicity for XYZ) as embedded metadata, not
|
|
121
|
+
just filenames. Reorganization Energy gained its own XYZ export — one file
|
|
122
|
+
per distinct geometry — and a generalized PNG-capture bridge shared with
|
|
123
|
+
the isosurface viewer.
|
|
124
|
+
- **Reorganization Energy is checkpointed.** The run most likely to be
|
|
125
|
+
interrupted — two geometry optimizations plus four SCF energies under one
|
|
126
|
+
Calculate-tab run — can now resume mid-leg instead of restarting from
|
|
127
|
+
scratch.
|
|
128
|
+
- Orbital isosurfaces gained **smoothed meshes** (no more visible
|
|
129
|
+
marching-cubes facets) and a **wireframe finish toggle**.
|
|
130
|
+
- TD-DFT's live status label now surfaces **per-root convergence**
|
|
131
|
+
("TD-DFT root 3 converged @ 16.663 eV") during the excited-state solve,
|
|
132
|
+
instead of only a generic heartbeat.
|
|
133
|
+
- A representative example gallery in the README and GitHub Pages site, and
|
|
134
|
+
new documentation for inorganic/coordination-complex support.
|
|
135
|
+
|
|
136
|
+
### Fixed
|
|
137
|
+
|
|
138
|
+
- **Heavy-element runs on an ECP basis were silently wrong.** Cisplatin and
|
|
139
|
+
similar complexes on LANL2DZ or def2 were built with the basis set but no
|
|
140
|
+
effective core potential attached, so PySCF ran all-electron against a
|
|
141
|
+
valence-only basis — converging to a nonphysical energy (positive HOMO)
|
|
142
|
+
with garbage gradients, which made a geometry optimization look like it was
|
|
143
|
+
diverging. ECPs are now attached consistently across every calculation
|
|
144
|
+
type.
|
|
145
|
+
- **Frequency time estimates for app runs were systematically inflated.** The
|
|
146
|
+
estimator's fallback cost model wasn't told which pool a run came from, so
|
|
147
|
+
small-molecule Frequency estimates drew on the calibration pool's
|
|
148
|
+
fresh-subprocess import overhead instead of the app-run pool.
|
|
149
|
+
- **Density fitting's "⚡ RI" badge could silently vanish.** TD-DFT, NMR,
|
|
150
|
+
Frequency, and Geometry Optimization results discarded the density-fitting
|
|
151
|
+
flag instead of storing it, and results were never persisting it to disk
|
|
152
|
+
for *any* calculation type — so even a live single point's badge
|
|
153
|
+
disappeared on History replay.
|
|
154
|
+
- **A warm-start rejection could abort an otherwise-good calculation.** A
|
|
155
|
+
GPU-migrated mean-field rejecting a host density, or an incompatible
|
|
156
|
+
chkfile density, now logs a warning and retries from a scratch guess
|
|
157
|
+
instead of failing the whole run.
|
|
158
|
+
- **Resuming a resumed-and-interrupted-again optimization under-reported its
|
|
159
|
+
progress** — the BFGS step counter wasn't seeded from the checkpoint, so it
|
|
160
|
+
restarted counting at 0 instead of continuing from what had already been
|
|
161
|
+
banked.
|
|
162
|
+
- The resume list's Restore/Discard buttons now log an unexpected exception
|
|
163
|
+
instead of letting it escape into ipywidgets' click dispatch, matching
|
|
164
|
+
every other action button.
|
|
165
|
+
- **Converged-but-near-degenerate metal runs no longer show a stale "HOMO ==
|
|
166
|
+
LUMO" warning** (observed on ferrocene) — the check now looks at the
|
|
167
|
+
converged gap, not PySCF's initial-guess density, which is always
|
|
168
|
+
near-degenerate for a bare d-manifold starting guess.
|
|
169
|
+
- Click-to-measure's highlight halo no longer sits buried inside larger atoms
|
|
170
|
+
— it was a fixed radius; ball-and-stick atoms render at a radius scaled
|
|
171
|
+
from each element's VDW radius.
|
|
172
|
+
- Analysis-tab polish: the welcome logo's SVG fill token, accordions
|
|
173
|
+
expanding automatically when they have data, scroll-to-top on tab entry,
|
|
174
|
+
and a shared seed-geometry dropdown for NMR Shielding.
|
|
175
|
+
- **Older History results without saved Mulliken data now say so
|
|
176
|
+
explicitly**, with a magnitude-only note for dipoles recorded before the
|
|
177
|
+
full vector was saved, instead of a blank or misleading panel.
|
|
178
|
+
- The CPU Apptainer build crashing on a floating `miniforge3:latest` base
|
|
179
|
+
image — libmamba choking on a fuzzy version pin. See
|
|
180
|
+
`apptainer/quantui.def`.
|
|
181
|
+
|
|
182
|
+
### Changed
|
|
183
|
+
|
|
184
|
+
- Three separate calc-type label→key mappings, and three separate
|
|
185
|
+
implementations of the Hill-formula algorithm, had drifted apart; each is
|
|
186
|
+
now a single shared helper.
|
|
187
|
+
- `python -m quantui.estimator_eval`'s replay is now linear time instead of
|
|
188
|
+
quadratic.
|
|
189
|
+
- ~380 scattered hex color literals across the chrome files are now one
|
|
190
|
+
theme token map.
|
|
191
|
+
- Real type checking restored in CI.
|
|
192
|
+
|
|
10
193
|
## [0.7.0] - 2026-08-06
|
|
11
194
|
|
|
12
195
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quantui
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.2
|
|
4
4
|
Summary: An open-source frontend for DFT and post-HF quantum chemistry with PySCF
|
|
5
5
|
Author-email: Jonathan Schultz <nccu-schultz-lab@users.noreply.github.com>
|
|
6
6
|
License: MIT License
|
|
@@ -55,13 +55,17 @@ Requires-Dist: numpy<3,>=1.24.0
|
|
|
55
55
|
Requires-Dist: requests<3,>=2.28.0
|
|
56
56
|
Requires-Dist: py3Dmol<3,>=2.0.0
|
|
57
57
|
Requires-Dist: matplotlib<4,>=3.7.0
|
|
58
|
-
Requires-Dist: plotly<
|
|
58
|
+
Requires-Dist: plotly<8,>=5.0.0
|
|
59
59
|
Requires-Dist: plotlymol<1,>=0.2.1
|
|
60
|
+
Requires-Dist: kaleido<2,>=0.2.1
|
|
60
61
|
Provides-Extra: pyscf
|
|
61
62
|
Requires-Dist: pyscf<3,>=2.13.0; extra == "pyscf"
|
|
62
63
|
Requires-Dist: pyscf-properties; extra == "pyscf"
|
|
63
64
|
Provides-Extra: ase
|
|
64
65
|
Requires-Dist: ase<4,>=3.22.0; extra == "ase"
|
|
66
|
+
Provides-Extra: xtb
|
|
67
|
+
Requires-Dist: xtb>=22.1; extra == "xtb"
|
|
68
|
+
Requires-Dist: ase<4,>=3.22.0; extra == "xtb"
|
|
65
69
|
Provides-Extra: app
|
|
66
70
|
Requires-Dist: voila<0.6,>=0.5.0; extra == "app"
|
|
67
71
|
Requires-Dist: ipykernel<8,>=6.0.0; extra == "app"
|
|
@@ -81,7 +85,7 @@ Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
|
81
85
|
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
82
86
|
Requires-Dist: pytest-mock>=3.10.0; extra == "dev"
|
|
83
87
|
Requires-Dist: pytest-xdist>=3.0.0; extra == "dev"
|
|
84
|
-
Requires-Dist: mypy
|
|
88
|
+
Requires-Dist: mypy<2.4,>=1.10; extra == "dev"
|
|
85
89
|
Requires-Dist: types-requests>=2.28.0; extra == "dev"
|
|
86
90
|
Requires-Dist: black~=26.5.1; python_version >= "3.10" and extra == "dev"
|
|
87
91
|
Requires-Dist: black~=25.11.0; python_version < "3.10" and extra == "dev"
|
|
@@ -109,13 +113,49 @@ research and classroom use.
|
|
|
109
113
|
|
|
110
114
|
---
|
|
111
115
|
|
|
116
|
+
## Example results
|
|
117
|
+
|
|
118
|
+
Real output from QuantUI, straight from the app:
|
|
119
|
+
|
|
120
|
+
<table>
|
|
121
|
+
<tr>
|
|
122
|
+
<td width="50%" align="center" valign="top">
|
|
123
|
+
<img src="https://raw.githubusercontent.com/The-Schultz-Lab/QuantUI/main/docs/images/cisplatin_lumo.png" alt="Cisplatin LUMO isosurface" width="400"><br>
|
|
124
|
+
<b>Cisplatin LUMO</b><br>
|
|
125
|
+
<sub>Molecular-orbital isosurface · B3LYP/LANL2DZ (ECP on Pt & Cl)</sub>
|
|
126
|
+
</td>
|
|
127
|
+
<td width="50%" align="center" valign="top">
|
|
128
|
+
<img src="https://raw.githubusercontent.com/The-Schultz-Lab/QuantUI/main/docs/images/aspartame_orbital_diagram.png" alt="Aspartame orbital energy-level diagram" width="300"><br>
|
|
129
|
+
<b>Aspartame orbital energies</b><br>
|
|
130
|
+
<sub>Occupied/virtual levels · HOMO–LUMO gap 6.09 eV · B3LYP/6-31G*</sub>
|
|
131
|
+
</td>
|
|
132
|
+
</tr>
|
|
133
|
+
<tr>
|
|
134
|
+
<td width="50%" align="center" valign="top">
|
|
135
|
+
<img src="https://raw.githubusercontent.com/The-Schultz-Lab/QuantUI/main/docs/images/benzene_ir_spectrum.png" alt="Benzene IR spectrum" width="400"><br>
|
|
136
|
+
<b>Benzene IR spectrum</b><br>
|
|
137
|
+
<sub>Analytical Hessian · ωB97X-D/6-31G · the four IR-active bands</sub>
|
|
138
|
+
</td>
|
|
139
|
+
<td width="50%" align="center" valign="top">
|
|
140
|
+
<img src="https://raw.githubusercontent.com/The-Schultz-Lab/QuantUI/main/docs/images/cisplatin_optimization.png" alt="Cisplatin geometry-optimization energy convergence" width="400"><br>
|
|
141
|
+
<b>Geometry optimization</b><br>
|
|
142
|
+
<sub>Cisplatin relaxing over 21 BFGS steps · B3LYP/LANL2DZ</sub>
|
|
143
|
+
</td>
|
|
144
|
+
</tr>
|
|
145
|
+
</table>
|
|
146
|
+
|
|
147
|
+
▶ **[Live interactive gallery →](https://the-schultz-lab.github.io/QuantUI/#examples)** — rotate the 3D structures, and watch the optimization trajectory and a vibrational mode animate.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
112
151
|
## What it does
|
|
113
152
|
|
|
114
|
-
- **Molecule input** — paste XYZ coordinates, browse an indexed
|
|
115
|
-
|
|
116
|
-
searchable by name/formula), or run a
|
|
117
|
-
InChI, PubChem CID, InChIKey, or CAS number
|
|
118
|
-
bundled-library fallback; SMILES/InChI resolve
|
|
153
|
+
- **Molecule input** — paste XYZ coordinates, browse an indexed bundled library
|
|
154
|
+
(organic presets + curated molecules + ~1,900 QM9 structures + **14
|
|
155
|
+
ready-to-run coordination complexes**, searchable by name/formula), or run a
|
|
156
|
+
structure search by name, SMILES, InChI, PubChem CID, InChIKey, or CAS number
|
|
157
|
+
(PubChem → NCI CACTUS → offline bundled-library fallback; SMILES/InChI resolve
|
|
158
|
+
locally with no network)
|
|
119
159
|
- **Offline-first** — runs with no internet: the bundled molecule library and
|
|
120
160
|
the 3D viewer's JavaScript (3Dmol.js) are vendored, so structure lookup and
|
|
121
161
|
every 3D view work in an air-gapped classroom. (Network is used only for the
|
|
@@ -139,6 +179,18 @@ research and classroom use.
|
|
|
139
179
|
animation; vibrational frequency analysis with animated normal modes,
|
|
140
180
|
user-tunable playback FPS, and a per-result-directory disk cache so mode
|
|
141
181
|
switches on repeat visits and history replay are instant
|
|
182
|
+
- **Inorganic / coordination complexes** — first-class support for
|
|
183
|
+
transition-metal chemistry the organic pipeline can't handle: 14 bundled
|
|
184
|
+
metal complexes (octahedral / tetrahedral / square-planar; aqua, ammine,
|
|
185
|
+
cyanide, carbonyl, halide, oxo) with correct charge and spin; a pre-run guard
|
|
186
|
+
that catches a metal on an incompatible basis (nudges to def2-SVP / LANL2DZ)
|
|
187
|
+
and an impossible charge/multiplicity before the calculation starts; a
|
|
188
|
+
**spin-state helper** that suggests a multiplicity from a metal centre's
|
|
189
|
+
oxidation state and geometry (both high- and low-spin where the ligand field
|
|
190
|
+
decides — you pick); optional **GFN-FF (xtb) pre-optimization** that relaxes a
|
|
191
|
+
metal complex the classical organic force field can't; a warning when a name
|
|
192
|
+
search returns a disconnected salt instead of the coordinated complex; and a
|
|
193
|
+
viewer that draws the coordination bonds so the metal is never a lone dot
|
|
142
194
|
- **Results persistence** — every calculation is saved automatically to a
|
|
143
195
|
timestamped directory; a built-in browser lets you reload past results
|
|
144
196
|
after a kernel restart; the full `pyscf.log` is shown inline
|
|
@@ -255,6 +307,26 @@ and result cards will display the compute device.
|
|
|
255
307
|
Whenever gpu4pyscf can't offload a particular call, QuantUI falls back
|
|
256
308
|
to CPU automatically and the result card reflects which device ran.
|
|
257
309
|
|
|
310
|
+
### Optional: GFN-FF metal pre-optimization (xtb)
|
|
311
|
+
|
|
312
|
+
The classical (MMFF/UFF) pre-optimizer relies on RDKit's organic valence
|
|
313
|
+
model, which can't handle a transition metal. Install
|
|
314
|
+
[xtb](https://github.com/grimme-lab/xtb) to enable **GFN-FF**, a general
|
|
315
|
+
force field that relaxes coordination complexes across the whole periodic
|
|
316
|
+
table. Fully optional — without it, metal pre-opt simply reports that it
|
|
317
|
+
isn't available and points you to the DFT geometry optimization.
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
# Linux (PyPI wheels bundle the compiled library):
|
|
321
|
+
pip install quantui[xtb]
|
|
322
|
+
|
|
323
|
+
# Windows / macOS (no PyPI wheel — use conda-forge):
|
|
324
|
+
conda install -c conda-forge xtb-python
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
QuantUI detects xtb automatically and routes metal pre-optimizations through
|
|
328
|
+
GFN-FF; organic molecules still use the faster RDKit force field.
|
|
329
|
+
|
|
258
330
|
---
|
|
259
331
|
|
|
260
332
|
## Quick start
|
|
@@ -456,7 +528,13 @@ Five step-by-step notebooks in [`notebooks/tutorials/`](https://github.com/The-S
|
|
|
456
528
|
### Basis sets
|
|
457
529
|
|
|
458
530
|
STO-3G (fast, good for learning) → 3-21G → 6-31G / 6-31G\* / 6-31G\*\* →
|
|
459
|
-
cc-pVDZ / cc-pVTZ → def2-SVP / def2-TZVP
|
|
531
|
+
cc-pVDZ / cc-pVTZ → def2-SVP / def2-TZVP → LANL2DZ
|
|
532
|
+
|
|
533
|
+
For **transition metals and heavy elements**, use **def2-SVP** / **def2-TZVP**
|
|
534
|
+
or **LANL2DZ** — these carry the effective core potentials that cover metals,
|
|
535
|
+
whereas the Pople (`6-31G…`) and Dunning (`cc-pV…`) sets do not. QuantUI's
|
|
536
|
+
pre-run guard flags a metal on an incompatible basis and offers a one-click
|
|
537
|
+
switch to def2-SVP before the calculation starts.
|
|
460
538
|
|
|
461
539
|
---
|
|
462
540
|
|
|
@@ -18,13 +18,49 @@ research and classroom use.
|
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
+
## Example results
|
|
22
|
+
|
|
23
|
+
Real output from QuantUI, straight from the app:
|
|
24
|
+
|
|
25
|
+
<table>
|
|
26
|
+
<tr>
|
|
27
|
+
<td width="50%" align="center" valign="top">
|
|
28
|
+
<img src="https://raw.githubusercontent.com/The-Schultz-Lab/QuantUI/main/docs/images/cisplatin_lumo.png" alt="Cisplatin LUMO isosurface" width="400"><br>
|
|
29
|
+
<b>Cisplatin LUMO</b><br>
|
|
30
|
+
<sub>Molecular-orbital isosurface · B3LYP/LANL2DZ (ECP on Pt & Cl)</sub>
|
|
31
|
+
</td>
|
|
32
|
+
<td width="50%" align="center" valign="top">
|
|
33
|
+
<img src="https://raw.githubusercontent.com/The-Schultz-Lab/QuantUI/main/docs/images/aspartame_orbital_diagram.png" alt="Aspartame orbital energy-level diagram" width="300"><br>
|
|
34
|
+
<b>Aspartame orbital energies</b><br>
|
|
35
|
+
<sub>Occupied/virtual levels · HOMO–LUMO gap 6.09 eV · B3LYP/6-31G*</sub>
|
|
36
|
+
</td>
|
|
37
|
+
</tr>
|
|
38
|
+
<tr>
|
|
39
|
+
<td width="50%" align="center" valign="top">
|
|
40
|
+
<img src="https://raw.githubusercontent.com/The-Schultz-Lab/QuantUI/main/docs/images/benzene_ir_spectrum.png" alt="Benzene IR spectrum" width="400"><br>
|
|
41
|
+
<b>Benzene IR spectrum</b><br>
|
|
42
|
+
<sub>Analytical Hessian · ωB97X-D/6-31G · the four IR-active bands</sub>
|
|
43
|
+
</td>
|
|
44
|
+
<td width="50%" align="center" valign="top">
|
|
45
|
+
<img src="https://raw.githubusercontent.com/The-Schultz-Lab/QuantUI/main/docs/images/cisplatin_optimization.png" alt="Cisplatin geometry-optimization energy convergence" width="400"><br>
|
|
46
|
+
<b>Geometry optimization</b><br>
|
|
47
|
+
<sub>Cisplatin relaxing over 21 BFGS steps · B3LYP/LANL2DZ</sub>
|
|
48
|
+
</td>
|
|
49
|
+
</tr>
|
|
50
|
+
</table>
|
|
51
|
+
|
|
52
|
+
▶ **[Live interactive gallery →](https://the-schultz-lab.github.io/QuantUI/#examples)** — rotate the 3D structures, and watch the optimization trajectory and a vibrational mode animate.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
21
56
|
## What it does
|
|
22
57
|
|
|
23
|
-
- **Molecule input** — paste XYZ coordinates, browse an indexed
|
|
24
|
-
|
|
25
|
-
searchable by name/formula), or run a
|
|
26
|
-
InChI, PubChem CID, InChIKey, or CAS number
|
|
27
|
-
bundled-library fallback; SMILES/InChI resolve
|
|
58
|
+
- **Molecule input** — paste XYZ coordinates, browse an indexed bundled library
|
|
59
|
+
(organic presets + curated molecules + ~1,900 QM9 structures + **14
|
|
60
|
+
ready-to-run coordination complexes**, searchable by name/formula), or run a
|
|
61
|
+
structure search by name, SMILES, InChI, PubChem CID, InChIKey, or CAS number
|
|
62
|
+
(PubChem → NCI CACTUS → offline bundled-library fallback; SMILES/InChI resolve
|
|
63
|
+
locally with no network)
|
|
28
64
|
- **Offline-first** — runs with no internet: the bundled molecule library and
|
|
29
65
|
the 3D viewer's JavaScript (3Dmol.js) are vendored, so structure lookup and
|
|
30
66
|
every 3D view work in an air-gapped classroom. (Network is used only for the
|
|
@@ -48,6 +84,18 @@ research and classroom use.
|
|
|
48
84
|
animation; vibrational frequency analysis with animated normal modes,
|
|
49
85
|
user-tunable playback FPS, and a per-result-directory disk cache so mode
|
|
50
86
|
switches on repeat visits and history replay are instant
|
|
87
|
+
- **Inorganic / coordination complexes** — first-class support for
|
|
88
|
+
transition-metal chemistry the organic pipeline can't handle: 14 bundled
|
|
89
|
+
metal complexes (octahedral / tetrahedral / square-planar; aqua, ammine,
|
|
90
|
+
cyanide, carbonyl, halide, oxo) with correct charge and spin; a pre-run guard
|
|
91
|
+
that catches a metal on an incompatible basis (nudges to def2-SVP / LANL2DZ)
|
|
92
|
+
and an impossible charge/multiplicity before the calculation starts; a
|
|
93
|
+
**spin-state helper** that suggests a multiplicity from a metal centre's
|
|
94
|
+
oxidation state and geometry (both high- and low-spin where the ligand field
|
|
95
|
+
decides — you pick); optional **GFN-FF (xtb) pre-optimization** that relaxes a
|
|
96
|
+
metal complex the classical organic force field can't; a warning when a name
|
|
97
|
+
search returns a disconnected salt instead of the coordinated complex; and a
|
|
98
|
+
viewer that draws the coordination bonds so the metal is never a lone dot
|
|
51
99
|
- **Results persistence** — every calculation is saved automatically to a
|
|
52
100
|
timestamped directory; a built-in browser lets you reload past results
|
|
53
101
|
after a kernel restart; the full `pyscf.log` is shown inline
|
|
@@ -164,6 +212,26 @@ and result cards will display the compute device.
|
|
|
164
212
|
Whenever gpu4pyscf can't offload a particular call, QuantUI falls back
|
|
165
213
|
to CPU automatically and the result card reflects which device ran.
|
|
166
214
|
|
|
215
|
+
### Optional: GFN-FF metal pre-optimization (xtb)
|
|
216
|
+
|
|
217
|
+
The classical (MMFF/UFF) pre-optimizer relies on RDKit's organic valence
|
|
218
|
+
model, which can't handle a transition metal. Install
|
|
219
|
+
[xtb](https://github.com/grimme-lab/xtb) to enable **GFN-FF**, a general
|
|
220
|
+
force field that relaxes coordination complexes across the whole periodic
|
|
221
|
+
table. Fully optional — without it, metal pre-opt simply reports that it
|
|
222
|
+
isn't available and points you to the DFT geometry optimization.
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
# Linux (PyPI wheels bundle the compiled library):
|
|
226
|
+
pip install quantui[xtb]
|
|
227
|
+
|
|
228
|
+
# Windows / macOS (no PyPI wheel — use conda-forge):
|
|
229
|
+
conda install -c conda-forge xtb-python
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
QuantUI detects xtb automatically and routes metal pre-optimizations through
|
|
233
|
+
GFN-FF; organic molecules still use the faster RDKit force field.
|
|
234
|
+
|
|
167
235
|
---
|
|
168
236
|
|
|
169
237
|
## Quick start
|
|
@@ -365,7 +433,13 @@ Five step-by-step notebooks in [`notebooks/tutorials/`](https://github.com/The-S
|
|
|
365
433
|
### Basis sets
|
|
366
434
|
|
|
367
435
|
STO-3G (fast, good for learning) → 3-21G → 6-31G / 6-31G\* / 6-31G\*\* →
|
|
368
|
-
cc-pVDZ / cc-pVTZ → def2-SVP / def2-TZVP
|
|
436
|
+
cc-pVDZ / cc-pVTZ → def2-SVP / def2-TZVP → LANL2DZ
|
|
437
|
+
|
|
438
|
+
For **transition metals and heavy elements**, use **def2-SVP** / **def2-TZVP**
|
|
439
|
+
or **LANL2DZ** — these carry the effective core potentials that cover metals,
|
|
440
|
+
whereas the Pople (`6-31G…`) and Dunning (`cc-pV…`) sets do not. QuantUI's
|
|
441
|
+
pre-run guard flags a metal on an incompatible basis and offers a one-click
|
|
442
|
+
switch to def2-SVP before the calculation starts.
|
|
369
443
|
|
|
370
444
|
---
|
|
371
445
|
|
|
@@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"
|
|
|
8
8
|
|
|
9
9
|
[project]
|
|
10
10
|
name = "quantui"
|
|
11
|
-
version = "0.
|
|
11
|
+
version = "0.8.2"
|
|
12
12
|
description = "An open-source frontend for DFT and post-HF quantum chemistry with PySCF"
|
|
13
13
|
readme = "README.md"
|
|
14
14
|
requires-python = ">=3.9"
|
|
@@ -62,8 +62,9 @@ dependencies = [
|
|
|
62
62
|
"requests>=2.28.0,<3",
|
|
63
63
|
"py3Dmol>=2.0.0,<3",
|
|
64
64
|
"matplotlib>=3.7.0,<4",
|
|
65
|
-
"plotly>=5.0.0,<
|
|
65
|
+
"plotly>=5.0.0,<8",
|
|
66
66
|
"plotlymol>=0.2.1,<1",
|
|
67
|
+
"kaleido>=0.2.1,<2",
|
|
67
68
|
]
|
|
68
69
|
|
|
69
70
|
[project.urls]
|
|
@@ -82,7 +83,7 @@ Issues = "https://github.com/The-Schultz-Lab/QuantUI/issues"
|
|
|
82
83
|
quantui = "quantui.cli:main"
|
|
83
84
|
|
|
84
85
|
[tool.setuptools]
|
|
85
|
-
packages = ["quantui"]
|
|
86
|
+
packages = ["quantui", "quantui.backends"]
|
|
86
87
|
|
|
87
88
|
[tool.setuptools.package-data]
|
|
88
89
|
# Bundled molecule library (M-STRUCT): the indexed SQLite store + the
|
|
@@ -118,6 +119,17 @@ ase = [
|
|
|
118
119
|
"ase>=3.22.0,<4",
|
|
119
120
|
]
|
|
120
121
|
|
|
122
|
+
# GFN-FF metal-capable classical pre-optimization via xtb (Grimme's general
|
|
123
|
+
# force field). RDKit's organic valence model can't touch a transition metal;
|
|
124
|
+
# GFN-FF covers the whole periodic table. quantui.preopt uses it when present
|
|
125
|
+
# and falls back gracefully otherwise. xtb publishes **Linux pip wheels only** —
|
|
126
|
+
# on Windows/macOS install it from conda-forge (see local-setup/environment.yml).
|
|
127
|
+
# Depends on ase (the optimizer driving the relaxation).
|
|
128
|
+
xtb = [
|
|
129
|
+
"xtb>=22.1",
|
|
130
|
+
"ase>=3.22.0,<4",
|
|
131
|
+
]
|
|
132
|
+
|
|
121
133
|
# Voilà app server — hides notebook code; students see only the widget UI.
|
|
122
134
|
# Run with: voila notebooks/molecule_computations.ipynb
|
|
123
135
|
app = [
|
|
@@ -164,7 +176,11 @@ dev = [
|
|
|
164
176
|
"pytest-cov>=4.0.0",
|
|
165
177
|
"pytest-mock>=3.10.0",
|
|
166
178
|
"pytest-xdist>=3.0.0", # parallel test execution (-n=auto in addopts)
|
|
167
|
-
"mypy>=1.
|
|
179
|
+
"mypy>=1.10,<2.4", # pinned, not an open floor — same reasoning as
|
|
180
|
+
# black/ruff below: it must agree with .pre-commit-config.yaml's rev,
|
|
181
|
+
# which is what CI enforces (M-TYPECHECK TYPE.2). A newer mypy silently
|
|
182
|
+
# disagrees: 2.x drops support for python_version = "3.9" (this repo's
|
|
183
|
+
# floor) and reports a different error set than the pinned check.
|
|
168
184
|
"types-requests>=2.28.0",
|
|
169
185
|
# Formatter/linter versions are pinned to a compatible range, NOT an open
|
|
170
186
|
# floor: they must agree with the revs in .pre-commit-config.yaml, which is
|
|
@@ -7,7 +7,7 @@ Calculations run locally in the Jupyter session — no cluster or SLURM required
|
|
|
7
7
|
PySCF requires Linux/macOS/WSL. Windows users should use the Apptainer container.
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
-
__version__ = "0.
|
|
10
|
+
__version__ = "0.8.2"
|
|
11
11
|
|
|
12
12
|
import logging
|
|
13
13
|
from typing import Any
|
|
@@ -34,7 +34,7 @@ import statistics
|
|
|
34
34
|
from collections import defaultdict
|
|
35
35
|
from datetime import datetime, timezone
|
|
36
36
|
from pathlib import Path
|
|
37
|
-
from typing import Optional
|
|
37
|
+
from typing import Optional, cast
|
|
38
38
|
|
|
39
39
|
from quantui.calc_log import _log_dir, get_perf_history, get_prediction_history
|
|
40
40
|
|
|
@@ -280,11 +280,17 @@ def _bar_chart_html(
|
|
|
280
280
|
margin=dict(l=40, r=20, t=10, b=40),
|
|
281
281
|
plot_bgcolor="#ffffff",
|
|
282
282
|
)
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
283
|
+
# plotly has no bundled type stubs; --ignore-missing-imports leaves
|
|
284
|
+
# pio.to_html untyped. It genuinely returns str (verified: this
|
|
285
|
+
# function's other returns are explicit None for the no-data case).
|
|
286
|
+
return cast(
|
|
287
|
+
str,
|
|
288
|
+
pio.to_html(
|
|
289
|
+
fig,
|
|
290
|
+
include_plotlyjs="inline" if include_plotlyjs else False,
|
|
291
|
+
full_html=False,
|
|
292
|
+
config={"displayModeBar": False},
|
|
293
|
+
),
|
|
288
294
|
)
|
|
289
295
|
|
|
290
296
|
|
|
@@ -344,11 +350,14 @@ def _timeline_html(records: list[dict], *, include_plotlyjs: bool) -> Optional[s
|
|
|
344
350
|
plot_bgcolor="#ffffff",
|
|
345
351
|
legend=dict(orientation="h", x=0, y=1.05),
|
|
346
352
|
)
|
|
347
|
-
return
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
353
|
+
return cast(
|
|
354
|
+
str,
|
|
355
|
+
pio.to_html(
|
|
356
|
+
fig,
|
|
357
|
+
include_plotlyjs="inline" if include_plotlyjs else False,
|
|
358
|
+
full_html=False,
|
|
359
|
+
config={"displayModeBar": False},
|
|
360
|
+
),
|
|
352
361
|
)
|
|
353
362
|
|
|
354
363
|
|
|
@@ -452,11 +461,14 @@ def _prediction_scatter_html(
|
|
|
452
461
|
plot_bgcolor="#ffffff",
|
|
453
462
|
legend=dict(orientation="h", x=0, y=1.05),
|
|
454
463
|
)
|
|
455
|
-
return
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
464
|
+
return cast(
|
|
465
|
+
str,
|
|
466
|
+
pio.to_html(
|
|
467
|
+
fig,
|
|
468
|
+
include_plotlyjs="inline" if include_plotlyjs else False,
|
|
469
|
+
full_html=False,
|
|
470
|
+
config={"displayModeBar": False},
|
|
471
|
+
),
|
|
460
472
|
)
|
|
461
473
|
|
|
462
474
|
|