Skip to content

Commit 807dd4c

Browse files
authored
Merge branch 'main' into test-results-file
2 parents 533411d + cf667d9 commit 807dd4c

File tree

8 files changed

+1196
-14
lines changed

8 files changed

+1196
-14
lines changed

.github/workflows/website.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,15 @@ jobs:
5050
run: |
5151
pytest tests/IVIMmodels/unit_tests/test_ivim_fit.py
5252
53+
- name: 'Filter and compress results file.'
54+
run: python utilities/reduce_output_size.py test_output.csv test_output.csv.gz
55+
5356
- name: move data to the dashboard folder
5457
run: |
55-
mv test_output.csv website/dashboard
58+
mv test_output.csv.gz website/dashboard
5659
mv test_results_report.json website/dashboard
5760
61+
5862
- name: Build documentation
5963
run: |
6064
mkdir docs/_static

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ __pycache__/
1010
*.raw
1111
bvals.txt
1212
download
13+
.Introduction_to_TF24_IVIM-MRI_CodeCollection_github_and_IVIM_Analysis_using_Python.ipynb
14+
.ipynb_checkpoints
1315
md5sums.txt
1416
*.gz
1517
*.zip

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ The ISMRM Open Science Initiative for Perfusion Imaging (OSIPI) is an initiative
66
77
This **IVIM code collection** code library is maintained by OSIPI [Taskforce 2.4](https://www.osipi.org/task-force-2-4/) (*currently not available*) and aims to collect, test and share open-source code related to intravoxel incoherent motion (IVIM) analysis of diffusion encoded MRI data to be used in research and software development. Code contributions can include any code related IVIM analysis (denoising, motion correction, model fitting, etc.), but at an initial phase, development of tests and other features of the repository will predominantly focus on fitting algorithms. A goal of the IVIM OSIPI task force is to develop a fully tested and harmonized code library, building upon the contributions obtained through this initiative. Documentation and analysis are available on the [OSIPI TF2.4](https://osipi.github.io/TF2.4_IVIM-MRI_CodeCollection/).
88

9+
We have some useful tools and further documentation on https://osipi.github.io/TF2.4_IVIM-MRI_CodeCollection/.
10+
911
## How to contribute
1012

1113
If you would like to get involve in OSIPI and work within the task force, please email the contacts listed on our website.
@@ -17,6 +19,9 @@ If you would like to contribute with code, please follow the instructions below:
1719
* [Guidelines for IVIM code contribution](doc/guidelines_for_contributions.md)
1820
* [Guidelines to creating a test file](doc/creating_test.md)
1921

22+
If you would like to use code from the repository and/or are new to Github or IVIM, please see the jupyter notebook below:
23+
* [Introduction to TF2.4_IVIM-MRI_CodeCollection github and IVIM Analysis using Python](doc/Introduction_to_TF24_IVIM-MRI_CodeCollection_github_and_IVIM_Analysis_using_Python.ipynb)
24+
2025
## Repository Organization
2126

2227
The repository is organized in four main folders along with configuration files for automated testing.

doc/Introduction_to_TF24_IVIM-MRI_CodeCollection_github_and_IVIM_Analysis_using_Python.ipynb

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

src/wrappers/OsipiBase.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from scipy.stats import norm
44
import pathlib
55
import sys
6+
from tqdm import tqdm
67

78
class OsipiBase:
89
"""The base class for OSIPI IVIM fitting"""
@@ -47,7 +48,7 @@ def initialize(**kwargs):
4748
pass
4849

4950
#def osipi_fit(self, data=None, bvalues=None, thresholds=None, bounds=None, initial_guess=None, **kwargs):
50-
def osipi_fit(self, data, bvalues, **kwargs):
51+
def osipi_fit(self, data, bvalues=None, **kwargs):
5152
"""Fits the data with the bvalues
5253
Returns [S0, f, Dstar, D]
5354
"""
@@ -68,7 +69,6 @@ def osipi_fit(self, data, bvalues, **kwargs):
6869
#kwargs["bvalues"] = use_bvalues
6970

7071
#args = [data, use_bvalues, use_thresholds]
71-
args = [data, use_bvalues]
7272
#if self.required_bounds or self.required_bounds_optional:
7373
#args.append(use_bounds)
7474
#if self.required_initial_guess or self.required_initial_guess_optional:
@@ -83,7 +83,13 @@ def osipi_fit(self, data, bvalues, **kwargs):
8383

8484
#args = [data, use_bvalues, use_initial_guess, use_bounds, use_thresholds]
8585
#args = [arg for arg in args if arg is not None]
86-
results = self.ivim_fit(*args, **kwargs)
86+
87+
# Assuming the last dimension of the data is the signal values of each b-value
88+
results = np.empty(list(data.shape[:-1])+[3]) # Create an array with the voxel dimensions + the ones required for the fit
89+
for ijk in tqdm(np.ndindex(data.shape[:-1]), total=np.prod(data.shape[:-1])):
90+
args = [data[ijk], use_bvalues]
91+
fit = list(self.ivim_fit(*args, **kwargs))
92+
results[ijk] = fit
8793

8894
#self.parameter_estimates = self.ivim_fit(data, bvalues)
8995
return results

utilities/reduce_output_size.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import os
2+
import gzip
3+
import csv
4+
import sys
5+
6+
def reduce_output_file_size(input_file:str, output_file:str):
7+
"""
8+
Simplify the data generated by the analysis pipeline by retaining only the essential information required for the frontend.
9+
"""
10+
if os.path.exists(input_file):
11+
# Open the input and output files
12+
with open(input_file, 'r') as infile, gzip.open(output_file, 'wt', newline='') as outfile:
13+
reader = csv.DictReader(infile)
14+
15+
# Drop b_values columns
16+
fieldnames = [field for field in reader.fieldnames if not field.startswith('bval_')]
17+
writer = csv.DictWriter(outfile, fieldnames=fieldnames)
18+
writer.writeheader()
19+
20+
columns_to_round = ['f', 'Dp', 'D', 'f_fitted', 'Dp_fitted', 'D_fitted']
21+
22+
for row in reader:
23+
#Delete columns starting with 'bval_'
24+
for key in list(row.keys()):
25+
if key.startswith('bval_'):
26+
del row[key]
27+
28+
# Round values in the remaining relevant columns
29+
for column in columns_to_round:
30+
if column in row:
31+
row[column] = round(float(row[column]), 4)
32+
writer.writerow(row)
33+
else:
34+
print(f"File '{input_file}' not found.")
35+
36+
if __name__ == '__main__':
37+
if len(sys.argv) != 3:
38+
print("Usage: python reduce_output_size.py <input_file> <output_file>")
39+
sys.exit(1)
40+
41+
input_file = sys.argv[1]
42+
output_file = sys.argv[2]
43+
reduce_output_file_size(input_file, output_file)

website/dashboard/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js"></script>
99
<script src="https://cdn.plot.ly/plotly-2.30.0.min.js"></script>
1010
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.3.0/papaparse.min.js"></script>
11+
<script src="https://cdn.jsdelivr.net/npm/pako@1.0.11/dist/pako.min.js"></script>
1112
<script src="index.js"></script>
1213
<script src="test_plots.js"></script>
1314
<link rel="stylesheet" href="index.css">

website/dashboard/index.js

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -205,17 +205,31 @@ document.addEventListener('DOMContentLoaded', function() {
205205

206206
showLoading();
207207

208-
Papa.parse('test_output.csv', {
209-
download: true,
210-
header: true,
211-
complete: results => {
212-
data = results;
213-
hideLoading();
214-
populateOptions(data);
215-
drawBoxPlot();
216-
drawRegionBoxPlot();
217-
208+
fetch('test_output.csv.gz')
209+
.then(response => {
210+
if (!response.ok) {
211+
throw new Error('Network response was not ok');
218212
}
213+
return response.arrayBuffer();
214+
})
215+
.then(buffer => {
216+
// Use pako to decompress the data
217+
var decompressed = pako.inflate(new Uint8Array(buffer), { to: 'string' });
218+
// Now use Papa Parse to parse the decompressed CSV data
219+
Papa.parse(decompressed, {
220+
header: true,
221+
complete: results => {
222+
console.log(results);
223+
data = results;
224+
hideLoading();
225+
populateOptions(data);
226+
drawBoxPlot();
227+
drawRegionBoxPlot();
228+
}
229+
});
230+
})
231+
.catch(error => {
232+
console.error('There has been a problem with your fetch operation:', error);
219233
});
220234

221235
function populateOptions(data) {

0 commit comments

Comments
 (0)