matterviz 0.3.7 → 0.4.0

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 (324) hide show
  1. package/dist/Icon.svelte +7 -4
  2. package/dist/MillerIndexInput.svelte +1 -1
  3. package/dist/api/optimade.js +32 -26
  4. package/dist/app.css +0 -3
  5. package/dist/brillouin/BrillouinZone.svelte +8 -3
  6. package/dist/brillouin/BrillouinZone.svelte.d.ts +2 -1
  7. package/dist/brillouin/BrillouinZoneScene.svelte +52 -6
  8. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -0
  9. package/dist/brillouin/BrillouinZoneTooltip.svelte +16 -25
  10. package/dist/brillouin/compute.js +10 -14
  11. package/dist/chempot-diagram/ChemPotDiagram.svelte +14 -13
  12. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +12 -15
  13. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +8 -10
  14. package/dist/chempot-diagram/async-compute.svelte.js +3 -1
  15. package/dist/chempot-diagram/chempot-worker.js +2 -1
  16. package/dist/chempot-diagram/compute.d.ts +1 -1
  17. package/dist/chempot-diagram/compute.js +17 -19
  18. package/dist/colors/index.js +6 -5
  19. package/dist/composition/FormulaFilter.svelte +12 -6
  20. package/dist/composition/PieChart.svelte +6 -5
  21. package/dist/composition/chem-sys.d.ts +8 -0
  22. package/dist/composition/chem-sys.js +85 -0
  23. package/dist/composition/format.js +4 -2
  24. package/dist/composition/index.d.ts +1 -0
  25. package/dist/composition/index.js +1 -0
  26. package/dist/composition/parse.js +25 -13
  27. package/dist/convex-hull/ConvexHull2D.svelte +12 -10
  28. package/dist/convex-hull/ConvexHull3D.svelte +5 -5
  29. package/dist/convex-hull/ConvexHull4D.svelte +5 -9
  30. package/dist/convex-hull/ConvexHullStats.svelte +12 -12
  31. package/dist/convex-hull/GasPressureControls.svelte +4 -4
  32. package/dist/convex-hull/TemperatureSlider.svelte +2 -2
  33. package/dist/convex-hull/demo-temperature.d.ts +1 -1
  34. package/dist/convex-hull/demo-temperature.js +20 -22
  35. package/dist/convex-hull/gas-thermodynamics.d.ts +2 -2
  36. package/dist/convex-hull/gas-thermodynamics.js +22 -30
  37. package/dist/convex-hull/helpers.d.ts +3 -0
  38. package/dist/convex-hull/helpers.js +17 -9
  39. package/dist/convex-hull/index.d.ts +1 -1
  40. package/dist/convex-hull/thermodynamics.js +83 -78
  41. package/dist/convex-hull/types.d.ts +1 -1
  42. package/dist/coordination/CoordinationBarPlot.svelte +23 -23
  43. package/dist/coordination/CoordinationBarPlot.svelte.d.ts +1 -1
  44. package/dist/element/ElementTile.svelte.d.ts +1 -1
  45. package/dist/fermi-surface/FermiSlice.svelte +13 -5
  46. package/dist/fermi-surface/FermiSurface.svelte +11 -5
  47. package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
  48. package/dist/fermi-surface/FermiSurfaceControls.svelte +1 -1
  49. package/dist/fermi-surface/FermiSurfaceScene.svelte +3 -0
  50. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +8 -34
  51. package/dist/fermi-surface/compute.js +59 -59
  52. package/dist/fermi-surface/export.js +3 -2
  53. package/dist/fermi-surface/parse.js +7 -4
  54. package/dist/fermi-surface/types.d.ts +1 -0
  55. package/dist/heatmap-matrix/HeatmapMatrix.svelte +23 -21
  56. package/dist/heatmap-matrix/index.js +1 -1
  57. package/dist/io/decompress.js +4 -2
  58. package/dist/io/export.d.ts +4 -4
  59. package/dist/io/export.js +47 -25
  60. package/dist/io/fetch.js +5 -1
  61. package/dist/io/file-drop.d.ts +1 -1
  62. package/dist/io/file-drop.js +35 -36
  63. package/dist/io/url-drop.js +64 -33
  64. package/dist/isosurface/parse.js +6 -7
  65. package/dist/isosurface/slice.js +5 -4
  66. package/dist/isosurface/types.js +1 -1
  67. package/dist/keyboard.d.ts +3 -0
  68. package/dist/keyboard.js +23 -0
  69. package/dist/labels.d.ts +1 -1
  70. package/dist/labels.js +8 -7
  71. package/dist/layout/PropertyFilter.svelte +3 -2
  72. package/dist/layout/SettingsSection.svelte +1 -1
  73. package/dist/layout/json-tree/JsonNode.svelte +1 -1
  74. package/dist/layout/json-tree/JsonTree.svelte +2 -2
  75. package/dist/layout/json-tree/utils.js +5 -4
  76. package/dist/marching-cubes.js +8 -13
  77. package/dist/math.d.ts +5 -1
  78. package/dist/math.js +24 -9
  79. package/dist/overlays/DraggablePane.svelte +4 -4
  80. package/dist/periodic-table/PeriodicTable.svelte +20 -9
  81. package/dist/periodic-table/PropertySelect.svelte +1 -0
  82. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +9 -3
  83. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
  84. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
  85. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +2 -1
  86. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +1 -1
  87. package/dist/phase-diagram/build-diagram.js +2 -2
  88. package/dist/phase-diagram/parse.js +6 -5
  89. package/dist/phase-diagram/types.d.ts +1 -1
  90. package/dist/phase-diagram/utils.d.ts +3 -3
  91. package/dist/phase-diagram/utils.js +8 -12
  92. package/dist/plot/{BarPlot.svelte → bar/BarPlot.svelte} +229 -587
  93. package/dist/plot/{BarPlot.svelte.d.ts → bar/BarPlot.svelte.d.ts} +5 -5
  94. package/dist/plot/{BarPlotControls.svelte → bar/BarPlotControls.svelte} +6 -5
  95. package/dist/plot/{BarPlotControls.svelte.d.ts → bar/BarPlotControls.svelte.d.ts} +3 -3
  96. package/dist/plot/{SpacegroupBarPlot.svelte → bar/SpacegroupBarPlot.svelte} +6 -6
  97. package/dist/plot/{SpacegroupBarPlot.svelte.d.ts → bar/SpacegroupBarPlot.svelte.d.ts} +1 -1
  98. package/dist/plot/bar/data.d.ts +40 -0
  99. package/dist/plot/bar/data.js +154 -0
  100. package/dist/plot/bar/geometry.d.ts +39 -0
  101. package/dist/plot/bar/geometry.js +60 -0
  102. package/dist/plot/bar/index.d.ts +3 -0
  103. package/dist/plot/bar/index.js +3 -0
  104. package/dist/plot/box/BoxPlot.svelte +1462 -0
  105. package/dist/plot/box/BoxPlot.svelte.d.ts +94 -0
  106. package/dist/plot/box/BoxPlotControls.svelte +109 -0
  107. package/dist/plot/box/BoxPlotControls.svelte.d.ts +19 -0
  108. package/dist/plot/box/Violin.svelte +14 -0
  109. package/dist/plot/box/Violin.svelte.d.ts +70 -0
  110. package/dist/plot/box/box-plot.d.ts +55 -0
  111. package/dist/plot/box/box-plot.js +126 -0
  112. package/dist/plot/box/index.d.ts +5 -0
  113. package/dist/plot/box/index.js +5 -0
  114. package/dist/plot/box/kde.d.ts +16 -0
  115. package/dist/plot/box/kde.js +160 -0
  116. package/dist/plot/box/quantile.d.ts +3 -0
  117. package/dist/plot/box/quantile.js +53 -0
  118. package/dist/plot/{auto-place.js → core/auto-place.js} +2 -2
  119. package/dist/plot/core/axis-utils.d.ts +46 -0
  120. package/dist/plot/core/axis-utils.js +110 -0
  121. package/dist/plot/{AxisLabel.svelte → core/components/AxisLabel.svelte} +2 -2
  122. package/dist/plot/{AxisLabel.svelte.d.ts → core/components/AxisLabel.svelte.d.ts} +1 -1
  123. package/dist/plot/{ColorBar.svelte → core/components/ColorBar.svelte} +36 -33
  124. package/dist/plot/{ColorBar.svelte.d.ts → core/components/ColorBar.svelte.d.ts} +2 -2
  125. package/dist/plot/{ColorScaleSelect.svelte → core/components/ColorScaleSelect.svelte} +4 -3
  126. package/dist/plot/{ColorScaleSelect.svelte.d.ts → core/components/ColorScaleSelect.svelte.d.ts} +2 -2
  127. package/dist/plot/core/components/ControlPane.svelte +46 -0
  128. package/dist/plot/core/components/ControlPane.svelte.d.ts +13 -0
  129. package/dist/plot/{FillArea.svelte → core/components/FillArea.svelte} +17 -6
  130. package/dist/plot/{FillArea.svelte.d.ts → core/components/FillArea.svelte.d.ts} +1 -1
  131. package/dist/plot/{InteractiveAxisLabel.svelte → core/components/InteractiveAxisLabel.svelte} +3 -3
  132. package/dist/plot/{InteractiveAxisLabel.svelte.d.ts → core/components/InteractiveAxisLabel.svelte.d.ts} +2 -2
  133. package/dist/plot/{Line.svelte → core/components/Line.svelte} +30 -13
  134. package/dist/plot/{PlotAxis.svelte → core/components/PlotAxis.svelte} +7 -5
  135. package/dist/plot/{PlotAxis.svelte.d.ts → core/components/PlotAxis.svelte.d.ts} +3 -2
  136. package/dist/plot/{PlotControls.svelte → core/components/PlotControls.svelte} +17 -29
  137. package/dist/plot/core/components/PlotControls.svelte.d.ts +4 -0
  138. package/dist/plot/{PlotLegend.svelte → core/components/PlotLegend.svelte} +21 -10
  139. package/dist/plot/{PlotLegend.svelte.d.ts → core/components/PlotLegend.svelte.d.ts} +3 -2
  140. package/dist/plot/{PlotTooltip.svelte → core/components/PlotTooltip.svelte} +17 -1
  141. package/dist/plot/{PlotTooltip.svelte.d.ts → core/components/PlotTooltip.svelte.d.ts} +8 -0
  142. package/dist/plot/{PortalSelect.svelte → core/components/PortalSelect.svelte} +11 -7
  143. package/dist/plot/{ReferenceLine.svelte → core/components/ReferenceLine.svelte} +3 -3
  144. package/dist/plot/{ReferenceLine.svelte.d.ts → core/components/ReferenceLine.svelte.d.ts} +1 -1
  145. package/dist/plot/{ReferenceLine3D.svelte → core/components/ReferenceLine3D.svelte} +4 -4
  146. package/dist/plot/{ReferenceLine3D.svelte.d.ts → core/components/ReferenceLine3D.svelte.d.ts} +2 -2
  147. package/dist/plot/{ReferencePlane.svelte → core/components/ReferencePlane.svelte} +7 -7
  148. package/dist/plot/{ReferencePlane.svelte.d.ts → core/components/ReferencePlane.svelte.d.ts} +2 -2
  149. package/dist/plot/{ZeroLines.svelte → core/components/ZeroLines.svelte} +3 -3
  150. package/dist/plot/{ZeroLines.svelte.d.ts → core/components/ZeroLines.svelte.d.ts} +3 -3
  151. package/dist/plot/{ZoomRect.svelte → core/components/ZoomRect.svelte} +1 -1
  152. package/dist/plot/{ZoomRect.svelte.d.ts → core/components/ZoomRect.svelte.d.ts} +1 -1
  153. package/dist/plot/core/components/index.d.ts +17 -0
  154. package/dist/plot/core/components/index.js +17 -0
  155. package/dist/plot/{data-cleaning.d.ts → core/data-cleaning.d.ts} +71 -1
  156. package/dist/plot/{data-cleaning.js → core/data-cleaning.js} +3 -5
  157. package/dist/plot/{data-transform.d.ts → core/data-transform.d.ts} +2 -2
  158. package/dist/plot/{data-transform.js → core/data-transform.js} +3 -3
  159. package/dist/plot/core/fill-utils.d.ts +33 -0
  160. package/dist/plot/core/fill-utils.js +388 -0
  161. package/dist/plot/{hover-lock.svelte.js → core/hover-lock.svelte.js} +5 -6
  162. package/dist/plot/core/index.d.ts +10 -0
  163. package/dist/plot/core/index.js +11 -0
  164. package/dist/plot/core/interactions.d.ts +35 -0
  165. package/dist/plot/core/interactions.js +195 -0
  166. package/dist/plot/{layout.d.ts → core/layout.d.ts} +1 -0
  167. package/dist/plot/{layout.js → core/layout.js} +16 -8
  168. package/dist/plot/{reference-line.d.ts → core/reference-line.d.ts} +1 -1
  169. package/dist/plot/{reference-line.js → core/reference-line.js} +23 -36
  170. package/dist/plot/{scales.d.ts → core/scales.d.ts} +2 -2
  171. package/dist/plot/{scales.js → core/scales.js} +84 -85
  172. package/dist/plot/core/svg.d.ts +2 -0
  173. package/dist/plot/core/svg.js +41 -0
  174. package/dist/plot/{types.d.ts → core/types.d.ts} +19 -79
  175. package/dist/plot/{types.js → core/types.js} +1 -1
  176. package/dist/plot/{utils → core/utils}/label-placement.d.ts +2 -2
  177. package/dist/plot/core/utils/series-visibility.d.ts +26 -0
  178. package/dist/plot/{utils → core/utils}/series-visibility.js +29 -2
  179. package/dist/plot/core/utils.d.ts +11 -0
  180. package/dist/plot/core/utils.js +27 -0
  181. package/dist/plot/{Histogram.svelte → histogram/Histogram.svelte} +154 -294
  182. package/dist/plot/{Histogram.svelte.d.ts → histogram/Histogram.svelte.d.ts} +2 -2
  183. package/dist/plot/{HistogramControls.svelte → histogram/HistogramControls.svelte} +6 -6
  184. package/dist/plot/{HistogramControls.svelte.d.ts → histogram/HistogramControls.svelte.d.ts} +4 -4
  185. package/dist/plot/histogram/index.d.ts +2 -0
  186. package/dist/plot/histogram/index.js +2 -0
  187. package/dist/plot/index.d.ts +8 -41
  188. package/dist/plot/index.js +10 -39
  189. package/dist/plot/sankey/Sankey.svelte +700 -0
  190. package/dist/plot/sankey/Sankey.svelte.d.ts +74 -0
  191. package/dist/plot/sankey/SankeyControls.svelte +98 -0
  192. package/dist/plot/sankey/SankeyControls.svelte.d.ts +19 -0
  193. package/dist/plot/sankey/index.d.ts +4 -0
  194. package/dist/plot/sankey/index.js +3 -0
  195. package/dist/plot/sankey/sankey-types.d.ts +42 -0
  196. package/dist/plot/sankey/sankey-types.js +4 -0
  197. package/dist/plot/sankey/sankey.d.ts +52 -0
  198. package/dist/plot/sankey/sankey.js +187 -0
  199. package/dist/plot/{BinnedScatterPlot.svelte → scatter/BinnedScatterPlot.svelte} +61 -59
  200. package/dist/plot/{BinnedScatterPlot.svelte.d.ts → scatter/BinnedScatterPlot.svelte.d.ts} +4 -4
  201. package/dist/plot/{ElementScatter.svelte → scatter/ElementScatter.svelte} +6 -6
  202. package/dist/plot/{ElementScatter.svelte.d.ts → scatter/ElementScatter.svelte.d.ts} +2 -2
  203. package/dist/plot/{ScatterPlot.svelte → scatter/ScatterPlot.svelte} +221 -642
  204. package/dist/plot/{ScatterPlot.svelte.d.ts → scatter/ScatterPlot.svelte.d.ts} +7 -7
  205. package/dist/plot/{ScatterPlotControls.svelte → scatter/ScatterPlotControls.svelte} +6 -5
  206. package/dist/plot/{ScatterPlotControls.svelte.d.ts → scatter/ScatterPlotControls.svelte.d.ts} +1 -1
  207. package/dist/plot/{ScatterPoint.svelte → scatter/ScatterPoint.svelte} +7 -7
  208. package/dist/plot/{ScatterPoint.svelte.d.ts → scatter/ScatterPoint.svelte.d.ts} +3 -3
  209. package/dist/plot/{adaptive-density.d.ts → scatter/adaptive-density.d.ts} +14 -4
  210. package/dist/plot/{adaptive-density.js → scatter/adaptive-density.js} +46 -20
  211. package/dist/plot/{binned-scatter-types.d.ts → scatter/binned-scatter-types.d.ts} +3 -3
  212. package/dist/plot/scatter/index.d.ts +7 -0
  213. package/dist/plot/scatter/index.js +5 -0
  214. package/dist/plot/scatter/scatter-data.d.ts +19 -0
  215. package/dist/plot/scatter/scatter-data.js +212 -0
  216. package/dist/plot/{ScatterPlot3D.svelte → scatter-3d/ScatterPlot3D.svelte} +12 -10
  217. package/dist/plot/{ScatterPlot3D.svelte.d.ts → scatter-3d/ScatterPlot3D.svelte.d.ts} +7 -7
  218. package/dist/plot/{ScatterPlot3DControls.svelte → scatter-3d/ScatterPlot3DControls.svelte} +5 -4
  219. package/dist/plot/{ScatterPlot3DControls.svelte.d.ts → scatter-3d/ScatterPlot3DControls.svelte.d.ts} +2 -2
  220. package/dist/plot/{ScatterPlot3DScene.svelte → scatter-3d/ScatterPlot3DScene.svelte} +11 -11
  221. package/dist/plot/{ScatterPlot3DScene.svelte.d.ts → scatter-3d/ScatterPlot3DScene.svelte.d.ts} +3 -3
  222. package/dist/plot/{Surface3D.svelte → scatter-3d/Surface3D.svelte} +1 -1
  223. package/dist/plot/{Surface3D.svelte.d.ts → scatter-3d/Surface3D.svelte.d.ts} +1 -1
  224. package/dist/plot/scatter-3d/index.d.ts +4 -0
  225. package/dist/plot/scatter-3d/index.js +4 -0
  226. package/dist/plot/sunburst/Sunburst.svelte +1045 -0
  227. package/dist/plot/sunburst/Sunburst.svelte.d.ts +96 -0
  228. package/dist/plot/sunburst/SunburstControls.svelte +200 -0
  229. package/dist/plot/sunburst/SunburstControls.svelte.d.ts +26 -0
  230. package/dist/plot/sunburst/index.d.ts +4 -0
  231. package/dist/plot/sunburst/index.js +4 -0
  232. package/dist/plot/sunburst/render.d.ts +34 -0
  233. package/dist/plot/sunburst/render.js +122 -0
  234. package/dist/plot/sunburst/sunburst.d.ts +62 -0
  235. package/dist/plot/sunburst/sunburst.js +266 -0
  236. package/dist/rdf/RdfPlot.svelte +2 -1
  237. package/dist/rdf/calc-rdf.js +11 -24
  238. package/dist/sanitize.js +1 -1
  239. package/dist/settings.d.ts +65 -1
  240. package/dist/settings.js +262 -0
  241. package/dist/spectral/Bands.svelte +39 -29
  242. package/dist/spectral/Bands.svelte.d.ts +3 -4
  243. package/dist/spectral/BandsAndDos.svelte +1 -1
  244. package/dist/spectral/BrillouinBandsDos.svelte +39 -27
  245. package/dist/spectral/Dos.svelte +10 -19
  246. package/dist/spectral/Dos.svelte.d.ts +2 -2
  247. package/dist/spectral/helpers.d.ts +3 -1
  248. package/dist/spectral/helpers.js +95 -29
  249. package/dist/structure/AtomLegend.svelte +8 -9
  250. package/dist/structure/CellSelect.svelte +1 -2
  251. package/dist/structure/Cylinder.svelte +12 -8
  252. package/dist/structure/Cylinder.svelte.d.ts +4 -1
  253. package/dist/structure/Structure.svelte +78 -72
  254. package/dist/structure/Structure.svelte.d.ts +1 -1
  255. package/dist/structure/StructureInfoPane.svelte +5 -6
  256. package/dist/structure/StructureScene.svelte +11 -10
  257. package/dist/structure/atom-properties.js +6 -6
  258. package/dist/structure/bond-order-perception.js +1 -1
  259. package/dist/structure/bonding.d.ts +1 -0
  260. package/dist/structure/bonding.js +43 -15
  261. package/dist/structure/export.js +27 -23
  262. package/dist/structure/index.d.ts +2 -4
  263. package/dist/structure/index.js +1 -3
  264. package/dist/structure/label-placement.js +4 -4
  265. package/dist/structure/measure.d.ts +3 -2
  266. package/dist/structure/measure.js +6 -5
  267. package/dist/structure/parse.js +121 -103
  268. package/dist/structure/pbc.js +4 -0
  269. package/dist/symmetry/SymmetryStats.svelte +2 -2
  270. package/dist/symmetry/index.d.ts +1 -1
  271. package/dist/symmetry/index.js +22 -24
  272. package/dist/symmetry/spacegroups.d.ts +7 -0
  273. package/dist/symmetry/spacegroups.js +48 -13
  274. package/dist/table/HeatmapTable.svelte +63 -11
  275. package/dist/table/HeatmapTable.svelte.d.ts +1 -1
  276. package/dist/table/index.d.ts +1 -3
  277. package/dist/table/index.js +1 -1
  278. package/dist/theme/index.js +8 -8
  279. package/dist/tooltip/KCoords.svelte +45 -0
  280. package/dist/tooltip/KCoords.svelte.d.ts +8 -0
  281. package/dist/tooltip/index.d.ts +1 -0
  282. package/dist/tooltip/index.js +1 -0
  283. package/dist/trajectory/Trajectory.svelte +66 -40
  284. package/dist/trajectory/Trajectory.svelte.d.ts +2 -1
  285. package/dist/trajectory/TrajectoryExportPane.svelte +2 -1
  286. package/dist/trajectory/TrajectoryInfoPane.svelte +2 -1
  287. package/dist/trajectory/format-detect.d.ts +1 -0
  288. package/dist/trajectory/format-detect.js +25 -11
  289. package/dist/trajectory/frame-reader.js +17 -50
  290. package/dist/trajectory/helpers.js +1 -1
  291. package/dist/trajectory/index.js +1 -1
  292. package/dist/trajectory/parse/hdf5.js +1 -1
  293. package/dist/trajectory/parse/index.js +14 -6
  294. package/dist/trajectory/parse/vasp.js +36 -17
  295. package/dist/trajectory/parse/xyz.d.ts +24 -0
  296. package/dist/trajectory/parse/xyz.js +102 -89
  297. package/dist/trajectory/plotting.d.ts +1 -1
  298. package/dist/trajectory/plotting.js +15 -15
  299. package/dist/utils.d.ts +1 -0
  300. package/dist/utils.js +6 -4
  301. package/dist/xrd/XrdPlot.svelte +2 -1
  302. package/dist/xrd/calc-xrd.js +15 -12
  303. package/dist/xrd/parse.js +2 -2
  304. package/package.json +22 -18
  305. package/dist/plot/PlotControls.svelte.d.ts +0 -4
  306. package/dist/plot/axis-utils.d.ts +0 -19
  307. package/dist/plot/axis-utils.js +0 -78
  308. package/dist/plot/defaults.d.ts +0 -19
  309. package/dist/plot/defaults.js +0 -9
  310. package/dist/plot/fill-utils.d.ts +0 -46
  311. package/dist/plot/fill-utils.js +0 -322
  312. package/dist/plot/interactions.d.ts +0 -12
  313. package/dist/plot/interactions.js +0 -101
  314. package/dist/plot/svg.d.ts +0 -1
  315. package/dist/plot/svg.js +0 -11
  316. package/dist/plot/utils/series-visibility.d.ts +0 -15
  317. package/dist/plot/utils.d.ts +0 -1
  318. package/dist/plot/utils.js +0 -14
  319. /package/dist/plot/{auto-place.d.ts → core/auto-place.d.ts} +0 -0
  320. /package/dist/plot/{Line.svelte.d.ts → core/components/Line.svelte.d.ts} +0 -0
  321. /package/dist/plot/{PortalSelect.svelte.d.ts → core/components/PortalSelect.svelte.d.ts} +0 -0
  322. /package/dist/plot/{hover-lock.svelte.d.ts → core/hover-lock.svelte.d.ts} +0 -0
  323. /package/dist/plot/{utils → core/utils}/label-placement.js +0 -0
  324. /package/dist/plot/{binned-scatter-types.js → scatter/binned-scatter-types.js} +0 -0
