Skip to content

Commit

Permalink
Values are now flattened in providers
Browse files Browse the repository at this point in the history
  • Loading branch information
loichuder committed May 17, 2021
1 parent 20d2ceb commit a3b4f5a
Show file tree
Hide file tree
Showing 10 changed files with 84 additions and 58 deletions.
14 changes: 6 additions & 8 deletions src/h5web/providers/hsds/hsds-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
Group,
ProviderError,
} from '../models';
import { assertDefined, assertGroup } from '../../guards';
import { assertDefined, assertGroup, hasArrayShape } from '../../guards';
import { ProviderApi } from '../api';
import {
assertHsdsDataset,
Expand Down Expand Up @@ -100,7 +100,7 @@ export class HsdsApi extends ProviderApi {
}

public async getValue(params: ValueRequestParams): Promise<unknown> {
const { path, selection = '' } = params;
const { path } = params;

const entity = await this.getEntity(path);
assertHsdsDataset(entity);
Expand All @@ -109,14 +109,12 @@ export class HsdsApi extends ProviderApi {

// https://github.com/HDFGroup/hsds/issues/88
// HSDS does not reduce the number of dimensions when selecting indices
// This is an issue when trying to slice nD arrays
// Therefore the dimension reduction is done "manually" here with a flat
const numberIndices = selection.match(/\d+/gu)?.length;
if (!numberIndices) {
return value;
// Therefore the flattening must be done on all dimensions regardless of the selection
if (hasArrayShape(entity)) {
return (value as unknown[]).flat(entity.shape.length - 1);
}

return (value as unknown[]).flat(numberIndices);
return value;
}

private async fetchRootId(): Promise<HsdsId> {
Expand Down
7 changes: 6 additions & 1 deletion src/h5web/providers/jupyter/jupyter-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import type {
JupyterMetaResponse,
} from './models';
import { makeStrAttr } from '../mock/metadata-utils';
import { assertDataset, hasComplexType } from '../../guards';
import { assertDataset, hasArrayShape, hasComplexType } from '../../guards';

export class JupyterStableApi extends ProviderApi {
/* API compatible with jupyterlab_hdf v0.5.1 */
Expand All @@ -48,6 +48,11 @@ export class JupyterStableApi extends ProviderApi {
return parseComplex(value as JupyterComplex);
}

if (hasArrayShape(entity)) {
const dims = params.selection?.match(/:/gu) || entity.shape;
return (value as unknown[]).flat(dims.length - 1);
}

return value;
}

Expand Down
15 changes: 14 additions & 1 deletion src/h5web/providers/jupyter/jupyter-dev-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
JupyterMetaResponse,
} from './models';
import { assertGroupContent, convertDtype } from './utils';
import { assertDataset, hasArrayShape } from '../../guards';

interface DevJupyterAttrMeta {
name: string;
Expand All @@ -32,7 +33,19 @@ export class JupyterDevApi extends JupyterStableApi {
}

public async getValue(params: ValueRequestParams): Promise<unknown> {
return this.fetchData(params);
const [value, entity] = await Promise.all([
this.fetchData(params),
this.getEntity(params.path),
]);

assertDataset(entity);

if (hasArrayShape(entity)) {
const dims = params.selection?.match(/:/gu) || entity.shape;
return (value as unknown[]).flat(dims.length - 1);
}

return value;
}

protected async fetchMetadata(path: string): Promise<DevJupyterMetaResponse> {
Expand Down
33 changes: 18 additions & 15 deletions src/h5web/providers/mock/mock-api.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import axios from 'axios';
import ndarray from 'ndarray';
import unpack from 'ndarray-unpack';
import { assertArrayShape, assertPrintableType } from '../../guards';
import {
assertArrayShape,
assertPrintableType,
hasArrayShape,
} from '../../guards';
import { applyMapping } from '../../vis-packs/core/utils';
import { ProviderApi } from '../api';
import type { ValueRequestParams, Entity } from '../models';
import type { ValueRequestParams, Entity, Primitive } from '../models';
import { mockFilepath } from './metadata';
import { assertMockDataset, findMockEntity } from './utils';

Expand Down Expand Up @@ -39,28 +43,27 @@ export class MockApi extends ProviderApi {
await this.cancellableDelay(params);
}

const { value } = dataset;
const { value: rawValue } = dataset;
const value = hasArrayShape(dataset)
? (rawValue as unknown[]).flat(dataset.shape.length - 1)
: rawValue;
if (!selection) {
return value;
}

assertArrayShape(dataset);
assertPrintableType(dataset);

const dataArray = ndarray(
(dataset.value as (number | string | boolean)[]).flat(
dataset.shape.length - 1
),
dataset.shape
);

const dataView = dataArray.pick(
...selection
const { shape, type } = dataset;
const dataArray = ndarray(value as Primitive<typeof type>[], shape);
const mappedArray = applyMapping(
dataArray,
selection
.split(',')
.map((s) => (s === ':' ? null : Number.parseInt(s, 10)))
.map((s) => (s === ':' ? 'x' : Number.parseInt(s, 10)))
);

return unpack(dataView);
return mappedArray.data;
}

private async cancellableDelay(params: ValueRequestParams) {
Expand Down
2 changes: 1 addition & 1 deletion src/h5web/providers/mock/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,5 @@ export function getMockDataArray(path: string): NdArray {
assertNumericType(dataset);
assertArrayShape(dataset);

return ndarray(value.flat(Infinity), dataset.shape);
return ndarray(value.flat(dataset.shape.length - 1), dataset.shape);
}
13 changes: 3 additions & 10 deletions src/h5web/vis-packs/core/complex/MappedComplexVis.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { useEffect, useMemo } from 'react';
import { useMappedArray } from '../hooks';
import { useEffect } from 'react';
import { useMappedArray, useSliceDimsAndMapping } from '../hooks';
import type { AxisMapping, ScaleType } from '../models';
import type { DimensionMapping } from '../../../dimension-mapper/models';
import { isAxis } from '../../../dimension-mapper/utils';
import shallow from 'zustand/shallow';
import { useSafeDomain, useVisDomain } from '../heatmap/hooks';
import type { H5WebComplex } from '../../../providers/models';
Expand Down Expand Up @@ -45,13 +44,7 @@ function MappedComplexVis(props: Props) {

const { visType } = useComplexConfig((state) => state, shallow);

const [slicedDims, slicedMapping] = useMemo(
() => [
dims.filter((_, i) => isAxis(dimMapping[i])),
dimMapping.filter((dim) => isAxis(dim)),
],
[dims, dimMapping]
);
const [slicedDims, slicedMapping] = useSliceDimsAndMapping(dims, dimMapping);

const [mappedArray] = useMappedArray(value, slicedDims, slicedMapping);

Expand Down
13 changes: 3 additions & 10 deletions src/h5web/vis-packs/core/heatmap/MappedHeatmapVis.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { useEffect, useMemo } from 'react';
import { useEffect } from 'react';
import HeatmapVis from './HeatmapVis';
import { useDomain, useMappedArray } from '../hooks';
import { useDomain, useMappedArray, useSliceDimsAndMapping } from '../hooks';
import { useHeatmapConfig } from './config';
import type { AxisMapping, ScaleType } from '../models';
import { DEFAULT_DOMAIN } from '../utils';
import type { DimensionMapping } from '../../../dimension-mapper/models';
import { isAxis } from '../../../dimension-mapper/utils';
import shallow from 'zustand/shallow';
import { useSafeDomain, useVisDomain } from './hooks';

Expand Down Expand Up @@ -39,13 +38,7 @@ function MappedHeatmapVis(props: Props) {
invertColorMap,
} = useHeatmapConfig((state) => state, shallow);

const [slicedDims, slicedMapping] = useMemo(
() => [
dims.filter((_, i) => isAxis(dimMapping[i])),
dimMapping.filter((dim) => isAxis(dim)),
],
[dims, dimMapping]
);
const [slicedDims, slicedMapping] = useSliceDimsAndMapping(dims, dimMapping);

const [dataArray] = useMappedArray(value, slicedDims, slicedMapping);

Expand Down
13 changes: 12 additions & 1 deletion src/h5web/vis-packs/core/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ import {
getBounds,
getCanvasScale,
getCombinedDomain,
getSliceDimsAndMapping,
getSliceSelection,
getValidDomainForScale,
getValueToIndexScale,
} from './utils';
import AxisSystemContext from './shared/AxisSystemContext';
import { AxisScale, ScaleType } from './models';
import { ProviderContext } from '../../providers/context';
import type { Dataset, Value } from '../../providers/models';
import { isDefined } from '../../guards';
import type { Dataset, Value } from '../../providers/models';

export function usePrefetchValues(
datasets: (Dataset | undefined)[],
Expand Down Expand Up @@ -200,3 +201,13 @@ export function useCSSCustomProperties(...names: string[]): {
refCallback,
};
}

export function useSliceDimsAndMapping<T extends DimensionMapping | undefined>(
dims: number[],
dimMapping: T
) {
return useMemo(
() => getSliceDimsAndMapping(dims, dimMapping),
[dimMapping, dims]
);
}
12 changes: 2 additions & 10 deletions src/h5web/vis-packs/core/matrix/MappedMatrixVis.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { useMemo } from 'react';
import MatrixVis from './MatrixVis';
import { useMappedArray } from '../hooks';
import type { DimensionMapping } from '../../../dimension-mapper/models';
import type { Primitive } from '../../../providers/models';
import { isAxis } from '../../../dimension-mapper/utils';
import { useMappedArray, useSliceDimsAndMapping } from '../hooks';
import type { PrintableType } from '../models';

interface Props {
Expand All @@ -17,13 +15,7 @@ interface Props {
function MappedMatrixVis(props: Props) {
const { value, dims, dimMapping, formatter, cellWidth } = props;

const [slicedDims, slicedMapping] = useMemo(
() => [
dims.filter((_, i) => isAxis(dimMapping[i])),
dimMapping.filter((dim) => isAxis(dim)),
],
[dimMapping, dims]
);
const [slicedDims, slicedMapping] = useSliceDimsAndMapping(dims, dimMapping);

const [mappedArray] = useMappedArray(value, slicedDims, slicedMapping);

Expand Down
20 changes: 19 additions & 1 deletion src/h5web/vis-packs/core/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ export function getBaseArray<T>(
value: T[] | undefined,
rawDims: number[]
): NdArray<T> | undefined {
return value && ndarray<T>(value.flat(rawDims.length - 1) as T[], rawDims);
return value && ndarray<T>(value, rawDims);
}

export function applyMapping<T extends NdArray<unknown> | undefined>(
Expand Down Expand Up @@ -363,3 +363,21 @@ export function getSliceSelection(
// Create slice selection string from dim mapping - e.g. [0, 'y', 'x'] => "0,:,:"
return dimMapping.map((dim) => (isAxis(dim) ? ':' : dim)).join(',');
}

export function getSliceDimsAndMapping<T extends DimensionMapping | undefined>(
dims: number[],
dimMapping: T
): [number[], T];
export function getSliceDimsAndMapping(
dims: number[],
dimMapping: DimensionMapping | undefined
): unknown {
if (dimMapping === undefined) {
return [dims, undefined];
}

return [
dims.filter((_, i) => isAxis(dimMapping[i])),
dimMapping.filter(isAxis),
];
}

0 comments on commit a3b4f5a

Please sign in to comment.