matterviz 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (527) hide show
  1. package/dist/EmptyState.svelte +10 -4
  2. package/dist/FilePicker.svelte +12 -14
  3. package/dist/Icon.svelte +7 -4
  4. package/dist/MillerIndexInput.svelte +2 -2
  5. package/dist/app.css +53 -0
  6. package/dist/brillouin/BrillouinZone.svelte +132 -219
  7. package/dist/brillouin/BrillouinZone.svelte.d.ts +9 -20
  8. package/dist/brillouin/BrillouinZoneControls.svelte +3 -6
  9. package/dist/brillouin/BrillouinZoneExportPane.svelte +47 -96
  10. package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +1 -1
  11. package/dist/brillouin/BrillouinZoneInfoPane.svelte +15 -42
  12. package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +2 -3
  13. package/dist/brillouin/BrillouinZoneScene.svelte +63 -230
  14. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +3 -23
  15. package/dist/brillouin/ReciprocalVectors.svelte +39 -0
  16. package/dist/brillouin/ReciprocalVectors.svelte.d.ts +9 -0
  17. package/dist/brillouin/compute.d.ts +2 -0
  18. package/dist/brillouin/compute.js +80 -77
  19. package/dist/brillouin/geometry.d.ts +8 -0
  20. package/dist/brillouin/geometry.js +57 -0
  21. package/dist/brillouin/index.d.ts +2 -0
  22. package/dist/brillouin/index.js +2 -0
  23. package/dist/brillouin/types.d.ts +2 -2
  24. package/dist/chempot-diagram/ChemPotDiagram.svelte +33 -38
  25. package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +1 -1
  26. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +143 -246
  27. package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +4 -1
  28. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +652 -976
  29. package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +7 -1
  30. package/dist/chempot-diagram/async-compute.svelte.js +1 -1
  31. package/dist/chempot-diagram/color.d.ts +3 -6
  32. package/dist/chempot-diagram/color.js +5 -5
  33. package/dist/chempot-diagram/compute.d.ts +3 -3
  34. package/dist/chempot-diagram/compute.js +3 -1
  35. package/dist/chempot-diagram/controls-state.svelte.d.ts +10 -0
  36. package/dist/chempot-diagram/controls-state.svelte.js +42 -0
  37. package/dist/chempot-diagram/export.d.ts +47 -0
  38. package/dist/chempot-diagram/export.js +133 -0
  39. package/dist/chempot-diagram/index.d.ts +1 -0
  40. package/dist/chempot-diagram/index.js +1 -0
  41. package/dist/chempot-diagram/pointer.d.ts +0 -10
  42. package/dist/chempot-diagram/pointer.js +4 -4
  43. package/dist/chempot-diagram/types.d.ts +3 -3
  44. package/dist/colors/index.d.ts +0 -4
  45. package/dist/colors/index.js +21 -22
  46. package/dist/composition/BarChart.svelte +37 -31
  47. package/dist/composition/BubbleChart.svelte +17 -17
  48. package/dist/composition/Composition.svelte +7 -11
  49. package/dist/composition/Formula.svelte +18 -25
  50. package/dist/composition/FormulaFilter.svelte +96 -98
  51. package/dist/composition/PieChart.svelte +60 -46
  52. package/dist/composition/chem-sys.js +3 -2
  53. package/dist/composition/format.js +4 -3
  54. package/dist/composition/index.d.ts +2 -0
  55. package/dist/composition/index.js +14 -0
  56. package/dist/composition/parse.d.ts +2 -3
  57. package/dist/composition/parse.js +27 -28
  58. package/dist/constants.js +11 -9
  59. package/dist/controls.d.ts +1 -0
  60. package/dist/controls.js +0 -1
  61. package/dist/convex-hull/ConvexHull.svelte +20 -25
  62. package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -4
  63. package/dist/convex-hull/ConvexHull2D.svelte +176 -256
  64. package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
  65. package/dist/convex-hull/ConvexHull3D.svelte +269 -804
  66. package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
  67. package/dist/convex-hull/ConvexHull4D.svelte +236 -755
  68. package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
  69. package/dist/convex-hull/ConvexHullChrome.svelte +264 -0
  70. package/dist/convex-hull/ConvexHullChrome.svelte.d.ts +30 -0
  71. package/dist/convex-hull/ConvexHullControls.svelte +128 -49
  72. package/dist/convex-hull/ConvexHullControls.svelte.d.ts +7 -6
  73. package/dist/convex-hull/ConvexHullInfoPane.svelte +18 -5
  74. package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +6 -5
  75. package/dist/convex-hull/ConvexHullStats.svelte +210 -351
  76. package/dist/convex-hull/ConvexHullStats.svelte.d.ts +3 -1
  77. package/dist/convex-hull/ConvexHullTooltip.svelte +16 -14
  78. package/dist/convex-hull/ConvexHullTooltip.svelte.d.ts +2 -1
  79. package/dist/convex-hull/GasPressureControls.svelte +5 -12
  80. package/dist/convex-hull/StructurePopup.svelte +17 -21
  81. package/dist/convex-hull/StructurePopup.svelte.d.ts +2 -0
  82. package/dist/convex-hull/TemperatureSlider.svelte +4 -10
  83. package/dist/convex-hull/barycentric-coords.d.ts +2 -4
  84. package/dist/convex-hull/barycentric-coords.js +6 -33
  85. package/dist/convex-hull/canvas-interactions.svelte.d.ts +79 -0
  86. package/dist/convex-hull/canvas-interactions.svelte.js +279 -0
  87. package/dist/convex-hull/helpers.d.ts +47 -17
  88. package/dist/convex-hull/helpers.js +186 -101
  89. package/dist/convex-hull/hull-state.svelte.d.ts +44 -0
  90. package/dist/convex-hull/hull-state.svelte.js +124 -0
  91. package/dist/convex-hull/index.d.ts +9 -7
  92. package/dist/convex-hull/index.js +7 -2
  93. package/dist/convex-hull/thermodynamics.js +109 -937
  94. package/dist/convex-hull/types.d.ts +12 -4
  95. package/dist/convex-hull/types.js +12 -0
  96. package/dist/coordination/CoordinationBarPlot.svelte +41 -43
  97. package/dist/coordination/CoordinationBarPlot.svelte.d.ts +1 -1
  98. package/dist/coordination/calc-coordination.d.ts +1 -1
  99. package/dist/coordination/calc-coordination.js +28 -25
  100. package/dist/element/BohrAtom.svelte +6 -8
  101. package/dist/element/ElementHeading.svelte +4 -1
  102. package/dist/element/ElementPhoto.svelte +11 -9
  103. package/dist/element/ElementStats.svelte +12 -10
  104. package/dist/element/ElementTile.svelte +24 -29
  105. package/dist/element/ElementTile.svelte.d.ts +1 -1
  106. package/dist/element/Nucleus.svelte +4 -2
  107. package/dist/element/data.d.ts +1 -2
  108. package/dist/element/helpers.d.ts +4 -0
  109. package/dist/element/helpers.js +18 -0
  110. package/dist/element/index.d.ts +1 -0
  111. package/dist/element/index.js +3 -0
  112. package/dist/feedback/DragOverlay.svelte +5 -3
  113. package/dist/feedback/DragOverlay.svelte.d.ts +2 -1
  114. package/dist/feedback/StatusMessage.svelte +20 -7
  115. package/dist/fermi-surface/FermiSlice.svelte +21 -18
  116. package/dist/fermi-surface/FermiSurface.svelte +78 -165
  117. package/dist/fermi-surface/FermiSurface.svelte.d.ts +9 -20
  118. package/dist/fermi-surface/FermiSurfaceControls.svelte +6 -20
  119. package/dist/fermi-surface/FermiSurfaceScene.svelte +93 -272
  120. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +3 -23
  121. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +9 -6
  122. package/dist/fermi-surface/compute.js +14 -13
  123. package/dist/fermi-surface/export.js +4 -15
  124. package/dist/fermi-surface/index.d.ts +0 -1
  125. package/dist/fermi-surface/index.js +0 -1
  126. package/dist/fermi-surface/parse.d.ts +1 -1
  127. package/dist/fermi-surface/parse.js +84 -97
  128. package/dist/fermi-surface/types.d.ts +2 -2
  129. package/dist/heatmap-matrix/HeatmapMatrix.svelte +161 -185
  130. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +6 -5
  131. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +12 -9
  132. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +5 -5
  133. package/dist/heatmap-matrix/index.d.ts +8 -2
  134. package/dist/icons.d.ts +4 -0
  135. package/dist/icons.js +4 -0
  136. package/dist/index.d.ts +1 -0
  137. package/dist/index.js +1 -0
  138. package/dist/io/ExportPane.svelte +170 -0
  139. package/dist/io/ExportPane.svelte.d.ts +17 -0
  140. package/dist/io/decompress.d.ts +2 -1
  141. package/dist/io/decompress.js +22 -36
  142. package/dist/io/export.d.ts +9 -1
  143. package/dist/io/export.js +37 -29
  144. package/dist/io/fetch.d.ts +2 -4
  145. package/dist/io/fetch.js +0 -11
  146. package/dist/io/file-drop.d.ts +7 -0
  147. package/dist/io/file-drop.js +13 -0
  148. package/dist/io/index.d.ts +1 -0
  149. package/dist/io/index.js +3 -0
  150. package/dist/io/is-binary.d.ts +9 -0
  151. package/dist/io/is-binary.js +45 -1
  152. package/dist/io/types.d.ts +13 -0
  153. package/dist/io/url-drop.js +13 -25
  154. package/dist/isosurface/Isosurface.svelte +17 -23
  155. package/dist/isosurface/IsosurfaceControls.svelte +37 -42
  156. package/dist/isosurface/parse-vaspwave.d.ts +3 -0
  157. package/dist/isosurface/parse-vaspwave.js +138 -0
  158. package/dist/isosurface/parse.js +50 -48
  159. package/dist/labels.d.ts +6 -2
  160. package/dist/labels.js +44 -14
  161. package/dist/layout/FullscreenButton.svelte +34 -0
  162. package/dist/layout/FullscreenButton.svelte.d.ts +10 -0
  163. package/dist/layout/FullscreenToggle.svelte +12 -12
  164. package/dist/layout/InfoCard.svelte +7 -18
  165. package/dist/layout/InfoTag.svelte +1 -3
  166. package/dist/layout/NumberRangeInput.svelte +46 -0
  167. package/dist/layout/NumberRangeInput.svelte.d.ts +12 -0
  168. package/dist/layout/PropertyFilter.svelte +2 -6
  169. package/dist/layout/SettingsSection.svelte +21 -17
  170. package/dist/layout/SubpageGrid.svelte +3 -1
  171. package/dist/layout/ViewerChrome.svelte +115 -0
  172. package/dist/layout/ViewerChrome.svelte.d.ts +18 -0
  173. package/dist/layout/fullscreen.d.ts +4 -0
  174. package/dist/layout/fullscreen.js +3 -5
  175. package/dist/layout/fullscreen.svelte.d.ts +8 -0
  176. package/dist/layout/fullscreen.svelte.js +36 -0
  177. package/dist/layout/index.d.ts +4 -0
  178. package/dist/layout/index.js +4 -0
  179. package/dist/layout/json-tree/JsonNode.svelte +8 -11
  180. package/dist/layout/json-tree/JsonTree.svelte +53 -77
  181. package/dist/layout/json-tree/JsonValue.svelte +7 -15
  182. package/dist/layout/json-tree/utils.js +14 -23
  183. package/dist/math.d.ts +9 -3
  184. package/dist/math.js +37 -21
  185. package/dist/overlays/ContextMenu.svelte +4 -2
  186. package/dist/overlays/CopyButton.svelte +11 -5
  187. package/dist/overlays/DragControlTab.svelte +6 -1
  188. package/dist/overlays/DraggablePane.svelte +81 -26
  189. package/dist/overlays/DraggablePane.svelte.d.ts +1 -0
  190. package/dist/overlays/GlassChip.svelte +30 -0
  191. package/dist/overlays/GlassChip.svelte.d.ts +8 -0
  192. package/dist/overlays/InfoPaneCards.svelte +11 -23
  193. package/dist/overlays/index.d.ts +11 -0
  194. package/dist/overlays/index.js +26 -0
  195. package/dist/overlays/portal.d.ts +2 -0
  196. package/dist/overlays/portal.js +14 -0
  197. package/dist/periodic-table/PeriodicTable.svelte +115 -146
  198. package/dist/periodic-table/PeriodicTable.svelte.d.ts +5 -3
  199. package/dist/periodic-table/PeriodicTableControls.svelte +11 -63
  200. package/dist/periodic-table/TableInset.svelte +9 -4
  201. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +50 -71
  202. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -8
  203. package/dist/phase-diagram/PhaseDiagramControls.svelte +73 -96
  204. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +4 -3
  205. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +4 -2
  206. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +2 -3
  207. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +49 -134
  208. package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +3 -4
  209. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +54 -58
  210. package/dist/phase-diagram/TdbInfoPanel.svelte +21 -15
  211. package/dist/phase-diagram/build-diagram.js +3 -3
  212. package/dist/phase-diagram/colors.js +1 -1
  213. package/dist/phase-diagram/diagram-input.d.ts +1 -2
  214. package/dist/phase-diagram/parse.d.ts +2 -1
  215. package/dist/phase-diagram/parse.js +15 -15
  216. package/dist/phase-diagram/svg-to-diagram.js +21 -15
  217. package/dist/phase-diagram/utils.js +2 -3
  218. package/dist/plot/bar/BarPlot.svelte +494 -692
  219. package/dist/plot/bar/BarPlot.svelte.d.ts +9 -15
  220. package/dist/plot/bar/BarPlotControls.svelte +1 -3
  221. package/dist/plot/bar/BarPlotControls.svelte.d.ts +5 -7
  222. package/dist/plot/bar/SpacegroupBarPlot.svelte +31 -37
  223. package/dist/plot/bar/data.d.ts +5 -4
  224. package/dist/plot/bar/data.js +2 -1
  225. package/dist/plot/box/BoxPlot.svelte +361 -439
  226. package/dist/plot/box/BoxPlot.svelte.d.ts +6 -3
  227. package/dist/plot/box/BoxPlotControls.svelte.d.ts +1 -1
  228. package/dist/plot/box/Violin.svelte.d.ts +2 -1
  229. package/dist/plot/box/box-plot.d.ts +3 -2
  230. package/dist/plot/box/box-plot.js +6 -3
  231. package/dist/plot/box/kde.d.ts +2 -1
  232. package/dist/plot/box/kde.js +4 -4
  233. package/dist/plot/core/auto-place.d.ts +1 -1
  234. package/dist/plot/core/auto-place.js +5 -2
  235. package/dist/plot/core/axis-utils.d.ts +12 -7
  236. package/dist/plot/core/axis-utils.js +48 -48
  237. package/dist/plot/core/components/AxisLabel.svelte +82 -20
  238. package/dist/plot/core/components/AxisLabel.svelte.d.ts +1 -0
  239. package/dist/plot/core/components/ColorBar.svelte +106 -111
  240. package/dist/plot/core/components/ColorBar.svelte.d.ts +5 -4
  241. package/dist/plot/core/components/ColorScaleSelect.svelte +1 -1
  242. package/dist/plot/core/components/FillArea.svelte +10 -17
  243. package/dist/plot/core/components/HierarchyControls.svelte +249 -0
  244. package/dist/plot/{sunburst/SunburstControls.svelte.d.ts → core/components/HierarchyControls.svelte.d.ts} +12 -8
  245. package/dist/plot/core/components/InteractiveAxisLabel.svelte +1 -1
  246. package/dist/plot/core/components/InteractiveAxisLabel.svelte.d.ts +1 -1
  247. package/dist/plot/core/components/Line.svelte +21 -11
  248. package/dist/plot/core/components/Line.svelte.d.ts +5 -2
  249. package/dist/plot/core/components/PlotAxis.svelte +42 -18
  250. package/dist/plot/core/components/PlotAxis.svelte.d.ts +2 -1
  251. package/dist/plot/core/components/PlotControls.svelte +65 -41
  252. package/dist/plot/core/components/PlotControls.svelte.d.ts +1 -1
  253. package/dist/plot/core/components/PlotLegend.svelte +31 -35
  254. package/dist/plot/core/components/PlotMarginals.svelte +616 -0
  255. package/dist/plot/core/components/PlotMarginals.svelte.d.ts +15 -0
  256. package/dist/plot/core/components/PlotTooltip.svelte +1 -1
  257. package/dist/plot/core/components/PortalSelect.svelte +4 -8
  258. package/dist/plot/core/components/ReferenceLine.svelte +27 -24
  259. package/dist/plot/core/components/ReferenceLine3D.svelte +56 -59
  260. package/dist/plot/core/components/ReferenceLine3D.svelte.d.ts +4 -4
  261. package/dist/plot/core/components/ReferencePlane.svelte +9 -10
  262. package/dist/plot/core/components/ReferencePlane.svelte.d.ts +4 -4
  263. package/dist/plot/core/components/ZeroLines.svelte +4 -8
  264. package/dist/plot/core/components/ZoomRect.svelte +1 -2
  265. package/dist/plot/core/components/index.d.ts +1 -0
  266. package/dist/plot/core/components/index.js +1 -0
  267. package/dist/plot/core/data-cleaning-signal.d.ts +46 -0
  268. package/dist/plot/core/data-cleaning-signal.js +467 -0
  269. package/dist/plot/core/data-cleaning.d.ts +2 -42
  270. package/dist/plot/core/data-cleaning.js +29 -476
  271. package/dist/plot/core/data-transform.js +9 -5
  272. package/dist/plot/core/fill-utils.d.ts +7 -4
  273. package/dist/plot/core/fill-utils.js +34 -9
  274. package/dist/plot/core/index.d.ts +1 -0
  275. package/dist/plot/core/index.js +1 -0
  276. package/dist/plot/core/interactions.d.ts +5 -1
  277. package/dist/plot/core/interactions.js +14 -2
  278. package/dist/plot/core/layout.d.ts +3 -1
  279. package/dist/plot/core/layout.js +22 -13
  280. package/dist/plot/core/marginals.d.ts +170 -0
  281. package/dist/plot/core/marginals.js +436 -0
  282. package/dist/plot/core/pan-zoom.svelte.d.ts +35 -0
  283. package/dist/plot/core/pan-zoom.svelte.js +221 -0
  284. package/dist/plot/core/placed-tween.svelte.d.ts +21 -0
  285. package/dist/plot/core/placed-tween.svelte.js +68 -0
  286. package/dist/plot/core/reference-line.d.ts +10 -10
  287. package/dist/plot/core/reference-line.js +7 -7
  288. package/dist/plot/core/scales.d.ts +40 -25
  289. package/dist/plot/core/scales.js +49 -21
  290. package/dist/plot/core/svg.d.ts +2 -1
  291. package/dist/plot/core/types/fills.d.ts +101 -0
  292. package/dist/plot/core/types/fills.js +15 -0
  293. package/dist/plot/core/types/plot-3d.d.ts +87 -0
  294. package/dist/plot/core/types/plot-3d.js +4 -0
  295. package/dist/plot/core/types/reference-lines.d.ts +140 -0
  296. package/dist/plot/core/types/reference-lines.js +9 -0
  297. package/dist/plot/core/types.d.ts +47 -331
  298. package/dist/plot/core/types.js +23 -20
  299. package/dist/plot/core/utils/hierarchy-chart.d.ts +51 -0
  300. package/dist/plot/core/utils/hierarchy-chart.js +179 -0
  301. package/dist/plot/core/utils/hierarchy-labels.d.ts +20 -0
  302. package/dist/plot/core/utils/hierarchy-labels.js +99 -0
  303. package/dist/plot/core/utils/label-placement.d.ts +1 -1
  304. package/dist/plot/core/utils/label-placement.js +5 -5
  305. package/dist/plot/core/utils.d.ts +2 -1
  306. package/dist/plot/histogram/Histogram.svelte +373 -631
  307. package/dist/plot/histogram/Histogram.svelte.d.ts +7 -7
  308. package/dist/plot/histogram/HistogramControls.svelte +30 -28
  309. package/dist/plot/histogram/HistogramControls.svelte.d.ts +1 -1
  310. package/dist/plot/histogram/histogram.d.ts +31 -0
  311. package/dist/plot/histogram/histogram.js +70 -0
  312. package/dist/plot/histogram/index.d.ts +1 -0
  313. package/dist/plot/histogram/index.js +1 -0
  314. package/dist/plot/index.d.ts +1 -0
  315. package/dist/plot/index.js +1 -0
  316. package/dist/plot/sankey/Sankey.svelte +79 -73
  317. package/dist/plot/sankey/Sankey.svelte.d.ts +3 -3
  318. package/dist/plot/sankey/SankeyControls.svelte +22 -16
  319. package/dist/plot/sankey/sankey.js +3 -1
  320. package/dist/plot/scatter/BinnedScatterPlot.svelte +264 -112
  321. package/dist/plot/scatter/BinnedScatterPlot.svelte.d.ts +11 -4
  322. package/dist/plot/scatter/ElementScatter.svelte +4 -1
  323. package/dist/plot/scatter/ScatterPlot.svelte +623 -821
  324. package/dist/plot/scatter/ScatterPlot.svelte.d.ts +9 -15
  325. package/dist/plot/scatter/ScatterPlotControls.svelte +18 -19
  326. package/dist/plot/scatter/ScatterPlotControls.svelte.d.ts +1 -1
  327. package/dist/plot/scatter/ScatterPoint.svelte +16 -9
  328. package/dist/plot/scatter/binned-scatter-types.d.ts +6 -12
  329. package/dist/plot/scatter/binned-scatter-types.js +6 -1
  330. package/dist/plot/scatter/index.d.ts +1 -1
  331. package/dist/plot/scatter/scatter-data.d.ts +1 -1
  332. package/dist/plot/scatter/scatter-data.js +8 -7
  333. package/dist/plot/scatter-3d/ScatterPlot3D.svelte +40 -60
  334. package/dist/plot/scatter-3d/ScatterPlot3D.svelte.d.ts +6 -14
  335. package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte +17 -15
  336. package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte.d.ts +5 -5
  337. package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte +232 -234
  338. package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte.d.ts +5 -14
  339. package/dist/plot/scatter-3d/Surface3D.svelte +9 -17
  340. package/dist/plot/scatter-3d/Surface3D.svelte.d.ts +4 -3
  341. package/dist/plot/sunburst/Sunburst.svelte +256 -338
  342. package/dist/plot/sunburst/Sunburst.svelte.d.ts +4 -3
  343. package/dist/plot/sunburst/index.d.ts +1 -1
  344. package/dist/plot/sunburst/index.js +2 -1
  345. package/dist/plot/sunburst/render.d.ts +2 -2
  346. package/dist/plot/sunburst/render.js +47 -22
  347. package/dist/plot/sunburst/sunburst.d.ts +5 -1
  348. package/dist/plot/sunburst/sunburst.js +14 -4
  349. package/dist/plot/treemap/Treemap.svelte +907 -0
  350. package/dist/plot/treemap/Treemap.svelte.d.ts +84 -0
  351. package/dist/plot/treemap/index.d.ts +3 -0
  352. package/dist/plot/treemap/index.js +4 -0
  353. package/dist/plot/treemap/treemap.d.ts +26 -0
  354. package/dist/plot/treemap/treemap.js +99 -0
  355. package/dist/rdf/RdfPlot.svelte +22 -26
  356. package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
  357. package/dist/rdf/calc-rdf.js +4 -8
  358. package/dist/sanitize.js +14 -3
  359. package/dist/scene/SceneCamera.svelte +62 -0
  360. package/dist/scene/SceneCamera.svelte.d.ts +19 -0
  361. package/dist/scene/bind-renderer.svelte.d.ts +2 -0
  362. package/dist/scene/bind-renderer.svelte.js +22 -0
  363. package/dist/scene/index.d.ts +4 -0
  364. package/dist/scene/index.js +5 -0
  365. package/dist/scene/props.js +52 -0
  366. package/dist/scene/types.d.ts +26 -0
  367. package/dist/scene/types.js +1 -0
  368. package/dist/settings.d.ts +33 -11
  369. package/dist/settings.js +136 -51
  370. package/dist/spectral/Bands.svelte +231 -237
  371. package/dist/spectral/Bands.svelte.d.ts +3 -2
  372. package/dist/spectral/BandsAndDos.svelte +29 -29
  373. package/dist/spectral/BrillouinBandsDos.svelte +21 -29
  374. package/dist/spectral/Dos.svelte +75 -77
  375. package/dist/spectral/Dos.svelte.d.ts +2 -1
  376. package/dist/spectral/helpers.d.ts +9 -9
  377. package/dist/spectral/helpers.js +66 -70
  378. package/dist/state.svelte.d.ts +0 -7
  379. package/dist/state.svelte.js +5 -24
  380. package/dist/structure/Arrow.svelte +6 -21
  381. package/dist/structure/ArrowInstances.svelte +160 -0
  382. package/dist/structure/ArrowInstances.svelte.d.ts +16 -0
  383. package/dist/structure/AtomLegend.svelte +115 -75
  384. package/dist/structure/AtomLegend.svelte.d.ts +1 -1
  385. package/dist/structure/Bond.svelte +31 -23
  386. package/dist/structure/CanvasTooltip.svelte +16 -3
  387. package/dist/structure/CellSelect.svelte +22 -29
  388. package/dist/structure/CellSelect.svelte.d.ts +2 -1
  389. package/dist/structure/Cylinder.svelte +24 -40
  390. package/dist/structure/InstancedAtoms.svelte +114 -0
  391. package/dist/structure/InstancedAtoms.svelte.d.ts +15 -0
  392. package/dist/structure/Lattice.svelte +85 -149
  393. package/dist/structure/SiteLabels.svelte +122 -0
  394. package/dist/structure/SiteLabels.svelte.d.ts +18 -0
  395. package/dist/structure/Structure.svelte +725 -735
  396. package/dist/structure/Structure.svelte.d.ts +8 -16
  397. package/dist/structure/StructureCarousel.svelte +630 -0
  398. package/dist/structure/StructureCarousel.svelte.d.ts +19 -0
  399. package/dist/structure/StructureControls.svelte +298 -325
  400. package/dist/structure/StructureControls.svelte.d.ts +5 -3
  401. package/dist/structure/StructureExportPane.svelte +62 -168
  402. package/dist/structure/StructureExportPane.svelte.d.ts +4 -5
  403. package/dist/structure/StructureInfoPane.svelte +77 -69
  404. package/dist/structure/StructureInfoPane.svelte.d.ts +6 -6
  405. package/dist/structure/StructureScene.svelte +758 -600
  406. package/dist/structure/StructureScene.svelte.d.ts +24 -20
  407. package/dist/structure/StructureViewport.svelte +386 -0
  408. package/dist/structure/StructureViewport.svelte.d.ts +63 -0
  409. package/dist/structure/atom-label-placement.d.ts +18 -0
  410. package/dist/structure/atom-label-placement.js +115 -0
  411. package/dist/structure/atom-properties.d.ts +3 -1
  412. package/dist/structure/atom-properties.js +115 -54
  413. package/dist/structure/bond-order-perception.js +2 -4
  414. package/dist/structure/bonding.d.ts +12 -2
  415. package/dist/structure/bonding.js +172 -73
  416. package/dist/structure/edit-history.d.ts +6 -0
  417. package/dist/structure/edit-history.js +27 -0
  418. package/dist/structure/export.d.ts +25 -4
  419. package/dist/structure/export.js +103 -153
  420. package/dist/structure/format-detect.d.ts +1 -0
  421. package/dist/structure/format-detect.js +22 -0
  422. package/dist/structure/geometry.d.ts +9 -0
  423. package/dist/structure/geometry.js +27 -0
  424. package/dist/structure/index.d.ts +18 -1
  425. package/dist/structure/index.js +15 -2
  426. package/dist/structure/measure.d.ts +1 -1
  427. package/dist/structure/measure.js +6 -12
  428. package/dist/structure/parse.d.ts +5 -3
  429. package/dist/structure/parse.js +551 -567
  430. package/dist/structure/partial-occupancy.d.ts +0 -1
  431. package/dist/structure/partial-occupancy.js +5 -3
  432. package/dist/structure/pbc.d.ts +1 -1
  433. package/dist/structure/pbc.js +204 -51
  434. package/dist/structure/polyhedra.d.ts +40 -0
  435. package/dist/structure/polyhedra.js +587 -0
  436. package/dist/structure/site.d.ts +4 -0
  437. package/dist/structure/site.js +1 -0
  438. package/dist/structure/supercell.d.ts +1 -2
  439. package/dist/structure/supercell.js +10 -15
  440. package/dist/structure/validation.js +5 -6
  441. package/dist/symmetry/SymmetryElementControls.svelte +69 -0
  442. package/dist/symmetry/SymmetryElementControls.svelte.d.ts +9 -0
  443. package/dist/symmetry/SymmetryElements.svelte +350 -0
  444. package/dist/symmetry/SymmetryElements.svelte.d.ts +24 -0
  445. package/dist/symmetry/SymmetryStats.svelte +142 -49
  446. package/dist/symmetry/WyckoffTable.svelte +58 -16
  447. package/dist/symmetry/WyckoffTable.svelte.d.ts +3 -0
  448. package/dist/symmetry/cell-transform.js +8 -14
  449. package/dist/symmetry/index.d.ts +15 -4
  450. package/dist/symmetry/index.js +308 -81
  451. package/dist/symmetry/spacegroups.d.ts +5 -1
  452. package/dist/symmetry/spacegroups.js +18 -3
  453. package/dist/symmetry/symmetry-elements.d.ts +33 -0
  454. package/dist/symmetry/symmetry-elements.js +521 -0
  455. package/dist/symmetry/wyckoff-db.d.ts +9 -0
  456. package/dist/symmetry/wyckoff-db.js +87 -0
  457. package/dist/table/HeatmapTable.svelte +1104 -378
  458. package/dist/table/HeatmapTable.svelte.d.ts +12 -2
  459. package/dist/table/ToggleMenu.svelte +5 -12
  460. package/dist/table/index.d.ts +21 -6
  461. package/dist/table/index.js +34 -21
  462. package/dist/theme/ThemeControl.svelte +16 -8
  463. package/dist/theme/index.d.ts +1 -5
  464. package/dist/theme/index.js +4 -10
  465. package/dist/theme/themes.mjs +14 -7
  466. package/dist/tooltip/KCoords.svelte +4 -1
  467. package/dist/tooltip/TooltipContent.svelte +2 -5
  468. package/dist/trajectory/Trajectory.svelte +556 -352
  469. package/dist/trajectory/Trajectory.svelte.d.ts +10 -22
  470. package/dist/trajectory/TrajectoryError.svelte +11 -8
  471. package/dist/trajectory/TrajectoryExportPane.svelte +28 -54
  472. package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +4 -5
  473. package/dist/trajectory/TrajectoryInfoPane.svelte +88 -99
  474. package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +3 -2
  475. package/dist/trajectory/constants.js +6 -2
  476. package/dist/trajectory/extract.js +73 -71
  477. package/dist/trajectory/format-detect.d.ts +0 -1
  478. package/dist/trajectory/format-detect.js +13 -17
  479. package/dist/trajectory/frame-reader.d.ts +2 -1
  480. package/dist/trajectory/frame-reader.js +74 -136
  481. package/dist/trajectory/helpers.d.ts +12 -2
  482. package/dist/trajectory/helpers.js +68 -37
  483. package/dist/trajectory/index.d.ts +1 -0
  484. package/dist/trajectory/index.js +3 -0
  485. package/dist/trajectory/parse/ase.d.ts +9 -1
  486. package/dist/trajectory/parse/ase.js +47 -32
  487. package/dist/trajectory/parse/diagnostics.d.ts +3 -0
  488. package/dist/trajectory/parse/diagnostics.js +14 -0
  489. package/dist/trajectory/parse/h5-utils.d.ts +13 -0
  490. package/dist/trajectory/parse/h5-utils.js +109 -0
  491. package/dist/trajectory/parse/hdf5.d.ts +1 -1
  492. package/dist/trajectory/parse/hdf5.js +116 -106
  493. package/dist/trajectory/parse/index.d.ts +3 -4
  494. package/dist/trajectory/parse/index.js +68 -119
  495. package/dist/trajectory/parse/lammps.d.ts +0 -2
  496. package/dist/trajectory/parse/lammps.js +14 -16
  497. package/dist/trajectory/parse/pymatgen.d.ts +2 -0
  498. package/dist/trajectory/parse/pymatgen.js +74 -0
  499. package/dist/trajectory/parse/vasp.js +13 -9
  500. package/dist/trajectory/parse/vaspout-electronic.d.ts +13 -0
  501. package/dist/trajectory/parse/vaspout-electronic.js +207 -0
  502. package/dist/trajectory/parse/vaspout-h5.d.ts +5 -0
  503. package/dist/trajectory/parse/vaspout-h5.js +284 -0
  504. package/dist/trajectory/parse/xyz.d.ts +9 -21
  505. package/dist/trajectory/parse/xyz.js +38 -39
  506. package/dist/trajectory/plotting.d.ts +8 -10
  507. package/dist/trajectory/plotting.js +102 -127
  508. package/dist/utils.d.ts +4 -0
  509. package/dist/utils.js +8 -1
  510. package/dist/xrd/XrdPlot.svelte +56 -85
  511. package/dist/xrd/broadening.d.ts +2 -1
  512. package/dist/xrd/broadening.js +2 -1
  513. package/dist/xrd/calc-xrd.js +8 -15
  514. package/dist/xrd/index.d.ts +2 -2
  515. package/dist/xrd/parse.d.ts +0 -1
  516. package/dist/xrd/parse.js +56 -73
  517. package/package.json +77 -36
  518. package/dist/api/mp.d.ts +0 -6
  519. package/dist/api/mp.js +0 -22
  520. package/dist/element/data.json +0 -11864
  521. package/dist/fermi-surface/marching-cubes.d.ts +0 -2
  522. package/dist/fermi-surface/marching-cubes.js +0 -2
  523. package/dist/plot/core/hover-lock.svelte.d.ts +0 -14
  524. package/dist/plot/core/hover-lock.svelte.js +0 -45
  525. package/dist/plot/sunburst/SunburstControls.svelte +0 -200
  526. package/dist/structure/label-placement.d.ts +0 -14
  527. package/dist/structure/label-placement.js +0 -72