@@ -25,7 +25,7 @@
25
25
  function handle_slider_input(
26
26
  event: Event & { currentTarget: HTMLInputElement },
27
27
  ): void {
28
- const new_index = +event.currentTarget.value
28
+ const new_index = Number(event.currentTarget.value)
29
29
  preview_index = new_index
30
30
  // Throttle parent updates during drag to prevent scene flashing
31
31
  const now = Date.now()
@@ -38,7 +38,7 @@
38
38
  function handle_slider_end(
39
39
  event: Event & { currentTarget: HTMLInputElement },
40
40
  ): void {
41
- const new_temp = available_temperatures[+event.currentTarget.value]
41
+ const new_temp = available_temperatures[Number(event.currentTarget.value)]
42
42
  if (new_temp !== undefined) temperature = new_temp
43
43
  preview_index = null
44
44
  }
@@ -2,5 +2,5 @@ import type { PhaseData } from './types';
2
2
  export declare const demo_temperatures: number[];
3
3
  type Composition = Record<string, number>;
4
4
  export declare function make_demo_phase(composition: Composition, seed: number, entropy_boost?: number): PhaseData;
5
- export declare function create_temp_ternary_entries_li_fe_o(): PhaseData[];
5
+ export declare const create_temp_ternary_entries_li_fe_o: () => PhaseData[];
6
6
  export {};
@@ -16,25 +16,23 @@ export function make_demo_phase(composition, seed, entropy_boost = 0) {
16
16
  0.00005 * temp_kelvin * Math.log(temp_kelvin)),
17
17
  };
