Skip to content

Commit 3370e54

Browse files
authored
Merge pull request #26 from EarthyScience/ZarrCache
Implemented caching and timeslicing from loaded array
2 parents e9db208 + 5acf12f commit 3370e54

File tree

4 files changed

+104
-5
lines changed

4 files changed

+104
-5
lines changed

.eslintrc.cjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ module.exports = {
1414
'warn',
1515
{ allowConstantExport: true },
1616
],
17+
'@typescript-eslint/no-unused-vars': ['off'],
1718
},
1819
}

src/components/CanvasGeometry.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ THREE.Cache.enabled = true;
33
import { Canvas } from '@react-three/fiber';
44
import { Center, OrbitControls, Environment, Html } from '@react-three/drei'
55
// import * as zarr from 'zarrita'
6-
import { variables, GetArray } from '@/components/ZarrLoaderLRU'
7-
import { useEffect, useState } from 'react';
6+
import { variables, ZarrDataset } from '@/components/ZarrLoaderLRU'
7+
import { useEffect, useState, useMemo } from 'react';
88
// import { useEffect, useState } from 'react';
99
import { useControls } from 'leva'
1010
// import { Leva } from 'leva'
@@ -55,15 +55,21 @@ export function CanvasGeometry() {
5555
const [valueScales,setValueScales] = useState({maxVal:1,minVal:-1})
5656
const [showTimeSeries,setShowTimeSeries] = useState<boolean>(false)
5757
const [colormap,setColormap] = useState<THREE.DataTexture>(GetColorMapTexture())
58+
const [timeSeries, setTimeSeries] = useState<number[]>([0]);
59+
60+
61+
const ZarrDS = useMemo(()=>new ZarrDataset(storeURL),[])
5862

5963
useEffect(()=>{
6064
setColormap(GetColorMapTexture(colormap,cmap));
6165
},[cmap, colormap])
6266

67+
68+
//DATA LOADING
6369
useEffect(() => {
6470
if (variable != "Default") {
6571
//Need to add a check somewhere here to swap to 2D or 3D based on shape. Probably export two variables from GetArray
66-
GetArray(storeURL, variable).then((result) => {
72+
ZarrDS.GetArray(variable).then((result) => {
6773
// result now contains: { data: TypedArray, shape: number[], dtype: string }
6874
const [texture, shape, scaling] = ArrayToTexture({
6975
data: result.data,
@@ -97,6 +103,13 @@ export function CanvasGeometry() {
97103
}
98104
}, [variable])
99105

106+
//TIMESERIES
107+
useEffect(()=>{
108+
if(ZarrDS){
109+
ZarrDS.GetTimeSeries(timeSeriesLocs).then((e)=> setTimeSeries(e))
110+
}
111+
},[timeSeriesLocs])
112+
100113
return (
101114
<>
102115
<div className='canvas'>

src/components/PlotObjects.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,6 @@ import { useState } from 'react'
132132

133133
export const UVCube = ({shape,setTimeSeriesLocs} : {shape:THREE.Vector3, setTimeSeriesLocs:React.Dispatch<React.SetStateAction<TimeSeriesLocs>>} )=>{
134134
const [clickPoint, setClickPoint] = useState<THREE.Vector3 | null>(null);
135-
console.log("logging the click point", clickPoint)
136-
137135
function TimeSeriesLocs(event: THREE.Intersection){
138136
const point = event.point;
139137
const uv = event.uv!;

src/components/ZarrLoaderLRU.tsx

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export async function GetArray(storePath: string, variable: string): Promise<Zar
4747
if (outVar.is("number") || outVar.is("bigint")) {
4848
const chunk = await zarr.get(outVar)
4949
const typedArray = new Float32Array(chunk.data);
50+
console.log(chunk);
5051
// TypeScript will now infer the correct numeric type
5152
return {
5253
data: typedArray,
@@ -83,6 +84,8 @@ function parseUVCoords({normal,uv}:{normal:THREE.Vector3,uv:THREE.Vector2}){
8384
}
8485
}
8586

87+
88+
8689
export async function GetTimeSeries({TimeSeriesObject}:GetTimeSeries){
8790
const {uv,normal,variable, storePath} = TimeSeriesObject
8891
const d_store = zarr.tryWithConsolidated(
@@ -99,6 +102,90 @@ export async function GetTimeSeries({TimeSeriesObject}:GetTimeSeries){
99102
return arr
100103
}
101104

105+
interface TimeSeriesInfo{
106+
uv:THREE.Vector2,
107+
normal:THREE.Vector3
108+
}
109+
110+
export class ZarrDataset{
111+
private storePath: string;
112+
private variable: string;
113+
private cache: { [key: string]: any };
114+
115+
constructor(storePath: string){
116+
this.storePath = storePath;
117+
this.variable = "Default";
118+
this.cache = {};
119+
}
120+
121+
async GetArray(variable: string){
122+
//This checks if variable is stored in cache
123+
this.variable = variable;
124+
let outVar = null;
125+
if (this.cache.hasOwnProperty(variable)){
126+
console.log("Using Cache")
127+
return this.cache[variable]
128+
}
129+
const d_store = zarr.tryWithConsolidated(
130+
new zarr.FetchStore(this.storePath)
131+
);
132+
133+
const group = await d_store.then(store => zarr.open(store, {kind: 'group'}))
134+
135+
outVar = await zarr.open(group.resolve(variable), {kind:"array"})
136+
// Type check using zarr.Array.is
137+
if (outVar.is("number") || outVar.is("bigint")) {
138+
const chunk = await zarr.get(outVar)
139+
const typedArray = new Float32Array(chunk.data);
140+
this.cache[variable] = chunk;
141+
// TypeScript will now infer the correct numeric type
142+
return {
143+
data: typedArray,
144+
shape: chunk.shape,
145+
dtype: outVar.dtype
146+
}
147+
} else {
148+
throw new Error(`Unsupported data type: Only numeric arrays are supported. Got: ${outVar.dtype}`)
149+
}
150+
}
151+
152+
async GetTimeSeries(TimeSeriesInfo:TimeSeriesInfo){
153+
const {uv,normal} = TimeSeriesInfo
154+
if (!this.cache[this.variable]){
155+
return [0]
156+
}
157+
const {data,shape,stride} = this.cache[this.variable]
158+
//This is a complicated logic check but it works bb
159+
const sliceSize = parseUVCoords({normal,uv})
160+
161+
const slice = sliceSize.map((value, index) =>
162+
value === null || shape[index] === null ? null : Math.round(value * shape[index]));
163+
164+
const mapDim = slice.indexOf(null);
165+
const dimStride = stride[mapDim];
166+
const pz = slice[0] == null ? 0 : stride[0]*slice[0]
167+
const py = slice[1] == null ? 0 : stride[1]*slice[1]
168+
const px = slice[2] == null ? 0 : stride[2]*slice[2]
169+
170+
// console.log(`
171+
// Slice:${slice}
172+
// mapDim:${mapDim}
173+
// dimStride:${dimStride}
174+
// pz:${pz}
175+
// py:${py}
176+
// px:${px}
177+
// `)
178+
const ts = [];
179+
180+
for (let i = 0; i < shape[mapDim] ; i++){
181+
const idx = i*dimStride+pz+py+px
182+
ts.push(data[idx])
183+
}
184+
return ts;
185+
}
186+
187+
}
188+
102189

103190

104191

0 commit comments

Comments
 (0)