@@ -1,11 +1,12 @@
1
1
  <script lang="ts">
2
2
  import type { D3InterpolateName } from '../colors'
3
- import { is_color, pick_contrast_color } from '../colors'
3
+ import { get_d3_interpolator, is_color, pick_contrast_color } from '../colors'
4
4
  import { format_num } from '../labels'
5
+ import type { Vec2 } from '../math'
5
6
  import type { AxisConfig } from '../plot'
6
7
  import ColorBar from '../plot/core/components/ColorBar.svelte'
7
- import { make_change_detector } from '../utils'
8
- import * as d3_sc from 'd3-scale-chromatic'
8
+ import { quickselect } from '../plot/box/quantile'
9
+ import { clamp01 } from '../utils'
9
10
  import { type ComponentProps, onDestroy, onMount, type Snippet } from 'svelte'
10
11
  import type { HTMLAttributes } from 'svelte/elements'
11
12
  import { SvelteMap, SvelteSet } from 'svelte/reactivity'
@@ -17,6 +18,7 @@
17
18
  HeatmapExportFormat,
18
19
  HeatmapTooltipProp,
19
20
  LegendPosition,
21
+ MissingCellStyle,
20
22
  NormalizeMode,
21
23
  SymmetricMode,
22
24
  } from './index'
