Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified cypress/snapshots/app.cy.ts/bgr_image.snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cypress/snapshots/app.cy.ts/compound_1D.snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cypress/snapshots/app.cy.ts/fillvalue_1D.snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cypress/snapshots/app.cy.ts/fillvalue_2D.snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cypress/snapshots/app.cy.ts/heatmap_2D.snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cypress/snapshots/app.cy.ts/heatmap_2D_complex.snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cypress/snapshots/app.cy.ts/heatmap_2D_inverted_cmap.snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cypress/snapshots/app.cy.ts/heatmap_4d_default.snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cypress/snapshots/app.cy.ts/heatmap_4d_remapped.snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cypress/snapshots/app.cy.ts/heatmap_4d_sliced.snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cypress/snapshots/app.cy.ts/heatmap_4d_zeros.snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cypress/snapshots/app.cy.ts/heatmap_domain.snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cypress/snapshots/app.cy.ts/line_1D.snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cypress/snapshots/app.cy.ts/line_complex_1D.snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cypress/snapshots/app.cy.ts/matrix_1D.snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified cypress/snapshots/app.cy.ts/rgb_image.snap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions packages/app/src/__tests__/CorePack.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ test('visualize 1D compound dataset', async () => {
expect(screen.getByText('Argon')).toBeVisible();
});

test('visualize 1D opaque dataset', async () => {
await renderApp('/nD_datasets/oneD_opaque');

expect(getVisTabs()).toEqual([Vis.Array]);
expect(getSelectedVisTab()).toBe(Vis.Array);
expect(screen.getByText('Uint8Array [ 0,1,2 ]')).toBeVisible();
});

