Skip to content

Commit 5b47b18

Browse files
committed
Initial commit
0 parents  commit 5b47b18

File tree

10 files changed

+824
-0
lines changed

10 files changed

+824
-0
lines changed

.github/workflows/publish.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
on:
2+
push:
3+
branches: [main]
4+
workflow_dispatch:
5+
6+
name: Render and publish
7+
8+
jobs:
9+
build-deploy:
10+
runs-on: ubuntu-latest
11+
permissions:
12+
contents: write
13+
steps:
14+
- name: Check out repository
15+
uses: actions/checkout@v4
16+
17+
- name: Set up Quarto
18+
uses: quarto-dev/quarto-actions/setup@v2
19+
20+
- name: Render and publish to GitHub Pages
21+
uses: quarto-dev/quarto-actions/publish@v2
22+
with:
23+
target: gh-pages
24+
env:
25+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Quarto build outputs
2+
_site/
3+
.quarto/
4+
**/*.quarto_ipynb
5+
6+
# Large neuroimaging data (not tracked — download separately)
7+
*.tck
8+
*.trx
9+
*.mif
10+
*.mif.gz
11+
*.nii.gz
12+
13+
# Generated pipeline outputs
14+
*.csv
15+
*.tsf
16+
walkthrough/*_nodes.txt
17+
walkthrough/*_mean.txt
18+
tmp_*
19+
20+
# Logs
21+
render.log

_freeze/site_libs/clipboard/clipboard.min.js

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

_freeze/walkthrough/execute-results/html.json

Lines changed: 15 additions & 0 deletions
Large diffs are not rendered by default.

_quarto.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
project:
2+
type: website
3+
output-dir: _site
4+
5+
website:
6+
title: "TRX Tractography: A Better Way"
7+
navbar:
8+
left:
9+
- href: index.qmd
10+
text: Home
11+
- href: walkthrough.qmd
12+
text: Walkthrough
13+
page-footer:
14+
center: "Built with [Quarto](https://quarto.org)"
15+
16+
format:
17+
html:
18+
theme: cosmo
19+
code-tools: true
20+
code-copy: true
21+
toc: true
22+
toc-depth: 3
23+
toc-location: right
24+
anchor-sections: true
25+
smooth-scroll: true
26+
highlight-style: monokai
27+
css: styles.css
28+
grid:
29+
sidebar-width: 0px
30+
body-width: 1050px
31+
margin-width: 220px

connectome_comparison.png

610 KB
Loading

index.qmd

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
---
2+
title: "TRX Tractography in MRtrix3"
3+
subtitle: "A self-contained, reproducible tractography workflow"
4+
---
5+
6+
## Why TRX?
7+
8+
A typical MRtrix3 tractography pipeline for one subject produces **at least six separate files** that must travel together:
9+
10+
```
11+
tracks.tck ← 5–15 GB geometry
12+
sift2_weights.csv ← per-streamline weights
13+
assignments.txt ← node-pair labels (tck2connectome)
14+
connectome.csv ← connectivity matrix
15+
node_names.txt ← atlas label list
16+
exemplar_bundles.zip ← optional
17+
```
18+
19+
Lose or misplace one, and downstream analyses break silently — wrong weights get applied, the connectome is recomputed without normalisation, or the wrong atlas is used.
20+
21+
**[TRX](https://github.com/tee-ar-ex/trx-spec)** (Tractography Exchange) is a container format that stores geometry, per-streamline data (dps), per-vertex data (dpv), and group memberships together in a single zip file. This walkthrough demonstrates a complete tractography pipeline run two ways — classic TCK-based and TRX-based — on the same HCP subject, showing that the outputs are numerically identical while the TRX pipeline requires fewer files and fewer commands.
22+
23+
## What you'll see
24+
25+
| Step | Classic pipeline | TRX pipeline |
26+
|------|-----------------|--------------|
27+
| Generate streamlines | `tckgen → tracks.tck` | `tckgen → tracks.trx` |
28+
| SIFT2 weighting | `tcksift2 → weights.csv` | `tcksift2 -trx_dps → (embedded)` |
29+
| Atlas labeling | `tck2connectome -out_assignment` | `trxlabel → (groups embedded)` |
30+
| Connectome | `tck2connectome` | `trx2connectome` |
31+
| Inspect state | `ls *.tck *.csv *.txt` | `tckinfo tracks.trx` |
32+
33+
The TRX file grows as each step adds metadata; `tckinfo` at each stage reveals its evolving contents.
34+
35+
## Data
36+
37+
Subject **sub-100307** from the HCP Young Adult dataset, processed through
38+
[QSIRecon](https://qsirecon.readthedocs.io)'s `mrtrix_multishell_msmt_hsvs` pipeline.
39+
Starting inputs:
40+
41+
- WM FOD (msmt-CSD, max SH order 8)
42+
- Brain mask (mtnormalize inlier mask)
43+
- Glasser 360-region atlas (registered to T1w space)
44+
45+
[Start the walkthrough](walkthrough.qmd)

styles.css

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/* ── Inline code (prose `backtick` spans) ────────────────────── */
2+
:not(pre) > code {
3+
background: #2d2d2d;
4+
color: #e8e8e8;
5+
padding: 0.1em 0.35em;
6+
border-radius: 3px;
7+
font-size: 0.88em;
8+
}
9+
10+
/* ── Terminal / command output blocks ─────────────────────────── */
11+
pre.sourceCode.bash, pre.sourceCode.sh {
12+
background: #1e1e1e;
13+
color: #d4d4d4;
14+
border-left: 3px solid #569cd6;
15+
}
16+
17+
/* Highlight the output blocks differently from code */
18+
.cell-output pre {
19+
background: #0d1117;
20+
color: #c9d1d9;
21+
border-left: 3px solid #3fb950;
22+
font-size: 0.85em;
23+
}
24+
25+
/* Column layout breathing room */
26+
.columns {
27+
gap: 1.5rem;
28+
}
29+
30+
/* Step headers */
31+
h2 {
32+
border-bottom: 2px solid #dee2e6;
33+
padding-bottom: 0.3em;
34+
margin-top: 2.5rem;
35+
}
36+
37+
/* File-inventory table */
38+
.file-table {
39+
font-family: var(--bs-font-monospace);
40+
font-size: 0.85em;
41+
}
42+
43+
/* Workflow comparison badges */
44+
.badge-classic {
45+
background: #6c757d;
46+
color: white;
47+
padding: 0.2em 0.6em;
48+
border-radius: 4px;
49+
font-size: 0.8em;
50+
font-weight: bold;
51+
}
52+
.badge-trx {
53+
background: #0d6efd;
54+
color: white;
55+
padding: 0.2em 0.6em;
56+
border-radius: 4px;
57+
font-size: 0.8em;
58+
font-weight: bold;
59+
}
60+
61+
/* tckinfo output box */
62+
.tckinfo-box {
63+
background: #0d1117;
64+
color: #c9d1d9;
65+
padding: 1rem 1.2rem;
66+
border-radius: 6px;
67+
border-left: 4px solid #58a6ff;
68+
font-family: var(--bs-font-monospace);
69+
font-size: 0.82em;
70+
overflow-x: auto;
71+
white-space: pre;
72+
}
73+
.tckinfo-box .highlight {
74+
color: #ffa657;
75+
font-weight: bold;
76+
}

