Skip to content

Commit 86bea59

Browse files
committed
Add helpers to find numeric and string scalar attributes
1 parent db58ffd commit 86bea59

File tree

8 files changed

+92
-85
lines changed

8 files changed

+92
-85
lines changed

packages/app/src/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,13 @@ export { default as DataProvider } from './providers/DataProvider';
176176
export { DataProviderApi } from './providers/api';
177177
export { getValueOrError } from './providers/utils';
178178
export { useValuesInCache } from './hooks';
179+
export {
180+
hasAttribute,
181+
findAttribute,
182+
findScalarNumAttr,
183+
findScalarStrAttr,
184+
getAttributeValue,
185+
} from './utils';
179186
export { parseShape } from '@h5web/shared/hdf5-utils';
180187

181188
export { default as ValueFetcher } from './vis-packs/core/ValueFetcher';

packages/app/src/utils.ts

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1-
import { assertValue } from '@h5web/shared/guards';
1+
import {
2+
assertValue,
3+
hasNumericType,
4+
hasScalarShape,
5+
hasStringType,
6+
} from '@h5web/shared/guards';
27
import {
38
type ArrayShape,
49
type Attribute,
510
type Entity,
11+
type NumericType,
612
type ScalarShape,
13+
type StringType,
714
type Value,
815
} from '@h5web/shared/hdf5-models';
916

@@ -20,9 +27,47 @@ export function findAttribute(
2027
return entity.attributes.find((attr) => attr.name === attributeName);
2128
}
2229

