chemparseplot 1.5.2__tar.gz → 1.5.4__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.2 → chemparseplot-1.5.4}/PKG-INFO +1 -2
  2. chemparseplot-1.5.4/_version.py +24 -0
  3. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/plot/neb.py +75 -13
  4. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/pyproject.toml +1 -1
  5. chemparseplot-1.5.2/_version.py +0 -34
  6. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/.gitignore +0 -0
  7. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/LICENSE +0 -0
  8. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/__init__.py +0 -0
  9. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/__init__.py +0 -0
  10. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/chemgp_hdf5.py +0 -0
  11. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/chemgp_jsonl.py +0 -0
  12. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/converter.py +0 -0
  13. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/eon/__init__.py +0 -0
  14. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/eon/dimer_trajectory.py +0 -0
  15. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/eon/gprd.py +0 -0
  16. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/eon/min_trajectory.py +0 -0
  17. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/eon/minimization.py +0 -0
  18. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/eon/neb.py +0 -0
  19. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/eon/saddle_search.py +0 -0
  20. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/file_.py +0 -0
  21. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/neb_utils.py +0 -0
  22. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/orca/__init__.py +0 -0
  23. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/orca/geomscan.py +0 -0
  24. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/orca/neb/__init__.py +0 -0
  25. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/orca/neb/interp.py +0 -0
  26. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/orca/neb/opi_parser.py +0 -0
  27. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/patterns.py +0 -0
  28. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/plumed.py +0 -0
  29. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/projection.py +0 -0
  30. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/sella/saddle_search.py +0 -0
  31. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/trajectory/__init__.py +0 -0
  32. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/trajectory/hdf5.py +0 -0
  33. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/parse/trajectory/neb.py +0 -0
  34. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/plot/__init__.py +0 -0
  35. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/plot/chemgp.py +0 -0
  36. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/plot/geomscan.py +0 -0
  37. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/plot/optimization.py +0 -0
  38. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/plot/plumed.py +0 -0
  39. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/plot/structs.py +0 -0
  40. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/plot/theme.py +0 -0
  41. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/units.py +0 -0
  42. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/chemparseplot/util.py +0 -0
  43. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/readme.md +0 -0
  44. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/tests/conftest.py +0 -0
  45. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/tests/parse/orca/test_geomscan.py +0 -0
  46. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/tests/parse/orca/test_interp.py +0 -0
  47. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/tests/parse/test_chemgp_hdf5.py +0 -0
  48. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/tests/parse/test_converter.py +0 -0
  49. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/tests/parse/test_dimer_trajectory.py +0 -0
  50. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/tests/parse/test_min_trajectory.py +0 -0
  51. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/tests/parse/test_neb_utils.py +0 -0
  52. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/tests/parse/test_patterns.py +0 -0
  53. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/tests/parse/test_plumed.py +0 -0
  54. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/tests/parse/test_projection.py +0 -0
  55. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/tests/parse/test_trajectory_hdf5.py +0 -0
  56. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/tests/parse/test_trajectory_neb.py +0 -0
  57. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/tests/plot/__init__.py +0 -0
  58. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/tests/plot/test_chemgp_utils.py +0 -0
  59. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/tests/plot/test_neb_renderers.py +0 -0
  60. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/tests/plot/test_optimization.py +0 -0
  61. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/tests/plot/test_projection_refactor.py +0 -0
  62. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/tests/plot/test_strip_rendering.py +0 -0
  63. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/tests/test_coverage_batch.py +0 -0
  64. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/tests/test_full_coverage.py +0 -0
  65. {chemparseplot-1.5.2 → chemparseplot-1.5.4}/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.2
3
+ Version: 1.5.4
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
@@ -20,7 +20,6 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
20
20
  Requires-Python: >=3.10
21
21
  Requires-Dist: numpy>=1.26.2
22
22
  Requires-Dist: pint>=0.22
23
- Requires-Dist: rgpycrumbs>=1.3.0
24
23
  Provides-Extra: all
25
24
  Requires-Dist: ase>=3.22; extra == 'all'
