Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
42b240f
add frozen spine generic test split for monitoring csa drift
naga-karthik Mar 8, 2025
0721c54
add minimal script to compute c2c3 csa using the given version of con…
naga-karthik Mar 8, 2025
36f9fd9
add standalone script to compute morphometrics given a model
naga-karthik Mar 8, 2025
95979ac
add comment
naga-karthik Mar 9, 2025
05224f8
clarify comment on vertebral labelling
naga-karthik Mar 9, 2025
da9de7d
add GT section to improve readability
naga-karthik Mar 9, 2025
69069b1
update comments to improve readability
naga-karthik Mar 9, 2025
a271332
deduplicate the use of test_subjects variable
naga-karthik Mar 10, 2025
edea755
prevent shell from failing if git clone already exists
naga-karthik Mar 10, 2025
2004663
update git clone command with a specific tag
naga-karthik Mar 10, 2025
06160b8
move readarray up
naga-karthik Mar 10, 2025
92a0add
remove 2nd readarray
naga-karthik Mar 11, 2025
baeb743
update VERSION_TO_BE_RELEASED variable to include v as well
naga-karthik Mar 11, 2025
18d111b
add first workflow to test GH actions
naga-karthik Mar 11, 2025
a679a4a
test downloading the dataset from workflow
naga-karthik Mar 11, 2025
d237034
add exit command for non-zero status
naga-karthik Mar 11, 2025
4a8ef3f
update dataset download workflow
naga-karthik Mar 11, 2025
4934493
add install git annex command to workflow
naga-karthik Mar 11, 2025
e76816e
remove duplicate uses key in workflow
naga-karthik Mar 11, 2025
6aad55e
install git annex with conda
naga-karthik Mar 11, 2025
5e1aa50
ensure git-annex is accessible via git:
naga-karthik Mar 11, 2025
7a897b4
configure git identity
naga-karthik Mar 11, 2025
1a7ad9e
update dependencies
naga-karthik Mar 11, 2025
fbde62d
update dependencies
naga-karthik Mar 11, 2025
b4522b0
update dependencies
naga-karthik Mar 11, 2025
d189db3
update dependencies
naga-karthik Mar 11, 2025
284cde8
update dependencies
naga-karthik Mar 11, 2025
d4b567f
update dependencies
naga-karthik Mar 11, 2025
2df81ca
update dependencies
naga-karthik Mar 11, 2025
f52a212
activate conda env inside the script, update to python
naga-karthik Mar 11, 2025
726d741
use enviroment yml for installing
naga-karthik Mar 11, 2025
cd1efe2
comment out git-annex accessing
naga-karthik Mar 11, 2025
d3d8138
update dependencies
naga-karthik Mar 11, 2025
763e40e
comment out git-annex accessing
naga-karthik Mar 11, 2025
f92e7cf
explicitly add test subjects
naga-karthik Mar 11, 2025
ffa25c6
revert back to the original installation
naga-karthik Mar 11, 2025
b8e2638
test folder structure
naga-karthik Mar 11, 2025
5393489
test folder structure
naga-karthik Mar 11, 2025
1418385
change directories on the fly
naga-karthik Mar 11, 2025
68a1515
add sct installation commands
naga-karthik Mar 11, 2025
3018594
add action-tmate
naga-karthik Mar 11, 2025
86ea007
add sct installation as a new job
naga-karthik Mar 11, 2025
e84de90
add conda installtion before sct
naga-karthik Mar 11, 2025
79eb6ab
update dependencies
naga-karthik Mar 11, 2025
8cd155c
update dependencies
naga-karthik Mar 11, 2025
5f6eaf0
update dependencies
naga-karthik Mar 11, 2025
8c955f9
update dependencies
naga-karthik Mar 11, 2025
a699b96
revert back to the working workflow
naga-karthik Mar 11, 2025
f306985
update dependencies
naga-karthik Mar 11, 2025
96e49b3
downgrage python
naga-karthik Mar 11, 2025
1361e1c
only install sct
naga-karthik Mar 11, 2025
e51707f
update dependencies
naga-karthik Mar 11, 2025
267838c
update dependencies
naga-karthik Mar 11, 2025
cfff1ab
update dependencies
naga-karthik Mar 12, 2025
aec3678
update dependencies
naga-karthik Mar 12, 2025
24d5de2
move sct install before python setup
naga-karthik Mar 12, 2025
abe0166
move conda before sct because of conda not found error
naga-karthik Mar 12, 2025
0aabf84
follow same sequence of actions as in manual-correction repo
naga-karthik Mar 12, 2025
f873b84
downgrage python
naga-karthik Mar 12, 2025
0ebfa21
remove shell login cmd
naga-karthik Mar 12, 2025
d81edc2
update scripts to run natively with sct_deepseg
naga-karthik Mar 12, 2025
1f7c937
download model with -custom-url flag
naga-karthik Mar 12, 2025
ca730d2
fix path to the csa computation script
naga-karthik Mar 12, 2025
c72fcff
fix path to the csa computation script
naga-karthik Mar 12, 2025
461bb53
add snippet to copy results after batch process
naga-karthik Mar 12, 2025
f779db9
add snippet to copy results after batch process
naga-karthik Mar 12, 2025
9f7cda5
ensure script returns to CWD
naga-karthik Mar 12, 2025
2ddba5a
update to pass model version as an input arg to run_batch
naga-karthik Mar 12, 2025
6d1d2aa
rest of test subjects
naga-karthik Mar 13, 2025
98e9ecd
add script to just download test data
naga-karthik Mar 13, 2025
9e6ffb3
add list of test subjects as input arg
naga-karthik Mar 13, 2025
caa601b
comment out subjects for debugging
naga-karthik Mar 13, 2025
baf339f
remove PATH_OUT
naga-karthik Mar 14, 2025
cdaa370
update how inputs are received
naga-karthik Mar 14, 2025
840552d
comment out subjects for debugging
naga-karthik Mar 14, 2025
caceeee
comment out other contrasts for debugging
naga-karthik Mar 14, 2025
1d10de1
add script to merge csvs
naga-karthik Mar 14, 2025
ecb91fa
fix folder name
naga-karthik Mar 14, 2025
bdb9b43
add print statements
naga-karthik Mar 15, 2025
9a2b346
fix bugs
naga-karthik Mar 15, 2025
155aaed
add bash script to merge csvs
naga-karthik Mar 15, 2025
658413a
uncomment all subjects
naga-karthik Mar 15, 2025
c7fdd56
merge results of all batches 1-12
naga-karthik Mar 15, 2025
6c01270
run across all contrasts
naga-karthik Mar 15, 2025
31d70d2
test running GHA on release
naga-karthik Mar 16, 2025
3539b8b
merge only 3
naga-karthik Mar 18, 2025
7e9dbc4
debug with 1 contrast
naga-karthik Mar 18, 2025
127b2b2
uncomment all subjects
naga-karthik Mar 18, 2025
69e0a41
merge all batches
naga-karthik Mar 18, 2025
cbca484
add lean script to plot csa across model releases
naga-karthik Mar 19, 2025
7b3c9b9
wrapper bash script for csa drift monitoring plots
naga-karthik Mar 19, 2025
cc62729
minor cleaning; run across all contrasts
naga-karthik Mar 19, 2025
691d9e3
clean script; update docs
naga-karthik Mar 19, 2025
28bedae
uncomment all contrasts
naga-karthik Mar 19, 2025
a2c1ed9
add condition no. of csvs
naga-karthik Mar 19, 2025
080c861
add print statements
naga-karthik Mar 19, 2025
e08922a
debug
naga-karthik Mar 19, 2025
6ca6d33
fix plotting bugs
naga-karthik Mar 20, 2025
b50796c
add color palette
naga-karthik Mar 20, 2025
ba45c75
add color palette
naga-karthik Mar 20, 2025
ac4f69c
Add tmate debugging step
joshuacwnewton Mar 20, 2025
247e3ff
Update PR workflow trigger condition
joshuacwnewton Mar 20, 2025
8b4b316
Test path length theory by `cd ..` before `install_sct`
joshuacwnewton Mar 20, 2025
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
75 changes: 75 additions & 0 deletions .github/workflows/download_dataset.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: Download dataset

