matterviz 0.3.5 → 0.3.7

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 (229) hide show
  1. package/dist/MillerIndexInput.svelte +5 -5
  2. package/dist/api/optimade.js +3 -3
  3. package/dist/brillouin/BrillouinZone.svelte +5 -2
  4. package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
  5. package/dist/brillouin/BrillouinZoneExportPane.svelte +1 -3
  6. package/dist/brillouin/BrillouinZoneInfoPane.svelte +1 -1
  7. package/dist/brillouin/BrillouinZoneScene.svelte +5 -5
  8. package/dist/brillouin/compute.js +21 -21
  9. package/dist/brillouin/index.d.ts +1 -1
  10. package/dist/brillouin/index.js +0 -1
  11. package/dist/brillouin/types.d.ts +8 -13
  12. package/dist/chempot-diagram/ChemPotDiagram.svelte +3 -3
  13. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +3 -4
  14. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +33 -34
  15. package/dist/chempot-diagram/compute.js +1 -7
  16. package/dist/chempot-diagram/temperature.d.ts +1 -1
  17. package/dist/chempot-diagram/temperature.js +1 -3
  18. package/dist/chempot-diagram/types.d.ts +4 -9
  19. package/dist/colors/index.js +5 -5
  20. package/dist/composition/Composition.svelte +2 -1
  21. package/dist/composition/Formula.svelte +7 -4
  22. package/dist/composition/FormulaFilter.svelte +1 -3
  23. package/dist/composition/format.js +4 -4
  24. package/dist/composition/parse.d.ts +2 -1
  25. package/dist/composition/parse.js +61 -46
  26. package/dist/convex-hull/ConvexHull2D.svelte +62 -51
  27. package/dist/convex-hull/ConvexHull3D.svelte +101 -90
  28. package/dist/convex-hull/ConvexHull4D.svelte +70 -58
  29. package/dist/convex-hull/ConvexHullControls.svelte +24 -35
  30. package/dist/convex-hull/ConvexHullInfoPane.svelte +8 -5
  31. package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +2 -0
  32. package/dist/convex-hull/ConvexHullStats.svelte +9 -2
  33. package/dist/convex-hull/ConvexHullStats.svelte.d.ts +2 -0
  34. package/dist/convex-hull/GasPressureControls.svelte +7 -7
  35. package/dist/convex-hull/StructurePopup.svelte +65 -30
  36. package/dist/convex-hull/StructurePopup.svelte.d.ts +6 -6
  37. package/dist/convex-hull/TemperatureSlider.svelte +8 -5
  38. package/dist/convex-hull/barycentric-coords.d.ts +2 -2
  39. package/dist/convex-hull/barycentric-coords.js +2 -2
  40. package/dist/convex-hull/gas-thermodynamics.js +2 -4
  41. package/dist/convex-hull/helpers.d.ts +13 -2
  42. package/dist/convex-hull/helpers.js +37 -16
  43. package/dist/convex-hull/index.d.ts +1 -0
  44. package/dist/convex-hull/index.js +1 -0
  45. package/dist/convex-hull/thermodynamics.d.ts +2 -1
  46. package/dist/convex-hull/thermodynamics.js +7 -7
  47. package/dist/convex-hull/types.d.ts +15 -15
  48. package/dist/effects.svelte.d.ts +12 -0
  49. package/dist/effects.svelte.js +37 -0
  50. package/dist/element/BohrAtom.svelte +4 -4
  51. package/dist/element/data.json.gz.d.ts +3 -1
  52. package/dist/element/index.d.ts +1 -1
  53. package/dist/element/index.js +0 -1
  54. package/dist/fermi-surface/FermiSurface.svelte +4 -4
  55. package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
  56. package/dist/fermi-surface/FermiSurfaceControls.svelte +15 -19
  57. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
  58. package/dist/fermi-surface/FermiSurfaceScene.svelte +8 -6
  59. package/dist/fermi-surface/compute.js +2 -2
  60. package/dist/fermi-surface/export.js +13 -26
  61. package/dist/fermi-surface/parse.js +8 -12
  62. package/dist/fermi-surface/types.d.ts +2 -5
  63. package/dist/heatmap-matrix/HeatmapMatrix.svelte +21 -3
  64. package/dist/heatmap-matrix/index.js +6 -6
  65. package/dist/io/decompress.d.ts +2 -1
  66. package/dist/io/decompress.js +1 -1
  67. package/dist/io/export.js +1 -1
  68. package/dist/io/index.d.ts +1 -1
  69. package/dist/io/index.js +0 -1
  70. package/dist/io/url-drop.js +7 -1
  71. package/dist/isosurface/IsosurfaceControls.svelte +11 -25
  72. package/dist/isosurface/slice.js +1 -1
  73. package/dist/isosurface/types.js +12 -12
  74. package/dist/labels.d.ts +1 -1
  75. package/dist/labels.js +14 -11
  76. package/dist/layout/InfoTag.svelte +6 -4
  77. package/dist/layout/PropertyFilter.svelte +4 -2
  78. package/dist/layout/json-tree/JsonTree.svelte +22 -14
  79. package/dist/layout/json-tree/JsonValue.svelte +2 -2
  80. package/dist/layout/json-tree/types.d.ts +3 -2
  81. package/dist/layout/json-tree/types.js +0 -1
  82. package/dist/layout/json-tree/utils.d.ts +4 -4
  83. package/dist/layout/json-tree/utils.js +12 -20
  84. package/dist/marching-cubes.js +13 -15
  85. package/dist/math.d.ts +11 -1
  86. package/dist/math.js +15 -6
  87. package/dist/overlays/DragControlTab.svelte +98 -0
  88. package/dist/overlays/DragControlTab.svelte.d.ts +8 -0
  89. package/dist/overlays/DraggablePane.svelte +7 -84
  90. package/dist/overlays/index.d.ts +1 -0
  91. package/dist/overlays/index.js +1 -0
  92. package/dist/periodic-table/PeriodicTable.svelte +11 -11
  93. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +4 -2
  94. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
  95. package/dist/phase-diagram/PhaseDiagramControls.svelte +4 -9
  96. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
  97. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +2 -10
  98. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +2 -3
  99. package/dist/phase-diagram/TdbInfoPanel.svelte +3 -3
  100. package/dist/phase-diagram/build-diagram.js +11 -18
  101. package/dist/phase-diagram/diagram-input.d.ts +5 -9
  102. package/dist/phase-diagram/index.d.ts +2 -2
  103. package/dist/phase-diagram/index.js +0 -2
  104. package/dist/phase-diagram/parse.d.ts +2 -2
  105. package/dist/phase-diagram/parse.js +6 -10
  106. package/dist/phase-diagram/svg-to-diagram.js +15 -15
  107. package/dist/phase-diagram/types.d.ts +5 -11
  108. package/dist/phase-diagram/utils.d.ts +2 -2
  109. package/dist/phase-diagram/utils.js +9 -11
  110. package/dist/plot/BarPlot.svelte +162 -314
  111. package/dist/plot/BarPlot.svelte.d.ts +5 -4
  112. package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
  113. package/dist/plot/BinnedScatterPlot.svelte +1114 -0
  114. package/dist/plot/BinnedScatterPlot.svelte.d.ts +66 -0
  115. package/dist/plot/ColorBar.svelte +19 -17
  116. package/dist/plot/ColorBar.svelte.d.ts +1 -1
  117. package/dist/plot/FillArea.svelte +2 -4
  118. package/dist/plot/FillArea.svelte.d.ts +1 -1
  119. package/dist/plot/Histogram.svelte +167 -281
  120. package/dist/plot/Histogram.svelte.d.ts +1 -1
  121. package/dist/plot/HistogramControls.svelte.d.ts +1 -1
  122. package/dist/plot/InteractiveAxisLabel.svelte +5 -3
  123. package/dist/plot/InteractiveAxisLabel.svelte.d.ts +1 -1
  124. package/dist/plot/PlotAxis.svelte +169 -0
  125. package/dist/plot/PlotAxis.svelte.d.ts +24 -0
  126. package/dist/plot/PlotControls.svelte.d.ts +1 -1
  127. package/dist/plot/ReferenceLine3D.svelte +53 -51
  128. package/dist/plot/ReferencePlane.svelte +39 -42
  129. package/dist/plot/ScatterPlot.svelte +300 -367
  130. package/dist/plot/ScatterPlot.svelte.d.ts +8 -5
  131. package/dist/plot/ScatterPlot3D.svelte +33 -6
  132. package/dist/plot/ScatterPlot3D.svelte.d.ts +3 -2
  133. package/dist/plot/ScatterPlot3DControls.svelte +9 -9
  134. package/dist/plot/ScatterPlotControls.svelte +3 -4
  135. package/dist/plot/ScatterPoint.svelte +18 -27
  136. package/dist/plot/ScatterPoint.svelte.d.ts +4 -3
  137. package/dist/plot/Surface3D.svelte +4 -7
  138. package/dist/plot/ZeroLines.svelte +2 -1
  139. package/dist/plot/ZeroLines.svelte.d.ts +2 -1
  140. package/dist/plot/ZoomRect.svelte +2 -2
  141. package/dist/plot/ZoomRect.svelte.d.ts +3 -3
  142. package/dist/plot/adaptive-density.d.ts +69 -0
  143. package/dist/plot/adaptive-density.js +191 -0
  144. package/dist/plot/auto-place.d.ts +43 -0
  145. package/dist/plot/auto-place.js +122 -0
  146. package/dist/plot/axis-utils.js +3 -5
  147. package/dist/plot/binned-scatter-types.d.ts +59 -0
  148. package/dist/plot/binned-scatter-types.js +1 -0
  149. package/dist/plot/data-cleaning.js +1 -1
  150. package/dist/plot/data-transform.js +1 -1
  151. package/dist/plot/fill-utils.d.ts +4 -9
  152. package/dist/plot/fill-utils.js +29 -44
  153. package/dist/plot/index.d.ts +4 -0
  154. package/dist/plot/index.js +2 -0
  155. package/dist/plot/interactions.d.ts +4 -4
  156. package/dist/plot/interactions.js +4 -3
  157. package/dist/plot/layout.d.ts +20 -2
  158. package/dist/plot/layout.js +59 -16
  159. package/dist/plot/reference-line.d.ts +1 -1
  160. package/dist/plot/reference-line.js +9 -11
  161. package/dist/plot/scales.d.ts +1 -1
  162. package/dist/plot/scales.js +20 -23
  163. package/dist/plot/types.d.ts +30 -58
  164. package/dist/plot/types.js +2 -6
  165. package/dist/plot/utils/label-placement.d.ts +24 -3
  166. package/dist/plot/utils/label-placement.js +82 -12
  167. package/dist/plot/utils/series-visibility.d.ts +8 -2
  168. package/dist/plot/utils/series-visibility.js +23 -5
  169. package/dist/rdf/RdfPlot.svelte +5 -5
  170. package/dist/rdf/calc-rdf.js +3 -3
  171. package/dist/sanitize.d.ts +2 -0
  172. package/dist/sanitize.js +2 -0
  173. package/dist/spectral/Bands.svelte +1 -1
  174. package/dist/spectral/BandsAndDos.svelte +22 -16
  175. package/dist/spectral/BrillouinBandsDos.svelte +20 -16
  176. package/dist/spectral/Dos.svelte +1 -1
  177. package/dist/spectral/helpers.d.ts +4 -2
  178. package/dist/spectral/helpers.js +44 -35
  179. package/dist/spectral/index.d.ts +1 -1
  180. package/dist/spectral/index.js +0 -1
  181. package/dist/structure/AtomLegend.svelte +23 -6
  182. package/dist/structure/AtomLegend.svelte.d.ts +1 -0
  183. package/dist/structure/CanvasTooltip.svelte +9 -9
  184. package/dist/structure/CanvasTooltip.svelte.d.ts +1 -1
  185. package/dist/structure/CellSelect.svelte +14 -16
  186. package/dist/structure/Structure.svelte +317 -68
  187. package/dist/structure/Structure.svelte.d.ts +4 -2
  188. package/dist/structure/StructureControls.svelte +20 -45
  189. package/dist/structure/StructureExportPane.svelte +2 -1
  190. package/dist/structure/StructureInfoPane.svelte +10 -8
  191. package/dist/structure/StructureScene.svelte +527 -177
  192. package/dist/structure/StructureScene.svelte.d.ts +5 -2
  193. package/dist/structure/atom-properties.js +4 -4
  194. package/dist/structure/bond-order-perception.js +115 -98
  195. package/dist/structure/bonding.d.ts +27 -1
  196. package/dist/structure/bonding.js +187 -16
  197. package/dist/structure/export.js +1 -1
  198. package/dist/structure/index.d.ts +3 -2
  199. package/dist/structure/index.js +0 -2
  200. package/dist/structure/parse.js +88 -59
  201. package/dist/symmetry/WyckoffTable.svelte +7 -0
  202. package/dist/symmetry/index.js +13 -14
  203. package/dist/table/HeatmapTable.svelte +45 -66
  204. package/dist/table/HeatmapTable.svelte.d.ts +1 -1
  205. package/dist/table/ToggleMenu.svelte +19 -10
  206. package/dist/theme/themes.mjs +12 -0
  207. package/dist/tooltip/index.d.ts +1 -1
  208. package/dist/tooltip/index.js +0 -1
  209. package/dist/trajectory/Trajectory.svelte +43 -15
  210. package/dist/trajectory/TrajectoryInfoPane.svelte +2 -2
  211. package/dist/trajectory/extract.js +1 -1
  212. package/dist/trajectory/frame-reader.js +4 -4
  213. package/dist/trajectory/helpers.d.ts +5 -4
  214. package/dist/trajectory/helpers.js +9 -17
  215. package/dist/trajectory/index.d.ts +2 -2
  216. package/dist/trajectory/index.js +2 -2
  217. package/dist/trajectory/parse/ase.js +4 -4
  218. package/dist/trajectory/parse/hdf5.js +1 -1
  219. package/dist/trajectory/parse/index.js +2 -3
  220. package/dist/trajectory/parse/lammps.js +1 -1
  221. package/dist/trajectory/parse/vasp.js +1 -1
  222. package/dist/trajectory/plotting.d.ts +1 -1
  223. package/dist/trajectory/plotting.js +38 -38
  224. package/dist/trajectory/types.d.ts +1 -1
  225. package/dist/utils.d.ts +1 -0
  226. package/dist/utils.js +9 -0
  227. package/dist/xrd/calc-xrd.js +3 -4
  228. package/dist/xrd/parse.js +1 -1
  229. package/package.json +42 -22