@@ -38,7 +40,7 @@
38
40
  color_scale = $bindable(`interpolateViridis`),
39
41
  color_scale_range = [null, null],
40
42
  color_overrides = {},
41
- missing_color = `transparent`,
43
+ missing = {},
42
44
  log = false,
43
45
  value_transform,
44
46
  normalize = `linear`,
@@ -113,13 +115,11 @@
113
115
  }: Omit<HTMLAttributes<HTMLDivElement>, `onclick` | `ondblclick`> & {
114
116
  x_items: AxisItem[]
115
117
  y_items: AxisItem[]
116
- values?:
117
- | CellValue[][]
118
- | Record<string, Record<string, CellValue>>
118
+ values?: CellValue[][] | Record<string, Record<string, CellValue>>
119
119
  color_scale?: D3InterpolateName | ((val: number) => string)
120
120
  color_scale_range?: [number | null, number | null]
121
121
  color_overrides?: Record<string, string>
122
- missing_color?: string
122
+ missing?: MissingCellStyle
123
123
  log?: boolean
124
124
  value_transform?: (
125
125
  value: number,
@@ -127,7 +127,7 @@
127
127
  ) => number | null
128
128
  normalize?: NormalizeMode
129
129
  domain_mode?: DomainMode
130
- quantile_clip?: [number, number]
130
+ quantile_clip?: Vec2
131
131
  show_legend?: boolean
132
132
  legend_position?: LegendPosition
133
133
  legend_label?: string
@@ -145,11 +145,7 @@
145
145
  onpin?: (cell: CellPos | null) => void
146
146
  oncontextmenu?: (cell: CellContext, event: MouseEvent) => void
147
147
  enable_brush?: boolean
148
- onbrush?: (payload: {
149
- x_range: [number, number]
150
- y_range: [number, number]
151
- cells: CellContext[]
152
- }) => void
148
+ onbrush?: (payload: { x_range: Vec2; y_range: Vec2; cells: CellContext[] }) => void
153
149
  tile_size?: string
154
150
  gap?: string
155
151
  // false: show all rows/cols. 'compact': remove all-null rows/cols.
@@ -199,9 +195,7 @@
199
195
  } = $props()
