Skip to content

Commit

Permalink
Provide three acute behavioral measures.
Browse files Browse the repository at this point in the history
  • Loading branch information
neurolabusc committed Jun 15, 2024
1 parent 5644b67 commit 5f790ba
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 37 deletions.
Binary file removed NoCoC.png
Binary file not shown.
28 changes: 8 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,20 @@
### NiiVue brainchop

Provided a lesion map and an acute [Center of Cancellation (CoC)](https://github.com/neurolabusc/Cancel) score, this web page will predict the chronic neglect severity. The provided lesion map should be normalized to standard space. This is an edge-based solution: the values are computed directly on the web browser, and are not shared with a cloud service. [Try the live demo](https://niivue.github.io/niivue-neglect/)
Provided a lesion map the [live demo](https://niivue.github.io/niivue-neglect/) web page will predict the chronic neglect severity. The provided lesion map should be normalized to standard space. For optimal performance, acute behavioral data should include three behavioral measures: the [Center of Cancellation (CoC) letter score](https://github.com/neurolabusc/Cancel), the [Center of Cancellation (CoC) bells score](https://github.com/neurolabusc/Cancel) and a simple [Copy Task](https://psycnet.apa.org/doiLanding?doi=10.1037%2Ft28076-000). However, the software will provide an estimate with degraded accuracy without these behavioral measures. This is an edge-based solution: the values are computed directly on the web browser, and are not shared with a cloud service.

### Optimal Usage

One can create an accurate prediction of long term spatial neglect symptom severity by providing a lesion map showing the location and extent of the injury as well as the acute behavior (the CoC score).

1. Open the [live demo](https://niivue.github.io/niivue-neglect/).
2. Press the `Open Lesion Map` button and select the normalized lesion. You can normalize lesions using [the clinical toolbox for SPM](https://github.com/neurolabusc/Clinical).
3. You can visually inspect the lesion (shown as red) with respect to the grayscale atlas and the core prediction voxels (shown in blue).
4. Make sure the `Acute CoC Score` option is `checked`.
5. Set the [Center of Cancellation (CoC)](https://github.com/neurolabusc/Cancel) score that was measured acutely.
6. Press the `Prediction` button to see the expected outcome score.

![niivue-neglect user interface](acuteCoC.png)

### Basic Usage

One can create an rough prediction of long term spatial neglect symptom severity by providing a lesion map showing the location and extent of the injury. Note this method is less accurate than methods where acute behavior is known.
### Usage

1. Open the [live demo](https://niivue.github.io/niivue-neglect/).
2. Press the `Open Lesion Map` button and select the normalized lesion. You can normalize lesions using [the clinical toolbox for SPM](https://github.com/neurolabusc/Clinical).
3. You can visually inspect the lesion (shown as red) with respect to the grayscale atlas and the extended prediction voxels (shown in translucent green).
4. Make sure the `Acute CoC Score` option is `unchecked`. Notice that the ability to set the symptom severity will be disabled.
6. Press the `Prediction` button to see the expected outcome score.

![niivue-neglect user interface](NoCoC.png)
3. You can visually inspect the lesion (shown as red) with respect to the grayscale atlas and the core prediction voxels (shown in blue).
4. If known, enter the `letters CoC`: this [Center of Cancellation](https://github.com/neurolabusc/Cancel) value should be a number in the range of 0..1. If this value is unknown, make sure this field is empty.
5. If known, enter the `bells CoC`: this [Center of Cancellation](https://github.com/neurolabusc/Cancel) value should be a number in the range of 0..1. If this value is unknown, make sure this field is empty.
6. If known, enter the `copying score`: this [value](https://psycnet.apa.org/doiLanding?doi=10.1037%2Ft28076-000) value should be a number in the range of 0..8. If this value is unknown, make sure this field is empty.
7. Press the `Prediction` button to see the expected outcome score.

![niivue-neglect user interface](niivue-neglect.png)

### For Developers

Expand Down
Binary file removed acuteCoC.png
Binary file not shown.
9 changes: 6 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@
<body>
<header>
<button id="openBtn">Open Lesion Map</button>
<input type="checkbox" id="cocCheck" checked />
<label for="cocNumber">Acute CoC Score</label>
<input style="width: 7em" type="number" id="cocNumber" min="-1" value ="0.65" max="1"/>
<label for="cocLetters">letters CoC (-1..1)</label>
<input style="width: 7em" type="number" id="cocLetters" min="-1" value ="0.3" max="1"/>
<label for="cocBells">bells CoC (-1..1)</label>
<input style="width: 7em" type="number" id="cocBells" min="-1" value ="0.2" max="1"/>
<label for="copyScore">copying score (0..8)</label>
<input style="width: 7em" type="number" id="copyScore" min="0" value ="2" max="8"/>
<button id="predictBtn">Prediction</button>
<label for="maskSlider">Mask Opacity</label>
<input
Expand Down
51 changes: 38 additions & 13 deletions main.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import { Niivue } from '@niivue/niivue'
async function main() {
function meanOmitNaN(values) {
// e.g. let mn = meanOmitNaN([NaN,2, 3])
let sum = 0
let n = 0
for (let i = 0; i < values.length; i++) {
if (isNaN(values[i])) continue
n ++
sum += values[i]
}
return sum/n
} // meanOmitNaN()
async function addVolumeFromFiles(f) {
await nv1.loadFromFile(f[0])
nv1.setColormap(nv1.volumes[3].id, 'red')
Expand Down Expand Up @@ -103,11 +114,27 @@ async function main() {
const chronCoC = chronZ * 0.0216 + 0.00803
return [lesionVolTotalML, ROI_volML, chronCoC, chronZ]
} // neglect_predict_noCoC()
function neglect_predict() {
function meanOmitNaN(values) {
// e.g. let mn = meanOmitNaN([NaN,2, 3])
let sum = 0
let n = 0
for (let i = 0; i < values.length; i++) {
if (isNaN(values[i])) continue
n ++
sum += values[i]
}
return sum/n
} // meanOmitNaN()
function neglect_predict(acuteLetters, acuteBells, acuteCopy) {
if (nv1.volumes.length !== 4) {
window.alert('Please reload the page and open lesions with the "Open Lesion Map" button')
return
}
let acuteCoC = meanOmitNaN([acuteLetters, acuteBells])
let acuteLettersZ = (acuteLetters - 0.00686)/0.0179 // mean/SD of controls
let acuteBellsZ = (acuteBells - 0.0092)/0.0253 // mean/SD of controls
let acuteCopyZ = (acuteCopy - 0.23333)/0.43018 // mean/SD of controls
let acuteZ = meanOmitNaN([acuteLettersZ, acuteBellsZ, acuteCopyZ])
//volumes: 0=T1, 1=MaskNoCoC, 2=Mask, 3=lesion
let mask = nv1.volumes[2].img
let lesion = nv1.volumes[3].img
Expand Down Expand Up @@ -153,7 +180,6 @@ async function main() {
for (let p = 0; p < nVoxPCA; p++) {
PC[p] = norm0to1(PC[p], -51.9073, 110.0535)
}
let acuteCoC = parseFloat(cocNumber.value)
let acuteCoC0_1 = norm0to1(acuteCoC, -0.024243014, 0.951938077)
let lesionVolTotalML = lesionVolTotal / 1000
let ROI_volML = lesionVol / 1000
Expand Down Expand Up @@ -194,8 +220,6 @@ async function main() {
}
const prediction_mean = prediction_sum / models.length
const diffZ = prediction_mean * (38.72560594 + 1.211389735) - 1.211389735
// calculate acute z-score based on user input CoC
const acuteZ = (acuteCoC - 0.00803)/0.0216 // mean/SD of controls
const chronZ = acuteZ-diffZ
const chronCoC = chronZ * 0.0216 + 0.00803
return [acuteCoC, acuteZ, lesionVolTotalML, ROI_volML, chronCoC, chronZ]
Expand All @@ -213,18 +237,19 @@ async function main() {
input.click()
}
predictBtn.onclick = function () {
if (cocCheck.checked) {
const [acuteCoC, acuteZ, lesionVolTotalML, ROI_volML, chronCoC, chronZ] = neglect_predict()
const str = (`Given ${lesionVolTotalML.toFixed(4)}ml lesion (with ${ROI_volML.toFixed(4)} in core neglect voxels), and acute CoC ${acuteCoC.toFixed(2)} (z= ${acuteZ.toFixed(4)}), predicted chronic CoC is ${chronCoC.toFixed(2)} (z= ${chronZ.toFixed(4)})`)
window.alert(str)
} else {
let acuteLetters = parseFloat(cocLetters.value)
let acuteBells = parseFloat(cocBells.value)
let acuteCopy = parseFloat(copyScore.value)
let acuteCoCNaN = isNaN(acuteLetters) && isNaN(acuteBells)
if (acuteCoCNaN) {
const [lesionVolTotalML, ROI_volML, chronCoC, chronZ] = neglect_predict_noCoC()
const str = (`Given ${lesionVolTotalML.toFixed(4)}ml lesion (with ${ROI_volML.toFixed(4)} in core neglect voxels), predicted chronic CoC is ${chronCoC.toFixed(4)} (z= ${chronZ.toFixed(4)})`)
window.alert(str)
}
}
cocCheck.onchange = function () {
cocNumber.disabled = !this.checked
} else {
const [acuteCoC, acuteZ, lesionVolTotalML, ROI_volML, chronCoC, chronZ] = neglect_predict(acuteLetters, acuteBells, acuteCopy)
const str = (`Given ${lesionVolTotalML.toFixed(4)}ml lesion (with ${ROI_volML.toFixed(4)} in core neglect voxels), and acute CoC ${acuteCoC.toFixed(2)} (z= ${acuteZ.toFixed(4)}), predicted chronic CoC is ${chronCoC.toFixed(4)} (z= ${chronZ.toFixed(4)})`)
window.alert(str)
}
}
function handleLocationChange(data) {
document.getElementById("intensity").innerHTML = data.string
Expand Down
Binary file added niivue-neglect.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion public/neglect_predict.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ function neglect_predict(fnm, acuteCoCl, acuteCoCb, acuteCop)
% Assumes lesion map is normalized to 181x217x181 using SPM
%Examples
% neglect_predict; %use GUI;
% neglect_predict('example_lesion.nii.gz', 0.87, 0.81, 2)
% neglect_predict('M2095_lesion.nii.gz', 0.87, 0.81, 2)
if nargin < 1
[p_file, p_path] = uigetfile('*.nii.gz;*.nii', 'Select lesion map');
if p_file==0
Expand Down

0 comments on commit 5f790ba

Please sign in to comment.