on:
push:
branches:
- jn/4813-debug-sct-installer-repo-issues
# release:
# types: [published]

jobs:
run_dataset_download:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install Python 3
uses: actions/setup-python@v4
with:
# python-version: 3.9.16
python-version: 3.8.18

# https://github.com/spinalcordtoolbox/spinalcordtoolbox/blob/master/.ci.sh
- name: Install SCT
run: |
cd .. # avoid long path name by not installing in repo subfolder
# source python/etc/profile.d/conda.sh >> $GITHUB_ENV
git clone https://github.com/spinalcordtoolbox/spinalcordtoolbox.git
cd spinalcordtoolbox
./.ci.sh -i
# NB: install_sct edits ~/.bashrc, but those environment changes don't get passed to subsequent steps in GH Actions.
# So, we filter through the .bashrc and pass the values to $GITHUB_ENV and $GITHUB_PATH.
# Relevant documentation: https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#environment-files
cat ~/.bashrc | grep "export SCT_DIR" | cut -d " " -f 2 >> $GITHUB_ENV
cat ~/.bashrc | grep "export PATH" | grep -o "/.*" | cut -d ':' -f 1 >> $GITHUB_PATH

- name: Install dependencies
run: |
python -m pip install --upgrade pip
# pip install -r requirements.txt

