matterviz 0.4.1 → 0.4.2

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 (395) hide show
  1. package/dist/EmptyState.svelte +10 -4
  2. package/dist/FilePicker.svelte +12 -14
  3. package/dist/Icon.svelte +7 -4
  4. package/dist/MillerIndexInput.svelte +2 -2
  5. package/dist/app.css +53 -0
  6. package/dist/brillouin/BrillouinZone.svelte +75 -85
  7. package/dist/brillouin/BrillouinZone.svelte.d.ts +5 -7
  8. package/dist/brillouin/BrillouinZoneControls.svelte +3 -6
  9. package/dist/brillouin/BrillouinZoneExportPane.svelte +18 -14
  10. package/dist/brillouin/BrillouinZoneInfoPane.svelte +6 -10
  11. package/dist/brillouin/BrillouinZoneScene.svelte +26 -39
  12. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
  13. package/dist/chempot-diagram/ChemPotDiagram.svelte +33 -38
  14. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +62 -74
  15. package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +1 -1
  16. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +511 -547
  17. package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +1 -1
  18. package/dist/chempot-diagram/async-compute.svelte.js +1 -1
  19. package/dist/chempot-diagram/controls-state.svelte.js +1 -1
  20. package/dist/colors/index.d.ts +0 -4
  21. package/dist/colors/index.js +19 -20
  22. package/dist/composition/BarChart.svelte +37 -31
  23. package/dist/composition/BubbleChart.svelte +17 -17
  24. package/dist/composition/Composition.svelte +7 -11
  25. package/dist/composition/Formula.svelte +18 -25
  26. package/dist/composition/FormulaFilter.svelte +92 -95
  27. package/dist/composition/PieChart.svelte +55 -41
  28. package/dist/composition/format.js +1 -1
  29. package/dist/composition/index.d.ts +2 -0
  30. package/dist/composition/index.js +14 -0
  31. package/dist/composition/parse.d.ts +2 -2
  32. package/dist/composition/parse.js +11 -10
  33. package/dist/constants.js +11 -9
  34. package/dist/convex-hull/ConvexHull.svelte +12 -15
  35. package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
  36. package/dist/convex-hull/ConvexHull2D.svelte +93 -92
  37. package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
  38. package/dist/convex-hull/ConvexHull3D.svelte +109 -140
  39. package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
  40. package/dist/convex-hull/ConvexHull4D.svelte +75 -94
  41. package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
  42. package/dist/convex-hull/ConvexHullChrome.svelte +36 -40
  43. package/dist/convex-hull/ConvexHullControls.svelte +46 -48
  44. package/dist/convex-hull/ConvexHullStats.svelte +193 -195
  45. package/dist/convex-hull/ConvexHullTooltip.svelte +5 -12
  46. package/dist/convex-hull/GasPressureControls.svelte +5 -12
  47. package/dist/convex-hull/StructurePopup.svelte +17 -21
  48. package/dist/convex-hull/StructurePopup.svelte.d.ts +2 -0
  49. package/dist/convex-hull/TemperatureSlider.svelte +4 -10
  50. package/dist/convex-hull/canvas-interactions.svelte.js +2 -1
  51. package/dist/convex-hull/helpers.d.ts +8 -10
  52. package/dist/convex-hull/helpers.js +36 -36
  53. package/dist/convex-hull/hull-state.svelte.d.ts +1 -1
  54. package/dist/convex-hull/thermodynamics.js +18 -17
  55. package/dist/coordination/CoordinationBarPlot.svelte +38 -33
  56. package/dist/coordination/CoordinationBarPlot.svelte.d.ts +1 -1
  57. package/dist/coordination/calc-coordination.d.ts +1 -1
  58. package/dist/coordination/calc-coordination.js +28 -25
  59. package/dist/element/BohrAtom.svelte +5 -8
  60. package/dist/element/ElementHeading.svelte +4 -1
  61. package/dist/element/ElementPhoto.svelte +11 -9
  62. package/dist/element/ElementStats.svelte +12 -10
  63. package/dist/element/ElementTile.svelte +24 -29
  64. package/dist/element/Nucleus.svelte +4 -2
  65. package/dist/element/data.d.ts +1 -2
  66. package/dist/element/helpers.d.ts +4 -0
  67. package/dist/element/helpers.js +18 -0
  68. package/dist/element/index.d.ts +1 -4
  69. package/dist/element/index.js +3 -18
  70. package/dist/feedback/DragOverlay.svelte +5 -5
  71. package/dist/feedback/DragOverlay.svelte.d.ts +2 -2
  72. package/dist/feedback/StatusMessage.svelte +7 -4
  73. package/dist/fermi-surface/FermiSlice.svelte +21 -18
  74. package/dist/fermi-surface/FermiSurface.svelte +14 -22
  75. package/dist/fermi-surface/FermiSurface.svelte.d.ts +5 -7
  76. package/dist/fermi-surface/FermiSurfaceControls.svelte +6 -20
  77. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
  78. package/dist/fermi-surface/FermiSurfaceScene.svelte +37 -64
  79. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
  80. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +9 -6
  81. package/dist/fermi-surface/compute.js +3 -3
  82. package/dist/fermi-surface/parse.js +22 -24
  83. package/dist/heatmap-matrix/HeatmapMatrix.svelte +109 -148
  84. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +2 -2
  85. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +9 -7
  86. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +1 -1
  87. package/dist/heatmap-matrix/index.d.ts +5 -0
  88. package/dist/icons.d.ts +4 -0
  89. package/dist/icons.js +4 -0
  90. package/dist/io/ExportPane.svelte +10 -6
  91. package/dist/io/decompress.d.ts +2 -1
  92. package/dist/io/decompress.js +22 -35
  93. package/dist/io/export.d.ts +4 -0
  94. package/dist/io/export.js +5 -1
  95. package/dist/io/fetch.d.ts +0 -3
  96. package/dist/io/fetch.js +0 -11
  97. package/dist/io/index.d.ts +0 -1
  98. package/dist/io/index.js +2 -9
  99. package/dist/io/is-binary.d.ts +9 -0
  100. package/dist/io/is-binary.js +45 -1
  101. package/dist/io/url-drop.js +13 -25
  102. package/dist/isosurface/Isosurface.svelte +17 -23
  103. package/dist/isosurface/IsosurfaceControls.svelte +37 -42
  104. package/dist/isosurface/parse-vaspwave.d.ts +3 -0
  105. package/dist/isosurface/parse-vaspwave.js +138 -0
  106. package/dist/isosurface/parse.js +6 -6
  107. package/dist/labels.d.ts +6 -2
  108. package/dist/labels.js +43 -13
  109. package/dist/layout/FullscreenButton.svelte +2 -1
  110. package/dist/layout/FullscreenToggle.svelte +10 -4
  111. package/dist/layout/InfoCard.svelte +7 -18
  112. package/dist/layout/InfoTag.svelte +1 -3
  113. package/dist/layout/NumberRangeInput.svelte +46 -0
  114. package/dist/layout/NumberRangeInput.svelte.d.ts +12 -0
  115. package/dist/layout/PropertyFilter.svelte +2 -6
  116. package/dist/layout/SettingsSection.svelte +21 -17
  117. package/dist/layout/SubpageGrid.svelte +3 -1
  118. package/dist/layout/ViewerChrome.svelte +9 -10
  119. package/dist/layout/ViewerChrome.svelte.d.ts +2 -1
  120. package/dist/layout/fullscreen.js +3 -5
  121. package/dist/layout/fullscreen.svelte.js +1 -2
  122. package/dist/layout/index.d.ts +1 -0
  123. package/dist/layout/index.js +1 -0
  124. package/dist/layout/json-tree/JsonNode.svelte +8 -11
  125. package/dist/layout/json-tree/JsonTree.svelte +53 -77
  126. package/dist/layout/json-tree/JsonValue.svelte +7 -15
  127. package/dist/layout/json-tree/utils.js +14 -23
  128. package/dist/math.d.ts +2 -0
  129. package/dist/math.js +19 -0
  130. package/dist/overlays/ContextMenu.svelte +4 -2
  131. package/dist/overlays/CopyButton.svelte +11 -5
  132. package/dist/overlays/DragControlTab.svelte +6 -1
  133. package/dist/overlays/DraggablePane.svelte +81 -26
  134. package/dist/overlays/DraggablePane.svelte.d.ts +1 -0
  135. package/dist/overlays/GlassChip.svelte +30 -0
  136. package/dist/overlays/GlassChip.svelte.d.ts +8 -0
  137. package/dist/overlays/InfoPaneCards.svelte +11 -23
  138. package/dist/overlays/index.d.ts +7 -0
  139. package/dist/overlays/index.js +26 -0
  140. package/dist/overlays/portal.d.ts +2 -0
  141. package/dist/overlays/portal.js +14 -0
  142. package/dist/periodic-table/PeriodicTable.svelte +113 -145
  143. package/dist/periodic-table/PeriodicTable.svelte.d.ts +5 -3
  144. package/dist/periodic-table/PeriodicTableControls.svelte +11 -63
  145. package/dist/periodic-table/TableInset.svelte +9 -4
  146. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +50 -71
  147. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -8
  148. package/dist/phase-diagram/PhaseDiagramControls.svelte +70 -94
  149. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
  150. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +2 -1
  151. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +12 -12
  152. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +54 -58
  153. package/dist/phase-diagram/TdbInfoPanel.svelte +21 -15
  154. package/dist/phase-diagram/build-diagram.js +3 -3
  155. package/dist/phase-diagram/diagram-input.d.ts +1 -2
  156. package/dist/phase-diagram/parse.js +15 -15
  157. package/dist/phase-diagram/svg-to-diagram.js +21 -15
  158. package/dist/phase-diagram/utils.js +2 -3
  159. package/dist/plot/bar/BarPlot.svelte +430 -391
  160. package/dist/plot/bar/BarPlot.svelte.d.ts +2 -0
  161. package/dist/plot/bar/BarPlotControls.svelte +1 -3
  162. package/dist/plot/bar/BarPlotControls.svelte.d.ts +4 -6
  163. package/dist/plot/bar/SpacegroupBarPlot.svelte +29 -36
  164. package/dist/plot/bar/data.d.ts +5 -4
  165. package/dist/plot/bar/data.js +2 -1
  166. package/dist/plot/box/BoxPlot.svelte +301 -209
  167. package/dist/plot/box/BoxPlot.svelte.d.ts +2 -0
  168. package/dist/plot/box/Violin.svelte.d.ts +1 -0
  169. package/dist/plot/box/box-plot.js +1 -1
  170. package/dist/plot/core/auto-place.js +1 -1
  171. package/dist/plot/core/axis-utils.d.ts +12 -7
  172. package/dist/plot/core/axis-utils.js +48 -48
  173. package/dist/plot/core/components/AxisLabel.svelte +82 -20
  174. package/dist/plot/core/components/AxisLabel.svelte.d.ts +1 -0
  175. package/dist/plot/core/components/ColorBar.svelte +101 -106
  176. package/dist/plot/core/components/ColorScaleSelect.svelte +1 -1
  177. package/dist/plot/core/components/FillArea.svelte +10 -17
  178. package/dist/plot/core/components/HierarchyControls.svelte +249 -0
  179. package/dist/plot/{sunburst/SunburstControls.svelte.d.ts → core/components/HierarchyControls.svelte.d.ts} +12 -8
  180. package/dist/plot/core/components/InteractiveAxisLabel.svelte +1 -1
  181. package/dist/plot/core/components/InteractiveAxisLabel.svelte.d.ts +1 -1
  182. package/dist/plot/core/components/Line.svelte +18 -9
  183. package/dist/plot/core/components/Line.svelte.d.ts +2 -0
  184. package/dist/plot/core/components/PlotAxis.svelte +40 -17
  185. package/dist/plot/core/components/PlotControls.svelte +65 -41
  186. package/dist/plot/core/components/PlotLegend.svelte +31 -35
  187. package/dist/plot/core/components/PlotMarginals.svelte +616 -0
  188. package/dist/plot/core/components/PlotMarginals.svelte.d.ts +15 -0
  189. package/dist/plot/core/components/PlotTooltip.svelte +1 -1
  190. package/dist/plot/core/components/PortalSelect.svelte +4 -8
  191. package/dist/plot/core/components/ReferenceLine.svelte +27 -24
  192. package/dist/plot/core/components/ReferenceLine3D.svelte +54 -57
  193. package/dist/plot/core/components/ReferencePlane.svelte +7 -8
  194. package/dist/plot/core/components/ZeroLines.svelte +4 -8
  195. package/dist/plot/core/components/ZoomRect.svelte +1 -2
  196. package/dist/plot/core/components/index.d.ts +1 -0
  197. package/dist/plot/core/components/index.js +1 -0
  198. package/dist/plot/core/data-cleaning-signal.d.ts +46 -0
  199. package/dist/plot/core/data-cleaning-signal.js +467 -0
  200. package/dist/plot/core/data-cleaning.d.ts +2 -42
  201. package/dist/plot/core/data-cleaning.js +27 -474
  202. package/dist/plot/core/data-transform.js +9 -5
  203. package/dist/plot/core/fill-utils.d.ts +3 -1
  204. package/dist/plot/core/fill-utils.js +28 -6
  205. package/dist/plot/core/index.d.ts +1 -0
  206. package/dist/plot/core/index.js +1 -0
  207. package/dist/plot/core/interactions.js +0 -2
  208. package/dist/plot/core/layout.d.ts +3 -1
  209. package/dist/plot/core/layout.js +22 -13
  210. package/dist/plot/core/marginals.d.ts +170 -0
  211. package/dist/plot/core/marginals.js +436 -0
  212. package/dist/plot/core/reference-line.js +1 -1
  213. package/dist/plot/core/scales.d.ts +23 -0
  214. package/dist/plot/core/scales.js +39 -13
  215. package/dist/plot/core/types/fills.d.ts +101 -0
  216. package/dist/plot/core/types/fills.js +15 -0
  217. package/dist/plot/core/types/plot-3d.d.ts +87 -0
  218. package/dist/plot/core/types/plot-3d.js +4 -0
  219. package/dist/plot/core/types/reference-lines.d.ts +140 -0
  220. package/dist/plot/core/types/reference-lines.js +9 -0
  221. package/dist/plot/core/types.d.ts +29 -324
  222. package/dist/plot/core/types.js +23 -20
  223. package/dist/plot/core/utils/hierarchy-chart.d.ts +51 -0
  224. package/dist/plot/core/utils/hierarchy-chart.js +179 -0
  225. package/dist/plot/core/utils/hierarchy-labels.d.ts +20 -0
  226. package/dist/plot/core/utils/hierarchy-labels.js +99 -0
  227. package/dist/plot/core/utils/label-placement.js +2 -2
  228. package/dist/plot/histogram/Histogram.svelte +304 -325
  229. package/dist/plot/histogram/Histogram.svelte.d.ts +7 -7
  230. package/dist/plot/histogram/HistogramControls.svelte +30 -28
  231. package/dist/plot/histogram/histogram.d.ts +31 -0
  232. package/dist/plot/histogram/histogram.js +70 -0
  233. package/dist/plot/histogram/index.d.ts +1 -0
  234. package/dist/plot/histogram/index.js +1 -0
  235. package/dist/plot/index.d.ts +1 -0
  236. package/dist/plot/index.js +1 -0
  237. package/dist/plot/sankey/Sankey.svelte +78 -69
  238. package/dist/plot/sankey/Sankey.svelte.d.ts +2 -2
  239. package/dist/plot/sankey/SankeyControls.svelte +22 -16
  240. package/dist/plot/scatter/BinnedScatterPlot.svelte +263 -109
  241. package/dist/plot/scatter/BinnedScatterPlot.svelte.d.ts +7 -0
  242. package/dist/plot/scatter/ElementScatter.svelte +4 -1
  243. package/dist/plot/scatter/ScatterPlot.svelte +477 -385
  244. package/dist/plot/scatter/ScatterPlot.svelte.d.ts +2 -0
  245. package/dist/plot/scatter/ScatterPlotControls.svelte +18 -19
  246. package/dist/plot/scatter/ScatterPlotControls.svelte.d.ts +1 -1
  247. package/dist/plot/scatter/ScatterPoint.svelte +16 -9
  248. package/dist/plot/scatter/binned-scatter-types.d.ts +3 -2
  249. package/dist/plot/scatter/binned-scatter-types.js +6 -1
  250. package/dist/plot/scatter/scatter-data.d.ts +1 -1
  251. package/dist/plot/scatter/scatter-data.js +8 -7
  252. package/dist/plot/scatter-3d/ScatterPlot3D.svelte +25 -34
  253. package/dist/plot/scatter-3d/ScatterPlot3D.svelte.d.ts +2 -2
  254. package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte +8 -5
  255. package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte +113 -116
  256. package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte.d.ts +2 -2
  257. package/dist/plot/scatter-3d/Surface3D.svelte +4 -13
  258. package/dist/plot/sunburst/Sunburst.svelte +251 -329
  259. package/dist/plot/sunburst/Sunburst.svelte.d.ts +2 -2
  260. package/dist/plot/sunburst/index.d.ts +1 -1
  261. package/dist/plot/sunburst/index.js +2 -1
  262. package/dist/plot/sunburst/render.d.ts +2 -2
  263. package/dist/plot/sunburst/render.js +47 -22
  264. package/dist/plot/sunburst/sunburst.d.ts +5 -1
  265. package/dist/plot/sunburst/sunburst.js +10 -3
  266. package/dist/plot/treemap/Treemap.svelte +907 -0
  267. package/dist/plot/treemap/Treemap.svelte.d.ts +84 -0
  268. package/dist/plot/treemap/index.d.ts +3 -0
  269. package/dist/plot/treemap/index.js +4 -0
  270. package/dist/plot/treemap/treemap.d.ts +26 -0
  271. package/dist/plot/treemap/treemap.js +99 -0
  272. package/dist/rdf/RdfPlot.svelte +22 -26
  273. package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
  274. package/dist/rdf/calc-rdf.js +4 -8
  275. package/dist/sanitize.js +1 -1
  276. package/dist/scene/bind-renderer.svelte.js +14 -6
  277. package/dist/settings.d.ts +19 -9
  278. package/dist/settings.js +77 -50
  279. package/dist/spectral/Bands.svelte +223 -230
  280. package/dist/spectral/BandsAndDos.svelte +11 -9
  281. package/dist/spectral/BrillouinBandsDos.svelte +19 -27
  282. package/dist/spectral/Dos.svelte +70 -73
  283. package/dist/spectral/helpers.d.ts +3 -3
  284. package/dist/spectral/helpers.js +25 -35
  285. package/dist/state.svelte.js +5 -18
  286. package/dist/structure/Arrow.svelte +5 -18
  287. package/dist/structure/ArrowInstances.svelte +160 -0
  288. package/dist/structure/ArrowInstances.svelte.d.ts +16 -0
  289. package/dist/structure/AtomLegend.svelte +115 -75
  290. package/dist/structure/AtomLegend.svelte.d.ts +1 -1
  291. package/dist/structure/Bond.svelte +31 -23
  292. package/dist/structure/CanvasTooltip.svelte +15 -3
  293. package/dist/structure/CellSelect.svelte +11 -26
  294. package/dist/structure/Cylinder.svelte +24 -40
  295. package/dist/structure/InstancedAtoms.svelte +114 -0
  296. package/dist/structure/InstancedAtoms.svelte.d.ts +15 -0
  297. package/dist/structure/Lattice.svelte +85 -149
  298. package/dist/structure/SiteLabels.svelte +122 -0
  299. package/dist/structure/SiteLabels.svelte.d.ts +18 -0
  300. package/dist/structure/Structure.svelte +473 -419
  301. package/dist/structure/Structure.svelte.d.ts +4 -2
  302. package/dist/structure/StructureCarousel.svelte +630 -0
  303. package/dist/structure/StructureCarousel.svelte.d.ts +19 -0
  304. package/dist/structure/StructureControls.svelte +157 -399
  305. package/dist/structure/StructureControls.svelte.d.ts +1 -1
  306. package/dist/structure/StructureExportPane.svelte +17 -21
  307. package/dist/structure/StructureInfoPane.svelte +72 -66
  308. package/dist/structure/StructureInfoPane.svelte.d.ts +1 -1
  309. package/dist/structure/StructureScene.svelte +467 -476
  310. package/dist/structure/StructureScene.svelte.d.ts +3 -1
  311. package/dist/structure/StructureViewport.svelte +386 -0
  312. package/dist/structure/StructureViewport.svelte.d.ts +63 -0
  313. package/dist/structure/atom-label-placement.d.ts +16 -12
  314. package/dist/structure/atom-label-placement.js +70 -37
  315. package/dist/structure/atom-properties.d.ts +2 -0
  316. package/dist/structure/atom-properties.js +104 -38
  317. package/dist/structure/bonding.d.ts +10 -3
  318. package/dist/structure/bonding.js +84 -28
  319. package/dist/structure/edit-history.d.ts +6 -0
  320. package/dist/structure/edit-history.js +27 -0
  321. package/dist/structure/export.d.ts +1 -0
  322. package/dist/structure/export.js +39 -31
  323. package/dist/structure/format-detect.d.ts +1 -0
  324. package/dist/structure/format-detect.js +22 -0
  325. package/dist/structure/geometry.d.ts +9 -0
  326. package/dist/structure/geometry.js +27 -0
  327. package/dist/structure/index.d.ts +16 -1
  328. package/dist/structure/index.js +13 -2
  329. package/dist/structure/measure.d.ts +1 -1
  330. package/dist/structure/measure.js +6 -12
  331. package/dist/structure/parse.d.ts +2 -1
  332. package/dist/structure/parse.js +243 -222
  333. package/dist/structure/partial-occupancy.js +4 -2
  334. package/dist/structure/pbc.js +78 -98
  335. package/dist/structure/polyhedra.d.ts +0 -1
  336. package/dist/structure/polyhedra.js +3 -18
  337. package/dist/structure/supercell.d.ts +1 -2
  338. package/dist/structure/supercell.js +7 -13
  339. package/dist/symmetry/SymmetryElements.svelte +11 -15
  340. package/dist/symmetry/SymmetryStats.svelte +56 -68
  341. package/dist/symmetry/WyckoffTable.svelte +5 -24
  342. package/dist/symmetry/cell-transform.js +1 -0
  343. package/dist/symmetry/index.d.ts +1 -0
  344. package/dist/symmetry/index.js +8 -2
  345. package/dist/symmetry/spacegroups.js +3 -2
  346. package/dist/table/HeatmapTable.svelte +1102 -365
  347. package/dist/table/HeatmapTable.svelte.d.ts +12 -2
  348. package/dist/table/ToggleMenu.svelte +5 -12
  349. package/dist/table/index.d.ts +21 -6
  350. package/dist/table/index.js +34 -21
  351. package/dist/theme/ThemeControl.svelte +16 -8
  352. package/dist/theme/index.d.ts +1 -5
  353. package/dist/theme/index.js +4 -10
  354. package/dist/theme/themes.mjs +14 -7
  355. package/dist/tooltip/KCoords.svelte +4 -1
  356. package/dist/tooltip/TooltipContent.svelte +2 -5
  357. package/dist/trajectory/Trajectory.svelte +515 -308
  358. package/dist/trajectory/Trajectory.svelte.d.ts +1 -1
  359. package/dist/trajectory/TrajectoryError.svelte +11 -8
  360. package/dist/trajectory/TrajectoryExportPane.svelte +14 -31
  361. package/dist/trajectory/TrajectoryInfoPane.svelte +85 -97
  362. package/dist/trajectory/extract.js +56 -34
  363. package/dist/trajectory/format-detect.js +11 -9
  364. package/dist/trajectory/frame-reader.d.ts +2 -0
  365. package/dist/trajectory/frame-reader.js +33 -29
  366. package/dist/trajectory/helpers.d.ts +2 -0
  367. package/dist/trajectory/helpers.js +18 -7
  368. package/dist/trajectory/index.d.ts +1 -0
  369. package/dist/trajectory/index.js +3 -0
  370. package/dist/trajectory/parse/h5-utils.d.ts +13 -0
  371. package/dist/trajectory/parse/h5-utils.js +109 -0
  372. package/dist/trajectory/parse/hdf5.d.ts +1 -1
  373. package/dist/trajectory/parse/hdf5.js +116 -106
  374. package/dist/trajectory/parse/index.d.ts +2 -3
  375. package/dist/trajectory/parse/index.js +17 -20
  376. package/dist/trajectory/parse/lammps.js +8 -12
  377. package/dist/trajectory/parse/vasp.js +10 -7
  378. package/dist/trajectory/parse/vaspout-electronic.d.ts +13 -0
  379. package/dist/trajectory/parse/vaspout-electronic.js +207 -0
  380. package/dist/trajectory/parse/vaspout-h5.d.ts +5 -0
  381. package/dist/trajectory/parse/vaspout-h5.js +284 -0
  382. package/dist/trajectory/parse/xyz.js +11 -7
  383. package/dist/trajectory/plotting.d.ts +8 -9
  384. package/dist/trajectory/plotting.js +99 -27
  385. package/dist/utils.d.ts +3 -0
  386. package/dist/utils.js +7 -0
  387. package/dist/xrd/XrdPlot.svelte +47 -61
  388. package/dist/xrd/broadening.js +2 -1
  389. package/dist/xrd/calc-xrd.js +2 -4
  390. package/dist/xrd/parse.d.ts +0 -1
  391. package/dist/xrd/parse.js +56 -73
  392. package/package.json +61 -33
  393. package/dist/api/mp.d.ts +0 -6
  394. package/dist/api/mp.js +0 -22
  395. package/dist/plot/sunburst/SunburstControls.svelte +0 -200