26
25
  Requires-Dist: cmcrameri>=1.7; extra == 'all'
@@ -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.4'
22
+ __version_tuple__ = version_tuple = (1, 5, 4)
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
@@ -759,6 +786,7 @@ def plot_landscape_surface(
759
786
  n_inducing=None,
760
787
  xlim=None,
761
788
  ylim=None,
789
+ basis=None,
762
790
  ) -> Any:
763
791
  """Plot the 2D landscape surface using reaction valley projection.
764
792
 
@@ -770,6 +798,14 @@ def plot_landscape_surface(
770
798
  The method rotates the RMSD plane into reaction progress and orthogonal
771
799
  deviation coordinates.
772
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
+
773
809
  ```{versionadded} 0.1.0
774
810
  ```
775
811
 
@@ -779,7 +815,8 @@ def plot_landscape_surface(
779
815
  """
780
816
  log.info(f"Generating 2D surface using {method} (Projected: {project_path})...")
781
817
 
782
- 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)
783
820
 
784
821
  # --- 1. Grid Setup (Handles both Projection and Standard RMSD) ---
785
822
  if project_path:
@@ -803,9 +840,9 @@ def plot_landscape_surface(
803
840
  xg_1d = np.linspace(
804
841
  s_min - (s_max - s_min) * 0.1, s_max + (s_max - s_min) * 0.1, 150
805
842
  )
806
- # Y-grid: same span as X (preserves aspect=equal), centered on 0
843
+ # Y-grid centered on 0, covering at least the data range
807
844
  x_span = xg_1d.max() - xg_1d.min()
808
- y_half = x_span / 2
845
+ y_half = max(x_span / 2, abs(d_data.max()), abs(d_data.min())) * 1.1
809
846
  yg_1d = np.linspace(-y_half, y_half, 150)
810
847
 
811
848
  xg, yg = np.meshgrid(xg_1d, yg_1d)
@@ -895,6 +932,28 @@ def plot_landscape_surface(
895
932
  grid_pts_eval = np.column_stack([xg.ravel(), yg.ravel()])
896
933
 
897
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
+
898
957
  rbf = model_class(
899
958
  x=np.column_stack([rmsd_r, rmsd_p]),
900
959
  y=z_data,
@@ -903,6 +962,7 @@ def plot_landscape_surface(
903
962
  smoothing=best_noise,
904
963
  optimize=False,
905
964
  nimags=actual_nimags,
965
+ noise_per_obs=noise_per_obs,
906
966
  **_approx_kwargs,
907
967
  )
908
968
 
@@ -1008,6 +1068,7 @@ def plot_landscape_path_overlay(
1008
1068
  all_r=None,
1009
1069
  all_p=None,
1010
1070
  all_z=None,
1071
+ basis=None,
1011
1072
  ) -> Any:
1012
1073
  """Overlay the colored path line on the landscape.
1013
1074
 
@@ -1027,7 +1088,8 @@ def plot_landscape_path_overlay(
1027
1088
  ```
1028
1089
  """
1029
1090
  if project_path:
1030
- basis = compute_projection_basis(r, p)
1091
+ if basis is None:
1092
+ basis = compute_projection_basis(r, p)
1031
1093
  plot_x, plot_y = project_to_sd(r, p, basis)
1032
1094
  else:
1033
1095
  plot_x = r
@@ -27,7 +27,7 @@ classifiers = [
27
27
  "Programming Language :: Python :: Implementation :: CPython",
28
28
  ]
29
29
  dynamic = ["version"]
30
- dependencies = ["numpy>=1.26.2", "pint>=0.22", "rgpycrumbs>=1.3.0"]
30
+ dependencies = ["numpy>=1.26.2", "pint>=0.22"]
31
31
 
32
32
  [project.optional-dependencies]
33
33
  doc = [
@@ -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.2'
32
- __version_tuple__ = version_tuple = (1, 5, 2)
33
-
34
- __commit_id__ = commit_id = None
File without changes
File without changes
File without changes