# - name: Set up Python
# uses: actions/setup-python@v4
# with:
# python-version: '3.9.16'

# - name: Install dependencies
# run: |
# conda install -y git-annex

# - name: Ensure git-annex is accessible via git
# run: |
# echo "$(conda info --base)/bin" >> $GITHUB_PATH
# export PATH="$(conda info --base)/bin:$PATH"
# which git-annex
# git-annex version

- name: Configure Git identity
run: |
git config --global user.email "[email protected]"
git config --global user.name "GitHub Actions"

# - name: Run dataset setup script
# shell: bash -l {0} # Ensures the Conda environment is properly loaded
# run: |
# chmod +x scripts/compute_morphometrics_spine_generic.sh
# source scripts/compute_morphometrics_spine_generic.sh

# - name: Run model script
# run: ./scripts/run_model.sh

- name: Setup tmate session
if: ${{ failure() }}
uses: mxschmitt/action-tmate@v3
206 changes: 206 additions & 0 deletions csa_generate_figures/analyse_csa_across_releases.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
"""
Generate violin plots from CSV data across different model releases/versions.

Usage:
python analyse_csa_across_releases.py -i /path/to/data.csv -a [methods, resolutions, thresholds]
"""

import os
import argparse
import pandas as pd
import re
import seaborn as sns
import matplotlib.pyplot as plt
import glob

# Setting the hue order as specified
FONTSIZE = 12
CONTRAST_ORDER = ["DWI", "MTon", "MToff", "T1w", "T2star", "T2w"]


def fetch_participant_id(filename_path):
"""
Get participant_id from the input BIDS-compatible filename or file path
:return: participant_id: subject ID (e.g., sub-001)
"""

_, filename = os.path.split(filename_path) # Get just the filename (i.e., remove the path)
participant = re.search('sub-(.*?)[_/]', filename_path) # [_/] slash or underscore
participant_id = participant.group(0)[:-1] if participant else "" # [:-1] removes the last underscore or slash
# REGEX explanation
# \d - digit
# \d? - no or one occurrence of digit
# *? - match the previous element as few times as possible (zero or more times)
# . - any character

return participant_id


# Function to extract contrast and method from the filename
def extract_contrast_and_details(filename, model_versions):
"""
Extract the segmentation method (e.g., deepseg (2d), v2.0 (monai), v3.0 (nnunet)) from the filename.
"""
# pattern = r'.*_(DWI|MTon|MToff|T1w|T2star|T2w).*_(softseg_bin|deepseg|).*'
pattern = r'.*_(DWI|MTon|MToff|T1w|T2star|T2w).*_(softseg_bin|).*'

# Extract existing values in the second capturing group
match = re.search(r'_\(softseg_bin\|?(.*?)\)\._', pattern) # Extract contents inside (softseg_bin|...)
existing_versions = set(match.group(1).split('|')) if match and match.group(1) else set()

# Merge existing versions with new model versions
updated_versions = existing_versions.union(model_versions)

# Rebuild the pattern, updating only the second capturing group
updated_pattern = re.sub(
r'\(softseg_bin\|?.*?\)', # Match the existing group
f"(softseg_bin|{'|'.join(sorted(updated_versions))})", # Replace with updated group
pattern
)

match = re.search(updated_pattern, filename)
if match:
return match.group(1), match.group(2)
else:
return 'Unknown', 'Unknown'


def generate_figure_csa(file_path, data, method=None):
"""
Generate violinplot showing absolute CSA error for each contrast for a given method/threshold
"""

if method is not None:

# create a dataframe with only the given method and get the mean CSA for each contrast
df = data[data['Method'] == method].groupby(['Contrast', 'Participant'])['MEAN(area)'].agg(['mean']).reset_index()

# define title for the plot
title = f'Method: {method}; CSA across MRI contrasts'

# define save path for the plot
save_fname = f"csa__model_{method}.png"

# plot the abs error for each contrast in a violinplot
plt.figure(figsize=(12, 6))
sns.violinplot(x='Contrast', y='mean', data=df, order=CONTRAST_ORDER, palette="Set2")
# overlay swarm plot on the violin plot to show individual data points
sns.swarmplot(x='Contrast', y='mean', data=df, color='k', order=CONTRAST_ORDER, size=3)
plt.xlabel(None)
plt.ylabel('CSA [mm^2]', fontweight='bold' ,fontsize=FONTSIZE)
plt.title(title)
# Add horizontal dashed grid
plt.grid(axis='y', alpha=0.5, linestyle='dashed')
# set the y-axis limits
plt.ylim(40, 110)
plt.yticks(range(40, 110, 5))

