Skip to content

Commit

Permalink
feat: added results and dynamic image display
Browse files Browse the repository at this point in the history
  • Loading branch information
nicoalee committed Dec 5, 2024
1 parent b7ec727 commit ad1b7ef
Show file tree
Hide file tree
Showing 10 changed files with 294 additions and 149 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,7 @@ export interface IStateHandlerComponent {

const StateHandlerComponent: React.FC<IStateHandlerComponent> = (props) => {
if (props.isError) {
return (
<Typography sx={{ color: 'error.main' }}>
{props.errorMessage || 'There was an error'}
</Typography>
);
return <Typography sx={{ color: 'error.main' }}>{props.errorMessage || 'There was an error'}</Typography>;
}

if (props.isLoading) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,74 @@
import { Box, Slider, Typography } from '@mui/material';
import { useEffect, useRef, useState } from 'react';
import { Box, Checkbox, Slider, Typography } from '@mui/material';
import { ChangeEvent, useEffect, useRef, useState } from 'react';
import { Niivue, SHOW_RENDER } from '@niivue/niivue';

let niivue: Niivue;

const NiiVueVisualizer: React.FC<{ imageURL: string }> = ({ imageURL }) => {
const canvasRef = useRef(null);
const [thresholdPositive, setThresholdPositive] = useState(3);
const [thresholdNegative, setThresholdNegative] = useState(-3);
const [softThreshold, setSoftThresold] = useState(false);
const [showNegatives, setShowNegatives] = useState(false);
const [showCrosshairs, setShowCrosshairs] = useState(true);
const [threshold, setThreshold] = useState<{
min: number;
max: number;
value: number;
}>({
min: 0,
max: 6,
value: 3,
});

const handleUpdateThresholdPositive = (event: Event, newValue: number | number[]) => {
const handleUpdateThreshold = (event: Event, newValue: number | number[]) => {
if (!niivue) return;
setThresholdPositive(newValue as number);
niivue.volumes[1].cal_min = newValue as number;
const typedVal = newValue as number;
setThreshold((prev) => ({
...prev,
value: typedVal,
}));

// update threshold positive
niivue.volumes[1].cal_min = typedVal;

// update threshold negative
niivue.volumes[1].cal_maxNeg = -1 * typedVal;

niivue.updateGLVolume();
};

const handleToggleSoftThreshold = (event: ChangeEvent<HTMLInputElement>, checked: boolean) => {
if (!niivue) return;

setSoftThresold(checked);
if (checked) {
niivue.overlayOutlineWidth = 2;
niivue.volumes[1].alphaThreshold = 5;
} else {
niivue.overlayOutlineWidth = 0;
niivue.volumes[1].alphaThreshold = 0;
}
niivue.updateGLVolume();
};

const handleToggleShowCrosshairs = (event: ChangeEvent<HTMLInputElement>, checked: boolean) => {
if (!niivue) return;
setShowCrosshairs(checked);
if (checked) {
niivue.setCrosshairWidth(1);
} else {
niivue.setCrosshairWidth(0);
}
niivue.updateGLVolume();
};

const handleUpdateThresholdNegative = (event: Event, newValue: number | number[]) => {
const handleToggleNegatives = (event: ChangeEvent<HTMLInputElement>, checked: boolean) => {
if (!niivue) return;
setThresholdNegative(newValue as number);
niivue.volumes[1].cal_minNeg = -6;
niivue.volumes[1].cal_maxNeg = newValue as number;
setShowNegatives(checked);
if (checked) {
niivue.volumes[1].colormapNegative = 'winter';
} else {
niivue.volumes[1].colormapNegative = '';
}
niivue.updateGLVolume();
};

Expand All @@ -39,11 +87,10 @@ const NiiVueVisualizer: React.FC<{ imageURL: string }> = ({ imageURL }) => {
url: imageURL,
// url: 'https://niivue.github.io/niivue/images/fslt.nii.gz',
colorMap: 'warm',
colormapNegative: 'winter',
cal_min: 3,
cal_max: 6,
cal_minNeg: -6,
cal_maxNeg: -3,
cal_min: 0, // default
cal_max: 6, // default
cal_minNeg: -6, // default
cal_maxNeg: 0, // default
opacity: 1,
},
];
Expand All @@ -58,42 +105,56 @@ const NiiVueVisualizer: React.FC<{ imageURL: string }> = ({ imageURL }) => {
niivue.attachToCanvas(canvasRef.current);
niivue.addVolumesFromUrl(volumes).then(() => {
niivue.volumes[1].alphaThreshold = 0;
niivue.overlayOutlineWidth = 0;

niivue.volumes[0].colorbarVisible = false;
niivue.volumes[1].colormapNegative = '';

niivue.opts.multiplanarShowRender = SHOW_RENDER.ALWAYS;

const globalMax = niivue.volumes[1].global_max || 6;
const globalMin = niivue.volumes[1].global_min || 0;
const largestAbsoluteValue = Math.max(Math.abs(globalMin), globalMax);
const startingValue = largestAbsoluteValue < 2.58 ? largestAbsoluteValue : 2.58;

setThreshold({
min: 0,
max: largestAbsoluteValue + 0.1,
value: startingValue,
});
niivue.volumes[1].cal_min = startingValue;
niivue.volumes[1].cal_max = largestAbsoluteValue + 0.1;

niivue.setInterpolation(true);
niivue.updateGLVolume();
console.log(niivue);
});
}, [imageURL]);

return (
<Box>
<Box sx={{ marginBottom: '10px', display: 'flex', justifyContent: 'space-between' }}>
<Box width="200px">
<Typography variant="body2" gutterBottom>
-Threshold
</Typography>
<Box width="300px">
<Typography gutterBottom={false}>Threshold</Typography>
<Slider
valueLabelDisplay="auto"
min={-6}
min={threshold.min}
step={0.01}
max={0}
onChange={handleUpdateThresholdNegative}
value={thresholdNegative}
max={threshold.max}
onChange={handleUpdateThreshold}
value={threshold.value}
></Slider>
</Box>
<Box width="200px">
<Typography variant="body2" gutterBottom>
+Threshold
</Typography>
<Slider
valueLabelDisplay="auto"
min={0}
step={0.01}
max={6}
onChange={handleUpdateThresholdPositive}
value={thresholdPositive}
></Slider>
<Box>
<Typography gutterBottom={false}>Soft Threshold</Typography>
<Checkbox checked={softThreshold} onChange={handleToggleSoftThreshold} />
</Box>
<Box>
<Typography gutterBottom={false}>Show Negatives</Typography>
<Checkbox checked={showNegatives} onChange={handleToggleNegatives} />
</Box>
<Box>
<Typography gutterBottom={false}>Show Crosshairs</Typography>
<Checkbox value={showCrosshairs} checked={showCrosshairs} onChange={handleToggleShowCrosshairs} />
</Box>
</Box>
<Box sx={{ height: '300px' }}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ import API from 'utils/api';
const useGetMetaAnalysisById = (metaAnalysisId: string | undefined) => {
const query = useQuery(
['meta-analyses', metaAnalysisId],
() =>
API.NeurosynthServices.MetaAnalysisService.metaAnalysesIdGet(
metaAnalysisId || '',
true
),
() => API.NeurosynthServices.MetaAnalysisService.metaAnalysesIdGet(metaAnalysisId || '', true),
{
enabled: !!metaAnalysisId,
select: (data) => data.data,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,8 @@ import API from 'utils/api';

const useGetMetaAnalysisResultById = (metaAnalysisResultId: string | undefined | null) => {
return useQuery(
['meta-analyses-results', metaAnalysisResultId],
() =>
API.NeurosynthServices.MetaAnalysisService.metaAnalysisResultsIdGet(
metaAnalysisResultId || ''
),
['meta-analyses-result', metaAnalysisResultId],
() => API.NeurosynthServices.MetaAnalysisService.metaAnalysisResultsIdGet(metaAnalysisResultId || ''),
{
select: (res: AxiosResponse<ResultReturn>) => res.data,
enabled: !!metaAnalysisResultId,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import axios, { AxiosResponse } from 'axios';
import { useQuery } from 'react-query';

export interface INeurovault {
url: string;
id: number;
file: string;
collection: string;
collection_id: string;
file_size: string;
cognitive_paradigm_cogatlas: string;
cognitive_paradigm_cogatlas_id: string;
cognitive_contrast_cogatlas: string;
cognitive_contrast_cogatlas_id: string;
map_type: string;
analysis_level: string;
name: string;
description: string;
add_date: string;
modify_date: string;
is_valid: boolean;
surface_left_file: string;
surface_right_file: string;
data_origin: string;
target_template_image: string;
subject_species: string;
figure: string;
handedness: string;
age: string;
gender: string;
race: string;
ethnicity: string;
BMI: string;
fat_percentage: string;
waist_hip_ratio: string;
mean_PDS_score: string;
tanner_stage: string;
days_since_menstruation: string;
hours_since_last_meal: string;
bis_bas_score: string;
spsrq_score: string;
bis11_score: string;
thumbnail: string;
reduced_representation: string;
is_thresholded: boolean;
perc_bad_voxels: number;
not_mni: boolean;
brain_coverage: number;
perc_voxels_outside: number;
number_of_subjects: string;
modality: string;
statistic_parameters: string;
smoothness_fwhm: string;
contrast_definition: string;
contrast_definition_cogatlas: string;
cognitive_paradigm_description_url: string;
image_type: string;
}

function useGetNeurovaultImages(neurovaultImages: string[]) {
return useQuery({
queryKey: ['neurovault-images', ...neurovaultImages],
queryFn: async () => {
const res = await Promise.all<AxiosResponse<INeurovault>>(neurovaultImages.map((url) => axios.get(url)));
return res.map((x) => ({
...x.data,
file: x.data.file.replace(/http/, 'https'),
}));
},
enabled: neurovaultImages.length > 0,
});
}

export default useGetNeurovaultImages;

This file was deleted.

Loading

0 comments on commit ad1b7ef

Please sign in to comment.