diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 65cdd163..6c2e2425 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -19,7 +19,6 @@ export default function RootLayout({ - {children} diff --git a/src/components/LandingHome.tsx b/src/components/LandingHome.tsx index e0a33484..4068e0f2 100644 --- a/src/components/LandingHome.tsx +++ b/src/components/LandingHome.tsx @@ -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, diff --git a/src/components/computation/ComputeModule.tsx b/src/components/computation/ComputeModule.tsx index f62caec2..9384c501 100644 --- a/src/components/computation/ComputeModule.tsx +++ b/src/components/computation/ComputeModule.tsx @@ -32,9 +32,10 @@ interface ComputeModule{ }, setters:{ setShowInfo:React.Dispatch>; - setLoc:React.Dispatch>; - setUV:React.Dispatch>; - setVal:React.Dispatch>; + setUV: React.Dispatch> + + val:React.RefObject; + loc: React.RefObject; } } @@ -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; @@ -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]) @@ -119,27 +120,17 @@ const timerRef = useRef(null); const handleMove = useCallback((e: ThreeEvent) => { 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]) diff --git a/src/components/plots/Analysis.tsx b/src/components/plots/Analysis.tsx index 36fd095f..8455b8fc 100644 --- a/src/components/plots/Analysis.tsx +++ b/src/components/plots/Analysis.tsx @@ -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'; @@ -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>({}); const setFlipY = useGlobalStore(state=>state.setFlipY) @@ -50,131 +52,42 @@ export function Analysis({ values }: { const [minVal2, setMinVal2] = useState(0); const [array , setArray] = useState(null) const [array2 , setArray2] = useState(null) - const [execute, setExecute] = useState(false) const [showInfo, setShowInfo] = useState(false) - const [loc, setLoc] = useState([0,0]) + const loc = useRef([0,0]) const [uv, setUV] = useState([0,0]) - const [val, setVal] = useState(0); - const [xCoord, setXCoord] = useState(0) - const [yCoord, setYCoord] = useState(0) + const val = useRef(0); + const xCoord = useRef(0) + const yCoord = useRef(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) @@ -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){ @@ -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 @@ -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 (
- + + {/* */} - {array && } + {array && } { +const AnalysisInfo = ({loc, show, info, } : {loc: number[], show: boolean, info: number[]}) => { const {dimNames, dimUnits} = useGlobalStore(useShallow(state=>({dimNames: state.dimNames, dimUnits: state.dimUnits}))) + const axis = useAnalysisStore(state=> state.axis) + + const plotNames = useMemo(()=>dimNames.filter((_val,idx)=> idx != axis),[dimNames, axis]) + const plotUnits = useMemo(()=>dimUnits.filter((_val,idx)=> idx != axis),[dimNames, axis]) - const plotNames = useMemo(()=>dimNames.filter((_val,idx)=> idx != plotDim),[dimNames, plotDim]) - const plotUnits = useMemo(()=>dimUnits.filter((_val,idx)=> idx != plotDim),[dimNames, plotDim]) - return (
{ zRange: state.zRange, quality: state.quality }))) - const paneContainer = createPaneContainer("plot-pane"); - const pane = useTweakpane( - { - flip: false, - }, - { - title: 'Volume', - container: paneContainer ?? undefined, - expanded: false, - } - ); - - const [threshold] = useSliderBlade(pane, { - label: 'Clip Values', - value: 0.0, - min: 0, - max: 1, - step: 0.01, - format: (value) => value.toFixed(2), - }) - - const [steps] = useSliderBlade(pane, { - label: 'Quality', - value: 200, - min: 50, - max: 1000, - step: 25, - }) - - const [flip] = usePaneInput( - pane, - 'flip', - { - label: 'Invert values', - value: false - } - ) // We need to check if moving this outside of useMemo means it's creating a ton of materials. This was how it was done in THREE Journey when I was doing that, so I know it's not stricly speaking wrong const shaderMaterial = new THREE.ShaderMaterial({ glslVersion: THREE.GLSL3, @@ -66,12 +29,11 @@ export const DataCube = ({ volTexture }: DataCubeProps ) => { map: { value: volTexture }, cmap:{value: colormap}, cameraPos: { value: new THREE.Vector3() }, - threshold: {value: threshold}, + threshold: {value: new THREE.Vector2(valueRange[0],valueRange[1])}, scale: {value: shape}, flatBounds:{value: new THREE.Vector4(xRange[0],xRange[1],zRange[0],zRange[1])}, vertBounds:{value: new THREE.Vector2(yRange[0],yRange[1])}, - steps: { value: quality }, - flip: {value: flip } + steps: { value: quality } }, vertexShader, fragmentShader, diff --git a/src/components/plots/Plot.tsx b/src/components/plots/Plot.tsx index 33a5d775..62efb1f2 100644 --- a/src/components/plots/Plot.tsx +++ b/src/components/plots/Plot.tsx @@ -8,11 +8,10 @@ import { ArrayToTexture, DefaultCubeTexture } from '@/components/textures'; import { ZarrDataset } from '../zarr/ZarrLoaderLRU'; import { useGlobalStore, usePlotStore } from '@/utils/GlobalStates'; import { useShallow } from 'zustand/shallow'; - +import { Navbar } from '../ui'; interface PlotParameters{ values:{ ZarrDS: ZarrDataset; - variable:string; canvasWidth:number } setShowLoading: React.Dispatch>; @@ -38,9 +37,9 @@ const Plot = ({values,setShowLoading}:PlotParameters) => { setDimNames:state.setDimNames, setDimUnits:state.setDimUnits} ))) - const colormap = useGlobalStore(state=>state.colormap) + const {colormap, variable} = useGlobalStore(useShallow(state=>({colormap: state.colormap, variable: state.variable}))) - const {ZarrDS,variable,canvasWidth} = values; + const {ZarrDS,canvasWidth} = values; const plotType = usePlotStore(state => state.plotType) const [texture, setTexture] = useState(null) @@ -146,6 +145,7 @@ const Plot = ({values,setShowLoading}:PlotParameters) => { width: windowWidth - canvasWidth }} > + threshold) || (d == 0.0 && threshold == 0.0); - cond = flip ? !cond : cond; + bool cond = (d > threshold.x) && (d < threshold.y); + if (cond) { vec4 col = texture(cmap, vec2(d, 0.5)); diff --git a/src/components/ui/Analysis.tsx b/src/components/ui/Analysis.tsx deleted file mode 100644 index aea528c1..00000000 --- a/src/components/ui/Analysis.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import './css/Analysis.css' -import * as React from 'react' - -const axis = [0,1,2] -const operations = [ - 'Max','Min','Mean','StDev' -] - -interface Analysis{ - setters:{ - setAxis:React.Dispatch>; - setOperation:React.Dispatch> - setExecute:React.Dispatch> - } -} - - -const AnalysisWindow = ({setters}:Analysis)=> { - const {setAxis, setOperation, setExecute} = setters; - - return( -
- - -
- - -
- -
- ) -} - -export default AnalysisWindow \ No newline at end of file diff --git a/src/components/ui/AnalysisOptions.tsx b/src/components/ui/AnalysisOptions.tsx new file mode 100644 index 00000000..703f9822 --- /dev/null +++ b/src/components/ui/AnalysisOptions.tsx @@ -0,0 +1,164 @@ +"use client"; + +import './css/Analysis.css' +import React, {useEffect, useState} from 'react' +import { useAnalysisStore, useGlobalStore } from '@/utils/GlobalStates' +import { useShallow } from 'zustand/shallow' +import { Button } from "@/components/ui/button" + +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectScrollDownButton, + SelectScrollUpButton, + SelectSeparator, + SelectTrigger, + SelectValue, +} from "@/components/ui/select" + +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuPortal, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" + +const oneVarOps = [ + "Mean", + "Min", + "Max", + "StDev" +] + +const twoVarOps = [ + "Correlation" +] + +const axes = [0,1,2] + +const AnalysisOptions = React.memo(function AnalysisOptions() { + const {setAxis, setVariable1, setVariable2, setOperation, setExecute, execute, variable1, variable2, operation, axis} = useAnalysisStore(useShallow(state => ({ + setAxis: state.setAxis, + setVariable1: state.setVariable1, + setVariable2: state.setVariable2, + setOperation: state.setOperation, + setExecute: state.setExecute, + execute: state.execute, + variable1: state.variable1, + variable2: state.variable2, + operation: state.operation, + axis: state.axis + }))) + const variables = useGlobalStore(state => state.variables) + console.log("options render") + const [useTwo, setUseTwo] = useState(false) + const [operations, setOperations] = useState(oneVarOps) + + useEffect(()=>{ + if (useTwo){ + setOperations(twoVarOps); + setOperation("Correlation") + } + else { + setVariable2("Default") //This reset variable2 when going back to one variable + setOperations(oneVarOps); + setOperation("Mean") + } + + },[useTwo]) + + function VariableSelect({variable, setVariable} : {variable: string, setVariable : (value: string) => void}) { + return( + <> + + + ) + } + + return( + <> +
+ + + + + + Variable + e.preventDefault()}> + + + + + {useTwo && } + + + + + + + e.preventDefault()}> + + + + + + + + + +
+ + ) +}) + +export default AnalysisOptions + diff --git a/src/components/ui/Navbar.tsx b/src/components/ui/Navbar.tsx index 8394961c..de40217e 100644 --- a/src/components/ui/Navbar.tsx +++ b/src/components/ui/Navbar.tsx @@ -109,10 +109,8 @@ const Navbar = () => { setInitStore : state.setInitStore, setVariable : state.setVariable, setColormap : state.setColormap - }))) - const [refresh, setRefresh] = useState(false) const variables = useGlobalStore(useShallow(state=>state.variables)) const setPlotType = usePlotStore(state=> state.setPlotType) const [cmap, setCmap] = useState("Default") diff --git a/src/components/ui/PlotTweaker.tsx b/src/components/ui/PlotTweaker.tsx index bdd66358..1bcb9c01 100644 --- a/src/components/ui/PlotTweaker.tsx +++ b/src/components/ui/PlotTweaker.tsx @@ -30,11 +30,12 @@ function DeNorm(val : number, min : number, max : number){ } -const MinMaxSlider = ({range, setRange, valueScales} : +const MinMaxSlider = ({range, setRange, valueScales, min=-1} : { range : number[], setRange : (value: number[]) => void, - valueScales : {minVal : number, maxVal : number} + valueScales : {minVal : number, maxVal : number}, + min?: number }) => { let {minVal, maxVal} = valueScales; minVal = Number(minVal) @@ -43,7 +44,7 @@ const MinMaxSlider = ({range, setRange, valueScales} :
{ Value Cropping e.preventDefault()}> - + diff --git a/src/components/ui/css/Analysis.css b/src/components/ui/css/Analysis.css index 5f18625e..9a41120b 100644 --- a/src/components/ui/css/Analysis.css +++ b/src/components/ui/css/Analysis.css @@ -1,9 +1,5 @@ -.analysis-container{ - position: fixed; - width: 200px; - height: 100px; - background-color: white; - z-index: 6; - left: 100px; - top: 800px; +.analysis-options{ + position: absolute; + z-index: 2; + left: calc(50% - 100px); } \ No newline at end of file diff --git a/src/components/ui/css/Navbar.css b/src/components/ui/css/Navbar.css index 4f1423af..7d687316 100644 --- a/src/components/ui/css/Navbar.css +++ b/src/components/ui/css/Navbar.css @@ -1,7 +1,7 @@ .navbar { display: flex; - position: fixed; + position: absolute; justify-content: space-between; top: 4px; left: 8px; diff --git a/src/components/ui/index.ts b/src/components/ui/index.ts index 320299a1..6e8ffc3d 100644 --- a/src/components/ui/index.ts +++ b/src/components/ui/index.ts @@ -16,6 +16,7 @@ import { Loading } from "./Loading"; import useCSSVariable from "./useCSSVariable"; import ShowLinePlot from "./ShowLinePlot"; import PlotTweaker from "./PlotTweaker"; +import AnalysisOptions from "./AnalysisOptions"; export { Navbar, Footer, @@ -35,5 +36,6 @@ export { Loading, useCSSVariable, ShowLinePlot, - PlotTweaker + PlotTweaker, + AnalysisOptions }; diff --git a/src/utils/GlobalStates.ts b/src/utils/GlobalStates.ts index da76d4ce..f38480d0 100644 --- a/src/utils/GlobalStates.ts +++ b/src/utils/GlobalStates.ts @@ -32,6 +32,7 @@ type StoreState = { initStore:string; variable: string; variables: string[]; + plotOn: boolean; setShape: (shape: THREE.Vector3) => void; setValueScales: (valueScales: { maxVal: number; minVal: number }) => void; @@ -49,6 +50,7 @@ type StoreState = { setInitStore: (initStore:string ) => void; setVariable: (variable: string) => void; setVariables: (variables: string[]) => void; + setPlotOn: (plotOn: boolean) => void; }; @@ -70,6 +72,8 @@ export const useGlobalStore = create((set) => ({ initStore: "https://s3.bgc-jena.mpg.de:9000/esdl-esdc-v3.0.2/esdc-16d-2.5deg-46x72x1440-3.0.2.zarr", variable: 'Default', variables: [], + plotOn: false, + setShape: (shape) => set({ shape }), setValueScales: (valueScales) => set({ valueScales }), setColormap: (colormap) => set({ colormap }), @@ -86,7 +90,8 @@ export const useGlobalStore = create((set) => ({ setInitStore: (initStore) => set({ initStore }), setVariable: (variable) => {set({ variable }) }, - setVariables: (variables) => set({variables}) + setVariables: (variables) => set({variables}), + setPlotOn: (plotOn) => set({ plotOn }), })); type PlotState ={ @@ -118,7 +123,7 @@ export const usePlotStore = create((set) => ({ scalePoints: false, scaleIntensity: 1, quality: 200, - valueRange: [-1, 1], + valueRange: [0, 1], xRange: [-1, 1], yRange: [-1, 1], zRange: [-1, 1], @@ -134,4 +139,31 @@ export const usePlotStore = create((set) => ({ setPlotType: (plotType) => {set({ plotType }) } -})) \ No newline at end of file +})) + +type AnalysisState = { + axis: number; + operation: string; + execute: boolean; + variable1: string; + variable2: string; + + setAxis: (axis: number) => void; + setOperation: (operation: string) => void; + setExecute: (execute: boolean) => void; + setVariable1: (variable1: string) => void; + setVariable2: (variable2: string) => void; +} + +export const useAnalysisStore = create((set) => ({ + axis: 0, + operation: "Mean", + execute: false, + variable1: "Default", + variable2: "Default", + setAxis: (axis) => set({ axis }), + setOperation: (operation) => set({ operation }), + setExecute: (execute) => set({ execute }), + setVariable1: (variable1) => set({ variable1 }), + setVariable2: (variable2) => set({ variable2 }), +}));