@@ -80,7 +80,7 @@ export function get_trajectory_stats(trajectory) {
80
80
  const frame_count = total_frames || frames.length;
81
81
  const stats = {
82
82
  frame_count,
83
- is_indexed: trajectory.is_indexed || false,
83
+ is_indexed: trajectory.is_indexed ?? false,
84
84
  };
85
85
  if (frames.length > 0) {
86
86
  const [first_frame, last_frame] = [frames[0], frames.at(-1) ?? frames[0]];
@@ -98,7 +98,7 @@ export function get_trajectory_stats(trajectory) {
98
98
  return result;
99
99
  })();
100
100
  const counts = sampled.map((frame) => frame.structure.sites.length);
101
- const constant = counts.every((c) => c === counts[0]);
101
+ const constant = counts.every((count) => count === counts[0]);
102
102
  const all_counts = constant
103
103
  ? [first_frame.structure.sites.length]
104
104
  : frames.map((frame) => frame.structure.sites.length);
@@ -31,11 +31,11 @@ export function parse_ase_trajectory(buffer, filename) {
31
31
  continue;
32
32
  }
33
33
  const frame_data = JSON.parse(new TextDecoder().decode(new Uint8Array(buffer, offset, json_length)));
34
- const positions_ref = frame_data[`positions.`] || frame_data.positions;
34
+ const positions_ref = frame_data[`positions.`] ?? frame_data.positions;
35
35
  const positions = positions_ref?.ndarray
36
36
  ? read_ndarray_from_view(view, positions_ref)
37
37
  : positions_ref;
38
- const numbers_ref = frame_data[`numbers.`] || frame_data.numbers || global_numbers;
38
+ const numbers_ref = frame_data[`numbers.`] ?? frame_data.numbers ?? global_numbers;
39
39
  const numbers = numbers_ref?.ndarray
40
40
  ? read_ndarray_from_view(view, numbers_ref).flat()
41
41
  : numbers_ref;
@@ -47,7 +47,7 @@ export function parse_ase_trajectory(buffer, filename) {
47
47
  }
48
48
  const elements = convert_atomic_numbers(numbers);
49
49
  const metadata = { step: idx, ...frame_data.calculator, ...frame_data.info };
50
- frames.push(create_trajectory_frame(positions, elements, frame_data.cell ? validate_3x3_matrix(frame_data.cell) : undefined, frame_data.pbc || [true, true, true], idx, metadata));
50
+ frames.push(create_trajectory_frame(positions, elements, frame_data.cell ? validate_3x3_matrix(frame_data.cell) : undefined, frame_data.pbc ?? [true, true, true], idx, metadata));
51
51
  }