18
18
  }
19
- export function create_temp_ternary_entries_li_fe_o() {
20
- return [
21
- ...[`Li`, `Fe`, `O`].map((element, idx) => make_demo_phase({ [element]: 1 }, idx)),
22
- ...[
23
- [`Li`, `Fe`],
24
- [`Li`, `O`],
25
- [`Fe`, `O`],
26
- ].flatMap(([element_a, element_b], idx) => [0.33, 0.5, 0.67].flatMap((fraction, jdx) => [
27
- make_demo_phase({ [element_a]: fraction, [element_b]: 1 - fraction }, 100 + idx * 10 + jdx),
28
- make_demo_phase({ [element_a]: fraction, [element_b]: 1 - fraction }, 200 + idx * 10 + jdx, 3),
29
- ])),
30
- ...[
31
- { Li: 0.33, Fe: 0.33, O: 0.34 },
32
- { Li: 0.5, Fe: 0.25, O: 0.25 },
33
- { Li: 0.25, Fe: 0.5, O: 0.25 },
34
- { Li: 0.25, Fe: 0.25, O: 0.5 },
35
- ].flatMap((composition, idx) => [
36
- make_demo_phase(composition, 300 + idx),
37
- make_demo_phase(composition, 400 + idx, 4),
38
- ]),
39
- ];
40
- }
19
+ export const create_temp_ternary_entries_li_fe_o = () => [
20
+ ...[`Li`, `Fe`, `O`].map((element, idx) => make_demo_phase({ [element]: 1 }, idx)),
21
+ ...[
22
+ [`Li`, `Fe`],
23
+ [`Li`, `O`],
24
+ [`Fe`, `O`],
25
+ ].flatMap(([element_a, element_b], idx) => [0.33, 0.5, 0.67].flatMap((fraction, jdx) => [
26
+ make_demo_phase({ [element_a]: fraction, [element_b]: 1 - fraction }, 100 + idx * 10 + jdx),
27
+ make_demo_phase({ [element_a]: fraction, [element_b]: 1 - fraction }, 200 + idx * 10 + jdx, 3),
28
+ ])),
29
+ ...[
30
+ { Li: 0.33, Fe: 0.33, O: 0.34 },
31
+ { Li: 0.5, Fe: 0.25, O: 0.25 },
32
+ { Li: 0.25, Fe: 0.5, O: 0.25 },
33
+ { Li: 0.25, Fe: 0.25, O: 0.5 },
34
+ ].flatMap((composition, idx) => [
35
+ make_demo_phase(composition, 300 + idx),
36
+ make_demo_phase(composition, 400 + idx, 4),
37
+ ]),
38
+ ];
@@ -4,7 +4,7 @@ export declare const R_EV_PER_K = 0.00008617333262;
4
4
  export declare const P_REF = 1;
