matterviz 0.3.1 → 0.3.3

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 (358) hide show
  1. package/dist/EmptyState.svelte +10 -2
  2. package/dist/FilePicker.svelte +154 -96
  3. package/dist/Icon.svelte +20 -14
  4. package/dist/MillerIndexInput.svelte +27 -21
  5. package/dist/api/optimade.js +6 -6
  6. package/dist/app.css +216 -178
  7. package/dist/brillouin/BrillouinZone.svelte +299 -198
  8. package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
  9. package/dist/brillouin/BrillouinZoneControls.svelte +32 -5
  10. package/dist/brillouin/BrillouinZoneExportPane.svelte +74 -55
  11. package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +1 -1
  12. package/dist/brillouin/BrillouinZoneInfoPane.svelte +99 -68
  13. package/dist/brillouin/BrillouinZoneScene.svelte +277 -165
  14. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
  15. package/dist/brillouin/BrillouinZoneTooltip.svelte +17 -7
  16. package/dist/brillouin/compute.js +11 -6
  17. package/dist/chempot-diagram/ChemPotDiagram.svelte +327 -0
  18. package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +13 -0
  19. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +847 -0
  20. package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +16 -0
  21. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +3194 -0
  22. package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +16 -0
  23. package/dist/chempot-diagram/ChemPotScene3D.svelte +11 -0
  24. package/dist/chempot-diagram/ChemPotScene3D.svelte.d.ts +7 -0
  25. package/dist/chempot-diagram/async-compute.svelte.d.ts +3 -0
  26. package/dist/chempot-diagram/async-compute.svelte.js +77 -0
  27. package/dist/chempot-diagram/chempot-worker.d.ts +1 -0
  28. package/dist/chempot-diagram/chempot-worker.js +11 -0
  29. package/dist/chempot-diagram/color.d.ts +10 -0
  30. package/dist/chempot-diagram/color.js +32 -0
  31. package/dist/chempot-diagram/compute.d.ts +48 -0
  32. package/dist/chempot-diagram/compute.js +812 -0
  33. package/dist/chempot-diagram/index.d.ts +6 -0
  34. package/dist/chempot-diagram/index.js +6 -0
  35. package/dist/chempot-diagram/pointer.d.ts +16 -0
  36. package/dist/chempot-diagram/pointer.js +40 -0
  37. package/dist/chempot-diagram/temperature.d.ts +15 -0
  38. package/dist/chempot-diagram/temperature.js +36 -0
  39. package/dist/chempot-diagram/types.d.ts +86 -0
  40. package/dist/chempot-diagram/types.js +28 -0
  41. package/dist/colors/index.d.ts +3 -1
  42. package/dist/colors/index.js +9 -3
  43. package/dist/composition/BarChart.svelte +141 -77
  44. package/dist/composition/BubbleChart.svelte +107 -52
  45. package/dist/composition/Composition.svelte +100 -79
  46. package/dist/composition/Formula.svelte +108 -62
  47. package/dist/composition/FormulaFilter.svelte +973 -353
  48. package/dist/composition/FormulaFilter.svelte.d.ts +35 -1
  49. package/dist/composition/PieChart.svelte +199 -99
  50. package/dist/composition/PieChart.svelte.d.ts +1 -1
  51. package/dist/composition/format.d.ts +5 -0
  52. package/dist/composition/format.js +20 -3
  53. package/dist/composition/parse.js +14 -9
  54. package/dist/convex-hull/ConvexHull.svelte +93 -38
  55. package/dist/convex-hull/ConvexHull2D.svelte +551 -393
  56. package/dist/convex-hull/ConvexHull3D.svelte +1303 -825
  57. package/dist/convex-hull/ConvexHull4D.svelte +1012 -686
  58. package/dist/convex-hull/ConvexHullControls.svelte +115 -28
  59. package/dist/convex-hull/ConvexHullInfoPane.svelte +29 -3
  60. package/dist/convex-hull/ConvexHullStats.svelte +821 -249
  61. package/dist/convex-hull/ConvexHullStats.svelte.d.ts +6 -1
  62. package/dist/convex-hull/ConvexHullTooltip.svelte +41 -16
  63. package/dist/convex-hull/GasPressureControls.svelte +104 -61
  64. package/dist/convex-hull/StructurePopup.svelte +25 -4
  65. package/dist/convex-hull/TemperatureSlider.svelte +45 -25
  66. package/dist/convex-hull/barycentric-coords.js +13 -7
  67. package/dist/convex-hull/demo-temperature.d.ts +6 -0
  68. package/dist/convex-hull/demo-temperature.js +40 -0
  69. package/dist/convex-hull/gas-thermodynamics.js +17 -12
  70. package/dist/convex-hull/helpers.d.ts +10 -1
  71. package/dist/convex-hull/helpers.js +79 -38
  72. package/dist/convex-hull/index.d.ts +1 -0
  73. package/dist/convex-hull/index.js +1 -0
  74. package/dist/convex-hull/thermodynamics.d.ts +8 -21
  75. package/dist/convex-hull/thermodynamics.js +163 -69
  76. package/dist/convex-hull/types.d.ts +12 -12
  77. package/dist/convex-hull/types.js +0 -12
  78. package/dist/coordination/CoordinationBarPlot.svelte +232 -176
  79. package/dist/element/BohrAtom.svelte +56 -13
  80. package/dist/element/ElementHeading.svelte +7 -2
  81. package/dist/element/ElementPhoto.svelte +15 -9
  82. package/dist/element/ElementStats.svelte +10 -4
  83. package/dist/element/ElementTile.svelte +137 -73
  84. package/dist/element/Nucleus.svelte +39 -11
  85. package/dist/element/data.js +2 -14
  86. package/dist/element/data.json.gz +0 -0
  87. package/dist/element/types.d.ts +1 -0
  88. package/dist/feedback/ClickFeedback.svelte +16 -5
  89. package/dist/feedback/DragOverlay.svelte +10 -2
  90. package/dist/feedback/Spinner.svelte +4 -2
  91. package/dist/feedback/StatusMessage.svelte +8 -2
  92. package/dist/fermi-surface/FermiSlice.svelte +118 -88
  93. package/dist/fermi-surface/FermiSurface.svelte +336 -239
  94. package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
  95. package/dist/fermi-surface/FermiSurfaceControls.svelte +113 -46
  96. package/dist/fermi-surface/FermiSurfaceScene.svelte +536 -343
  97. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
  98. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +14 -5
  99. package/dist/fermi-surface/compute.js +16 -20
  100. package/dist/fermi-surface/parse.js +37 -33
  101. package/dist/fermi-surface/symmetry.js +2 -7
  102. package/dist/fermi-surface/types.d.ts +3 -5
  103. package/dist/heatmap-matrix/HeatmapMatrix.svelte +1527 -0
  104. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +110 -0
  105. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +225 -0
  106. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +30 -0
  107. package/dist/heatmap-matrix/index.d.ts +53 -0
  108. package/dist/heatmap-matrix/index.js +100 -0
  109. package/dist/heatmap-matrix/shared.d.ts +2 -0
  110. package/dist/heatmap-matrix/shared.js +4 -0
  111. package/dist/icons.d.ts +111 -0
  112. package/dist/icons.js +158 -0
  113. package/dist/index.d.ts +5 -2
  114. package/dist/index.js +5 -2
  115. package/dist/io/decompress.js +1 -1
  116. package/dist/io/export.d.ts +3 -0
  117. package/dist/io/export.js +138 -140
  118. package/dist/io/file-drop.d.ts +7 -0
  119. package/dist/io/file-drop.js +43 -0
  120. package/dist/io/index.d.ts +2 -2
  121. package/dist/io/index.js +2 -112
  122. package/dist/io/is-binary.js +2 -3
  123. package/dist/io/types.d.ts +1 -0
  124. package/dist/io/url-drop.d.ts +2 -0
  125. package/dist/io/url-drop.js +117 -0
  126. package/dist/isosurface/Isosurface.svelte +220 -110
  127. package/dist/isosurface/IsosurfaceControls.svelte +65 -28
  128. package/dist/isosurface/parse.js +104 -56
  129. package/dist/isosurface/slice.d.ts +2 -1
  130. package/dist/isosurface/slice.js +8 -13
  131. package/dist/isosurface/types.d.ts +14 -1
  132. package/dist/isosurface/types.js +152 -5
  133. package/dist/labels.d.ts +2 -1
  134. package/dist/labels.js +12 -8
  135. package/dist/layout/FullscreenToggle.svelte +11 -2
  136. package/dist/layout/InfoCard.svelte +38 -6
  137. package/dist/layout/InfoTag.svelte +125 -94
  138. package/dist/layout/PropertyFilter.svelte +82 -37
  139. package/dist/layout/SettingsSection.svelte +85 -55
  140. package/dist/layout/SubpageGrid.svelte +82 -0
  141. package/dist/layout/SubpageGrid.svelte.d.ts +14 -0
  142. package/dist/layout/index.d.ts +1 -0
  143. package/dist/layout/index.js +1 -0
  144. package/dist/layout/json-tree/JsonNode.svelte +266 -223
  145. package/dist/layout/json-tree/JsonTree.svelte +516 -429
  146. package/dist/layout/json-tree/JsonTree.svelte.d.ts +1 -1
  147. package/dist/layout/json-tree/JsonValue.svelte +281 -173
  148. package/dist/layout/json-tree/types.d.ts +10 -2
  149. package/dist/layout/json-tree/utils.d.ts +2 -0
  150. package/dist/layout/json-tree/utils.js +37 -2
  151. package/dist/marching-cubes.js +25 -2
  152. package/dist/math.d.ts +20 -17
  153. package/dist/math.js +474 -57
  154. package/dist/overlays/ContextMenu.svelte +66 -40
  155. package/dist/overlays/DraggablePane.svelte +331 -154
  156. package/dist/overlays/DraggablePane.svelte.d.ts +2 -0
  157. package/dist/periodic-table/PeriodicTable.svelte +278 -145
  158. package/dist/periodic-table/PeriodicTableControls.svelte +178 -128
  159. package/dist/periodic-table/PropertySelect.svelte +25 -7
  160. package/dist/periodic-table/TableInset.svelte +8 -3
  161. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +559 -267
  162. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -2
  163. package/dist/phase-diagram/PhaseDiagramControls.svelte +131 -51
  164. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +3 -2
  165. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +126 -0
  166. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +15 -0
  167. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +160 -110
  168. package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +8 -1
  169. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +217 -86
  170. package/dist/phase-diagram/PhaseDiagramTooltip.svelte.d.ts +6 -3
  171. package/dist/phase-diagram/TdbInfoPanel.svelte +28 -4
  172. package/dist/phase-diagram/build-diagram.js +9 -9
  173. package/dist/phase-diagram/colors.js +1 -3
  174. package/dist/phase-diagram/index.d.ts +2 -0
  175. package/dist/phase-diagram/index.js +2 -0
  176. package/dist/phase-diagram/parse.js +10 -9
  177. package/dist/phase-diagram/svg-to-diagram.d.ts +2 -0
  178. package/dist/phase-diagram/svg-to-diagram.js +869 -0
  179. package/dist/phase-diagram/types.d.ts +10 -0
  180. package/dist/phase-diagram/utils.d.ts +8 -4
  181. package/dist/phase-diagram/utils.js +219 -74
  182. package/dist/plot/AxisLabel.svelte +51 -0
  183. package/dist/plot/AxisLabel.svelte.d.ts +16 -0
  184. package/dist/plot/BarPlot.svelte +1461 -768
  185. package/dist/plot/BarPlot.svelte.d.ts +3 -3
  186. package/dist/plot/BarPlotControls.svelte +33 -6
  187. package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
  188. package/dist/plot/ColorBar.svelte +533 -383
  189. package/dist/plot/ColorBar.svelte.d.ts +1 -1
  190. package/dist/plot/ColorScaleSelect.svelte +28 -7
  191. package/dist/plot/ElementScatter.svelte +38 -16
  192. package/dist/plot/FillArea.svelte +152 -92
  193. package/dist/plot/Histogram.svelte +1162 -709
  194. package/dist/plot/Histogram.svelte.d.ts +1 -1
  195. package/dist/plot/HistogramControls.svelte +81 -18
  196. package/dist/plot/HistogramControls.svelte.d.ts +6 -2
  197. package/dist/plot/InteractiveAxisLabel.svelte +34 -11
  198. package/dist/plot/InteractiveAxisLabel.svelte.d.ts +1 -1
  199. package/dist/plot/Line.svelte +63 -28
  200. package/dist/plot/PlotControls.svelte +221 -96
  201. package/dist/plot/PlotControls.svelte.d.ts +1 -1
  202. package/dist/plot/PlotLegend.svelte +174 -91
  203. package/dist/plot/PlotTooltip.svelte +45 -6
  204. package/dist/plot/PortalSelect.svelte +175 -146
  205. package/dist/plot/ReferenceLine.svelte +77 -22
  206. package/dist/plot/ReferenceLine.svelte.d.ts +1 -0
  207. package/dist/plot/ReferenceLine3D.svelte +132 -107
  208. package/dist/plot/ReferencePlane.svelte +146 -123
  209. package/dist/plot/ScatterPlot.svelte +1880 -1156
  210. package/dist/plot/ScatterPlot.svelte.d.ts +3 -3
  211. package/dist/plot/ScatterPlot3D.svelte +256 -131
  212. package/dist/plot/ScatterPlot3D.svelte.d.ts +2 -2
  213. package/dist/plot/ScatterPlot3DControls.svelte +300 -297
  214. package/dist/plot/ScatterPlot3DControls.svelte.d.ts +2 -1
  215. package/dist/plot/ScatterPlot3DScene.svelte +608 -406
  216. package/dist/plot/ScatterPlot3DScene.svelte.d.ts +2 -2
  217. package/dist/plot/ScatterPlotControls.svelte +150 -70
  218. package/dist/plot/ScatterPlotControls.svelte.d.ts +1 -1
  219. package/dist/plot/ScatterPoint.svelte +98 -26
  220. package/dist/plot/ScatterPoint.svelte.d.ts +1 -0
  221. package/dist/plot/SpacegroupBarPlot.svelte +142 -85
  222. package/dist/plot/Surface3D.svelte +159 -108
  223. package/dist/plot/ZeroLines.svelte +96 -0
  224. package/dist/plot/ZeroLines.svelte.d.ts +32 -0
  225. package/dist/plot/ZoomRect.svelte +23 -0
  226. package/dist/plot/ZoomRect.svelte.d.ts +8 -0
  227. package/dist/plot/axis-utils.d.ts +1 -1
  228. package/dist/plot/axis-utils.js +1 -3
  229. package/dist/plot/data-cleaning.js +12 -28
  230. package/dist/plot/data-transform.js +2 -1
  231. package/dist/plot/fill-utils.js +2 -0
  232. package/dist/plot/index.d.ts +6 -2
  233. package/dist/plot/index.js +6 -2
  234. package/dist/plot/interactions.d.ts +8 -10
  235. package/dist/plot/interactions.js +2 -3
  236. package/dist/plot/layout.d.ts +11 -2
  237. package/dist/plot/layout.js +44 -17
  238. package/dist/plot/reference-line.d.ts +5 -22
  239. package/dist/plot/reference-line.js +12 -84
  240. package/dist/plot/scales.js +24 -36
  241. package/dist/plot/types.d.ts +53 -40
  242. package/dist/plot/types.js +12 -7
  243. package/dist/plot/utils/label-placement.d.ts +32 -15
  244. package/dist/plot/utils/label-placement.js +227 -63
  245. package/dist/plot/utils/series-visibility.js +2 -3
  246. package/dist/plot/utils.d.ts +1 -0
  247. package/dist/plot/utils.js +14 -0
  248. package/dist/rdf/RdfPlot.svelte +173 -132
  249. package/dist/rdf/calc-rdf.js +4 -5
  250. package/dist/sanitize.d.ts +4 -0
  251. package/dist/sanitize.js +107 -0
  252. package/dist/settings.d.ts +21 -6
  253. package/dist/settings.js +63 -19
  254. package/dist/spectral/Bands.svelte +963 -412
  255. package/dist/spectral/Bands.svelte.d.ts +22 -2
  256. package/dist/spectral/BandsAndDos.svelte +90 -49
  257. package/dist/spectral/BrillouinBandsDos.svelte +151 -93
  258. package/dist/spectral/Dos.svelte +389 -258
  259. package/dist/spectral/helpers.d.ts +23 -1
  260. package/dist/spectral/helpers.js +119 -51
  261. package/dist/spectral/types.d.ts +2 -0
  262. package/dist/state.svelte.d.ts +1 -1
  263. package/dist/state.svelte.js +3 -2
  264. package/dist/structure/Arrow.svelte +59 -20
  265. package/dist/structure/AtomLegend.svelte +231 -129
  266. package/dist/structure/AtomLegend.svelte.d.ts +1 -1
  267. package/dist/structure/Bond.svelte +73 -47
  268. package/dist/structure/CanvasTooltip.svelte +10 -2
  269. package/dist/structure/CellSelect.svelte +148 -51
  270. package/dist/structure/Cylinder.svelte +33 -17
  271. package/dist/structure/Lattice.svelte +88 -33
  272. package/dist/structure/Structure.svelte +1077 -821
  273. package/dist/structure/Structure.svelte.d.ts +1 -1
  274. package/dist/structure/StructureControls.svelte +373 -139
  275. package/dist/structure/StructureControls.svelte.d.ts +1 -1
  276. package/dist/structure/StructureExportPane.svelte +124 -89
  277. package/dist/structure/StructureExportPane.svelte.d.ts +1 -1
  278. package/dist/structure/StructureInfoPane.svelte +304 -231
  279. package/dist/structure/StructureScene.svelte +919 -445
  280. package/dist/structure/StructureScene.svelte.d.ts +16 -7
  281. package/dist/structure/atom-properties.d.ts +6 -2
  282. package/dist/structure/atom-properties.js +42 -29
  283. package/dist/structure/bonding.js +6 -7
  284. package/dist/structure/export.js +22 -34
  285. package/dist/structure/ferrox-wasm-types.d.ts +3 -2
  286. package/dist/structure/ferrox-wasm-types.js +0 -3
  287. package/dist/structure/ferrox-wasm.d.ts +3 -2
  288. package/dist/structure/ferrox-wasm.js +2 -3
  289. package/dist/structure/index.d.ts +16 -0
  290. package/dist/structure/index.js +88 -6
  291. package/dist/structure/measure.d.ts +2 -2
  292. package/dist/structure/measure.js +4 -44
  293. package/dist/structure/parse.js +130 -155
  294. package/dist/structure/partial-occupancy.d.ts +25 -0
  295. package/dist/structure/partial-occupancy.js +99 -0
  296. package/dist/structure/pbc.d.ts +1 -0
  297. package/dist/structure/pbc.js +16 -6
  298. package/dist/structure/supercell.d.ts +2 -2
  299. package/dist/structure/supercell.js +12 -22
  300. package/dist/structure/validation.js +5 -3
  301. package/dist/symmetry/SymmetryStats.svelte +94 -37
  302. package/dist/symmetry/WyckoffTable.svelte +42 -14
  303. package/dist/symmetry/cell-transform.js +5 -3
  304. package/dist/symmetry/index.d.ts +7 -4
  305. package/dist/symmetry/index.js +87 -21
  306. package/dist/symmetry/spacegroups.js +148 -148
  307. package/dist/table/HeatmapTable.svelte +1112 -516
  308. package/dist/table/HeatmapTable.svelte.d.ts +12 -1
  309. package/dist/table/ToggleMenu.svelte +125 -90
  310. package/dist/table/index.d.ts +2 -0
  311. package/dist/table/index.js +2 -4
  312. package/dist/theme/ThemeControl.svelte +21 -12
  313. package/dist/time.js +4 -1
  314. package/dist/tooltip/TooltipContent.svelte +33 -8
  315. package/dist/trajectory/Trajectory.svelte +889 -687
  316. package/dist/trajectory/TrajectoryError.svelte +14 -3
  317. package/dist/trajectory/TrajectoryExportPane.svelte +148 -90
  318. package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +1 -1
  319. package/dist/trajectory/TrajectoryInfoPane.svelte +272 -143
  320. package/dist/trajectory/constants.d.ts +6 -0
  321. package/dist/trajectory/constants.js +7 -0
  322. package/dist/trajectory/extract.js +13 -31
  323. package/dist/trajectory/format-detect.d.ts +9 -0
  324. package/dist/trajectory/format-detect.js +76 -0
  325. package/dist/trajectory/frame-reader.d.ts +17 -0
  326. package/dist/trajectory/frame-reader.js +332 -0
  327. package/dist/trajectory/helpers.d.ts +14 -0
  328. package/dist/trajectory/helpers.js +172 -0
  329. package/dist/trajectory/index.d.ts +1 -0
  330. package/dist/trajectory/index.js +23 -14
  331. package/dist/trajectory/parse/ase.d.ts +2 -0
  332. package/dist/trajectory/parse/ase.js +77 -0
  333. package/dist/trajectory/parse/hdf5.d.ts +2 -0
  334. package/dist/trajectory/parse/hdf5.js +129 -0
  335. package/dist/trajectory/parse/index.d.ts +12 -0
  336. package/dist/trajectory/parse/index.js +299 -0
  337. package/dist/trajectory/parse/lammps.d.ts +5 -0
  338. package/dist/trajectory/parse/lammps.js +179 -0
  339. package/dist/trajectory/parse/vasp.d.ts +2 -0
  340. package/dist/trajectory/parse/vasp.js +68 -0
  341. package/dist/trajectory/parse/xyz.d.ts +2 -0
  342. package/dist/trajectory/parse/xyz.js +110 -0
  343. package/dist/trajectory/plotting.js +13 -8
  344. package/dist/trajectory/types.d.ts +11 -0
  345. package/dist/trajectory/types.js +1 -0
  346. package/dist/utils.d.ts +3 -0
  347. package/dist/utils.js +17 -0
  348. package/dist/xrd/XrdPlot.svelte +337 -245
  349. package/dist/xrd/broadening.js +14 -9
  350. package/dist/xrd/calc-xrd.js +12 -19
  351. package/dist/xrd/parse.d.ts +1 -1
  352. package/dist/xrd/parse.js +17 -17
  353. package/package.json +103 -101
  354. package/readme.md +4 -4
  355. package/dist/trajectory/parse.d.ts +0 -42
  356. package/dist/trajectory/parse.js +0 -1267
  357. /package/dist/element/{data.json.d.ts → data.json.gz.d.ts} +0 -0
  358. /package/dist/theme/{themes.js → themes.mjs} +0 -0
