From 42da8e462b7c71697ade2a447cb978253939f5c8 Mon Sep 17 00:00:00 2001 From: Nicholas Lee Date: Sun, 1 Dec 2024 22:24:36 -0500 Subject: [PATCH] feat: visualizer changes --- .../NeurosynthAutocomplete.tsx | 12 +-- .../Visualizer/NiiVueVisualizer.tsx | 28 +++---- .../pages/MetaAnalysis/MetaAnalysisPage.tsx | 78 ++----------------- ...MetaAnalysisSpecificationSelectionStep.tsx | 18 ++--- ...isSpecificationSelectionStepMultiGroup.tsx | 13 ++-- .../components/EditSpecificationDialog.tsx | 39 +++------- .../NoMetaAnalysisResultDisplay.tsx | 75 ++++++++++++++++++ 7 files changed, 123 insertions(+), 140 deletions(-) create mode 100644 compose/neurosynth-frontend/src/pages/MetaAnalysis/components/NoMetaAnalysisResultDisplay.tsx diff --git a/compose/neurosynth-frontend/src/components/NeurosynthAutocomplete/NeurosynthAutocomplete.tsx b/compose/neurosynth-frontend/src/components/NeurosynthAutocomplete/NeurosynthAutocomplete.tsx index a7159df3..4843bbf1 100644 --- a/compose/neurosynth-frontend/src/components/NeurosynthAutocomplete/NeurosynthAutocomplete.tsx +++ b/compose/neurosynth-frontend/src/components/NeurosynthAutocomplete/NeurosynthAutocomplete.tsx @@ -1,11 +1,5 @@ import ErrorIcon from '@mui/icons-material/Error'; -import { - Autocomplete, - AutocompleteRenderOptionState, - Box, - FilterOptionsState, - TextField, -} from '@mui/material'; +import { Autocomplete, AutocompleteRenderOptionState, Box, FilterOptionsState, TextField } from '@mui/material'; import { SystemStyleObject } from '@mui/system'; import ProgressLoader from 'components/ProgressLoader'; import { useInputValidation } from '../../hooks'; @@ -38,6 +32,7 @@ interface INeurosynthAutocomplete { inputPropsSx?: SystemStyleObject; filterOptions?: (options: T[], state: FilterOptionsState) => T[]; groupBy?: (option: T) => string; + errorText?: string; } const NeurosynthAutocomplete = (props: INeurosynthAutocomplete) => { @@ -63,6 +58,7 @@ const NeurosynthAutocomplete = (props: INeurosynthAutocomplete) => { size = 'small', inputPropsSx = {}, groupBy = undefined, + errorText = 'There was an error', } = props; const handleOnChange = (_event: any, newVal: T | null, _reason: any) => { @@ -96,7 +92,7 @@ const NeurosynthAutocomplete = (props: INeurosynthAutocomplete) => { <> {isError && ( - There was an error + {errorText} )} diff --git a/compose/neurosynth-frontend/src/components/Visualizer/NiiVueVisualizer.tsx b/compose/neurosynth-frontend/src/components/Visualizer/NiiVueVisualizer.tsx index e43c5383..70dec558 100644 --- a/compose/neurosynth-frontend/src/components/Visualizer/NiiVueVisualizer.tsx +++ b/compose/neurosynth-frontend/src/components/Visualizer/NiiVueVisualizer.tsx @@ -6,8 +6,8 @@ let niivue: Niivue; const NiiVueVisualizer: React.FC<{ imageURL: string }> = ({ imageURL }) => { const canvasRef = useRef(null); - const [thresholdPositive, setThresholdPositive] = useState(0); - const [thresholdNegative, setThresholdNegative] = useState(0); + const [thresholdPositive, setThresholdPositive] = useState(3); + const [thresholdNegative, setThresholdNegative] = useState(-3); const handleUpdateThresholdPositive = (event: Event, newValue: number | number[]) => { if (!niivue) return; @@ -16,10 +16,10 @@ const NiiVueVisualizer: React.FC<{ imageURL: string }> = ({ imageURL }) => { niivue.updateGLVolume(); }; - const handkleUpdateThresholdNegative = (event: Event, newValue: number | number[]) => { + const handleUpdateThresholdNegative = (event: Event, newValue: number | number[]) => { if (!niivue) return; setThresholdNegative(newValue as number); - niivue.volumes[1].cal_minNeg = -2; + niivue.volumes[1].cal_minNeg = -6; niivue.volumes[1].cal_maxNeg = newValue as number; niivue.updateGLVolume(); }; @@ -29,18 +29,21 @@ const NiiVueVisualizer: React.FC<{ imageURL: string }> = ({ imageURL }) => { const volumes = [ { + // TODO: need to check if TAL vs MNI and set accordingly url: 'https://neurovault.org/static/images/GenericMNI.nii.gz', + // url: 'https://niivue.github.io/niivue/images/fslmean.nii.gz', colormap: 'gray', opacity: 1, }, { url: imageURL, + // url: 'https://niivue.github.io/niivue/images/fslt.nii.gz', colorMap: 'warm', colormapNegative: 'winter', - cal_min: 0, - cal_max: 2, - cal_minNeg: -1, - cal_maxNeg: -2, + cal_min: 3, + cal_max: 6, + cal_minNeg: -6, + cal_maxNeg: -3, opacity: 1, }, ]; @@ -56,11 +59,10 @@ const NiiVueVisualizer: React.FC<{ imageURL: string }> = ({ imageURL }) => { niivue.addVolumesFromUrl(volumes).then(() => { niivue.volumes[1].alphaThreshold = 0; niivue.volumes[0].colorbarVisible = false; - niivue.volumes[1].cal_minNeg = -1.0; - niivue.volumes[1].cal_maxNeg = -2.0; niivue.opts.multiplanarShowRender = SHOW_RENDER.ALWAYS; niivue.setInterpolation(true); niivue.updateGLVolume(); + console.log(niivue); }); }, [imageURL]); @@ -73,10 +75,10 @@ const NiiVueVisualizer: React.FC<{ imageURL: string }> = ({ imageURL }) => { @@ -88,7 +90,7 @@ const NiiVueVisualizer: React.FC<{ imageURL: string }> = ({ imageURL }) => { valueLabelDisplay="auto" min={0} step={0.01} - max={2} + max={6} onChange={handleUpdateThresholdPositive} value={thresholdPositive} > diff --git a/compose/neurosynth-frontend/src/pages/MetaAnalysis/MetaAnalysisPage.tsx b/compose/neurosynth-frontend/src/pages/MetaAnalysis/MetaAnalysisPage.tsx index 3b1c1fa8..bc413214 100644 --- a/compose/neurosynth-frontend/src/pages/MetaAnalysis/MetaAnalysisPage.tsx +++ b/compose/neurosynth-frontend/src/pages/MetaAnalysis/MetaAnalysisPage.tsx @@ -1,5 +1,4 @@ -import { Box, Button, Chip, Typography } from '@mui/material'; -import NeurosynthAccordion from 'components/NeurosynthAccordion/NeurosynthAccordion'; +import { Box, Chip, Typography } from '@mui/material'; import NeurosynthBreadcrumbs from 'components/NeurosynthBreadcrumbs'; import StateHandlerComponent from 'components/StateHandlerComponent/StateHandlerComponent'; import TextEdit from 'components/TextEdit/TextEdit'; @@ -9,18 +8,14 @@ import useGetSpecificationById from 'hooks/metaAnalyses/useGetSpecificationById' import useUpdateMetaAnalysis from 'hooks/metaAnalyses/useUpdateMetaAnalysis'; import useUserCanEdit from 'hooks/useUserCanEdit'; import { ResultReturn, SpecificationReturn, StudysetReturn } from 'neurosynth-compose-typescript-sdk'; -import EditSpecificationDialog from 'pages/MetaAnalysis/components/EditSpecificationDialog'; import MetaAnalysisPageStyles from 'pages/MetaAnalysis/MetaAnalysisPage.styles'; import { useInitProjectStoreIfRequired, useProjectName, useProjectUser } from 'pages/Project/store/ProjectStore'; -import { useState } from 'react'; import { useParams } from 'react-router-dom'; import { NeurostoreAnnotation } from 'utils/api'; import MetaAnalysisResult from './components/MetaAnalysisResult'; -import DisplayMetaAnalysisSpecification from './components/MetaAnalysisSpecification'; -import RunMetaAnalysisInstructions from './components/RunMetaAnalysisInstructions'; -import MetaAnalysisResultStatusAlert from './components/MetaAnalysisResultStatusAlert'; +import NoMetaAnalysisResultDisplay from './components/NoMetaAnalysisResultDisplay'; -const MetaAnalysisPage: React.FC = (props) => { +const MetaAnalysisPage: React.FC = () => { // const { startTour } = useGetTour('MetaAnalysisPage'); const { projectId, metaAnalysisId } = useParams<{ projectId: string; @@ -63,9 +58,7 @@ const MetaAnalysisPage: React.FC = (props) => { const viewingThisPageFromProject = !!projectId; - const [editSpecificationDialogIsOpen, setEditSpecificationDialogIsOpen] = useState(false); - - const updateName = (updatedName: string, _label: string) => { + const updateName = (updatedName: string) => { if (metaAnalysis?.id && specification?.id && studyset?.id && annotation?.id) { updateMetaAnalysisName({ metaAnalysisId: metaAnalysis.id, @@ -76,7 +69,7 @@ const MetaAnalysisPage: React.FC = (props) => { } }; - const updateDescription = (updatedDescription: string, _label: string) => { + const updateDescription = (updatedDescription: string) => { if (metaAnalysis?.id && specification?.id && studyset?.id && annotation?.id) { updateMetaAnalysisDescription({ metaAnalysisId: metaAnalysis.id, @@ -177,66 +170,7 @@ const MetaAnalysisPage: React.FC = (props) => { - {noMetaAnalysisResults ? ( - <> - - - {editsAllowed ? 'View/Edit' : 'View'} Meta-Analysis Specification - - } - > - - setEditSpecificationDialogIsOpen(false)} - /> - - - - - - - - - ) : ( - - )} + {noMetaAnalysisResults ? : } ); diff --git a/compose/neurosynth-frontend/src/pages/MetaAnalysis/components/CreateMetaAnalysisSpecificationSelectionStep.tsx b/compose/neurosynth-frontend/src/pages/MetaAnalysis/components/CreateMetaAnalysisSpecificationSelectionStep.tsx index 0aa2c468..015cabdd 100644 --- a/compose/neurosynth-frontend/src/pages/MetaAnalysis/components/CreateMetaAnalysisSpecificationSelectionStep.tsx +++ b/compose/neurosynth-frontend/src/pages/MetaAnalysis/components/CreateMetaAnalysisSpecificationSelectionStep.tsx @@ -1,10 +1,7 @@ import { Box, Button, Link, Typography } from '@mui/material'; import { ENavigationButton } from 'components/Buttons/NavigationButtons'; import { EPropertyType } from 'components/EditMetadata/EditMetadata.types'; -import { - useProjectExtractionAnnotationId, - useProjectExtractionStudysetId, -} from 'pages/Project/store/ProjectStore'; +import { useProjectExtractionAnnotationId, useProjectExtractionStudysetId } from 'pages/Project/store/ProjectStore'; import { useState } from 'react'; import { IAnalysesSelection, @@ -40,8 +37,8 @@ const CreateMetaAnalysisSpecificationSelectionStep: React.FC<{ - At this time, all of the studies within your studyset should have all the - relevant information (i.e. coordinates, annotations) needed for a meta-analysis + At this time, all of the studies within your studyset should have all the relevant information (i.e. + coordinates, annotations) needed for a meta-analysis @@ -66,8 +63,8 @@ const CreateMetaAnalysisSpecificationSelectionStep: React.FC<{ - By default, the "included" column includes all studies & analyses. At the - moment, only boolean and string annotations are supported. + By default, the "included" column includes all studies & analyses. At the moment, only boolean and + string annotations are supported. - - You selected {algorithm?.estimator?.label || ''} in the previous step, which - is an estimator that requires a second dataset to use as a comparison. Select a - dataset using the dropdown below. You can either select our default reference - datasets (i.e. neurostore, neuroquery, etc) or choose another value from the - inclusion column you set above to use as your own dataset. + You selected {algorithm?.estimator?.label || ''} in the previous step, which is an estimator that + requires a second dataset to use as a comparison. Select a dataset using the dropdown below. You can + either select our default reference datasets (i.e. neurostore, neuroquery, etc) or choose another value + from the inclusion column you set above to use as your own dataset. option?.label === value?.label} value={selectedOption} + isError={!selectedOption} + errorText="No option selected" size="medium" inputPropsSx={{ color: NeurosynthTableStyles[EPropertyType.NONE], @@ -85,7 +86,7 @@ const CreateMetaAnalysisSpecificationSelectionStepMultiGroup: React.FC<{ )} getOptionLabel={(option) => `${option?.label}`} - onChange={(_event, newVal, _reason) => handleSelect(newVal || undefined)} + onChange={(_event, newVal) => handleSelect(newVal || undefined)} options={multiGroupOptions} /> diff --git a/compose/neurosynth-frontend/src/pages/MetaAnalysis/components/EditSpecificationDialog.tsx b/compose/neurosynth-frontend/src/pages/MetaAnalysis/components/EditSpecificationDialog.tsx index 0f1ab673..2f5eb9f7 100644 --- a/compose/neurosynth-frontend/src/pages/MetaAnalysis/components/EditSpecificationDialog.tsx +++ b/compose/neurosynth-frontend/src/pages/MetaAnalysis/components/EditSpecificationDialog.tsx @@ -9,11 +9,7 @@ import { useGetMetaAnalysisById } from 'hooks'; import { EAnalysisType } from 'hooks/metaAnalyses/useCreateAlgorithmSpecification'; import useGetSpecificationById from 'hooks/metaAnalyses/useGetSpecificationById'; import useUpdateSpecification from 'hooks/metaAnalyses/useUpdateSpecification'; -import { - AnnotationReturn, - SpecificationReturn, - StudysetReturn, -} from 'neurosynth-compose-typescript-sdk'; +import { AnnotationReturn, SpecificationReturn, StudysetReturn } from 'neurosynth-compose-typescript-sdk'; import { useEffect, useMemo, useState } from 'react'; import { useParams } from 'react-router-dom'; import { getType } from 'components/EditMetadata/EditMetadata.types'; @@ -69,24 +65,20 @@ const EditSpecificationDialog: React.FC = (props) => { const estimator = specification?.estimator?.type ? { label: specification.estimator.type, - description: - metaAnalysisSpecification.CBMA[specification?.estimator?.type].summary, + description: metaAnalysisSpecification.CBMA[specification?.estimator?.type].summary, } : null; const corrector = specification?.corrector?.type ? { label: specification.corrector.type, - description: - metaAnalysisSpecification.CORRECTOR[specification.corrector.type].summary, + description: metaAnalysisSpecification.CORRECTOR[specification.corrector.type].summary, } : null; setAlgorithmSpec({ estimator: estimator, corrector: corrector, - estimatorArgs: - (specification?.estimator?.args as { [key: string]: any } | undefined) || {}, - correctorArgs: - (specification?.corrector?.args as { [key: string]: any } | undefined) || {}, + estimatorArgs: (specification?.estimator?.args as { [key: string]: any } | undefined) || {}, + correctorArgs: (specification?.corrector?.args as { [key: string]: any } | undefined) || {}, }); }, [specification, props.isOpen]); // add isOpen so that on close/open, the selected val, estimator & corrector are reset @@ -158,10 +150,7 @@ const EditSpecificationDialog: React.FC = (props) => { dialogContentSx={{ paddingBottom: '0' }} maxWidth="lg" > - + = (props) => { Edit Analyses Selection: { setSelectedValue(update); @@ -195,9 +182,7 @@ const EditSpecificationDialog: React.FC = (props) => { {isMultiGroup && ( setSelectedValue(newVal)} - annotationId={ - (metaAnalysis?.annotation as AnnotationReturn)?.neurostore_id || '' - } + annotationId={(metaAnalysis?.annotation as AnnotationReturn)?.neurostore_id || ''} selectedValue={selectedValue} algorithm={algorithmSpec} /> @@ -220,12 +205,8 @@ const EditSpecificationDialog: React.FC = (props) => { {/* empty div used for equally spacing and centering components */} diff --git a/compose/neurosynth-frontend/src/pages/MetaAnalysis/components/NoMetaAnalysisResultDisplay.tsx b/compose/neurosynth-frontend/src/pages/MetaAnalysis/components/NoMetaAnalysisResultDisplay.tsx new file mode 100644 index 00000000..d3f0eb4a --- /dev/null +++ b/compose/neurosynth-frontend/src/pages/MetaAnalysis/components/NoMetaAnalysisResultDisplay.tsx @@ -0,0 +1,75 @@ +import { Box, Button, Typography } from '@mui/material'; +import NeurosynthAccordion from 'components/NeurosynthAccordion/NeurosynthAccordion'; +import DisplayMetaAnalysisSpecification from './MetaAnalysisSpecification'; +import EditSpecificationDialog from './EditSpecificationDialog'; +import MetaAnalysisResultStatusAlert from './MetaAnalysisResultStatusAlert'; +import { useUserCanEdit } from 'hooks'; +import { useProjectUser } from 'pages/Project/store/ProjectStore'; +import { useState } from 'react'; +import { useParams } from 'react-router-dom'; +import RunMetaAnalysisInstructions from './RunMetaAnalysisInstructions'; + +function NoMetaAnalysisResultDisplay() { + const { projectId, metaAnalysisId } = useParams<{ + projectId: string; + metaAnalysisId: string; + }>(); + const projectUser = useProjectUser(); + const editsAllowed = useUserCanEdit(projectUser || undefined); + const [editSpecificationDialogIsOpen, setEditSpecificationDialogIsOpen] = useState(false); + + return ( + <> + + + {editsAllowed ? 'View/Edit' : 'View'} Meta-Analysis Specification + + } + > + + setEditSpecificationDialogIsOpen(false)} + /> + + + + + + + + + ); +} + +export default NoMetaAnalysisResultDisplay;