5
5
  export declare const DEFAULT_ELEMENT_TO_GAS: Readonly<Partial<Record<ElementSymbol, GasSpecies>>>;
6
6
  export declare const GAS_STOICHIOMETRY: Readonly<Record<GasSpecies, Partial<Record<ElementSymbol, number>>>>;
7
- export declare function create_default_gas_provider(): GasThermodynamicsProvider;
7
+ export declare const create_default_gas_provider: () => GasThermodynamicsProvider;
8
8
  export declare function get_default_gas_provider(): GasThermodynamicsProvider;
9
9
  export declare function compute_gas_chemical_potential(provider: GasThermodynamicsProvider, gas: GasSpecies, T: number, P: number): number;
10
10
  export declare function compute_element_chemical_potential(provider: GasThermodynamicsProvider, gas: GasSpecies, element: ElementSymbol, T: number, P: number): number;
@@ -12,5 +12,5 @@ export declare function analyze_gas_data(entries: PhaseData[], config: GasThermo
12
12
  export declare function get_effective_pressures(config: GasThermodynamicsConfig): Record<GasSpecies, number>;
13
13
  export declare function compute_gas_correction(entry: PhaseData, config: GasThermodynamicsConfig, T: number, pressures: Record<GasSpecies, number>): number;
14
14
  export declare function apply_gas_corrections(entries: PhaseData[], config: GasThermodynamicsConfig | undefined, T: number): PhaseData[];
15
- export declare function format_chemical_potential(mu: number, decimals?: number): string;
15
+ export declare const format_chemical_potential: (mu: number, decimals?: number) => string;
16
16
  export declare function format_pressure(P: number): string;
@@ -100,23 +100,21 @@ function interpolate_ts(data, T) {
100
100
  }
101
101
  // Default Provider Implementation
102
102
  // Create the default gas thermodynamics provider using built-in data
103
- export function create_default_gas_provider() {
104
- return {
105
- get_standard_chemical_potential(gas, T) {
106
- // μ°(T) = H_f - T*S
107
- // For elemental gases (O2, N2, H2, F2), H_f = 0
108
- const H_f = DEFAULT_ENTHALPY[gas] ?? 0;
109
- const TS = interpolate_ts(DEFAULT_TS_DATA[gas], T);
110
- return H_f - TS;
111
- },
112
- get_supported_gases() {
113
- return [...GAS_SPECIES];
114
- },
115
- get_temperature_range() {
116
- return [0, 2000];
117
- },
118
- };
119
- }
103
+ export const create_default_gas_provider = () => ({
104
+ get_standard_chemical_potential(gas, T) {
105
+ // μ°(T) = H_f - T*S
106
+ // For elemental gases (O2, N2, H2, F2), H_f = 0
107
+ const H_f = DEFAULT_ENTHALPY[gas] ?? 0;
108
+ const TS = interpolate_ts(DEFAULT_TS_DATA[gas], T);
109
+ return H_f - TS;
110
+ },
111
+ get_supported_gases() {
112
+ return [...GAS_SPECIES];
113
+ },
114
+ get_temperature_range() {
115
+ return [0, 2000];
116
+ },
117
+ });
120
118
  // Singleton default provider
121
119
  let default_provider = null;
122
120
  // Get the default gas thermodynamics provider (lazy initialization)
@@ -237,7 +235,7 @@ export function compute_gas_correction(entry, config, T, pressures) {
237
235
  ...DEFAULT_ELEMENT_TO_GAS,
238
236
  ...config.element_to_gas,
239
237
  };
240
- const enabled_gases = new Set(config.enabled_gases ?? []);
238
+ const enabled_gases = new Set(config.enabled_gases);
241
239
  let correction = 0;
242
240
  const n_atoms = count_atoms_in_composition(entry.composition);
243
241
  for (const [el_str, amount] of Object.entries(entry.composition)) {
@@ -290,21 +288,15 @@ export function apply_gas_corrections(entries, config, T) {
290
288
  // If no correction needed, return entry unchanged
291
289
  if (Math.abs(correction) < 1e-12)
292
290
  return entry;
293
- // Apply correction to energy (update both energy and energy_per_atom
294
- // so downstream formation energy calculations use the corrected value)
295
- // Both fields store per-atom values, and correction is also per-atom
296
- const corrected_energy = entry.energy + correction;
297
- return {
298
- ...entry,
299
- energy: corrected_energy,
300
- energy_per_atom: corrected_energy,
301
- };
291
+ // compute_gas_correction is PER-ATOM: shift energy_per_atom by it and rescale total
292
+ // energy by atom count so downstream formation energies use the corrected values
293
+ const atoms = count_atoms_in_composition(entry.composition);
294
+ const energy_per_atom = (entry.energy_per_atom ?? entry.energy / atoms) + correction;
295
+ return { ...entry, energy: energy_per_atom * atoms, energy_per_atom };
302
296
  });
303
297
  }