30+
export function findScalarNumAttr(
31+
entity: Entity,
32+
attributeName: AttrName,
33+
): Attribute<ScalarShape, NumericType> | undefined {
34+
const attr = findAttribute(entity, attributeName);
35+
return attr && hasScalarShape(attr) && hasNumericType(attr)
36+
? attr
37+
: undefined;
38+
}
39+
40+
export function findScalarStrAttr(
41+
entity: Entity,
42+
attributeName: AttrName,
43+
): Attribute<ScalarShape, StringType> | undefined {
44+
const attr = findAttribute(entity, attributeName);
45+
return attr && hasScalarShape(attr) && hasStringType(attr) ? attr : undefined;
46+
}
47+
2348
export function getAttributeValue<
2449
A extends Attribute<ScalarShape | ArrayShape>,
25-
>(entity: Entity, attribute: A, attrValuesStore: AttrValuesStore): Value<A> {
50+
>(entity: Entity, attribute: A, attrValuesStore: AttrValuesStore): Value<A>;
51+
52+
export function getAttributeValue<
53+
A extends Attribute<ScalarShape | ArrayShape>,
54+
>(
55+
entity: Entity,
56+
attribute: A | undefined,
57+
attrValuesStore: AttrValuesStore,
58+
): Value<A> | undefined;
59+
60+
export function getAttributeValue<
61+
A extends Attribute<ScalarShape | ArrayShape>,
62+
>(
63+
entity: Entity,
64+
attribute: A | undefined,
65+
attrValuesStore: AttrValuesStore,
66+
): Value<A> | undefined {
67+
if (!attribute) {
68+
return undefined;
69+
}
70+
2671
const value = attrValuesStore.get(entity)[attribute.name];
2772
assertValue(value, attribute);
2873
return value;

packages/app/src/vis-packs/core/hooks.ts

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
import { type DimensionMapping } from '@h5web/lib';
22
import { createMemo } from '@h5web/shared/createMemo';
3-
import {
4-
hasNumericType,
5-
hasScalarShape,
6-
isDefined,
7-
} from '@h5web/shared/guards';
3+
import { isDefined } from '@h5web/shared/guards';
84
import {
95
type ArrayValue,
106
type Dataset,
@@ -25,7 +21,7 @@ import {
2521
bigIntTypedArrayFromDType,
2622
typedArrayFromDType,
2723
} from '../../providers/utils';
28-
import { findAttribute, getAttributeValue } from '../../utils';
24+
import { findScalarNumAttr, getAttributeValue } from '../../utils';
2925
import { applyMapping, getBaseArray, toNumArray } from './utils';
3026

3127
export const useToNumArray = createMemo(toNumArray);
@@ -104,13 +100,8 @@ export function useIgnoreFillValue(dataset: Dataset): IgnoreValue | undefined {
104100
const { attrValuesStore } = useDataContext();
105101

106102
return useMemo(() => {
107-
const fillValueAttr = findAttribute(dataset, '_FillValue');
108-
109-
if (
110-
!fillValueAttr ||
111-
!hasScalarShape(fillValueAttr) ||
112-
!hasNumericType(fillValueAttr)
113-
) {
103+
const fillValueAttr = findScalarNumAttr(dataset, '_FillValue');
104+
if (!fillValueAttr) {
114105
return undefined;
115106
}
116107

packages/app/src/vis-packs/core/rgb/utils.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
1-
import { hasScalarShape, hasStringType } from '@h5web/shared/guards';
21
import { type Dataset } from '@h5web/shared/hdf5-models';
32

43
import { type AttrValuesStore } from '../../../providers/models';
5-
import { findAttribute, getAttributeValue } from '../../../utils';
4+
import { findScalarStrAttr, getAttributeValue } from '../../../utils';
65

76
export function assertSubclassIfPresent(
87
dataset: Dataset,
98
attrValuesStore: AttrValuesStore,
109
): void {
11-
const subClassAttr = findAttribute(dataset, 'IMAGE_SUBCLASS');
10+
const subClassAttr = findScalarStrAttr(dataset, 'IMAGE_SUBCLASS');
1211

1312
if (
1413
subClassAttr &&
15-
hasScalarShape(subClassAttr) &&
16-
hasStringType(subClassAttr) &&
1714
getAttributeValue(dataset, subClassAttr, attrValuesStore) !==
1815
'IMAGE_TRUECOLOR'
1916
) {

packages/app/src/vis-packs/core/visualizations.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
hasPrintableCompoundType,
1010
hasPrintableType,
1111
hasScalarShape,
12-
hasStringType,
1312
} from '@h5web/shared/guards';
1413
import { type Dataset } from '@h5web/shared/hdf5-models';
1514
import {
@@ -23,7 +22,7 @@ import {
2322
} from 'react-icons/fi';
2423

2524
import { type AttrValuesStore } from '../../providers/models';
26-
import { findAttribute, getAttributeValue } from '../../utils';
25+
import { findScalarStrAttr, getAttributeValue } from '../../utils';
2726
import { type VisDef } from '../models';
2827
import {
2928
HeatmapConfigProvider,
@@ -148,11 +147,8 @@ export const CORE_VIS = {
148147
Container: RgbVisContainer,
149148
ConfigProvider: RgbConfigProvider,
150149
supportsDataset: (dataset, attrValuesStore) => {
151-
const classAttr = findAttribute(dataset, 'CLASS');
152-
const classVal =
153-
classAttr && hasScalarShape(classAttr) && hasStringType(classAttr)
154-
? getAttributeValue(dataset, classAttr, attrValuesStore)
155-
: undefined;
150+
const classAttr = findScalarStrAttr(dataset, 'CLASS');
151+
const classVal = getAttributeValue(dataset, classAttr, attrValuesStore);
156152

157153
return (
158154
classVal === 'IMAGE' &&

packages/app/src/vis-packs/nexus/utils.ts

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
assertStringType,
1010
hasArrayShape,
1111
hasNonNullShape,
12-
hasScalarShape,
1312
hasStringType,
1413
isAxisScaleType,
1514
isColorScaleType,
@@ -30,7 +29,12 @@ import { getChildEntity } from '@h5web/shared/hdf5-utils';
3029
import { castArray } from '@h5web/shared/vis-utils';
3130

3231
import { type AttrValuesStore } from '../../providers/models';
33-
import { findAttribute, getAttributeValue, hasAttribute } from '../../utils';
32+
import {
33+
findAttribute,
34+
findScalarStrAttr,
35+
getAttributeValue,
36+
hasAttribute,
37+
} from '../../utils';
3438
import {
3539
type AxisDef,
3640
type DatasetInfo,
@@ -42,11 +46,7 @@ export function getNxClass(
4246
group: Group,
4347
attrValuesStore: AttrValuesStore,
4448
): string | undefined {
45-
const attr = findAttribute(group, 'NX_class');
46-
if (!attr || !hasScalarShape(attr) || !hasStringType(attr)) {
47-
return undefined;
48-
}
49-
49+
const attr = findScalarStrAttr(group, 'NX_class');
5050
return getAttributeValue(group, attr, attrValuesStore);
5151
}
5252

@@ -194,8 +194,8 @@ function findOldStyleAxesDatasets(
194194
signal: Dataset,
195195
attrValuesStore: AttrValuesStore,
196196
): Dataset<ArrayShape, NumericType>[] {
197-
const axesAttr = findAttribute(signal, 'axes');
198-
if (!axesAttr || !hasScalarShape(axesAttr) || !hasStringType(axesAttr)) {
197+
const axesAttr = findScalarStrAttr(signal, 'axes');
198+
if (!axesAttr) {
199199
return [];
200200
}
201201

@@ -309,13 +309,8 @@ export function getSilxStyle(
309309
group: Group,
310310
attrValuesStore: AttrValuesStore,
311311
): SilxStyle {
312-
const silxStyleAttr = findAttribute(group, 'SILX_style');
313-
314-
if (
315-
!silxStyleAttr ||
316-
!hasScalarShape(silxStyleAttr) ||
317-
!hasStringType(silxStyleAttr)
318-
) {
312+
const silxStyleAttr = findScalarStrAttr(group, 'SILX_style');
313+
if (!silxStyleAttr) {
319314
return {};
320315
}
321316

@@ -348,18 +343,11 @@ export function getDatasetInfo(
348343
dataset: Dataset,
349344
attrValuesStore: AttrValuesStore,
350345
): DatasetInfo {
351-
const longNameAttr = findAttribute(dataset, 'long_name');
352-
const unitsAttr = findAttribute(dataset, 'units');
353-
354-
const longName =
355-
longNameAttr && hasScalarShape(longNameAttr) && hasStringType(longNameAttr)
356-
? getAttributeValue(dataset, longNameAttr, attrValuesStore)
357-
: undefined;
358-
359-
const units =
360-
unitsAttr && hasScalarShape(unitsAttr) && hasStringType(unitsAttr)
361-
? getAttributeValue(dataset, unitsAttr, attrValuesStore)
362-
: undefined;
346+
const longNameAttr = findScalarStrAttr(dataset, 'long_name');
347+
const longName = getAttributeValue(dataset, longNameAttr, attrValuesStore);
348+
349+
const unitsAttr = findScalarStrAttr(dataset, 'units');
350+
const units = getAttributeValue(dataset, unitsAttr, attrValuesStore);
363351

364352
return {
365353
label: longName || (units ? `${dataset.name} (${units})` : dataset.name),

packages/app/src/vis-packs/nexus/visualizations.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ import {
33
hasMinDims,
44
hasNumDims,
55
hasNumericType,
6-
hasScalarShape,
7-
hasStringType,
86
} from '@h5web/shared/guards';
97
import {
108
type ArrayShape,
@@ -18,7 +16,7 @@ import { FiActivity, FiFileText, FiImage, FiMap } from 'react-icons/fi';
1816
import { MdGrain } from 'react-icons/md';
1917

2018
import { type AttrValuesStore } from '../../providers/models';
21-
import { findAttribute, getAttributeValue } from '../../utils';
19+
import { findScalarStrAttr, getAttributeValue } from '../../utils';
2220
import {
2321
HeatmapConfigProvider,
2422
LineConfigProvider,
@@ -94,11 +92,8 @@ export const NX_DATA_VIS = {
9492
Container: NxRgbContainer,
9593
ConfigProvider: RgbConfigProvider,
9694
supports: (_, signal, interpretation, attrValuesStore) => {
97-
const classAttr = findAttribute(signal, 'CLASS');
98-
const classVal =
99-
classAttr && hasScalarShape(classAttr) && hasStringType(classAttr)
100-
? getAttributeValue(signal, classAttr, attrValuesStore)
101-
: undefined;
95+
const classAttr = findScalarStrAttr(signal, 'CLASS');
96+
const classVal = getAttributeValue(signal, classAttr, attrValuesStore);
10297

10398
return (
10499
(interpretation === NxInterpretation.RGB || classVal === 'IMAGE') &&

packages/app/src/visualizer/utils.ts

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
import {
2-
hasScalarShape,
3-
hasStringType,
4-
isDataset,
5-
isGroup,
6-
} from '@h5web/shared/guards';
1+
import { isDataset, isGroup } from '@h5web/shared/guards';
72
import {
83
type ChildEntity,
94
type Dataset,
@@ -13,7 +8,7 @@ import {
138
import { buildEntityPath } from '@h5web/shared/hdf5-utils';
149

1510
import { type AttrValuesStore, type EntitiesStore } from '../providers/models';
16-
import { findAttribute, getAttributeValue } from '../utils';
11+
import { findScalarStrAttr, getAttributeValue } from '../utils';
1712
import {
1813
CORE_VIS,
1914
type CoreVisDef,
@@ -53,13 +48,12 @@ export function resolvePath(
5348
if (isNxDataGroup(entity, attrValuesStore)) {
5449
const signal = findSignalDataset(entity, attrValuesStore);
5550

56-
const interpretationAttr = findAttribute(signal, 'interpretation');
57-
const interpretation =
58-
interpretationAttr &&
59-
hasScalarShape(interpretationAttr) &&
60-
hasStringType(interpretationAttr)
61-
? getAttributeValue(signal, interpretationAttr, attrValuesStore)
62-
: undefined;
51+
const interpretationAttr = findScalarStrAttr(signal, 'interpretation');
52+
const interpretation = getAttributeValue(
53+
signal,
54+
interpretationAttr,
55+
attrValuesStore,
56+
);
6357

6458
const supportedVis = Object.values(NX_DATA_VIS).filter((vis) =>
6559
vis.supports(entity, signal, interpretation, attrValuesStore),
@@ -100,18 +94,12 @@ function getNxDefaultPath(
10094
group: GroupWithChildren,
10195
attrValuesStore: AttrValuesStore,
10296
): string | undefined {
103-
const defaultAttr = findAttribute(group, 'default');
104-
105-
if (
106-
!defaultAttr ||
107-
!hasScalarShape(defaultAttr) ||
108-
!hasStringType(defaultAttr)
109-
) {
97+
const defaultAttr = findScalarStrAttr(group, 'default');
98+
if (!defaultAttr) {
11099
return getImplicitDefaultChild(group.children, attrValuesStore)?.path;
111100
}
112101

113102
const defaultPath = getAttributeValue(group, defaultAttr, attrValuesStore);
114-
115103
return defaultPath.startsWith('/')
116104
? defaultPath
117105
: buildEntityPath(group.path, defaultPath);

0 commit comments

Comments
 (0)