200
196
 
201
197
  // Normalize symmetric prop: true→'lower', otherwise pass through
202
- const symmetric = $derived(
203
- symmetric_prop === true ? `lower` : symmetric_prop,
204
- )
198
+ const symmetric = $derived(symmetric_prop === true ? `lower` : symmetric_prop)
205
199
 
206
200
  // Check if a cell should be skipped in symmetric mode
207
201
  function is_hidden_cell(x_idx: number, y_idx: number): boolean {
@@ -213,7 +207,6 @@
213
207
  // === Value resolution ===
214
208
  let x_keys = $derived(x_items.map((item) => item.key ?? item.label))
215
209
  let y_keys = $derived(y_items.map((item) => item.key ?? item.label))
216
- let interaction_axis_signature = $derived(JSON.stringify([x_keys, y_keys]))
217
210
  let highlight_x_key_set = $derived(new SvelteSet(highlight_x_keys))
218
211
  let highlight_y_key_set = $derived(new SvelteSet(highlight_y_keys))
219
212
  let search_query_norm = $derived(search_query.trim().toLowerCase())
@@ -221,8 +214,7 @@
221
214
  let get_value = $derived.by(() => {
222
215
  if (Array.isArray(values)) {
223
216
  const matrix_values = values as CellValue[][]
224
- return (x_idx: number, y_idx: number): CellValue =>
225
- matrix_values[y_idx]?.[x_idx] ?? null
217
+ return (x_idx: number, y_idx: number): CellValue => matrix_values[y_idx]?.[x_idx] ?? null
226
218
  }
227
219
  // Record<y_key, Record<x_key, value>>
228
220
  const record = values as Record<string, Record<string, CellValue>>
@@ -267,19 +259,23 @@
267
259
  const all_y = Array.from({ length: y_items.length }, (_, idx) => idx)
268
260
  const filtered_x = search_query_norm
269
261
  ? all_x.filter((idx) => {
270
- const item = x_items[idx]
271
- const key = item.key ?? item.label
272
- return key.toLowerCase().includes(search_query_norm) ||
273
- item.label.toLowerCase().includes(search_query_norm)
274
- })
262
+ const item = x_items[idx]
263
+ const key = item.key ?? item.label
264
+ return (
265
+ key.toLowerCase().includes(search_query_norm) ||
266
+ item.label.toLowerCase().includes(search_query_norm)
267
+ )
268
+ })
275
269
  : all_x
276
270
  const filtered_y = search_query_norm
277
271
  ? all_y.filter((idx) => {
278
- const item = y_items[idx]
279
- const key = item.key ?? item.label
280
- return key.toLowerCase().includes(search_query_norm) ||
281
- item.label.toLowerCase().includes(search_query_norm)
282
- })
272
+ const item = y_items[idx]
273
+ const key = item.key ?? item.label
274
+ return (
275
+ key.toLowerCase().includes(search_query_norm) ||
276
+ item.label.toLowerCase().includes(search_query_norm)
277
+ )
278
+ })
283
279
  : all_y