test('visualize 2D dataset', async () => {
await renderApp('/nD_datasets/twoD');

Expand Down Expand Up @@ -166,6 +174,14 @@ test('visualize 2D complex dataset', async () => {
).toBeVisible();
});

test('visualize 2D opaque dataset', async () => {
await renderApp('/nD_datasets/twoD_opaque');

expect(getVisTabs()).toEqual([Vis.Array]);
expect(getSelectedVisTab()).toBe(Vis.Array);
expect(screen.getByText('Uint8Array [ 0,1 ]')).toBeVisible();
});

test('show interactions help for heatmap according to "keep ratio"', async () => {
const { user } = await renderApp();

Expand Down
13 changes: 13 additions & 0 deletions packages/app/src/__tests__/DimensionMapper.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,19 @@ test('slice through 2D dataset', async () => {
expect(d0Slider).toHaveValue(1);
});

test('slice through 2D opaque dataset', async () => {
const { user } = await renderApp('/nD_datasets/twoD_opaque');

expect(screen.getByText('Uint8Array [ 0,1 ]')).toBeVisible();

// Move to next slice with keyboard
const d0Slider = screen.getByRole('slider', { name: 'D0' });
await user.type(d0Slider, '{ArrowUp}');

expect(d0Slider).toHaveValue(1);
await expect(screen.findByText('Uint8Array [ 4,5 ]')).resolves.toBeVisible();
});

test('maintain mapping when switching to inspect mode and back', async () => {
const { user } = await renderApp({
initialPath: '/nD_datasets/twoD',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@

.dimSize {
flex: 1 0;
min-width: 2.25em; /* in case there are no axes */
padding: 0 0.1875rem;
text-align: center;
}
Expand Down
6 changes: 3 additions & 3 deletions packages/app/src/dimension-mapper/store.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ interface DimMappingState {
) => void;
}

function createLineConfigStore() {
function createDimMappingStore() {
return createStore<DimMappingState>((set) => ({
dims: [],
axesCount: 0,
Expand All @@ -41,7 +41,7 @@ interface Props {}
export function DimMappingProvider(props: PropsWithChildren<Props>) {
const { children } = props;

const [store] = useState(createLineConfigStore);
const [store] = useState(createDimMappingStore);

return (
<StoreContext.Provider value={store}>{children}</StoreContext.Provider>
Expand All @@ -62,7 +62,7 @@ export function useDimMappingState(
const mapping = isStale
? [
...Array.from({ length: dims.length - axesCount }, () => 0),
...(dims.length > 0
...(dims.length > 0 && axesCount > 0
? ['y' as const, 'x' as const].slice(-axesCount)
: []),
]
Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function useDatasetValue<D extends Dataset<ArrayShape | ScalarShape>>(
// If `selection` is undefined, the entire dataset will be fetched
const value = valuesStore.get({ dataset, selection });

assertDatasetValue(value, dataset);
assertDatasetValue(value, dataset, selection);
return value;
}

Expand All @@ -73,7 +73,7 @@ export function useDatasetsValues<D extends Dataset<ArrayShape | ScalarShape>>(
}

const value = valuesStore.get({ dataset, selection });
assertDatasetValue(value, dataset);
assertDatasetValue(value, dataset, selection);
return value;
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,29 @@ exports[`test file matches snapshot 1`] = `
34,
],
},
{
"name": "byte_string_2D",
"rawType": {
"class": 5,
"dtype": "|V1",
"size": 1,
"tag": "",
},
"shape": [
2,
2,
],
"type": {
"class": "Opaque",
"tag": "",
},
"value": Uint8Array [
0,
17,
0,
17,
],
},
{
"name": "datetime64_scalar",
"rawType": {
Expand Down Expand Up @@ -1586,6 +1609,108 @@ exports[`test file matches snapshot 1`] = `
],
],
},
{
"name": "compound_mixed_2D",
"rawType": {
"class": 6,
"dtype": {
"arr": "|V8",
"bool": "|b1",
},
"members": {
"arr": {
"base": {
"class": 1,
"dtype": "<f4",
"order": 0,
"size": 4,
},
"class": 10,
"dims": [
2,
],
"dtype": "|V8",
"size": 8,
},
"bool": {
"base": {
"class": 0,
"dtype": "|i1",
"order": 0,
"sign": 1,
"size": 1,
},
"class": 8,
"dtype": "|b1",
"members": {
"FALSE": 0,
"TRUE": 1,
},
"size": 1,
},
},
"size": 9,
},
"shape": [
2,
2,
],
"type": {
"class": "Compound",
"fields": {
"arr": {
"base": {
"class": "Float",
"endianness": "little-endian",
"size": 32,
},
"class": "Array",
"dims": [
2,
],
},
"bool": {
"base": {
"class": "Integer",
"endianness": "little-endian",
"signed": true,
"size": 8,
},
"class": "Boolean",
},
},
},
"value": [
[
true,
[
0,
1,
],
],
[
false,
[
2,
3,
],
],
[
false,
[
4,
5,
],
],
[
true,
[
6,
7,
],
],
],
},
{
"name": "reference_scalar",
"rawType": {
Expand Down
10 changes: 5 additions & 5 deletions packages/app/src/providers/hsds/hsds-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,15 +140,15 @@ export class HsdsApi extends DataProviderApi {
signal?: AbortSignal,
onProgress?: OnProgress,
): Promise<unknown> {
const { dataset } = params;
const { dataset, selection } = params;
assertHsdsDataset(dataset);

const value = await this.fetchValue(dataset.id, params, signal, onProgress);

/* HSDS doesn't reduce the number of dimensions when selecting indices,
* so the flattening must be done on all dimensions regardless of the selection.
* https://github.com/HDFGroup/hsds/issues/88 */
return hasArrayShape(dataset) ? flattenValue(value, dataset) : value;
// HSDS doesn't reduce the number of dimensions when slicing
return hasArrayShape(dataset)
? flattenValue(value, dataset, selection)
: value;
}

public override async getAttrValues(
Expand Down
14 changes: 9 additions & 5 deletions packages/app/src/providers/hsds/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { assertArray, isGroup } from '@h5web/shared/guards';
import { assertArray, isGroup, isScalarSelection } from '@h5web/shared/guards';
import { H5T_CSET, H5T_ORDER, H5T_STR } from '@h5web/shared/h5t';
import {
type ArrayShape,
Expand Down Expand Up @@ -166,9 +166,13 @@ export function flattenValue(
value: unknown,
dataset: Dataset<ArrayShape>,
selection?: string,
): unknown[] {
): unknown {
assertArray(value);
const slicedDims = selection?.split(',').filter((s) => s.includes(':'));
const dims = slicedDims || dataset.shape;
return value.flat(dims.length - 1);

// Always flatten on all dimensions, regardless of selection
// https://github.com/HDFGroup/hsds/issues/88
const flattened = value.flat(dataset.shape.length - 1);

// Remove last remaining dimension when selecting a scalar value
return isScalarSelection(selection) ? flattened[0] : flattened;
}
8 changes: 7 additions & 1 deletion packages/app/src/providers/mock/mock-api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { assertArrayShape, assertDefined } from '@h5web/shared/guards';
import {
assertArray,
assertArrayShape,
assertDefined,
} from '@h5web/shared/guards';
import {
type ArrayShape,
type AttributeValues,
Expand Down Expand Up @@ -79,6 +83,8 @@ export class MockApi extends DataProviderApi {
}

assertArrayShape(dataset);
assertArray(value);

return sliceValue(value, dataset, selection);
}

Expand Down
8 changes: 8 additions & 0 deletions packages/app/src/providers/mock/mock-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@ export function makeMockFile(): GroupWithChildren {
array('oneD_enum', {
type: enumType(intType(false, 8), ENUM_MAPPING),
}),
array('oneD_opaque', { type: opaqueType() }),
dataset(
'oneD_opaque_png',
opaqueType(),
[2],
[PNG_RED_DOT, PNG_RED_DOT],
),
array('twoD'),
array('twoD_fillvalue', {
valueId: 'twoD',
Expand All @@ -152,6 +159,7 @@ export function makeMockFile(): GroupWithChildren {
array('twoD_enum', {
type: enumType(intType(false, 8), ENUM_MAPPING),
}),
array('twoD_opaque', { type: opaqueType() }),
array('threeD'),
array('threeD_bool'),
array('threeD_cplx'),
Expand Down
30 changes: 15 additions & 15 deletions packages/app/src/providers/mock/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,18 @@ import {
assertGroup,
assertGroupWithChildren,
isGroup,
isScalarSelection,
} from '@h5web/shared/guards';
import {
type ArrayShape,
type Dataset,
type DType,
type GroupWithChildren,
type ProvidedEntity,
type ScalarShape,
type ScalarValue,
} from '@h5web/shared/hdf5-models';
import { getChildEntity } from '@h5web/shared/hdf5-utils';
import { createArrayFromView } from '@h5web/shared/vis-utils';
import ndarray from 'ndarray';

import { applyMapping } from '../../vis-packs/core/utils';

export const SLOW_TIMEOUT = 3000;

export function findMockEntity(
Expand Down Expand Up @@ -46,19 +43,22 @@ export function findMockEntity(
return child;
}

export function sliceValue<T extends DType>(
value: unknown,
dataset: Dataset<ArrayShape | ScalarShape, T>,
export function sliceValue(
value: unknown[],
dataset: Dataset<ArrayShape>,
selection: string,
): ScalarValue<T>[] {
): unknown {
const { shape } = dataset;
const dataArray = ndarray(value as ScalarValue<typeof dataset.type>[], shape);
const mappedArray = applyMapping(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

applyMapping brings some unnecessary misdirection. Instead, I now call pick and createArrayFromView directly.

And since pick always returns an array even when selecting a scalar, I add a condition to extract the scalar.

dataArray,
selection.split(',').map((s) => (s === ':' ? s : Number.parseInt(s))),
);
const dataArray = ndarray(value, shape);

const slicingState = selection
.split(',')
.map((val) => (val === ':' ? null : Number.parseInt(val)));

const slicedView = dataArray.pick(...slicingState);
const slicedArray = createArrayFromView(slicedView);

return mappedArray.data;
return isScalarSelection(selection) ? slicedArray.get(0) : slicedArray.data;
}

export function getChildrenPaths(
Expand Down
Loading