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.
- package/dist/ContextMenu.svelte +1 -1
- package/dist/ContextMenu.svelte.d.ts +3 -3
- package/dist/DraggablePane.svelte +10 -5
- package/dist/DraggablePane.svelte.d.ts +3 -3
- package/dist/FilePicker.svelte.d.ts +3 -3
- package/dist/Icon.svelte.d.ts +3 -3
- package/dist/Nav.svelte +76 -31
- package/dist/SettingsSection.svelte.d.ts +3 -3
- package/dist/Spinner.svelte +18 -29
- package/dist/Spinner.svelte.d.ts +3 -3
- package/dist/app.css +4 -0
- package/dist/bands/Bands.svelte +216 -0
- package/dist/bands/Bands.svelte.d.ts +16 -0
- package/dist/bands/BandsAndDos.svelte +26 -0
- package/dist/bands/BandsAndDos.svelte.d.ts +16 -0
- package/dist/bands/Dos.svelte +124 -0
- package/dist/bands/Dos.svelte.d.ts +18 -0
- package/dist/bands/helpers.d.ts +11 -0
- package/dist/bands/helpers.js +195 -0
- package/dist/bands/index.d.ts +5 -0
- package/dist/bands/index.js +6 -0
- package/dist/bands/types.d.ts +54 -0
- package/dist/bands/types.js +2 -0
- package/dist/brillouin/BrillouinZone.svelte +373 -0
- package/dist/brillouin/BrillouinZone.svelte.d.ts +57 -0
- package/dist/brillouin/BrillouinZoneControls.svelte +88 -0
- package/dist/brillouin/BrillouinZoneControls.svelte.d.ts +14 -0
- package/dist/brillouin/BrillouinZoneExportPane.svelte +129 -0
- package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +15 -0
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +115 -0
- package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +13 -0
- package/dist/brillouin/BrillouinZoneScene.svelte +180 -0
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +34 -0
- package/dist/brillouin/compute.d.ts +7 -0
- package/dist/brillouin/compute.js +215 -0
- package/dist/brillouin/index.d.ts +7 -0
- package/dist/brillouin/index.js +7 -0
- package/dist/brillouin/types.d.ts +23 -0
- package/dist/brillouin/types.js +1 -0
- package/dist/composition/BarChart.svelte.d.ts +3 -3
- package/dist/composition/BubbleChart.svelte +7 -6
- package/dist/composition/BubbleChart.svelte.d.ts +3 -3
- package/dist/composition/Composition.svelte.d.ts +3 -3
- package/dist/composition/PieChart.svelte +1 -1
- package/dist/composition/PieChart.svelte.d.ts +3 -3
- package/dist/composition/parse.d.ts +3 -3
- package/dist/coordination/CoordinationBarPlot.svelte +241 -0
- package/dist/coordination/CoordinationBarPlot.svelte.d.ts +29 -0
- package/dist/coordination/calc-coordination.d.ts +15 -0
- package/dist/coordination/calc-coordination.js +66 -0
- package/dist/coordination/index.d.ts +8 -0
- package/dist/coordination/index.js +7 -0
- package/dist/element/BohrAtom.svelte.d.ts +3 -3
- package/dist/element/ElementHeading.svelte.d.ts +3 -3
- package/dist/element/ElementPhoto.svelte.d.ts +3 -3
- package/dist/element/ElementStats.svelte.d.ts +3 -3
- package/dist/element/ElementTile.svelte +1 -1
- package/dist/element/ElementTile.svelte.d.ts +4 -4
- package/dist/element/Nucleus.svelte.d.ts +3 -3
- package/dist/icons.d.ts +4 -0
- package/dist/icons.js +4 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +5 -1
- package/dist/io/export.d.ts +1 -6
- package/dist/io/export.js +12 -12
- package/dist/labels.d.ts +19 -0
- package/dist/labels.js +59 -0
- package/dist/math.d.ts +7 -2
- package/dist/math.js +24 -12
- package/dist/periodic-table/PeriodicTable.svelte.d.ts +3 -3
- package/dist/periodic-table/PeriodicTableControls.svelte.d.ts +3 -3
- package/dist/periodic-table/PropertySelect.svelte +1 -1
- package/dist/periodic-table/PropertySelect.svelte.d.ts +5 -4
- package/dist/periodic-table/TableInset.svelte.d.ts +3 -3
- package/dist/phase-diagram/PhaseDiagram2D.svelte +44 -107
- package/dist/phase-diagram/PhaseDiagram2D.svelte.d.ts +7 -27
- package/dist/phase-diagram/PhaseDiagram3D.svelte +67 -170
- package/dist/phase-diagram/PhaseDiagram3D.svelte.d.ts +7 -31
- package/dist/phase-diagram/PhaseDiagram4D.svelte +87 -145
- package/dist/phase-diagram/PhaseDiagram4D.svelte.d.ts +5 -28
- package/dist/phase-diagram/PhaseDiagramControls.svelte +9 -9
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +6 -6
- package/dist/phase-diagram/PhaseDiagramInfoPane.svelte +4 -4
- package/dist/phase-diagram/PhaseDiagramInfoPane.svelte.d.ts +5 -5
- package/dist/phase-diagram/PhaseDiagramStats.svelte +9 -16
- package/dist/phase-diagram/PhaseDiagramStats.svelte.d.ts +3 -3
- package/dist/phase-diagram/StructurePopup.svelte.d.ts +3 -3
- package/dist/phase-diagram/barycentric-coords.js +13 -24
- package/dist/phase-diagram/helpers.d.ts +12 -14
- package/dist/phase-diagram/helpers.js +70 -23
- package/dist/phase-diagram/index.d.ts +58 -0
- package/dist/phase-diagram/index.js +44 -0
- package/dist/phase-diagram/thermodynamics.js +2 -3
- package/dist/phase-diagram/types.d.ts +3 -8
- package/dist/plot/BarPlot.svelte +474 -240
- package/dist/plot/BarPlot.svelte.d.ts +16 -37
- package/dist/plot/BarPlotControls.svelte +33 -201
- package/dist/plot/BarPlotControls.svelte.d.ts +11 -22
- package/dist/plot/ColorBar.svelte.d.ts +3 -3
- package/dist/plot/ColorScaleSelect.svelte +1 -1
- package/dist/plot/ColorScaleSelect.svelte.d.ts +3 -3
- package/dist/plot/ElementScatter.svelte +5 -5
- package/dist/plot/ElementScatter.svelte.d.ts +8 -8
- package/dist/plot/Histogram.svelte +318 -170
- package/dist/plot/Histogram.svelte.d.ts +21 -41
- package/dist/plot/HistogramControls.svelte +115 -347
- package/dist/plot/HistogramControls.svelte.d.ts +13 -28
- package/dist/plot/Line.svelte +1 -1
- package/dist/plot/Line.svelte.d.ts +4 -4
- package/dist/plot/PlotControls.svelte +280 -0
- package/dist/plot/PlotControls.svelte.d.ts +4 -0
- package/dist/plot/PlotLegend.svelte +9 -24
- package/dist/plot/PlotLegend.svelte.d.ts +3 -3
- package/dist/plot/ScatterPlot.svelte +536 -571
- package/dist/plot/ScatterPlot.svelte.d.ts +18 -90
- package/dist/plot/ScatterPlotControls.svelte +108 -316
- package/dist/plot/ScatterPlotControls.svelte.d.ts +11 -38
- package/dist/plot/ScatterPoint.svelte +1 -1
- package/dist/plot/ScatterPoint.svelte.d.ts +5 -5
- package/dist/plot/SpacegroupBarPlot.svelte +235 -0
- package/dist/plot/SpacegroupBarPlot.svelte.d.ts +9 -0
- package/dist/plot/data-transform.d.ts +2 -2
- package/dist/plot/data-transform.js +1 -5
- package/dist/plot/index.d.ts +12 -200
- package/dist/plot/index.js +14 -6
- package/dist/plot/layout.d.ts +10 -16
- package/dist/plot/layout.js +40 -25
- package/dist/plot/scales.d.ts +7 -8
- package/dist/plot/scales.js +22 -7
- package/dist/plot/types.d.ts +303 -0
- package/dist/plot/types.js +1 -0
- package/dist/rdf/RdfPlot.svelte +156 -0
- package/dist/rdf/RdfPlot.svelte.d.ts +20 -0
- package/dist/rdf/calc-rdf.d.ts +4 -0
- package/dist/rdf/calc-rdf.js +107 -0
- package/dist/rdf/index.d.ts +22 -0
- package/dist/rdf/index.js +2 -0
- package/dist/settings.d.ts +86 -75
- package/dist/settings.js +257 -155
- package/dist/structure/Bond.svelte +126 -110
- package/dist/structure/Bond.svelte.d.ts +7 -20
- package/dist/structure/CanvasTooltip.svelte.d.ts +4 -4
- package/dist/structure/Cylinder.svelte +29 -0
- package/dist/structure/Cylinder.svelte.d.ts +10 -0
- package/dist/structure/Lattice.svelte +1 -2
- package/dist/structure/Lattice.svelte.d.ts +3 -3
- package/dist/structure/Structure.svelte +23 -8
- package/dist/structure/Structure.svelte.d.ts +10 -7
- package/dist/structure/StructureControls.svelte +25 -134
- package/dist/structure/StructureControls.svelte.d.ts +4 -9
- package/dist/structure/StructureExportPane.svelte +188 -0
- package/dist/structure/StructureExportPane.svelte.d.ts +17 -0
- package/dist/structure/StructureInfoPane.svelte.d.ts +3 -3
- package/dist/structure/StructureLegend.svelte +91 -27
- package/dist/structure/StructureLegend.svelte.d.ts +5 -4
- package/dist/structure/StructureScene.svelte +93 -100
- package/dist/structure/StructureScene.svelte.d.ts +15 -12
- package/dist/structure/Vector.svelte +19 -25
- package/dist/structure/Vector.svelte.d.ts +3 -3
- package/dist/structure/bonding.d.ts +16 -14
- package/dist/structure/bonding.js +207 -216
- package/dist/structure/export.d.ts +3 -0
- package/dist/structure/export.js +120 -0
- package/dist/structure/index.d.ts +15 -1
- package/dist/structure/index.js +2 -0
- package/dist/symmetry/WyckoffTable.svelte.d.ts +3 -3
- package/dist/symmetry/index.d.ts +1 -0
- package/dist/symmetry/index.js +1 -0
- package/dist/symmetry/spacegroups.d.ts +9 -0
- package/dist/symmetry/spacegroups.js +397 -0
- package/dist/theme/ThemeControl.svelte.d.ts +3 -3
- package/dist/theme/themes.js +2 -16
- package/dist/trajectory/Trajectory.svelte +52 -78
- package/dist/trajectory/Trajectory.svelte.d.ts +5 -5
- package/dist/trajectory/TrajectoryError.svelte.d.ts +3 -3
- package/dist/trajectory/TrajectoryExportPane.svelte +1 -1
- package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +5 -5
- package/dist/trajectory/TrajectoryInfoPane.svelte +1 -1
- package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +3 -3
- package/dist/trajectory/extract.js +2 -1
- package/dist/trajectory/index.d.ts +1 -1
- package/dist/trajectory/index.js +1 -1
- package/dist/trajectory/parse.js +21 -14
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +17 -0
- package/dist/xrd/XrdPlot.svelte +14 -11
- package/dist/xrd/XrdPlot.svelte.d.ts +6 -5
- package/package.json +20 -12
- package/readme.md +1 -1
- package/dist/material/MaterialCard.svelte +0 -123
- package/dist/material/MaterialCard.svelte.d.ts +0 -9
- package/dist/material/index.d.ts +0 -1
- package/dist/material/index.js +0 -1
- package/dist/plot/formatting.d.ts +0 -7
- package/dist/plot/formatting.js +0 -53
|
@@ -5,81 +5,33 @@ import { format_fractional, format_num } from '../labels';
|
|
|
5
5
|
import { ColorBar } from '../plot';
|
|
6
6
|
import { SvelteMap } from 'svelte/reactivity';
|
|
7
7
|
import { get_ternary_3d_coordinates, get_triangle_centroid, get_triangle_edges, get_triangle_vertical_edges, TRIANGLE_VERTICES, } from './barycentric-coords';
|
|
8
|
-
import
|
|
8
|
+
import * as helpers from './helpers';
|
|
9
|
+
import { default_controls, default_pd_config, PD_STYLE } from './index';
|
|
9
10
|
import PhaseDiagramControls from './PhaseDiagramControls.svelte';
|
|
10
11
|
import PhaseDiagramInfoPane from './PhaseDiagramInfoPane.svelte';
|
|
11
12
|
import StructurePopup from './StructurePopup.svelte';
|
|
12
|
-
import
|
|
13
|
-
let { entries, controls = {}, config = {}, on_point_click, on_point_hover, fullscreen = $bindable(false), enable_fullscreen = true, enable_info_pane = true, wrapper = $bindable(undefined), label_threshold = 50, show_stable = $bindable(true), show_unstable = $bindable(true), show_hull_faces = $bindable(true), hull_face_opacity = $bindable(0.3), color_mode = $bindable(`energy`), color_scale = $bindable(`interpolateViridis`), info_pane_open = $bindable(false), legend_pane_open = $bindable(false),
|
|
14
|
-
on_file_drop, enable_structure_preview = true, energy_source_mode = $bindable(`precomputed`), phase_stats = $bindable(null),
|
|
15
|
-
const merged_controls = $derived({
|
|
16
|
-
...default_controls,
|
|
17
|
-
...controls,
|
|
18
|
-
});
|
|
19
|
-
const default_config = {
|
|
20
|
-
margin: { top: 40, right: 40, bottom: 60, left: 60 },
|
|
21
|
-
width: 600,
|
|
22
|
-
height: 600,
|
|
23
|
-
unstable_threshold: 0.2,
|
|
24
|
-
show_labels: true,
|
|
25
|
-
show_hull: true,
|
|
26
|
-
point_size: 8,
|
|
27
|
-
line_width: 2,
|
|
28
|
-
font_size: 12,
|
|
29
|
-
colors: {
|
|
30
|
-
stable: `#0072B2`,
|
|
31
|
-
unstable: `#E69F00`,
|
|
32
|
-
hull_line: `var(--accent-color, #1976D2)`,
|
|
33
|
-
background: `transparent`,
|
|
34
|
-
text: `var(--text-color, #212121)`,
|
|
35
|
-
edge: `var(--text-color, #212121)`,
|
|
36
|
-
tooltip_bg: `var(--tooltip-bg, rgba(0, 0, 0, 0.85))`,
|
|
37
|
-
tooltip_text: `var(--tooltip-text, white)`,
|
|
38
|
-
annotation: `var(--text-color, #212121)`,
|
|
39
|
-
},
|
|
40
|
-
};
|
|
13
|
+
import * as thermo from './thermodynamics';
|
|
14
|
+
let { entries, controls = {}, config = {}, on_point_click, on_point_hover, fullscreen = $bindable(false), enable_fullscreen = true, enable_info_pane = true, wrapper = $bindable(undefined), label_threshold = 50, show_stable = $bindable(true), show_unstable = $bindable(true), show_hull_faces = $bindable(true), hull_face_opacity = $bindable(0.3), color_mode = $bindable(`energy`), color_scale = $bindable(`interpolateViridis`), info_pane_open = $bindable(false), legend_pane_open = $bindable(false), max_hull_dist_show_phases = $bindable(0.5), // eV/atom above hull for showing entries
|
|
15
|
+
on_file_drop, enable_structure_preview = true, energy_source_mode = $bindable(`precomputed`), phase_stats = $bindable(null), stable_entries = $bindable([]), unstable_entries = $bindable([]), ...rest } = $props();
|
|
16
|
+
const merged_controls = $derived({ ...default_controls, ...controls });
|
|
41
17
|
const merged_config = $derived({
|
|
42
|
-
...
|
|
18
|
+
...default_pd_config,
|
|
43
19
|
...config,
|
|
44
|
-
|
|
45
|
-
})
|
|
46
|
-
// Decide which energy source to use per entry
|
|
47
|
-
const has_precomputed_e_form = $derived(entries.length > 0 && entries.every((e) => typeof e.e_form_per_atom === `number`));
|
|
48
|
-
const has_precomputed_hull = $derived(entries.length > 0 && entries.every((e) => typeof e.e_above_hull === `number`));
|
|
49
|
-
// Build unary references once from entries; inexpensive and used for capability checks
|
|
50
|
-
const unary_refs = $derived.by(() => find_lowest_energy_unary_refs(entries));
|
|
51
|
-
const can_compute_e_form = $derived.by(() => {
|
|
52
|
-
const elements_in_entries = Array.from(new Set(entries.flatMap((e) => Object.keys(e.composition))));
|
|
53
|
-
return elements_in_entries.every((el) => Boolean(unary_refs[el]));
|
|
54
|
-
});
|
|
55
|
-
const can_compute_hull = $derived(can_compute_e_form);
|
|
56
|
-
// Resolve mode to avoid inconsistent states:
|
|
57
|
-
// - If full precomputed available, honor user toggle
|
|
58
|
-
// - Else if we can compute both, use on-the-fly automatically
|
|
59
|
-
// - Else fall back to precomputed (best-effort)
|
|
60
|
-
const energy_mode = $derived((has_precomputed_e_form && has_precomputed_hull)
|
|
61
|
-
? energy_source_mode
|
|
62
|
-
: ((can_compute_e_form && can_compute_hull) ? `on-the-fly` : `precomputed`));
|
|
63
|
-
const effective_entries = $derived.by(() => {
|
|
64
|
-
if (energy_mode === `precomputed`)
|
|
65
|
-
return entries;
|
|
66
|
-
return entries.map((entry) => {
|
|
67
|
-
const e_form = compute_e_form_per_atom(entry, unary_refs);
|
|
68
|
-
if (e_form == null)
|
|
69
|
-
return entry;
|
|
70
|
-
return { ...entry, e_form_per_atom: e_form };
|
|
71
|
-
});
|
|
20
|
+
colors: { ...default_pd_config.colors, ...(config.colors || {}) },
|
|
21
|
+
margin: { t: 40, r: 40, b: 60, l: 60, ...(config.margin || {}) },
|
|
72
22
|
});
|
|
23
|
+
let { // Compute energy mode information
|
|
24
|
+
has_precomputed_e_form, has_precomputed_hull, can_compute_e_form, can_compute_hull, energy_mode, unary_refs, } = $derived(helpers.compute_energy_mode_info(entries, thermo.find_lowest_energy_unary_refs, energy_source_mode));
|
|
25
|
+
const effective_entries = $derived(helpers.get_effective_entries(entries, energy_mode, unary_refs, thermo.compute_e_form_per_atom));
|
|
73
26
|
// Process phase diagram data with unified PhaseEntry interface using effective entries
|
|
74
27
|
const processed_entries = $derived(effective_entries);
|
|
75
|
-
const pd_data = $derived(process_pd_entries(processed_entries));
|
|
28
|
+
const pd_data = $derived(thermo.process_pd_entries(processed_entries));
|
|
76
29
|
const elements = $derived.by(() => {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
console.error(`PhaseDiagram3D: Dataset contains ${all_elements.length} elements, but ternary diagrams require exactly 3. Found: [${all_elements.join(`, `)}]`);
|
|
30
|
+
if (pd_data.elements.length > 3) {
|
|
31
|
+
console.error(`PhaseDiagram3D: Dataset contains ${pd_data.elements.length} elements, but ternary diagrams require exactly 3. Found: [${pd_data.elements.join(`, `)}]`);
|
|
80
32
|
return [];
|
|
81
33
|
}
|
|
82
|
-
return
|
|
34
|
+
return pd_data.elements;
|
|
83
35
|
});
|
|
84
36
|
// 1) Raw 3D coordinates (formation-energy z), independent of hull state
|
|
85
37
|
const coords_entries = $derived.by(() => {
|
|
@@ -103,12 +55,12 @@ const plot_entries = $derived.by(() => {
|
|
|
103
55
|
const enriched = (() => {
|
|
104
56
|
if (energy_mode === `on-the-fly`) {
|
|
105
57
|
const pts = coords_entries.map((e) => ({ x: e.x, y: e.y, z: e.z }));
|
|
106
|
-
const e_hulls = compute_e_above_hull_for_points(pts, hull_model);
|
|
58
|
+
const e_hulls = thermo.compute_e_above_hull_for_points(pts, hull_model);
|
|
107
59
|
return coords_entries.map((e, idx) => ({ ...e, e_above_hull: e_hulls[idx] }));
|
|
108
60
|
}
|
|
109
61
|
return coords_entries;
|
|
110
62
|
})();
|
|
111
|
-
const energy_filtered = enriched.filter((entry) => (entry.e_above_hull ?? 0) <=
|
|
63
|
+
const energy_filtered = enriched.filter((entry) => (entry.e_above_hull ?? 0) <= max_hull_dist_show_phases);
|
|
112
64
|
return energy_filtered.map((entry) => {
|
|
113
65
|
const is_stable = entry.is_stable || entry.e_above_hull === 0;
|
|
114
66
|
return {
|
|
@@ -117,16 +69,18 @@ const plot_entries = $derived.by(() => {
|
|
|
117
69
|
};
|
|
118
70
|
});
|
|
119
71
|
});
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
72
|
+
$effect(() => {
|
|
73
|
+
stable_entries = plot_entries.filter((entry) => entry.is_stable || entry.e_above_hull === 0);
|
|
74
|
+
unstable_entries = plot_entries.filter((entry) => typeof entry.e_above_hull === `number` && entry.e_above_hull > 0 &&
|
|
75
|
+
!entry.is_stable);
|
|
76
|
+
});
|
|
123
77
|
const hull_faces = $derived.by(() => {
|
|
124
78
|
if (coords_entries.length === 0) {
|
|
125
79
|
return [];
|
|
126
80
|
}
|
|
127
81
|
const points = coords_entries.map((e) => ({ x: e.x, y: e.y, z: e.z }));
|
|
128
82
|
try {
|
|
129
|
-
return compute_lower_hull_triangles(points);
|
|
83
|
+
return thermo.compute_lower_hull_triangles(points);
|
|
130
84
|
}
|
|
131
85
|
catch (error) {
|
|
132
86
|
console.error(`Error computing convex hull:`, error);
|
|
@@ -134,7 +88,7 @@ const hull_faces = $derived.by(() => {
|
|
|
134
88
|
}
|
|
135
89
|
});
|
|
136
90
|
// Cached hull model for e_above_hull queries; recompute only when faces change
|
|
137
|
-
let hull_model = $derived.by(() => build_lower_hull_model(hull_faces));
|
|
91
|
+
let hull_model = $derived.by(() => thermo.build_lower_hull_model(hull_faces));
|
|
138
92
|
// Total counts based on hull-enriched entries
|
|
139
93
|
const total_unstable_count = $derived(plot_entries.filter((entry) => typeof entry.e_above_hull === `number` && entry.e_above_hull > 0 &&
|
|
140
94
|
!entry.is_stable).length);
|
|
@@ -203,32 +157,18 @@ $effect(() => {
|
|
|
203
157
|
$effect(() => {
|
|
204
158
|
// deno-fmt-ignore
|
|
205
159
|
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
206
|
-
[show_stable, show_unstable, show_hull_faces, color_mode, color_scale,
|
|
160
|
+
[show_stable, show_unstable, show_hull_faces, color_mode, color_scale, max_hull_dist_show_phases, show_stable_labels, show_unstable_labels, max_hull_dist_show_labels, camera.elevation, camera.azimuth, camera.zoom, camera.center_x, camera.center_y, plot_entries, hull_face_color, hull_face_opacity];
|
|
207
161
|
render_once();
|
|
208
162
|
});
|
|
209
163
|
// Label controls with smart defaults based on entry count
|
|
210
164
|
let show_stable_labels = $state(true);
|
|
211
165
|
let show_unstable_labels = $state(false);
|
|
212
|
-
let
|
|
213
|
-
// Smart label defaults - hide labels if too many entries
|
|
214
|
-
$effect(() => {
|
|
215
|
-
const total_entries = processed_entries.length;
|
|
216
|
-
if (total_entries > label_threshold) {
|
|
217
|
-
show_stable_labels = false;
|
|
218
|
-
show_unstable_labels = false;
|
|
219
|
-
}
|
|
220
|
-
else {
|
|
221
|
-
// For smaller datasets, show stable labels by default
|
|
222
|
-
show_stable_labels = true;
|
|
223
|
-
show_unstable_labels = false;
|
|
224
|
-
}
|
|
225
|
-
});
|
|
166
|
+
let max_hull_dist_show_labels = $state(0.1); // eV/atom above hull for showing labels
|
|
226
167
|
// Function to extract structure data from a phase diagram entry
|
|
227
168
|
function extract_structure_from_entry(entry) {
|
|
228
169
|
const original_entry = entries.find((orig_entry) => orig_entry.entry_id === entry.entry_id);
|
|
229
170
|
return original_entry?.structure || null;
|
|
230
171
|
}
|
|
231
|
-
const get_tooltip_text = (entry) => build_entry_tooltip_text(entry);
|
|
232
172
|
const reset_camera = () => Object.assign(camera, camera_default);
|
|
233
173
|
function reset_all() {
|
|
234
174
|
reset_camera();
|
|
@@ -241,8 +181,8 @@ function reset_all() {
|
|
|
241
181
|
show_unstable = PD_DEFAULTS.ternary.show_unstable;
|
|
242
182
|
show_stable_labels = PD_DEFAULTS.ternary.show_stable_labels;
|
|
243
183
|
show_unstable_labels = PD_DEFAULTS.ternary.show_unstable_labels;
|
|
244
|
-
|
|
245
|
-
|
|
184
|
+
max_hull_dist_show_labels = PD_DEFAULTS.ternary.max_hull_dist_show_labels;
|
|
185
|
+
max_hull_dist_show_phases = PD_DEFAULTS.ternary.max_hull_dist_show_phases;
|
|
246
186
|
show_hull_faces = PD_DEFAULTS.ternary.show_hull_faces;
|
|
247
187
|
hull_face_color = PD_DEFAULTS.ternary.hull_face_color;
|
|
248
188
|
hull_face_opacity = PD_DEFAULTS.ternary.hull_face_opacity;
|
|
@@ -262,7 +202,7 @@ const handle_keydown = (event) => {
|
|
|
262
202
|
};
|
|
263
203
|
async function handle_file_drop(event) {
|
|
264
204
|
drag_over = false;
|
|
265
|
-
const data = await parse_pd_entries_from_drop(event);
|
|
205
|
+
const data = await helpers.parse_pd_entries_from_drop(event);
|
|
266
206
|
if (data)
|
|
267
207
|
on_file_drop?.(data);
|
|
268
208
|
}
|
|
@@ -272,20 +212,13 @@ async function copy_to_clipboard(text, position) {
|
|
|
272
212
|
copy_feedback_visible = true;
|
|
273
213
|
setTimeout(() => copy_feedback_visible = false, 1500);
|
|
274
214
|
}
|
|
275
|
-
|
|
276
|
-
return get_point_color_for_entry(entry, color_mode, merged_config.colors, energy_color_scale);
|
|
277
|
-
}
|
|
215
|
+
const get_point_color = (entry) => helpers.get_point_color_for_entry(entry, color_mode, merged_config.colors, energy_color_scale);
|
|
278
216
|
// Cache energy color scale per frame/setting
|
|
279
|
-
const energy_color_scale = $derived.by(() => get_energy_color_scale(color_mode, color_scale, plot_entries));
|
|
280
|
-
const
|
|
217
|
+
const energy_color_scale = $derived.by(() => helpers.get_energy_color_scale(color_mode, color_scale, plot_entries));
|
|
218
|
+
const max_hull_dist_in_data = $derived(helpers.calc_max_hull_dist_in_data(processed_entries));
|
|
281
219
|
// Phase diagram statistics - compute internally and expose via bindable prop
|
|
282
220
|
$effect(() => {
|
|
283
|
-
phase_stats = get_phase_diagram_stats(processed_entries, elements, 3);
|
|
284
|
-
});
|
|
285
|
-
// Sync stable and unstable entries to bindable props
|
|
286
|
-
$effect(() => {
|
|
287
|
-
stable_entries_out = stable_entries;
|
|
288
|
-
unstable_entries_out = unstable_entries;
|
|
221
|
+
phase_stats = thermo.get_phase_diagram_stats(processed_entries, elements, 3);
|
|
289
222
|
});
|
|
290
223
|
// 3D to 2D projection for ternary diagrams
|
|
291
224
|
function project_3d_point(x, y, z) {
|
|
@@ -294,7 +227,7 @@ function project_3d_point(x, y, z) {
|
|
|
294
227
|
// Center coordinates around the volumetric center of the phase diagram
|
|
295
228
|
const triangle_centroid = get_triangle_centroid();
|
|
296
229
|
// Calculate the energy center (middle of formation energy range)
|
|
297
|
-
const formation_energies = plot_entries.map((e) => e.
|
|
230
|
+
const formation_energies = plot_entries.map((e) => e.e_form);
|
|
298
231
|
const e_form_min = Math.min(0, ...formation_energies);
|
|
299
232
|
const e_form_max = Math.max(0, ...formation_energies);
|
|
300
233
|
const energy_center = (e_form_min + e_form_max) / 2;
|
|
@@ -349,7 +282,7 @@ function draw_triangle_structure() {
|
|
|
349
282
|
if (!ctx)
|
|
350
283
|
return;
|
|
351
284
|
// Get formation energy range for vertical edges
|
|
352
|
-
const formation_energies = plot_entries.map((e) => e.
|
|
285
|
+
const formation_energies = plot_entries.map((e) => e.e_form);
|
|
353
286
|
const e_form_min = Math.min(0, ...formation_energies); // Include 0 for elemental references
|
|
354
287
|
const e_form_max = Math.max(0, ...formation_energies); // Include 0 for elemental references
|
|
355
288
|
// Draw base triangle edges (top triangle at formation energy = 0)
|
|
@@ -418,7 +351,7 @@ function draw_convex_hull_faces() {
|
|
|
418
351
|
if (!ctx || !show_hull_faces || hull_faces.length === 0)
|
|
419
352
|
return;
|
|
420
353
|
// Normalize alpha by formation energy: 0 eV -> 0 alpha, min E_form -> hull_face_opacity
|
|
421
|
-
const formation_energies = plot_entries.map((e) => e.
|
|
354
|
+
const formation_energies = plot_entries.map((e) => e.e_form);
|
|
422
355
|
const min_fe = Math.min(0, ...formation_energies);
|
|
423
356
|
const norm_alpha = (z) => {
|
|
424
357
|
const t = Math.max(0, Math.min(1, (0 - z) / Math.max(1e-6, 0 - min_fe)));
|
|
@@ -504,7 +437,7 @@ function draw_convex_hull_faces() {
|
|
|
504
437
|
}
|
|
505
438
|
// Formation energy color bar helpers
|
|
506
439
|
const e_form_range = $derived.by(() => {
|
|
507
|
-
const energies = plot_entries.map((e) => e.
|
|
440
|
+
const energies = plot_entries.map((e) => e.e_form);
|
|
508
441
|
const min_fe = energies.length ? Math.min(0, ...energies) : -1;
|
|
509
442
|
return [min_fe, 0];
|
|
510
443
|
});
|
|
@@ -604,36 +537,22 @@ function draw_hull_labels() {
|
|
|
604
537
|
const can_label_stable = is_stable_point && show_stable_labels;
|
|
605
538
|
const can_label_unstable = !is_stable_point && show_unstable_labels &&
|
|
606
539
|
(typeof entry.e_above_hull === `number` &&
|
|
607
|
-
entry.e_above_hull <=
|
|
540
|
+
entry.e_above_hull <= max_hull_dist_show_labels);
|
|
608
541
|
if (!(can_label_stable || can_label_unstable))
|
|
609
542
|
continue;
|
|
610
543
|
const projected = project_3d_point(entry.x, entry.y, entry.z);
|
|
611
|
-
// Generate
|
|
544
|
+
// Generate label from composition
|
|
612
545
|
let formula = entry.reduced_formula || entry.name || ``;
|
|
613
546
|
if (!formula) {
|
|
614
|
-
//
|
|
615
|
-
|
|
547
|
+
// Format composition as element fractions
|
|
548
|
+
formula = Object.entries(entry.composition)
|
|
616
549
|
.filter(([, amt]) => amt > 0)
|
|
617
550
|
.sort(([el1], [el2]) => elements.indexOf(el1) -
|
|
618
|
-
elements.indexOf(el2))
|
|
619
|
-
// Find GCD to reduce the formula
|
|
620
|
-
const amounts = composition_elements.map(([, amt]) => Math.round(amt * 1000) / 1000);
|
|
621
|
-
const gcd_val = amounts.reduce((a, b) => {
|
|
622
|
-
// Simple GCD for fractional numbers (scaled by 1000)
|
|
623
|
-
const scale = 1000;
|
|
624
|
-
let a_int = Math.round(a * scale);
|
|
625
|
-
let b_int = Math.round(b * scale);
|
|
626
|
-
while (b_int !== 0) {
|
|
627
|
-
const temp = b_int;
|
|
628
|
-
b_int = a_int % b_int;
|
|
629
|
-
a_int = temp;
|
|
630
|
-
}
|
|
631
|
-
return a_int / scale;
|
|
632
|
-
});
|
|
633
|
-
formula = composition_elements
|
|
551
|
+
elements.indexOf(el2))
|
|
634
552
|
.map(([element, amount]) => {
|
|
635
|
-
|
|
636
|
-
|
|
553
|
+
if (Math.abs(amount - 1) < 1e-6)
|
|
554
|
+
return element;
|
|
555
|
+
return `${element}${format_num(amount, `.2~`)}`;
|
|
637
556
|
})
|
|
638
557
|
.join(``);
|
|
639
558
|
}
|
|
@@ -710,7 +629,7 @@ const handle_hover = (event) => {
|
|
|
710
629
|
: null;
|
|
711
630
|
on_point_hover?.(hover_data);
|
|
712
631
|
};
|
|
713
|
-
const find_entry_at_mouse = (event) => find_pd_entry_at_mouse(canvas, event, plot_entries, (x, y, z) => {
|
|
632
|
+
const find_entry_at_mouse = (event) => helpers.find_pd_entry_at_mouse(canvas, event, plot_entries, (x, y, z) => {
|
|
714
633
|
const pt = project_3d_point(x, y, z);
|
|
715
634
|
return { x: pt.x, y: pt.y };
|
|
716
635
|
});
|
|
@@ -729,7 +648,7 @@ const handle_click = (event) => {
|
|
|
729
648
|
if (structure) {
|
|
730
649
|
selected_structure = structure;
|
|
731
650
|
selected_entry = entry;
|
|
732
|
-
calculate_modal_side();
|
|
651
|
+
modal_place_right = helpers.calculate_modal_side(wrapper);
|
|
733
652
|
modal_open = true;
|
|
734
653
|
}
|
|
735
654
|
}
|
|
@@ -737,16 +656,6 @@ const handle_click = (event) => {
|
|
|
737
656
|
else if (modal_open)
|
|
738
657
|
close_structure_popup();
|
|
739
658
|
};
|
|
740
|
-
// Decide side based on available viewport room; modal is absolutely positioned
|
|
741
|
-
function calculate_modal_side() {
|
|
742
|
-
if (!wrapper)
|
|
743
|
-
return;
|
|
744
|
-
const rect = wrapper.getBoundingClientRect();
|
|
745
|
-
const viewport_width = globalThis.innerWidth;
|
|
746
|
-
const space_on_right = viewport_width - rect.right;
|
|
747
|
-
const space_on_left = rect.left;
|
|
748
|
-
modal_place_right = space_on_right >= space_on_left;
|
|
749
|
-
}
|
|
750
659
|
function close_structure_popup() {
|
|
751
660
|
modal_open = false;
|
|
752
661
|
selected_structure = null;
|
|
@@ -755,7 +664,7 @@ function close_structure_popup() {
|
|
|
755
664
|
const handle_double_click = (event) => {
|
|
756
665
|
const entry = find_entry_at_mouse(event);
|
|
757
666
|
if (entry) {
|
|
758
|
-
copy_to_clipboard(
|
|
667
|
+
copy_to_clipboard(helpers.build_entry_tooltip_text(entry), {
|
|
759
668
|
x: event.clientX,
|
|
760
669
|
y: event.clientY,
|
|
761
670
|
});
|
|
@@ -819,20 +728,14 @@ $effect(() => {
|
|
|
819
728
|
// Fullscreen handling with camera reset on transitions
|
|
820
729
|
let was_fullscreen = $state(fullscreen);
|
|
821
730
|
$effect(() => {
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
}
|
|
830
|
-
// Reset camera only on fullscreen transitions
|
|
831
|
-
if (fullscreen !== was_fullscreen) {
|
|
832
|
-
camera.center_x = 0;
|
|
833
|
-
camera.center_y = -50;
|
|
834
|
-
was_fullscreen = fullscreen;
|
|
835
|
-
}
|
|
731
|
+
helpers.setup_fullscreen_effect(fullscreen, wrapper, (entering_fullscreen) => {
|
|
732
|
+
// Reset camera only on fullscreen transitions
|
|
733
|
+
if (entering_fullscreen !== was_fullscreen) {
|
|
734
|
+
camera.center_x = 0;
|
|
735
|
+
camera.center_y = -50;
|
|
736
|
+
was_fullscreen = entering_fullscreen;
|
|
737
|
+
}
|
|
738
|
+
});
|
|
836
739
|
});
|
|
837
740
|
let style = $derived(`--pd-stable-color:${merged_config.colors?.stable || `#0072B2`};
|
|
838
741
|
--pd-unstable-color:${merged_config.colors?.unstable || `#E69F00`};
|
|
@@ -882,13 +785,11 @@ let style = $derived(`--pd-stable-color:${merged_config.colors?.stable || `#0072
|
|
|
882
785
|
|
|
883
786
|
<!-- Formation Energy Color Bar (bottom-left corner) -->
|
|
884
787
|
{#if color_mode === `energy` && plot_entries.length > 0}
|
|
885
|
-
{@const
|
|
788
|
+
{@const hull_distances = plot_entries
|
|
886
789
|
.map((e) => e.e_above_hull)
|
|
887
790
|
.filter((v): v is number => typeof v === `number`)}
|
|
888
|
-
{@const min_energy =
|
|
889
|
-
{@const max_energy =
|
|
890
|
-
? Math.max(...formation_energies, 0.1)
|
|
891
|
-
: 0.1}
|
|
791
|
+
{@const min_energy = hull_distances.length > 0 ? Math.min(...hull_distances) : 0}
|
|
792
|
+
{@const max_energy = hull_distances.length > 0 ? Math.max(...hull_distances, 0.1) : 0.1}
|
|
892
793
|
<ColorBar
|
|
893
794
|
title="Energy above hull (eV/atom)"
|
|
894
795
|
range={[min_energy, max_energy]}
|
|
@@ -930,12 +831,10 @@ let style = $derived(`--pd-stable-color:${merged_config.colors?.stable || `#0072
|
|
|
930
831
|
{phase_stats}
|
|
931
832
|
{stable_entries}
|
|
932
833
|
{unstable_entries}
|
|
933
|
-
{
|
|
934
|
-
{
|
|
834
|
+
{max_hull_dist_show_phases}
|
|
835
|
+
{max_hull_dist_show_labels}
|
|
935
836
|
{label_threshold}
|
|
936
|
-
toggle_props={{
|
|
937
|
-
class: `info-btn`,
|
|
938
|
-
}}
|
|
837
|
+
toggle_props={{ class: `info-btn` }}
|
|
939
838
|
/>
|
|
940
839
|
{/if}
|
|
941
840
|
|
|
@@ -959,17 +858,15 @@ let style = $derived(`--pd-stable-color:${merged_config.colors?.stable || `#0072
|
|
|
959
858
|
bind:show_unstable
|
|
960
859
|
bind:show_stable_labels
|
|
961
860
|
bind:show_unstable_labels
|
|
962
|
-
bind:
|
|
963
|
-
bind:
|
|
964
|
-
{
|
|
861
|
+
bind:max_hull_dist_show_phases
|
|
862
|
+
bind:max_hull_dist_show_labels
|
|
863
|
+
{max_hull_dist_in_data}
|
|
965
864
|
{stable_entries}
|
|
966
865
|
{unstable_entries}
|
|
967
866
|
{total_unstable_count}
|
|
968
867
|
{camera}
|
|
969
868
|
{merged_controls}
|
|
970
|
-
toggle_props={{
|
|
971
|
-
class: `legend-controls-btn`,
|
|
972
|
-
}}
|
|
869
|
+
toggle_props={{ class: `legend-controls-btn` }}
|
|
973
870
|
{show_hull_faces}
|
|
974
871
|
on_hull_faces_change={(value) => show_hull_faces = value}
|
|
975
872
|
{hull_face_color}
|
|
@@ -1,33 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
on_point_click?: (entry: TernaryPlotEntry) => void;
|
|
9
|
-
on_point_hover?: (data: HoverData3D<TernaryPlotEntry> | null) => void;
|
|
10
|
-
fullscreen?: boolean;
|
|
11
|
-
enable_fullscreen?: boolean;
|
|
12
|
-
enable_info_pane?: boolean;
|
|
13
|
-
wrapper?: HTMLDivElement;
|
|
14
|
-
label_threshold?: number;
|
|
15
|
-
show_stable?: boolean;
|
|
16
|
-
show_unstable?: boolean;
|
|
17
|
-
show_hull_faces?: boolean;
|
|
18
|
-
hull_face_opacity?: number;
|
|
19
|
-
color_mode?: `stability` | `energy`;
|
|
20
|
-
color_scale?: D3InterpolateName;
|
|
21
|
-
info_pane_open?: boolean;
|
|
22
|
-
legend_pane_open?: boolean;
|
|
23
|
-
energy_threshold?: number;
|
|
24
|
-
on_file_drop?: (entries: PhaseEntry[]) => void;
|
|
25
|
-
enable_structure_preview?: boolean;
|
|
26
|
-
energy_source_mode?: `precomputed` | `on-the-fly`;
|
|
27
|
-
phase_stats?: PhaseStats | null;
|
|
28
|
-
stable_entries_out?: TernaryPlotEntry[];
|
|
29
|
-
unstable_entries_out?: TernaryPlotEntry[];
|
|
30
|
-
}
|
|
31
|
-
declare const PhaseDiagram3D: import("svelte").Component<Props, {}, "color_mode" | "color_scale" | "show_stable" | "show_unstable" | "energy_threshold" | "fullscreen" | "info_pane_open" | "legend_pane_open" | "show_hull_faces" | "hull_face_opacity" | "wrapper" | "energy_source_mode" | "phase_stats" | "stable_entries_out" | "unstable_entries_out">;
|
|
1
|
+
import type { BasePhaseDiagramProps, Hull3DProps } from './index';
|
|
2
|
+
import type { TernaryPlotEntry } from './types';
|
|
3
|
+
type $$ComponentProps = BasePhaseDiagramProps<TernaryPlotEntry> & Hull3DProps & {
|
|
4
|
+
stable_entries?: TernaryPlotEntry[];
|
|
5
|
+
unstable_entries?: TernaryPlotEntry[];
|
|
6
|
+
};
|
|
7
|
+
declare const PhaseDiagram3D: import("svelte").Component<$$ComponentProps, {}, "show_hull_faces" | "hull_face_opacity" | "color_mode" | "color_scale" | "show_stable" | "show_unstable" | "max_hull_dist_show_phases" | "fullscreen" | "info_pane_open" | "legend_pane_open" | "wrapper" | "energy_source_mode" | "stable_entries" | "unstable_entries" | "phase_stats">;
|
|
32
8
|
type PhaseDiagram3D = ReturnType<typeof PhaseDiagram3D>;
|
|
33
9
|
export default PhaseDiagram3D;
|