Skip to content

Commit 7c20841

Browse files
authored
Merge pull request #547 from EarthyScience/jp/data-hook
Move Datafetch to hook
2 parents 3060a57 + 5219339 commit 7c20841

3 files changed

Lines changed: 194 additions & 169 deletions

File tree

src/components/plots/Plot.tsx

Lines changed: 24 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,16 @@ import React, { useMemo, useRef, useState, useEffect } from 'react';
33
import * as THREE from 'three';
44
import { PointCloud, UVCube, DataCube, FlatMap, Sphere, CountryBorders, AxisLines, SphereBlocks, FlatBlocks, KeyFramePreviewer } from '@/components/plots';
55
import { Canvas, invalidate, useThree } from '@react-three/fiber';
6-
import { ArrayToTexture, CreateTexture } from '@/components/textures';
7-
import { GetArray, GetAttributes } from '../zarr/ZarrLoaderLRU';
8-
import { useAnalysisStore, useGlobalStore, useImageExportStore, usePlotStore, useZarrStore } from '@/GlobalStates';
6+
import { CreateTexture } from '@/components/textures';
7+
import { useAnalysisStore, useGlobalStore, useImageExportStore, usePlotStore } from '@/GlobalStates';
98
import { useShallow } from 'zustand/shallow';
109
import { Navbar, Colorbar, ExportExtent } from '../ui';
1110
import AnalysisInfo from './AnalysisInfo';
1211
import { OrbitControls as OrbitControlsImpl } from 'three-stdlib';
1312
import AnalysisWG from './AnalysisWG';
14-
import { ParseExtent, GetDimInfo, coarsenFlatArray } from '@/utils/HelperFuncs';
1513
import ExportCanvas from '@/utils/ExportCanvas';
1614
import KeyFrames from '../ui/KeyFrames';
17-
15+
import { useDataFetcher } from '@/hooks/useDataFetcher';
1816