284
280
  if (!hide_empty) {
285
281
  return {
@@ -290,11 +286,23 @@
290
286
 
291
287
  const col_has_data = Array(x_items.length).fill(false)
292
288
  const row_has_data = Array(y_items.length).fill(false)
289
+ // Early-exit: skip cells whose row+col are already non-empty, stop once all resolved (dense matrices touch ~n+m cells, not n*m)
290
+ let unknown_cols = x_items.length
291
+ let unknown_rows = y_items.length
293
292
  for (let y_idx = 0; y_idx < y_items.length; y_idx++) {
293
+ if (unknown_cols === 0 && unknown_rows === 0) break
294
294
  for (let x_idx = 0; x_idx < x_items.length; x_idx++) {
295
- if (get_value(x_idx, y_idx) !== null) {
295
+ if (row_has_data[y_idx] && col_has_data[x_idx]) continue
296
+ // ignore cells hidden by symmetric rendering so emptiness reflects only visible cells
297
+ if (is_hidden_cell(x_idx, y_idx)) continue
298
+ if (get_value(x_idx, y_idx) === null) continue
299
+ if (!col_has_data[x_idx]) {
296
300
  col_has_data[x_idx] = true
301
+ unknown_cols--
302
+ }
303
+ if (!row_has_data[y_idx]) {
297
304
  row_has_data[y_idx] = true
305
+ unknown_rows--
298
306
  }
299
307
  }
300
308
  }
@@ -313,11 +321,9 @@
313
321
  })
314
322
 
315
323
  // === Color computation ===
316
- let color_scale_fn = $derived.by(() => {
317
- if (typeof color_scale === `function`) return color_scale
318
- const named_scale = d3_sc[color_scale]
319
- return typeof named_scale === `function` ? named_scale : d3_sc.interpolateViridis
320
- })
324
+ let color_scale_fn = $derived(
325
+ typeof color_scale === `function` ? color_scale : get_d3_interpolator(color_scale),
326
+ )
321
327
 
322
328
  function get_transformed_value(x_idx: number, y_idx: number): number | null {
323
329
  const raw_value = get_value(x_idx, y_idx)
@@ -333,56 +339,56 @@
333
339
  return transformed_value
334
340
  }
335
341
 
336
- function get_quantile(sorted_values: number[], quantile: number): number {
337
- if (sorted_values.length === 0) return 0
338
- const clipped_quantile = Math.max(0, Math.min(1, quantile))
339
- const float_idx = (sorted_values.length - 1) * clipped_quantile
342
+ // Interpolated quantile via quickselect (O(n) avg vs full sort); reorders `scratch_values` in place so callers must pass a copy they own
343
+ function get_quantile(scratch_values: number[], quantile: number): number {
344
+ if (scratch_values.length === 0) return 0
345
+ const clipped_quantile = clamp01(quantile)
346
+ const float_idx = (scratch_values.length - 1) * clipped_quantile
340
347
  const low_idx = Math.floor(float_idx)
341
348
  const high_idx = Math.ceil(float_idx)
342
- if (low_idx === high_idx) return sorted_values[low_idx]
349
+ const low_val = quickselect(scratch_values, low_idx)
350
+ if (low_idx === high_idx) return low_val
351
+ const high_val = quickselect(scratch_values, high_idx)
343
352
  const low_weight = high_idx - float_idx
344
353
  const high_weight = float_idx - low_idx
345
- return sorted_values[low_idx] * low_weight + sorted_values[high_idx] * high_weight
354
+ return low_val * low_weight + high_val * high_weight
346
355
  }
347
356
 
348
- let valid_numeric_values = $derived.by(() => {
357
+ // Single pass collecting transformed values + min/max (avoids spreading large arrays into
358
+ // Math.min/max). min_pos is the log-mode lower bound when domain min <= 0 (the old
359
+ // Number.MIN_VALUE floor gave log_min ~ -744, squashing all colors to the top)
360
+ let { valid_numeric_values, auto_min, auto_max, min_pos } = $derived.by(() => {
349
361
  const numeric_values: number[] = []
362
+ let [min, max, pos] = [Infinity, -Infinity, Infinity]
350
363
  for (let y_idx = 0; y_idx < y_items.length; y_idx++) {
351
364
  for (let x_idx = 0; x_idx < x_items.length; x_idx++) {
352
365
  if (is_hidden_cell(x_idx, y_idx)) continue
353
366
  const value = get_transformed_value(x_idx, y_idx)
354
367
  if (value === null) continue
355
368
  numeric_values.push(value)
369
+ if (value < min) min = value
370
+ if (value > max) max = value
371
+ if (value > 0 && value < pos) pos = value
356
372
  }
357
373
  }
358
- return numeric_values
359
- })
360
-
361
- // Single-pass min/max to avoid spreading large arrays into Math.min/max. min_pos is
362
- // the log-mode lower bound when the domain min is <= 0 (the old Number.MIN_VALUE
363
- // floor gave log_min ~ -744, squashing all colors to the top)
364
- let [auto_min, auto_max, min_pos] = $derived.by(() => {
365
- let [min, max, pos] = [Infinity, -Infinity, Infinity]
366
- for (const value of valid_numeric_values) {
367
- if (value < min) min = value
368
- if (value > max) max = value
369
- if (value > 0 && value < pos) pos = value
374
+ return {
375
+ valid_numeric_values: numeric_values,
376
+ auto_min: min <= max ? min : 0,
377
+ auto_max: min <= max ? max : 1,
378
+ min_pos: Number.isFinite(pos) ? pos : null,
370
379
  }
371
- const min_pos_val = Number.isFinite(pos) ? pos : null
372
- return min <= max ? [min, max, min_pos_val] as const : [0, 1, min_pos_val] as const
373
380
  })
374
381
 
382
+ // Lazy derived: only evaluated while domain_mode === 'robust' reads it
375
383
  let [robust_min, robust_max] = $derived.by(() => {
376
384
  if (valid_numeric_values.length === 0) return [0, 1] as const
377
- const sorted_values = valid_numeric_values.toSorted((value_a, value_b) =>
378
- value_a - value_b
379
- )
385
+ const scratch = [...valid_numeric_values]
380
386
  const [q_low, q_high] = quantile_clip
381
- const clipped_min = get_quantile(sorted_values, q_low)
382
- const clipped_max = get_quantile(sorted_values, q_high)
387
+ const clipped_min = get_quantile(scratch, q_low)
388
+ const clipped_max = get_quantile(scratch, q_high)
383
389
  return clipped_min <= clipped_max
384
- ? [clipped_min, clipped_max] as const
385
- : [clipped_max, clipped_min] as const
390
+ ? ([clipped_min, clipped_max] as const)
391
+ : ([clipped_max, clipped_min] as const)
386
392
  })
387
393
 
388
394
  let [domain_min, domain_max] = $derived.by(() => {
@@ -401,41 +407,44 @@
401
407
  let cs_max = $derived(color_scale_range[1] ?? domain_max)
402
408
  let use_log_norm = $derived(normalize === `log` || log)
403
409
 
410
+ // fill for cells with no mappable value (default transparent)
411
+ let missing_fill = $derived(missing.color ?? `transparent`)
412
+
413
+ // whether a value lacks a mappable scale color (-> missing fill + label/style decorations)
414
+ function cell_is_missing(val: CellValue): boolean {
415
+ if (val === null) return true
416
+ if (typeof val === `string`) return !is_color(val)
417
+ return !Number.isFinite(val) || (use_log_norm && val <= 0)
418
+ }
419
+
404
420
  // Map a single value to a background color
405
421
  function value_to_color(val: CellValue): string | null {
406
- if (val === null) return missing_color || null
407
- if (typeof val === `string`) {
408
- if (is_color(val)) return val
409
- return missing_color || null
410
- }
411
- if (!Number.isFinite(val) || !color_scale_fn) return missing_color || null
412
- if (use_log_norm && val <= 0) return missing_color || null
422
+ if (typeof val === `string`) return is_color(val) ? val : missing_fill || null
423
+ // null/string excluded above -> val narrows to number past this guard
424
+ if (val === null || !color_scale_fn || cell_is_missing(val)) return missing_fill || null
413
425
 
414
426
  const span = cs_max - cs_min
415
427
  if (!Number.isFinite(span) || span === 0) return color_scale_fn(0.5)
416
428
 
417
- let normalized = typeof normalize === `function`
418
- ? normalize(val, cs_min, cs_max)
419
- : (val - cs_min) / span
429
+ let normalized =
430
+ typeof normalize === `function` ? normalize(val, cs_min, cs_max) : (val - cs_min) / span
420
431
  if (use_log_norm) {
421
432
  const is_descending_range = cs_min > cs_max
422
433
  const lower_bound = Math.min(cs_min, cs_max)
423
434
  const upper_bound = Math.max(cs_min, cs_max)
424
- if (upper_bound <= 0) return missing_color || null
435
+ if (upper_bound <= 0) return missing_fill || null
425
436
  const safe_lower_bound = lower_bound > 0 ? lower_bound : (min_pos ?? upper_bound)
426
437
  const safe_value = Math.max(val, safe_lower_bound)
427
438
  const log_min = Math.log(safe_lower_bound)
428
439
  const log_max = Math.log(upper_bound)
429
- if (
430
- !Number.isFinite(log_min) || !Number.isFinite(log_max) || log_max === log_min
431
- ) {
440
+ if (!Number.isFinite(log_min) || !Number.isFinite(log_max) || log_max === log_min) {
432
441
  return color_scale_fn(0.5)
433
442
  }
434
443
  const log_normalized = (Math.log(safe_value) - log_min) / (log_max - log_min)
435
444
  normalized = is_descending_range ? 1 - log_normalized : log_normalized
436
445
  }
437
- if (!Number.isFinite(normalized)) return missing_color || null
438
- return color_scale_fn(Math.max(0, Math.min(1, normalized)))
446
+ if (!Number.isFinite(normalized)) return missing_fill || null
447
+ return color_scale_fn(clamp01(normalized))
439
448
  }
440
449
 
441
450
  // Batch compute background colors as a flat array indexed by y_idx * n_x + x_idx.
@@ -453,21 +462,19 @@
453
462
  }
454
463
  const override_key = make_color_override_key(x_keys[x_idx], y_keys[y_idx])
455
464
  const raw_value = get_value(x_idx, y_idx)
456
- const transformed_value = typeof raw_value === `number`
457
- ? get_transformed_value(x_idx, y_idx)
458
- : raw_value
459
- colors[row_offset + x_idx] = override_key in color_overrides
460
- ? color_overrides[override_key]
461
- : value_to_color(transformed_value)
465
+ const transformed_value =
466
+ typeof raw_value === `number` ? get_transformed_value(x_idx, y_idx) : raw_value
467
+ colors[row_offset + x_idx] =
468
+ override_key in color_overrides
469
+ ? color_overrides[override_key]
470
+ : value_to_color(transformed_value)
462
471
  }
463
472
  }
464
473
  return colors
465
474
  })
466
475
 
467
476
  const to_contrast_colors = (bg_values: (string | null)[]): (string | null)[] =>
468
- bg_values.map((bg_color) =>
469
- bg_color ? pick_contrast_color({ bg_color }) : null
470
- )
477
+ bg_values.map((bg_color) => (bg_color ? pick_contrast_color({ bg_color }) : null))
471
478
 
472
479
  // Compute text colors when cells render content that needs contrast (cell snippet or show_values)
473
480
  let text_flat = $derived.by(() => {
@@ -521,12 +528,10 @@
521
528
  symmetric && symmetric_label_position === `diagonal`,
522
529
  )
523
530
  let use_staggered_x_labels = $derived(
524
- stagger_axis_labels === true ||
525
- (stagger_axis_labels === `auto` && vis_x.length >= 24),
531
+ stagger_axis_labels === true || (stagger_axis_labels === `auto` && vis_x.length >= 24),
526
532
  )
527
533
  let use_staggered_y_labels = $derived(
528
- stagger_axis_labels === true ||
529
- (stagger_axis_labels === `auto` && vis_y.length >= 24),
534
+ stagger_axis_labels === true || (stagger_axis_labels === `auto` && vis_y.length >= 24),
530
535
  )
531
536
  let use_side_split_x_labels = $derived(
532
537
  use_staggered_x_labels && !use_diagonal_symmetric_labels,
@@ -551,7 +556,7 @@
551
556
  )
552
557
 
553
558
  function parse_px_size(size: string): number {
554
- const parsed = Number.parseFloat(size)
559
+ const parsed = Number(size.replace(`px`, ``))
555
560
  return Number.isFinite(parsed) && parsed > 0 ? parsed : 12
556
561
  }
557
562
 
@@ -564,8 +569,7 @@
564
569
  Math.floor((scroll_left - grid_offset_left) / tile_stride_px) - overscan
565
570
  const start_pos = Math.max(0, raw_start_pos)
566
571
  const raw_end_pos =
567
- Math.ceil((scroll_left - grid_offset_left + viewport_width) / tile_stride_px) +
568
- overscan
572
+ Math.ceil((scroll_left - grid_offset_left + viewport_width) / tile_stride_px) + overscan
569
573
  const end_pos = Math.min(vis_x.length, raw_end_pos)
570
574
  return vis_x.slice(start_pos, end_pos)
571
575
  })
@@ -575,8 +579,7 @@
575
579
  Math.floor((scroll_top - grid_offset_top) / tile_stride_px) - overscan
576
580
  const start_pos = Math.max(0, raw_start_pos)
577
581
  const raw_end_pos =
578
- Math.ceil((scroll_top - grid_offset_top + viewport_height) / tile_stride_px) +
579
- overscan
582
+ Math.ceil((scroll_top - grid_offset_top + viewport_height) / tile_stride_px) + overscan
580
583
  const end_pos = Math.min(vis_y.length, raw_end_pos)
581
584
  return vis_y.slice(start_pos, end_pos)
582
585
  })
