Skip to content
Draft
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9b7e3c0
add extra spinal levels info L1 - L5
sandrinebedard Feb 13, 2023
b686796
add updated spinal levels
sandrinebedard Feb 13, 2023
ce64bdf
update spinal levels withour reorientation to RPI
sandrinebedard Feb 14, 2023
e854bba
Add unprocessed Phillips Lab PAM50 levels (#5)
joshuacwnewton Feb 14, 2023
d1520ca
Merge branch 'master' into sb/update-spinal-levels
joshuacwnewton Feb 14, 2023
6ad1a93
Remove unprocessed spinal levels
joshuacwnewton Feb 14, 2023
74cac59
Add README.md with updated processing script
joshuacwnewton Feb 14, 2023
b5a1870
add notebook to generate spinal level map
sandrinebedard Apr 3, 2023
bdfdd5f
Attempt to estimate spinal level using intervertebral foramen distance
tzebre Apr 27, 2023
1f588dc
Attempt to estimate spinal level using intervertebral foramen distanc…
tzebre Apr 27, 2023
2e5ee73
data in csv
tzebre Apr 27, 2023
aacbfb3
estimation with dorsal width
tzebre Apr 28, 2023
93a9433
compute the 3D eucledean distance to position rostral and caudal rootlet
sandrinebedard Apr 28, 2023
00b3c6c
add z_ref since z_c is not adeaqute
sandrinebedard Apr 28, 2023
d0b0099
sort by z_c
sandrinebedard Apr 28, 2023
6a2e221
Diameter + width for estimation
tzebre Apr 28, 2023
558672a
Merge remote-tracking branch 'origin/sb/update-spinal-levels' into sb…
tzebre Apr 28, 2023
8f6297f
Revert "Diameter + width for estimation"
tzebre Apr 28, 2023
5fe0d9a
dorsal width and posterior cord
tzebre Apr 28, 2023
80e8884
dorsal width and posterior SC
tzebre Apr 28, 2023
9d8e965
add foramen file and notebbok with STD
tzebre May 1, 2023
d5208ff
clean notebook with and without std 'spinal_level_theo_sandrine_STD'
tzebre May 4, 2023
4b52a2b
remove old notebook
tzebre May 4, 2023
95f796b
add notebook to generate mendez_df.csv with Supp_values
tzebre May 4, 2023
bb07efd
New version of notebook, modif mm to voxel conversion
tzebre May 10, 2023
4bb585f
local commit of graph testing
tzebre May 10, 2023
87d61b5
push commit with graph and ration modification
tzebre May 16, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions spinal_levels/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
### PAM50 Levels
Copy link
Member

@joshuacwnewton joshuacwnewton Feb 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sharp transition between level values (with no gradient/smoothness)

Is that normal that in the new version, values seem almost binary, ie: the same value is spread out along the S-I axis, without "smoothness" to it. Eg: zoomed version of C2_new (same value across ~20 voxels). Maybe we should inquired the Phillips group about that?

image

Copy link
Member

@joshuacwnewton joshuacwnewton Mar 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The response from Aaron Phillips is as follows:

Email exchange

Julien Cohen-Adad: Q: Is it normal that in the new version, values seem almost binary, ie: the same value is spread out along the S-I axis, without "smoothness" to it.

Aaron Phillips: A: The dataset that we used to estimate both the spinal levels and the corresponding DREZ provided only the mean of each segment (C2-L5) and the standard deviation, from 9 cadavers. Our probability estimate assumed that the mean of each segment had a 100% probability, and we added a normal distribution on both the rostral and caudal ends of each segment to account for variability using the standard deviation of measurement for each spinal level / DREZ (from Mendez paper). This was logical to us, but maybe you have a different thought? Popped a figure in below to help explain.

image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I don't understand from this diagram, is that the "mean" is not a single value in the absissa, but a range. I'm not sure how to interpret that... i'll answer in the email

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The email has been answered, and there has been some back and forth discussion as follows:

Email exchange

Julien Cohen-Adad: What I don't understand from this diagram, is that the "mean" is not a single value, but a range. I'm not sure how to interpret that... To me, if the location of subject 1 is Z=[3,5], subject 2 [4,6] and subject 3 [5,7], then the "average" should be (one line corresponds to a value of Z):

1:0
2:0
3: 0.33
4: 0.66
5: 1
6: 0.66
7: 0.33
8: 0
etc.

So I would not expect to see such a "block" of ones.

Can you please provide us with more details about how this mean spinal segment was obtained?

Aaron Phillips: The dataset that we used to estimate probabilities for each spinal cord level (from the Mendez paper) contained only the population mean and standard deviation across all 9 cadavers from which measurements were taken. As a result, it was not possible to create probability estimates for each layer (1 rostral-caudal voxel level) in the PAM50 model.

We used the total length of the spinal cord between C2 and L5 in the PAM50 model, and with the measurements from the Mendez paper to determine the midpoint of each spinal cord level based on the length of each segment relative to the total length. With the data that we had, we moved forward by estimating the probability to be 1 for each spinal cord level, as it was given as a population mean, and added uncertainty based on the standard deviations. We thought that this approach was feasible given the limitations of the data that we used, relying on a mean length (±st-dev) for a population.

Happy to clarify further

Julien Cohen-Adad: Thank you for your answers.

I think I finally understand what you did, and why I was confused earlier. Our approach, with the PAM50, was to represent the mid-point of the nerve rootlets, whereas in your case (please correct me if I'm wrong), you represent the complete length of a spinal segment (ie: the entire "fanning" of rootlets entry point, which is not a single point in space, but a "range"). > So, if I understand correctly, you did the following:

  • compute the length of the PAM50 cord between C2 and L5 mid-point, let's call it "cord(PAM50)". Related question: Did you compute the total length between C2 and L5 mid-points, or between C2 (most rostral of nerve root entry) and L5 (most caudal of nerve root entry). I presume you did the former, because the PAM50 does not have information about most rostral/caudal entry of nerve rootlets.
  • got the length of the Mendez cords between C2 and L5 mid-point, averaged across subjects let's call it cord(Mendez)
  • got the length of each spinal segment (ie: from the most rostral to the most caudal nerve rootlet), averaged across subjects. Let's call it length_segment[i](Mendez) (i stands for a segment, eg: L5).
  • scale the length of each spinal segment to match the PAM50, using the following equation:
    • length_segment[i](PAM50) = length_segment[i](Mendez) * cord(PAM50) / cord(Mendez)
  • scale the position of the mid-points of each spinal level from the average Mendez cord, to the PAM50 cord, using the same normalization strategy as in the previous point.
  • scale the STD of each spinal level from the average Mendez cord, to the PAM50 cord, using the same normalization strategy. By the way: what STD are we talking about here? Is that the STD that represents the variation of the mid-point along the rostro-caudal axis?
  • build the PAM50 spinal level template, by centering each segment in the mid-points, and by adding, at the rostral and caudal edge of the segment, a half-gaussian function with height of one and STD of value calculated at the previous point.

Also, if my description above is correct, then I do not understand the discrepancy between the figure of the article, and the observed spinal segments. More specifically, the levels in the figure appear to vary more like a Gaussian along the rostro-caudal axis, while the generated spinal segments look more like a segment of "ones", with short smoothness at the edges:

image

Could you share the code and the data that were used to generate the spinal level atlas? That way we will be able to understand exactly what was done. In the future, if users ask us how these levels were calculated, we will be able to point to the exact code, which is better practice for transparency and reproducibility.

About the data: Did you contact Mendez et al., or did you use the values they report in their article? I assume they report all results in the supplementary material, however the link to the supplementary material does not work in the PDF of the article. They also say that the suppl. material is available on the mayoclinic website (see screenshot below), but when going to this website and searching for their article, I do not see a link to the suppl. material. Can you please send it to us if you have it?

image

We are now waiting on a response from Aaron to confirm the methods used, and to potentially supply us with the raw data + processing code. Until then, I'm not sure if there is much we can do to proceed.


These level files are a slightly modified copy of the [level files](https://github.com/PhillipsLab/pam50/tree/main/Spinal%20Cord%20Levels%20NIfTI) produced by the [Phillips Lab](https://github.com/PhillipsLab):

Modifications include:

- Change data type from float64 to float32
- Copy header from current PAM50/spinal_levels
- Rename files

To reproduce the modified files, please run `git checkout e854bbad9ab550fd93acabeaf43c97cf66b3a4e5`, then run the following script in your terminal:

```bash
#!/bin/bash
#
# Process Phillips Lab PAM50 spinal levels to match existing PAM50 conventions.
#
# Usage:
# ./process_spinal_levels.sh
# 1. Clone https://github.com/spinalcordtoolbox/PAM50
# 2. Checkout commit e854bbad9ab550fd93acabeaf43c97cf66b3a4e5
# 3. Run inside /PAM50/spinal_levels_PhillipsLab/
# Authors: Sandrine Bédard, Joshua Newton

set -x
# Immediately exit if error
set -e -o pipefail

# Exit if user presses CTRL+C (Linux) or CMD+C (OSX)
trap "echo Caught Keyboard Interrupt within script. Exiting now.; exit" INT

start=`date +%s`

# Add missing info to the `info_label.txt` file to account for newly-added levels
file_info_label=$(realpath "../spinal_levels/info_label.txt")
extra_spinal_levels="20, Spinal level L1, spinal_level_21.nii.gz
21, Spinal level L2, spinal_level_22.nii.gz
22, Spinal level L3, spinal_level_23.nii.gz
23, Spinal level L4, spinal_level_24.nii.gz
24, Spinal level L5, spinal_level_25.nii.gz"
if [[ $(tail -c 23 "$file_info_label") == "spinal_level_20.nii.gz" ]]
then
echo "$extra_spinal_levels" >> "$file_info_label"
fi

# Retrieve input params
PATH_IN=$PWD
PATH_OUT="$PATH_IN/spinal_levels_processed"
for FILE in *.nii.gz; do
file=${FILE/%".nii.gz"}
echo $file
mkdir -p $PATH_OUT/${file}_processed
rsync -avzh $FILE $PATH_OUT/${file}_processed
cd $PATH_OUT/${file}_processed
# Change file type
sct_image -i ${file}.nii.gz -type float32 -o ${file}_float32.nii.gz
file="${file}_float32"
# Copy header of SCT PAM50 template
sct_image -i $SCT_DIR/data/PAM50/spinal_levels/spinal_level_02.nii.gz -copy-header $file.nii.gz -o ${file}_header.nii.gz
file="${file}_header"
# Rename the file to the filename corresponding to the level (specified by `info_label.txt`)
level=$(echo "$file" | cut -d '_' -f 3)
file_out=$(grep -F "$level," $file_info_label | cut -d "," -f 3)
cp $file.nii.gz $file_out
cd "$PATH_IN"
echo $PATH_IN
done

# Display useful info for the log
end=`date +%s`
runtime=$((end-start))
echo
echo "~~~"
echo "SCT version: `sct_version`"
echo "Ran on: `uname -nsr`"
echo "Duration: $(($runtime / 3600))hrs $((($runtime / 60) % 60))min $(($runtime % 60))sec"
echo "~~~"
```
7 changes: 6 additions & 1 deletion spinal_levels/info_label.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Spinal levels labels - generated on 2016-11-28
# Spinal levels labels - generated on 2023-02-13
# Keyword=IndivLabels (Please DO NOT change this line)
# ID, name, file
0, Spinal level C1, spinal_level_01.nii.gz
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blank C1 file

Is that normal that C1 is completely blank?

They did not include any C1 files

Hum, I am a bit reluctant to include a file labeled "C1 spinal levels" but without any label inside-- this is quite confusing for users. Maybe we should just get rid of it?

Copy link
Member

@joshuacwnewton joshuacwnewton Mar 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The response from Aaron Phillips was as follows:

Q: Is there a reason that there is no C1 label?
A: There were not any anatomical measurements for C1 (in the Mendez paper). As a result, we did not include this in our updated estimations of spinal levels.

This partially answers the question, however we still need to decide whether or not we should remove the blank C1 file.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This partially answers the question, however we still need to decide whether or not we should remove the file.

we definitely should. There is absolutely no point in having a 'label' file that contains only zeros. It is just confusing for everyone.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I'm in favor of removing the C1 file, as it would it help to avoid confusion such as this user on the forum: https://forum.spinalcordmri.org/t/c1-vertebral-level-labelling/1002/4?u=joshuacwnewton

However, @jcohenadad has also promised that we would add coverage of the C1 vertebral level in https://github.com/spinalcordtoolbox/spinalcordtoolbox/issues/3997.

So, is the idea that we would remove it just for this release, then re-add it once we have proper spinal level data? 🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrong promise then 😅 , let's get rid of the file

Expand All @@ -21,3 +21,8 @@
17, Spinal level T10, spinal_level_18.nii.gz
18, Spinal level T11, spinal_level_19.nii.gz
19, Spinal level T12, spinal_level_20.nii.gz
20, Spinal level L1, spinal_level_21.nii.gz
21, Spinal level L2, spinal_level_22.nii.gz
22, Spinal level L3, spinal_level_23.nii.gz
23, Spinal level L4, spinal_level_24.nii.gz
24, Spinal level L5, spinal_level_25.nii.gz
Binary file modified spinal_levels/spinal_level_02.nii.gz
Binary file not shown.
Binary file modified spinal_levels/spinal_level_03.nii.gz
Binary file not shown.
Binary file modified spinal_levels/spinal_level_04.nii.gz
Binary file not shown.
Binary file modified spinal_levels/spinal_level_05.nii.gz
Binary file not shown.
Binary file modified spinal_levels/spinal_level_06.nii.gz
Binary file not shown.
Binary file modified spinal_levels/spinal_level_07.nii.gz
Binary file not shown.
Binary file modified spinal_levels/spinal_level_08.nii.gz
Binary file not shown.
Binary file modified spinal_levels/spinal_level_09.nii.gz
Binary file not shown.
Binary file modified spinal_levels/spinal_level_10.nii.gz
Binary file not shown.
Binary file modified spinal_levels/spinal_level_11.nii.gz
Binary file not shown.
Binary file modified spinal_levels/spinal_level_12.nii.gz
Binary file not shown.
Binary file modified spinal_levels/spinal_level_13.nii.gz
Binary file not shown.
Binary file modified spinal_levels/spinal_level_14.nii.gz
Binary file not shown.
Binary file modified spinal_levels/spinal_level_15.nii.gz
Binary file not shown.
Binary file modified spinal_levels/spinal_level_16.nii.gz
Binary file not shown.
Binary file modified spinal_levels/spinal_level_17.nii.gz
Binary file not shown.
Binary file modified spinal_levels/spinal_level_18.nii.gz
Binary file not shown.
Binary file modified spinal_levels/spinal_level_19.nii.gz
Binary file not shown.
Binary file modified spinal_levels/spinal_level_20.nii.gz
Binary file not shown.
Binary file added spinal_levels/spinal_level_21.nii.gz
Binary file not shown.
Binary file added spinal_levels/spinal_level_22.nii.gz
Binary file not shown.
Binary file added spinal_levels/spinal_level_23.nii.gz
Binary file not shown.
Binary file added spinal_levels/spinal_level_24.nii.gz
Binary file not shown.
Binary file added spinal_levels/spinal_level_25.nii.gz
Binary file not shown.