1917
const TransectNotice = () =>{
2018
const {selectTS} = usePlotStore(useShallow(state => ({selectTS: state.selectTS})))
@@ -131,143 +129,29 @@ const Orbiter = ({isFlat} : {isFlat : boolean}) =>{
131129
}
132130

133131
const Plot = () => {
134-
const {
135-
setShape, setDataShape, setFlipY, setValueScales, setMetadata, setDimArrays,
136-
setDimNames, setDimUnits, setPlotOn, setStatus} = useGlobalStore(
137-
useShallow(state => ({ //UseShallow for object returns
138-
setShape:state.setShape,
139-
setDataShape: state.setDataShape,
140-
setFlipY:state.setFlipY,
141-
setValueScales:state.setValueScales,
142-
setMetadata: state.setMetadata,
143-
setDimArrays:state.setDimArrays,
144-
setDimNames:state.setDimNames,
145-
setDimUnits:state.setDimUnits,
146-
setPlotOn: state.setPlotOn,
147-
setStatus: state.setStatus
148-
}
149-
)))
150-
const {colormap, variable, isFlat, DPR, valueScales, is4D, setIsFlat} = useGlobalStore(useShallow(state=>({
151-
colormap: state.colormap,
152-
variable: state.variable,
153-
isFlat: state.isFlat,
154-
DPR: state.DPR,
155-
valueScales: state.valueScales,
156-
is4D: state.is4D,
157-
setIsFlat: state.setIsFlat,
158-
})))
159-
const {keyFrameEditor} = useImageExportStore(useShallow(state => ({ keyFrameEditor:state.keyFrameEditor})))
160-
const {plotType, displaceSurface, interpPixels, setPlotType} = usePlotStore(useShallow(state => ({
161-
plotType: state.plotType,
162-
displaceSurface: state.displaceSurface,
163-
interpPixels: state.interpPixels,
164-
setPlotType: state.setPlotType
165-
})))
166-
167-
const {zSlice, ySlice, xSlice, reFetch} = useZarrStore(useShallow(state=> ({
168-
zSlice: state.zSlice,
169-
ySlice: state.ySlice,
170-
xSlice: state.xSlice,
171-
reFetch: state.reFetch,
172-
coarsen: state.coarsen,
173-
kernelDepth: state.kernelDepth,
174-
kernelSize: state.kernelSize
175-
})))
176-
const {analysisMode} = useAnalysisStore(useShallow(state => ({
177-
analysisMode: state.analysisMode
178-
})))
179-
const coords = useRef<number[]>([0,0])
180-
const val = useRef<number>(0)
181-
182-
const [showInfo, setShowInfo] = useState<boolean>(false)
183-
const [loc, setLoc] = useState<number[]>([0,0])
184-
185-
const [textures, setTextures] = useState<THREE.DataTexture[] | THREE.Data3DTexture[] | null>(null)
186-
const [show, setShow] = useState<boolean>(true) //Prevents rendering of 3D objects until data is fully loaded in
187-
const [stableMetadata, setStableMetadata] = useState<Record<string, any>>({});
132+
const {colormap, isFlat, DPR, valueScales, setIsFlat} = useGlobalStore(useShallow(state=>({
133+
colormap: state.colormap,
134+
isFlat: state.isFlat,
135+
DPR: state.DPR,
136+
valueScales: state.valueScales,
137+
setIsFlat: state.setIsFlat,
138+
})))
139+
const {keyFrameEditor} = useImageExportStore(useShallow(state => ({ keyFrameEditor:state.keyFrameEditor})))
140+
const {plotType, displaceSurface} = usePlotStore(useShallow(state => ({
141+
plotType: state.plotType,
142+
displaceSurface: state.displaceSurface,
143+
})))
144+
const {analysisMode} = useAnalysisStore(useShallow(state => ({
145+
analysisMode: state.analysisMode
146+
})))
147+
const coords = useRef<number[]>([0,0])
148+
const val = useRef<number>(0)
149+
150+
const [showInfo, setShowInfo] = useState<boolean>(false)
151+
const [loc, setLoc] = useState<number[]>([0,0])
188152

189153
//DATA LOADING
190-
useEffect(() => {
191-
if (variable != "Default") {
192-
setShow(false)
193-
try{
194-
if (textures) {
195-
textures.forEach(tex =>{
196-
tex.dispose();
197-
(tex.source as any).data = null;
198-
});
199-
}
200-
const {setZSlice, setYSlice, setXSlice} = usePlotStore.getState() // Set the plot slices with zarr slices
201-
setZSlice(zSlice);
202-
setYSlice(ySlice);
203-
setXSlice(xSlice);
204-
GetArray().then((result) => {
205-
// const shape = result.shape.filter(x => x>1) //This is np.squeeze(). Using this works as expected but there are some fringe cases where it breaks things. Will implement later
206-
const shape = result.shape
207-
const [tempTexture, scaling] = ArrayToTexture({
208-
data: result.data,
209-
shape
210-
})
211-
setTextures(tempTexture)
212-
setValueScales(scaling as { maxVal: number; minVal: number });
213-
useGlobalStore.getState().setScalingFactor(result.scalingFactor)
214-
const shapeLength = shape.length
215-
if (shapeLength == 2){
216-
setIsFlat(true)
217-
if (!["flat", "sphere"].includes(plotType)){// If the plottype isn't already sphere or flat, change it to sphere
218-
setPlotType("sphere")
219-
}
220-
}
221-
else{
222-
setIsFlat(false)
223-
}
224-
const aspectRatio = shape[shapeLength-2] / shape[shapeLength-1];
225-
const timeRatio = shape[shapeLength-3] / shape[shapeLength-1];
226-
setShape(new THREE.Vector3(2, aspectRatio * 2, Math.max(timeRatio, 2)));
227-
setDataShape(result.shape)
228-
setShow(true)
229-
setPlotOn(true)
230-
setStatus(null)
231-
})
232-
}catch{
233-
setStatus(null);
234-
return;
235-
}
236-
//Get Metadata
237-
GetAttributes().then((result)=>{
238-
setMetadata(result);
239-
setStableMetadata(result);
240-
})
241-
GetDimInfo(variable).then((arrays)=>{
242-
let {dimArrays, dimUnits, dimNames}= arrays;
243-
244-
if (is4D){
245-
dimArrays = dimArrays.slice(1);
246-
dimUnits = dimUnits.slice(1);
247-
dimNames = dimNames.slice(1);
248-
}
249-
setDimNames(dimNames)
250-
setDimArrays(dimArrays)
251-
if (dimArrays.length > 2){
252-
if (dimArrays[1][1] < dimArrays[1][0])
253-
{setFlipY(true)}
254-
else
255-
{setFlipY(false)}
256-
}
257-
else{
258-
if (dimArrays[0][1] < dimArrays[0][0])
259-
{setFlipY(true)}
260-
else
261-
{setFlipY(false)}
262-
}
263-
setDimUnits(dimUnits)
264-
ParseExtent(dimUnits, dimArrays)
265-
})
266-
}else{
267-
setMetadata(null)
268-
}
269-
}, [reFetch])
270-
154+
const {textures, show, stableMetadata, setTextures} = useDataFetcher()
271155

272156
useEffect(()=>{ // Reset after analysis mode
273157
if(!analysisMode && show){
@@ -287,35 +171,6 @@ const Plot = () => {
287171
val
288172
}),[])
289173

290-
useEffect(() => {
291-
// This cleanup function will run when the `textures` state is about to change,
292-
// or when the component unmounts.
293-
return () => {
294-
if (textures) {
295-
textures.forEach(tex => {
296-
tex.dispose();
297-
});
298-
}
299-
};
300-
}, [textures]);
301-
302-
useEffect(()=> {
303-
if (!textures) return;
304-
const updated = textures.map(tex => {
305-
const clone = tex.clone();
306-
if (interpPixels) {
307-
clone.minFilter = THREE.LinearFilter;
308-
clone.magFilter = THREE.LinearFilter;
309-
} else {
310-
clone.minFilter = THREE.NearestFilter;
311-
clone.magFilter = THREE.NearestFilter;
312-
}
313-
clone.needsUpdate = true;
314-
return clone ;
315-
});
316-
setTextures(updated as THREE.Data3DTexture[] | THREE.DataTexture[]);
317-
},[interpPixels])
318-
319174
useEffect(()=>{ // Rotates flat back when changing away
320175
usePlotStore.setState({rotateFlat: false})
321176
},[plotType])

src/hooks/useDataFetcher.tsx

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import { useState, useEffect } from 'react';
2+
import * as THREE from 'three';
3+
import { useGlobalStore, usePlotStore, useZarrStore } from '@/GlobalStates';
4+
import { useShallow } from 'zustand/shallow';
5+
import { ParseExtent, GetDimInfo } from '@/utils/HelperFuncs';
6+
import { GetArray, GetAttributes } from '@/components/zarr/ZarrLoaderLRU';
7+
import { ArrayToTexture } from '@/components/textures';
8+
9+
export const useDataFetcher = () => {
10+
const {
11+
setShape, setDataShape, setFlipY, setValueScales, setMetadata, setDimArrays,
12+
setDimNames, setDimUnits, setPlotOn, setStatus} = useGlobalStore(
13+
useShallow(state => ({
14+
setShape:state.setShape,
15+
setDataShape: state.setDataShape,
16+
setFlipY:state.setFlipY,
17+
setValueScales:state.setValueScales,
18+
setMetadata: state.setMetadata,
19+
setDimArrays:state.setDimArrays,
20+
setDimNames:state.setDimNames,
21+
setDimUnits:state.setDimUnits,
22+
setPlotOn: state.setPlotOn,
23+
setStatus: state.setStatus
24+
})))
25+
const {variable, is4D, setIsFlat} = useGlobalStore(
26+
useShallow(state=>({
27+
variable: state.variable,
28+
is4D: state.is4D,
29+
setIsFlat: state.setIsFlat,
30+
})))
31+
const {plotType, interpPixels, setPlotType} = usePlotStore(
32+
useShallow(state => ({
33+
plotType: state.plotType,
34+
interpPixels:state.interpPixels,
35+
setPlotType: state.setPlotType
36+
})))
37+
const {zSlice, ySlice, xSlice, reFetch} = useZarrStore(
38+
useShallow(state=> ({
39+
zSlice: state.zSlice,
40+
ySlice: state.ySlice,
41+
xSlice: state.xSlice,
42+
reFetch: state.reFetch,
43+
coarsen: state.coarsen,
44+
kernelDepth: state.kernelDepth,
45+
kernelSize: state.kernelSize
46+
})))
47+
48+
//---- Local State ----//
49+
const [textures, setTextures] = useState<THREE.DataTexture[] | THREE.Data3DTexture[] | null>(null);
50+
const [show, setShow] = useState<boolean>(true);
51+
const [stableMetadata, setStableMetadata] = useState<Record<string, any>>({});
52+
53+
useEffect(() => {
54+
if (variable !== "Default") {
55+
setShow(false);
56+
try {
57+
//---- Texture Cleanup ----//
58+
if (textures) {
59+
textures.forEach((tex) => {
60+
tex.dispose();
61+
if (tex.source) (tex.source as any).data = null;
62+
});
63+
}
64+
65+
//---- Set Plot Slicez ----//
66+
const { setZSlice, setYSlice, setXSlice } = usePlotStore.getState();
67+
setZSlice(zSlice);
68+
setYSlice(ySlice);
69+
setXSlice(xSlice);
70+
71+
//---- Main Fetch ----//
72+
GetArray().then((result) => {
73+
const shape = result.shape;
74+
const [tempTexture, scaling] = ArrayToTexture({
75+
data: result.data,
76+
shape
77+
});
78+
79+
setTextures(tempTexture);
80+
setValueScales(scaling as { maxVal: number; minVal: number });
81+
useGlobalStore.getState().setScalingFactor(result.scalingFactor);
82+
83+
const shapeLength = shape.length;
84+
85+
if (shapeLength === 2) {
86+
setIsFlat(true);
87+
if (!["flat", "sphere"].includes(plotType)) {
88+
setPlotType("sphere");
89+
}
90+
} else {
91+
setIsFlat(false);
92+
}
93+
94+
const aspectRatio = shape[shapeLength - 2] / shape[shapeLength - 1];
95+
const timeRatio = shape[shapeLength - 3] / shape[shapeLength - 1];
96+
97+
setShape(new THREE.Vector3(2, aspectRatio * 2, Math.max(timeRatio, 2)));
98+
setDataShape(result.shape);
99+
100+
setShow(true);
101+
setPlotOn(true);
102+
setStatus(null);
103+
});
104+
} catch (error) {
105+
console.error(error);
106+
setStatus(null);
107+
return;
108+
}
109+
110+
//---- Metadata ----//
111+
GetAttributes().then((result) => {
112+
setMetadata(result);
113+
setStableMetadata(result);
114+
});
115+
116+
//---- DimInfo ----//
117+
GetDimInfo(variable).then((arrays) => {
118+
let { dimArrays, dimUnits, dimNames } = arrays;
119+
if (is4D) {
120+
dimArrays = dimArrays.slice(1);
121+
dimUnits = dimUnits.slice(1);
122+
dimNames = dimNames.slice(1);
123+
}
124+
setDimNames(dimNames);
125+
setDimArrays(dimArrays);
126+
127+
const targetDim = dimArrays.length > 2 ? dimArrays[1] : dimArrays[0];
128+
const shouldFlip = targetDim[1] < targetDim[0];
129+
setFlipY(shouldFlip);
130+
131+
setDimUnits(dimUnits);
132+
ParseExtent(dimUnits, dimArrays);
133+
});
134+
135+
} else {
136+
setMetadata(null);
137+
}
138+
}, [reFetch]);
139+
140+
useEffect(()=> {
141+
if (!textures) return;
142+
const updated = textures.map(tex => {
143+
const clone = tex.clone();
144+
if (interpPixels) {
145+
clone.minFilter = THREE.LinearFilter;
146+
clone.magFilter = THREE.LinearFilter;
147+
} else {
148+
clone.minFilter = THREE.NearestFilter;
149+
clone.magFilter = THREE.NearestFilter;
150+
}
151+
clone.needsUpdate = true;
152+
return clone ;
153+
});
154+
setTextures(updated as THREE.Data3DTexture[] | THREE.DataTexture[]);
155+
},[interpPixels])
156+
157+
useEffect(() => {
158+
// This cleanup function will run when the `textures` state is about to change,
159+
// or when the component unmounts.
160+
return () => {
161+
if (textures) {
162+
textures.forEach(tex => {
163+
tex.dispose();
164+
});
165+
}
166+
};
167+
}, [textures]);
168+
169+
return { textures, show, stableMetadata, setTextures };
170+
};

0 commit comments

Comments
 (0)