matterviz 0.1.12 → 0.1.13

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 (195) hide show
  1. package/dist/ContextMenu.svelte +1 -1
  2. package/dist/ContextMenu.svelte.d.ts +3 -3
  3. package/dist/DraggablePane.svelte +10 -5
  4. package/dist/DraggablePane.svelte.d.ts +3 -3
  5. package/dist/FilePicker.svelte.d.ts +3 -3
  6. package/dist/Icon.svelte.d.ts +3 -3
  7. package/dist/Nav.svelte +76 -31
  8. package/dist/SettingsSection.svelte.d.ts +3 -3
  9. package/dist/Spinner.svelte +18 -29
  10. package/dist/Spinner.svelte.d.ts +3 -3
  11. package/dist/app.css +4 -0
  12. package/dist/bands/Bands.svelte +216 -0
  13. package/dist/bands/Bands.svelte.d.ts +16 -0
  14. package/dist/bands/BandsAndDos.svelte +26 -0
  15. package/dist/bands/BandsAndDos.svelte.d.ts +16 -0
  16. package/dist/bands/Dos.svelte +124 -0
  17. package/dist/bands/Dos.svelte.d.ts +18 -0
  18. package/dist/bands/helpers.d.ts +11 -0
  19. package/dist/bands/helpers.js +195 -0
  20. package/dist/bands/index.d.ts +5 -0
  21. package/dist/bands/index.js +6 -0
  22. package/dist/bands/types.d.ts +54 -0
  23. package/dist/bands/types.js +2 -0
  24. package/dist/brillouin/BrillouinZone.svelte +373 -0
  25. package/dist/brillouin/BrillouinZone.svelte.d.ts +57 -0
  26. package/dist/brillouin/BrillouinZoneControls.svelte +88 -0
  27. package/dist/brillouin/BrillouinZoneControls.svelte.d.ts +14 -0
  28. package/dist/brillouin/BrillouinZoneExportPane.svelte +129 -0
  29. package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +15 -0
  30. package/dist/brillouin/BrillouinZoneInfoPane.svelte +115 -0
  31. package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +13 -0
  32. package/dist/brillouin/BrillouinZoneScene.svelte +180 -0
  33. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +34 -0
  34. package/dist/brillouin/compute.d.ts +7 -0
  35. package/dist/brillouin/compute.js +215 -0
  36. package/dist/brillouin/index.d.ts +7 -0
  37. package/dist/brillouin/index.js +7 -0
  38. package/dist/brillouin/types.d.ts +23 -0
  39. package/dist/brillouin/types.js +1 -0
  40. package/dist/composition/BarChart.svelte.d.ts +3 -3
  41. package/dist/composition/BubbleChart.svelte +7 -6
  42. package/dist/composition/BubbleChart.svelte.d.ts +3 -3
  43. package/dist/composition/Composition.svelte.d.ts +3 -3
  44. package/dist/composition/PieChart.svelte +1 -1
  45. package/dist/composition/PieChart.svelte.d.ts +3 -3
  46. package/dist/composition/parse.d.ts +3 -3
  47. package/dist/coordination/CoordinationBarPlot.svelte +241 -0
  48. package/dist/coordination/CoordinationBarPlot.svelte.d.ts +29 -0
  49. package/dist/coordination/calc-coordination.d.ts +15 -0
  50. package/dist/coordination/calc-coordination.js +66 -0
  51. package/dist/coordination/index.d.ts +8 -0
  52. package/dist/coordination/index.js +7 -0
  53. package/dist/element/BohrAtom.svelte.d.ts +3 -3
  54. package/dist/element/ElementHeading.svelte.d.ts +3 -3
  55. package/dist/element/ElementPhoto.svelte.d.ts +3 -3
  56. package/dist/element/ElementStats.svelte.d.ts +3 -3
  57. package/dist/element/ElementTile.svelte +1 -1
  58. package/dist/element/ElementTile.svelte.d.ts +4 -4
  59. package/dist/element/Nucleus.svelte.d.ts +3 -3
  60. package/dist/icons.d.ts +4 -0
  61. package/dist/icons.js +4 -0
  62. package/dist/index.d.ts +5 -1
  63. package/dist/index.js +5 -1
  64. package/dist/io/export.d.ts +1 -6
  65. package/dist/io/export.js +12 -12
  66. package/dist/labels.d.ts +19 -0
  67. package/dist/labels.js +59 -0
  68. package/dist/math.d.ts +7 -2
  69. package/dist/math.js +24 -12
  70. package/dist/periodic-table/PeriodicTable.svelte.d.ts +3 -3
  71. package/dist/periodic-table/PeriodicTableControls.svelte.d.ts +3 -3
  72. package/dist/periodic-table/PropertySelect.svelte +1 -1
  73. package/dist/periodic-table/PropertySelect.svelte.d.ts +5 -4
  74. package/dist/periodic-table/TableInset.svelte.d.ts +3 -3
  75. package/dist/phase-diagram/PhaseDiagram2D.svelte +44 -107
  76. package/dist/phase-diagram/PhaseDiagram2D.svelte.d.ts +7 -27
  77. package/dist/phase-diagram/PhaseDiagram3D.svelte +67 -170
  78. package/dist/phase-diagram/PhaseDiagram3D.svelte.d.ts +7 -31
  79. package/dist/phase-diagram/PhaseDiagram4D.svelte +87 -145
  80. package/dist/phase-diagram/PhaseDiagram4D.svelte.d.ts +5 -28
  81. package/dist/phase-diagram/PhaseDiagramControls.svelte +9 -9
  82. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +6 -6
  83. package/dist/phase-diagram/PhaseDiagramInfoPane.svelte +4 -4
  84. package/dist/phase-diagram/PhaseDiagramInfoPane.svelte.d.ts +5 -5
  85. package/dist/phase-diagram/PhaseDiagramStats.svelte +9 -16
  86. package/dist/phase-diagram/PhaseDiagramStats.svelte.d.ts +3 -3
  87. package/dist/phase-diagram/StructurePopup.svelte.d.ts +3 -3
  88. package/dist/phase-diagram/barycentric-coords.js +13 -24
  89. package/dist/phase-diagram/helpers.d.ts +12 -14
  90. package/dist/phase-diagram/helpers.js +70 -23
  91. package/dist/phase-diagram/index.d.ts +58 -0
  92. package/dist/phase-diagram/index.js +44 -0
  93. package/dist/phase-diagram/thermodynamics.js +2 -3
  94. package/dist/phase-diagram/types.d.ts +3 -8
  95. package/dist/plot/BarPlot.svelte +474 -240
  96. package/dist/plot/BarPlot.svelte.d.ts +16 -37
  97. package/dist/plot/BarPlotControls.svelte +33 -201
  98. package/dist/plot/BarPlotControls.svelte.d.ts +11 -22
  99. package/dist/plot/ColorBar.svelte.d.ts +3 -3
  100. package/dist/plot/ColorScaleSelect.svelte +1 -1
  101. package/dist/plot/ColorScaleSelect.svelte.d.ts +3 -3
  102. package/dist/plot/ElementScatter.svelte +5 -5
  103. package/dist/plot/ElementScatter.svelte.d.ts +8 -8
  104. package/dist/plot/Histogram.svelte +318 -170
  105. package/dist/plot/Histogram.svelte.d.ts +21 -41
  106. package/dist/plot/HistogramControls.svelte +115 -347
  107. package/dist/plot/HistogramControls.svelte.d.ts +13 -28
  108. package/dist/plot/Line.svelte +1 -1
  109. package/dist/plot/Line.svelte.d.ts +4 -4
  110. package/dist/plot/PlotControls.svelte +280 -0
  111. package/dist/plot/PlotControls.svelte.d.ts +4 -0
  112. package/dist/plot/PlotLegend.svelte +9 -24
  113. package/dist/plot/PlotLegend.svelte.d.ts +3 -3
  114. package/dist/plot/ScatterPlot.svelte +536 -571
  115. package/dist/plot/ScatterPlot.svelte.d.ts +18 -90
  116. package/dist/plot/ScatterPlotControls.svelte +108 -316
  117. package/dist/plot/ScatterPlotControls.svelte.d.ts +11 -38
  118. package/dist/plot/ScatterPoint.svelte +1 -1
  119. package/dist/plot/ScatterPoint.svelte.d.ts +5 -5
  120. package/dist/plot/SpacegroupBarPlot.svelte +235 -0
  121. package/dist/plot/SpacegroupBarPlot.svelte.d.ts +9 -0
  122. package/dist/plot/data-transform.d.ts +2 -2
  123. package/dist/plot/data-transform.js +1 -5
  124. package/dist/plot/index.d.ts +12 -200
  125. package/dist/plot/index.js +14 -6
  126. package/dist/plot/layout.d.ts +10 -16
  127. package/dist/plot/layout.js +40 -25
  128. package/dist/plot/scales.d.ts +7 -8
  129. package/dist/plot/scales.js +22 -7
  130. package/dist/plot/types.d.ts +303 -0
  131. package/dist/plot/types.js +1 -0
  132. package/dist/rdf/RdfPlot.svelte +156 -0
  133. package/dist/rdf/RdfPlot.svelte.d.ts +20 -0
  134. package/dist/rdf/calc-rdf.d.ts +4 -0
  135. package/dist/rdf/calc-rdf.js +107 -0
  136. package/dist/rdf/index.d.ts +22 -0
  137. package/dist/rdf/index.js +2 -0
  138. package/dist/settings.d.ts +86 -75
  139. package/dist/settings.js +257 -155
  140. package/dist/structure/Bond.svelte +126 -110
  141. package/dist/structure/Bond.svelte.d.ts +7 -20
  142. package/dist/structure/CanvasTooltip.svelte.d.ts +4 -4
  143. package/dist/structure/Cylinder.svelte +29 -0
  144. package/dist/structure/Cylinder.svelte.d.ts +10 -0
  145. package/dist/structure/Lattice.svelte +1 -2
  146. package/dist/structure/Lattice.svelte.d.ts +3 -3
  147. package/dist/structure/Structure.svelte +23 -8
  148. package/dist/structure/Structure.svelte.d.ts +10 -7
  149. package/dist/structure/StructureControls.svelte +25 -134
  150. package/dist/structure/StructureControls.svelte.d.ts +4 -9
  151. package/dist/structure/StructureExportPane.svelte +188 -0
  152. package/dist/structure/StructureExportPane.svelte.d.ts +17 -0
  153. package/dist/structure/StructureInfoPane.svelte.d.ts +3 -3
  154. package/dist/structure/StructureLegend.svelte +91 -27
  155. package/dist/structure/StructureLegend.svelte.d.ts +5 -4
  156. package/dist/structure/StructureScene.svelte +93 -100
  157. package/dist/structure/StructureScene.svelte.d.ts +15 -12
  158. package/dist/structure/Vector.svelte +19 -25
  159. package/dist/structure/Vector.svelte.d.ts +3 -3
  160. package/dist/structure/bonding.d.ts +16 -14
  161. package/dist/structure/bonding.js +207 -216
  162. package/dist/structure/export.d.ts +3 -0
  163. package/dist/structure/export.js +120 -0
  164. package/dist/structure/index.d.ts +15 -1
  165. package/dist/structure/index.js +2 -0
  166. package/dist/symmetry/WyckoffTable.svelte.d.ts +3 -3
  167. package/dist/symmetry/index.d.ts +1 -0
  168. package/dist/symmetry/index.js +1 -0
  169. package/dist/symmetry/spacegroups.d.ts +9 -0
  170. package/dist/symmetry/spacegroups.js +397 -0
  171. package/dist/theme/ThemeControl.svelte.d.ts +3 -3
  172. package/dist/theme/themes.js +2 -16
  173. package/dist/trajectory/Trajectory.svelte +52 -78
  174. package/dist/trajectory/Trajectory.svelte.d.ts +5 -5
  175. package/dist/trajectory/TrajectoryError.svelte.d.ts +3 -3
  176. package/dist/trajectory/TrajectoryExportPane.svelte +1 -1
  177. package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +5 -5
  178. package/dist/trajectory/TrajectoryInfoPane.svelte +1 -1
  179. package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +3 -3
  180. package/dist/trajectory/extract.js +2 -1
  181. package/dist/trajectory/index.d.ts +1 -1
  182. package/dist/trajectory/index.js +1 -1
  183. package/dist/trajectory/parse.js +21 -14
  184. package/dist/utils.d.ts +1 -0
  185. package/dist/utils.js +17 -0
  186. package/dist/xrd/XrdPlot.svelte +14 -11
  187. package/dist/xrd/XrdPlot.svelte.d.ts +6 -5
  188. package/package.json +20 -12
  189. package/readme.md +1 -1
  190. package/dist/material/MaterialCard.svelte +0 -123
  191. package/dist/material/MaterialCard.svelte.d.ts +0 -9
  192. package/dist/material/index.d.ts +0 -1
  193. package/dist/material/index.js +0 -1
  194. package/dist/plot/formatting.d.ts +0 -7
  195. package/dist/plot/formatting.js +0 -53