@@ -59,8 +59,7 @@
59
59
 
60
60
  // Convert pressure to log scale slider position (0-100)
61
61
  const pressure_to_slider = (P: number): number =>
62
- ((Math.max(LOG_P_MIN, Math.min(LOG_P_MAX, Math.log10(P))) - LOG_P_MIN) /
63
- LOG_P_RANGE) * 100
62
+ ((Math.max(LOG_P_MIN, Math.min(LOG_P_MAX, Math.log10(P))) - LOG_P_MIN) / LOG_P_RANGE) * 100
64
63
 
65
64
  // Convert slider position (0-100) to pressure
66
65
  const slider_to_pressure = (value: number): number =>
@@ -68,7 +67,7 @@
68
67
 
69
68
  // Format gas name for display (subscript numbers)
70
69
  const format_gas_name = (gas: GasSpecies): string =>
71
- gas.replaceAll(/(\d+)/g, `<sub>$1</sub>`)
70
+ gas.replaceAll(/(?<digits>\d+)/g, `<sub>$1</sub>`)
72
71
 
73
72
  // Format pressure as plain text (no HTML) for the number input
74
73
  function format_pressure(P: number): string {
@@ -102,24 +101,18 @@
102
101
  }
103
102
 
104
103
  function set_pressure_direct(gas: GasSpecies, value: number): void {
105
- const clamped = Math.max(
106
- 10 ** LOG_P_MIN,
107
- Math.min(10 ** LOG_P_MAX, value),
108
- )
104
+ const clamped = Math.max(10 ** LOG_P_MIN, Math.min(10 ** LOG_P_MAX, value))
109
105
  pressures = { ...pressures, [gas]: clamped }
110
106
  }
