diff --git a/apps/client/src/stores/dataStores/datasetSelectionUntrrackedStore.ts b/apps/client/src/stores/dataStores/datasetSelectionUntrrackedStore.ts index f6d76e86..58ee30c2 100644 --- a/apps/client/src/stores/dataStores/datasetSelectionUntrrackedStore.ts +++ b/apps/client/src/stores/dataStores/datasetSelectionUntrrackedStore.ts @@ -28,8 +28,13 @@ export interface ExperimentMetadata { // can precompute min/max for each column across experiments locationMetadataList: LocationMetadata[]; compositeTabularDataFilename?: string; + // how the segmentation files are saved + // split by cell (default), split by frame + segmentationGrouping?: SegmentationGroupingOptions; } +export type SegmentationGroupingOptions = 'CellFiles' | 'FrameFiles'; + export type Tags = Record; export interface LocationMetadata { @@ -81,6 +86,14 @@ export const useDatasetSelectionStore = defineStore( return null; }); + const segmentationGrouping = computed(() => { + // TODO: calc based on currentExperimentMetadata + if (!currentExperimentMetadata.value) { + return 'CellFiles' + } + return currentExperimentMetadata.value.segmentationGrouping ?? 'CellFiles'; + }) + // Generate Experiment List const experimentFilenameList = asyncComputed(async () => { if (configStore.serverUrl == null) return null; @@ -406,6 +419,7 @@ export const useDatasetSelectionStore = defineStore( compTableName, aggTableName, shownSelectedLocationIds, + segmentationGrouping, }; } ); diff --git a/apps/client/src/stores/dataStores/segmentationStore.ts b/apps/client/src/stores/dataStores/segmentationStore.ts index 426124c0..09ebc375 100644 --- a/apps/client/src/stores/dataStores/segmentationStore.ts +++ b/apps/client/src/stores/dataStores/segmentationStore.ts @@ -6,15 +6,10 @@ import { type Track, } from '@/stores/dataStores/cellMetaDataStore'; import { useDatasetSelectionStore } from '@/stores/dataStores/datasetSelectionUntrrackedStore'; -import type { Feature } from 'geojson'; +import type { Feature, FeatureCollection } from 'geojson'; import { LRUCache } from 'lru-cache'; import { useConfigStore } from '../misc/configStore'; - -// interface LocationSegmentations { -// location: string, -// segmentations: Feature[]; -// } /** * Custom store for managing segmentations. * @returns An object containing functions to retrieve segmentations. @@ -23,14 +18,18 @@ export const useSegmentationStore = defineStore('segmentationStore', () => { const datasetSelectionStore = useDatasetSelectionStore(); const cellMetaData = useCellMetaData(); const configStore = useConfigStore(); + const filesGroupedByFrame = computed(() => datasetSelectionStore.segmentationGrouping === 'FrameFiles'); + const cache = ref( - new LRUCache({ - max: 25_000, + new LRUCache({ + // TODO: this max for the cache is probably too large if we are saving frames. + // could use diff max depending on if we are grabbing from frames vs. cells. + max: filesGroupedByFrame.value ? 500 : 25_000, // each item is small (1-2 KB) fetchMethod: async (jsonUrl, staleValue, { signal }) => { return (await fetch(jsonUrl, { signal }).then((res) => res.json() - )) as Feature; + )) as Feature | FeatureCollection; }, }) ); @@ -40,7 +39,12 @@ export const useSegmentationStore = defineStore('segmentationStore', () => { * @returns An array of GeoJson features representing the segmentations. */ async function getFrameSegmentations(frame: number): Promise { - // Implementation goes here + if (filesGroupedByFrame.value) { + const featureCollection = (await cache.value.fetch( + `${segmentationFolderUrl.value}/${frame}.json` + )) as FeatureCollection; + return featureCollection.features; + } const cells = cellMetaData.frameMap.get(frame); if (!cells) return []; const promises = cells.map((cell) => getCellSegmentation(cell)); @@ -49,15 +53,6 @@ export const useSegmentationStore = defineStore('segmentationStore', () => { ) as Feature[]; } - // /** - // * Get segmentations for a specific track. - // * @param track - The track object. - // * @returns An array of GeoJson features representing the segmentations. - // */ - // async function getTrackSegmentations(track: Track): Promise { - // // Implementation goes here - // } - const segmentationFolderUrl = computed(() => { if ( datasetSelectionStore.currentLocationMetadata @@ -71,21 +66,20 @@ export const useSegmentationStore = defineStore('segmentationStore', () => { return url; }); - async function getCellLocationSegmentations( - cells: Cell[] - ): Promise { - const promises = cells.map((cell) => getCellSegmentation(cell)); - return (await Promise.all(promises)).filter( - (x) => x != null - ) as Feature[]; - } - // Based on the frame, the id, and the location, return the feature (segmentation) - async function getCellLocationSegmentation (frame: string, trackId: string, location: string): Promise { + async function getCellLocationSegmentation(frame: string, trackId: string, location: string): Promise { const locationSegmentationUrl = configStore.getFileUrl(datasetSelectionStore.getLocationMetadata(location)?.segmentationsFolder || ''); - return await cache.value.fetch( + if (filesGroupedByFrame.value) { + const featureCollection = (await cache.value.fetch( + `${locationSegmentationUrl}/${frame}.json` + )) as FeatureCollection; + return featureCollection.features.find( + (feature) => feature.properties?.id.toString() === trackId.toString() + ); + } + return (await cache.value.fetch( `${locationSegmentationUrl}/cells/${frame}-${trackId}.json` - ); + )) as Feature; } /** @@ -98,9 +92,17 @@ export const useSegmentationStore = defineStore('segmentationStore', () => { ): Promise { const frame = cellMetaData.getFrame(cell); const id = cell.trackId; - return await cache.value.fetch( + if (filesGroupedByFrame.value) { + const featureCollection = (await cache.value.fetch( + `${segmentationFolderUrl.value}/${frame}.json` + )) as FeatureCollection; + return featureCollection.features.find( + (feature) => feature.properties?.id.toString() === id.toString() + ); + } + return (await cache.value.fetch( `${segmentationFolderUrl.value}/cells/${frame}-${id}.json` - ); + )) as Feature; } async function getCellSegmentations( @@ -115,8 +117,6 @@ export const useSegmentationStore = defineStore('segmentationStore', () => { return { getFrameSegmentations, getCellLocationSegmentation, - getCellLocationSegmentations, - // getTrackSegmentations, getCellSegmentation, getCellSegmentations, };