chemparseplot 1.5.1__tar.gz → 1.5.3__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.
Files changed (65) hide show
  1. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/PKG-INFO +1 -1
  2. chemparseplot-1.5.3/_version.py +24 -0
  3. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/plot/neb.py +96 -25
  4. chemparseplot-1.5.1/_version.py +0 -34
  5. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/.gitignore +0 -0
  6. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/LICENSE +0 -0
  7. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/__init__.py +0 -0
  8. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/__init__.py +0 -0
  9. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/chemgp_hdf5.py +0 -0
  10. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/chemgp_jsonl.py +0 -0
  11. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/converter.py +0 -0
  12. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/eon/__init__.py +0 -0
  13. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/eon/dimer_trajectory.py +0 -0
  14. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/eon/gprd.py +0 -0
  15. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/eon/min_trajectory.py +0 -0
  16. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/eon/minimization.py +0 -0
  17. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/eon/neb.py +0 -0
  18. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/eon/saddle_search.py +0 -0
  19. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/file_.py +0 -0
  20. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/neb_utils.py +0 -0
  21. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/orca/__init__.py +0 -0
  22. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/orca/geomscan.py +0 -0
  23. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/orca/neb/__init__.py +0 -0
  24. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/orca/neb/interp.py +0 -0
  25. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/orca/neb/opi_parser.py +0 -0
  26. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/patterns.py +0 -0
  27. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/plumed.py +0 -0
  28. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/projection.py +0 -0
  29. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/sella/saddle_search.py +0 -0
  30. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/trajectory/__init__.py +0 -0
  31. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/trajectory/hdf5.py +0 -0
  32. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/parse/trajectory/neb.py +0 -0
  33. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/plot/__init__.py +0 -0
  34. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/plot/chemgp.py +0 -0
  35. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/plot/geomscan.py +0 -0
  36. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/plot/optimization.py +0 -0
  37. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/plot/plumed.py +0 -0
  38. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/plot/structs.py +0 -0
  39. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/plot/theme.py +0 -0
  40. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/units.py +0 -0
  41. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/chemparseplot/util.py +0 -0
  42. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/pyproject.toml +0 -0
  43. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/readme.md +0 -0
  44. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/conftest.py +0 -0
  45. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/parse/orca/test_geomscan.py +0 -0
  46. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/parse/orca/test_interp.py +0 -0
  47. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/parse/test_chemgp_hdf5.py +0 -0
  48. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/parse/test_converter.py +0 -0
  49. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/parse/test_dimer_trajectory.py +0 -0
  50. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/parse/test_min_trajectory.py +0 -0
  51. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/parse/test_neb_utils.py +0 -0
  52. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/parse/test_patterns.py +0 -0
  53. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/parse/test_plumed.py +0 -0
  54. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/parse/test_projection.py +0 -0
  55. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/parse/test_trajectory_hdf5.py +0 -0
  56. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/parse/test_trajectory_neb.py +0 -0
  57. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/plot/__init__.py +0 -0
  58. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/plot/test_chemgp_utils.py +0 -0
  59. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/plot/test_neb_renderers.py +0 -0
  60. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/plot/test_optimization.py +0 -0
  61. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/plot/test_projection_refactor.py +0 -0
  62. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/plot/test_strip_rendering.py +0 -0
  63. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/test_coverage_batch.py +0 -0
  64. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/test_full_coverage.py +0 -0
  65. {chemparseplot-1.5.1 → chemparseplot-1.5.3}/tests/tutorials/test_chemparseplot.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: chemparseplot
3
- Version: 1.5.1
3
+ Version: 1.5.3
4
4
  Summary: Parsers and plotting tools for computational chemistry
5
5
  Project-URL: Documentation, https://chemparseplot.rgoswami.me
6
6
  Project-URL: Issues, https://github.com/HaoZeke/chemparseplot/issues
@@ -0,0 +1,24 @@
1
+ # file generated by vcs-versioning
2
+ # don't change, don't track in version control
3
+ from __future__ import annotations
4
+
5
+ __all__ = [
6
+ "__version__",
7
+ "__version_tuple__",
8
+ "version",
9
+ "version_tuple",
10
+ "__commit_id__",
11
+ "commit_id",
12
+ ]
13
+
14
+ version: str
15
+ __version__: str
16
+ __version_tuple__: tuple[int | str, ...]
17
+ version_tuple: tuple[int | str, ...]
18
+ commit_id: str | None
19
+ __commit_id__: str | None
20
+
21
+ __version__ = version = '1.5.3'
22
+ __version_tuple__ = version_tuple = (1, 5, 3)
23
+
24
+ __commit_id__ = commit_id = None
@@ -8,6 +8,7 @@ from dataclasses import dataclass
8
8
  from pathlib import Path