304
298
  // Format chemical potential for display (e.g., "-1.23 eV")
305
- export function format_chemical_potential(mu, decimals = 3) {
306
- return `${mu >= 0 ? `+` : ``}${mu.toFixed(decimals)} eV`;
307
- }
299
+ export const format_chemical_potential = (mu, decimals = 3) => `${mu >= 0 ? `+` : ``}${mu.toFixed(decimals)} eV`;
308
300
  // Format pressure for display (scientific notation for very small/large values)
309
301
  export function format_pressure(P) {
310
302
  if (P >= 0.01 && P < 100) {
@@ -34,6 +34,9 @@ export declare function auto_threshold_reset(default_threshold: number): (next_s
34
34
  export declare function current_entry<Entry extends {
35
35
  entry_id?: string;
36
36
  }>(entry: Entry | null | undefined, entries: readonly Entry[]): Entry | null;
37
+ export declare function same_entry<Entry extends {
38
+ entry_id?: string;
39
+ }>(a: Entry | null | undefined, b: Entry | null | undefined): boolean;
37
40
  export declare function build_entry_tooltip_text(entry: PhaseData): string;
38
41
  export declare function find_hull_entry_at_mouse<T extends {
39
42
  x: number;
@@ -48,7 +48,7 @@ export function get_energy_color_scale(color_mode, color_scale, plot_entries) {
48
48
  export function get_point_color_for_entry(entry, color_mode, colors, energy_scale) {
49
49
  const is_stable = entry_is_stable(entry);
50
50
  if (color_mode === `stability`) {
51
- return is_stable ? colors?.stable || `#0072B2` : colors?.unstable || `#E69F00`;
51
+ return is_stable ? (colors?.stable ?? `#0072B2`) : (colors?.unstable ?? `#E69F00`);
52
52
  }
53
53
  return energy_scale && typeof entry.e_above_hull === `number`
54
54
  ? energy_scale(entry.e_above_hull)
@@ -120,6 +120,16 @@ export function current_entry(entry, entries) {
120
120
  }
121
121
  return entries.includes(entry) ? entry : null;
122
122
  }
123
+ // Same logical entry: same object or same entry_id. The id check is proxy-safe — a raw
124
+ // plot entry equals its $state-proxied copy, so the selection effect doesn't reassign
125
+ // forever (effect_update_depth_exceeded) on identity mismatch.
126
+ export function same_entry(a, b) {
127
+ if (a === b)
128
+ return true;
129
+ if (!a || !b)
130
+ return false;
131
+ return a.entry_id != null && a.entry_id === b.entry_id;
132
+ }
123
133
  // Build a tooltip text for any phase entry (shared)
124
134
  export function build_entry_tooltip_text(entry) {
125
135
  const is_element = is_unary_entry(entry);
@@ -127,7 +137,7 @@ export function build_entry_tooltip_text(entry) {
127
137
  const elem_name = is_element ? (ELEM_SYMBOL_TO_NAME[elem_symbol] ?? ``) : ``;
128
138
  let text = is_element
129
139
  ? `${elem_symbol}${elem_name ? ` (${elem_name})` : ``}\n`
130
- : `${entry.name || entry.reduced_formula || ``}\n`;
140
+ : `${entry.name ?? entry.reduced_formula ?? ``}\n`;
131
141
  if (!is_element) {
132
142
  const total = Object.values(entry.composition).reduce((sum, amt) => sum + amt, 0);
133
143
  if (total > 0) {
@@ -254,7 +264,7 @@ export const merge_highlight_style = (custom_style) => ({
254
264
  });
255
265
  // Check if entry matches any item in highlighted_list (by structure_id or entry_id)
256
266
  export function is_entry_highlighted(entry, highlighted_list) {
257
- if (!highlighted_list.length)
267
+ if (highlighted_list.length === 0)
258
268
  return false;
259
269
  const { entry_id, structure_id } = entry;
260
270
  if (!entry_id && !structure_id)
@@ -322,12 +332,10 @@ function get_label_representative_energy(entry) {
322
332
  return entry.e_above_hull;
323
333
  return Number.POSITIVE_INFINITY;
324
334
  }
325
- function get_fractional_composition_key(composition) {
326
- return Object.entries(get_fractional_composition(composition))
327
- .sort(([elem_a], [elem_b]) => elem_a.localeCompare(elem_b))
328
- .map(([elem, frac]) => `${elem}:${frac.toFixed(6)}`)
329
- .join(`|`);
330
- }
335
+ const get_fractional_composition_key = (composition) => Object.entries(get_fractional_composition(composition))
336
+ .sort(([elem_a], [elem_b]) => elem_a.localeCompare(elem_b))
337
+ .map(([elem, frac]) => `${elem}:${frac.toFixed(6)}`)
338
+ .join(`|`);
331
339
  // Pick one label target per normalized composition. Multiple polymorphs, supercell
332
340
  // formulas, or same-composition entries often project to the same screen position.
333
341
  export function get_composition_label_entries(entries) {
@@ -1,4 +1,5 @@
1
1
  import type { D3InterpolateName } from '../colors';
2
+ import type { TooltipConfig } from '../tooltip';
2
3
  import type { Snippet } from 'svelte';
3
4
  import type { HTMLAttributes } from 'svelte/elements';
4
5
  import type { ConvexHullConfig, ConvexHullControlsType, GasSpecies, GasThermodynamicsConfig, HighlightStyle, HoverData3D, HullFaceColorMode, PhaseData, PhaseStats } from './types';
@@ -29,7 +30,6 @@ export interface TooltipSnippetProps<AnyDimEntry = PhaseData> {
29
30
  entry: AnyDimEntry;
30
31
  highlight_style?: HighlightStyle;
31
32
  }
32
- import type { TooltipConfig } from '../tooltip';
33
33
  export type ConvexHullTooltipConfig<AnyDimEntry = PhaseData> = TooltipConfig<AnyDimEntry>;
34
34
  export type ConvexHullTooltipProp<AnyDimEntry = PhaseData> = Snippet<[TooltipSnippetProps<AnyDimEntry>]> | ConvexHullTooltipConfig<AnyDimEntry>;
35
35
  export interface BaseConvexHullProps<AnyDimEntry = PhaseData> extends Omit<HTMLAttributes<HTMLDivElement>, `entries` | `children`> {
@@ -101,6 +101,8 @@ export function find_lowest_energy_unary_refs(entries) {
101
101
  }
102
102
  return refs;
103
103
  }
104
+ // Result key for an entry: entry_id, falling back to its serialized composition
105
+ const id_of = (entry) => entry.entry_id ?? JSON.stringify(entry.composition);
104
106
  export function calculate_e_above_hull(input, reference_entries) {
105
107
  const is_single = !Array.isArray(input);
106
108
  const entries_of_interest = is_single ? [input] : input;
@@ -135,7 +137,7 @@ export function calculate_e_above_hull(input, reference_entries) {
135
137
  if (arity === 1) {
136
138
  // Unary system
137
139
  for (const { entry, e_form } of interest_data) {
138
- const id = entry.entry_id ?? JSON.stringify(entry.composition);
140
+ const id = id_of(entry);
139
141
  // For unary, e_above_hull is simply e_form (since stable state is 0)
140
142
  // Unless we have multiple polymorphs, in which case the hull is at min(e_form) which should be 0
141
143
  // But compute_e_form_per_atom already subtracts the stable unary reference energy.
@@ -149,6 +151,8 @@ export function calculate_e_above_hull(input, reference_entries) {
149
151
  // Build hull points from references
150
152
  const hull_input_map = new Map(); // x -> min_e_form
151
153
  for (const ref of reference_entries) {
154
+ if (ref.exclude_from_hull)
155
+ continue; // Shown but not used in hull construction
152
156
  const e_form = compute_e_form(ref);
153
157
  if (typeof e_form !== `number`)
154
158
  continue;
@@ -169,7 +173,7 @@ export function calculate_e_above_hull(input, reference_entries) {
169
173
  const hull_points = Array.from(hull_input_map, ([x, y]) => ({ x, y }));
170
174
  const lower_hull = compute_lower_hull_2d(hull_points);
171
175
  for (const { entry, e_form } of interest_data) {
172
- const id = entry.entry_id ?? JSON.stringify(entry.composition);
176
+ const id = id_of(entry);
173
177
  if (typeof e_form !== `number`) {
174
178
  results[id] = NaN;
175
179
  continue;
@@ -189,6 +193,8 @@ export function calculate_e_above_hull(input, reference_entries) {
189
193
  // Ternary system
190
194
  const ref_points = [];
191
195
  for (const ref of reference_entries) {
196
+ if (ref.exclude_from_hull)
197
+ continue; // Shown but not used in hull construction
192
198
  const e_form = compute_e_form(ref);
193
199
  if (typeof e_form !== `number`)
194
200
  continue;
@@ -204,20 +210,26 @@ export function calculate_e_above_hull(input, reference_entries) {
204
210
  // Ensure corner points (pure elements default to e_form = 0)
205
211
  for (const el of elements) {
206
212
  const corner = barycentric_to_ternary_xyz(composition_to_barycentric_3d({ [el]: 1 }, elements), 0);
207
- if (!ref_points.some((point) => Math.hypot(point.x - corner.x, point.y - corner.y, point.z - corner.z) < 1e-9)) {
213
+ const dist = (point) => Math.hypot(point.x - corner.x, point.y - corner.y, point.z - corner.z);
214
+ if (!ref_points.some((point) => dist(point) < 1e-9))
208
215
  ref_points.push(corner);
209
- }
210
216
  }
211
217
  const hull_triangles = compute_lower_hull_triangles(ref_points);
212
218
  const hull_models = build_lower_hull_model(hull_triangles);
219
+ // No facets despite enough refs → all coplanar at e_form = 0: use elemental tie-plane
220
+ const degenerate_hull_3d = hull_triangles.length === 0 && ref_points.length >= arity;
213
221
  for (const { entry, e_form } of interest_data) {
214
- const id = entry.entry_id ?? JSON.stringify(entry.composition);
222
+ const id = id_of(entry);
215
223
  if (typeof e_form !== `number`) {
216
224
  results[id] = NaN;
217
225
  continue;
218
226
  }
219
227
  try {
220
228
  const bary = composition_to_barycentric_3d(entry.composition, elements);
229
+ if (degenerate_hull_3d) {
230
+ results[id] = Math.max(0, e_form);
231
+ continue;
232
+ }
221
233
  const point = barycentric_to_ternary_xyz(bary, e_form);
222
234
  const z_hull = e_hull_at_xy(hull_models, point.x, point.y);
223
235
  results[id] = z_hull === null ? NaN : Math.max(0, point.z - z_hull);
@@ -231,6 +243,8 @@ export function calculate_e_above_hull(input, reference_entries) {
231
243
  // Quaternary system
232
244
  const ref_points = [];
233
245
  for (const ref of reference_entries) {
246
+ if (ref.exclude_from_hull)
247
+ continue; // Shown but not used in hull construction
234
248
  const e_form = compute_e_form(ref);
235
249
  if (typeof e_form !== `number`)
236
250
  continue;
@@ -252,46 +266,45 @@ export function calculate_e_above_hull(input, reference_entries) {
252
266
  ref_points.push(corner);
253
267
  }
254
268
  const hull_tetrahedra = compute_lower_hull_4d(ref_points);
269
+ // No facets despite enough refs → all coplanar at e_form = 0: use elemental tie-plane
270
+ const degenerate_hull_4d = hull_tetrahedra.length === 0 && ref_points.length >= arity;
255
271
  const interest_points = [];
256
- const interest_indices = [];
272
+ const idx_to_point_idx = new Map(); // entry idx -> point idx
257
273
  interest_data.forEach(({ entry, e_form }, idx) => {
258
- if (typeof e_form === `number`) {
259
- try {
260
- const bary = composition_to_barycentric_4d(entry.composition, elements);
261
- const tet = barycentric_to_tetrahedral(bary);
262
- interest_points.push({ ...tet, w: e_form });
263
- interest_indices.push(idx);
264
- }
265
- catch {
266
- // Skip
267
- }
274
+ if (typeof e_form !== `number`)
275
+ return;
276
+ try {
277
+ const bary = composition_to_barycentric_4d(entry.composition, elements);
278
+ const tet = barycentric_to_tetrahedral(bary);
279
+ idx_to_point_idx.set(idx, interest_points.length);
280
+ interest_points.push({ ...tet, w: e_form });
281
+ }
282
+ catch {
283
+ // Skip
268
284
  }
269
285
  });
270
286
  const distances = compute_e_above_hull_4d(interest_points, hull_tetrahedra);
271
- // Build reverse lookup for O(1) access
272
- const idx_to_point_idx = new Map();
273
- interest_indices.forEach((original_idx, point_idx) => {
274
- idx_to_point_idx.set(original_idx, point_idx);
275
- });
276
287
  // Map back
277
288
  for (let idx = 0; idx < interest_data.length; idx++) {
278
- const { entry } = interest_data[idx];
279
- const id = entry.entry_id ?? JSON.stringify(entry.composition);
280
- const point_idx = idx_to_point_idx.get(idx) ?? -1;
281
- if (point_idx !== -1) {
282
- results[id] = Math.max(0, distances[point_idx]);
283
- }
284
- else {
289
+ const { entry, e_form } = interest_data[idx];
290
+ const id = id_of(entry);
291
+ const point_idx = idx_to_point_idx.get(idx);
292
+ const on_tie_plane = degenerate_hull_4d && typeof e_form === `number`;
293
+ if (point_idx === undefined)
285
294
  results[id] = NaN;
286
- }
295
+ else
296
+ results[id] = Math.max(0, on_tie_plane ? e_form : distances[point_idx]);
287
297
  }
288
298
  }
289
299
  else {
290
300
  // Arity 5+ uses generalized N-dimensional convex hull
291
- // Helper to convert entry to hull point, returns null on expected errors
301
+ // Helper to convert entry to hull point, returns null on expected errors.
302
+ // Barycentric coords sum to 1, so the first is dropped: keeping all N would confine
303
+ // points to an (N-1)-dim affine subspace, leaving the hull permanently degenerate.
292
304
  const to_hull_point = (entry, e_form) => {
293
305
  try {
294
- return [...composition_to_barycentric_nd(entry.composition, elements), e_form];
306
+ const bary = composition_to_barycentric_nd(entry.composition, elements);
307
+ return [...bary.slice(1), e_form];
295
308
  }
296
309
  catch (err) {
297
310
  // Skip expected errors (missing elements), warn on unexpected
@@ -304,6 +317,8 @@ export function calculate_e_above_hull(input, reference_entries) {
304
317
  // Build reference points
305
318
  const ref_points = [];
306
319
  for (const ref of reference_entries) {
320
+ if (ref.exclude_from_hull)
321
+ continue; // Shown but not used in hull construction
307
322
  const e_form = compute_e_form(ref);
308
323
  if (typeof e_form !== `number`)
309
324
  continue;
@@ -311,20 +326,21 @@ export function calculate_e_above_hull(input, reference_entries) {
311
326
  if (point)
312
327
  ref_points.push(point);
313
328
  }
314
- // Ensure corner points (pure elements default to e_form = 0)
329
+ // Ensure corner points (pure elements default to e_form = 0). In reduced
330
+ // coordinates, element 0 is the origin; element k > 0 has (k-1)th coord = 1.
315
331
  for (let el_idx = 0; el_idx < arity; el_idx++) {
316
- const corner = Array(arity + 1).fill(0);
317
- corner[el_idx] = 1; // ith barycentric coord = 1
332
+ const corner = Array(arity).fill(0);
333
+ if (el_idx > 0)
334
+ corner[el_idx - 1] = 1;
318
335
  if (!ref_points.some((pt) => norm_nd(subtract_nd(pt, corner)) < EPS)) {
319
336
  ref_points.push(corner);
320
337
  }
321
338
  }
322
339
  const hull_facets = compute_lower_hull_nd(compute_quickhull_nd(ref_points));
323
- // Warn if hull is degenerate (all points coplanar or insufficient spread)
340
+ // Degenerate hull (all refs co-hyperplanar, e.g. all e_form = 0): tie-plane fallback is exact
324
341
  if (hull_facets.length === 0 && ref_points.length >= arity + 1) {
325
- console.warn(`N-dimensional hull for ${arity}-element system is degenerate. ` +
326
- `Falling back to tie-hyperplane at energy 0. ` +
327
- `Consider using pymatgen for complex high-dimensional phase diagrams.`);
342
+ console.warn(`N-dimensional hull for ${arity}-element system is degenerate ` +
343
+ `(all reference points co-hyperplanar). Falling back to tie-hyperplane at energy 0.`);
328
344
  }
329
345
  // Build query points with mapping back to original indices
330
346
  const interest_points = [];
@@ -343,27 +359,20 @@ export function calculate_e_above_hull(input, reference_entries) {
343
359
  const distances = hull_facets.length > 0
344
360
  ? compute_e_above_hull_nd(interest_points, hull_facets, ref_points)
345
361
  : [];
346
- // Map results back to entries
362
+ // Map results back to entries (degenerate hull → tie-hyperplane at energy 0)
347
363
  for (let idx = 0; idx < interest_data.length; idx++) {
348
364
  const { entry, e_form } = interest_data[idx];
349
- const id = entry.entry_id ?? JSON.stringify(entry.composition);
365
+ const id = id_of(entry);
350
366
  const point_idx = idx_to_point_idx.get(idx);
351
- if (point_idx === undefined) {
367
+ const on_tie_plane = hull_facets.length === 0 && typeof e_form === `number`;
368
+ if (point_idx === undefined)
352
369
  results[id] = NaN;
353
- }
354
- else if (hull_facets.length === 0 && typeof e_form === `number`) {
355
- // Degenerate case: hull is tie-hyperplane at energy 0
356
- results[id] = Math.max(0, e_form);
357
- }
358
- else {
359
- results[id] = Math.max(0, distances[point_idx]);
360
- }
370
+ else
371
+ results[id] = Math.max(0, on_tie_plane ? e_form : distances[point_idx]);
361
372
  }
362
373
  }
363
- if (is_single) {
364
- const id = entries_of_interest[0].entry_id ?? JSON.stringify(entries_of_interest[0].composition);
365
- return results[id];
366
- }
374
+ if (is_single)
375
+ return results[id_of(entries_of_interest[0])];
367
376
  return results;
368
377
  }
369
378
  export function get_convex_hull_stats(processed_entries, elements, max_arity = 4) {
@@ -437,25 +446,23 @@ export function get_convex_hull_stats(processed_entries, elements, max_arity = 4
437
446
  }
438
447
  // Convert a PhaseData entry to a ConvexHullEntry with default visual fields.
439
448
  // x/y/z default to 0 since high-dim systems aren't visually plotted.
440
- function to_hull_entry(entry) {
441
- return {
442
- ...entry,
443
- is_element: get_arity(entry) === 1,
444
- x: 0,
445
- y: 0,
446
- z: 0,
447
- };
448
- }
449
+ const to_hull_entry = (entry) => ({
450
+ ...entry,
451
+ is_element: get_arity(entry) === 1,
452
+ x: 0,
453
+ y: 0,
454
+ z: 0,
455
+ });
449
456
  // Process raw hull entries for high-dimensional systems (5+ elements) where the
450
457
  // ConvexHull visual component can't render. Computes formation energies, hull distances,
451
458
  // stable/unstable classification, and phase stats. Returns null on failure.
452
459
  // Optionally accepts `elements` to scope the chemical system; if omitted, elements
453
460
  // are derived from the entries' compositions.
454
461
  export function process_hull_for_stats(entries, elements) {
455
- if (!entries.length)
462
+ if (entries.length === 0)
456
463
  return null;
457
464
  const processed = process_hull_entries(entries);
458
- if (!processed.entries.length)
465
+ if (processed.entries.length === 0)
459
466
  return null;
460
467
  const hull_elements = elements ?? processed.elements;
461
468
  // Compute formation energies
@@ -473,7 +480,7 @@ export function process_hull_for_stats(entries, elements) {
473
480
  try {
474
481
  const hull_distances = calculate_e_above_hull(processed.entries, processed.entries);
475
482
  for (const entry of processed.entries) {
476
- const dist = hull_distances[entry.entry_id ?? JSON.stringify(entry.composition)];
483
+ const dist = hull_distances[id_of(entry)];
477
484
  if (typeof dist === `number` && Number.isFinite(dist)) {
478
485
  entry.e_above_hull = dist;
479
486
  entry.is_stable = dist < HULL_STABILITY_TOL;
@@ -1672,19 +1679,17 @@ export function compute_lower_hull_nd(faces) {
1672
1679
  // Last dimension is energy; negative normal means "downward"
1673
1680
  return faces.filter((face) => (face.plane.normal.at(-1) ?? 0) < -EPS);
1674
1681
  }
1675
- function build_simplex_models_nd(faces, points) {
1676
- return faces.map((face) => {
1677
- const vertices = face.vertex_indices.map((idx) => points[idx]);
1678
- const n = vertices[0].length;
1679
- // Spatial coords are all except last (energy)
1680
- const vertices_spatial = vertices.map((pt) => pt.slice(0, n - 1));
1681
- // Compute bounding box in spatial dimensions
1682
- const spatial_dim = n - 1;
1683
- const bbox_min = Array.from({ length: spatial_dim }, (_, idx) => Math.min(...vertices_spatial.map((pt) => pt[idx])));
1684
- const bbox_max = Array.from({ length: spatial_dim }, (_, idx) => Math.max(...vertices_spatial.map((pt) => pt[idx])));
1685
- return { vertices, vertices_spatial, bbox_min, bbox_max };
1686
- });
1687
- }
1682
+ const build_simplex_models_nd = (faces, points) => faces.map((face) => {
1683
+ const vertices = face.vertex_indices.map((idx) => points[idx]);
1684
+ const n = vertices[0].length;
1685
+ // Spatial coords are all except last (energy)
1686
+ const vertices_spatial = vertices.map((pt) => pt.slice(0, n - 1));
1687
+ // Compute bounding box in spatial dimensions
1688
+ const spatial_dim = n - 1;
1689
+ const bbox_min = Array.from({ length: spatial_dim }, (_, idx) => Math.min(...vertices_spatial.map((pt) => pt[idx])));
1690
+ const bbox_max = Array.from({ length: spatial_dim }, (_, idx) => Math.max(...vertices_spatial.map((pt) => pt[idx])));
1691
+ return { vertices, vertices_spatial, bbox_min, bbox_max };
1692
+ });
1688
1693
  // Check if point is inside simplex and return barycentric coordinates
1689
1694
  // Uses linear system solution: point = sum(bary[i] * vertex[i]) with sum(bary) = 1
1690
1695
  function point_in_simplex_nd(point, simplex_vertices) {
@@ -2,7 +2,7 @@ import type { CompositionType } from '../composition';
2
2
  import type { ShowControlsProp } from '../controls';
3
3
  import type { ElementSymbol } from '../element';
4
4
  import type { Point2D, Point3D, Vec3 } from '../math';
5
- import type { Rect, Sides } from '../plot/layout';
5
+ import type { Rect, Sides } from '../plot/core/layout';
6
6
  import type { AnyStructure } from '../structure';
7
7
  export interface StructurePopupStats {
8
8
  id?: string;
@@ -9,7 +9,7 @@
9
9
  BarHandlerProps,
10
10
  BarSeries,
11
11
  Orientation,
12
- } from '../plot/types'
12
+ } from '../plot/core/types'
13
13
  import type { AnyStructure } from '../structure'
14
14
  import type { BondingStrategy } from '../structure/bonding'
15
15
  import { parse_any_structure } from '../structure/parse'
@@ -18,6 +18,7 @@
18
18
  import { SvelteMap, SvelteSet } from 'svelte/reactivity'
19
19
  import { calc_coordination_nums, type CoordinationData } from './calc-coordination'
20
20
  import type { SplitMode } from './index'
21
+ import { to_error } from '../utils'
21
22
 
22
23
  type CoordinationMetadata = {
23
24
  element?: string
@@ -178,31 +179,30 @@
178
179
  metadata: { structure_label: entry.label },
179
180
  }
180
181
  })
181
- } else {
182
- // split_mode === 'none': combine all into single series
183
- const combined_histogram = new SvelteMap<number, number>()
182
+ }
183
+ // split_mode === 'none': combine all into single series
184
+ const combined_histogram = new SvelteMap<number, number>()
184
185
 
185
- for (const entry of entries_with_data) {
186
- for (const [cn, count] of entry.data.cn_histogram) {
187
- combined_histogram.set(cn, (combined_histogram.get(cn) ?? 0) + count)
188
- }
186
+ for (const entry of entries_with_data) {
187
+ for (const [cn, count] of entry.data.cn_histogram) {
188
+ combined_histogram.set(cn, (combined_histogram.get(cn) ?? 0) + count)
189
189
  }
190
+ }
190
191
 
191
- const x_vals = Array.from(combined_histogram.keys()).sort((a, b) => a - b)
192
- const y_vals = x_vals.map((cn) => combined_histogram.get(cn) ?? 0)
192
+ const x_vals = Array.from(combined_histogram.keys()).sort((a, b) => a - b)
193
+ const y_vals = x_vals.map((cn) => combined_histogram.get(cn) ?? 0)
193
194
 
194
- return [
195
- {
196
- x: x_vals,
197
- y: y_vals,
198
- label: `All Sites`,
199
- color: PLOT_COLORS[0],
200
- bar_width: 0.8,
201
- visible: true,
202
- metadata: {},
203
- },
204
- ]
205
- }
195
+ return [
196
+ {
197
+ x: x_vals,
198
+ y: y_vals,
199
+ label: `All Sites`,
200
+ color: PLOT_COLORS[0],
201
+ bar_width: 0.8,
202
+ visible: true,
203
+ metadata: {},
204
+ },
205
+ ]
206
206
  })
207
207
 
208
208
  const compute_and_add = (content: string | ArrayBuffer, filename: string) => {
@@ -221,7 +221,7 @@
221
221
  }
222
222
  } catch (exc) {
223
223
  error_msg = `Failed to process structure: ${
224
- exc instanceof Error ? exc.message : String(exc)
224
+ to_error(exc).message
225
225
  }`
226
226
  }
227
227
  }