@@ -601,16 +604,12 @@
601
604
  })
602
605
  let highlight_x_by_idx = $derived(
603
606
  new SvelteSet(
604
- vis_x.filter((idx) =>
605
- highlight_x_key_set.has(x_items[idx].key ?? x_items[idx].label)
606
- ),
607
+ vis_x.filter((idx) => highlight_x_key_set.has(x_items[idx].key ?? x_items[idx].label)),
607
608
  ),
608
609
  )
609
610
  let highlight_y_by_idx = $derived(
610
611
  new SvelteSet(
611
- vis_y.filter((idx) =>
612
- highlight_y_key_set.has(y_items[idx].key ?? y_items[idx].label)
613
- ),
612
+ vis_y.filter((idx) => highlight_y_key_set.has(y_items[idx].key ?? y_items[idx].label)),
614
613
  ),
615
614
  )
616
615
 
@@ -699,18 +698,14 @@
699
698
  click_timeout_id = null
700
699
  }
701
700
 
702
- function parse_cell_indices(
703
- cell_el: HTMLElement,
704
- ): { x_idx: number; y_idx: number } | null {
701
+ function parse_cell_indices(cell_el: HTMLElement): { x_idx: number; y_idx: number } | null {
705
702
  const x_value = Number(cell_el.dataset.x)
706
703
  const y_value = Number(cell_el.dataset.y)
707
704
  if (!Number.isInteger(x_value) || !Number.isInteger(y_value)) return null
708
705
  return { x_idx: x_value, y_idx: y_value }
709
706
  }
710
707
 
711
- function get_cell_context_from_target(
712
- event_target: EventTarget | null,
713
- ): CellContext | null {
708
+ function get_cell_context_from_target(event_target: EventTarget | null): CellContext | null {
714
709
  const cell_el = get_cell_el_from_target(event_target)
715
710
  if (!cell_el) return null
716
711
  const indices = parse_cell_indices(cell_el)
@@ -731,9 +726,7 @@
731
726
  }, dblclick_delay_ms)
732
727
  }
