matterviz 0.3.2 → 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 (280) hide show
  1. package/dist/EmptyState.svelte +10 -2
  2. package/dist/FilePicker.svelte +123 -82
  3. package/dist/Icon.svelte +18 -12
  4. package/dist/MillerIndexInput.svelte +27 -21
  5. package/dist/api/optimade.js +6 -6
  6. package/dist/app.css +216 -207
  7. package/dist/brillouin/BrillouinZone.svelte +292 -149
  8. package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
  9. package/dist/brillouin/BrillouinZoneControls.svelte +32 -5
  10. package/dist/brillouin/BrillouinZoneExportPane.svelte +69 -42
  11. package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +1 -1
  12. package/dist/brillouin/BrillouinZoneInfoPane.svelte +99 -68
  13. package/dist/brillouin/BrillouinZoneScene.svelte +275 -163
  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 +162 -27
  18. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +451 -281
  19. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +2148 -1642
  20. package/dist/chempot-diagram/ChemPotScene3D.svelte +8 -5
  21. package/dist/chempot-diagram/async-compute.svelte.d.ts +3 -0
  22. package/dist/chempot-diagram/async-compute.svelte.js +77 -0
  23. package/dist/chempot-diagram/chempot-worker.d.ts +1 -0
  24. package/dist/chempot-diagram/chempot-worker.js +11 -0
  25. package/dist/chempot-diagram/color.js +1 -2
  26. package/dist/chempot-diagram/compute.d.ts +10 -0
  27. package/dist/chempot-diagram/compute.js +250 -88
  28. package/dist/chempot-diagram/index.d.ts +2 -1
  29. package/dist/chempot-diagram/index.js +2 -1
  30. package/dist/chempot-diagram/temperature.js +8 -9
  31. package/dist/chempot-diagram/types.d.ts +3 -0
  32. package/dist/chempot-diagram/types.js +1 -0
  33. package/dist/colors/index.d.ts +1 -1
  34. package/dist/colors/index.js +5 -3
  35. package/dist/composition/BarChart.svelte +128 -55
  36. package/dist/composition/BubbleChart.svelte +102 -49
  37. package/dist/composition/Composition.svelte +100 -79
  38. package/dist/composition/Formula.svelte +108 -62
  39. package/dist/composition/FormulaFilter.svelte +665 -537
  40. package/dist/composition/PieChart.svelte +183 -108
  41. package/dist/composition/format.d.ts +5 -0
  42. package/dist/composition/format.js +20 -3
  43. package/dist/composition/parse.js +14 -9
  44. package/dist/convex-hull/ConvexHull.svelte +93 -40
  45. package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
  46. package/dist/convex-hull/ConvexHull2D.svelte +549 -360
  47. package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
  48. package/dist/convex-hull/ConvexHull3D.svelte +1296 -827
  49. package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
  50. package/dist/convex-hull/ConvexHull4D.svelte +1004 -688
  51. package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
  52. package/dist/convex-hull/ConvexHullControls.svelte +115 -28
  53. package/dist/convex-hull/ConvexHullControls.svelte.d.ts +1 -1
  54. package/dist/convex-hull/ConvexHullInfoPane.svelte +29 -3
  55. package/dist/convex-hull/ConvexHullStats.svelte +425 -328
  56. package/dist/convex-hull/ConvexHullTooltip.svelte +40 -16
  57. package/dist/convex-hull/GasPressureControls.svelte +104 -61
  58. package/dist/convex-hull/StructurePopup.svelte +25 -4
  59. package/dist/convex-hull/TemperatureSlider.svelte +45 -25
  60. package/dist/convex-hull/barycentric-coords.js +13 -7
  61. package/dist/convex-hull/demo-temperature.js +8 -4
  62. package/dist/convex-hull/gas-thermodynamics.js +17 -12
  63. package/dist/convex-hull/helpers.d.ts +9 -0
  64. package/dist/convex-hull/helpers.js +77 -34
  65. package/dist/convex-hull/thermodynamics.js +61 -56
  66. package/dist/convex-hull/types.d.ts +9 -14
  67. package/dist/convex-hull/types.js +0 -17
  68. package/dist/coordination/CoordinationBarPlot.svelte +227 -154
  69. package/dist/element/BohrAtom.svelte +55 -12
  70. package/dist/element/ElementHeading.svelte +7 -2
  71. package/dist/element/ElementPhoto.svelte +15 -9
  72. package/dist/element/ElementStats.svelte +10 -4
  73. package/dist/element/ElementTile.svelte +137 -73
  74. package/dist/element/Nucleus.svelte +39 -11
  75. package/dist/feedback/ClickFeedback.svelte +16 -5
  76. package/dist/feedback/DragOverlay.svelte +10 -2
  77. package/dist/feedback/Spinner.svelte +4 -2
  78. package/dist/feedback/StatusMessage.svelte +8 -2
  79. package/dist/fermi-surface/FermiSlice.svelte +118 -88
  80. package/dist/fermi-surface/FermiSurface.svelte +328 -187
  81. package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
  82. package/dist/fermi-surface/FermiSurfaceControls.svelte +113 -46
  83. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
  84. package/dist/fermi-surface/FermiSurfaceScene.svelte +535 -342
  85. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
  86. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +14 -5
  87. package/dist/fermi-surface/compute.js +16 -20
  88. package/dist/fermi-surface/parse.js +24 -14
  89. package/dist/fermi-surface/symmetry.js +2 -7
  90. package/dist/fermi-surface/types.d.ts +3 -5
  91. package/dist/heatmap-matrix/HeatmapMatrix.svelte +1019 -765
  92. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +1 -1
  93. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +76 -22
  94. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +2 -3
  95. package/dist/icons.js +47 -0
  96. package/dist/index.d.ts +2 -1
  97. package/dist/index.js +2 -1
  98. package/dist/io/decompress.js +1 -1
  99. package/dist/io/export.d.ts +3 -0
  100. package/dist/io/export.js +129 -143
  101. package/dist/io/is-binary.js +2 -3
  102. package/dist/io/url-drop.js +1 -2
  103. package/dist/isosurface/Isosurface.svelte +202 -148
  104. package/dist/isosurface/IsosurfaceControls.svelte +46 -28
  105. package/dist/isosurface/parse.js +34 -29
  106. package/dist/isosurface/slice.js +5 -10
  107. package/dist/isosurface/types.d.ts +2 -1
  108. package/dist/isosurface/types.js +61 -12
  109. package/dist/labels.js +11 -8
  110. package/dist/layout/FullscreenToggle.svelte +11 -2
  111. package/dist/layout/InfoCard.svelte +38 -6
  112. package/dist/layout/InfoTag.svelte +63 -32
  113. package/dist/layout/PropertyFilter.svelte +82 -37
  114. package/dist/layout/SettingsSection.svelte +85 -55
  115. package/dist/layout/SubpageGrid.svelte +10 -2
  116. package/dist/layout/json-tree/JsonNode.svelte +183 -138
  117. package/dist/layout/json-tree/JsonTree.svelte +499 -413
  118. package/dist/layout/json-tree/JsonValue.svelte +127 -99
  119. package/dist/layout/json-tree/utils.js +4 -2
  120. package/dist/marching-cubes.js +25 -2
  121. package/dist/math.d.ts +13 -17
  122. package/dist/math.js +133 -67
  123. package/dist/overlays/ContextMenu.svelte +65 -40
  124. package/dist/overlays/DraggablePane.svelte +211 -139
  125. package/dist/periodic-table/PeriodicTable.svelte +278 -145
  126. package/dist/periodic-table/PeriodicTableControls.svelte +178 -128
  127. package/dist/periodic-table/PropertySelect.svelte +25 -7
  128. package/dist/periodic-table/TableInset.svelte +8 -3
  129. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +446 -309
  130. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
  131. package/dist/phase-diagram/PhaseDiagramControls.svelte +102 -43
  132. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
  133. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +63 -40
  134. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +71 -28
  135. package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +1 -1
  136. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +158 -101
  137. package/dist/phase-diagram/TdbInfoPanel.svelte +28 -4
  138. package/dist/phase-diagram/build-diagram.js +9 -9
  139. package/dist/phase-diagram/colors.js +1 -3
  140. package/dist/phase-diagram/parse.js +10 -9
  141. package/dist/phase-diagram/svg-to-diagram.js +53 -49
  142. package/dist/phase-diagram/utils.d.ts +1 -0
  143. package/dist/phase-diagram/utils.js +80 -25
  144. package/dist/plot/AxisLabel.svelte +28 -3
  145. package/dist/plot/BarPlot.svelte +1182 -734
  146. package/dist/plot/BarPlot.svelte.d.ts +2 -2
  147. package/dist/plot/BarPlotControls.svelte +31 -5
  148. package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
  149. package/dist/plot/ColorBar.svelte +479 -329
  150. package/dist/plot/ColorScaleSelect.svelte +27 -6
  151. package/dist/plot/ElementScatter.svelte +36 -15
  152. package/dist/plot/FillArea.svelte +152 -95
  153. package/dist/plot/Histogram.svelte +934 -571
  154. package/dist/plot/Histogram.svelte.d.ts +1 -1
  155. package/dist/plot/HistogramControls.svelte +53 -9
  156. package/dist/plot/HistogramControls.svelte.d.ts +1 -1
  157. package/dist/plot/InteractiveAxisLabel.svelte +34 -11
  158. package/dist/plot/InteractiveAxisLabel.svelte.d.ts +1 -1
  159. package/dist/plot/Line.svelte +63 -28
  160. package/dist/plot/PlotControls.svelte +157 -114
  161. package/dist/plot/PlotControls.svelte.d.ts +1 -1
  162. package/dist/plot/PlotLegend.svelte +174 -91
  163. package/dist/plot/PlotTooltip.svelte +45 -6
  164. package/dist/plot/PortalSelect.svelte +175 -147
  165. package/dist/plot/ReferenceLine.svelte +76 -22
  166. package/dist/plot/ReferenceLine3D.svelte +132 -107
  167. package/dist/plot/ReferencePlane.svelte +146 -121
  168. package/dist/plot/ScatterPlot.svelte +1681 -1091
  169. package/dist/plot/ScatterPlot.svelte.d.ts +2 -2
  170. package/dist/plot/ScatterPlot3D.svelte +256 -131
  171. package/dist/plot/ScatterPlot3D.svelte.d.ts +2 -2
  172. package/dist/plot/ScatterPlot3DControls.svelte +113 -63
  173. package/dist/plot/ScatterPlot3DControls.svelte.d.ts +2 -1
  174. package/dist/plot/ScatterPlot3DScene.svelte +608 -403
  175. package/dist/plot/ScatterPlot3DScene.svelte.d.ts +2 -2
  176. package/dist/plot/ScatterPlotControls.svelte +65 -25
  177. package/dist/plot/ScatterPlotControls.svelte.d.ts +1 -1
  178. package/dist/plot/ScatterPoint.svelte +98 -26
  179. package/dist/plot/ScatterPoint.svelte.d.ts +1 -0
  180. package/dist/plot/SpacegroupBarPlot.svelte +142 -85
  181. package/dist/plot/Surface3D.svelte +159 -108
  182. package/dist/plot/ZeroLines.svelte +55 -3
  183. package/dist/plot/ZoomRect.svelte +4 -2
  184. package/dist/plot/axis-utils.js +1 -3
  185. package/dist/plot/data-cleaning.js +12 -28
  186. package/dist/plot/data-transform.js +2 -1
  187. package/dist/plot/fill-utils.js +2 -0
  188. package/dist/plot/layout.d.ts +4 -1
  189. package/dist/plot/layout.js +33 -14
  190. package/dist/plot/reference-line.d.ts +2 -2
  191. package/dist/plot/reference-line.js +7 -5
  192. package/dist/plot/scales.js +24 -36
  193. package/dist/plot/types.d.ts +11 -23
  194. package/dist/plot/types.js +6 -11
  195. package/dist/plot/utils/label-placement.d.ts +32 -15
  196. package/dist/plot/utils/label-placement.js +227 -66
  197. package/dist/plot/utils/series-visibility.js +2 -3
  198. package/dist/rdf/RdfPlot.svelte +143 -91
  199. package/dist/rdf/calc-rdf.js +4 -5
  200. package/dist/sanitize.d.ts +4 -0
  201. package/dist/sanitize.js +107 -0
  202. package/dist/settings.d.ts +18 -6
  203. package/dist/settings.js +46 -16
  204. package/dist/spectral/Bands.svelte +632 -453
  205. package/dist/spectral/BandsAndDos.svelte +90 -49
  206. package/dist/spectral/BrillouinBandsDos.svelte +151 -93
  207. package/dist/spectral/Dos.svelte +389 -258
  208. package/dist/spectral/helpers.js +55 -43
  209. package/dist/state.svelte.d.ts +1 -1
  210. package/dist/state.svelte.js +3 -2
  211. package/dist/structure/Arrow.svelte +59 -20
  212. package/dist/structure/AtomLegend.svelte +215 -134
  213. package/dist/structure/Bond.svelte +73 -47
  214. package/dist/structure/CanvasTooltip.svelte +10 -2
  215. package/dist/structure/CellSelect.svelte +72 -45
  216. package/dist/structure/Cylinder.svelte +33 -17
  217. package/dist/structure/Lattice.svelte +88 -33
  218. package/dist/structure/Structure.svelte +1063 -797
  219. package/dist/structure/Structure.svelte.d.ts +1 -1
  220. package/dist/structure/StructureControls.svelte +349 -118
  221. package/dist/structure/StructureExportPane.svelte +124 -89
  222. package/dist/structure/StructureExportPane.svelte.d.ts +1 -1
  223. package/dist/structure/StructureInfoPane.svelte +304 -237
  224. package/dist/structure/StructureScene.svelte +879 -443
  225. package/dist/structure/StructureScene.svelte.d.ts +15 -7
  226. package/dist/structure/atom-properties.js +8 -8
  227. package/dist/structure/bonding.js +6 -7
  228. package/dist/structure/export.js +14 -29
  229. package/dist/structure/ferrox-wasm.js +1 -1
  230. package/dist/structure/index.d.ts +13 -3
  231. package/dist/structure/index.js +83 -23
  232. package/dist/structure/measure.d.ts +2 -2
  233. package/dist/structure/measure.js +4 -44
  234. package/dist/structure/parse.js +113 -141
  235. package/dist/structure/partial-occupancy.js +7 -10
  236. package/dist/structure/pbc.d.ts +1 -0
  237. package/dist/structure/pbc.js +16 -6
  238. package/dist/structure/supercell.d.ts +2 -2
  239. package/dist/structure/supercell.js +12 -22
  240. package/dist/structure/validation.js +1 -2
  241. package/dist/symmetry/SymmetryStats.svelte +84 -41
  242. package/dist/symmetry/WyckoffTable.svelte +26 -6
  243. package/dist/symmetry/cell-transform.js +5 -3
  244. package/dist/symmetry/index.js +8 -7
  245. package/dist/symmetry/spacegroups.js +148 -148
  246. package/dist/table/HeatmapTable.svelte +790 -554
  247. package/dist/table/HeatmapTable.svelte.d.ts +1 -1
  248. package/dist/table/ToggleMenu.svelte +125 -92
  249. package/dist/table/index.js +2 -4
  250. package/dist/theme/ThemeControl.svelte +21 -12
  251. package/dist/time.js +4 -1
  252. package/dist/tooltip/TooltipContent.svelte +33 -8
  253. package/dist/trajectory/Trajectory.svelte +758 -558
  254. package/dist/trajectory/TrajectoryError.svelte +14 -3
  255. package/dist/trajectory/TrajectoryExportPane.svelte +137 -83
  256. package/dist/trajectory/TrajectoryInfoPane.svelte +272 -143
  257. package/dist/trajectory/extract.js +10 -26
  258. package/dist/trajectory/format-detect.js +5 -5
  259. package/dist/trajectory/frame-reader.d.ts +1 -1
  260. package/dist/trajectory/frame-reader.js +5 -12
  261. package/dist/trajectory/helpers.d.ts +0 -1
  262. package/dist/trajectory/helpers.js +2 -17
  263. package/dist/trajectory/index.js +14 -12
  264. package/dist/trajectory/parse/ase.js +5 -4
  265. package/dist/trajectory/parse/hdf5.js +26 -18
  266. package/dist/trajectory/parse/index.js +13 -18
  267. package/dist/trajectory/parse/lammps.js +17 -7
  268. package/dist/trajectory/parse/vasp.js +5 -2
  269. package/dist/trajectory/parse/xyz.js +8 -7
  270. package/dist/trajectory/plotting.js +13 -8
  271. package/dist/utils.d.ts +1 -0
  272. package/dist/utils.js +13 -0
  273. package/dist/xrd/XrdPlot.svelte +337 -247
  274. package/dist/xrd/broadening.js +14 -9
  275. package/dist/xrd/calc-xrd.js +12 -18
  276. package/dist/xrd/parse.d.ts +1 -1
  277. package/dist/xrd/parse.js +17 -17
  278. package/package.json +99 -103
  279. package/readme.md +1 -1
  280. /package/dist/theme/{themes.js → themes.mjs} +0 -0