plt.xticks(range(len(CONTRAST_ORDER)), CONTRAST_ORDER, fontsize=FONTSIZE)

# Get y-axis limits
ymin, ymax = plt.gca().get_ylim()

# Compute the mean +- std across resolutions for each method and place it above the corresponding violin
for contrast in CONTRAST_ORDER:
mean = df[df['Contrast'] == contrast]['mean'].mean()
std = df[df['Contrast'] == contrast]['mean'].std()
plt.text(CONTRAST_ORDER.index(contrast), ymax-5, f'{mean:.2f} +- {std:.2f}', ha='center', va='bottom', color='k', fontsize=FONTSIZE)

# Save the figure in 300 DPI as a PNG file
save_path = os.path.join(file_path, save_fname)
plt.savefig(save_path, dpi=300)
print(f'Figure saved to {save_path}')



def generate_figure_std_csa(data, file_path, across="Method", hue_order=None):
"""
Generate violinplot showing STD across participants for each method
"""

# Compute mean and std across contrasts for each method
df = data.groupby([across, 'Participant'])['MEAN(area)'].agg(['mean', 'std']).reset_index()

plt.figure(figsize=(12, 6))
sns.violinplot(x=across, y='std', data=df, order=hue_order, palette="Set2")
# overlay swarm plot on the violin plot to show individual data points
sns.swarmplot(x=across, y='std', data=df, color='k', order=hue_order, size=3)

# Draw vertical line between 1st and 2nd violin
plt.axvline(x=0.5, color='k', linestyle='--')

plt.xlabel(None) # plt.xlabel(across)
plt.ylabel('STD [mm^2]', fontweight='bold' ,fontsize=FONTSIZE)
plt.title(f'STD of C2-C3 CSA for each {across}', fontweight='bold' ,fontsize=FONTSIZE)

XTICKS = [hue_order[0].replace('softseg_bin', 'GT')] + hue_order[1:]
XTICKS = [XTICKS[0]] + [f"model_{version}" for version in XTICKS[1:]]
plt.xticks(range(len(hue_order)), XTICKS, fontsize=FONTSIZE)

# set upper y-axis limits
plt.ylim(-0.5, 8.5)

# Get y-axis limits
ymin, ymax = plt.gca().get_ylim()

# Compute the mean +- std across resolutions for each method and place it above the corresponding violin
for method in df['Method'].unique():
mean = df[df['Method'] == method]['std'].mean()
std = df[df['Method'] == method]['std'].std()
plt.text(hue_order.index(method), ymax-1, f'{mean:.2f} +- {std:.2f}', ha='center', va='bottom', color='k')

# Add horizontal dashed grid
plt.grid(axis='y', alpha=0.5, linestyle='dashed')

# Save the figure in 300 DPI as a PNG file
save_path = os.path.join(file_path, f"std_c2c3_csa_across_versions.png")
plt.savefig(save_path, dpi=300)
print(f'Figure saved to {save_path}')


def main(args):

csvs_list = glob.glob(os.path.join(args.i, "*.csv"))
# sort the list of CSV files
csvs_list.sort()

# assuming 50 models released, we don't want to plot 50 violin plots,
# hence only take the most recent 5 models
csvs_list = csvs_list[-5:]

# of the format: csa_c2c3__model_v2.0.csv, csa_c2c3__model_v3.0.csv
models_to_compare = [os.path.basename(f).split('__')[1].strip('.csv') for f in csvs_list]
model_versions = [model.split('_')[1] for model in models_to_compare]

# define order of the violin plots
hue_order = ['softseg_bin'] + model_versions

# merge the CSV files for each model release
if len(csvs_list) > 1:
data_avg_csa = pd.concat([pd.read_csv(f) for f in csvs_list], ignore_index=True)
else:
data_avg_csa = pd.read_csv(csvs_list[0])

# Apply the function to extract participant ID
data_avg_csa['Participant'] = data_avg_csa['Filename'].apply(fetch_participant_id)

# Apply the function to extract method and the corresponding analysis details
data_avg_csa['Contrast'], data_avg_csa['Method'] = zip(
*data_avg_csa['Filename'].apply(extract_contrast_and_details, model_versions=model_versions))

# Generate violinplot showing STD across participants for each method
generate_figure_std_csa(data_avg_csa, file_path=args.i, across="Method", hue_order=hue_order)

# Generate violinplot showing absolute CSA error for each contrast for a given method/threshold
for method in model_versions:
generate_figure_csa(file_path=args.i, data=data_avg_csa, method=method)


if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Generate violin plot from CSV data.')
parser.add_argument('-i', type=str, required=True,
help='Path to the folder containing CSV files C2-C3 CSA for all releases.'
'Output will be saved in the same folder')

args = parser.parse_args()
main(args)
Loading