Improved Ui and plotting stuff
This commit is contained in:
+46
-15
@@ -42,19 +42,33 @@ export default function Home() {
|
||||
const [plotType, setPlotType] = useState<PlotType>("scatter");
|
||||
const [colorscale, setColorscale] = useState<string>(COLORSCALES[0]);
|
||||
|
||||
// First row after header = axis sizes (X max, Y max, Z max); rest = plot data.
|
||||
const plotData = rows.length > 1 ? rows.slice(1) : rows;
|
||||
const axisSizes =
|
||||
rows.length > 1 && x && y && z
|
||||
? (() => {
|
||||
const sx = Number(rows[0][x]);
|
||||
const sy = Number(rows[0][y]);
|
||||
const sz = Number(rows[0][z]);
|
||||
return [sx, sy, sz].every((n) => Number.isFinite(n))
|
||||
? { x: sx, y: sy, z: sz }
|
||||
: null;
|
||||
})()
|
||||
: null;
|
||||
|
||||
// Build surface grid from scattered (x,y,z) points. Returns null if data isn't a grid.
|
||||
function buildSurfaceGrid(): {
|
||||
xUnique: number[];
|
||||
yUnique: number[];
|
||||
zMatrix: number[][];
|
||||
} | null {
|
||||
const xVals = rows.map((r) => Number(r[x]));
|
||||
const yVals = rows.map((r) => Number(r[y]));
|
||||
const zVals = rows.map((r) => Number(r[z]));
|
||||
const xVals = plotData.map((r) => Number(r[x]));
|
||||
const yVals = plotData.map((r) => Number(r[y]));
|
||||
const zVals = plotData.map((r) => Number(r[z]));
|
||||
const xUnique = [...new Set(xVals)].sort((a, b) => a - b);
|
||||
const yUnique = [...new Set(yVals)].sort((a, b) => a - b);
|
||||
const keyToZ = new Map<string, number>();
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
for (let i = 0; i < plotData.length; i++) {
|
||||
const k = `${xVals[i]},${yVals[i]}`;
|
||||
if (!keyToZ.has(k)) keyToZ.set(k, zVals[i]);
|
||||
}
|
||||
@@ -75,9 +89,9 @@ export default function Home() {
|
||||
const Plotly = await import("plotly.js-dist-min");
|
||||
if (cancelled) return;
|
||||
|
||||
const xVals = rows.map((r) => Number(r[x]));
|
||||
const yVals = rows.map((r) => Number(r[y]));
|
||||
const zVals = rows.map((r) => Number(r[z]));
|
||||
const xVals = plotData.map((r) => Number(r[x]));
|
||||
const yVals = plotData.map((r) => Number(r[y]));
|
||||
const zVals = plotData.map((r) => Number(r[z]));
|
||||
|
||||
const grid = buildSurfaceGrid();
|
||||
const useSurface = plotType === "surface" && grid !== null;
|
||||
@@ -104,6 +118,21 @@ export default function Home() {
|
||||
},
|
||||
};
|
||||
|
||||
const sceneLayout: {
|
||||
xaxis: { title: { text: string }; range?: [number, number] };
|
||||
yaxis: { title: { text: string }; range?: [number, number] };
|
||||
zaxis: { title: { text: string }; range?: [number, number] };
|
||||
} = {
|
||||
xaxis: { title: { text: x } },
|
||||
yaxis: { title: { text: y } },
|
||||
zaxis: { title: { text: z } },
|
||||
};
|
||||
if (axisSizes) {
|
||||
sceneLayout.xaxis.range = [0, axisSizes.x];
|
||||
sceneLayout.yaxis.range = [0, axisSizes.y];
|
||||
sceneLayout.zaxis.range = [0, axisSizes.z];
|
||||
}
|
||||
|
||||
Plotly.newPlot(
|
||||
plotRef.current!,
|
||||
[trace],
|
||||
@@ -111,11 +140,7 @@ export default function Home() {
|
||||
paper_bgcolor: "#0b0d12",
|
||||
plot_bgcolor: "#0b0d12",
|
||||
font: { color: "#cfd3ff" },
|
||||
scene: {
|
||||
xaxis: { title: { text: x } },
|
||||
yaxis: { title: { text: y } },
|
||||
zaxis: { title: { text: z } },
|
||||
},
|
||||
scene: sceneLayout,
|
||||
margin: { l: 0, r: 0, t: 0, b: 0 },
|
||||
},
|
||||
{ responsive: true }
|
||||
@@ -198,6 +223,12 @@ export default function Home() {
|
||||
file:rounded file:px-2 file:py-1"
|
||||
/>
|
||||
</Control>
|
||||
<p className="text-xs text-muted">
|
||||
First data row = axis sizes (X max, Y max, Z max). Plot uses rows after that.{" "}
|
||||
<a href="/example-surface.csv" className="text-accent underline" download>
|
||||
Example (surface)
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<Control label="X axis">
|
||||
<select
|
||||
@@ -270,16 +301,16 @@ export default function Home() {
|
||||
</Control>
|
||||
|
||||
{plotType === "surface" &&
|
||||
rows.length > 0 &&
|
||||
plotData.length > 0 &&
|
||||
buildSurfaceGrid() === null && (
|
||||
<p className="text-xs text-amber-500/90">
|
||||
Surface needs a full X×Y grid of points. Showing dots instead.
|
||||
Surface needs a full X and Y grid of points. Showing dots instead.
|
||||
</p>
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={exportPNG}
|
||||
className="w-full mt-2 bg-accent text-black text-sm rounded px-2 py-1 hover:opacity-90"
|
||||
className="w-full mt-2 bg-accent text-sm rounded px-2 py-1 hover:opacity-90"
|
||||
>
|
||||
Export PNG
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user