@@ -1,4 +1,4 @@
1
- import { format_value } from './formatting';
1
+ import { format_value } from '../labels';
2
2
  // Measure text width using canvas (singleton pattern for performance)
3
3
  let measurement_canvas = null;
4
4
  export function measure_text_width(text, font = `12px sans-serif`) {
@@ -14,12 +14,24 @@ export function measure_text_width(text, font = `12px sans-serif`) {
14
14
  return ctx.measureText(text).width;
15
15
  }
16
16
  // Helper to measure max tick width
17
- const measure_max_tick_width = (ticks, format) => ticks.length === 0 ? 0 : Math.max(...ticks.map((tick) => measure_text_width(format_value(tick, format), `12px sans-serif`)));
18
- export const calc_auto_padding = ({ base_padding, y_ticks = [], y_format = ``, y2_ticks = [], y2_format = ``, label_gap = 45, }) => ({
19
- ...base_padding,
20
- l: Math.max(base_padding.l, measure_max_tick_width(y_ticks, y_format) + label_gap),
21
- r: Math.max(base_padding.r, measure_max_tick_width(y2_ticks, y2_format) + label_gap),
22
- });
17
+ const measure_max_tick_width = (ticks, format = ``) => ticks.length === 0 ? 0 : Math.max(...ticks.map((tick) => {
18
+ const label = typeof tick === `string` ? tick : format_value(tick, format);
19
+ return measure_text_width(label, `12px sans-serif`);
20
+ }));
21
+ export const calc_auto_padding = ({ padding, default_padding, y_axis = {}, y2_axis = {}, label_gap = 45, }) => {
22
+ const y_ticks = y_axis.tick_values ?? [];
23
+ const y_format = y_axis.format ?? ``;
24
+ const y2_ticks = y2_axis.tick_values ?? [];
25
+ const y2_format = y2_axis.format ?? ``;
26
+ return {
27
+ t: padding.t ?? default_padding.t,
28
+ b: padding.b ?? default_padding.b,
29
+ l: padding.l ??
30
+ Math.max(default_padding.l, measure_max_tick_width(y_ticks, y_format) + label_gap),
31
+ r: padding.r ??
32
+ Math.max(default_padding.r, measure_max_tick_width(y2_ticks, y2_format) + label_gap),
33
+ };
34
+ };
23
35
  // Constrain tooltip position within chart bounds
24
36
  export function constrain_tooltip_position(base_x, base_y, tooltip_width, tooltip_height, chart_width, chart_height) {
25
37
  // Calculate the maximum allowable position for the tooltip
@@ -30,10 +42,6 @@ export function constrain_tooltip_position(base_x, base_y, tooltip_width, toolti
30
42
  y: Math.min(max_y, Math.max(10, base_y - 10)),
31
43
  };
32
44
  }
33
- // Get chart dimensions from width, height, and padding
34
- export function get_chart_dimensions(width, height, padding) {
35
- return { width: width - padding.l - padding.r, height: height - padding.t - padding.b };
36
- }
37
45
  // Define anchor positions with their transform origins
38
46
  export const PLACEMENT_ANCHORS = {
39
47
  // Corners (priority 1)
@@ -63,12 +71,17 @@ export const PLACEMENT_PRIORITY = [
63
71
  export function find_best_plot_area(points, config) {
64
72
  const { plot_width, plot_height, padding, margin = 10 } = config;
65
73
  const { width = 120, height = 80 } = config.legend_size ?? {};
66
- // Detection radius for point counting (legend diagonal / 2)
67
- const radius = Math.sqrt(width ** 2 + height ** 2) / 2;
68
- const radius_sq = radius * radius;
74
+ // For performance, subsample points if there are too many (>500)
75
+ const max_points_for_full_calc = 500;
76
+ const sampled_points = points.length > max_points_for_full_calc
77
+ ? (() => {
78
+ const step = points.length / max_points_for_full_calc;
79
+ return Array.from({ length: max_points_for_full_calc }, (_, idx) => points[Math.floor(idx * step)]);
80
+ })()
81
+ : points;
69
82
  let best_position = `top-right`;
70
- let min_count = Infinity;
71
- // Try each position in priority order, pick the one with fewest nearby points
83
+ let max_min_distance = -Infinity;
84
+ // Try each position in priority order, pick the one with maximum distance to nearest point
72
85
  for (const position of PLACEMENT_PRIORITY) {
73
86
  const { anchor } = PLACEMENT_ANCHORS[position];
74
87
  // Calculate position coordinates
@@ -79,20 +92,22 @@ export function find_best_plot_area(points, config) {
79
92
  (anchor.x === 0 ? margin : anchor.x === 1 ? -margin : 0);
80
93
  const y = base_y +
81
94
  (anchor.y === 0 ? margin : anchor.y === 1 ? -margin : 0);
82
- // Calculate rectangle center for distance measurement
95
+ // Calculate legend center for distance measurement
83
96
  const center_x = x + width * (0.5 - anchor.x);
84
97
  const center_y = y + height * (0.5 - anchor.y);
85
- // Count nearby points
86
- let count = 0;
87
- for (const point of points) {
98
+ // Find minimum distance to any point (distance to nearest point)
99
+ let min_distance_sq = Infinity;
100
+ for (const point of sampled_points) {
88
101
  const dx = point.x - center_x;
89
102
  const dy = point.y - center_y;
90
- if (dx * dx + dy * dy <= radius_sq)
91
- count++;
103
+ const dist_sq = dx * dx + dy * dy;
104
+ if (dist_sq < min_distance_sq) {
105
+ min_distance_sq = dist_sq;
106
+ }
92
107
  }
93
- // Update best if this position is less crowded
94
- if (count < min_count) {
95
- min_count = count;
108
+ // Update best if this position has greater distance to nearest point
109
+ if (min_distance_sq > max_min_distance) {
110
+ max_min_distance = min_distance_sq;
96
111
  best_position = position;
97
112
  }
98
113
  }
@@ -1,16 +1,15 @@
1
- import type { Point } from './';
2
- import type { ScaleContinuousNumeric } from 'd3-scale';
3
- export type ScaleType = `linear` | `log`;
4
- export type TimeInterval = `day` | `month` | `year`;
5
- export type TicksOption = number | number[] | TimeInterval;
1
+ import type { Point, ScaleType, TimeInterval } from './';
2
+ import type { ScaleContinuousNumeric, ScaleTime } from 'd3-scale';
3
+ export type TicksOption = number | number[] | TimeInterval | Record<number, string>;
6
4
  export declare function create_scale(scale_type: ScaleType, domain: [number, number], range: [number, number]): import("d3-scale").ScaleLinear<number, number, never>;
7
- export declare function create_time_scale(domain: [number, number], range: [number, number]): import("d3-scale").ScaleTime<number, number, never>;
8
- export declare function generate_ticks(domain: [number, number], scale_type: ScaleType, ticks_option: TicksOption | undefined, scale_fn: ScaleContinuousNumeric<number, number>, // D3 scale function with .ticks() method
5
+ export declare function create_time_scale(domain: [number, number], range: [number, number]): ScaleTime<number, number, never>;
6
+ export declare function generate_ticks(domain: [number, number], scale_type: ScaleType, ticks_option: TicksOption | undefined, scale_fn: ScaleContinuousNumeric<number, number> | ScaleTime<number, number>, // D3 scale function with .ticks() method
9
7
  options?: {
10
8
  format?: string;
11
9
  default_count?: number;
12
10
  interval_padding?: number;
13
11
  }): number[];
14
12
  export declare function calculate_domain(values: number[], scale_type?: ScaleType): [number, number];
15
- export declare function get_nice_data_range(points: Point[], get_value: (p: Point) => number, lim: [number | null, number | null], scale_type: ScaleType, padding_factor: number, is_time?: boolean): [number, number];
13
+ export declare function get_nice_data_range(points: Point[], get_value: (p: Point) => number, range: [number | null, number | null], scale_type: ScaleType, padding_factor: number, is_time?: boolean): [number, number];
16
14
  export declare function generate_log_ticks(min: number, max: number, ticks_option?: TicksOption): number[];
15
+ export declare function get_tick_label(tick_value: number, ticks_option: TicksOption | undefined): string | null;
@@ -19,6 +19,14 @@ export function generate_ticks(domain, scale_type, ticks_option, scale_fn, // D3
19
19
  options = {}) {
20
20
  const { format, default_count = 8, interval_padding = 0.1 } = options;
21
21
  const [min_val, max_val] = domain;
22
+ // If ticks_option is an object (value-to-label mapping), extract values
23
+ if (ticks_option && typeof ticks_option === `object` && !Array.isArray(ticks_option)) {
24
+ const [domain_min, domain_max] = [Math.min(...domain), Math.max(...domain)];
25
+ return Object.keys(ticks_option)
26
+ .map(Number)
27
+ .filter((val) => Number.isFinite(val) && val >= domain_min && val <= domain_max)
28
+ .sort((a, b) => a - b);
29
+ }
22
30
  // If ticks_option is already an array, use it directly
23
31
  if (Array.isArray(ticks_option))
24
32
  return ticks_option;
@@ -73,13 +81,13 @@ export function calculate_domain(values, scale_type = `linear`) {
73
81
  : [min_val, max_val];
74
82
  }
75
83
  // Advanced domain calculation with padding and nice boundaries (from ScatterPlot)
76
- export function get_nice_data_range(points, get_value, lim, scale_type, padding_factor, is_time = false) {
77
- const [min_lim, max_lim] = lim;
84
+ export function get_nice_data_range(points, get_value, range, scale_type, padding_factor, is_time = false) {
85
+ const [min, max] = range;
78
86
  const [min_ext, max_ext] = extent(points, get_value);
79
- let data_min = min_lim ?? min_ext ?? 0;
80
- let data_max = max_lim ?? max_ext ?? 1;
87
+ let data_min = min ?? min_ext ?? 0;
88
+ let data_max = max ?? max_ext ?? 1;
81
89
  // Apply padding *only if* limits were NOT provided
82
- if (min_lim === null && max_lim === null && points.length > 0) {
90
+ if (min === null && max === null && points.length > 0) {
83
91
  if (data_min !== data_max) {
84
92
  // Apply percentage padding based on scale type if there's a range
85
93
  const span = data_max - data_min;
@@ -163,7 +171,14 @@ export function generate_log_ticks(min, max, ticks_option) {
163
171
  if (power * 5 <= Math.pow(10, extended_max_power))
164
172
  detailed_ticks.push(power * 5);
165
173
  });
166
- return detailed_ticks;
174
+ return detailed_ticks.filter((t) => t >= min && t <= max);
175
+ }
176
+ return powers.filter((p) => p >= min && p <= max);
177
+ }
178
+ // Get custom label for a tick value if provided, otherwise return null
179
+ export function get_tick_label(tick_value, ticks_option) {
180
+ if (ticks_option && typeof ticks_option === `object` && !Array.isArray(ticks_option)) {
181
+ return ticks_option[tick_value] ?? null;
167
182
  }
168
- return powers;
183
+ return null;
169
184
  }
@@ -0,0 +1,303 @@
1
+ import type DraggablePane from '../DraggablePane.svelte';
2
+ import type { D3SymbolName } from '../labels';
3
+ import type { SimulationNodeDatum } from 'd3-force';
4
+ import type { ComponentProps, Snippet } from 'svelte';
5
+ import type { HTMLAttributes } from 'svelte/elements';
6
+ import type ColorBar from './ColorBar.svelte';
7
+ import type PlotLegend from './PlotLegend.svelte';
8
+ import type { TicksOption } from './scales';
9
+ export interface TweenedOptions<T> {
10
+ delay?: number;
11
+ duration?: number | ((from: T, to: T) => number);
12
+ easing?: (t: number) => number;
13
+ interpolate?: (a: T, b: T) => (t: number) => T;
14
+ }
15
+ export type XyObj = {
16
+ x: number;
17
+ y: number;
18
+ };
19
+ export type Sides = {
20
+ t?: number;
21
+ b?: number;
22
+ l?: number;
23
+ r?: number;
24
+ };
25
+ export type Point = {
26
+ x: number;
27
+ y: number;
28
+ metadata?: {
29
+ [key: string]: unknown;
30
+ };
31
+ offset?: XyObj;
32
+ };
33
+ export interface PointStyle {
34
+ fill?: string;
35
+ radius?: number;
36
+ stroke?: string;
37
+ stroke_width?: number;
38
+ stroke_opacity?: number;
39
+ fill_opacity?: number;
40
+ symbol_type?: D3SymbolName;
41
+ symbol_size?: number | null;
42
+ shape?: string;
43
+ cursor?: string;
44
+ }
45
+ export interface HoverStyle {
46
+ enabled?: boolean;
47
+ scale?: number;
48
+ stroke?: string;
49
+ stroke_width?: number;
50
+ brightness?: number;
51
+ }
52
+ export interface LabelStyle {
53
+ text?: string;
54
+ offset?: XyObj;
55
+ font_size?: string;
56
+ font_family?: string;
57
+ auto_placement?: boolean;
58
+ }
59
+ export interface BarStyle {
60
+ color?: string;
61
+ opacity?: number;
62
+ stroke_width?: number;
63
+ stroke_color?: string;
64
+ stroke_opacity?: number;
65
+ [key: string]: unknown;
66
+ }
67
+ export interface LineStyle {
68
+ color?: string;
69
+ width?: number;
70
+ dash?: string;
71
+ [key: string]: unknown;
72
+ }
73
+ export interface PlotPoint extends Point {
74
+ color_value?: number | null;
75
+ metadata?: Record<string, unknown>;
76
+ point_style?: PointStyle;
77
+ point_hover?: HoverStyle;
78
+ point_label?: LabelStyle;
79
+ point_offset?: XyObj;
80
+ point_tween?: TweenedOptions<XyObj>;
81
+ }
82
+ export type Markers = `line` | `points` | `line+points` | `none`;
83
+ export interface DataSeries {
84
+ id?: string | number;
85
+ x: readonly number[];
86
+ y: readonly number[];
87
+ markers?: Markers;
88
+ y_axis?: `y1` | `y2`;
89
+ color_values?: (number | null)[] | null;
90
+ size_values?: readonly (number | null)[] | null;
91
+ metadata?: Record<string, unknown>[] | Record<string, unknown>;
92
+ point_style?: PointStyle[] | PointStyle;
93
+ point_hover?: HoverStyle[] | HoverStyle;
94
+ point_label?: LabelStyle[] | LabelStyle;
95
+ point_offset?: XyObj[] | XyObj;
96
+ point_tween?: TweenedOptions<XyObj>;
97
+ visible?: boolean;
98
+ label?: string;
99
+ unit?: string;
100
+ line_style?: {
101
+ stroke?: string;
102
+ stroke_width?: number;
103
+ line_dash?: string;
104
+ };
105
+ }
106
+ export interface InternalPoint extends PlotPoint {
107
+ series_idx: number;
108
+ point_idx: number;
109
+ size_value?: number | null;
110
+ }
111
+ export interface Tooltip {
112
+ show: boolean;
113
+ x: number;
114
+ y: number;
115
+ title?: string;
116
+ items?: {
117
+ label: string;
118
+ value: string;
119
+ color?: string;
120
+ }[];
121
+ }
122
+ export interface TooltipProps {
123
+ x: number;
124
+ y: number;
125
+ metadata?: Record<string, unknown> | null;
126
+ color?: string | null;
127
+ label?: string | null;
128
+ series_idx: number;
129
+ }
130
+ export interface ScatterTooltipProps extends TooltipProps {
131
+ cx: number;
132
+ cy: number;
133
+ x_formatted: string;
134
+ y_formatted: string;
135
+ }
136
+ export interface BarTooltipProps extends TooltipProps {
137
+ bar_idx: number;
138
+ orient_x: number;
139
+ orient_y: number;
140
+ y_axis: `y1` | `y2`;
141
+ }
142
+ export type TimeInterval = `day` | `month` | `year`;
143
+ export type ScaleType = `linear` | `log`;
144
+ export type QuadrantCounts = {
145
+ top_left: number;
146
+ top_right: number;
147
+ bottom_left: number;
148
+ bottom_right: number;
149
+ };
150
+ export interface LabelNode extends SimulationNodeDatum {
151
+ id: string;
152
+ anchor_x: number;
153
+ anchor_y: number;
154
+ point_node: InternalPoint;
155
+ label_width: number;
156
+ label_height: number;
157
+ }
158
+ export interface LabelPlacementConfig {
159
+ collision_strength: number;
160
+ link_strength: number;
161
+ link_distance: number;
162
+ placement_ticks: number;
163
+ link_distance_range?: [number | null, number | null];
164
+ }
165
+ export type HoverConfig = {
166
+ threshold_px: number;
167
+ };
168
+ export interface AnchorNode extends SimulationNodeDatum {
169
+ id: string;
170
+ fx: number;
171
+ fy: number;
172
+ point_radius: number;
173
+ show_color_bar?: boolean;
174
+ color_bar?: ComponentProps<typeof ColorBar> | null;
175
+ label_placement_config?: Partial<LabelPlacementConfig>;
176
+ }
177
+ export type LegendConfig = Omit<ComponentProps<typeof PlotLegend>, `series_data` | `on_drag_start` | `on_drag` | `on_drag_end`> & {
178
+ margin?: number | Sides;
179
+ tween?: TweenedOptions<XyObj>;
180
+ responsive?: boolean;
181
+ draggable?: boolean;
182
+ };
183
+ export interface LegendItem {
184
+ label: string;
185
+ visible: boolean;
186
+ series_idx: number;
187
+ display_style: {
188
+ symbol_type?: D3SymbolName;
189
+ symbol_color?: string;
190
+ line_color?: string;
191
+ line_dash?: string;
192
+ };
193
+ }
194
+ export type UserContentProps = {
195
+ height: number;
196
+ width: number;
197
+ x_scale_fn: (x: number) => number;
198
+ y_scale_fn: (y: number) => number;
199
+ y2_scale_fn?: (y: number) => number;
200
+ pad: Required<Sides>;
201
+ x_range: [number, number];
202
+ y_range: [number, number];
203
+ y2_range?: [number, number];
204
+ };
205
+ export type Orientation = `vertical` | `horizontal`;
206
+ export type BarMode = `overlay` | `stacked` | `grouped`;
207
+ export interface BarSeries {
208
+ id?: string | number;
209
+ x: readonly number[];
210
+ y: readonly number[];
211
+ label?: string;
212
+ color?: string;
213
+ bar_width?: number | readonly number[];
214
+ visible?: boolean;
215
+ metadata?: Record<string, unknown>[] | Record<string, unknown>;
216
+ labels?: readonly (string | null | undefined)[];
217
+ render_mode?: `bar` | `line`;
218
+ y_axis?: `y1` | `y2`;
219
+ line_style?: {
220
+ stroke_width?: number;
221
+ line_dash?: string;
222
+ };
223
+ }
224
+ export interface AxisConfig {
225
+ label?: string;
226
+ format?: string;
227
+ ticks?: TicksOption;
228
+ scale_type?: ScaleType;
229
+ range?: [number | null, number | null];
230
+ unit?: string;
231
+ label_shift?: {
232
+ x?: number;
233
+ y?: number;
234
+ };
235
+ tick_label_shift?: {
236
+ x?: number;
237
+ y?: number;
238
+ };
239
+ tick_rotation?: number;
240
+ grid_style?: HTMLAttributes<SVGLineElement>;
241
+ color?: string | null;
242
+ }
243
+ export interface DisplayConfig {
244
+ x_grid?: boolean;
245
+ y_grid?: boolean;
246
+ y2_grid?: boolean;
247
+ x_zero_line?: boolean;
248
+ y_zero_line?: boolean;
249
+ }
250
+ export interface StyleOverrides {
251
+ point?: {
252
+ size?: number;
253
+ color?: string;
254
+ opacity?: number;
255
+ stroke_width?: number;
256
+ stroke_color?: string;
257
+ stroke_opacity?: number;
258
+ };
259
+ line?: {
260
+ width?: number;
261
+ color?: string;
262
+ opacity?: number;
263
+ dash?: string;
264
+ };
265
+ show_points?: boolean;
266
+ show_lines?: boolean;
267
+ }
268
+ export interface ControlsConfig {
269
+ show?: boolean;
270
+ open?: boolean;
271
+ toggle_props?: ComponentProps<typeof DraggablePane>[`toggle_props`];
272
+ pane_props?: ComponentProps<typeof DraggablePane>[`pane_props`];
273
+ }
274
+ export interface PlotControlsProps {
275
+ show_controls?: boolean;
276
+ controls_open?: boolean;
277
+ children?: Snippet<[]>;
278
+ post_children?: Snippet<[]>;
279
+ x_axis?: AxisConfig;
280
+ y_axis?: AxisConfig;
281
+ y2_axis?: AxisConfig;
282
+ display?: DisplayConfig;
283
+ auto_x_range?: [number, number];
284
+ auto_y_range?: [number, number];
285
+ auto_y2_range?: [number, number];
286
+ has_y2_points?: boolean;
287
+ show_ticks?: boolean;
288
+ controls_title?: string;
289
+ controls_class?: string;
290
+ toggle_props?: ComponentProps<typeof DraggablePane>[`toggle_props`];
291
+ pane_props?: ComponentProps<typeof DraggablePane>[`pane_props`];
292
+ }
293
+ export interface BasePlotProps {
294
+ x_range?: [number | null, number | null];
295
+ y_range?: [number | null, number | null];
296
+ y2_range?: [number | null, number | null];
297
+ range_padding?: number;
298
+ padding?: Sides;
299
+ change?: (...args: unknown[]) => void;
300
+ controls_toggle_props?: ComponentProps<typeof DraggablePane>[`toggle_props`];
301
+ controls_pane_props?: ComponentProps<typeof DraggablePane>[`pane_props`];
302
+ children?: Snippet<[]>;
303
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,156 @@
1
+ <script lang="ts">import { plot_colors } from '../colors';
2
+ import { get_electro_neg_formula } from '../composition';
3
+ import { ScatterPlot } from '../plot';
4
+ import { calculate_all_pair_rdfs, calculate_rdf } from './index';
5
+ let { patterns, structures, mode = `element_pairs`, show_reference_line = true, x_axis = {}, y_axis = {}, cutoff = 15, n_bins = 75, pbc = [true, true, true], enable_drop = false, children, ...rest } = $props();
6
+ // Set default axis labels if not provided
7
+ x_axis.label ??= `r (Å)`;
8
+ y_axis.label ??= `g(r)`;
9
+ let dropped = $state([]);
10
+ let dragging = $state(false);
11
+ const entries = $derived.by(() => {
12
+ const result = [];
13
+ // Add patterns
14
+ if (patterns) {
15
+ if (Array.isArray(patterns))
16
+ result.push(...patterns);
17
+ else
18
+ result.push(patterns);
19
+ }
20
+ // Add structures
21
+ const struct_list = [];
22
+ if (structures) {
23
+ if (Array.isArray(structures)) {
24
+ structures.forEach((struct, idx) => struct_list.push({ struct: struct, label: `Structure ${idx + 1}` }));
25
+ }
26
+ else if (`lattice` in structures && `sites` in structures) {
27
+ struct_list.push({
28
+ struct: structures,
29
+ label: `${get_electro_neg_formula(structures)}: `,
30
+ });
31
+ }
32
+ else {
33
+ Object.entries(structures).forEach(([label, struct]) => struct_list.push({ struct, label }));
34
+ }
35
+ }
36
+ dropped.forEach((struct, idx) => struct_list.push({ struct, label: `Dropped ${idx + 1}` }));
37
+ for (const { struct, label } of struct_list) {
38
+ if (mode === `element_pairs`) {
39
+ const pairs = calculate_all_pair_rdfs(struct, { cutoff, n_bins, pbc });
40
+ result.push(...pairs.map((p) => ({
41
+ label: p.element_pair
42
+ ? `${label} ${p.element_pair[0]}-${p.element_pair[1]}`
43
+ : label,
44
+ pattern: p,
45
+ })));
46
+ }
47
+ else { // Calculate full RDF directly without element filters to properly weight all pairs
48
+ const full_rdf = calculate_rdf(struct, { cutoff, n_bins, pbc });
49
+ result.push({ label, pattern: full_rdf });
50
+ }
51
+ }
52
+ return result;
53
+ });
54
+ const max_r = $derived(Math.max(...entries.flatMap((e) => e.pattern.r), 0));
55
+ const max_g = $derived(Math.max(1.2, ...entries.flatMap((e) => e.pattern.g_r)));
56
+ const series = $derived(entries.map((ent, idx) => ({
57
+ x: ent.pattern.r,
58
+ y: ent.pattern.g_r,
59
+ label: ent.label,
60
+ visible: true,
61
+ markers: `line`,
62
+ line_style: {
63
+ stroke: ent.color ?? plot_colors[idx % plot_colors.length],
64
+ stroke_width: 2,
65
+ },
66
+ })));
67
+ async function handle_drop(ev) {
68
+ ev.preventDefault();
69
+ dragging = false;
70
+ const files = ev.dataTransfer?.files;
71
+ if (!files)
72
+ return;
73
+ for (const file of Array.from(files)) {
74
+ try {
75
+ const struct = JSON.parse(await file.text());
76
+ if (struct.lattice && struct.sites)
77
+ dropped = [...dropped, struct];
78
+ }
79
+ catch { }
80
+ }
81
+ }
82
+ </script>
83
+
84
+ {#if enable_drop && dropped.length > 0}
85
+ <div
86
+ style="padding: 0.5em; margin-bottom: 0.5em; background: #f0f0f0; border-radius: 4px"
87
+ >
88
+ {dropped.length} structure{dropped.length > 1 ? `s` : ``} loaded
89
+ <button onclick={() => (dropped = [])}>Clear</button>
90
+ </div>
91
+ {/if}
92
+
93
+ <ScatterPlot
94
+ {...rest}
95
+ {series}
96
+ x_axis={{ ...x_axis, range: [0, max_r] }}
97
+ y_axis={{ ...y_axis, range: [0, max_g * 1.05] }}
98
+ styles={{ show_lines: true, show_points: false }}
99
+ class={`${rest.class ?? ``} ${dragging ? `dragging` : ``}`}
100
+ style={rest.style ?? `height: 400px;`}
101
+ ondragover={enable_drop
102
+ ? (ev) => {
103
+ ev.preventDefault()
104
+ if (ev.dataTransfer) ev.dataTransfer.dropEffect = `copy`
105
+ dragging = true
106
+ }
107
+ : undefined}
108
+ ondragleave={enable_drop ? () => (dragging = false) : undefined}
109
+ ondrop={enable_drop ? handle_drop : undefined}
110
+ >
111
+ {#snippet user_content({ width, y_scale_fn, pad })}
112
+ {#if show_reference_line}
113
+ {@const y1 = y_scale_fn(1)}
114
+ {#if isFinite(y1)}
115
+ <line
116
+ x1={pad.l}
117
+ x2={width - pad.r}
118
+ {y1}
119
+ y2={y1}
120
+ stroke="gray"
121
+ stroke-dasharray="4"
122
+ opacity="0.5"
123
+ />
124
+ <text
125
+ x={width - pad.r - 5}
126
+ y={y1 - 5}
127
+ text-anchor="end"
128
+ fill="gray"
129
+ font-size="0.8em"
130
+ >
131
+ g(r) = 1
132
+ </text>
133
+ {/if}
134
+ {/if}
135
+ {/snippet}
136
+
137
+ {@render children?.()}
138
+ </ScatterPlot>
139
+
140
+ <style>
141
+ :global(.dragging) {
142
+ outline: 2px dashed #4e79a7;
143
+ outline-offset: 4px;
144
+ }
145
+ button {
146
+ margin-left: 1em;
147
+ padding: 0.25em 0.75em;
148
+ background: #e0e0e0;
149
+ border: 1px solid #ccc;
150
+ border-radius: 3px;
151
+ cursor: pointer;
152
+ }
153
+ button:hover {
154
+ background: #d0d0d0;
155
+ }
156
+ </style>
@@ -0,0 +1,20 @@
1
+ import { ScatterPlot } from '../plot';
2
+ import type { Pbc, PymatgenStructure as Structure } from '../structure';
3
+ import type { ComponentProps, Snippet } from 'svelte';
4
+ import { type RdfEntry } from './index';
5
+ type $$ComponentProps = {
6
+ patterns?: RdfEntry | RdfEntry[];
7
+ structures?: Structure | Structure[] | Record<string, Structure>;
8
+ mode?: `element_pairs` | `full`;
9
+ show_reference_line?: boolean;
10
+ x_axis?: ComponentProps<typeof ScatterPlot>[`x_axis`];
11
+ y_axis?: ComponentProps<typeof ScatterPlot>[`y_axis`];
12
+ cutoff?: number;
13
+ n_bins?: number;
14
+ pbc?: Pbc;
15
+ enable_drop?: boolean;
16
+ children?: Snippet<[]>;
17
+ } & ComponentProps<typeof ScatterPlot>;
18
+ declare const RdfPlot: import("svelte").Component<$$ComponentProps, {}, "">;
19
+ type RdfPlot = ReturnType<typeof RdfPlot>;
20
+ export default RdfPlot;
@@ -0,0 +1,4 @@
1
+ import type { PymatgenStructure as Structure } from '../structure';
2
+ import type { RdfOptions, RdfPattern } from './index';
3
+ export declare function calculate_rdf(structure: Structure, options?: RdfOptions): RdfPattern;
4
+ export declare function calculate_all_pair_rdfs(structure: Structure, options?: Omit<RdfOptions, `center_species` | `neighbor_species`>): RdfPattern[];