Skip to content

Commit

Permalink
feat: added nimare file parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
nicoalee committed Dec 5, 2024
1 parent 7e11b5e commit 5e3d363
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ let niivue: Niivue;

const NiiVueVisualizer: React.FC<{ imageURL: string }> = ({ imageURL }) => {
const canvasRef = useRef(null);
const [softThreshold, setSoftThresold] = useState(false);
const [softThreshold, setSoftThresold] = useState(true);
const [showNegatives, setShowNegatives] = useState(false);
const [showCrosshairs, setShowCrosshairs] = useState(true);
const [threshold, setThreshold] = useState<{
Expand Down Expand Up @@ -104,8 +104,8 @@ const NiiVueVisualizer: React.FC<{ imageURL: string }> = ({ imageURL }) => {

niivue.attachToCanvas(canvasRef.current);
niivue.addVolumesFromUrl(volumes).then(() => {
niivue.volumes[1].alphaThreshold = 0;
niivue.overlayOutlineWidth = 0;
niivue.overlayOutlineWidth = 2;
niivue.volumes[1].alphaThreshold = 5;

niivue.volumes[0].colorbarVisible = false;
niivue.volumes[1].colormapNegative = '';
Expand All @@ -119,7 +119,7 @@ const NiiVueVisualizer: React.FC<{ imageURL: string }> = ({ imageURL }) => {

setThreshold({
min: 0,
max: largestAbsoluteValue + 0.1,
max: Math.round((largestAbsoluteValue + 0.1) * 100) / 100,
value: startingValue,
});
niivue.volumes[1].cal_min = startingValue;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { OpenInNew } from '@mui/icons-material';
import { Download, OpenInNew } from '@mui/icons-material';
import { Box, Button, Link, List, ListItemButton, ListItemText, Typography } from '@mui/material';
import NiiVueVisualizer from 'components/Visualizer/NiiVueVisualizer';
import { MetaAnalysisReturn, NeurovaultFile, ResultReturn } from 'neurosynth-compose-typescript-sdk';
import MetaAnalysisResultStatusAlert from './MetaAnalysisResultStatusAlert';
import useGetMetaAnalysisResultById from 'hooks/metaAnalyses/useGetMetaAnalysisResultById';
import { useState } from 'react';
import { useEffect, useState } from 'react';
import StateHandlerComponent from 'components/StateHandlerComponent/StateHandlerComponent';
import useGetNeurovaultImages, { INeurovault } from 'hooks/metaAnalyses/useGetNeurovault';
import DisplayParsedNiMareFile from './DisplayParsedNiMareFile';
import ImageIcon from '@mui/icons-material/Image';

const DisplayMetaAnalysisResults: React.FC<{
metaAnalysis: MetaAnalysisReturn | undefined;
Expand All @@ -28,17 +30,21 @@ const DisplayMetaAnalysisResults: React.FC<{
isLoading: neurovaultFilesIsLoading,
isError: neurovaultFilesIsError,
} = useGetNeurovaultImages(neurovaultFileURLs);
console.log({ neurovaultFiles });
const [selectedNeurovaultImage, setSelectedNeurovaultImage] = useState<INeurovault>();

useEffect(() => {
if (!neurovaultFiles) return;
setSelectedNeurovaultImage(neurovaultFiles[0]);
}, [neurovaultFiles]);

return (
<StateHandlerComponent
isLoading={isLoading || neurovaultFilesIsLoading}
isError={isError || neurovaultFilesIsError}
>
<MetaAnalysisResultStatusAlert metaAnalysis={props.metaAnalysis} metaAnalysisResult={data} />
<Box display="flex" sx={{ height: '100%' }}>
<Box sx={{ width: '27%', height: '100%', maxHeight: '448px', overflowY: 'auto' }}>
<Box display="flex" sx={{ height: '100%', minHeight: '600px' }}>
<Box sx={{ width: '27%', maxHeight: '600px', overflowY: 'auto' }}>
<List sx={{ padding: 0 }}>
{(neurovaultFiles || []).map((neurovaultFile) => (
<ListItemButton
Expand All @@ -54,32 +60,62 @@ const DisplayMetaAnalysisResults: React.FC<{
<Box
sx={{
width: '73%',
backgroundColor: '#f0f0f0',
// backgroundColor: '#0000000a',
padding: '1.5rem',
paddingTop: 0,
borderTopRightRadius: '0px',
borderBottomRightRadius: '8',
maxHeight: '448px',
}}
>
<Box sx={{ marginBottom: '1rem' }}>
<DisplayParsedNiMareFile nimareFileName={selectedNeurovaultImage?.name} />
</Box>
{selectedNeurovaultImage?.file ? (
<NiiVueVisualizer imageURL={selectedNeurovaultImage.file} />
<>
<NiiVueVisualizer imageURL={selectedNeurovaultImage.file} />
<Box display="flex" alignItems="center" justifyContent="space-between">
<Button
component={Link}
sx={{ marginTop: '0.5rem' }}
href={
neurovaultLink.includes('/api')
? neurovaultLink.replace(/\/api/, '')
: neurovaultLink
}
variant="contained"
rel="noreferrer"
size="small"
target="_blank"
disableElevation
>
Open in neurovault
<OpenInNew sx={{ marginLeft: '4px' }} fontSize="small" />
</Button>
<Box>
<Button
size="small"
variant="contained"
endIcon={<Download />}
sx={{ marginTop: '0.5rem', marginRight: '0.5rem' }}
>
Download nifti
</Button>
<Button
size="small"
variant="contained"
endIcon={<ImageIcon />}
sx={{ marginTop: '0.5rem' }}
>
Download image
</Button>
</Box>
</Box>
</>
) : (
<Typography color="warning.dark">No image selected</Typography>
)}
</Box>
</Box>
<Button
component={Link}
sx={{ marginTop: '1rem', marginBottom: '2rem' }}
href={neurovaultLink.includes('/api') ? neurovaultLink.replace(/\/api/, '') : neurovaultLink}
variant="contained"
rel="noreferrer"
target="_blank"
disableElevation
>
Open in neurovault
<OpenInNew sx={{ marginLeft: 'px' }} />
</Button>
</StateHandlerComponent>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { HelpOutline } from '@mui/icons-material';
import { Box, Icon, Paper, Tooltip, Typography } from '@mui/material';
import { useMemo } from 'react';

const nimareOutputs = {
// possible value types
z: 'Z-statistic',
t: 'T-statistic',
p: 'p-value',
logp: 'Negative base-ten logarithm of p-value',
chi2: 'Chi-squared value',
prob: 'Probability value',
stat: 'Test value of meta-analytic algorithm (e.g., ALE values for ALE, OF values for MKDA)',
est: 'Parameter estimate (IBMA only)',
se: 'Standard error of the parameter estimate (IBMA only)',
tau2: 'Estimated between-study variance (IBMA only)',
sigma2: 'Estimated within-study variance (IBMA only)',
label: 'Label map',
// methods of meta analysis
desc: 'Description of the data type. Only used when multiple maps with the same data type are produced by the same method.',
level: 'Level of multiple comparisons correction. Either cluster or voxel.',
corr: 'Type of multiple comparisons correction. Either FWE (familywise error rate) or FDR (false discovery rate).',
method: 'Name of the method used for multiple comparisons correction (e.g., “montecarlo” for a Monte Carlo procedure).',
diag: 'Type of diagnostic. Either Jackknife (jackknife analysis) or FocusCounter (focus-count analysis).',
tab: 'Type of table. Either clust (clusters table) or counts (contribution table).',
tail: 'Sign of the tail for label maps. Either positive or negative.',
};

const parseSegment = (segment: string): { key: string; keyDesc: string; value: string } => {
const [key, value] = segment.split('-');
if (value === undefined) {
// not a method
return {
key: 'type',
keyDesc: 'The type of data in the map.',
value: `${nimareOutputs[key as keyof typeof nimareOutputs]}`,
};
} else {
return {
key: key,
keyDesc: nimareOutputs[key as keyof typeof nimareOutputs],
value: value,
};
}
};

const DisplayParsedNiMareFile: React.FC<{ nimareFileName: string | undefined }> = (props) => {
const fileNameSegments = useMemo(() => {
if (!props.nimareFileName) return [];
const segments = props.nimareFileName.replace('.nii.gz', '').split('_');
return segments.map(parseSegment);
}, [props.nimareFileName]);

return (
<Box display="flex" flexWrap="wrap" justifyContent="space-between">
{fileNameSegments.map((segment) => (
<Paper
key={segment.key}
component={Box}
variant="elevation"
display="flex"
flexDirection="column"
width="30%"
marginBottom="0.5rem"
padding="0.5rem"
elevation={1}
>
<Box display="flex" alignItems="center">
<Typography color="muted.main" gutterBottom={false} variant="caption" marginRight="4px">
{segment.key}
</Typography>
<Tooltip title={<Typography variant="caption">{segment.keyDesc}</Typography>} placement="top">
<Icon fontSize="small">
<HelpOutline fontSize="small" sx={{ color: 'muted.main' }} />
</Icon>
</Tooltip>
</Box>
<Typography variant="body2">{segment.value}</Typography>
</Paper>
))}
</Box>
);
};

export default DisplayParsedNiMareFile;

0 comments on commit 5e3d363

Please sign in to comment.