Skip to content

Commit

Permalink
Support complex auxiliaries
Browse files Browse the repository at this point in the history
  • Loading branch information
axelboc committed Jun 20, 2024
1 parent 392b58f commit 450d14c
Show file tree
Hide file tree
Showing 15 changed files with 151 additions and 45 deletions.
1 change: 1 addition & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module.exports = createConfig(__dirname, getDependencies(), [
'testing-library/await-async-utils': 'off', // Cypress has its own way of dealing with asynchronicity
'testing-library/prefer-screen-queries': 'off', // Cypress provides `cy` object instead of `screen`
'sonarjs/no-duplicate-string': 'off', // incompatible with Cypress testing syntax
'sonarjs/cognitive-complexity': 'off', // allow long `describe` and `context` functions
'unicorn/numeric-separators-style': 'off', // not supported
},
},
Expand Down
34 changes: 30 additions & 4 deletions cypress/e2e/app.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ describe('/mock', () => {
cy.findByRole('figure', { name: 'NeXus 2D' }).should('be.visible');
});

it('visualize dataset with "spectrum" interpretation as NxSpectrum', () => {
it('visualize dataset with "spectrum" interpretation as NxLine', () => {
cy.selectExplorerNode('nexus_entry');
cy.selectExplorerNode('spectrum');

Expand All @@ -304,7 +304,7 @@ describe('/mock', () => {
cy.get('svg[data-type="abscissa"] svg').should('have.text', 'X (nm)');

if (Cypress.env('TAKE_SNAPSHOTS')) {
cy.matchImageSnapshot('nxspectrum');
cy.matchImageSnapshot('nxline');
}
});

Expand Down Expand Up @@ -340,7 +340,7 @@ describe('/mock', () => {
);
});

it('visualize dataset with log scales on both axes on NxSpectrum with SILX_style', () => {
it('visualize dataset with log scales on both axes on NxLine with SILX_style', () => {
cy.selectExplorerNode('nexus_entry');
cy.selectExplorerNode('log_spectrum');

Expand All @@ -357,7 +357,7 @@ describe('/mock', () => {
}
});

it('visualize signal and auxiliary signals datasets as NxSpectrum', () => {
it('visualize signal and auxiliary signals datasets as NxLine', () => {
cy.selectExplorerNode('nexus_entry');
cy.selectExplorerNode('spectrum_with_aux');

Expand Down Expand Up @@ -391,6 +391,32 @@ describe('/mock', () => {
}
});

it('visualize 2D complex signal as NxImage', () => {
cy.selectExplorerNode('nexus_entry');
cy.selectExplorerNode('complex');

cy.findByRole('heading', {
name: 'nexus_entry / complex',
}).should('be.visible');

if (Cypress.env('TAKE_SNAPSHOTS')) {
cy.matchImageSnapshot('nximage_complex_2d');
}
});

it('visualize 2D complex signal with "spectrum" interpretation and auxiliaries as NxLine', () => {
cy.selectExplorerNode('nexus_entry');
cy.selectExplorerNode('complex_spectrum');

cy.findByRole('heading', {
name: 'nexus_entry / complex_spectrum',
}).should('be.visible');

if (Cypress.env('TAKE_SNAPSHOTS')) {
cy.matchImageSnapshot('nxline_complex_2d_aux');
}
});

it('visualize dataset with "rgb-image" interpretation as NxRGB', () => {
cy.selectExplorerNode('nexus_entry');
cy.selectExplorerNode('rgb-image');
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/providers/mock/mock-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@ export function makeMockFile(): GroupWithChildren {
signal: withNxAttr(array('twoD_cplx'), {
interpretation: 'spectrum',
}),
auxiliary: { secondary_cplx: array('secondary_cplx') },
auxAttr: ['secondary_cplx'],
}),
nxData('rgb-image', {
signal: withImageAttr(
Expand Down
52 changes: 32 additions & 20 deletions packages/app/src/vis-packs/core/complex/MappedComplexLineVis.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
import { LineVis, useDomain, useSafeDomain, useVisDomain } from '@h5web/lib';
import type { H5WebComplex } from '@h5web/shared/hdf5-models';
import {
LineVis,
useCombinedDomain,
useDomain,
useDomains,
useSafeDomain,
useVisDomain,
} from '@h5web/lib';
import type { ArrayValue, ComplexType } from '@h5web/shared/hdf5-models';
import type { AxisMapping } from '@h5web/shared/nexus-models';
import type { NumArray } from '@h5web/shared/vis-models';
import { ComplexVisType } from '@h5web/shared/vis-models';
import { useMemo } from 'react';
import { createPortal } from 'react-dom';

import type { DimensionMapping } from '../../../dimension-mapper/models';
import visualizerStyles from '../../../visualizer/Visualizer.module.css';
import { useMappedArray, useSlicedDimsAndMapping } from '../hooks';
import type { LineConfig } from '../line/config';
import { DEFAULT_DOMAIN } from '../utils';
import ComplexLineToolbar from './ComplexLineToolbar';
import { useMappedComplexArrays } from './hooks';
import type { ComplexLineConfig } from './lineConfig';
import { COMPLEX_VIS_TYPE_LABELS, getPhaseAmplitudeValues } from './utils';
import { COMPLEX_VIS_TYPE_LABELS } from './utils';

interface Props {
value: H5WebComplex[];
value: ArrayValue<ComplexType>;
valueLabel?: string;
auxLabels?: string[];
auxValues?: ArrayValue<ComplexType>[];
dims: number[];
dimMapping: DimensionMapping;
axisLabels?: AxisMapping<string>;
Expand All @@ -32,6 +39,8 @@ function MappedComplexLineVis(props: Props) {
const {
value,
valueLabel,
auxLabels = [],
auxValues = [],
dims,
dimMapping,
axisLabels,
Expand All @@ -46,21 +55,20 @@ function MappedComplexLineVis(props: Props) {
const { customDomain, yScaleType, xScaleType, curveType, showGrid } =
lineConfig;

const [slicedDims, slicedMapping] = useSlicedDimsAndMapping(dims, dimMapping);
const { phaseValues, amplitudeValues } = useMemo(
() => getPhaseAmplitudeValues(value),
[value],
const [dataArray, ...auxArrays] = useMappedComplexArrays(
[value, ...auxValues],
dims,
dimMapping,
visType,
);

const dataArray = useMappedArray(
visType === ComplexVisType.Amplitude ? amplitudeValues : phaseValues,
slicedDims,
slicedMapping,
);
const dataDomain = useDomain(dataArray, yScaleType);
const auxDomains = useDomains(auxArrays, yScaleType);
const combinedDomain =
useCombinedDomain([dataDomain, ...auxDomains]) || DEFAULT_DOMAIN;

const dataDomain = useDomain(dataArray, yScaleType) || DEFAULT_DOMAIN;
const visDomain = useVisDomain(customDomain, dataDomain);
const [safeDomain] = useSafeDomain(visDomain, dataDomain, yScaleType);
const visDomain = useVisDomain(customDomain, combinedDomain);
const [safeDomain] = useSafeDomain(visDomain, combinedDomain, yScaleType);

const xDimIndex = dimMapping.indexOf('x');
const ordinateLabel = valueLabel
Expand All @@ -72,7 +80,7 @@ function MappedComplexLineVis(props: Props) {
{toolbarContainer &&
createPortal(
<ComplexLineToolbar
dataDomain={dataDomain}
dataDomain={combinedDomain}
config={config}
lineConfig={lineConfig}
/>,
Expand All @@ -93,6 +101,10 @@ function MappedComplexLineVis(props: Props) {
}}
ordinateLabel={ordinateLabel}
title={title}
auxiliaries={auxArrays.map((array, i) => ({
label: auxLabels[i],
array,
}))}
testid={dimMapping.toString()}
/>
</>
Expand Down
40 changes: 40 additions & 0 deletions packages/app/src/vis-packs/core/complex/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { ComplexVisType } from '@h5web/lib';
import type { H5WebComplex } from '@h5web/shared/hdf5-models';
import type { ComplexLineVisType } from '@h5web/shared/vis-models';
import type { NdArray } from 'ndarray';
import { useMemo } from 'react';

import type { DimensionMapping } from '../../../dimension-mapper/models';
import { useSlicedDimsAndMapping } from '../hooks';
import { applyMapping, getBaseArray } from '../utils';
import { getPhaseAmplitudeValues } from './utils';

export function useMappedComplexArrays(
values: H5WebComplex[][],
dims: number[],
mapping: DimensionMapping,
complexVisType: ComplexLineVisType,
): NdArray<number[]>[] {
const [slicedDims, slicedMapping] = useSlicedDimsAndMapping(dims, mapping);

const phaseAmplitudeValues = useMemo(
() => values.map(getPhaseAmplitudeValues),
[...values], // eslint-disable-line react-hooks/exhaustive-deps
);

const baseArrays = useMemo(() => {
return phaseAmplitudeValues.map((paValues) =>
getBaseArray(
complexVisType === ComplexVisType.Phase
? paValues.phaseValues
: paValues.amplitudeValues,
slicedDims,
),
);
}, [complexVisType, slicedDims, phaseAmplitudeValues]);

return useMemo(
() => baseArrays.map((ndArr) => applyMapping(ndArr, slicedMapping)),
[baseArrays, slicedMapping],
);
}
3 changes: 1 addition & 2 deletions packages/app/src/vis-packs/core/complex/lineConfig.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { ComplexLineVisType } from '@h5web/shared/vis-models';
import { ComplexVisType } from '@h5web/shared/vis-models';
import { createContext, useContext, useState } from 'react';
import type { StoreApi } from 'zustand';
Expand All @@ -6,8 +7,6 @@ import { persist } from 'zustand/middleware';

import type { ConfigProviderProps } from '../../models';

type ComplexLineVisType = ComplexVisType.Phase | ComplexVisType.Amplitude;

export interface ComplexLineConfig {
visType: ComplexLineVisType;
setVisType: (visType: ComplexLineVisType) => void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function NxComplexSpectrumContainer(props: VisContainerProps) {
const nxData = useNxData(entity);
assertComplexNxData(nxData);

const { signalDef, axisDefs, silxStyle } = nxData;
const { signalDef, axisDefs, auxDefs, silxStyle } = nxData;
const signalDims = signalDef.dataset.shape;

const [dimMapping, setDimMapping] = useDimMappingState(signalDims, 1);
Expand Down Expand Up @@ -50,12 +50,14 @@ function NxComplexSpectrumContainer(props: VisContainerProps) {
nxData={nxData}
selection={getSliceSelection(dimMapping)}
render={(nxValues) => {
const { signal, axisValues, title } = nxValues;
const { signal, axisValues, auxValues, title } = nxValues;

return (
<MappedComplexLineVis
value={signal}
valueLabel={signalDef.label}
auxLabels={auxDefs.map((def) => def?.label)}
auxValues={auxValues}
dims={signalDims}
dimMapping={dimMapping}
axisLabels={axisLabels}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ function NxSpectrumContainer(props: VisContainerProps) {

const nxData = useNxData(entity);
assertNumericNxData(nxData);
const { signalDef, axisDefs, auxDefs, silxStyle } = nxData;

const { signalDef, axisDefs, auxDefs, silxStyle } = nxData;
const signalDims = signalDef.dataset.shape;
const errorDims = signalDef.errorDataset?.shape;

Expand Down
6 changes: 4 additions & 2 deletions packages/app/src/vis-packs/nexus/guards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import type { NxData } from './models';
export function assertNumericNxData(
nxData: NxData,
): asserts nxData is NxData<NumericType> {
const { signalDef } = nxData;
const { signalDef, auxDefs } = nxData;
assertNumericType(signalDef.dataset);
auxDefs.forEach((def) => assertNumericType(def.dataset));
}

export function assertComplexNxData(
nxData: NxData,
): asserts nxData is NxData<ComplexType> {
const { signalDef } = nxData;
const { signalDef, auxDefs } = nxData;
assertComplexType(signalDef.dataset);
auxDefs.forEach((def) => assertComplexType(def.dataset));
}
9 changes: 2 additions & 7 deletions packages/app/src/vis-packs/nexus/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { isDefined } from '@h5web/shared/guards';
import type { GroupWithChildren } from '@h5web/shared/hdf5-models';

import type { DimensionMapping } from '../../dimension-mapper/models';
Expand All @@ -7,8 +6,8 @@ import { useValuesInCache } from '../core/hooks';
import type { NxData } from './models';
import {
assertNxDataGroup,
findAssociatedDatasets,
findAuxErrorDataset,
findAuxiliaryDatasets,
findAxesDatasets,
findErrorDataset,
findSignalDataset,
Expand All @@ -23,11 +22,7 @@ export function useNxData(group: GroupWithChildren): NxData {
assertNxDataGroup(group, attrValuesStore);
const signalDataset = findSignalDataset(group, attrValuesStore);
const axisDatasets = findAxesDatasets(group, signalDataset, attrValuesStore);
const auxSignals = findAssociatedDatasets(
group,
'auxiliary_signals',
attrValuesStore,
).filter(isDefined);
const auxSignals = findAuxiliaryDatasets(group, attrValuesStore);

return {
titleDataset: findTitleDataset(group),
Expand Down
5 changes: 2 additions & 3 deletions packages/app/src/vis-packs/nexus/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ type WithError<T extends DatasetDef> = T & {
errorDataset?: NumArrayDataset;
};

export type AuxDef = WithError<DatasetDef<NumericType>>;
export type AxisDef = DatasetDef<NumericType>;

export interface SilxStyle {
Expand All @@ -51,7 +50,7 @@ export interface NxData<
> {
titleDataset?: Dataset<ScalarShape, StringType>;
signalDef: WithError<DatasetDef<T>>;
auxDefs: AuxDef[];
auxDefs: WithError<DatasetDef<T>>[];
axisDefs: AxisMapping<AxisDef>;
silxStyle: SilxStyle;
}
Expand All @@ -60,7 +59,7 @@ export interface NxValues<T extends NumericType | ComplexType> {
title: string;
signal: ArrayValue<T>;
errors?: NumArray;
auxValues: NumArray[];
auxValues: ArrayValue<T>[];
auxErrors: (NumArray | undefined)[];
axisValues: AxisMapping<NumArray>;
}
Loading

0 comments on commit 450d14c

Please sign in to comment.