9
9
  from typing import Any
10
10
 
11
+ import matplotlib.patheffects as path_effects
11
12
  import matplotlib.pyplot as plt
12
13
  import numpy as np
13
14
  from ase.io import write as ase_write
@@ -157,11 +158,12 @@ def _parse_rotation_angles(rotation_str):
157
158
  return rx, ry, rz
158
159
 
159
160
 
160
- def _render_xyzrender(atoms, rotation="auto", canvas_size=400):
161
+ def _render_xyzrender(atoms, rotation="auto", canvas_size=400, config="paton"):
161
162
  """Render an ASE Atoms object to a numpy RGBA array via xyzrender.
162
163
 
163
- Uses the ``paton`` preset with hydrogens visible for ball-and-stick
164
- style rendering.
164
+ Uses the specified config preset (default: ``paton`` for ball-and-stick).
165
+ Other useful presets: ``bubble`` (space-filling, good for surfaces),
166
+ ``flat``, ``tube``, ``wire``, ``skeletal``.
165
167
 
166
168
  Parameters
167
169
  ----------
@@ -205,7 +207,7 @@ def _render_xyzrender(atoms, rotation="auto", canvas_size=400):
205
207
  "-S",
206
208
  str(canvas_size),
207
209
  "--config",
208
- "paton",
210
+ config,
209
211
  "--hy",
210
212
  "-t",
211
213
  ]
@@ -224,7 +226,15 @@ def _render_xyzrender(atoms, rotation="auto", canvas_size=400):
224
226
  return img_data
225
227
 
226
228
 
227
- def _render_atoms(atoms, renderer, zoom, rotation, canvas_size=400, perspective_tilt=0.0):
229
+ def _render_atoms(
230
+ atoms,
231
+ renderer,
232
+ zoom,
233
+ rotation,
234
+ canvas_size=400,
235
+ perspective_tilt=0.0,
236
+ xyzrender_config="paton",
237
+ ):
228
238
  """Dispatch rendering to the selected backend.
229
239
 
230
240
  All backends return a numpy RGBA image array.