733
728
 
734
- function get_cell_el_from_target(
735
- event_target: EventTarget | null,
736
- ): HTMLElement | null {
729
+ function get_cell_el_from_target(event_target: EventTarget | null): HTMLElement | null {
737
730
  const target_node = event_target
738
731
  if (!(target_node instanceof Element)) return null
739
732
  if (target_node instanceof HTMLElement && target_node.dataset.x !== undefined) {
@@ -743,21 +736,14 @@
743
736
  return closest_cell instanceof HTMLElement ? closest_cell : null
744
737
  }
745
738
 
746
- function update_selected_cells(
747
- event: MouseEvent,
748
- clicked_cell: CellPos,
749
- ): void {
739
+ function update_selected_cells(event: MouseEvent, clicked_cell: CellPos): void {
750
740
  if (selection_mode === `single`) {
751
741
  selected_cells = [clicked_cell]
752
742
  last_selected_cell = clicked_cell
753
743
  onselect?.(selected_cells)
754
744
  return
755
745
  }
756
- if (
757
- selection_mode === `range` &&
758
- event.shiftKey &&
759
- last_selected_cell
760
- ) {
746
+ if (selection_mode === `range` && event.shiftKey && last_selected_cell) {
761
747
  const x_min = Math.min(last_selected_cell.x_idx, clicked_cell.x_idx)
762
748
  const x_max = Math.max(last_selected_cell.x_idx, clicked_cell.x_idx)
763
749
  const y_min = Math.min(last_selected_cell.y_idx, clicked_cell.y_idx)
@@ -775,8 +761,8 @@
775
761
  }
776
762
  const clicked_key = cell_pos_key(clicked_cell.x_idx, clicked_cell.y_idx)
777
763
  const next_cells = [...selected_cells]
778
- const existing_idx = next_cells.findIndex((pos) =>
779
- cell_pos_key(pos.x_idx, pos.y_idx) === clicked_key
764
+ const existing_idx = next_cells.findIndex(
765
+ (pos) => cell_pos_key(pos.x_idx, pos.y_idx) === clicked_key,
780
766
  )
781
767
  const toggle_mode = selection_mode === `multi` && (event.metaKey || event.ctrlKey)
782
768
  if (existing_idx !== -1 && toggle_mode) next_cells.splice(existing_idx, 1)
@@ -792,8 +778,10 @@
792
778
  const tw = tooltip_div.offsetWidth
793
779
  const th = tooltip_div.offsetHeight
794
780
  // Flip to opposite side of cursor when near viewport edges
795
- const left = client_x + 10 + tw > globalThis.innerWidth ? client_x - 10 - tw : client_x + 10
796
- const top = client_y + 12 + th > globalThis.innerHeight ? client_y - 12 - th : client_y + 12
781
+ const left =
782
+ client_x + 10 + tw > globalThis.innerWidth ? client_x - 10 - tw : client_x + 10
783
+ const top =
784
+ client_y + 12 + th > globalThis.innerHeight ? client_y - 12 - th : client_y + 12
797
785
  tooltip_div.style.left = `${Math.max(0, left)}px`
798
786
  tooltip_div.style.top = `${Math.max(0, top)}px`
799
787
  }
@@ -804,19 +792,12 @@
804
792
  }
805
793
 
806
794
  // Write default tooltip content imperatively (no reactive state)
807
- function update_tooltip_content(
808
- td: HTMLElement,
809
- x_idx: number,
810
- y_idx: number,
811
- ): void {
795
+ function update_tooltip_content(td: HTMLElement, x_idx: number, y_idx: number): void {
812
796
  const x_label = x_items[x_idx]?.label ?? ``
813
797
  const y_label = y_items[y_idx]?.label ?? ``
814
798
  const val = get_value(x_idx, y_idx)
815
- const value_str = val == null
816
- ? ``
817
- : typeof val === `number`
818
- ? format_num(val)
819
- : String(val)
799
+ const value_str =
800
+ val == null ? `` : typeof val === `number` ? format_num(val) : String(val)
820
801
  td.textContent = value_str
821
802
  ? `${x_label} - ${y_label}: ${value_str}`
822
803
  : `${x_label} - ${y_label}`
@@ -864,8 +845,8 @@
864
845
  // Clear active state imperatively
865
846
  last_hover_x = -1
866
847
  last_hover_y = -1
867
- const keep_tooltip_visible = tooltip_mode === `pinned` ||
868
- (tooltip_mode === `both` && pinned_cell !== null)
848
+ const keep_tooltip_visible =
849
+ tooltip_mode === `pinned` || (tooltip_mode === `both` && pinned_cell !== null)
869
850
  if (!keep_tooltip_visible) {
870
851
  tooltip_div?.classList.remove(`visible`)
871
852
  }
@@ -973,10 +954,7 @@
973
954
  for (let step_idx = 0; step_idx < max_steps; step_idx++) {
974
955
  next_x += x_step
975
956
  next_y += y_step
976
- if (
977
- next_x < 0 || next_y < 0 || next_x >= x_items.length ||
978
- next_y >= y_items.length
979
- ) {
957
+ if (next_x < 0 || next_y < 0 || next_x >= x_items.length || next_y >= y_items.length) {
980
958
  return
981
959
  }
982
960
  if (is_hidden_cell(next_x, next_y)) continue
@@ -1069,29 +1047,32 @@
1069
1047
  let legend_wrapper_style = $derived.by(() =>
1070
1048
  legend_position === `right`
1071
1049
  ? `--cbar-height: 120px; --cbar-min-height: 120px; --cbar-max-height: 120px;`
1072
- : `--cbar-width: 180px;`
1050
+ : `--cbar-width: 180px;`,
1073
1051
  )
1074
1052
 
1075
1053
  let has_interaction_handlers = $derived(
1076
1054
  !disabled &&
1077
- (
1078
- Boolean(onclick) ||
1055
+ (Boolean(onclick) ||
1079
1056
  Boolean(ondblclick) ||
1080
1057
  Boolean(oncontextmenu) ||
1081
1058
  selection_mode !== `single` ||
1082
- tooltip_mode !== `hover`
1083
- ),
1059
+ tooltip_mode !== `hover`),
1084
1060
  )
1085
1061
  let cell_tag_name = $derived(has_interaction_handlers ? `button` : `div`)
1086
- let cell_class_name = $derived(
1087
- has_interaction_handlers ? `cell interactive` : `cell`,
1088
- )
1062
+ let cell_class_name = $derived(has_interaction_handlers ? `cell interactive` : `cell`)
1089
1063
 
1090
1064
  // Tooltip state: only used for custom tooltip snippets (function tooltips)
1091
1065
  let tooltip_cell: CellContext | null = $state(null)
1092
- const axis_changed = make_change_detector()
1066
+ // Reset interactions when axis keys change; element-wise compare beats JSON.stringify-ing every key on each x_items/y_items update
1067
+ const keys_equal = (keys_a: string[], keys_b: string[]): boolean =>
1068
+ keys_a.length === keys_b.length && keys_a.every((key, idx) => key === keys_b[idx])
1069
+ let prev_axis_keys: { x: string[]; y: string[] } | null = null
1093
1070
  $effect(() => {
1094
- if (!axis_changed(interaction_axis_signature)) return
1071
+ const changed =
1072
+ prev_axis_keys !== null &&
1073
+ !(keys_equal(x_keys, prev_axis_keys.x) && keys_equal(y_keys, prev_axis_keys.y))
1074
+ prev_axis_keys = { x: x_keys, y: y_keys }
1075
+ if (!changed) return
1095
1076
  cancel_raf(active_cell_raf)
1096
1077
  // Cancel delayed clicks before old cell coordinates can fire on new axes.
1097
1078
  clear_pending_click()
@@ -1136,8 +1117,8 @@
1136
1117
  bind:search_query
1137
1118
  {export_formats}
1138
1119
  onexport={onexport
1139
- ? (fmt: HeatmapExportFormat) => onexport(fmt, build_export_payload(fmt))
1140
- : undefined}
1120
+ ? (fmt: HeatmapExportFormat) => onexport(fmt, build_export_payload(fmt))
1121
+ : undefined}
1141
1122
  toggle_visible
1142
1123
  children={controls_children}
1143
1124
  {...controls_props}
@@ -1146,12 +1127,14 @@
1146
1127
  <div
1147
1128
  {...rest}
1148
1129
  bind:this={matrix_el}
1149
- class="grid theme-{theme} {rest.class ?? ``}"
1130
+ class={[`grid`, `theme-${theme}`, rest.class]}
1150
1131
  style:--n-cols={gaps_mode ? x_items.length : grid_col_count}
1151
1132
  style:--n-rows={gaps_mode ? y_items.length : grid_row_count}
1152
- style:--extra-right-y={(use_side_split_y_labels || symmetric === `upper`) ? 1 : 0}
1133
+ style:--extra-right-y={use_side_split_y_labels || symmetric === `upper` ? 1 : 0}
1153
1134
  style:--extra-bottom-x={use_side_split_x_labels ? 1 : 0}
1154
- style:--right-y-track={(use_side_split_y_labels || symmetric === `upper`) ? `max-content` : `0`}
1135
+ style:--right-y-track={use_side_split_y_labels || symmetric === `upper`
1136
+ ? `max-content`
1137
+ : `0`}
1155
1138
  style:--bottom-x-track={use_side_split_x_labels ? `max-content` : `0`}
1156
1139
  style:--tile-size={tile_size}
1157
1140
  style:--heatmap-gridline-color={gridline_color}
@@ -1226,6 +1209,11 @@
1226
1209
  {@const bg = bg_flat[flat_idx]}
1227
1210
  {@const should_render = !is_hidden_cell(x_idx, y_idx)}
1228
1211
  {#if should_render}
1212
+ {@const raw = get_value(x_idx, y_idx)}
1213
+ <!-- missing-state must match bg_flat, which colors from the transformed value -->
1214
+ {@const cell_missing = cell_is_missing(
1215
+ typeof raw === `number` ? get_transformed_value(x_idx, y_idx) : raw,
1216
+ )}
1229
1217
  <svelte:element
1230
1218
  this={cell_tag_name}
1231
1219
  class={cell_class_name}
@@ -1234,6 +1222,7 @@
1234
1222
  class:animated={animate_updates}
1235
1223
  data-x={x_idx}
1236
1224
  data-y={y_idx}
1225
+ style={cell_missing ? missing.style : undefined}
1237
1226
  style:background-color={bg}
1238
1227
  style:color={text_flat?.[flat_idx]}
1239
1228
  style:--heatmap-selected-outline-color={selected_outline_flat[flat_idx]}
@@ -1242,15 +1231,14 @@
1242
1231
  >
1243
1232
  {#if cell}
1244
1233
  {@render cell(build_cell_context(x_idx, y_idx))}
1245
- {:else if show_values}
1246
- {@const raw = get_value(x_idx, y_idx)}
1247
- {#if raw !== null}
1248
- <span class="cell-value">{
1249
- typeof raw === `number`
1234
+ {:else if cell_missing}
1235
+ {#if missing.label}<span class="cell-value">{missing.label}</span>{/if}
1236
+ {:else if show_values && raw !== null}
1237
+ <span class="cell-value"
1238
+ >{typeof raw === `number`
1250
1239
  ? format_num(raw, show_values === true ? `.3~g` : show_values)
1251
- : raw
1252
- }</span>
1253
- {/if}
1240
+ : raw}</span
1241
+ >
1254
1242
  {/if}
1255
1243
  </svelte:element>
1256
1244
  {:else}
@@ -1258,8 +1246,7 @@
1258
1246
  class="cell empty"
1259
1247
  style:grid-column={cell_grid_col(x_idx)}
1260
1248
  style:grid-row={cell_grid_row(y_idx)}
1261
- >
1262
- </div>
1249
+ ></div>
1263
1250
  {/if}
1264
1251
  {/each}
1265
1252
  {/each}
@@ -1364,25 +1351,17 @@
1364
1351
  .grid {
1365
1352
  display: grid;
1366
1353
  grid-template-columns:
1367
- max-content repeat(
1368
- var(--n-cols),
1369
- minmax(var(--tile-size, 6px), 1fr)
1370
- ) var(--right-y-track, 0);
1354
+ max-content repeat(var(--n-cols), minmax(var(--tile-size, 6px), 1fr))
1355
+ var(--right-y-track, 0);
1371
1356
  grid-template-rows:
1372
- max-content repeat(
1373
- var(--n-rows),
1374
- minmax(var(--tile-size, 6px), 1fr)
1375
- ) var(--bottom-x-track, 0);
1357
+ max-content repeat(var(--n-rows), minmax(var(--tile-size, 6px), 1fr))
1358
+ var(--bottom-x-track, 0);
1376
1359
  position: relative;
1377
1360
  width: min(100%, var(--heatmap-max-width, 1200px));
1378
1361
  max-width: var(--heatmap-max-width, 1200px);
1379
1362
  aspect-ratio: calc(
1380
- (
1381
- var(--n-cols) + 1 + var(--extra-right-y, 0)
1382
- )
1383
- / (
1384
- var(--n-rows) + 1 + var(--extra-bottom-x, 0)
1385
- )
1363
+ (var(--n-cols) + 1 + var(--extra-right-y, 0)) /
1364
+ (var(--n-rows) + 1 + var(--extra-bottom-x, 0))
1386
1365
  );
1387
1366
  overflow: auto;
1388
1367
  &.theme-publication {
@@ -1512,10 +1491,7 @@
1512
1491
  display: none;
1513
1492
  position: fixed;
1514
1493
  transform: none;
1515
- background: var(
1516
- --tooltip-bg,
1517
- light-dark(rgba(255, 255, 255, 0.95), rgba(0, 0, 0, 0.85))
1518
- );
1494
+ background: var(--tooltip-bg, light-dark(rgba(255, 255, 255, 0.95), rgba(0, 0, 0, 0.85)));
1519
1495
  color: var(--tooltip-color, light-dark(#222, #eee));
1520
1496
  padding: var(--tooltip-padding, 4px 6px);
1521
1497
  border-radius: var(--tooltip-border-radius, var(--border-radius, 3pt));