@@ -1,6 +1,6 @@
1
1
  // Helper utilities for band structure and DOS data processing
2
2
  import { SUBSCRIPT_MAP } from '../labels';
3
- import { centered_frac, euclidean_dist, } from '../math';
3
+ import { centered_frac, euclidean_dist } from '../math';
4
4
  // Check if range is a valid [min, max] tuple (strict 2-element array of finite numbers)
5
5
  export const is_valid_range = (range) => Array.isArray(range) &&
6
6
  range.length === 2 &&
@@ -70,7 +70,10 @@ export function pretty_sym_point(symbol) {
70
70
  .replace(/\\?SIGMA/gi, `Σ`)
71
71
  .replace(/\\?LAMBDA/gi, `Λ`)
72
72
  .replace(/(\p{L})(\d+)/gu, (_, letter, num) => letter +
73
- num.split(``).map((digit) => SUBSCRIPT_MAP[digit] ?? digit).join(``));
73
+ num
74
+ .split(``)
75
+ .map((digit) => SUBSCRIPT_MAP[digit] ?? digit)
76
+ .join(``));
74
77
  }
75
78
  // Create segment key from start and end labels
76
79
  export const get_segment_key = (start_label, end_label) => `${start_label ?? `null`}_${end_label ?? `null`}`;