@@ -237,6 +247,8 @@ def _render_atoms(atoms, renderer, zoom, rotation, canvas_size=400, perspective_
237
247
  perspective_tilt : float
238
248
  Small off-axis tilt in degrees to reveal occluded atoms.
239
249
  0 disables. 5-10 is usually enough.
250
+ xyzrender_config : str
251
+ xyzrender preset name (paton, bubble, flat, tube, wire, skeletal).
240
252
  """
241
253
  if perspective_tilt > 0:
242
254
  atoms = atoms.copy()
@@ -246,7 +258,9 @@ def _render_atoms(atoms, renderer, zoom, rotation, canvas_size=400, perspective_
246
258
 
247
259
  if renderer == "xyzrender":
248
260
  _check_xyzrender()
249
- return _render_xyzrender(atoms, rotation=rotation, canvas_size=canvas_size)
261
+ return _render_xyzrender(
262
+ atoms, rotation=rotation, canvas_size=canvas_size, config=xyzrender_config
263
+ )
250
264
  elif renderer == "solvis":
251
265
  return _render_solvis(atoms, rotation=effective_rotation, canvas_size=canvas_size)
252
266
  elif renderer == "ovito":
@@ -422,6 +436,7 @@ def plot_structure_strip(
422
436
  renderer="xyzrender",
423
437
  col_spacing=1.5,
424
438
  show_dividers=False, # noqa: FBT002
439
+ xyzrender_config="paton",
425
440
  divider_color="gray",
426
441
  divider_style="--",
427
442
  perspective_tilt=0.0,
@@ -475,10 +490,15 @@ def plot_structure_strip(
475
490
  x_pos, y_pos = col * col_step, -row * row_step
476
491
 
477
492
  img_data = _render_atoms(
478
- atoms, renderer, zoom, rotation, perspective_tilt=perspective_tilt
493
+ atoms,
494
+ renderer,
495
+ zoom,
496
+ rotation,
497
+ perspective_tilt=perspective_tilt,
498
+ xyzrender_config=xyzrender_config,
479
499
  )
480
500
 
481
- effective_zoom = zoom * 0.45
501
+ effective_zoom = zoom * 0.15
482
502
  imagebox = OffsetImage(img_data, zoom=effective_zoom)
483
503
 
484
504
  ab = AnnotationBbox(
@@ -489,6 +509,7 @@ def plot_structure_strip(
489
509
  boxcoords="offset points",
490
510
  pad=0.0,
491
511
  )
512
+ ab.set_clip_on(True)
492
513
  ax.add_artist(ab)
493
514
 
494
515
  if labels and i < len(labels):
@@ -528,6 +549,7 @@ def plot_structure_inset(
528
549
  arrow_props=None,
529
550
  renderer="xyzrender",
530
551
  perspective_tilt=0.0,
552
+ xyzrender_config="paton",
531
553
  ) -> Any:
532
554
  """Plots a single structure as an annotation inset.
533
555
 
@@ -544,7 +566,12 @@ def plot_structure_inset(
544
566
  ```
545
567
  """
546
568
  img_data = _render_atoms(
547
- atoms, renderer, zoom, rotation, perspective_tilt=perspective_tilt
569
+ atoms,
570
+ renderer,
571
+ zoom,
572
+ rotation,
573
+ perspective_tilt=perspective_tilt,
574
+ xyzrender_config=xyzrender_config,
548
575
  )
549
576
  # Apply the same unified scaling as the strip
550
577
  effective_zoom = zoom * 0.45
@@ -757,6 +784,9 @@ def plot_landscape_surface(
757
784
  project_path=True, # noqa: FBT002
758
785
  extra_points=None,
759
786
  n_inducing=None,
787
+ xlim=None,
788
+ ylim=None,
789
+ basis=None,
760
790
  ) -> Any:
761
791
  """Plot the 2D landscape surface using reaction valley projection.
762
792
 
@@ -768,6 +798,14 @@ def plot_landscape_surface(
768
798
  The method rotates the RMSD plane into reaction progress and orthogonal
769
799
  deviation coordinates.
770
800
 
801
+ Parameters
802
+ ----------
803
+ basis : ProjectionBasis or None
804
+ Pre-computed projection basis. When provided, this basis is used
805
+ instead of computing one from ``rmsd_r``/``rmsd_p``. Pass this
806
+ when the surface data is a subset (e.g. last step only) but the
807
+ basis should come from the full path.
808
+
771
809
  ```{versionadded} 0.1.0
772
810
  ```
773
811
 
@@ -777,28 +815,36 @@ def plot_landscape_surface(
777
815
  """
778
816
  log.info(f"Generating 2D surface using {method} (Projected: {project_path})...")
779
817
 
780
- basis = compute_projection_basis(rmsd_r, rmsd_p) if project_path else None
818
+ if basis is None and project_path:
819
+ basis = compute_projection_basis(rmsd_r, rmsd_p)
781
820
 
782
821
  # --- 1. Grid Setup (Handles both Projection and Standard RMSD) ---
783
822
  if project_path:
784
823
  s_data, d_data = project_to_sd(rmsd_r, rmsd_p, basis)
785
- s_min, s_max = s_data.min(), s_data.max()
786
- d_min, d_max = d_data.min(), d_data.max()
787
824
 
788
- if extra_points is not None and len(extra_points) > 0:
789
- extra_s, extra_d = project_to_sd(
790
- extra_points[:, 0], extra_points[:, 1], basis
825
+ if xlim is not None and ylim is not None:
826
+ # Caller pre-computed the viewport -- build grid to match exactly
827
+ xg_1d = np.linspace(xlim[0], xlim[1], 150)
828
+ yg_1d = np.linspace(ylim[0], ylim[1], 150)
829
+ else:
830
+ s_min, s_max = s_data.min(), s_data.max()
831
+ d_min, d_max = d_data.min(), d_data.max()
832
+
833
+ if extra_points is not None and len(extra_points) > 0:
834
+ extra_s, extra_d = project_to_sd(
835
+ extra_points[:, 0], extra_points[:, 1], basis
836
+ )
837
+ s_min, s_max = min(s_min, extra_s.min()), max(s_max, extra_s.max())
838
+ d_min, d_max = min(d_min, extra_d.min()), max(d_max, extra_d.max())
839
+
840
+ xg_1d = np.linspace(
841
+ s_min - (s_max - s_min) * 0.1, s_max + (s_max - s_min) * 0.1, 150
791
842
  )
792
- s_min, s_max = min(s_min, extra_s.min()), max(s_max, extra_s.max())
793
- d_min, d_max = min(d_min, extra_d.min()), max(d_max, extra_d.max())
843
+ # Y-grid centered on 0, covering at least the data range
844
+ x_span = xg_1d.max() - xg_1d.min()
845
+ y_half = max(x_span / 2, abs(d_data.max()), abs(d_data.min())) * 1.1
846
+ yg_1d = np.linspace(-y_half, y_half, 150)
794
847
 
795
- xg_1d = np.linspace(
796
- s_min - (s_max - s_min) * 0.1, s_max + (s_max - s_min) * 0.1, 150
797
- )
798
- # Y-grid: same span as X (preserves aspect=equal), centered at 0
799
- x_span = xg_1d.max() - xg_1d.min()
800
- y_half = x_span / 2
801
- yg_1d = np.linspace(-y_half, y_half, 150)
802
848
  xg, yg = np.meshgrid(xg_1d, yg_1d)
803
849
  else:
804
850
  r_min, r_max = rmsd_r.min(), rmsd_r.max()
@@ -886,6 +932,28 @@ def plot_landscape_surface(
886
932
  grid_pts_eval = np.column_stack([xg.ravel(), yg.ravel()])
887
933
 
888
934
  _grad_stack = np.column_stack([grad_r, grad_p]) if grad_r is not None else None
935
+
936
+ # Convergence-based heteroscedastic noise: early (unconverged) NEB steps
937
+ # get higher noise so the GP trusts the converged data more. This allows
938
+ # using all optimization steps for off-path coverage without corrupting
939
+ # the surface fit near the converged path.
940
+ noise_per_obs = None
941
+ if step_data is not None:
942
+ max_s = int(step_data.max())
943
+ if max_s > 0:
944
+ last_mask = step_data == max_s
945
+ last_z = z_data[last_mask]
946
+ n_imgs = int(last_mask.sum())
947
+ noise_per_obs = np.full(len(z_data), best_noise)
948
+ for s in range(max_s + 1):
949
+ s_mask = step_data == s
950
+ s_z = z_data[s_mask]
951
+ if len(s_z) == n_imgs:
952
+ dev = np.mean(np.abs(s_z - last_z))
953
+ else:
954
+ dev = 10.0
955
+ noise_per_obs[s_mask] = best_noise + dev
956
+
889
957
  rbf = model_class(
890
958
  x=np.column_stack([rmsd_r, rmsd_p]),
891
959
  y=z_data,
@@ -894,6 +962,7 @@ def plot_landscape_surface(
894
962
  smoothing=best_noise,
895
963
  optimize=False,
896
964
  nimags=actual_nimags,
965
+ noise_per_obs=noise_per_obs,
897
966
  **_approx_kwargs,
898
967
  )
899
968
 
@@ -999,6 +1068,7 @@ def plot_landscape_path_overlay(
999
1068
  all_r=None,
1000
1069
  all_p=None,
1001
1070
  all_z=None,
1071
+ basis=None,
1002
1072
  ) -> Any:
1003
1073
  """Overlay the colored path line on the landscape.
1004
1074
 
@@ -1018,7 +1088,8 @@ def plot_landscape_path_overlay(
1018
1088
  ```
1019
1089
  """
1020
1090
  if project_path:
1021
- basis = compute_projection_basis(r, p)
1091
+ if basis is None:
1092
+ basis = compute_projection_basis(r, p)
1022
1093
  plot_x, plot_y = project_to_sd(r, p, basis)
1023
1094
  else:
1024
1095
  plot_x = r
@@ -1,34 +0,0 @@
1
- # file generated by setuptools-scm
2
- # don't change, don't track in version control
3
-
4
- __all__ = [
5
- "__version__",
6
- "__version_tuple__",
7
- "version",
8
- "version_tuple",
9
- "__commit_id__",
10
- "commit_id",
11
- ]
12
-
13
- TYPE_CHECKING = False
14
- if TYPE_CHECKING:
15
- from typing import Tuple
16
- from typing import Union
17
-
18
- VERSION_TUPLE = Tuple[Union[int, str], ...]
19
- COMMIT_ID = Union[str, None]
20
- else:
21
- VERSION_TUPLE = object
22
- COMMIT_ID = object
23
-
24
- version: str
25
- __version__: str
26
- __version_tuple__: VERSION_TUPLE
27
- version_tuple: VERSION_TUPLE
28
- commit_id: COMMIT_ID
29
- __commit_id__: COMMIT_ID
30
-
31
- __version__ = version = '1.5.1'
32
- __version_tuple__ = version_tuple = (1, 5, 1)
33
-
34
- __commit_id__ = commit_id = None
File without changes
File without changes
File without changes