UNPKG

bands-visualiser

Version:

A plotly.js renderer for Bands, DOS, combined Bands/Dos and fatBands.

215 lines (189 loc) 4.99 kB
const baseColors = [ "#636EFA", "#EF553B", "#00CC96", "#AB63FA", "#FFA15A", "#19D3F3", "#FF6692", "#B6E880", "#FF97FF", "#FECB52", ]; export function getColor(i) { if (i < baseColors.length) { return baseColors[i]; } else { // Fallback: generate a unique-ish color using HSL const hue = (i * 47) % 360; // 47 is a prime: avoids obvious cycles return `hsl(${hue}, 70%, 50%)`; } } export function mergeLegendTracesByName(traces) { const merged = new Set(); const mergedTraces = traces.map((trace) => { const traceName = trace.name || ""; const show = !merged.has(traceName); if (show) { merged.add(traceName); } return { ...trace, legendgroup: traceName, showlegend: show, }; }); return mergedTraces; } export function getXYData(bandData) { const xs = []; const ys = []; let lastX = null; bandData.paths.forEach((path, pathIndex) => { const pathX = path.x; const pathVals = path.values; if (pathIndex > 0) { xs.push(null); ys.forEach((yBand) => yBand.push(null)); } pathX.forEach((xVal, i) => { if (xVal === lastX) { xs.push(null); ys.forEach((yBand) => yBand.push(null)); } xs.push(xVal); lastX = xVal; pathVals.forEach((band, bIndex) => { if (!ys[bIndex]) ys[bIndex] = []; ys[bIndex].push(band[i]); }); }); }); return { xs, ys }; } export function prettifyLabels(label) { const greekMapping = { GAMMA: "Γ", DELTA: "Δ", SIGMA: "Σ", LAMBDA: "Λ", }; Object.keys(greekMapping).forEach((symbol) => { const regex = new RegExp(symbol, "gi"); label = label.replace(regex, greekMapping[symbol]); }); label = label.replace(/\bG\b/g, "Γ"); label = label.replace(/-/g, "—"); const ssMapping = { 0: "₀", 1: "₁", 2: "₂", 3: "₃", 4: "₄", 5: "₅", 6: "₆", 7: "₇", 8: "₈", 9: "₉", }; label = label.replace(/_(.)/g, (match, p1) => ssMapping[p1] || match); return label; } export function getXLabelPos(paths = td.paths) { const xLabelPos = [0]; for (const path of paths) { if (path.x.length < 3) continue; //skip short paths (these dont move on x) xLabelPos.push(path.x[path.x.length - 1]); } return xLabelPos; } export function getXLabelsfromkpath(kpath) { const arr = kpath.flat(); const result = []; result.push(arr[0]); for (let i = 1; i < arr.length - 1; i++) { if (arr[i] === arr[i + 1]) { result.push(arr[i]); i++; } else { result.push(arr[i] + "|" + arr[i + 1]); i++; } } // Always push last result.push(arr[arr.length - 1]); return result; } // Extract min/max ranges for specified x and y axes from traces function getXYRangeForAxis(traces, axisX = "x", axisY = "y") { let minX = Infinity, maxX = -Infinity; let minY = Infinity, maxY = -Infinity; for (const trace of traces) { const matchesX = trace.xaxis === axisX || (!trace.xaxis && axisX === "x"); const matchesY = trace.yaxis === axisY || (!trace.yaxis && axisY === "y"); if (!matchesX || !matchesY) continue; for (const x of trace.x ?? []) { if (typeof x === "number") { minX = Math.min(minX, x); maxX = Math.max(maxX, x); } } for (const y of trace.y ?? []) { if (typeof y === "number") { minY = Math.min(minY, y); maxY = Math.max(maxY, y); } } } return { x: minX === Infinity ? null : [minX, maxX], y: minY === Infinity ? null : [minY, maxY], }; } // helper fxn to create a fermiLine trace. function createFermiLine(x, y, fermi, opts = {}) { return { x, y, mode: "lines", type: "scatter", name: `Fermi [${fermi}eV]`, legendgroup: `fermi-${fermi}`, showlegend: opts.showlegend ?? true, line: { color: "green", width: 1.25, dash: "dash" }, ...opts, }; } // helper function to add Fermi level lines export function addfermiLines(fermiLevels, traces, hasDOS, hasBands) { const out = [...traces]; // DOS if (hasDOS && !hasBands) { const { y } = getXYRangeForAxis(traces); for (const fermi of fermiLevels) { out.push(createFermiLine([fermi, fermi], [y[0], y[1]], fermi)); } // Bands } else if (hasBands && !hasDOS) { const { x } = getXYRangeForAxis(traces); for (const fermi of fermiLevels) { out.push(createFermiLine([x[0], x[1]], [fermi, fermi], fermi)); } // Both } else if (hasBands && hasDOS) { const { x: x2 } = getXYRangeForAxis(traces, "x2", "y"); const { x, y } = getXYRangeForAxis(traces, "x", "y"); for (const fermi of fermiLevels) { out.push(createFermiLine([x[0], x[1]], [fermi, fermi], fermi)); out.push( createFermiLine([x2[0], x2[1]], [fermi, fermi], fermi, { showlegend: false, xaxis: "x2", yaxis: "y", }) ); } } return out; }