Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ export default function RootLayout({
<body className="antialiased">
<ThemeProvider defaultTheme="system">
<Overlays />
<Navbar />
{children}
</ThemeProvider>
</body>
Expand Down
4 changes: 1 addition & 3 deletions src/components/LandingHome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,11 @@ export function LandingHome() {
//These values are passed to the Plot Component
const plotObj = useMemo(() => ({
ZarrDS,
variable,
canvasWidth
}), [settings.plotType, ZarrDS, variable, canvasWidth]);
}), [ ZarrDS, canvasWidth]);

//This is the data being passed down the plot tree
const analysisObj = useMemo(() => ({
setters: {},
values: {
ZarrDS,
canvasWidth,
Expand Down
39 changes: 15 additions & 24 deletions src/components/computation/ComputeModule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ interface ComputeModule{
},
setters:{
setShowInfo:React.Dispatch<React.SetStateAction<boolean>>;
setLoc:React.Dispatch<React.SetStateAction<number[]>>;
setUV:React.Dispatch<React.SetStateAction<number[]>>;
setVal:React.Dispatch<React.SetStateAction<number>>;
setUV: React.Dispatch<React.SetStateAction<number[]>>

val:React.RefObject<number>;
loc: React.RefObject<number[]>;
}

}
Expand All @@ -45,7 +46,7 @@ function Rescale(value: number, scales: {minVal: number, maxVal: number}){
}

const ComputeModule = ({arrays,values, setters}:ComputeModule) => {
const {setShowInfo, setLoc, setUV, setVal} = setters;
const {setShowInfo, loc, setUV, val} = setters;
const {colormap, flipY} = useGlobalStore(useShallow(state=>({colormap:state.colormap, flipY:state.flipY})))
const {stateVars,valueScales} = values
const {firstArray, secondArray} = arrays;
Expand Down Expand Up @@ -104,7 +105,7 @@ const ComputeModule = ({arrays,values, setters}:ComputeModule) => {
setTexture(newText)
setPlaneShape(shape.filter((_val,idx)=> idx !== axis))
}
},[execute, axis])
},[execute, axis, operation])

const shapeRatio = useMemo(()=>flipY ? planeShape[0]/planeShape[1]*-2 : planeShape[0]/planeShape[1]*2,[flipY,planeShape])

Expand All @@ -119,27 +120,17 @@ const timerRef = useRef<NodeJS.Timeout | null>(null);

const handleMove = useCallback((e: ThreeEvent<PointerEvent>) => {
if (infoRef.current && e.uv) {
// Always store the latest event
eventRef.current = e;

if (!timerRef.current) {
timerRef.current = setTimeout(() => {
if (eventRef.current) {
setLoc([eventRef.current.clientX, eventRef.current.clientY]);
// @ts-expect-error: uv is not defined ?
const {x, y} = eventRef.current.uv
setUV([x, y]);
const yStep = Math.round(planeShape[0]* y)
const xStep = Math.round(planeShape[1] * x)
const dataIdx = planeShape[1] * yStep + xStep
const dataVal = dataArray.current[dataIdx * 4]
setVal(Rescale(dataVal,valueScales.firstArray))
}
timerRef.current = null; // Reset the timer
}, 50); // 0.1s delay
}
loc.current = [e.clientX, e.clientY];
const { x, y } = e.uv;
setUV([x, y]);
const yStep = Math.round(planeShape[0] * y);
const xStep = Math.round(planeShape[1] * x);
const dataIdx = planeShape[1] * yStep + xStep;
const dataVal = dataArray.current[dataIdx * 4];
val.current = Rescale(dataVal, valueScales.firstArray);
}
}, [setLoc, setUV]);
}, []);

const geometry = useMemo(()=>new THREE.PlaneGeometry(2,shapeRatio),[shapeRatio])

Expand Down
182 changes: 49 additions & 133 deletions src/components/plots/Analysis.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-nocheck Analysis requires quite a lot of work to mesh with new UI. Will Monkey with that later
import React, { useEffect, useMemo, useRef } from 'react'
import { useState } from 'react'
"use client";