timing_utils.sh

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#!/usr/bin/env bash
2+
# timing_utils.sh — source this file before running the walkthrough
3+
#
4+
# Provides mtime(): runs a command, shows its stderr live in the chunk output,
5+
# then appends a one-line timing + memory summary.
6+
#
7+
# How the stderr separation works:
8+
# /usr/bin/time -l writes its timing block to stderr AFTER the command exits.
9+
# The command's own progress output also goes to stderr. Both land in $tmp.
10+
# We locate the timing block by finding the last line matching
11+
# "^ *[0-9.]+ real " (the first line of /usr/bin/time -l output), forward
12+
# every line before that as the command's stderr, then parse the timing block.
13+
#
14+
# Memory metric: "peak memory footprint" (phys_footprint from TASK_VM_INFO).
15+
# Excludes clean read-only mmap pages, so TRX files are not counted twice.
16+
# RSS ("maximum resident set size") would be inflated for TRX inputs.
17+
#
18+
# Linux: replace -l with -v; the footprint grep becomes:
19+
# awk '/Maximum resident/{print $NF * 1024}' "$tmp"
20+
21+
mtime() {
22+
local label="$1"; shift
23+
local tmp; tmp=$(mktemp)
24+
25+
/usr/bin/time -l "$@" 2>"$tmp"
26+
local exit_code=$?
27+
28+
# Find where /usr/bin/time's own output starts.
29+
# Its first line always matches "^ *[0-9.]+ real " (BSD time format).
30+
local timing_line
31+
timing_line=$(grep -n "^[[:space:]]*[0-9.]\+ real " "$tmp" \
32+
| tail -1 | cut -d: -f1)
33+
34+
if [ -n "$timing_line" ] && [ "$timing_line" -gt 1 ]; then
35+
# Replay the command's stderr (lines before the timing block)
36+
head -n "$((timing_line - 1))" "$tmp"
37+
fi
38+
39+
if [ -z "$timing_line" ]; then
40+
# /usr/bin/time didn't produce output — command likely failed
41+
cat "$tmp"
42+
rm -f "$tmp"
43+
return "$exit_code"
44+
fi
45+
46+
# Parse wall / user / sys from the timing line
47+
local wall user sys
48+
read -r wall _ user _ sys _ \
49+
< <(sed -n "${timing_line}p" "$tmp")
50+
51+
# Parse physical footprint (excludes clean mmap pages)
52+
local fp_bytes fp_gb
53+
fp_bytes=$(tail -n "+${timing_line}" "$tmp" \
54+
| awk '/peak memory footprint/{print $1}')
55+
fp_gb=$(awk "BEGIN {printf \"%.2f\", ${fp_bytes:-0} / 1073741824}")
56+
57+
printf "\n┌─ %-28s ─────────────────────────────────────────────┐\n" "$label"
58+
printf "│ wall: %8ss user: %8ss sys: %6ss peak mem: %5s GB │\n" \
59+
"$wall" "$user" "$sys" "$fp_gb"
60+
printf "└────────────────────────────────────────────────────────────────────────────┘\n\n"
61+
62+
rm -f "$tmp"
63+
return "$exit_code"
64+
}

0 commit comments

Comments
 (0)