@@ -1,306 +1,437 @@
1
- <script lang="ts">import { PLOT_COLORS } from '../colors';
2
- import EmptyState from '../EmptyState.svelte';
3
- import { SettingsSection } from '../layout';
4
- import ScatterPlot from '../plot/ScatterPlot.svelte';
5
- import { tooltip as attach_tooltip } from 'svelte-multiselect/attachments';
6
- import { apply_gaussian_smearing, calculate_sigma_step, convert_frequencies, extract_efermi, extract_pdos, format_dos_tooltip, format_sigma, FREQUENCY_UNITS, IMAGINARY_MODE_NOISE_THRESHOLD, is_valid_range, negative_fraction, NORMALIZATION_MODES, normalize_densities, normalize_dos, SPIN_MODES, validate_sigma_range, } from './helpers';
7
- let { doses, stack = false, sigma = $bindable(0), units = $bindable(`THz`), normalize = $bindable(null), orientation = `vertical`, show_legend = true, x_axis = {}, y_axis = $bindable({}), hovered_frequency = $bindable(null), reference_frequency = null, fermi_level = undefined, spin_mode = $bindable(`mirror`), pdos_type = null, pdos_filter = undefined,
8
- // Controls configuration
9
- show_controls = true, show_sigma_control = true, show_normalize_control = false, show_units_control = false, sigma_range = undefined, ...rest } = $props();
10
- const is_horizontal = $derived(orientation === `horizontal`);
11
- // Normalize input to dict format - converts any DosInput format to DosData
12
- // If pdos_type is set, extract projected DOS from the input instead
13
- let doses_dict = $derived.by(() => {
14
- if (!doses)
15
- return {};
1
+ <script lang="ts">
2
+ import { PLOT_COLORS } from '../colors'
3
+ import EmptyState from '../EmptyState.svelte'
4
+ import { SettingsSection } from '../layout'
5
+ import ScatterPlot from '../plot/ScatterPlot.svelte'
6
+ import type { AxisConfig, DataSeries } from '../plot/types'
7
+ import type { ComponentProps } from 'svelte'
8
+ import { tooltip as attach_tooltip } from 'svelte-multiselect/attachments'
9
+ import {
10
+ apply_gaussian_smearing,
11
+ calculate_sigma_step,
12
+ convert_frequencies,
13
+ extract_efermi,
14
+ extract_pdos,
15
+ format_dos_tooltip,
16
+ format_sigma,
17
+ FREQUENCY_UNITS,
18
+ IMAGINARY_MODE_NOISE_THRESHOLD,
19
+ is_valid_range,
20
+ negative_fraction,
21
+ NORMALIZATION_MODES,
22
+ normalize_densities,
23
+ normalize_dos,
24
+ SPIN_MODES,
25
+ validate_sigma_range,
26
+ } from './helpers'
27
+ import type {
28
+ DosData,
29
+ DosInput,
30
+ FrequencyUnit,
31
+ NormalizationMode,
32
+ PdosType,
33
+ SpinMode,
34
+ StackedAreaData,
35
+ } from './types'
36
+
37
+ let {
38
+ doses,
39
+ stack = false,
40
+ sigma = $bindable(0),
41
+ units = $bindable(`THz`),
42
+ normalize = $bindable(null),
43
+ orientation = `vertical`,
44
+ show_legend = true,
45
+ x_axis = {},
46
+ y_axis = $bindable({}),
47
+ hovered_frequency = $bindable(null),
48
+ reference_frequency = null,
49
+ fermi_level = undefined,
50
+ spin_mode = $bindable(`mirror`),
51
+ pdos_type = null,
52
+ pdos_filter = undefined,
53
+ // Controls configuration
54
+ show_controls = true,
55
+ show_sigma_control = true,
56
+ show_normalize_control = false,
57
+ show_units_control = false,
58
+ sigma_range = undefined,
59
+ ...rest
60
+ }: ComponentProps<typeof ScatterPlot> & {
61
+ doses: DosInput | Record<string, DosInput>
62
+ x_axis?: AxisConfig
63
+ y_axis?: AxisConfig
64
+ stack?: boolean
65
+ sigma?: number
66
+ units?: FrequencyUnit
67
+ normalize?: NormalizationMode
68
+ orientation?: `vertical` | `horizontal`
69
+ show_legend?: boolean
70
+ hovered_frequency?: number | null
71
+ reference_frequency?: number | null
72
+ fermi_level?: number // Fermi level for electronic DOS (auto-detected if not provided)
73
+ spin_mode?: SpinMode // How to display spin-polarized DOS: mirror (default), overlay, up_only, down_only, or null (auto)
74
+ pdos_type?: PdosType | null // Extract projected DOS: 'atom' for atom-resolved, 'orbital' for orbital-resolved (s, p, d)
75
+ pdos_filter?: string[] // Filter projected DOS to specific keys (e.g., ["Fe", "O"] for atoms or ["s", "p", "d"] for orbitals)
76
+ // Controls configuration
77
+ show_controls?: boolean // Show the controls pane
78
+ show_sigma_control?: boolean // Show sigma/smearing control
79
+ show_normalize_control?: boolean // Show normalization selector
80
+ show_units_control?: boolean // Show units selector (phonon DOS only)
81
+ sigma_range?: [number, number] // Min/max range for sigma slider (auto-detected if not provided)
82
+ } = $props()
83
+
84
+ const is_horizontal = $derived(orientation === `horizontal`)
85
+
86
+ // Normalize input to dict format - converts any DosInput format to DosData
87
+ // If pdos_type is set, extract projected DOS from the input instead
88
+ let doses_dict = $derived.by((): Record<string, DosData> => {
89
+ if (!doses) return {}
90
+
16
91
  // If pdos_type is set, try to extract projected DOS
17
92
  if (pdos_type) {
18
- // Try extracting from the doses object directly (single CompleteDos)
19
- const pdos = extract_pdos(doses, pdos_type, pdos_filter);
20
- if (pdos)
21
- return pdos;
22
- // Try extracting from first entry if doses is a dict
23
- if (typeof doses === `object` && !(`densities` in doses)) {
24
- const first_dos = Object.values(doses)[0];
25
- const pdos_from_first = extract_pdos(first_dos, pdos_type, pdos_filter);
26
- if (pdos_from_first)
27
- return pdos_from_first;
28
- }
29
- // PDOS extraction was requested but failed - warn and revert to normal processing
30
- console.warn(`PDOS extraction requested (pdos_type="${pdos_type}") but no projected DOS data found. ` +
31
- `Falling back to total DOS. Ensure input has atom_dos (for atom) or spd_dos (for orbital) data.`);
93
+ // Try extracting from the doses object directly (single CompleteDos)
94
+ const pdos = extract_pdos(doses, pdos_type, pdos_filter)
95
+ if (pdos) return pdos
96
+
97
+ // Try extracting from first entry if doses is a dict
98
+ if (typeof doses === `object` && !(`densities` in doses)) {
99
+ const first_dos = Object.values(doses)[0]
100
+ const pdos_from_first = extract_pdos(first_dos, pdos_type, pdos_filter)
101
+ if (pdos_from_first) return pdos_from_first
102
+ }
103
+ // PDOS extraction was requested but failed - warn and revert to normal processing
104
+ console.warn(
105
+ `PDOS extraction requested (pdos_type="${pdos_type}") but no projected DOS data found. ` +
106
+ `Falling back to total DOS. Ensure input has atom_dos (for atom) or spd_dos (for orbital) data.`,
107
+ )
32
108
  }
109
+
33
110
  if (`densities` in doses && (`frequencies` in doses || `energies` in doses)) {
34
- // Single DOS
35
- const normalized = normalize_dos(doses);
36
- return normalized ? { '': normalized } : {};
111
+ // Single DOS
112
+ const normalized = normalize_dos(doses)
113
+ return normalized ? { '': normalized } : {}
37
114
  }
115
+
38
116
  // Already a dict - normalize each DOS
39
- const result = {};
40
- for (const [key, dos] of Object.entries(doses)) {
41
- const normalized = normalize_dos(dos);
42
- if (normalized)
43
- result[key] = normalized;
44
- }
45
- return result;
46
- });
47
- // Determine if this is phonon or electronic DOS using discriminated union
48
- let is_phonon = $derived(Object.values(doses_dict)[0]?.type === `phonon`);
49
- // Auto-detect Fermi level from electronic DOS data if not explicitly provided
50
- let effective_fermi_level = $derived.by(() => {
51
- if (fermi_level !== undefined)
52
- return fermi_level;
53
- if (is_phonon)
54
- return undefined;
55
- return extract_efermi(doses);
56
- });
57
- // Check if any DOS in the dict has spin-polarized data
58
- let has_spin_polarized = $derived(Object.values(doses_dict).some((dos) => dos.type === `electronic` && dos.spin_down_densities?.length));
59
- // Effective spin mode: null means auto-detect (mirror if spin data exists)
60
- let effective_spin_mode = $derived.by(() => {
61
- if (spin_mode !== null)
62
- return spin_mode;
63
- return has_spin_polarized ? `mirror` : null;
64
- });
65
- // Convert DOS data to scatter plot series and stacked area data
66
- // Performance: Only recalculates when doses_dict, units, sigma, normalize, or spin_mode changes
67
- let { series_data, stacked_areas } = $derived.by(() => {
68
- if (Object.keys(doses_dict).length === 0) {
69
- return { series_data: [], stacked_areas: [] };
117
+ const result: Record<string, DosData> = {}
118
+ for (const [key, dos] of Object.entries(doses as Record<string, DosInput>)) {
119
+ const normalized = normalize_dos(dos)
120
+ if (normalized) result[key] = normalized
70
121
  }
71
- const all_series = [];
72
- const areas = [];
73
- const dos_entries = Object.entries(doses_dict);
74
- // Separate cumulative trackers for spin-up and spin-down in overlay mode
75
- // This prevents spin-down from incorrectly stacking on top of spin-up
76
- let cumulative_spin_up = null;
77
- let cumulative_spin_down = null;
78
- for (let dos_idx = 0; dos_idx < dos_entries.length; dos_idx++) {
79
- const [label, dos] = dos_entries[dos_idx];
80
- const color = PLOT_COLORS[dos_idx % PLOT_COLORS.length];
122
+ return result
123
+ })
124
+
125
+ // Determine if this is phonon or electronic DOS using discriminated union
126
+ let is_phonon = $derived(Object.values(doses_dict)[0]?.type === `phonon`)
127
+
128
+ // Auto-detect Fermi level from electronic DOS data if not explicitly provided
129
+ let effective_fermi_level = $derived.by((): number | undefined => {
130
+ if (fermi_level !== undefined) return fermi_level
131
+ if (is_phonon) return undefined
132
+ return extract_efermi(doses)
133
+ })
134
+
135
+ // Check if any DOS in the dict has spin-polarized data
136
+ let has_spin_polarized = $derived(
137
+ Object.values(doses_dict).some(
138
+ (dos) => dos.type === `electronic` && dos.spin_down_densities?.length,
139
+ ),
140
+ )
141
+
142
+ // Effective spin mode: null means auto-detect (mirror if spin data exists)
143
+ let effective_spin_mode = $derived.by((): SpinMode => {
144
+ if (spin_mode !== null) return spin_mode
145
+ return has_spin_polarized ? `mirror` : null
146
+ })
147
+
148
+ // Convert DOS data to scatter plot series and stacked area data
149
+ // Performance: Only recalculates when doses_dict, units, sigma, normalize, or spin_mode changes
150
+ let { series_data, stacked_areas } = $derived.by(
151
+ (): { series_data: DataSeries[]; stacked_areas: StackedAreaData[] } => {
152
+ if (Object.keys(doses_dict).length === 0) {
153
+ return { series_data: [], stacked_areas: [] }
154
+ }
155
+
156
+ const all_series: DataSeries[] = []
157
+ const areas: StackedAreaData[] = []
158
+ const dos_entries = Object.entries(doses_dict)
159
+ // Separate cumulative trackers for spin-up and spin-down in overlay mode
160
+ // This prevents spin-down from incorrectly stacking on top of spin-up
161
+ let cumulative_spin_up: number[] | null = null
162
+ let cumulative_spin_down: number[] | null = null
163
+
164
+ for (let dos_idx = 0; dos_idx < dos_entries.length; dos_idx++) {
165
+ const [label, dos] = dos_entries[dos_idx]
166
+ const color = PLOT_COLORS[dos_idx % PLOT_COLORS.length]
167
+
81
168
  // Get frequencies or energies using discriminated union type narrowing
82
- let x_values = dos.type === `phonon` ? dos.frequencies : dos.energies;
169
+ let x_values = dos.type === `phonon` ? dos.frequencies : dos.energies
170
+
83
171
  // Convert units if needed
84
172
  if (dos.type === `phonon` && units !== `THz`) {
85
- x_values = convert_frequencies(x_values, units);
173
+ x_values = convert_frequencies(x_values, units)
86
174
  }
175
+
87
176
  // Check for spin-down data (only for electronic DOS)
88
177
  const has_spin_down = dos.type === `electronic` &&
89
- dos.spin_down_densities?.length === dos.densities.length;
90
- const should_show_spin_up = effective_spin_mode !== `down_only`;
178
+ dos.spin_down_densities?.length === dos.densities.length
179
+ const should_show_spin_up = effective_spin_mode !== `down_only`
91
180
  const should_show_spin_down = has_spin_down &&
92
- effective_spin_mode !== `up_only` && effective_spin_mode !== null;
181
+ effective_spin_mode !== `up_only` && effective_spin_mode !== null
182
+
93
183
  // Process spin-up (or total) densities
94
184
  if (should_show_spin_up) {
95
- let densities_up = sigma > 0
96
- ? apply_gaussian_smearing(x_values, dos.densities, sigma)
97
- : [...dos.densities];
98
- densities_up = normalize_densities(densities_up, x_values, normalize);
99
- // Store previous cumulative for area fill baseline
100
- const prev_cumulative = cumulative_spin_up ? [...cumulative_spin_up] : null;
101
- // For stacked plots, accumulate densities (only if array lengths match)
102
- if (stack && cumulative_spin_up?.length === densities_up.length) {
103
- densities_up = densities_up.map((d, idx) => d + cumulative_spin_up[idx]);
104
- }
105
- else if (stack && cumulative_spin_up) {
106
- console.warn(`DOS stacking: length mismatch for "${label}"`);
107
- }
108
- // Store stacked area data for rendering
109
- if (stack) {
110
- areas.push({
111
- x_values: [...x_values],
112
- upper_densities: [...densities_up],
113
- lower_densities: prev_cumulative ?? x_values.map(() => 0),
114
- color,
115
- });
116
- cumulative_spin_up = densities_up;
117
- }
118
- const spin_label = has_spin_down && effective_spin_mode
119
- ? `${label || `DOS ${dos_idx + 1}`} (↑)`
120
- : (label || `DOS ${dos_idx + 1}`);
121
- const series_up = {
122
- x: is_horizontal ? densities_up : x_values,
123
- y: is_horizontal ? x_values : densities_up,
124
- markers: `line`,
125
- label: spin_label,
126
- line_style: { stroke: color, stroke_width: 1.5 },
127
- point_style: { fill: stack ? color : undefined },
128
- };
129
- all_series.push(series_up);
185
+ let densities_up = sigma > 0
186
+ ? apply_gaussian_smearing(x_values, dos.densities, sigma)
187
+ : [...dos.densities]
188
+
189
+ densities_up = normalize_densities(densities_up, x_values, normalize)
190
+
191
+ // Store previous cumulative for area fill baseline
192
+ const prev_cumulative = cumulative_spin_up ? [...cumulative_spin_up] : null
193
+
194
+ // For stacked plots, accumulate densities (only if array lengths match)
195
+ if (stack && cumulative_spin_up?.length === densities_up.length) {
196
+ densities_up = densities_up.map((density, idx) =>
197
+ density + (cumulative_spin_up?.[idx] ?? 0)
198
+ )
199
+ } else if (stack && cumulative_spin_up) {
200
+ console.warn(`DOS stacking: length mismatch for "${label}"`)
201
+ }
202
+
203
+ // Store stacked area data for rendering
204
+ if (stack) {
205
+ areas.push({
206
+ x_values: [...x_values],
207
+ upper_densities: [...densities_up],
208
+ lower_densities: prev_cumulative ?? x_values.map(() => 0),
209
+ color,
210
+ })
211
+ cumulative_spin_up = densities_up
212
+ }
213
+
214
+ const spin_label = has_spin_down && effective_spin_mode
215
+ ? `${label || `DOS ${dos_idx + 1}`} (↑)`
216
+ : (label || `DOS ${dos_idx + 1}`)
217
+
218
+ const series_up: DataSeries = {
219
+ x: is_horizontal ? densities_up : x_values,
220
+ y: is_horizontal ? x_values : densities_up,
221
+ markers: `line`,
222
+ label: spin_label,
223
+ line_style: { stroke: color, stroke_width: 1.5 },
224
+ point_style: { fill: stack ? color : undefined },
225
+ }
226
+ all_series.push(series_up)
130
227
  }
228
+
131
229
  // Process spin-down densities if available
132
- if (should_show_spin_down && dos.type === `electronic` &&
133
- dos.spin_down_densities) {
134
- let densities_down = sigma > 0
135
- ? apply_gaussian_smearing(x_values, dos.spin_down_densities, sigma)
136
- : [...dos.spin_down_densities];
137
- densities_down = normalize_densities(densities_down, x_values, normalize);
138
- // For mirror mode, negate the densities
139
- if (effective_spin_mode === `mirror`) {
140
- densities_down = densities_down.map((d) => -d);
141
- }
142
- // For stacked plots with overlay mode, use separate spin-down cumulative
143
- // This prevents spin-down from stacking on top of spin-up within the same DOS
144
- if (stack && effective_spin_mode === `overlay`) {
145
- const prev_spin_down = cumulative_spin_down
146
- ? [...cumulative_spin_down]
147
- : null;
148
- if (cumulative_spin_down?.length === densities_down.length) {
149
- densities_down = densities_down.map((d, idx) => d + cumulative_spin_down[idx]);
150
- }
151
- else if (cumulative_spin_down) {
152
- console.warn(`DOS stacking (spin-down): length mismatch for "${label}"`);
153
- }
154
- // Store stacked area for spin-down
155
- areas.push({
156
- x_values: [...x_values],
157
- upper_densities: [...densities_down],
158
- lower_densities: prev_spin_down ?? x_values.map(() => 0),
159
- color: PLOT_COLORS[(dos_idx * 2 + 1) % PLOT_COLORS.length],
160
- });
161
- cumulative_spin_down = densities_down;
230
+ if (
231
+ should_show_spin_down && dos.type === `electronic` &&
232
+ dos.spin_down_densities
233
+ ) {
234
+ let densities_down = sigma > 0
235
+ ? apply_gaussian_smearing(x_values, dos.spin_down_densities, sigma)
236
+ : [...dos.spin_down_densities]
237
+
238
+ densities_down = normalize_densities(densities_down, x_values, normalize)
239
+
240
+ // For mirror mode, negate the densities
241
+ if (effective_spin_mode === `mirror`) {
242
+ densities_down = densities_down.map((d) => -d)
243
+ }
244
+
245
+ // For stacked plots with overlay mode, use separate spin-down cumulative
246
+ // This prevents spin-down from stacking on top of spin-up within the same DOS
247
+ if (stack && effective_spin_mode === `overlay`) {
248
+ const prev_spin_down = cumulative_spin_down
249
+ ? [...cumulative_spin_down]
250
+ : null
251
+ if (cumulative_spin_down?.length === densities_down.length) {
252
+ densities_down = densities_down.map((density, idx) =>
253
+ density + (cumulative_spin_down?.[idx] ?? 0)
254
+ )
255
+ } else if (cumulative_spin_down) {
256
+ console.warn(`DOS stacking (spin-down): length mismatch for "${label}"`)
162
257
  }
163
- // Use a slightly different shade for spin-down in overlay mode
164
- const spin_down_color = effective_spin_mode === `overlay`
165
- ? PLOT_COLORS[(dos_idx * 2 + 1) % PLOT_COLORS.length]
166
- : color;
167
- const series_down = {
168
- x: is_horizontal ? densities_down : x_values,
169
- y: is_horizontal ? x_values : densities_down,
170
- markers: `line`,
171
- label: `${label || `DOS ${dos_idx + 1}`} (↓)`,
172
- line_style: {
173
- stroke: spin_down_color,
174
- stroke_width: 1.5,
175
- line_dash: effective_spin_mode === `overlay` ? `4,2` : undefined,
176
- },
177
- point_style: { fill: stack ? spin_down_color : undefined },
178
- };
179
- all_series.push(series_down);
258
+
259
+ // Store stacked area for spin-down
260
+ areas.push({
261
+ x_values: [...x_values],
262
+ upper_densities: [...densities_down],
263
+ lower_densities: prev_spin_down ?? x_values.map(() => 0),
264
+ color: PLOT_COLORS[(dos_idx * 2 + 1) % PLOT_COLORS.length],
265
+ })
266
+ cumulative_spin_down = densities_down
267
+ }
268
+
269
+ // Use a slightly different shade for spin-down in overlay mode
270
+ const spin_down_color = effective_spin_mode === `overlay`
271
+ ? PLOT_COLORS[(dos_idx * 2 + 1) % PLOT_COLORS.length]
272
+ : color
273
+
274
+ const series_down: DataSeries = {
275
+ x: is_horizontal ? densities_down : x_values,
276
+ y: is_horizontal ? x_values : densities_down,
277
+ markers: `line`,
278
+ label: `${label || `DOS ${dos_idx + 1}`} (↓)`,
279
+ line_style: {
280
+ stroke: spin_down_color,
281
+ stroke_width: 1.5,
282
+ line_dash: effective_spin_mode === `overlay` ? `4,2` : undefined,
283
+ },
284
+ point_style: { fill: stack ? spin_down_color : undefined },
285
+ }
286
+ all_series.push(series_down)
180
287
  }
181
- }
182
- return { series_data: all_series, stacked_areas: areas };
183
- });
184
- let all_freqs = $derived(// for clamping phonon noise
185
- Object.values(doses_dict).flatMap((dos) => dos.type === `phonon` ? dos.frequencies : dos.energies));
186
- let clamp_to_zero = $derived(is_phonon &&
187
- all_freqs.length > 0 &&
188
- Math.min(...all_freqs) < 0 &&
189
- negative_fraction(all_freqs) < IMAGINARY_MODE_NOISE_THRESHOLD);
190
- // Check if we have mirrored spin-down data (negative densities)
191
- let has_mirrored_spin = $derived(effective_spin_mode === `mirror` && has_spin_polarized);
192
- let x_range = $derived.by(() => {
193
- if (!series_data.length)
194
- return undefined;
195
- const all_x = series_data.flatMap((srs) => srs.x);
196
- const min_x = Math.min(...all_x), max_x = Math.max(...all_x);
288
+ }
289
+ return { series_data: all_series, stacked_areas: areas }
290
+ },
291
+ )
292
+
293
+ let all_freqs = $derived( // for clamping phonon noise
294
+ Object.values(doses_dict).flatMap((dos) =>
295
+ dos.type === `phonon` ? dos.frequencies : dos.energies
296
+ ),
297
+ )
298
+ let clamp_to_zero = $derived(
299
+ is_phonon &&
300
+ all_freqs.length > 0 &&
301
+ Math.min(...all_freqs) < 0 &&
302
+ negative_fraction(all_freqs) < IMAGINARY_MODE_NOISE_THRESHOLD,
303
+ )
304
+
305
+ // Check if we have mirrored spin-down data (negative densities)
306
+ let has_mirrored_spin = $derived(
307
+ effective_spin_mode === `mirror` && has_spin_polarized,
308
+ )
309
+
310
+ let x_range = $derived.by((): [number, number] | undefined => {
311
+ if (!series_data.length) return undefined
312
+ const all_x = series_data.flatMap((srs) => srs.x)
313
+ const min_x = Math.min(...all_x), max_x = Math.max(...all_x)
197
314
  // For horizontal orientation with mirror mode, allow negative values (mirrored densities)
198
- if (is_horizontal && has_mirrored_spin)
199
- return [min_x, max_x];
200
- if (is_horizontal || clamp_to_zero)
201
- return [0, max_x];
202
- return [min_x, max_x];
203
- });
204
- let y_range = $derived.by(() => {
205
- if (!series_data.length)
206
- return undefined;
207
- const all_y = series_data.flatMap((srs) => srs.y);
208
- const min_y = Math.min(...all_y), max_y = Math.max(...all_y);
315
+ if (is_horizontal && has_mirrored_spin) return [min_x, max_x]
316
+ if (is_horizontal || clamp_to_zero) return [0, max_x]
317
+ return [min_x, max_x]
318
+ })
319
+
320
+ let y_range = $derived.by((): [number, number] | undefined => {
321
+ if (!series_data.length) return undefined
322
+ const all_y = series_data.flatMap((srs) => srs.y)
323
+ const min_y = Math.min(...all_y), max_y = Math.max(...all_y)
209
324
  // For vertical orientation with mirror mode, allow negative values (mirrored densities)
210
- if (!is_horizontal && has_mirrored_spin)
211
- return [min_y, max_y];
212
- if (!is_horizontal || clamp_to_zero)
213
- return [0, max_y];
214
- return [min_y, max_y];
215
- });
216
- // Get axis labels based on orientation
217
- let x_label = $derived(is_horizontal
218
- ? `Density of States`
219
- : is_phonon
220
- ? `Frequency (${units})`
221
- : `Energy (eV)`);
222
- let y_label = $derived(is_horizontal
223
- ? (is_phonon ? `Frequency (${units})` : `Energy (eV)`)
224
- : `Density of States`);
225
- // Compute final axis configurations with default labels
226
- let final_x_axis = $derived({
325
+ if (!is_horizontal && has_mirrored_spin) return [min_y, max_y]
326
+ if (!is_horizontal || clamp_to_zero) return [0, max_y]
327
+ return [min_y, max_y]
328
+ })
329
+
330
+ // Get axis labels based on orientation
331
+ let x_label = $derived(
332
+ is_horizontal
333
+ ? `Density of States`
334
+ : is_phonon
335
+ ? `Frequency (${units})`
336
+ : `Energy (eV)`,
337
+ )
338
+ let y_label = $derived(
339
+ is_horizontal
340
+ ? (is_phonon ? `Frequency (${units})` : `Energy (eV)`)
341
+ : `Density of States`,
342
+ )
343
+
344
+ // Compute final axis configurations with default labels
345
+ let final_x_axis = $derived({
227
346
  label: x_label,
228
347
  format: `.2f`,
229
348
  range: x_range,
230
349
  label_shift: { x: 0, y: -48 }, // Increase standoff from tick labels
231
350
  ...(is_horizontal && { ticks: 4 }),
232
351
  ...x_axis,
233
- });
234
- // Internal y_axis that ScatterPlot binds to - syncs zoom changes back to parent
235
- let internal_y_axis = $derived({
352
+ })
353
+ // Internal y_axis that ScatterPlot binds to - syncs zoom changes back to parent
354
+ let internal_y_axis = $derived({
236
355
  label: y_label,
237
356
  format: `.2f`,
238
357
  range: y_range,
239
358
  ...y_axis,
240
- });
241
- // Sync zoom changes from ScatterPlot back to parent via bindable y_axis
242
- // Also clears parent range when internal range becomes invalid (auto-range reset)
243
- $effect(() => {
244
- const range = internal_y_axis.range;
359
+ })
360
+
361
+ // Sync zoom changes from ScatterPlot back to parent via bindable y_axis
362
+ // Also clears parent range when internal range becomes invalid (auto-range reset)
363
+ $effect(() => {
364
+ const range = internal_y_axis.range
245
365
  if (is_valid_range(range)) {
246
- if (y_axis.range?.[0] !== range[0] || y_axis.range?.[1] !== range[1]) {
247
- y_axis = { ...y_axis, range };
248
- }
249
- return;
366
+ if (y_axis.range?.[0] !== range[0] || y_axis.range?.[1] !== range[1]) {
367
+ y_axis = { ...y_axis, range }
368
+ }
369
+ return
250
370
  }
251
371
  // Range became invalid - clear parent's range to propagate reset
252
372
  if (`range` in y_axis) {
253
- const { range: _omit, ...rest } = y_axis;
254
- y_axis = rest;
373
+ const { range: _omit, ...rest } = y_axis
374
+ y_axis = rest
255
375
  }
256
- });
257
- let display = $state({
376
+ })
377
+
378
+ let display = $state({
258
379
  x_grid: true,
259
380
  y_grid: true,
260
381
  x_zero_line: true,
261
382
  y_zero_line: true,
262
- });
263
- // Determine if we have valid data to display
264
- let has_valid_data = $derived(series_data.length > 0);
265
- // Auto-detect sigma range based on frequency/energy range
266
- let effective_sigma_range = $derived.by(() => {
267
- if (sigma_range)
268
- return sigma_range;
269
- if (!all_freqs.length)
270
- return [0, 1];
271
- const freq_range = Math.max(...all_freqs) - Math.min(...all_freqs);
383
+ })
384
+
385
+ // Determine if we have valid data to display
386
+ let has_valid_data = $derived(series_data.length > 0)
387
+
388
+ // Auto-detect sigma range based on frequency/energy range
389
+ let effective_sigma_range = $derived.by((): [number, number] => {
390
+ if (sigma_range) return sigma_range
391
+ if (!all_freqs.length) return [0, 1]
392
+ const freq_range = Math.max(...all_freqs) - Math.min(...all_freqs)
272
393
  // Reasonable sigma range: 0 to ~5% of total range
273
- const max_sigma = Math.max(0.1, freq_range * 0.05);
274
- return [0, max_sigma];
275
- });
276
- // Computed values for sigma slider
277
- let safe_sigma_range = $derived(validate_sigma_range(effective_sigma_range));
278
- let sigma_step = $derived(calculate_sigma_step(effective_sigma_range));
279
- // Build SVG path for stacked area fill between upper and lower density curves
280
- function build_stacked_area_path(area, x_scale_fn, y_scale_fn, horizontal) {
281
- const pts = area.x_values.length;
282
- if (pts < 2)
283
- return ``;
284
- const upper_coords = [];
285
- const lower_coords = [];
394
+ const max_sigma = Math.max(0.1, freq_range * 0.05)
395
+ return [0, max_sigma]
396
+ })
397
+
398
+ // Computed values for sigma slider
399
+ let safe_sigma_range = $derived(validate_sigma_range(effective_sigma_range))
400
+ let sigma_step = $derived(calculate_sigma_step(effective_sigma_range))
401
+
402
+ // Build SVG path for stacked area fill between upper and lower density curves
403
+ function build_stacked_area_path(
404
+ area: StackedAreaData,
405
+ x_scale_fn: (val: number) => number,
406
+ y_scale_fn: (val: number) => number,
407
+ horizontal: boolean,
408
+ ): string {
409
+ const pts = area.x_values.length
410
+ if (pts < 2) return ``
411
+
412
+ const upper_coords: string[] = []
413
+ const lower_coords: string[] = []
414
+
286
415
  for (let idx = 0; idx < pts; idx++) {
287
- const freq = area.x_values[idx];
288
- const upper_dens = area.upper_densities[idx];
289
- const lower_dens = area.lower_densities[idx];
290
- // For vertical orientation: x = freq, y = density
291
- // For horizontal orientation: x = density, y = freq
292
- const [upper_x, upper_y] = horizontal
293
- ? [x_scale_fn(upper_dens), y_scale_fn(freq)]
294
- : [x_scale_fn(freq), y_scale_fn(upper_dens)];
295
- const [lower_x, lower_y] = horizontal
296
- ? [x_scale_fn(lower_dens), y_scale_fn(freq)]
297
- : [x_scale_fn(freq), y_scale_fn(lower_dens)];
298
- upper_coords.push(`${upper_x.toFixed(2)},${upper_y.toFixed(2)}`);
299
- lower_coords.push(`${lower_x.toFixed(2)},${lower_y.toFixed(2)}`);
416
+ const freq = area.x_values[idx]
417
+ const upper_dens = area.upper_densities[idx]
418
+ const lower_dens = area.lower_densities[idx]
419
+ // For vertical orientation: x = freq, y = density
420
+ // For horizontal orientation: x = density, y = freq
421
+ const [upper_x, upper_y] = horizontal
422
+ ? [x_scale_fn(upper_dens), y_scale_fn(freq)]
423
+ : [x_scale_fn(freq), y_scale_fn(upper_dens)]
424
+ const [lower_x, lower_y] = horizontal
425
+ ? [x_scale_fn(lower_dens), y_scale_fn(freq)]
426
+ : [x_scale_fn(freq), y_scale_fn(lower_dens)]
427
+ upper_coords.push(`${upper_x.toFixed(2)},${upper_y.toFixed(2)}`)
428
+ lower_coords.push(`${lower_x.toFixed(2)},${lower_y.toFixed(2)}`)
300
429
  }
301
430
  // Trace upper edge forward, lower edge backward, close path
302
- return `M${upper_coords[0]} ${upper_coords.slice(1).map((coord) => `L${coord}`).join(` `)} ${lower_coords.toReversed().map((coord) => `L${coord}`).join(` `)} Z`;
303
- }
431
+ return `M${upper_coords[0]} ${
432
+ upper_coords.slice(1).map((coord) => `L${coord}`).join(` `)
433
+ } ${lower_coords.toReversed().map((coord) => `L${coord}`).join(` `)} Z`
434
+ }
304
435
  </script>
305
436
 
306
437
  {#if has_valid_data}