import React, { useEffect, useMemo, useRef, useState } from 'react'
import { Canvas } from '@react-three/fiber'
import * as THREE from 'three'
import { ArrayMinMax, getVariablesOptions } from '@/utils/HelperFuncs'
import AnalysisInfo from './AnalysisInfo'
import ComputeModule from '@/components/computation/ComputeModule'
import { ZarrDataset } from '@/components/zarr/ZarrLoaderLRU'
import { createPaneContainer } from '@/components/ui'
import { useTweakpane, usePaneInput, useButtonBlade } from '@lazarusa/react-tweakpane'
import { AnalysisOptions } from '@/components/ui'
import { OrbitControls } from '@react-three/drei'
import { useGlobalStore } from '@/utils/GlobalStates'
import { useAnalysisStore, useGlobalStore } from '@/utils/GlobalStates'
import './Plots.css'
import { useShallow } from 'zustand/shallow'
// import { Perf } from 'r3f-perf';
Expand All @@ -23,24 +21,28 @@ interface Array{
stride:number[]
}

// This wrapper handles loading state

// This renders only when data is ready and uses hooks safely
export function Analysis({ values }: {
values: { ZarrDS: ZarrDataset; canvasWidth: number };
}) {
const {dimNames, dimArrays, dimUnits, setDimNames, setDimArrays, setDimUnits} = useGlobalStore(
const {dimNames, dimArrays, dimUnits, variables, setDimNames, setDimArrays, setDimUnits} = useGlobalStore(
useShallow(state=>({
dimNames: state.dimNames,
dimArrays: state.dimArrays,
dimUnits: state.dimUnits,
variables: state.variables,
setDimNames: state.setDimNames,
setDimArrays: state.setDimArrays,
setDimUnits: state.setDimUnits
})))

const {axis, operation, variable1, variable2, execute} = useAnalysisStore(useShallow(state => ({
axis: state.axis,
operation: state.operation,
variable1: state.variable1,
variable2: state.variable2,
execute: state.execute,
})))

const variables = useGlobalStore(state => state.variables)
const {ZarrDS, canvasWidth} = values
const scaleObjRef = useRef<Record<string, { min: number; max: number }>>({});
const setFlipY = useGlobalStore(state=>state.setFlipY)
Expand All @@ -50,131 +52,42 @@ export function Analysis({ values }: {
const [minVal2, setMinVal2] = useState<number>(0);
const [array , setArray] = useState<Array | null>(null)
const [array2 , setArray2] = useState<Array | null>(null)
const [execute, setExecute] = useState<boolean>(false)
const [showInfo, setShowInfo] = useState<boolean>(false)
const [loc, setLoc] = useState<number[]>([0,0])
const loc = useRef<number[]>([0,0])
const [uv, setUV] = useState<number[]>([0,0])
const [val, setVal] = useState<number>(0);
const [xCoord, setXCoord] = useState<number>(0)
const [yCoord, setYCoord] = useState<number>(0)
const val = useRef<number>(0);
const xCoord = useRef<number>(0)
const yCoord = useRef<number>(0)

const dimNamesAxis = useMemo(() => dimNames.map((element,idx) => ({
text: element,
value: idx
})), []);

const paneContainer = createPaneContainer("analysis")
const pane = useTweakpane({
backgroundColor: "#292b32",
operation: "Mean",
firstVar: "Default",
secondVar: "Default",
execute: false,
axis: 0,
active: false
},
{
title: "Analysis",
container: paneContainer ?? undefined,
expanded: false
}
)
const [bgcolor] = usePaneInput(pane, 'backgroundColor', {
label: 'bgcolor',
value: '#292b32'
})
const [firstVar] = usePaneInput(pane, 'firstVar', {
label: 'Variable 1',
options: [...optionsVariables],
value: 'Default'
})

const [secondVar] = usePaneInput(pane, 'secondVar', {
label: 'Variable 2',
options: [
{
text: 'Default',
value: 'Default',
},
...optionsVariables
],
value: 'Default'
})
const [operation] = usePaneInput(pane, "operation",
{
label:"Operation",
options:[
{
text:"Mean",
value:"Mean"
},
{
text:"Min",
value:"Min"
},
{
text:"Max",
value:"Max"
},
{
text:"StDev",
value:"StDev"
}
],
value:"Mean"
}
)

const [axis] = usePaneInput(
pane,
'axis',
{
label: 'Axis',
options: [
{
text:"0",
value:0
},
{
text:"1",
value:1
},
{
text:"2",
value:2
}
],

}
)

useButtonBlade(pane,{
title:"Compute"
},()=>setExecute(x=>!x))

const stateVars = {
const stateVars = useMemo(
() => ({
operation,
axis,
execute,
}
}),[operation,axis,execute])

useEffect(()=>{
if (firstVar !== "Default"){
ZarrDS.GetArray(firstVar).then(result=>{
if (variable1 !== "Default"){
ZarrDS.GetArray(variable1).then(result=>{
setArray(result);

if (firstVar in scaleObjRef.current){
setMinVal(scaleObjRef.current[firstVar].min)
setMaxVal(scaleObjRef.current[firstVar].max)
if (variable1 in scaleObjRef.current){
setMinVal(scaleObjRef.current[variable1].min)
setMaxVal(scaleObjRef.current[variable1].max)
}
else{
const [minVal,maxVal] = ArrayMinMax(result.data)
setMaxVal(maxVal);
setMinVal(minVal);
scaleObjRef.current[firstVar] = {min:minVal,max:maxVal}
scaleObjRef.current[variable1] = {min:minVal,max:maxVal}
}
})
ZarrDS.GetAttributes(firstVar).then(()=>{
ZarrDS.GetAttributes(variable1).then(()=>{
const [dimArrs, dimMetas, dimNames] = ZarrDS.GetDimArrays()
setDimArrays(dimArrs)
setDimNames(dimNames)
Expand All @@ -189,28 +102,28 @@ export function Analysis({ values }: {
{setFlipY(false)}
})
}
if (secondVar !== "Default"){
ZarrDS.GetArray(secondVar).then(result=>{
if (variable2 !== "Default"){
ZarrDS.GetArray(variable2).then(result=>{
setArray2(result);
if (secondVar in scaleObjRef.current){
setMinVal2(scaleObjRef.current[secondVar].min)
setMaxVal2(scaleObjRef.current[secondVar].max)
if (variable2 in scaleObjRef.current){
setMinVal2(scaleObjRef.current[variable2].min)
setMaxVal2(scaleObjRef.current[variable2].max)
}
else{
const [minVal,maxVal] = ArrayMinMax(result.data)
setMaxVal2(maxVal);
setMinVal2(minVal);
scaleObjRef.current[secondVar] = {min:minVal,max:maxVal}
scaleObjRef.current[variable2] = {min:minVal,max:maxVal}
}
})
}
if (secondVar === "Default"){
if (variable2 === "Default"){
setArray2(null)
}

},[firstVar,secondVar])
const plotArrays = useMemo(()=>dimArrays.filter((_val,idx)=> idx != axis),[axis, dimArrays])
},[variable1,variable2, axis])

const plotArrays = useMemo(()=>dimArrays.filter((_val,idx)=> idx != axis),[axis, dimArrays])
//Get Info for Display
useEffect(()=>{
if (dimArrays){
Expand All @@ -219,13 +132,14 @@ export function Analysis({ values }: {
const ySize = plotArrays[0].length;
const xIdx = Math.round(uv[0]*xSize-.5)
const yIdx = Math.round(uv[1]*ySize-.5)
setXCoord(plotArrays[1][xIdx])
setYCoord(plotArrays[0][yIdx])},50)
xCoord.current = plotArrays[1][xIdx]
yCoord.current = plotArrays[0][yIdx]},50)
return ()=> clearTimeout(timeout)
}
},[uv, plotArrays])

const valueScales = {

const valueScales = useMemo(()=>({
firstArray:{
maxVal,
minVal
Expand All @@ -234,22 +148,24 @@ export function Analysis({ values }: {
maxVal: maxVal2,
minVal: minVal2
}
}
const computeObj = {
}),[maxVal,minVal,maxVal2,minVal2],)

const computeObj = useMemo(()=>({
stateVars,
valueScales
}
}),[stateVars,valueScales])
const Options = useMemo(()=> AnalysisOptions,[])
return (
<div className='analysis-canvas'
style={{
width:canvasWidth,
background:bgcolor
}}
>
<AnalysisInfo loc={loc} show={showInfo} info={[yCoord, xCoord, val]} plotDim={axis} />
<Options />
<AnalysisInfo loc={loc.current} show={showInfo} info={[yCoord.current, xCoord.current, val.current]}/>
<Canvas camera={{ position: [0, 0, 50], zoom:400 }} orthographic>
{/* <Perf position='bottom-left'/> */}
{array && <ComputeModule arrays={{firstArray: array, secondArray: array2}} values={computeObj} setters={{setShowInfo, setLoc, setUV, setVal}}/>}
{array && <ComputeModule arrays={{firstArray: array, secondArray: array2}} values={computeObj} setters={{setShowInfo, loc, setUV, val}}/>}
<OrbitControls
enablePan={true}
enableRotate={false}
Expand Down
Loading