52
52
  catch (error) {
53
53
  console.warn(`Error processing frame ${idx + 1}/${n_items}:`, error);
@@ -66,7 +66,7 @@ export function parse_ase_trajectory(buffer, filename) {
66
66
  filename,
67
67
  source_format: `ase_trajectory`,
68
68
  frame_count: frames.length,
69
- total_atoms: global_numbers?.length || 0,
69
+ total_atoms: global_numbers?.length ?? 0,
70
70
  periodic_boundary_conditions,
71
71
  };
72
72
  return { frames, metadata };
@@ -25,7 +25,7 @@ export async function parse_torch_sim_hdf5(buffer, filename) {
25
25
  const item = parent.get(name);
26
26
  const full_path = path ? `${path}/${name}` : `/${name}`;
27
27
  if (names.includes(name) && is_hdf5_dataset(item)) {
28
- const found_name = names.find((n) => n === name);
28
+ const found_name = names.find((dataset_name) => dataset_name === name);
29
29
  if (found_name)
30
30
  found_paths[found_name] = full_path;
31
31
  return item;
@@ -19,9 +19,8 @@ export async function parse_trajectory_data(data, filename, atom_type_mapping) {
19
19
  if (data instanceof ArrayBuffer) {
20
20
  if (FORMAT_PATTERNS.ase(data, filename))
21
21
  return parse_ase_trajectory(data, filename);
22
- if (FORMAT_PATTERNS.hdf5(data, filename)) {
23
- return await parse_torch_sim_hdf5(data, filename);
24
- }
22
+ if (FORMAT_PATTERNS.hdf5(data, filename))
23
+ return parse_torch_sim_hdf5(data, filename);
25
24
  throw new Error(`Unsupported binary format${filename ? `: ${filename}` : ``}`);
26
25
  }
27
26
  if (typeof data === `string`) {
@@ -1,6 +1,7 @@
1
1
  import { ELEM_SYMBOLS } from '../../labels';
2
2
  import * as math from '../../math';
3
3
  import { coerce_element_symbol, create_trajectory_frame } from '../helpers';
4
+ const is_periodic = (token) => token.toLowerCase().startsWith(`p`);
4
5
  // Parse LAMMPS box bounds → lattice matrix. Handles orthogonal and triclinic boxes.
5
6
  // Triclinic: converts bounding box to actual dims per https://docs.lammps.org/Howto_triclinic.html
6
7
  // Lattice vectors: a=(lx,0,0), b=(xy,ly,0), c=(xz,yz,lz)
@@ -70,7 +71,6 @@ export function parse_lammps_trajectory(content, filename, atom_type_mapping) {
70
71
  const box_header = read_line();
71
72
  const is_triclinic = /BOX BOUNDS\s+xy\s+xz\s+yz/i.test(box_header);
72
73
  const tokens = box_header.replace(`ITEM: BOX BOUNDS`, ``).trim().split(/\s+/).slice(-3);
73
- const is_periodic = (tok) => tok.toLowerCase().startsWith(`p`);
74
74
  const pbc = tokens.length === 3
75
75
  ? [is_periodic(tokens[0]), is_periodic(tokens[1]), is_periodic(tokens[2])]
76
76
  : [true, true, true];
@@ -10,7 +10,7 @@ export function parse_vasp_xdatcar(content, filename) {
10
10
  const lattice_matrix = validate_3x3_matrix(lines.slice(2, 5).map((line) => line
11
11
  .trim()
12
12
  .split(/\s+/)
13
- .map((x) => parseFloat(x) * scale)));
13
+ .map((component) => parseFloat(component) * scale)));
14
14
  const element_names = lines[5].trim().split(/\s+/);
15
15
  const element_counts = lines[6].trim().split(/\s+/).map(Number);
16
16
  if (element_names.length !== element_counts.length) {
@@ -1,4 +1,4 @@
1
- import type { DataSeries } from '../plot';
1
+ import type { DataSeries } from '../plot/types';
2
2
  import type { TrajectoryDataExtractor, TrajectoryMetadata, TrajectoryType } from './index';
3
3
  export interface PlotSeriesOptions {
4
4
  property_config?: Record<string, {
@@ -49,8 +49,8 @@ function extract_property_statistics(trajectory, data_extractor) {
49
49
  // Convert to final format with variation detection
50
50
  const result = new Map();
51
51
  for (const [key, stat] of property_stats) {
52
- const n = stat.values.length;
53
- if (n <= 1)
52
+ const n_values = stat.values.length;
53
+ if (n_values <= 1)
54
54
  continue;
55
55
  const coefficient_of_variation = get_coefficient_of_variation(stat.values);
56
56
  const lower_key = key.toLowerCase();
@@ -74,18 +74,18 @@ function create_series_from_stats(property_stats, property_config, colors) {
74
74
  for (const [key, stat] of property_stats) {
75
75
  if (!stat)
76
76
  continue;
77
- const n = stat.values.length;
77
+ const n_values = stat.values.length;
78
78
  const { clean_label, unit } = extract_label_and_unit(key, property_config);
79
79
  const color = colors[color_idx % colors.length];
80
80
  all_series.push({
81
- x: Array.from({ length: n }, (_, idx) => idx),
81
+ x: Array.from({ length: n_values }, (_, idx) => idx),
82
82
  y: stat.values,
83
83
  label: clean_label,
84
84
  unit,
85
85
  y_axis: `y1`, // Will be reassigned
86
86
  visible: false, // Will be assigned
87
- markers: n < 30 ? `line+points` : `line`,
88
- metadata: Array(n).fill({
87
+ markers: n_values < 30 ? `line+points` : `line`,
88
+ metadata: Array(n_values).fill({
89
89
  series_label: unit ? `${clean_label} (${unit})` : clean_label,
90
90
  property_key: key, // Store original property key for robust lookups
91
91
  }),
@@ -119,7 +119,7 @@ function group_and_assign_series(series, default_visible_properties) {
119
119
  })
120
120
  .sort((a, b) => a.priority - b.priority);
121
121
  // Apply 2-group visibility limit
122
- const visible_groups = groups.filter((g) => g.is_visible);
122
+ const visible_groups = groups.filter((group) => group.is_visible);
123
123
  if (visible_groups.length > 2) {
124
124
  // Keep only first 2 (highest priority)
125
125
  groups.forEach((group) => {
@@ -133,7 +133,7 @@ function group_and_assign_series(series, default_visible_properties) {
133
133
  }
134
134
  // Apply group assignments to individual series
135
135
  function apply_group_assignments(series, unit_groups) {
136
- const visible_groups = unit_groups.filter((g) => g.is_visible);
136
+ const visible_groups = unit_groups.filter((group) => group.is_visible);
137
137
  const axis_map = new Map();
138
138
  // Assign axes
139
139
  if (visible_groups.length === 1) {
@@ -145,10 +145,10 @@ function apply_group_assignments(series, unit_groups) {
145
145
  }
146
146
  // Apply to series
147
147
  for (const srs of series) {
148
- const group = unit_groups.find((g) => g.series.includes(srs));
148
+ const group = unit_groups.find((unit_group) => unit_group.series.includes(srs));
149
149
  if (group) {
150
150
  srs.visible = group.is_visible;
151
- srs.y_axis = axis_map.get(group) || `y1`;
151
+ srs.y_axis = axis_map.get(group) ?? `y1`;
152
152
  }
153
153
  }
154
154
  }
@@ -209,7 +209,7 @@ export function toggle_series_visibility(series, target_series_idx) {
209
209
  const new_visibility = !target_series.visible;
210
210
  // Create unit groups from current state
211
211
  const unit_groups = create_unit_groups_from_series(series);
212
- const target_group = unit_groups.find((g) => g.series.includes(target_series));
212
+ const target_group = unit_groups.find((group) => group.series.includes(target_series));
213
213
  if (!target_group)
214
214
  return series;
215
215
  // Start with updating the target series visibility
@@ -262,8 +262,8 @@ function update_group_visibility_and_axes(series, unit_groups) {
262
262
  group.is_visible = group.series.some((srs1) => series.find((srs2) => srs2.label === srs1.label && srs2.unit === srs1.unit)?.visible);
263
263
  }
264
264
  // Apply 2-group limit
265
- if (unit_groups.filter((g) => g.is_visible).length > 2) {
266
- for (const group of unit_groups.filter((g) => g.is_visible).slice(2)) {
265
+ if (unit_groups.filter((unit_group) => unit_group.is_visible).length > 2) {
266
+ for (const group of unit_groups.filter((unit_group) => unit_group.is_visible).slice(2)) {
267
267
  group.is_visible = false;
268
268
  for (const srs1 of group.series) {
269
269
  const idx = series.findIndex((srs2) => srs2.label === srs1.label && srs2.unit === srs1.unit);
@@ -283,7 +283,7 @@ function update_group_visibility_and_axes(series, unit_groups) {
283
283
  axis_map.set(final_visible[1], `y2`);
284
284
  // Apply to series
285
285
  for (const [idx, srs] of series.entries()) {
286
- const group = unit_groups.find((g) => g.series.some((gs) => gs.label === srs.label && gs.unit === srs.unit));
286
+ const group = unit_groups.find((unit_group) => unit_group.series.some((member) => member.label === srs.label && member.unit === srs.unit));
287
287
  if (group && axis_map.has(group)) {
288
288
  series[idx] = { ...srs, y_axis: axis_map.get(group) };
289
289
  }
@@ -311,30 +311,30 @@ export function should_hide_plot(trajectory, plot_series, tolerance = 1e-10) {
311
311
  return valid_values.every((value) => Math.abs(value - first_valid) <= tolerance);
312
312
  });
313
313
  }
314
+ function get_axis_label(axis_series) {
315
+ const visible_series = axis_series.filter((srs) => srs.visible);
316
+ if (!visible_series.length)
317
+ return `Value`;
318
+ const unit_groups = new Map();
319
+ visible_series.forEach((srs) => {
320
+ const unit = srs.unit || ``;
321
+ const label = srs.label || `Value`;
322
+ if (!unit_groups.has(unit))
323
+ unit_groups.set(unit, []);
324
+ const group = unit_groups.get(unit);
325
+ if (group)
326
+ group.push(label);
327
+ });
328
+ const unit_entries = Array.from(unit_groups.entries());
329
+ if (!unit_entries.length)
330
+ return `Value`;
331
+ const [unit, labels] = unit_entries[0];
332
+ const unique_labels = [...new Set(labels)].sort().join(` / `);
333
+ return unit ? `${unique_labels} (${unit})` : unique_labels;
334
+ }
314
335
  export function generate_axis_labels(plot_series) {
315
336
  if (!plot_series.length)
316
337
  return { y1: `Value`, y2: `Value` };
317
- const get_axis_label = (axis_series) => {
318
- const visible_series = axis_series.filter((srs) => srs.visible);
319
- if (!visible_series.length)
320
- return `Value`;
321
- const unit_groups = new Map();
322
- visible_series.forEach((srs) => {
323
- const unit = srs.unit || ``;
324
- const label = srs.label || `Value`;
325
- if (!unit_groups.has(unit))
326
- unit_groups.set(unit, []);
327
- const group = unit_groups.get(unit);
328
- if (group)
329
- group.push(label);
330
- });
331
- const unit_entries = Array.from(unit_groups.entries());
332
- if (!unit_entries.length)
333
- return `Value`;
334
- const [unit, labels] = unit_entries[0];
335
- const unique_labels = [...new Set(labels)].sort().join(` / `);
336
- return unit ? `${unique_labels} (${unit})` : unique_labels;
337
- };
338
338
  return {
339
339
  y1: get_axis_label(plot_series.filter((srs) => (srs.y_axis ?? `y1`) === `y1`)),
340
340
  y2: get_axis_label(plot_series.filter((srs) => srs.y_axis === `y2`)),
@@ -362,7 +362,7 @@ export function generate_streaming_plot_series(metadata_list, options = {}) {
362
362
  if (data_points.length < 2)
363
363
  continue;
364
364
  const is_energy = property_key.toLowerCase() === `energy`;
365
- if (!is_energy && !has_significant_variation(data_points.map((p) => p.y)))
365
+ if (!is_energy && !has_significant_variation(data_points.map((point) => point.y)))
366
366
  continue;
367
367
  const { clean_label, unit } = extract_label_and_unit(property_key, property_config);
368
368
  const is_visible = is_default_visible(property_key, default_visible_properties) || color_idx < 2;
@@ -370,8 +370,8 @@ export function generate_streaming_plot_series(metadata_list, options = {}) {
370
370
  if (is_visible)
371
371
  visible_props.push({ property: property_key, unit });
372
372
  all_series.push({
373
- x: data_points.map((p) => p.x),
374
- y: data_points.map((p) => p.y),
373
+ x: data_points.map((point) => point.x),
374
+ y: data_points.map((point) => point.y),
375
375
  label: clean_label,
376
376
  unit,
377
377
  y_axis: determine_axis_from_groups(property_key, unit, visible_props),
@@ -1,4 +1,4 @@
1
- import type { ElementSymbol } from '../element';
1
+ import type { ElementSymbol } from '../element/types';
2
2
  export type AtomTypeMapping = Record<number, ElementSymbol>;
3
3
  export interface LoadingOptions {
4
4
  use_indexing?: boolean;
package/dist/utils.d.ts CHANGED
@@ -2,4 +2,5 @@ export declare function merge_nested<T extends Record<string, unknown>>(obj1: T,
2
2
  export declare const escape_html: (unsafe_string: string) => string;
3
3
  export declare const normalize_unicode_minus: (value: string) => string;
4
4
  export declare const normalize_scientific_notation: (value: string) => string;
5
+ export declare function make_change_detector(): (value: unknown) => boolean;
5
6
  export declare function decode_url_safe_base64(encoded: string): string | undefined;
package/dist/utils.js CHANGED
@@ -21,6 +21,15 @@ export const escape_html = (unsafe_string) => unsafe_string
21
21
  export const normalize_unicode_minus = (value) => value.replace(/−/g, `-`);
22
22
  // Normalize scientific notation variants (d/D exponent, Mathematica *^).
23
23
  export const normalize_scientific_notation = (value) => normalize_unicode_minus(value).toLowerCase().replace(/d/g, `e`).replace(/\*\^/g, `e`);
24
+ export function make_change_detector() {
25
+ const unset = Symbol();
26
+ let prev = unset;
27
+ return (value) => {
28
+ const changed = prev !== unset && value !== prev;
29
+ prev = value;
30
+ return changed;
31
+ };
32
+ }
24
33
  // Decode a URL-safe base64 string (RFC 4648 §5) to its original text.
25
34
  // Converts `-` → `+`, `_` → `/`, restores padding, then decodes.
26
35
  // Returns undefined if decoding fails.
@@ -33,9 +33,7 @@ export const WAVELENGTHS = {
33
33
  AgKb1: 0.497082,
34
34
  };
35
35
  // Type guard to safely check if a string is a valid RadiationKey
36
- function is_radiation_key(key) {
37
- return key in WAVELENGTHS;
38
- }
36
+ const is_radiation_key = (key) => key in WAVELENGTHS;
39
37
  // Tolerances from pymatgen.analysis.diffraction.core
40
38
  const TWO_THETA_TOL = 1e-5;
41
39
  const SCALED_INTENSITY_TOL = 1e-3;
@@ -296,7 +294,8 @@ wavelength) {
296
294
  buffer_content = content;
297
295
  }
298
296
  else {
299
- buffer_content = new Uint8Array(content).buffer;
297
+ buffer_content =
298
+ content instanceof ArrayBuffer ? content : new Uint8Array(content).slice().buffer;
300
299
  }
301
300
  const pattern = await parse_xrd_file(buffer_content, filename);
302
301
  if (pattern && pattern.x.length > 0) {
package/dist/xrd/parse.js CHANGED
@@ -734,7 +734,7 @@ export async function parse_xrd_file(content, filename) {
734
734
  return parse_xrdml_file(get_text());
735
735
  // Binary formats
736
736
  if (ext === `brml`)
737
- return await parse_brml_file(get_buffer()); // async due to lazy fflate import
737
+ return parse_brml_file(get_buffer()); // async due to lazy fflate import
738
738
  if (ext === `raw`)
739
739
  return parse_bruker_raw_file(get_buffer());
740
740
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matterviz",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "description": "Interactive visualizations for materials science: periodic tables, 3D structures, MD trajectories, heatmaps, scatter plots.",
5
5
  "keywords": [
6
6
  "chemistry",
@@ -49,6 +49,10 @@
49
49
  "types": "./dist/colors/index.d.ts",
50
50
  "default": "./dist/colors/index.js"
51
51
  },
52
+ "./coordination": {
53
+ "types": "./dist/coordination/index.d.ts",
54
+ "default": "./dist/coordination/index.js"
55
+ },
52
56
  "./element": {
53
57
  "types": "./dist/element/index.d.ts",
54
58
  "default": "./dist/element/index.js"
@@ -61,10 +65,18 @@
61
65
  "types": "./dist/fermi-surface/index.d.ts",
62
66
  "default": "./dist/fermi-surface/index.js"
63
67
  },
68
+ "./heatmap-matrix": {
69
+ "types": "./dist/heatmap-matrix/index.d.ts",
70
+ "default": "./dist/heatmap-matrix/index.js"
71
+ },
64
72
  "./io": {
65
73
  "types": "./dist/io/index.d.ts",
66
74
  "default": "./dist/io/index.js"
67
75
  },
76
+ "./isosurface": {
77
+ "types": "./dist/isosurface/index.d.ts",
78
+ "default": "./dist/isosurface/index.js"
79
+ },
68
80
  "./labels": {
69
81
  "types": "./dist/labels.d.ts",
70
82
  "default": "./dist/labels.js"
@@ -82,8 +94,8 @@
82
94
  "default": "./dist/overlays/index.js"
83
95
  },
84
96
  "./periodic-table": {
85
- "types": "./dist/periodic-table.d.ts",
86
- "default": "./dist/periodic-table.js"
97
+ "types": "./dist/periodic-table/index.d.ts",
98
+ "default": "./dist/periodic-table/index.js"
87
99
  },
88
100
  "./phase-diagram": {
89
101
  "types": "./dist/phase-diagram/index.d.ts",
@@ -156,16 +168,17 @@
156
168
  },
157
169
  "scripts": {
158
170
  "test": "vp test --run && playwright test",
171
+ "knip": "knip --include dependencies,devDependencies",
159
172
  "package-dist-assets": "NODE_OPTIONS=--experimental-strip-types node scripts/package-dist-assets.ts",
160
173
  "package:dist": "svelte-package && npm run package-dist-assets",
161
174
  "prepare": "NODE_OPTIONS=--experimental-strip-types svelte-kit sync && npm run package:dist",
162
175
  "prepublishOnly": "npm run package:dist"
163
176
  },
164
177
  "dependencies": {
165
- "@spglib/moyo-wasm": "^0.9.0",
166
- "@sveltejs/kit": "2.60.1",
167
- "@threlte/core": "^8.5.14",
168
- "@threlte/extras": "^9.19.0",
178
+ "@spglib/moyo-wasm": "^0.10.0",
179
+ "@sveltejs/kit": "2.61.1",
180
+ "@threlte/core": "^8.5.16",
181
+ "@threlte/extras": "^9.20.1",
169
182
  "d3-array": "^3.2.4",
170
183
  "d3-color": "^3.1.0",
171
184
  "d3-format": "^3.1.2",
@@ -175,16 +188,15 @@
175
188
  "d3-scale-chromatic": "^3.1.0",
176
189
  "d3-shape": "^3.2.0",
177
190
  "d3-time-format": "^4.1.0",
178
- "dompurify": "^3.4.5",
191
+ "dompurify": "^3.4.7",
179
192
  "fflate": "^0.8.3",
180
- "h5wasm": "^0.10.1",
193
+ "h5wasm": "^0.10.2",
181
194
  "js-yaml": "^4.1.1",
182
195
  "svelte-multiselect": "^11.7.1",
183
196
  "three": "^0.184.0"
184
197
  },
185
198
  "devDependencies": {
186
199
  "@playwright/test": "^1.60.0",
187
- "@rollup/plugin-yaml": "^4.1.2",
188
200
  "@sveltejs/adapter-static": "3.0.10",
189
201
  "@sveltejs/package": "^2.5.7",
190
202
  "@sveltejs/vite-plugin-svelte": "^7.1.2",
@@ -198,31 +210,39 @@
198
210
  "@types/d3-shape": "^3.1.8",
199
211
  "@types/d3-time-format": "^4.0.3",
200
212
  "@types/js-yaml": "^4.0.9",
201
- "@types/node": "^25.9.0",
213
+ "@types/node": "^25.9.1",
202
214
  "@types/three": "^0.184.1",
203
- "@typescript/native-preview": "7.0.0-dev.20260519.1",
204
- "@vitest/coverage-v8": "4.1.5",
215
+ "@typescript/native-preview": "7.0.0-dev.20260527.2",
216
+ "@vitest/coverage-v8": "4.1.7",
205
217
  "@wooorm/starry-night": "^3.9.0",
206
218
  "happy-dom": "^20.9.0",
219
+ "knip": "^6.14.2",
207
220
  "mdsvex": "^0.12.7",
208
221
  "rehype-katex": "^7.0.1",
209
222
  "remark-math": "3.0.1",
210
- "svelte": "5.55.8",
211
- "svelte-check-rs": "0.9.13",
223
+ "svelte": "5.56.0",
224
+ "svelte-check-rs": "0.9.19",
212
225
  "typescript": "6.0.3",
213
- "vite": "npm:@voidzero-dev/vite-plus-core@^0.1.21",
226
+ "vite": "^8.0.14",
214
227
  "vite-plus": "latest",
215
- "vitest": "npm:@voidzero-dev/vite-plus-test@^0.1.21"
228
+ "vitest": "4.1.7"
216
229
  },
217
230
  "peerDependencies": {
218
231
  "svelte": "^5.0.0"
219
232
  },
220
- "overrides": {
221
- "vite": "npm:@voidzero-dev/vite-plus-core@^0.1.21",
222
- "vitest": "npm:@voidzero-dev/vite-plus-test@^0.1.21"
223
- },
224
233
  "engines": {
225
234
  "node": ">=24"
226
235
  },
227
- "packageManager": "pnpm@10.33.0"
236
+ "knip": {
237
+ "entry": [
238
+ "svelte.config.ts"
239
+ ],
240
+ "ignore": [
241
+ "extensions/**"
242
+ ],
243
+ "ignoreDependencies": [
244
+ "@typescript/native-preview",
245
+ "svelte-check-rs"
246
+ ]
247
+ }
228
248
  }