@@ -148,10 +151,10 @@ export function get_band_xaxis_ticks(band_struct, branches = []) {
148
151
  // Convert frequencies from THz to specified units.
149
152
  export function convert_frequencies(frequencies, unit = `THz`) {
150
153
  const conversion_factors = {
151
- 'THz': 1,
152
- 'eV': THz_TO_EV,
153
- 'meV': THz_TO_MEV,
154
- 'Ha': THz_TO_HA,
154
+ THz: 1,
155
+ eV: THz_TO_EV,
156
+ meV: THz_TO_MEV,
157
+ Ha: THz_TO_HA,
155
158
  'cm-1': THz_TO_CM,
156
159
  };
157
160
  const factor = conversion_factors[unit];
@@ -276,7 +279,9 @@ export function clear_smearing_cache() {
276
279
  }
277
280
  // Type guards for pymatgen qpoint formats
278
281
  const is_vec3 = (val) => Array.isArray(val) && val.length >= 3 && val.slice(0, 3).every(Number.isFinite);
279
- const is_kpoint = (val) => !!val && typeof val === `object` && `frac_coords` in val &&
282
+ const is_kpoint = (val) => !!val &&
283
+ typeof val === `object` &&
284
+ `frac_coords` in val &&
280
285
  is_vec3(val.frac_coords);
281
286
  const is_pymatgen_format = (obj) => {
282
287
  // Check for explicit pymatgen markers
@@ -369,19 +374,24 @@ function convert_pymatgen_band_structure(pmg) {
369
374
  const labels_dict = pmg.labels_dict;
370
375
  const lattice_rec = pmg.lattice_rec;
371
376
  // Determine unit: cm-1 if frequencies_cm present, else check explicit unit or default to THz
372
- const unit = pmg.unit?.toLowerCase() ??
373
- (has_frequencies_cm ? `cm-1` : `thz`);
374
- if (!Array.isArray(raw_qpts) || !Array.isArray(raw_bands) ||
375
- !raw_qpts.length || !raw_bands.length)
377
+ const unit = pmg.unit?.toLowerCase() ?? (has_frequencies_cm ? `cm-1` : `thz`);
378
+ if (!Array.isArray(raw_qpts) ||
379
+ !Array.isArray(raw_bands) ||
380
+ !raw_qpts.length ||
381
+ !raw_bands.length)
376
382
  return null;
377
- const qpoints = raw_qpts.map((q) => parse_qpoint(q, labels_dict)).filter((q) => q !== null);
383
+ const qpoints = raw_qpts
384
+ .map((q) => parse_qpoint(q, labels_dict))
385
+ .filter((q) => q !== null);
378
386
  if (!qpoints.length)
379
387
  return null;
380
388
  // Step distances and discontinuity detection (5x median threshold)
381
- const steps = qpoints.slice(1).map((q, idx) => euclidean_dist(qpoints[idx].frac_coords, q.frac_coords));
389
+ const steps = qpoints
390
+ .slice(1)
391
+ .map((q, idx) => euclidean_dist(qpoints[idx].frac_coords, q.frac_coords));
382
392
  const sorted = steps.slice().sort((a, b) => a - b);
383
393
  const threshold = (sorted[Math.floor(sorted.length / 2)] ?? 0) * 5;
384
- const disc_set = new Set(steps.map((s, idx) => s > threshold ? idx + 1 : -1).filter((i) => i >= 0));
394
+ const disc_set = new Set(steps.map((s, idx) => (s > threshold ? idx + 1 : -1)).filter((i) => i >= 0));
385
395
  // Cumulative distance (skip discontinuities)
386
396
  const distance = steps.reduce((acc, step, idx) => [...acc, disc_set.has(idx + 1) ? acc[idx] : acc[idx] + step], [0]);
387
397
  // Use pymatgen's branches if available - they correctly handle discontinuities
@@ -398,7 +408,7 @@ function convert_pymatgen_band_structure(pmg) {
398
408
  }
399
409
  // Fallback: infer branches from discontinuities when none provided or all invalid
400
410
  if (branches.length === 0) {
401
- console.info(`Band structure missing 'branches' field - inferring from path discontinuities`);
411
+ console.warn(`Band structure missing 'branches' field - inferring from path discontinuities`);
402
412
  // Discontinuity indices mark points where the path jumps (disc before that index)
403
413
  // Create continuous segments between discontinuities
404
414
  const disc_indices = [...disc_set].sort((a, b) => a - b);
@@ -444,7 +454,13 @@ function convert_pymatgen_band_structure(pmg) {
444
454
  spin_down_bands: converted_spin_down_bands,
445
455
  nb_bands: raw_bands.length,
446
456
  labels_dict: labels_dict ?? {},
447
- recip_lattice: { matrix: lattice_rec?.matrix ?? [[1, 0, 0], [0, 1, 0], [0, 0, 1]] },
457
+ recip_lattice: {
458
+ matrix: lattice_rec?.matrix ?? [
459
+ [1, 0, 0],
460
+ [0, 1, 0],
461
+ [0, 0, 1],
462
+ ],
463
+ },
448
464
  };
449
465
  }
450
466
  export function normalize_band_structure(bs) {
@@ -483,8 +499,7 @@ export function normalize_dos(dos, options = {}) {
483
499
  return null;
484
500
  const dos_obj = dos;
485
501
  // Check for pymatgen format (has @class or @module)
486
- const is_pymatgen = typeof dos_obj[`@class`] === `string` ||
487
- typeof dos_obj[`@module`] === `string`;
502
+ const is_pymatgen = typeof dos_obj[`@class`] === `string` || typeof dos_obj[`@module`] === `string`;
488
503
  const { frequencies, energies, spin_polarized } = dos_obj;
489
504
  // Handle densities as either array or dict with spin keys (pymatgen format)
490
505
  // Pymatgen stores densities as {1: [...], -1: [...]} or {"Spin.up": [...], ...}
@@ -493,8 +508,7 @@ export function normalize_dos(dos, options = {}) {
493
508
  return null;
494
509
  const densities = spin_channels.up;
495
510
  // Use extracted spin-down or fallback to explicit field (for already-normalized DosData)
496
- const spin_down_densities = spin_channels.down ??
497
- dos_obj.spin_down_densities ?? null;
511
+ const spin_down_densities = spin_channels.down ?? dos_obj.spin_down_densities ?? null;
498
512
  if (!Array.isArray(densities))
499
513
  return null;
500
514
  // Phonon DOS: has frequencies
@@ -509,7 +523,7 @@ export function normalize_dos(dos, options = {}) {
509
523
  if (auto_convert_units && max_freq > 100) {
510
524
  // Likely in cm⁻¹, convert to THz
511
525
  final_frequencies = frequencies.map((f) => f * CM_TO_THZ);
512
- console.info(`Phonon DOS frequencies appear to be in cm⁻¹ (max: ${max_freq.toFixed(1)}). ` +
526
+ console.warn(`Phonon DOS frequencies appear to be in cm⁻¹ (max: ${max_freq.toFixed(1)}). ` +
513
527
  `Converting to THz (max: ${(max_freq * CM_TO_THZ).toFixed(1)} THz).`);
514
528
  }
515
529
  return { type: `phonon`, frequencies: final_frequencies, densities };
@@ -525,9 +539,7 @@ export function normalize_dos(dos, options = {}) {
525
539
  type: `electronic`,
526
540
  energies,
527
541
  densities,
528
- spin_down_densities: is_spin_polarized
529
- ? spin_down_densities ?? undefined
530
- : undefined,
542
+ spin_down_densities: is_spin_polarized ? (spin_down_densities ?? undefined) : undefined,
531
543
  spin_polarized: is_spin_polarized,
532
544
  };
533
545
  }
@@ -558,11 +570,10 @@ export function extract_k_path_points(band_struct, recip_lattice_matrix, options
558
570
  y = centered_frac(y);
559
571
  z = centered_frac(z);
560
572
  }
561
- return [
562
- x * m00 + y * m10 + z * m20,
563
- x * m01 + y * m11 + z * m21,
564
- x * m02 + y * m12 + z * m22,
565
- ];
573
+ const kx = x * m00 + y * m10 + z * m20;
574
+ const ky = x * m01 + y * m11 + z * m21;
575
+ const kz = x * m02 + y * m12 + z * m22;
576
+ return [kx, ky, kz];
566
577
  });
567
578
  }
568
579
  // Find the q-point index closest to a given distance along the band structure path
@@ -638,7 +649,10 @@ export function find_qpoint_at_rescaled_x(band_struct, rescaled_x, x_positions)
638
649
  if (!segment_range)
639
650
  continue;
640
651
  const [x_start, x_end] = segment_range;
641
- for (const [x_pos, idx] of [[x_start, start_idx], [x_end, end_idx]]) {
652
+ for (const [x_pos, idx] of [
653
+ [x_start, start_idx],
654
+ [x_end, end_idx],
655
+ ]) {
642
656
  const dist = Math.abs(rescaled_x - x_pos);
643
657
  if (dist < min_dist) {
644
658
  min_dist = dist;
@@ -675,15 +689,12 @@ export function extract_pdos(dos, pdos_type, filter_keys) {
675
689
  const densities = spin_channels.up;
676
690
  if (!Array.isArray(densities) || energies.length !== densities.length)
677
691
  continue;
678
- const is_spin_polarized = spin_channels.down !== null &&
679
- spin_channels.down.length === densities.length;
692
+ const is_spin_polarized = spin_channels.down !== null && spin_channels.down.length === densities.length;
680
693
  result[key] = {
681
694
  type: `electronic`,
682
695
  energies,
683
696
  densities,
684
- spin_down_densities: is_spin_polarized
685
- ? spin_channels.down ?? undefined
686
- : undefined,
697
+ spin_down_densities: is_spin_polarized ? (spin_channels.down ?? undefined) : undefined,
687
698
  spin_polarized: is_spin_polarized,
688
699
  efermi: nested_dos.efermi,
689
700
  };
@@ -743,9 +754,7 @@ export function generate_ribbon_path(x_values, y_values, width_values, x_scale_f
743
754
  const x_px = x_scale_fn(x_values[idx]);
744
755
  const y_data = y_values[idx];
745
756
  const raw_width = width_values[idx] ?? 0;
746
- const width_normalized = Number.isFinite(raw_width) && raw_width > 0
747
- ? raw_width / max_width_val
748
- : 0;
757
+ const width_normalized = Number.isFinite(raw_width) && raw_width > 0 ? raw_width / max_width_val : 0;
749
758
  const half_width_px = width_normalized * max_width_px * scale;
750
759
  // In SVG, y increases downward, so upper edge has smaller y value
751
760
  const y_upper_px = y_scale_fn(y_data) - half_width_px;
@@ -757,7 +766,7 @@ export function generate_ribbon_path(x_values, y_values, width_values, x_scale_f
757
766
  const path_parts = [
758
767
  `M${upper_points[0]}`,
759
768
  ...upper_points.slice(1).map((pt) => `L${pt}`),
760
- ...lower_points.reverse().map((pt) => `L${pt}`),
769
+ ...lower_points.toReversed().map((pt) => `L${pt}`),
761
770
  `Z`,
762
771
  ];
763
772
  return path_parts.join(` `);
@@ -811,7 +820,8 @@ function is_electronic_band_struct(bs) {
811
820
  return true;
812
821
  }
813
822
  // Pymatgen @class: BandStructure* but not Phonon*
814
- const py_class_name = String(obj[`@class`] ?? ``);
823
+ const raw_class = obj[`@class`];
824
+ const py_class_name = typeof raw_class === `string` ? raw_class : ``;
815
825
  if (py_class_name.startsWith(`BandStructure`) && !py_class_name.includes(`Phonon`)) {
816
826
  return true;
817
827
  }
@@ -825,7 +835,8 @@ export function compute_frequency_range(band_structs, doses, padding_factor = 0.
825
835
  // (normalized structures always have qpoints, so we can't detect from them)
826
836
  let has_electronic_bs = false;
827
837
  // Support both qpoints (phonon) and kpoints (electronic) to detect single vs dict
828
- const is_single_bs = band_structs && typeof band_structs === `object` &&
838
+ const is_single_bs = band_structs &&
839
+ typeof band_structs === `object` &&
829
840
  (`qpoints` in band_structs || `kpoints` in band_structs);
830
841
  if (band_structs && typeof band_structs === `object`) {
831
842
  // Single structure check
@@ -887,7 +898,8 @@ export function compute_frequency_range(band_structs, doses, padding_factor = 0.
887
898
  }
888
899
  if (!Number.isFinite(min_val) || !Number.isFinite(max_val))
889
900
  return undefined;
890
- const clamp_min = is_phonon && min_val < 0 && // clamp phonon noise to 0
901
+ const clamp_min = is_phonon &&
902
+ min_val < 0 && // clamp phonon noise to 0
891
903
  negative_fraction(all_freqs) < IMAGINARY_MODE_NOISE_THRESHOLD;
892
904
  if (clamp_min)
893
905
  min_val = 0;
@@ -897,7 +909,7 @@ export function compute_frequency_range(band_structs, doses, padding_factor = 0.
897
909
  }
898
910
  // Parse axis label: "Frequency (THz)" → { name: "Frequency", unit: "THz" }
899
911
  function parse_axis_label(label) {
900
- const match = label.match(/^(.+?)\s*\(([^)]+)\)$/);
912
+ const match = /^(.+?)\s*\(([^)]+)\)$/.exec(label);
901
913
  return match ? { name: match[1], unit: match[2] } : { name: label };
902
914
  }
903
915
  // Format DOS tooltip content from axis labels and values
@@ -1,7 +1,7 @@
1
1
  import type { ChemicalElement, ElementCategory } from './element/types';
2
2
  import { DEFAULT_CATEGORY_COLORS, default_element_colors } from './colors';
3
3
  import type { Tooltip } from './plot';
4
- import type { ThemeMode, ThemeType } from './theme';
4
+ import { type ThemeMode, type ThemeType } from './theme';
5
5
  export declare const selected: {
6
6
  category: ElementCategory | null;
7
7
  element: ChemicalElement | null;
@@ -1,5 +1,6 @@
1
1
  import { AUTO_THEME, COLOR_THEMES, THEME_TYPE } from './theme/index';
2
2
  import { DEFAULT_CATEGORY_COLORS, default_element_colors } from './colors';
3
+ import { is_valid_theme_mode } from './theme';
3
4
  export const selected = $state({
4
5
  category: null,
5
6
  element: null,
@@ -22,8 +23,8 @@ let initial_system_mode = COLOR_THEMES.light;
22
23
  // Safe theme initialization for test environments
23
24
  try {
24
25
  if (typeof window !== `undefined` && globalThis.localStorage) {
25
- initial_theme_mode = localStorage.getItem(`matterviz-theme`) ||
26
- AUTO_THEME;
26
+ const saved_theme = localStorage.getItem(`matterviz-theme`) ?? ``;
27
+ initial_theme_mode = is_valid_theme_mode(saved_theme) ? saved_theme : AUTO_THEME;
27
28
  }
28
29
  else {
29
30
  initial_theme_mode = AUTO_THEME;
@@ -1,23 +1,62 @@
1
- <script lang="ts">import * as math from '../math';
2
- import { DEFAULTS } from '../settings';
3
- import { T } from '@threlte/core';
4
- import { Euler, Quaternion, Vector3 } from 'three';
5
- let { position, vector, scale = DEFAULTS.structure.force_scale, color = DEFAULTS.structure.force_color, shaft_radius = DEFAULTS.structure.force_shaft_radius, arrow_head_radius = DEFAULTS.structure.force_arrow_head_radius, arrow_head_length = DEFAULTS.structure.force_arrow_head_length, ...rest } = $props();
6
- const mag = $derived(Math.hypot(...vector));
7
- const dir = $derived(mag > math.EPS ? math.scale(vector, 1 / mag) : [0, 1, 0]);
8
- const vec_len = $derived(mag * scale);
9
- const head_len = $derived(arrow_head_length < 0 ? vec_len * -arrow_head_length : arrow_head_length);
10
- const shaft_len = $derived(Math.max(0, vec_len - head_len * 0.5));
11
- const shaft_r = $derived(shaft_radius < 0 ? shaft_len * -shaft_radius : shaft_radius);
12
- const head_r = $derived(arrow_head_radius < 0 ? shaft_len * -arrow_head_radius : arrow_head_radius);
13
- const shaft_pos = $derived(math.add(position, math.scale(dir, shaft_len * 0.5)));
14
- const head_pos = $derived(math.add(position, math.scale(dir, shaft_len + head_len * 0.5)));
15
- const rotation = $derived.by(() => {
16
- if (mag < math.EPS)
17
- return [0, 0, 0];
18
- const quat = new Quaternion().setFromUnitVectors(new Vector3(0, 1, 0), new Vector3(...dir));
19
- return new Euler().setFromQuaternion(quat).toArray().slice(0, 3);
20
- });
1
+ <script lang="ts">
2
+ import type { Vec3 } from '../math'
3
+ import * as math from '../math'
4
+ import { DEFAULTS } from '../settings'
5
+ import { T } from '@threlte/core'
6
+ import type { ComponentProps } from 'svelte'
7
+ import { Euler, Quaternion, Vector3 } from 'three'
8
+
9
+ let {
10
+ position,
11
+ vector,
12
+ scale = DEFAULTS.structure.vector_scale,
13
+ color = DEFAULTS.structure.vector_color,
14
+ shaft_radius = DEFAULTS.structure.vector_shaft_radius,
15
+ arrow_head_radius = DEFAULTS.structure.vector_arrow_head_radius,
16
+ arrow_head_length = DEFAULTS.structure.vector_arrow_head_length,
17
+ ...rest
18
+ }: ComponentProps<typeof T.Mesh> & {
19
+ position: Vec3
20
+ vector: Vec3
21
+ scale?: number
22
+ color?: string
23
+ shaft_radius?: number // negative = relative to length
24
+ arrow_head_radius?: number
25
+ arrow_head_length?: number
26
+ } = $props()
27
+
28
+ const mag = $derived(Math.hypot(...vector))
29
+ const dir = $derived(
30
+ mag > math.EPS ? math.scale(vector, 1 / mag) : ([0, 1, 0] as Vec3),
31
+ )
32
+ const vec_len = $derived(mag * scale)
33
+
34
+ const head_len = $derived(
35
+ arrow_head_length < 0 ? vec_len * -arrow_head_length : arrow_head_length,
36
+ )
37
+ const shaft_len = $derived(Math.max(0, vec_len - head_len * 0.5))
38
+ const shaft_r = $derived(
39
+ shaft_radius < 0 ? shaft_len * -shaft_radius : shaft_radius,
40
+ )
41
+ const head_r = $derived(
42
+ arrow_head_radius < 0 ? shaft_len * -arrow_head_radius : arrow_head_radius,
43
+ )
44
+
45
+ const shaft_pos = $derived(
46
+ math.add(position, math.scale(dir, shaft_len * 0.5)) as Vec3,
47
+ )
48
+ const head_pos = $derived(
49
+ math.add(position, math.scale(dir, shaft_len + head_len * 0.5)) as Vec3,
50
+ )
51
+
52
+ const rotation = $derived.by((): Vec3 => {
53
+ if (mag < math.EPS) return [0, 0, 0]
54
+ const quat = new Quaternion().setFromUnitVectors(
55
+ new Vector3(0, 1, 0),
56
+ new Vector3(...dir),
57
+ )
58
+ return new Euler().setFromQuaternion(quat).toArray().slice(0, 3) as Vec3
59
+ })
21
60
  </script>
22
61
 
23
62
  {#if shaft_len > 0.01}