111
107
  </script>
112
108
 
113
109
  {#if enabled_gases.length > 0}
114
- <div {...rest} class="pressure-controls {position} {rest.class ?? ``}">
110
+ <div {...rest} class={[`pressure-controls`, position, rest.class]}>
115
111
  {#each enabled_gases as gas (gas)}
116
112
  {@const P = get_pressure(gas)}
117
113
  {@const mu = get_mu(gas)}
118
114
  {@const tooltip_content = `${gas} partial pressure for μ(T,P)\nμ = ${format_chemical_potential(mu, 3)}`}
119
- <div
120
- class="pressure-slider"
121
- {@attach tooltip({ content: tooltip_content })}
122
- >
115
+ <div class="pressure-slider" {@attach tooltip({ content: tooltip_content })}>
123
116
  <label class="pressure-label">
124
117
  <input
125
118
  type="text"
@@ -3,7 +3,7 @@
3
3
  import { get_electro_neg_formula } from '../composition'
4
4
  import Icon from '../Icon.svelte'
5
5
  import { format_num } from '../labels'
6
- import { DragControlTab } from '../overlays'
6
+ import { DragControlTab, GlassChip } from '../overlays'
7
7
  import { sanitize_formula } from '../sanitize'
8
8
  import { Structure } from '../structure'
9
9
  import type { StructurePopupContext, StructurePopupStats } from './types'
@@ -17,6 +17,8 @@
17
17
  width = 500,
18
18
  height = 400,
19
19
  onclose,
20
+ close_on_outside = true,
21
+ show_drag_handle = true,
20
22
  stats,
21
23
  top_left,
22
24
  children,
@@ -28,6 +30,8 @@
28
30
  width?: number
29
31
  height?: number
30
32
  onclose?: () => void
33
+ close_on_outside?: boolean
34
+ show_drag_handle?: boolean
31
35
  stats?: StructurePopupStats
32
36
  top_left?: Snippet<[StructurePopupContext]>
33
37
  children?: Snippet<[StructurePopupContext]>
@@ -35,7 +39,8 @@
35
39
  } = $props()
36
40
 
37
41
  const formula_html = $derived.by(() =>
38
- sanitize_formula(get_electro_neg_formula(stats?.formula ?? structure, true)))
42
+ sanitize_formula(get_electro_neg_formula(stats?.formula ?? structure, true)),
43
+ )
39
44
  const context = $derived({ structure, stats, formula_html })
