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.
- package/dist/MillerIndexInput.svelte +5 -5
- package/dist/api/optimade.js +3 -3
- package/dist/brillouin/BrillouinZone.svelte +5 -2
- package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneExportPane.svelte +1 -3
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +1 -1
- package/dist/brillouin/BrillouinZoneScene.svelte +5 -5
- package/dist/brillouin/compute.js +21 -21
- package/dist/brillouin/index.d.ts +1 -1
- package/dist/brillouin/index.js +0 -1
- package/dist/brillouin/types.d.ts +8 -13
- package/dist/chempot-diagram/ChemPotDiagram.svelte +3 -3
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +3 -4
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +33 -34
- package/dist/chempot-diagram/compute.js +1 -7
- package/dist/chempot-diagram/temperature.d.ts +1 -1
- package/dist/chempot-diagram/temperature.js +1 -3
- package/dist/chempot-diagram/types.d.ts +4 -9
- package/dist/colors/index.js +5 -5
- package/dist/composition/Composition.svelte +2 -1
- package/dist/composition/Formula.svelte +7 -4
- package/dist/composition/FormulaFilter.svelte +1 -3
- package/dist/composition/format.js +4 -4
- package/dist/composition/parse.d.ts +2 -1
- package/dist/composition/parse.js +61 -46
- package/dist/convex-hull/ConvexHull2D.svelte +62 -51
- package/dist/convex-hull/ConvexHull3D.svelte +101 -90
- package/dist/convex-hull/ConvexHull4D.svelte +70 -58
- package/dist/convex-hull/ConvexHullControls.svelte +24 -35
- package/dist/convex-hull/ConvexHullInfoPane.svelte +8 -5
- package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +2 -0
- package/dist/convex-hull/ConvexHullStats.svelte +9 -2
- package/dist/convex-hull/ConvexHullStats.svelte.d.ts +2 -0
- package/dist/convex-hull/GasPressureControls.svelte +7 -7
- package/dist/convex-hull/StructurePopup.svelte +65 -30
- package/dist/convex-hull/StructurePopup.svelte.d.ts +6 -6
- package/dist/convex-hull/TemperatureSlider.svelte +8 -5
- package/dist/convex-hull/barycentric-coords.d.ts +2 -2
- package/dist/convex-hull/barycentric-coords.js +2 -2
- package/dist/convex-hull/gas-thermodynamics.js +2 -4
- package/dist/convex-hull/helpers.d.ts +13 -2
- package/dist/convex-hull/helpers.js +37 -16
- package/dist/convex-hull/index.d.ts +1 -0
- package/dist/convex-hull/index.js +1 -0
- package/dist/convex-hull/thermodynamics.d.ts +2 -1
- package/dist/convex-hull/thermodynamics.js +7 -7
- package/dist/convex-hull/types.d.ts +15 -15
- package/dist/effects.svelte.d.ts +12 -0
- package/dist/effects.svelte.js +37 -0
- package/dist/element/BohrAtom.svelte +4 -4
- package/dist/element/data.json.gz.d.ts +3 -1
- package/dist/element/index.d.ts +1 -1
- package/dist/element/index.js +0 -1
- package/dist/fermi-surface/FermiSurface.svelte +4 -4
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceControls.svelte +15 -19
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte +8 -6
- package/dist/fermi-surface/compute.js +2 -2
- package/dist/fermi-surface/export.js +13 -26
- package/dist/fermi-surface/parse.js +8 -12
- package/dist/fermi-surface/types.d.ts +2 -5
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +21 -3
- package/dist/heatmap-matrix/index.js +6 -6
- package/dist/io/decompress.d.ts +2 -1
- package/dist/io/decompress.js +1 -1
- package/dist/io/export.js +1 -1
- package/dist/io/index.d.ts +1 -1
- package/dist/io/index.js +0 -1
- package/dist/io/url-drop.js +7 -1
- package/dist/isosurface/IsosurfaceControls.svelte +11 -25
- package/dist/isosurface/slice.js +1 -1
- package/dist/isosurface/types.js +12 -12
- package/dist/labels.d.ts +1 -1
- package/dist/labels.js +14 -11
- package/dist/layout/InfoTag.svelte +6 -4
- package/dist/layout/PropertyFilter.svelte +4 -2
- package/dist/layout/json-tree/JsonTree.svelte +22 -14
- package/dist/layout/json-tree/JsonValue.svelte +2 -2
- package/dist/layout/json-tree/types.d.ts +3 -2
- package/dist/layout/json-tree/types.js +0 -1
- package/dist/layout/json-tree/utils.d.ts +4 -4
- package/dist/layout/json-tree/utils.js +12 -20
- package/dist/marching-cubes.js +13 -15
- package/dist/math.d.ts +11 -1
- package/dist/math.js +15 -6
- package/dist/overlays/DragControlTab.svelte +98 -0
- package/dist/overlays/DragControlTab.svelte.d.ts +8 -0
- package/dist/overlays/DraggablePane.svelte +7 -84
- package/dist/overlays/index.d.ts +1 -0
- package/dist/overlays/index.js +1 -0
- package/dist/periodic-table/PeriodicTable.svelte +11 -11
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +4 -2
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramControls.svelte +4 -9
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +2 -10
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +2 -3
- package/dist/phase-diagram/TdbInfoPanel.svelte +3 -3
- package/dist/phase-diagram/build-diagram.js +11 -18
- package/dist/phase-diagram/diagram-input.d.ts +5 -9
- package/dist/phase-diagram/index.d.ts +2 -2
- package/dist/phase-diagram/index.js +0 -2
- package/dist/phase-diagram/parse.d.ts +2 -2
- package/dist/phase-diagram/parse.js +6 -10
- package/dist/phase-diagram/svg-to-diagram.js +15 -15
- package/dist/phase-diagram/types.d.ts +5 -11
- package/dist/phase-diagram/utils.d.ts +2 -2
- package/dist/phase-diagram/utils.js +9 -11
- package/dist/plot/BarPlot.svelte +162 -314
- package/dist/plot/BarPlot.svelte.d.ts +5 -4
- package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
- package/dist/plot/BinnedScatterPlot.svelte +1114 -0
- package/dist/plot/BinnedScatterPlot.svelte.d.ts +66 -0
- package/dist/plot/ColorBar.svelte +19 -17
- package/dist/plot/ColorBar.svelte.d.ts +1 -1
- package/dist/plot/FillArea.svelte +2 -4
- package/dist/plot/FillArea.svelte.d.ts +1 -1
- package/dist/plot/Histogram.svelte +167 -281
- package/dist/plot/Histogram.svelte.d.ts +1 -1
- package/dist/plot/HistogramControls.svelte.d.ts +1 -1
- package/dist/plot/InteractiveAxisLabel.svelte +5 -3
- package/dist/plot/InteractiveAxisLabel.svelte.d.ts +1 -1
- package/dist/plot/PlotAxis.svelte +169 -0
- package/dist/plot/PlotAxis.svelte.d.ts +24 -0
- package/dist/plot/PlotControls.svelte.d.ts +1 -1
- package/dist/plot/ReferenceLine3D.svelte +53 -51
- package/dist/plot/ReferencePlane.svelte +39 -42
- package/dist/plot/ScatterPlot.svelte +300 -367
- package/dist/plot/ScatterPlot.svelte.d.ts +8 -5
- package/dist/plot/ScatterPlot3D.svelte +33 -6
- package/dist/plot/ScatterPlot3D.svelte.d.ts +3 -2
- package/dist/plot/ScatterPlot3DControls.svelte +9 -9
- package/dist/plot/ScatterPlotControls.svelte +3 -4
- package/dist/plot/ScatterPoint.svelte +18 -27
- package/dist/plot/ScatterPoint.svelte.d.ts +4 -3
- package/dist/plot/Surface3D.svelte +4 -7
- package/dist/plot/ZeroLines.svelte +2 -1
- package/dist/plot/ZeroLines.svelte.d.ts +2 -1
- package/dist/plot/ZoomRect.svelte +2 -2
- package/dist/plot/ZoomRect.svelte.d.ts +3 -3
- package/dist/plot/adaptive-density.d.ts +69 -0
- package/dist/plot/adaptive-density.js +191 -0
- package/dist/plot/auto-place.d.ts +43 -0
- package/dist/plot/auto-place.js +122 -0
- package/dist/plot/axis-utils.js +3 -5
- package/dist/plot/binned-scatter-types.d.ts +59 -0
- package/dist/plot/binned-scatter-types.js +1 -0
- package/dist/plot/data-cleaning.js +1 -1
- package/dist/plot/data-transform.js +1 -1
- package/dist/plot/fill-utils.d.ts +4 -9
- package/dist/plot/fill-utils.js +29 -44
- package/dist/plot/index.d.ts +4 -0
- package/dist/plot/index.js +2 -0
- package/dist/plot/interactions.d.ts +4 -4
- package/dist/plot/interactions.js +4 -3
- package/dist/plot/layout.d.ts +20 -2
- package/dist/plot/layout.js +59 -16
- package/dist/plot/reference-line.d.ts +1 -1
- package/dist/plot/reference-line.js +9 -11
- package/dist/plot/scales.d.ts +1 -1
- package/dist/plot/scales.js +20 -23
- package/dist/plot/types.d.ts +30 -58
- package/dist/plot/types.js +2 -6
- package/dist/plot/utils/label-placement.d.ts +24 -3
- package/dist/plot/utils/label-placement.js +82 -12
- package/dist/plot/utils/series-visibility.d.ts +8 -2
- package/dist/plot/utils/series-visibility.js +23 -5
- package/dist/rdf/RdfPlot.svelte +5 -5
- package/dist/rdf/calc-rdf.js +3 -3
- package/dist/sanitize.d.ts +2 -0
- package/dist/sanitize.js +2 -0
- package/dist/spectral/Bands.svelte +1 -1
- package/dist/spectral/BandsAndDos.svelte +22 -16
- package/dist/spectral/BrillouinBandsDos.svelte +20 -16
- package/dist/spectral/Dos.svelte +1 -1
- package/dist/spectral/helpers.d.ts +4 -2
- package/dist/spectral/helpers.js +44 -35
- package/dist/spectral/index.d.ts +1 -1
- package/dist/spectral/index.js +0 -1
- package/dist/structure/AtomLegend.svelte +23 -6
- package/dist/structure/AtomLegend.svelte.d.ts +1 -0
- package/dist/structure/CanvasTooltip.svelte +9 -9
- package/dist/structure/CanvasTooltip.svelte.d.ts +1 -1
- package/dist/structure/CellSelect.svelte +14 -16
- package/dist/structure/Structure.svelte +317 -68
- package/dist/structure/Structure.svelte.d.ts +4 -2
- package/dist/structure/StructureControls.svelte +20 -45
- package/dist/structure/StructureExportPane.svelte +2 -1
- package/dist/structure/StructureInfoPane.svelte +10 -8
- package/dist/structure/StructureScene.svelte +527 -177
- package/dist/structure/StructureScene.svelte.d.ts +5 -2
- package/dist/structure/atom-properties.js +4 -4
- package/dist/structure/bond-order-perception.js +115 -98
- package/dist/structure/bonding.d.ts +27 -1
- package/dist/structure/bonding.js +187 -16
- package/dist/structure/export.js +1 -1
- package/dist/structure/index.d.ts +3 -2
- package/dist/structure/index.js +0 -2
- package/dist/structure/parse.js +88 -59
- package/dist/symmetry/WyckoffTable.svelte +7 -0
- package/dist/symmetry/index.js +13 -14
- package/dist/table/HeatmapTable.svelte +45 -66
- package/dist/table/HeatmapTable.svelte.d.ts +1 -1
- package/dist/table/ToggleMenu.svelte +19 -10
- package/dist/theme/themes.mjs +12 -0
- package/dist/tooltip/index.d.ts +1 -1
- package/dist/tooltip/index.js +0 -1
- package/dist/trajectory/Trajectory.svelte +43 -15
- package/dist/trajectory/TrajectoryInfoPane.svelte +2 -2
- package/dist/trajectory/extract.js +1 -1
- package/dist/trajectory/frame-reader.js +4 -4
- package/dist/trajectory/helpers.d.ts +5 -4
- package/dist/trajectory/helpers.js +9 -17
- package/dist/trajectory/index.d.ts +2 -2
- package/dist/trajectory/index.js +2 -2
- package/dist/trajectory/parse/ase.js +4 -4
- package/dist/trajectory/parse/hdf5.js +1 -1
- package/dist/trajectory/parse/index.js +2 -3
- package/dist/trajectory/parse/lammps.js +1 -1
- package/dist/trajectory/parse/vasp.js +1 -1
- package/dist/trajectory/plotting.d.ts +1 -1
- package/dist/trajectory/plotting.js +38 -38
- package/dist/trajectory/types.d.ts +1 -1
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +9 -0
- package/dist/xrd/calc-xrd.js +3 -4
- package/dist/xrd/parse.js +1 -1
- package/package.json +42 -22
package/dist/plot/scales.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export type PlotScaleFn = ScaleContinuousNumeric<number, number> | ScaleTime<num
|
|
|
17
17
|
export declare function scale_arcsinh(threshold?: number): ArcsinhScale;
|
|
18
18
|
export declare function generate_arcsinh_ticks(min: number, max: number, threshold?: number, count?: number): number[];
|
|
19
19
|
export declare function create_scale(scale_type: ScaleType, domain: [number, number], output_range: [number, number]): ScaleContinuousNumeric<number, number> | ArcsinhScale;
|
|
20
|
-
export declare
|
|
20
|
+
export declare const create_time_scale: (domain: [number, number], output_range: [number, number]) => ScaleTime<number, number, never>;
|
|
21
21
|
export declare function generate_ticks(domain: [number, number], scale_type: ScaleType, ticks_option: TicksOption | undefined, scale_fn: PlotScaleFn, // D3 scale function with .ticks() method
|
|
22
22
|
options?: {
|
|
23
23
|
format?: string;
|
package/dist/plot/scales.js
CHANGED
|
@@ -107,7 +107,7 @@ export function generate_arcsinh_ticks(min, max, threshold = 1, count = 10) {
|
|
|
107
107
|
const ticks = [0];
|
|
108
108
|
// Add positive ticks
|
|
109
109
|
const pos_ticks = generate_positive_arcsinh_ticks(0, hi, safe_threshold, half_count);
|
|
110
|
-
ticks.push(...pos_ticks.filter((
|
|
110
|
+
ticks.push(...pos_ticks.filter((tick) => tick > 0));
|
|
111
111
|
// Add negative ticks (mirror of positive)
|
|
112
112
|
const neg_ticks = generate_positive_arcsinh_ticks(0, -lo, safe_threshold, half_count);
|
|
113
113
|
ticks.push(...neg_ticks.filter((tick) => tick > 0).map((tick) => -tick));
|
|
@@ -116,13 +116,12 @@ export function generate_arcsinh_ticks(min, max, threshold = 1, count = 10) {
|
|
|
116
116
|
// Add boundaries if not already present and we have room
|
|
117
117
|
const sorted = dedupe_sort(ticks);
|
|
118
118
|
if (sorted.length < count) {
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
ticks.push(lo);
|
|
119
|
+
// Snap the larger-magnitude boundary to a clean power of 10 (raw extremes would render
|
|
120
|
+
// as long unrounded labels); keeps some coverage for very small tick counts.
|
|
121
|
+
const boundary = Math.abs(hi) >= Math.abs(lo) ? hi : lo;
|
|
122
|
+
const nice = Math.sign(boundary) * 10 ** Math.floor(Math.log10(Math.abs(boundary)));
|
|
123
|
+
if (Number.isFinite(nice) && nice !== 0 && !sorted.includes(nice))
|
|
124
|
+
ticks.push(nice);
|
|
126
125
|
}
|
|
127
126
|
}
|
|
128
127
|
return dedupe_sort(ticks);
|
|
@@ -146,12 +145,10 @@ function generate_positive_arcsinh_ticks(min, max, threshold, count) {
|
|
|
146
145
|
}
|
|
147
146
|
}
|
|
148
147
|
else {
|
|
149
|
-
// Large range: combine linear near zero with powers of 10
|
|
150
|
-
//
|
|
151
|
-
//
|
|
152
|
-
|
|
153
|
-
ticks.push(min);
|
|
154
|
-
ticks.push(max);
|
|
148
|
+
// Large range: combine linear near zero with powers of 10.
|
|
149
|
+
// Domain endpoints are intentionally NOT added as ticks: raw extremes render as long
|
|
150
|
+
// unrounded labels (e.g. 1325.8239811994677). Powers of 10 plus 2x/5x multiples below
|
|
151
|
+
// already give clean round ticks; pass axis.ticks/axis.format for custom labels.
|
|
155
152
|
// Add threshold as a tick if in range
|
|
156
153
|
if (threshold >= min && threshold <= max)
|
|
157
154
|
ticks.push(threshold);
|
|
@@ -197,11 +194,9 @@ export function create_scale(scale_type, domain, output_range) {
|
|
|
197
194
|
return scaleLinear().domain(domain).range(output_range);
|
|
198
195
|
}
|
|
199
196
|
// Create a time scale for time-based data
|
|
200
|
-
export
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
.range(output_range);
|
|
204
|
-
}
|
|
197
|
+
export const create_time_scale = (domain, output_range) => scaleTime()
|
|
198
|
+
.domain([new Date(domain[0]), new Date(domain[1])])
|
|
199
|
+
.range(output_range);
|
|
205
200
|
// Unified tick generation function
|
|
206
201
|
export function generate_ticks(domain, scale_type, ticks_option, scale_fn, // D3 scale function with .ticks() method
|
|
207
202
|
options = {}) {
|
|
@@ -359,7 +354,8 @@ export function get_nice_data_range(points, get_value, limits, scale_type, paddi
|
|
|
359
354
|
]) // Ensure log domain > 0
|
|
360
355
|
: scaleLinear().domain([data_min, data_max]);
|
|
361
356
|
scale.nice();
|
|
362
|
-
|
|
357
|
+
const [nice_min = data_min, nice_max = data_max] = scale.domain();
|
|
358
|
+
return [nice_min, nice_max];
|
|
363
359
|
}
|
|
364
360
|
// Generate logarithmic ticks (from ScatterPlot)
|
|
365
361
|
export function generate_log_ticks(min, max, ticks_option) {
|
|
@@ -400,9 +396,10 @@ export function get_tick_label(tick_value, ticks_option) {
|
|
|
400
396
|
// Create a color scale function from configuration
|
|
401
397
|
export function create_color_scale(color_scale_config, auto_color_range) {
|
|
402
398
|
const scheme = typeof color_scale_config === `string` ? color_scale_config : color_scale_config.scheme;
|
|
403
|
-
const
|
|
404
|
-
|
|
405
|
-
|
|
399
|
+
const candidate_interpolator = Object.entries(d3_sc).find(([key]) => key === scheme)?.[1];
|
|
400
|
+
const interpolator = typeof candidate_interpolator === `function`
|
|
401
|
+
? candidate_interpolator
|
|
402
|
+
: d3_sc.interpolateViridis;
|
|
406
403
|
const [min_val, max_val] = (typeof color_scale_config === `string` ? undefined : color_scale_config.value_range) ??
|
|
407
404
|
auto_color_range;
|
|
408
405
|
const scale_type = typeof color_scale_config === `string` ? undefined : color_scale_config.type;
|
package/dist/plot/types.d.ts
CHANGED
|
@@ -1,26 +1,17 @@
|
|
|
1
1
|
import type { D3SymbolName } from '../labels';
|
|
2
|
-
import type { Vec2, Vec3 } from '../math';
|
|
2
|
+
import type { Point2D, Point3D, Vec2, Vec3 } from '../math';
|
|
3
3
|
import type DraggablePane from '../overlays/DraggablePane.svelte';
|
|
4
4
|
import type { ComponentProps, Snippet } from 'svelte';
|
|
5
5
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
6
6
|
import type { TweenOptions } from 'svelte/motion';
|
|
7
7
|
export type { TweenOptions } from 'svelte/motion';
|
|
8
|
+
import type { Sides } from './layout';
|
|
8
9
|
import type PlotLegend from './PlotLegend.svelte';
|
|
9
10
|
import type { TicksOption } from './scales';
|
|
10
|
-
export type XyObj = {
|
|
11
|
-
x: number;
|
|
12
|
-
y: number;
|
|
13
|
-
};
|
|
14
11
|
export type XyShift = {
|
|
15
12
|
x?: number;
|
|
16
13
|
y?: number;
|
|
17
14
|
};
|
|
18
|
-
export type Sides = {
|
|
19
|
-
t?: number;
|
|
20
|
-
b?: number;
|
|
21
|
-
l?: number;
|
|
22
|
-
r?: number;
|
|
23
|
-
};
|
|
24
15
|
export type InitialRanges = {
|
|
25
16
|
initial_x_range: Vec2;
|
|
26
17
|
initial_x2_range: Vec2;
|
|
@@ -31,7 +22,7 @@ export type Point<Metadata = Record<string, unknown>> = {
|
|
|
31
22
|
x: number;
|
|
32
23
|
y: number;
|
|
33
24
|
metadata?: Metadata;
|
|
34
|
-
offset?:
|
|
25
|
+
offset?: Point2D;
|
|
35
26
|
};
|
|
36
27
|
export interface PointStyle {
|
|
37
28
|
fill?: string;
|
|
@@ -57,10 +48,14 @@ export interface HoverStyle {
|
|
|
57
48
|
}
|
|
58
49
|
export interface LabelStyle {
|
|
59
50
|
text?: string;
|
|
60
|
-
offset?:
|
|
51
|
+
offset?: Point2D;
|
|
61
52
|
font_size?: string;
|
|
62
53
|
font_family?: string;
|
|
63
54
|
auto_placement?: boolean;
|
|
55
|
+
size?: {
|
|
56
|
+
width: number;
|
|
57
|
+
height: number;
|
|
58
|
+
};
|
|
64
59
|
}
|
|
65
60
|
export interface BarStyle {
|
|
66
61
|
color?: string;
|
|
@@ -84,8 +79,8 @@ export interface PlotPoint<Metadata = Record<string, unknown>> extends Point<Met
|
|
|
84
79
|
point_style?: PointStyle;
|
|
85
80
|
point_hover?: HoverStyle;
|
|
86
81
|
point_label?: LabelStyle;
|
|
87
|
-
point_offset?:
|
|
88
|
-
point_tween?: TweenOptions<
|
|
82
|
+
point_offset?: Point2D;
|
|
83
|
+
point_tween?: TweenOptions<Point2D>;
|
|
89
84
|
}
|
|
90
85
|
export type Markers = `line` | `points` | `line+points` | `none`;
|
|
91
86
|
export interface DataSeries<Metadata = Record<string, unknown>> {
|
|
@@ -101,8 +96,8 @@ export interface DataSeries<Metadata = Record<string, unknown>> {
|
|
|
101
96
|
point_style?: PointStyle[] | PointStyle;
|
|
102
97
|
point_hover?: HoverStyle[] | HoverStyle;
|
|
103
98
|
point_label?: LabelStyle[] | LabelStyle;
|
|
104
|
-
point_offset?:
|
|
105
|
-
point_tween?: TweenOptions<
|
|
99
|
+
point_offset?: Point2D[] | Point2D;
|
|
100
|
+
point_tween?: TweenOptions<Point2D>;
|
|
106
101
|
visible?: boolean;
|
|
107
102
|
label?: string;
|
|
108
103
|
legend_group?: string;
|
|
@@ -184,7 +179,7 @@ export interface ArcsinhScaleConfig {
|
|
|
184
179
|
threshold?: number;
|
|
185
180
|
}
|
|
186
181
|
export type ScaleType = `linear` | `log` | `arcsinh` | `time` | ArcsinhScaleConfig;
|
|
187
|
-
export declare
|
|
182
|
+
export declare const is_scale_type_name: (val: string) => val is ScaleTypeName;
|
|
188
183
|
export declare function get_scale_type_name(scale_type: ScaleType | undefined): ScaleTypeName;
|
|
189
184
|
export declare function get_arcsinh_threshold(scale_type: ScaleType | undefined): number;
|
|
190
185
|
export declare function is_time_scale(scale_type: ScaleType | undefined, format: string | undefined): boolean;
|
|
@@ -207,13 +202,18 @@ export interface LabelPlacementConfig {
|
|
|
207
202
|
weights?: LabelPlacementWeights;
|
|
208
203
|
leader_line_threshold?: number;
|
|
209
204
|
max_labels?: number;
|
|
205
|
+
candidate_gap?: number;
|
|
206
|
+
max_neighbors?: {
|
|
207
|
+
count: number;
|
|
208
|
+
radius: number;
|
|
209
|
+
};
|
|
210
210
|
}
|
|
211
211
|
export type HoverConfig = {
|
|
212
212
|
threshold_px: number;
|
|
213
213
|
};
|
|
214
214
|
export type LegendConfig = Omit<ComponentProps<typeof PlotLegend>, `series_data` | `on_drag_start` | `on_drag` | `on_drag_end`> & {
|
|
215
215
|
margin?: number | Sides;
|
|
216
|
-
tween?: TweenOptions<
|
|
216
|
+
tween?: TweenOptions<Point2D>;
|
|
217
217
|
responsive?: boolean;
|
|
218
218
|
draggable?: boolean;
|
|
219
219
|
axis_clearance?: number;
|
|
@@ -278,7 +278,7 @@ export interface BarSeries<Metadata = Record<string, unknown>> {
|
|
|
278
278
|
point_style?: PointStyle[] | PointStyle;
|
|
279
279
|
point_hover?: HoverStyle[] | HoverStyle;
|
|
280
280
|
point_label?: LabelStyle[] | LabelStyle;
|
|
281
|
-
point_offset?:
|
|
281
|
+
point_offset?: Point2D[] | Point2D;
|
|
282
282
|
}
|
|
283
283
|
export interface TickLabelConfig {
|
|
284
284
|
inside?: boolean;
|
|
@@ -294,7 +294,7 @@ export interface AxisOption {
|
|
|
294
294
|
unit?: string;
|
|
295
295
|
}
|
|
296
296
|
export type Y2SyncMode = `none` | `synced` | `align`;
|
|
297
|
-
export declare
|
|
297
|
+
export declare const is_y2_sync_mode: (val: string) => val is Y2SyncMode;
|
|
298
298
|
export interface Y2SyncConfig {
|
|
299
299
|
mode: Y2SyncMode;
|
|
300
300
|
align_value?: number;
|
|
@@ -440,17 +440,10 @@ export declare const DEFAULT_GRID_STYLE: {
|
|
|
440
440
|
export declare const DEFAULT_MARKERS: "line+points";
|
|
441
441
|
export declare const DEFAULT_SERIES_COLORS: readonly ["#4e79a7", "#f28e2c", "#e15759", "#76b7b2", "#59a14f", "#edc949", "#af7aa1", "#ff9da7", "#9c755f", "#bab0ab"];
|
|
442
442
|
export declare const DEFAULT_SERIES_SYMBOLS: readonly ["Circle", "Square", "Triangle", "Cross", "Diamond", "Star", "Wye"];
|
|
443
|
-
export type XyzObj = {
|
|
444
|
-
x: number;
|
|
445
|
-
y: number;
|
|
446
|
-
z: number;
|
|
447
|
-
};
|
|
448
443
|
export interface ScatterPoint3D<Metadata = Record<string, unknown>> extends Point<Metadata> {
|
|
449
444
|
z: number;
|
|
450
445
|
}
|
|
451
|
-
export interface DataSeries3D<Metadata = Record<string, unknown>> extends Omit<DataSeries<Metadata>, `
|
|
452
|
-
x: readonly number[];
|
|
453
|
-
y: readonly number[];
|
|
446
|
+
export interface DataSeries3D<Metadata = Record<string, unknown>> extends Omit<DataSeries<Metadata>, `y_axis` | `filtered_data`> {
|
|
454
447
|
z: readonly number[];
|
|
455
448
|
filtered_data?: InternalPoint3D<Metadata>[];
|
|
456
449
|
}
|
|
@@ -471,8 +464,8 @@ export interface Surface3DConfig {
|
|
|
471
464
|
z_fn?: (x: number, y: number) => number;
|
|
472
465
|
u_range?: Vec2;
|
|
473
466
|
v_range?: Vec2;
|
|
474
|
-
parametric_fn?: (u: number, v: number) =>
|
|
475
|
-
points?:
|
|
467
|
+
parametric_fn?: (u: number, v: number) => Point3D;
|
|
468
|
+
points?: Point3D[];
|
|
476
469
|
triangles?: Vec3[];
|
|
477
470
|
color?: string;
|
|
478
471
|
color_fn?: (x: number, y: number, z: number) => string;
|
|
@@ -502,13 +495,8 @@ export interface DisplayConfig3D extends DisplayConfig {
|
|
|
502
495
|
projection_opacity?: number;
|
|
503
496
|
projection_scale?: number;
|
|
504
497
|
}
|
|
505
|
-
export interface Scatter3DHandlerProps<Metadata = Record<string, unknown>> {
|
|
506
|
-
x: number;
|
|
507
|
-
y: number;
|
|
498
|
+
export interface Scatter3DHandlerProps<Metadata = Record<string, unknown>> extends Omit<HandlerProps<Metadata>, `x_axis` | `x2_axis` | `y_axis` | `y2_axis`> {
|
|
508
499
|
z: number;
|
|
509
|
-
metadata?: Metadata | null;
|
|
510
|
-
label?: string | null;
|
|
511
|
-
series_idx: number;
|
|
512
500
|
x_axis: AxisConfig3D;
|
|
513
501
|
y_axis: AxisConfig3D;
|
|
514
502
|
z_axis: AxisConfig3D;
|
|
@@ -516,7 +504,6 @@ export interface Scatter3DHandlerProps<Metadata = Record<string, unknown>> {
|
|
|
516
504
|
y_formatted: string;
|
|
517
505
|
z_formatted: string;
|
|
518
506
|
color_value?: number | null;
|
|
519
|
-
fullscreen?: boolean;
|
|
520
507
|
}
|
|
521
508
|
export type Scatter3DHandlerEvent<Metadata = Record<string, unknown>> = Scatter3DHandlerProps<Metadata> & {
|
|
522
509
|
event?: MouseEvent;
|
|
@@ -707,16 +694,13 @@ export type RefLine = RefLineBase & ({
|
|
|
707
694
|
p2: [RefLineValue, RefLineValue];
|
|
708
695
|
});
|
|
709
696
|
export declare const REF_LINE_STYLE_DEFAULTS: Required<RefLineStyle>;
|
|
710
|
-
|
|
711
|
-
id?: string | number;
|
|
712
|
-
x_span?: [number | null, number | null];
|
|
713
|
-
y_span?: [number | null, number | null];
|
|
697
|
+
type Ref3DBase = Omit<RefLineBase, `coord_mode` | `x_axis` | `y_axis` | `style` | `hover_style` | `annotation` | `on_click` | `on_hover`> & {
|
|
714
698
|
z_span?: [number | null, number | null];
|
|
699
|
+
};
|
|
700
|
+
export interface RefLine3DBase extends Ref3DBase {
|
|
715
701
|
style?: RefLineStyle;
|
|
716
|
-
visible?: boolean;
|
|
717
|
-
label?: string;
|
|
718
|
-
metadata?: Record<string, unknown>;
|
|
719
702
|
hover_style?: RefLineStyle;
|
|
703
|
+
annotation?: RefLineAnnotation;
|
|
720
704
|
on_click?: (event: {
|
|
721
705
|
line_idx: number;
|
|
722
706
|
line_id?: string | number;
|
|
@@ -725,10 +709,6 @@ export interface RefLine3DBase {
|
|
|
725
709
|
line_idx: number;
|
|
726
710
|
line_id?: string | number;
|
|
727
711
|
} | null) => void;
|
|
728
|
-
z_index?: LayerZIndex;
|
|
729
|
-
show_in_legend?: boolean;
|
|
730
|
-
legend_group?: string;
|
|
731
|
-
annotation?: RefLineAnnotation;
|
|
732
712
|
}
|
|
733
713
|
export type RefLine3D = RefLine3DBase & ({
|
|
734
714
|
type: `x-axis`;
|
|
@@ -758,16 +738,8 @@ export interface RefPlaneStyle {
|
|
|
758
738
|
wireframe_color?: string;
|
|
759
739
|
double_sided?: boolean;
|
|
760
740
|
}
|
|
761
|
-
export interface RefPlaneBase {
|
|
762
|
-
id?: string | number;
|
|
763
|
-
x_span?: [number | null, number | null];
|
|
764
|
-
y_span?: [number | null, number | null];
|
|
765
|
-
z_span?: [number | null, number | null];
|
|
741
|
+
export interface RefPlaneBase extends Ref3DBase {
|
|
766
742
|
style?: RefPlaneStyle;
|
|
767
|
-
visible?: boolean;
|
|
768
|
-
label?: string;
|
|
769
|
-
show_in_legend?: boolean;
|
|
770
|
-
metadata?: Record<string, unknown>;
|
|
771
743
|
}
|
|
772
744
|
export type RefPlane = RefPlaneBase & ({
|
|
773
745
|
type: `xy`;
|
package/dist/plot/types.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
// Type guard for select value narrowing (avoids unsafe casts)
|
|
2
2
|
const SCALE_TYPE_NAMES = new Set([`linear`, `log`, `arcsinh`, `time`]);
|
|
3
|
-
export
|
|
4
|
-
return SCALE_TYPE_NAMES.has(val);
|
|
5
|
-
}
|
|
3
|
+
export const is_scale_type_name = (val) => SCALE_TYPE_NAMES.has(val);
|
|
6
4
|
// Helper to normalize ScaleType to base type name
|
|
7
5
|
export function get_scale_type_name(scale_type) {
|
|
8
6
|
if (!scale_type)
|
|
@@ -34,9 +32,7 @@ export function is_time_scale(scale_type, format) {
|
|
|
34
32
|
}
|
|
35
33
|
// Type guard for select value narrowing (avoids unsafe casts)
|
|
36
34
|
const Y2_SYNC_MODES = new Set([`none`, `synced`, `align`]);
|
|
37
|
-
export
|
|
38
|
-
return Y2_SYNC_MODES.has(val);
|
|
39
|
-
}
|
|
35
|
+
export const is_y2_sync_mode = (val) => Y2_SYNC_MODES.has(val);
|
|
40
36
|
export const LINE_TYPES = [`solid`, `dashed`, `dotted`];
|
|
41
37
|
// Define grid cell identifiers
|
|
42
38
|
export const CELLS_3X3 = [
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Point2D } from '../../math';
|
|
2
|
+
import type { AxisConfig, DataSeries } from '..';
|
|
2
3
|
import type { PlotScaleFn } from '../scales';
|
|
3
4
|
import type { LabelPlacementConfig, LabelPlacementWeights } from '../types';
|
|
4
5
|
export interface Rect {
|
|
@@ -21,13 +22,33 @@ interface AnchorInfo {
|
|
|
21
22
|
interface LabelState extends Rect {
|
|
22
23
|
anchor_idx: number;
|
|
23
24
|
}
|
|
25
|
+
export interface LabelSize {
|
|
26
|
+
width: number;
|
|
27
|
+
height: number;
|
|
28
|
+
}
|
|
29
|
+
export interface LeaderLineSegment {
|
|
30
|
+
x1: number;
|
|
31
|
+
y1: number;
|
|
32
|
+
x2: number;
|
|
33
|
+
y2: number;
|
|
34
|
+
}
|
|
35
|
+
export interface LeaderLineOptions {
|
|
36
|
+
point: Point2D;
|
|
37
|
+
point_radius: number;
|
|
38
|
+
label_center: Point2D;
|
|
39
|
+
label_size: LabelSize;
|
|
40
|
+
min_length?: number;
|
|
41
|
+
label_padding?: number;
|
|
42
|
+
}
|
|
24
43
|
export declare function parse_font_size(size_str?: string): number;
|
|
44
|
+
export declare function estimate_label_size(text: string, font_size_str?: string): LabelSize;
|
|
25
45
|
export declare function rect_overlap_area(a: Rect, b: Rect): number;
|
|
26
46
|
export declare function rect_circle_overlap(rect: Rect, cx: number, cy: number, radius: number): number;
|
|
27
47
|
export declare function segments_intersect(ax1: number, ay1: number, ax2: number, ay2: number, bx1: number, by1: number, bx2: number, by2: number): boolean;
|
|
28
48
|
export declare function segment_rect_intersects(sx1: number, sy1: number, sx2: number, sy2: number, rect: Rect): boolean;
|
|
29
49
|
export declare function rect_out_of_bounds_area(rect: Rect, bounds: PlotBounds): number;
|
|
30
|
-
export declare function
|
|
50
|
+
export declare function label_leader_segment({ point, point_radius, label_center, label_size, min_length, label_padding, }: LeaderLineOptions): LeaderLineSegment | null;
|
|
51
|
+
export declare function generate_candidates(ax: number, ay: number, point_radius: number, label_w: number, label_h: number, gap: number): Point2D[];
|
|
31
52
|
export declare function compute_delta_energy(labels: LabelState[], anchors: AnchorInfo[], changed_idx: number, old_state: LabelState, new_state: LabelState, weights: Required<LabelPlacementWeights>, bounds: PlotBounds): number;
|
|
32
53
|
export declare function compute_label_positions(filtered_series: DataSeries[], config: LabelPlacementConfig, scales: {
|
|
33
54
|
x_scale_fn: PlotScaleFn;
|
|
@@ -43,5 +64,5 @@ export declare function compute_label_positions(filtered_series: DataSeries[], c
|
|
|
43
64
|
l: number;
|
|
44
65
|
r: number;
|
|
45
66
|
};
|
|
46
|
-
}): Record<string,
|
|
67
|
+
}): Record<string, Point2D>;
|
|
47
68
|
export {};
|
|
@@ -7,6 +7,14 @@ const DEFAULT_WEIGHTS = {
|
|
|
7
7
|
distance: 0.5,
|
|
8
8
|
bounds: 100,
|
|
9
9
|
};
|
|
10
|
+
const NEIGHBOR_CELL_OFFSETS = [-1, 0, 1];
|
|
11
|
+
const copy_state = (target, source) => {
|
|
12
|
+
target.x = source.x;
|
|
13
|
+
target.y = source.y;
|
|
14
|
+
target.w = source.w;
|
|
15
|
+
target.h = source.h;
|
|
16
|
+
target.anchor_idx = source.anchor_idx;
|
|
17
|
+
};
|
|
10
18
|
export function parse_font_size(size_str) {
|
|
11
19
|
if (!size_str)
|
|
12
20
|
return 12;
|
|
@@ -16,6 +24,15 @@ export function parse_font_size(size_str) {
|
|
|
16
24
|
const value = parseFloat(match[1]);
|
|
17
25
|
return match[2] === `em` || match[2] === `rem` ? value * 16 : value;
|
|
18
26
|
}
|
|
27
|
+
export function estimate_label_size(text, font_size_str) {
|
|
28
|
+
const font_size = parse_font_size(font_size_str);
|
|
29
|
+
const label_lines = text.split(/\r?\n/);
|
|
30
|
+
const max_line_length = Math.max(...label_lines.map((line) => line.length));
|
|
31
|
+
return {
|
|
32
|
+
width: max_line_length * font_size * 0.6 + 10,
|
|
33
|
+
height: label_lines.length * font_size * 1.2,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
19
36
|
// === Geometry helpers ===
|
|
20
37
|
export function rect_overlap_area(a, b) {
|
|
21
38
|
const ox = Math.max(0, Math.min(a.x + a.w, b.x + b.w) - Math.max(a.x, b.x));
|
|
@@ -64,6 +81,26 @@ export function rect_out_of_bounds_area(rect, bounds) {
|
|
|
64
81
|
penalty += (rect.y + rect.h - bounds.max_y) * rect.w;
|
|
65
82
|
return penalty;
|
|
66
83
|
}
|
|
84
|
+
export function label_leader_segment({ point, point_radius, label_center, label_size, min_length = 6, label_padding = 1, }) {
|
|
85
|
+
const delta_x = label_center.x - point.x;
|
|
86
|
+
const delta_y = label_center.y - point.y;
|
|
87
|
+
const center_distance = Math.hypot(delta_x, delta_y);
|
|
88
|
+
if (center_distance <= 0)
|
|
89
|
+
return null;
|
|
90
|
+
const unit_x = delta_x / center_distance;
|
|
91
|
+
const unit_y = delta_y / center_distance;
|
|
92
|
+
const start_x = point.x + unit_x * point_radius;
|
|
93
|
+
const start_y = point.y + unit_y * point_radius;
|
|
94
|
+
const half_width = label_size.width / 2 + label_padding;
|
|
95
|
+
const half_height = label_size.height / 2 + label_padding;
|
|
96
|
+
const edge_distance = Math.min(Math.abs(unit_x) > 0.001 ? half_width / Math.abs(unit_x) : Infinity, Math.abs(unit_y) > 0.001 ? half_height / Math.abs(unit_y) : Infinity);
|
|
97
|
+
const visible_length = center_distance - point_radius - edge_distance;
|
|
98
|
+
if (visible_length <= min_length)
|
|
99
|
+
return null;
|
|
100
|
+
const end_x = label_center.x - unit_x * edge_distance;
|
|
101
|
+
const end_y = label_center.y - unit_y * edge_distance;
|
|
102
|
+
return { x1: start_x, y1: start_y, x2: end_x, y2: end_y };
|
|
103
|
+
}
|
|
67
104
|
// 8 candidate positions around anchor: R, TR, T, TL, L, BL, B, BR
|
|
68
105
|
// Positions are top-left corner of the label bounding box.
|
|
69
106
|
// All positions keep a full `offset` gap from the marker edge.
|
|
@@ -131,6 +168,41 @@ export function compute_delta_energy(labels, anchors, changed_idx, old_state, ne
|
|
|
131
168
|
}
|
|
132
169
|
return delta;
|
|
133
170
|
}
|
|
171
|
+
function cull_dense_labels(label_infos, max_neighbors, radius) {
|
|
172
|
+
if (radius <= 0 || label_infos.length <= max_neighbors + 1)
|
|
173
|
+
return label_infos;
|
|
174
|
+
const radius_squared = radius * radius;
|
|
175
|
+
const get_cell = (value) => Math.floor(value / radius);
|
|
176
|
+
const grid = {};
|
|
177
|
+
label_infos.forEach(({ anchor }, label_idx) => {
|
|
178
|
+
const key = `${get_cell(anchor.x)},${get_cell(anchor.y)}`;
|
|
179
|
+
const bucket = grid[key] ?? (grid[key] = []);
|
|
180
|
+
bucket.push(label_idx);
|
|
181
|
+
});
|
|
182
|
+
return label_infos.filter(({ anchor }, label_idx) => {
|
|
183
|
+
const cell_x = get_cell(anchor.x);
|
|
184
|
+
const cell_y = get_cell(anchor.y);
|
|
185
|
+
let neighbors = 0;
|
|
186
|
+
for (const cell_x_offset of NEIGHBOR_CELL_OFFSETS) {
|
|
187
|
+
for (const cell_y_offset of NEIGHBOR_CELL_OFFSETS) {
|
|
188
|
+
const bucket = grid[`${cell_x + cell_x_offset},${cell_y + cell_y_offset}`];
|
|
189
|
+
if (!bucket)
|
|
190
|
+
continue;
|
|
191
|
+
for (const neighbor_idx of bucket) {
|
|
192
|
+
if (neighbor_idx === label_idx)
|
|
193
|
+
continue;
|
|
194
|
+
const delta_x = anchor.x - label_infos[neighbor_idx].anchor.x;
|
|
195
|
+
const delta_y = anchor.y - label_infos[neighbor_idx].anchor.y;
|
|
196
|
+
if (delta_x * delta_x + delta_y * delta_y <= radius_squared)
|
|
197
|
+
neighbors += 1;
|
|
198
|
+
if (neighbors > max_neighbors)
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return true;
|
|
204
|
+
});
|
|
205
|
+
}
|
|
134
206
|
// === Main export ===
|
|
135
207
|
export function compute_label_positions(filtered_series, config, scales, bounds) {
|
|
136
208
|
const { x_scale_fn, y_scale_fn, y2_scale_fn, x_axis } = scales;
|
|
@@ -142,7 +214,8 @@ export function compute_label_positions(filtered_series, config, scales, bounds)
|
|
|
142
214
|
max_y: height - pad.b,
|
|
143
215
|
};
|
|
144
216
|
// Collect all label data in a single pass
|
|
145
|
-
|
|
217
|
+
let label_infos = [];
|
|
218
|
+
const candidate_gap = config.candidate_gap ?? 4;
|
|
146
219
|
for (const series of filtered_series) {
|
|
147
220
|
for (const pt of series.filtered_data ?? []) {
|
|
148
221
|
if (!pt.point_label?.auto_placement || !pt.point_label.text)
|
|
@@ -151,19 +224,23 @@ export function compute_label_positions(filtered_series, config, scales, bounds)
|
|
|
151
224
|
? x_scale_fn(new Date(pt.x))
|
|
152
225
|
: x_scale_fn(pt.x);
|
|
153
226
|
const ay = (series.y_axis === `y2` ? y2_scale_fn : y_scale_fn)(pt.y);
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
const
|
|
227
|
+
const label_size = pt.point_label.size ??
|
|
228
|
+
estimate_label_size(pt.point_label.text, pt.point_label.font_size);
|
|
229
|
+
const label_w = label_size.width;
|
|
230
|
+
const label_h = label_size.height;
|
|
157
231
|
const radius = pt.point_style?.radius ?? 3;
|
|
158
232
|
label_infos.push({
|
|
159
233
|
id: `${pt.series_idx}-${pt.point_idx}`,
|
|
160
234
|
anchor: { x: ax, y: ay, radius },
|
|
161
235
|
width: label_w,
|
|
162
236
|
height: label_h,
|
|
163
|
-
candidates: generate_candidates(ax, ay, radius, label_w, label_h,
|
|
237
|
+
candidates: generate_candidates(ax, ay, radius, label_w, label_h, candidate_gap),
|
|
164
238
|
});
|
|
165
239
|
}
|
|
166
240
|
}
|
|
241
|
+
if (config.max_neighbors) {
|
|
242
|
+
label_infos = cull_dense_labels(label_infos, config.max_neighbors.count, config.max_neighbors.radius);
|
|
243
|
+
}
|
|
167
244
|
const num_labels = label_infos.length;
|
|
168
245
|
if (num_labels === 0)
|
|
169
246
|
return {};
|
|
@@ -218,13 +295,6 @@ export function compute_label_positions(filtered_series, config, scales, bounds)
|
|
|
218
295
|
// Reusable scratch objects to avoid allocations in the hot loop
|
|
219
296
|
const old_scratch = { x: 0, y: 0, w: 0, h: 0, anchor_idx: 0 };
|
|
220
297
|
const new_scratch = { x: 0, y: 0, w: 0, h: 0, anchor_idx: 0 };
|
|
221
|
-
const copy_state = (dst, src) => {
|
|
222
|
-
dst.x = src.x;
|
|
223
|
-
dst.y = src.y;
|
|
224
|
-
dst.w = src.w;
|
|
225
|
-
dst.h = src.h;
|
|
226
|
-
dst.anchor_idx = src.anchor_idx;
|
|
227
|
-
};
|
|
228
298
|
for (let step = 0; step < total_steps; step++) {
|
|
229
299
|
const temperature = Math.max(0.001, 1.0 - step * cooling_rate);
|
|
230
300
|
const label_idx = Math.floor(next_random() * num_labels);
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import type { DataSeries } from '../types';
|
|
2
2
|
export type StrRecord = Record<string, unknown>;
|
|
3
|
+
type SeriesSource = [string, string, string, unknown, unknown];
|
|
4
|
+
export type SeriesVisibilitySnapshot = {
|
|
5
|
+
visibility: boolean[];
|
|
6
|
+
source: SeriesSource[];
|
|
7
|
+
};
|
|
3
8
|
export declare function have_compatible_units<Metadata extends StrRecord = StrRecord>(series1: DataSeries<Metadata>, series2: DataSeries<Metadata>): boolean;
|
|
4
9
|
export declare function toggle_series_visibility<Metadata extends StrRecord = StrRecord>(series: DataSeries<Metadata>[], series_idx: number): DataSeries<Metadata>[];
|
|
5
10
|
export declare function toggle_group_visibility<Metadata extends StrRecord = StrRecord>(series: DataSeries<Metadata>[], series_indices: number[]): DataSeries<Metadata>[];
|
|
6
|
-
export declare function handle_legend_double_click<Metadata extends StrRecord = StrRecord>(series: DataSeries<Metadata>[], idx: number,
|
|
11
|
+
export declare function handle_legend_double_click<Metadata extends StrRecord = StrRecord>(series: DataSeries<Metadata>[], idx: number, prev_snapshot: SeriesVisibilitySnapshot | null): {
|
|
7
12
|
series: DataSeries<Metadata>[];
|
|
8
|
-
|
|
13
|
+
prev_visibility: SeriesVisibilitySnapshot | null;
|
|
9
14
|
};
|
|
15
|
+
export {};
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
const series_source = (series, length = series.length) => series
|
|
2
|
+
.slice(0, length)
|
|
3
|
+
.map((srs) => [srs.label ?? ``, srs.unit ?? ``, srs.y_axis ?? ``, srs.x, srs.y]);
|
|
4
|
+
const same_series_source = (series, snapshot_series) => series.length === snapshot_series.length &&
|
|
5
|
+
series.every((source, idx) => source.every((part, part_idx) => Object.is(part, snapshot_series[idx][part_idx])));
|
|
1
6
|
export function have_compatible_units(series1, series2) {
|
|
2
7
|
if (!series1.unit || !series2.unit)
|
|
3
8
|
return true;
|
|
@@ -34,12 +39,18 @@ export function toggle_group_visibility(series, series_indices) {
|
|
|
34
39
|
const new_visibility = !all_visible;
|
|
35
40
|
return series.map((srs, idx) => idx_set.has(idx) ? { ...srs, visible: new_visibility } : srs);
|
|
36
41
|
}
|
|
37
|
-
export function handle_legend_double_click(series, idx,
|
|
42
|
+
export function handle_legend_double_click(series, idx, prev_snapshot) {
|
|
38
43
|
if (idx < 0 || idx >= series.length) {
|
|
39
|
-
return { series,
|
|
44
|
+
return { series, prev_visibility: prev_snapshot };
|
|
40
45
|
}
|
|
41
46
|
const { label } = series[idx];
|
|
42
47
|
const current = series.map((srs) => srs.visible ?? true);
|
|
48
|
+
const current_source = prev_snapshot
|
|
49
|
+
? series_source(series, prev_snapshot.visibility.length)
|
|
50
|
+
: [];
|
|
51
|
+
const prev_visibility = prev_snapshot && same_series_source(current_source, prev_snapshot.source)
|
|
52
|
+
? prev_snapshot.visibility
|
|
53
|
+
: null;
|
|
43
54
|
// Only check original series (ignore new ones added after isolation)
|
|
44
55
|
const check_series = prev_visibility ? series.slice(0, prev_visibility.length) : series;
|
|
45
56
|
const is_isolated = check_series.every((srs, srs_idx) => {
|
|
@@ -52,16 +63,23 @@ export function handle_legend_double_click(series, idx, prev_visibility) {
|
|
|
52
63
|
series: series.map((srs, srs_idx) => srs_idx < prev_visibility.length && current[srs_idx] !== prev_visibility[srs_idx]
|
|
53
64
|
? { ...srs, visible: prev_visibility[srs_idx] }
|
|
54
65
|
: srs),
|
|
55
|
-
|
|
66
|
+
prev_visibility: null,
|
|
56
67
|
};
|
|
57
68
|
}
|
|
58
69
|
// Isolate series
|
|
59
|
-
const new_prev = prev_visibility
|
|
70
|
+
const new_prev = prev_visibility
|
|
71
|
+
? prev_snapshot
|
|
72
|
+
: current.filter(Boolean).length > 1
|
|
73
|
+
? {
|
|
74
|
+
visibility: [...current],
|
|
75
|
+
source: series_source(series),
|
|
76
|
+
}
|
|
77
|
+
: null;
|
|
60
78
|
return {
|
|
61
79
|
series: series.map((srs, srs_idx) => {
|
|
62
80
|
const in_group = label ? srs.label === label : srs_idx === idx;
|
|
63
81
|
return (srs.visible ?? true) !== in_group ? { ...srs, visible: in_group } : srs;
|
|
64
82
|
}),
|
|
65
|
-
|
|
83
|
+
prev_visibility: new_prev,
|
|
66
84
|
};
|
|
67
85
|
}
|
package/dist/rdf/RdfPlot.svelte
CHANGED
|
@@ -130,10 +130,10 @@
|
|
|
130
130
|
for (const { struct, label } of struct_list) {
|
|
131
131
|
if (mode === `element_pairs`) {
|
|
132
132
|
const pairs = calculate_all_pair_rdfs(struct, { cutoff, n_bins, pbc })
|
|
133
|
-
result.push(...pairs.map((
|
|
134
|
-
label:
|
|
133
|
+
result.push(...pairs.map((pair) => ({
|
|
134
|
+
label: pair.element_pair ? `${pair.element_pair[0]}-${pair.element_pair[1]}` : label,
|
|
135
135
|
legend_group: label, // Group by structure name for multi-structure plots
|
|
136
|
-
pattern:
|
|
136
|
+
pattern: pair,
|
|
137
137
|
})))
|
|
138
138
|
} else {
|
|
139
139
|
const pattern = calculate_rdf(struct, { cutoff, n_bins, pbc })
|
|
@@ -143,8 +143,8 @@
|
|
|
143
143
|
return result
|
|
144
144
|
})
|
|
145
145
|
|
|
146
|
-
const max_r = $derived(Math.max(...entries.flatMap((
|
|
147
|
-
const max_g = $derived(Math.max(1.2, ...entries.flatMap((
|
|
146
|
+
const max_r = $derived(Math.max(...entries.flatMap((entry) => entry.pattern.r), 0))
|
|
147
|
+
const max_g = $derived(Math.max(1.2, ...entries.flatMap((entry) => entry.pattern.g_r)))
|
|
148
148
|
|
|
149
149
|
const series = $derived<DataSeries[]>(
|
|
150
150
|
entries.map((ent, idx) => ({
|
package/dist/rdf/calc-rdf.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { calc_lattice_params, create_lattice_converters, euclidean_dist, pbc_dist, } from '../math';
|
|
2
2
|
import { make_supercell } from '../structure/supercell';
|
|
3
|
+
const get_occu = (site, elem) => elem ? (site.species.find((spec) => spec.element === elem)?.occu ?? 0) : 1;
|
|
4
|
+
const has_species = (site, elem) => !elem || site.species.some((spec) => spec.element === elem);
|
|
5
|
+
const sum_occu = (sites, elem) => sites.reduce((sum, site) => sum + get_occu(site, elem), 0);
|
|
3
6
|
// Calculate radial distribution function
|
|
4
7
|
export function calculate_rdf(structure, options = {}) {
|
|
5
8
|
const { center_species, neighbor_species, cutoff = 15, n_bins = 75, auto_expand = true, expansion_factor = 2.0, } = options;
|
|
@@ -33,8 +36,6 @@ export function calculate_rdf(structure, options = {}) {
|
|
|
33
36
|
if (sites.length === 0)
|
|
34
37
|
return { r, g_r };
|
|
35
38
|
// Get occupancy weight for a site-species pair (supports mixed occupancy)
|
|
36
|
-
const get_occu = (site, elem) => elem ? (site.species.find((spec) => spec.element === elem)?.occu ?? 0) : 1;
|
|
37
|
-
const has_species = (site, elem) => !elem || site.species.some((spec) => spec.element === elem);
|
|
38
39
|
const centers = sites.filter((site) => has_species(site, center_species));
|
|
39
40
|
const neighbors = sites.filter((site) => has_species(site, neighbor_species));
|
|
40
41
|
if (centers.length === 0 || neighbors.length === 0) {
|
|
@@ -61,7 +62,6 @@ export function calculate_rdf(structure, options = {}) {
|
|
|
61
62
|
}
|
|
62
63
|
}
|
|
63
64
|
// Normalize using occupancy-weighted pair count (excludes self-interactions for same species)
|
|
64
|
-
const sum_occu = (arr, elem) => arr.reduce((sum, site) => sum + get_occu(site, elem), 0);
|
|
65
65
|
const center_weight = sum_occu(centers, center_species);
|
|
66
66
|
const neighbor_weight = sum_occu(neighbors, neighbor_species);
|
|
67
67
|
const self_weight = center_species === neighbor_species
|