Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RE2022-278 RE2022-280 add basic histogram and scatter #133

Merged
merged 10 commits into from
Mar 4, 2024
9,101 changes: 4,327 additions & 4,774 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,24 @@
"@types/dompurify": "^3.0.0",
"@types/leaflet": "^1.9.3",
"@types/marked": "^4.0.8",
"@types/plotly.js": "^2.12.30",
"@types/react-plotly.js": "^2.6.3",
"ajv": "^8.12.0",
"canvas": "^2.11.2",
"d3-zoom": "^3.0.0",
"dompurify": "^3.0.1",
"downsample-lttb-ts": "^0.0.6",
"jest-fetch-mock": "^3.0.3",
"leaflet": "^1.9.4",
"marked": "^4.2.12",
"node-sass": "^9.0.0",
"plotly.js": "^2.27.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-error-boundary": "^3.1.4",
"react-hook-form": "^7.47.0",
"react-hot-toast": "^2.4.1",
"react-plotly.js": "^2.6.0",
"react-popper": "^2.3.0",
"react-redux": "^8.0.5",
"react-router-dom": "^6.11.1",
Expand Down
58 changes: 58 additions & 0 deletions src/common/api/collectionsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,15 @@ interface CollectionsResults {
data?: null;
count?: number;
};
getAttribHistogram: {
bins: number[];
values: number[];
};
getAttribScatter: {
xcolumn: string;
ycolumn: string;
data: { x: number; y: number }[];
};
getGenomeAttribsMeta: {
count: number;
columns: Array<ColumnMeta>;
Expand Down Expand Up @@ -377,6 +386,23 @@ interface CollectionsParams {
collection_id: Collection['id'];
load_ver_override?: Collection['ver_tag'];
};
getAttribHistogram: {
collection_id: Collection['id'];
column: string;
match_id?: Match['match_id'];
selection_id?: Selection['selection_id'];
load_ver_override?: Collection['ver_tag'];
filters?: Record<string, string>;
};
getAttribScatter: {
collection_id: Collection['id'];
xcolumn: string;
ycolumn: string;
match_id?: Match['match_id'];
selection_id?: Selection['selection_id'];
load_ver_override?: Collection['ver_tag'];
filters?: Record<string, string>;
};
getMicroTrait: {
collection_id: Collection['id'];
start_after?: KBaseId;
Expand Down Expand Up @@ -683,6 +709,36 @@ export const collectionsApi = baseApi.injectEndpoints({
}),
}),

getAttribHistogram: builder.query<
CollectionsResults['getAttribHistogram'],
CollectionsParams['getAttribHistogram']
>({
query: ({ collection_id, ...options }) =>
collectionsService({
method: 'GET',
url: encode`/collections/${collection_id}/data_products/genome_attribs/hist`,
params: options,
headers: {
authorization: `Bearer ${store.getState().auth.token}`,
},
}),
}),

getAttribScatter: builder.query<
CollectionsResults['getAttribScatter'],
CollectionsParams['getAttribScatter']
>({
query: ({ collection_id, ...options }) =>
collectionsService({
method: 'GET',
url: encode`/collections/${collection_id}/data_products/genome_attribs/scatter`,
params: options,
headers: {
authorization: `Bearer ${store.getState().auth.token}`,
},
}),
}),

getMicroTrait: builder.query<
CollectionsResults['getMicroTrait'],
CollectionsParams['getMicroTrait']
Expand Down Expand Up @@ -876,6 +932,8 @@ export const {
listTaxaCountRanks,
getTaxaCountRank,
getGenomeAttribs,
getAttribHistogram,
getAttribScatter,
getGenomeAttribsMeta,
getMicroTrait,
getMicroTraitMeta,
Expand Down
39 changes: 37 additions & 2 deletions src/common/components/Loader.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { faSpinner } from '@fortawesome/free-solid-svg-icons';
import {
faExclamationCircle,
faSpinner,
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Box, Chip, Stack } from '@mui/material';

/**
* Component for rendering loading states
Expand All @@ -13,8 +17,29 @@ export const Loader = (props: {
children?: React.ReactNode | React.ReactNode[];
/** Overrides the loader style to render a custom loader*/
render?: React.ReactNode | React.ReactNode[];
size?: [width: string, height: string];
error?: string;
}) => {
if (props.loading ?? true) {
const isLoading = props.loading ?? true;
if (props.size && (isLoading || props.error)) {
const {
size: [width, height],
...forwardProps
} = props;
return (
<Box sx={{ width, height, position: 'relative' }}>
<Stack
direction="row"
justifyContent="center"
alignItems="center"
sx={{ width: 1, height: '100%' }}
>
<Loader {...forwardProps} />
</Stack>
</Box>
);
}
if (isLoading) {
if (props.render !== undefined) return <>{props.render}</>;
switch (props.type) {
case 'text':
Expand All @@ -23,6 +48,16 @@ export const Loader = (props: {
default:
return <FontAwesomeIcon icon={faSpinner} spin />;
}
}
if (props.error) {
return (
<Chip
icon={<FontAwesomeIcon icon={faExclamationCircle} />}
variant="outlined"
color="error"
label={props.error}
/>
);
} else {
return <>{props.children}</>;
}
Expand Down
59 changes: 59 additions & 0 deletions src/features/collections/data_products/AttribHistogram.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { ComponentProps, useMemo } from 'react';
import Plot from 'react-plotly.js';
import { getAttribHistogram } from '../../../common/api/collectionsApi';
import { parseError } from '../../../common/api/utils/parseError';
import { Loader } from '../../../common/components/Loader';
import { useFilters } from '../collectionsSlice';
import { useTableViewParams } from './GenomeAttribs';

export const AttribHistogram = ({
collection_id,
column,
size = [600, 600],
}: {
collection_id: string;
column: string;
size?: [width: number, height: number];
}) => {
const { filterMatch, filterSelection, columnMeta } =
useFilters(collection_id);
const viewParams = useTableViewParams(collection_id, {
filtered: true,
selected: Boolean(filterMatch),
matched: Boolean(filterSelection),
});
const { data, isLoading, error } = getAttribHistogram.useQuery({
...viewParams,
column,
});
const plotData: ComponentProps<typeof Plot>['data'] = useMemo(() => {
if (!data) return [];
const bins = data.bins ?? [];
const values = data.values ?? [];
const binStarts = bins.slice(0, -1);
const binWidths = bins.slice(1).map((end, index) => end - bins[index]);
return [{ type: 'bar', x: binStarts, width: binWidths, y: values }];
}, [data]);
if (plotData && !isLoading && !error) {
return (
<Plot
data={plotData}
layout={{
height: size[1],
width: size[0],
title: column,
xaxis: { title: { text: columnMeta?.[column]?.display_name } },
yaxis: { title: { text: 'Count' } },
}}
/>
);
} else {
return (
<Loader
loading={isLoading}
size={[`${size[0]}px`, `${size[1]}px`]}
error={error ? parseError(error).message : undefined}
/>
);
}
};
Loading
Loading