40
45
  </script>
41
46
 
@@ -48,6 +53,7 @@
48
53
  <svelte:window
49
54
  onkeydown={(event) => event.key === `Escape` && onclose?.()}
50
55
  onmousedown={(event) => {
56
+ if (!close_on_outside) return
51
57
  if (!popup_div || !(event.target instanceof Node)) return
52
58
  if (!popup_div.contains(event.target)) onclose?.()
53
59
  }}
@@ -58,34 +64,36 @@
58
64
  handle_selector: `.drag-handle`,
59
65
  })}
60
66
  {...rest}
61
- class="structure-popup {place_right ? `right` : `left`} {rest.class ?? ``}"
67
+ class={[`structure-popup`, place_right ? `right` : `left`, rest.class]}
62
68
  role="dialog"
63
69
  aria-modal="true"
64
70
  tabindex="-1"
65
71
  bind:this={popup_div}
66
72
  >
67
- <DragControlTab />
73
+ {#if show_drag_handle}
74
+ <DragControlTab />
75
+ {/if}
68
76
  <div class="structure-popup-content">
69
77
  {#if top_left || stats}
70
- <div class="structure-stats">
78
+ <GlassChip class="structure-stats">
71
79
  {#if top_left}
72
80
  {@render top_left(context)}
73
81
  {:else if stats}
74
82
  {#if stats.id}
75
- ID = {stats.id}<br>
83
+ ID = {stats.id}<br />
76
84
  {/if}
77
85
  {#if formula_html}
78
- {@html formula_html}<br>
86
+ {@html formula_html}<br />
79
87
  {/if}
80
88
  {#if stats.e_above_hull != null}
81
- E<sub>above hull</sub> = {format_num(stats.e_above_hull, `.3~`)} eV/atom<br>
89
+ E<sub>above hull</sub> = {format_num(stats.e_above_hull, `.3~`)} eV/atom<br />
82
90
  {/if}
83
91
  {#if stats.e_form != null}
84
92
  E<sub>form</sub> = {format_num(stats.e_form, `.3~`)}
85
93
  eV/atom
86
94
  {/if}
87
95
  {/if}
88
- </div>
96
+ </GlassChip>
89
97
  {/if}
90
98
 
91
99
  <Structure
@@ -136,16 +144,4 @@
136
144
  .close-btn:hover {
137
145
  background: var(--pane-btn-bg-hover);
138
146
  }
139
- .structure-stats {
140
- position: absolute;
141
- top: 10px;
142
- left: 10px;
143
- background: transparent;
144
- backdrop-filter: blur(8px);
145
- color: var(--text-color);
146
- padding: 4px 8px;
147
- border-radius: 6px;
148
- font-size: 0.85em;
149
- z-index: 2;
150
- }
151
147
  </style>
@@ -8,6 +8,8 @@ type $$ComponentProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {
8
8
  width?: number;
9
9
  height?: number;
10
10
  onclose?: () => void;
11
+ close_on_outside?: boolean;
12
+ show_drag_handle?: boolean;
11
13
  stats?: StructurePopupStats;
12
14
  top_left?: Snippet<[StructurePopupContext]>;
13
15
  children?: Snippet<[StructurePopupContext]>;
@@ -16,15 +16,11 @@
16
16
  let last_update_time = 0
17
17
  const THROTTLE_MS = 100
18
18
 
19
- const temp_index = $derived(
20
- Math.max(0, available_temperatures.indexOf(temperature)),
21
- )
19
+ const temp_index = $derived(Math.max(0, available_temperatures.indexOf(temperature)))
22
20
  const display_index = $derived(preview_index ?? temp_index)
23
21
  const display_temp = $derived(available_temperatures[display_index] ?? temperature)
24
22
 
25
- function handle_slider_input(
26
- event: Event & { currentTarget: HTMLInputElement },
27
- ): void {
23
+ function handle_slider_input(event: Event & { currentTarget: HTMLInputElement }): void {
28
24
  const new_index = Number(event.currentTarget.value)
29
25
  preview_index = new_index
30
26
  // Throttle parent updates during drag to prevent scene flashing
@@ -35,9 +31,7 @@
35
31
  }
36
32
  }
37
33
 
38
- function handle_slider_end(
39
- event: Event & { currentTarget: HTMLInputElement },
40
- ): void {
34
+ function handle_slider_end(event: Event & { currentTarget: HTMLInputElement }): void {
41
35
  const new_temp = available_temperatures[Number(event.currentTarget.value)]
42
36
  if (new_temp !== undefined) temperature = new_temp
43
37
  preview_index = null
@@ -53,7 +47,7 @@
53
47
 
54
48
  <div
55
49
  {...rest}
56
- class="temperature-slider {rest.class ?? ``}"
50
+ class={[`temperature-slider`, rest.class]}
57
51
  {@attach tooltip({ content: `Temperature for G(T) free energies` })}
58
52
  >
59
53
  <label class="temp-label">
@@ -123,7 +123,8 @@ export function create_canvas_interactions(inputs) {
123
123
  };
124
124
  const handle_wheel = (event) => {
125
125
  event.preventDefault();
126
- inputs.set_zoom(Math.max(zoom_min, Math.min(zoom_max, inputs.zoom() * (event.deltaY > 0 ? 0.98 : 1.02))));
126
+ const zoomed = inputs.zoom() * (event.deltaY > 0 ? 0.98 : 1.02);
127
+ inputs.set_zoom(Math.max(zoom_min, Math.min(zoom_max, zoomed)));
127
128
  };
128
129
  const handle_hover = (event) => {
129
130
  if (is_dragging)
@@ -3,12 +3,11 @@ import type { EnergyModeInfo } from './';
3
3
  import type { ElementSymbol } from '../element';
4
4
  import type { AnyStructure } from '../structure';
5
5
  import type { ConvexHullConfig, EntryCategoryConfig, GasAnalysis, GasThermodynamicsConfig, HighlightStyle, MarkerSymbol, PhaseData } from './types';
6
- import { DEFAULT_GAS_TEMP } from './types';
7
- export { DEFAULT_GAS_TEMP };
6
+ export { DEFAULT_GAS_TEMP } from './types';
8
7
  export declare const HULL_STABILITY_TOL = 0.000001;
9
- export declare function compute_hull_stability(raw_distance: number, exclude_from_hull?: boolean, tol?: number): {
10
- e_above_hull: number;
11
- is_stable: boolean;
8
+ export declare function compute_hull_stability(raw_distance: number | null | undefined, exclude_from_hull?: boolean, tol?: number): {
9
+ e_above_hull: number | undefined;
10
+ is_stable: boolean | undefined;
12
11
  };
13
12
  type StabilityEntry = {
14
13
  is_stable?: boolean;
@@ -17,8 +16,11 @@ type StabilityEntry = {
17
16
  export declare const extract_structure_from_entry: (entries: PhaseData[], entry: {
18
17
  entry_id?: string;
19
18
  }) => AnyStructure | null;
19
+ export declare const array_min: (values: readonly number[]) => number;
20
+ export declare const array_max: (values: readonly number[]) => number;
20
21
  export declare const hull_distance_range: (entries: PhaseData[]) => [number, number];
21
22
  export declare const entry_is_stable: (entry: StabilityEntry, tol?: number) => boolean;
23
+ export declare const entry_within_hull_dist: (entry: StabilityEntry, max_dist: number) => boolean;
22
24
  export declare const is_on_hull: (entry: PhaseData, tol?: number) => boolean;
23
25
  export declare const get_arity: (entry: PhaseData) => number;
24
26
  export declare const is_unary_entry: (entry: PhaseData) => boolean;
@@ -142,8 +144,4 @@ export declare function get_gas_corrected_entries(entries: PhaseData[], gas_conf
142
144
  analysis: GasAnalysis;
143
145
  merged_config: GasThermodynamicsConfig | undefined;
144
146
  };
145
- export declare function get_entry_label(entry: {
146
- reduced_formula?: string;
147
- name?: string;
148
- composition: Record<string, number>;
149
- }, elements?: ElementSymbol[]): string;
147
+ export declare function get_entry_label(entry: Pick<PhaseData, `reduced_formula` | `name` | `composition`>, elements?: ElementSymbol[]): string;
@@ -3,14 +3,19 @@ import { ELEM_SYMBOL_TO_NAME } from '../composition';
3
3
  import { format_fractional, format_num, symbol_map } from '../labels';
4
4
  import { scaleSequential } from 'd3-scale';
5
5
  import { symbol } from 'd3-shape';
6
- import { analyze_gas_data as _analyze_gas_data, apply_gas_corrections as _apply_gas_corrections, } from './gas-thermodynamics';
7
- import { DEFAULT_GAS_TEMP, MAGNETIC_ORDERING_CATEGORY } from './types';
8
- export { DEFAULT_GAS_TEMP };
6
+ import { analyze_gas_data, apply_gas_corrections } from './gas-thermodynamics';
7
+ import { MAGNETIC_ORDERING_CATEGORY } from './types';
8
+ export { DEFAULT_GAS_TEMP } from './types';
9
9
  // Tolerance for classifying a phase as on the convex hull (eV/atom)
10
10
  export const HULL_STABILITY_TOL = 1e-6;
11
11
  // Clamp raw hull distance and compute stability for a single entry.
12
12
  // Excluded entries keep their raw (possibly negative) distance and are never stable.
13
13
  export function compute_hull_stability(raw_distance, exclude_from_hull, tol = HULL_STABILITY_TOL) {
14
+ // unknown distance (degenerate hull / point outside hull projection / missing energy):
15
+ // not 0/stable — leave both undefined so it isn't mislabeled on-hull
16
+ if (raw_distance == null || !Number.isFinite(raw_distance)) {
17
+ return { e_above_hull: undefined, is_stable: undefined };
18
+ }
14
19
  if (exclude_from_hull)
15
20
  return { e_above_hull: raw_distance, is_stable: false };
16
21
  const e_above_hull = Math.abs(raw_distance) < tol ? 0 : Math.max(0, raw_distance);
@@ -24,15 +29,23 @@ export const extract_structure_from_entry = (entries, entry) => {
24
29
  const orig_entry = entries.find((ent) => ent.entry_id === entry.entry_id);
25
30
  return orig_entry?.structure || null;
26
31
  };
27
- // [min, max] energy above hull across entries, for ColorBar ranges (max floored at 0.1)
32
+ // Loop-based min/max Math.min/max(...arr) blows the stack on large (>~100k) arrays
33
+ export const array_min = (values) => values.reduce((min, val) => (val < min ? val : min), Infinity);
34
+ export const array_max = (values) => values.reduce((max, val) => (val > max ? val : max), -Infinity);
35
+ // [min, max] energy above hull across entries, for ColorBar ranges (max floored at 0.1).
36
+ // Filter to finite values: NaN/undefined distances would otherwise produce a broken range.
28
37
  export const hull_distance_range = (entries) => {
29
38
  const dists = entries
30
39
  .map((entry) => entry.e_above_hull)
31
- .filter((val) => typeof val === `number`);
32
- return dists.length > 0 ? [Math.min(...dists), Math.max(...dists, 0.1)] : [0, 0.1];
40
+ .filter((val) => typeof val === `number` && Number.isFinite(val));
41
+ return dists.length > 0 ? [array_min(dists), Math.max(array_max(dists), 0.1)] : [0, 0.1];
33
42
  };
34
43
  export const entry_is_stable = (entry, tol = HULL_STABILITY_TOL) => entry.is_stable === true ||
35
44
  (entry.is_stable !== false && Math.abs(entry.e_above_hull ?? Infinity) <= tol);
45
+ // Whether to plot an entry at a given max hull distance: stable, or a finite distance
46
+ // within max_dist. Unknown distance (undefined) is excluded, not treated as 0/stable.
47
+ export const entry_within_hull_dist = (entry, max_dist) => entry_is_stable(entry) ||
48
+ (typeof entry.e_above_hull === `number` && entry.e_above_hull <= max_dist);
36
49
  // Check if entry is on the convex hull (stable or e_above_hull ≈ 0)
37
50
  export const is_on_hull = (entry, tol = HULL_STABILITY_TOL) => !entry.exclude_from_hull && entry_is_stable(entry, tol);
38
51
  export const get_arity = (entry) => Object.values(entry.composition).filter((count) => count > 0).length;
@@ -211,15 +224,9 @@ export function build_entry_tooltip_text(entry, category = MAGNETIC_ORDERING_CAT
211
224
  ? `${elem_symbol}${elem_name ? ` (${elem_name})` : ``}\n`
212
225
  : `${entry.name ?? entry.reduced_formula ?? ``}\n`;
213
226
  if (!is_element) {
214
- const total = Object.values(entry.composition).reduce((sum, amt) => sum + amt, 0);
215
- if (total > 0) {
216
- const fractions = Object.entries(entry.composition)
217
- .filter(([, amt]) => amt > 0)
218
- .map(([el, amt]) => `${el}: ${format_fractional(amt / total)}`);
219
- if (fractions.length > 1) {
220
- text += `Composition: ${fractions.join(`, `)}\n`;
221
- }
222
- }
227
+ const fractions = Object.entries(get_fractional_composition(entry.composition)).map(([elem, frac]) => `${elem}: ${format_fractional(frac)}`);
228
+ if (fractions.length > 1)
229
+ text += `Composition: ${fractions.join(`, `)}\n`;
223
230
  }
224
231
  if (entry.e_above_hull !== undefined) {
225
232
  const e_hull_str = format_num(entry.e_above_hull, `.3~`);
@@ -290,21 +297,21 @@ energy_source_mode) {
290
297
  break;
291
298
  }
292
299
  }
293
- const can_compute_hull = can_compute_e_form;
294
300
  // Resolve mode to avoid inconsistent states:
295
301
  // - If full precomputed available, honor user toggle
296
- // - Else if we can compute both, use on-the-fly automatically
302
+ // - Else if we can compute, use on-the-fly automatically
297
303
  // - Else fall back to precomputed (best-effort)
298
304
  const energy_mode = has_precomputed_e_form && has_precomputed_hull
299
305
  ? energy_source_mode
300
- : can_compute_e_form && can_compute_hull
306
+ : can_compute_e_form
301
307
  ? `on-the-fly`
302
308
  : `precomputed`;
303
309
  return {
304
310
  has_precomputed_e_form,
305
311
  has_precomputed_hull,
306
312
  can_compute_e_form,
307
- can_compute_hull,
313
+ // hull needs the same unary references as e_form, so the two always agree
314
+ can_compute_hull: can_compute_e_form,
308
315
  energy_mode,
309
316
  unary_refs,
310
317
  };
@@ -752,8 +759,7 @@ export function filter_entries_at_temperature(entries, T, options = {}) {
752
759
  return [{ ...entry, energy, energy_per_atom: energy }];
753
760
  }
754
761
  }
755
- // Exclude entry (has temp data but can't get energy at T)
756
- return [];
762
+ return []; // Exclude entry (has temp data but can't get energy at T)
757
763
  });
758
764
  }
759
765
  // Get gas-corrected entries in one call (consolidates analysis + correction)
@@ -762,29 +768,23 @@ export function filter_entries_at_temperature(entries, T, options = {}) {
762
768
  // if no gas config or no relevant gases.
763
769
  export function get_gas_corrected_entries(entries, gas_config, gas_pressures, temperature) {
764
770
  if (!gas_config?.enabled_gases?.length) {
765
- return {
766
- entries,
767
- analysis: {
768
- has_gas_dependent_elements: false,
769
- gas_elements: [],
770
- relevant_gases: [],
771
- },
772
- merged_config: undefined,
771
+ const analysis = {
772
+ has_gas_dependent_elements: false,
773
+ gas_elements: [],
774
+ relevant_gases: [],
773
775
  };
776
+ return { entries, analysis, merged_config: undefined };
774
777
  }
775
778
  const merged_config = {
776
779
  ...gas_config,
777
780
  pressures: { ...gas_config.pressures, ...gas_pressures },
778
781
  };
779
- const analysis = _analyze_gas_data(entries, merged_config);
782
+ const analysis = analyze_gas_data(entries, merged_config);
780
783
  if (!analysis.has_gas_dependent_elements) {
781
784
  return { entries, analysis, merged_config };
782
785
  }
783
- return {
784
- entries: _apply_gas_corrections(entries, merged_config, temperature),
785
- analysis,
786
- merged_config,
787
- };
786
+ const corr_entries = apply_gas_corrections(entries, merged_config, temperature);
787
+ return { entries: corr_entries, analysis, merged_config };
788
788
  }
789
789
  // Derive a display label for a convex hull entry, falling back to composition
790
790
  // when reduced_formula and name are both missing.
@@ -793,7 +793,7 @@ export function get_entry_label(entry, elements) {
793
793
  return entry.reduced_formula;
794
794
  if (entry.name)
795
795
  return entry.name;
796
- let pairs = Object.entries(entry.composition).filter(([, amt]) => amt > 0);
796
+ let pairs = Object.entries(entry.composition).filter(([, amt]) => (amt ?? 0) > 0);
797
797
  if (elements) {
798
798
  pairs = pairs.sort(([el1], [el2]) => elements.indexOf(el1) - elements.indexOf(el2));
799
799
  }
@@ -36,7 +36,7 @@ export declare function create_hull_data_pipeline<Entry extends PhaseData>(input
36
36
  })[];
37
37
  readonly pd_data: import("./types").ProcessedPhaseData;
38
38
  readonly polymorph_stats_map: Map<string, helpers.PolymorphStats>;
39
- readonly elements: ("S" | "K" | "B" | "H" | "He" | "Li" | "Be" | "C" | "N" | "O" | "F" | "Ne" | "Na" | "Mg" | "Al" | "Si" | "P" | "Cl" | "Ar" | "Ca" | "Sc" | "Ti" | "V" | "Cr" | "Mn" | "Fe" | "Co" | "Ni" | "Cu" | "Zn" | "Ga" | "Ge" | "As" | "Se" | "Br" | "Kr" | "Rb" | "Sr" | "Y" | "Zr" | "Nb" | "Mo" | "Tc" | "Ru" | "Rh" | "Pd" | "Ag" | "Cd" | "In" | "Sn" | "Sb" | "Te" | "I" | "Xe" | "Cs" | "Ba" | "La" | "Ce" | "Pr" | "Nd" | "Pm" | "Sm" | "Eu" | "Gd" | "Tb" | "Dy" | "Ho" | "Er" | "Tm" | "Yb" | "Lu" | "Hf" | "Ta" | "W" | "Re" | "Os" | "Ir" | "Pt" | "Au" | "Hg" | "Tl" | "Pb" | "Bi" | "Po" | "At" | "Rn" | "Fr" | "Ra" | "Ac" | "Th" | "Pa" | "U" | "Np" | "Pu" | "Am" | "Cm" | "Bk" | "Cf" | "Es" | "Fm" | "Md" | "No" | "Lr" | "Rf" | "Db" | "Sg" | "Bh" | "Hs" | "Mt" | "Ds" | "Rg" | "Cn" | "Nh" | "Fl" | "Mc" | "Lv" | "Ts" | "Og")[];
39
+ readonly elements: ("Ac" | "Ag" | "Al" | "Am" | "Ar" | "As" | "At" | "Au" | "B" | "Ba" | "Be" | "Bh" | "Bi" | "Bk" | "Br" | "C" | "Ca" | "Cd" | "Ce" | "Cf" | "Cl" | "Cm" | "Co" | "Cr" | "Cs" | "Cu" | "Db" | "Dy" | "Er" | "Es" | "Eu" | "F" | "Fe" | "Fm" | "Fr" | "Ga" | "Gd" | "Ge" | "H" | "He" | "Hf" | "Hg" | "Ho" | "Hs" | "I" | "In" | "Ir" | "K" | "Kr" | "La" | "Li" | "Lr" | "Lu" | "Md" | "Mg" | "Mn" | "Mo" | "Mt" | "N" | "Na" | "Nb" | "Nd" | "Ne" | "Ni" | "No" | "Np" | "O" | "Os" | "P" | "Pa" | "Pb" | "Pd" | "Pm" | "Po" | "Pr" | "Pt" | "Pu" | "Ra" | "Rb" | "Re" | "Rf" | "Rh" | "Rn" | "Ru" | "S" | "Sb" | "Sc" | "Se" | "Sg" | "Si" | "Sm" | "Sn" | "Sr" | "Ta" | "Tb" | "Tc" | "Te" | "Th" | "Ti" | "Tl" | "Tm" | "U" | "V" | "W" | "Xe" | "Y" | "Yb" | "Zn" | "Zr" | "Ds" | "Rg" | "Cn" | "Nh" | "Fl" | "Mc" | "Lv" | "Ts" | "Og")[];
40
40
  readonly max_hull_dist_in_data: number;
41
41
  readonly auto_default_threshold: number;
42
42
  readonly plot_entries: Entry[];
@@ -1,7 +1,7 @@
1
1
  import { count_atoms_in_composition, extract_formula_elements, sort_by_electronegativity, } from '../composition';
2
2
  import * as math from '../math';
3
3
  import { composition_to_barycentric_nd } from './barycentric-coords';
4
- import { get_arity, HULL_STABILITY_TOL, is_on_hull, is_unary_entry } from './helpers';
4
+ import { array_max, array_min, get_arity, HULL_STABILITY_TOL, is_on_hull, is_unary_entry, } from './helpers';
5
5
  // Track warned keys to avoid log spam on large datasets with repeated invalid keys
6
6
  const warned_keys = new Set();
7
7
  // Normalize convex hull composition keys by stripping oxidation states (e.g. "V4+" -> "V")
@@ -49,13 +49,7 @@ export function process_hull_entries(entries) {
49
49
  const el_refs = Object.fromEntries(stable_entries
50
50
  .filter(is_unary_entry)
51
51
  .map((entry) => [Object.keys(entry.composition)[0], entry]));
52
- return {
53
- entries: normalized_entries,
54
- stable_entries,
55
- unstable_entries,
56
- elements,
57
- el_refs,
58
- };
52
+ return { entries: normalized_entries, stable_entries, unstable_entries, elements, el_refs };
59
53
  }
60
54
  // Get energy per atom with correction applied, or fallback to raw energy_per_atom/energy.
61
55
  // Note: correction is expected to be a total-entry value (eV), not per-atom.
@@ -99,8 +93,14 @@ export function find_lowest_energy_unary_refs(entries) {
99
93
  }
100
94
  return refs;
101
95
  }
102
- // Result key for an entry: entry_id, falling back to its serialized composition
103
- const id_of = (entry) => entry.entry_id ?? JSON.stringify(entry.composition);
96
+ // Result key: entry_id, else composition|energy|structure. Composition alone collides for
97
+ // same-stoichiometry polymorphs (last distance would win), so add energy + structure.
98
+ const id_of = (entry) => {
99
+ if (entry.entry_id)
100
+ return entry.entry_id;
101
+ const structure_hash = entry.structure ? JSON.stringify(entry.structure) : ``;
102
+ return `${JSON.stringify(entry.composition)}|${entry.energy}|${structure_hash}`;
103
+ };
104
104
  export function calculate_e_above_hull(input, reference_entries) {
105
105
  const is_single = !Array.isArray(input);
106
106
  const entries_of_interest = is_single ? [input] : input;
@@ -302,11 +302,12 @@ export function get_convex_hull_stats(processed_entries, elements, max_arity = 4
302
302
  const energies = processed_entries
303
303
  .map((entry) => entry.e_form_per_atom ?? entry.energy_per_atom ?? get_energy_per_atom(entry))
304
304
  .filter(Number.isFinite);
305
- // Use reduce instead of Math.min/max(...arr) to avoid stack overflow on large datasets
305
+ // array_min/array_max reduce instead of Math.min/max(...arr) to avoid stack
306
+ // overflow on large datasets
306
307
  const energy_range = energies.length > 0
307
308
  ? {
308
- min: energies.reduce((min, val) => (val < min ? val : min), Infinity),
309
- max: energies.reduce((max, val) => (val > max ? val : max), -Infinity),
309
+ min: array_min(energies),
310
+ max: array_max(energies),
310
311
  avg: energies.reduce((sum, val) => sum + val, 0) / energies.length,
311
312
  }
312
313
  : { min: 0, max: 0, avg: 0 };
@@ -315,7 +316,7 @@ export function get_convex_hull_stats(processed_entries, elements, max_arity = 4
315
316
  .filter((val) => typeof val === `number` && val >= 0);
316
317
  const hull_distance = hull_distances.length > 0
317
318
  ? {
318
- max: hull_distances.reduce((max, val) => (val > max ? val : max), -Infinity),
319
+ max: array_max(hull_distances),
319
320
  avg: hull_distances.reduce((sum, val) => sum + val, 0) / hull_distances.length,
320
321
  }
321
322
  : { max: 0, avg: 0 };
@@ -505,7 +506,7 @@ export function e_hull_at_xy(models, x, y) {
505
506
  export const compute_e_above_hull_for_points = (points, models) => points.map((point) => {
506
507
  const z_hull = e_hull_at_xy(models, point.x, point.y);
507
508
  if (z_hull === null)
508
- return 0;
509
+ return NaN; // unknown: no hull face covers this point
509
510
  return Math.max(0, point.z - z_hull);
510
511
  });
511
512
  // Map an ND facet (vertex indices into `points`) back to the public tetrahedron shape
@@ -851,8 +852,8 @@ const build_simplex_models_nd = (simplices) => simplices.map((vertices) => {
851
852
  const vertices_spatial = vertices.map((pt) => pt.slice(0, dim - 1));
852
853
  // Compute bounding box in spatial dimensions
853
854
  const spatial_dim = dim - 1;
854
- const bbox_min = Array.from({ length: spatial_dim }, (_, idx) => Math.min(...vertices_spatial.map((pt) => pt[idx])));
855
- const bbox_max = Array.from({ length: spatial_dim }, (_, idx) => Math.max(...vertices_spatial.map((pt) => pt[idx])));
855
+ const bbox_min = Array.from({ length: spatial_dim }, (_, idx) => array_min(vertices_spatial.map((pt) => pt[idx])));
856
+ const bbox_max = Array.from({ length: spatial_dim }, (_, idx) => array_max(vertices_spatial.map((pt) => pt[idx])));
856
857
  return { vertices, vertices_spatial, bbox_min, bbox_max };
857
858
  });
858
859
  // Check if point is inside simplex and return barycentric coordinates
@@ -12,12 +12,13 @@
12
12
  Orientation,
13
13
  } from '../plot/core/types'
14
14
  import type { AnyStructure } from '../structure'
15
+ import { calc_structure_coordination } from '../structure/atom-properties'
15
16
  import type { BondingStrategy } from '../structure/bonding'
16
17
  import { parse_any_structure } from '../structure/parse'
17
18
  import { is_crystal } from '../structure/validation'
18
19
  import type { ComponentProps } from 'svelte'
19
20
  import { SvelteMap, SvelteSet } from 'svelte/reactivity'
20
- import { calc_coordination_nums, type CoordinationData } from './calc-coordination'
21
+ import type { CoordinationData } from './calc-coordination'
21
22
  import type { SplitMode } from './index'
22
23
  import { to_error } from '../utils'
23
24
 
@@ -70,28 +71,31 @@
70
71
 
71
72
  const base_entries = Array.isArray(structures)
72
73
  ? (structures as StructureEntry[])
73
- : (is_crystal(structures)
74
+ : is_crystal(structures)
74
75
  ? [{ label: `Structure`, structure: structures as AnyStructure }]
75
76
  : Object.entries(
76
- structures as Record<
77
- string,
78
- AnyStructure | { structure: AnyStructure; color?: string }
79
- >,
80
- ).map(([label, value]) =>
81
- `structure` in value
82
- ? { label, ...value }
83
- : { label, structure: value as AnyStructure }
84
- ))
77
+ structures as Record<
78
+ string,
79
+ AnyStructure | { structure: AnyStructure; color?: string }
80
+ >,
81
+ ).map(([label, value]) =>
82
+ `structure` in value
83
+ ? { label, ...value }
84
+ : { label, structure: value as AnyStructure },
85
+ )
85
86
 
86
87
  // Merge user-provided structures with dropped structures
87
88
  return [...base_entries, ...dropped_entries]
88
89
  })
89
90
 
90
- // Compute coordination data for each structure
91
- const entries_with_data = $derived(structure_entries.map((entry) => ({
92
- ...entry,
93
- data: calc_coordination_nums(entry.structure, strategy),
94
- })))
91
+ // Compute coordination data for each structure via the shared PBC-aware helper so
92
+ // boundary-atom coordination matches the 3D viewer (which uses the same path).
93
+ const entries_with_data = $derived(
94
+ structure_entries.map((entry) => ({
95
+ ...entry,
96
+ data: calc_structure_coordination(entry.structure, strategy),
97
+ })),
98
+ )
95
99
 
96
100
  // Compute appropriate ranges
97
101
  const ranges = $derived.by(() => {
@@ -116,7 +120,6 @@
116
120
  }
117
121
  return Array.from(all_cns).sort((cn1, cn2) => cn1 - cn2)
118
122
  })
119
-
120
123
  // Build BarPlot series based on split_mode
121
124
  const bar_series = $derived.by<BarSeries<CoordinationMetadata>[]>(() => {
122
125
  if (split_mode === `by_element`) {
@@ -208,29 +211,28 @@
208
211
 
209
212
  const compute_and_add = (content: string | ArrayBuffer, filename: string) => {
210
213
  try {
211
- const text_content = content instanceof ArrayBuffer
212
- ? new TextDecoder().decode(content)
213
- : content
214
+ const text_content =
215
+ content instanceof ArrayBuffer ? new TextDecoder().decode(content) : content
214
216
  const parsed_structure = parse_any_structure(text_content, filename)
215
217
  if (is_crystal(parsed_structure)) {
216
- dropped_entries = [{
217
- label: filename || `Dropped structure`,
218
- structure: parsed_structure,
219
- }, ...dropped_entries]
218
+ dropped_entries = [
219
+ {
220
+ label: filename || `Dropped structure`,
221
+ structure: parsed_structure,
222
+ },
223
+ ...dropped_entries,
224
+ ]
220
225
  } else {
221
226
  error_msg = `Structure has no lattice or sites; cannot compute coordination`
222
227
  }
223
228
  } catch (exc) {
224
- error_msg = `Failed to process structure: ${
225
- to_error(exc).message
226
- }`
229
+ error_msg = `Failed to process structure: ${to_error(exc).message}`
227
230
  }
228
231
  }
229
232
 
230
233
  const handle_file_drop = create_file_drop_handler({
231
234
  allow: () => allow_file_drop,
232
- on_drop: (content, filename) =>
233
- (on_file_drop || compute_and_add)(content, filename),
235
+ on_drop: (content, filename) => (on_file_drop || compute_and_add)(content, filename),
234
236
  on_error: (msg) => {
235
237
  error_msg = msg
236
238
  },
@@ -256,8 +258,8 @@
256
258
  {#if bar_series.length === 0}
257
259
  <StatusMessage
258
260
  message={allow_file_drop
259
- ? `Drag and drop structure files here to compute coordination numbers`
260
- : `No coordination data to display`}
261
+ ? `Drag and drop structure files here to compute coordination numbers`
262
+ : `No coordination data to display`}
261
263
  />
262
264
  {:else}
263
265
  {#snippet tooltip(info: BarHandlerProps<CoordinationMetadata>)}
@@ -298,7 +300,10 @@
298
300
  bind:display
299
301
  {tooltip}
300
302
  ondrop={handle_file_drop}
301
- {...drag_over_handlers({ allow: () => allow_file_drop, set_dragover: (over) => dragover = over })}
302
- class={(rest.class ?? ``) + (dragover ? ` dragover` : ``)}
303
+ {...drag_over_handlers({
304
+ allow: () => allow_file_drop,
305
+ set_dragover: (over) => (dragover = over),
306
+ })}
307
+ class={[rest.class, dragover && `dragover`]}
303
308
  />
304
309
  {/if}
@@ -3,7 +3,7 @@ import type { AxisConfig } from '../plot/core/types';
3
3
  import type { AnyStructure } from '../structure';
4
4
  import type { BondingStrategy } from '../structure/bonding';
5
5
  import type { ComponentProps } from 'svelte';
6
- import { type CoordinationData } from './calc-coordination';
6
+ import type { CoordinationData } from './calc-coordination';
7
7
  import type { SplitMode } from './index';
8
8
  interface StructureEntry {
9
9
  label: string;