bids-mosaic 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bids_mosaic-0.0.1/LICENSE.txt +21 -0
- bids_mosaic-0.0.1/PKG-INFO +46 -0
- bids_mosaic-0.0.1/README.md +23 -0
- bids_mosaic-0.0.1/bids_mosaic.egg-info/PKG-INFO +46 -0
- bids_mosaic-0.0.1/bids_mosaic.egg-info/SOURCES.txt +11 -0
- bids_mosaic-0.0.1/bids_mosaic.egg-info/dependency_links.txt +1 -0
- bids_mosaic-0.0.1/bids_mosaic.egg-info/entry_points.txt +2 -0
- bids_mosaic-0.0.1/bids_mosaic.egg-info/requires.txt +7 -0
- bids_mosaic-0.0.1/bids_mosaic.egg-info/top_level.txt +1 -0
- bids_mosaic-0.0.1/bidsmosaic/__init__.py +0 -0
- bids_mosaic-0.0.1/bidsmosaic/mosaic.py +365 -0
- bids_mosaic-0.0.1/pyproject.toml +38 -0
- bids_mosaic-0.0.1/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 - present Joseph Wexler
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bids-mosaic
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A BIDS tool for creating PDFs containing slices of nifti images
|
|
5
|
+
Author-email: Joseph Wexler <jbwexler@stanford.edu>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Source, https://github.com/jbwexler/bids-mosaic
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Programming Language :: Python
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE.txt
|
|
15
|
+
Requires-Dist: numpy>=1.24.0
|
|
16
|
+
Requires-Dist: pybids>=0.16.0
|
|
17
|
+
Requires-Dist: nilearn>=0.10.0
|
|
18
|
+
Requires-Dist: nibabel>=5.0.0
|
|
19
|
+
Requires-Dist: reportlab>=3.6.12
|
|
20
|
+
Requires-Dist: pillow>=9.3.0
|
|
21
|
+
Requires-Dist: matplotlib>=3.7.0
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
## BIDS-Mosaic
|
|
25
|
+
A BIDS tool for creating PDFs containing slices of nifti images
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
```
|
|
29
|
+
pip install bidsmosaic
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
```
|
|
34
|
+
bids-mosiac <bids_dataset_directory>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
For more options:
|
|
38
|
+
```
|
|
39
|
+
bids-mosaic --help
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Example
|
|
43
|
+

|
|
44
|
+
|
|
45
|
+
## License
|
|
46
|
+
BIDS-Mosaic is licensed under [MIT license](LICENSE.txt).
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
## BIDS-Mosaic
|
|
2
|
+
A BIDS tool for creating PDFs containing slices of nifti images
|
|
3
|
+
|
|
4
|
+
## Installation
|
|
5
|
+
```
|
|
6
|
+
pip install bidsmosaic
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
```
|
|
11
|
+
bids-mosiac <bids_dataset_directory>
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
For more options:
|
|
15
|
+
```
|
|
16
|
+
bids-mosaic --help
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Example
|
|
20
|
+

|
|
21
|
+
|
|
22
|
+
## License
|
|
23
|
+
BIDS-Mosaic is licensed under [MIT license](LICENSE.txt).
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bids-mosaic
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A BIDS tool for creating PDFs containing slices of nifti images
|
|
5
|
+
Author-email: Joseph Wexler <jbwexler@stanford.edu>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Source, https://github.com/jbwexler/bids-mosaic
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Programming Language :: Python
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE.txt
|
|
15
|
+
Requires-Dist: numpy>=1.24.0
|
|
16
|
+
Requires-Dist: pybids>=0.16.0
|
|
17
|
+
Requires-Dist: nilearn>=0.10.0
|
|
18
|
+
Requires-Dist: nibabel>=5.0.0
|
|
19
|
+
Requires-Dist: reportlab>=3.6.12
|
|
20
|
+
Requires-Dist: pillow>=9.3.0
|
|
21
|
+
Requires-Dist: matplotlib>=3.7.0
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
## BIDS-Mosaic
|
|
25
|
+
A BIDS tool for creating PDFs containing slices of nifti images
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
```
|
|
29
|
+
pip install bidsmosaic
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
```
|
|
34
|
+
bids-mosiac <bids_dataset_directory>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
For more options:
|
|
38
|
+
```
|
|
39
|
+
bids-mosaic --help
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Example
|
|
43
|
+

|
|
44
|
+
|
|
45
|
+
## License
|
|
46
|
+
BIDS-Mosaic is licensed under [MIT license](LICENSE.txt).
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
LICENSE.txt
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
bids_mosaic.egg-info/PKG-INFO
|
|
5
|
+
bids_mosaic.egg-info/SOURCES.txt
|
|
6
|
+
bids_mosaic.egg-info/dependency_links.txt
|
|
7
|
+
bids_mosaic.egg-info/entry_points.txt
|
|
8
|
+
bids_mosaic.egg-info/requires.txt
|
|
9
|
+
bids_mosaic.egg-info/top_level.txt
|
|
10
|
+
bidsmosaic/__init__.py
|
|
11
|
+
bidsmosaic/mosaic.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
bidsmosaic
|
|
File without changes
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import argparse
|
|
3
|
+
import os.path
|
|
4
|
+
import glob
|
|
5
|
+
import tempfile
|
|
6
|
+
import json
|
|
7
|
+
import logging
|
|
8
|
+
import PIL.Image
|
|
9
|
+
from bids import BIDSLayout
|
|
10
|
+
from nilearn.plotting import plot_img
|
|
11
|
+
import matplotlib.pyplot as plt
|
|
12
|
+
import nibabel as nb
|
|
13
|
+
from reportlab.platypus import (
|
|
14
|
+
Paragraph,
|
|
15
|
+
Image,
|
|
16
|
+
Table,
|
|
17
|
+
SimpleDocTemplate,
|
|
18
|
+
PageBreak,
|
|
19
|
+
TableStyle,
|
|
20
|
+
Spacer,
|
|
21
|
+
)
|
|
22
|
+
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
|
23
|
+
from reportlab.lib import colors
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def enhance_brightness(
|
|
30
|
+
img: PIL.Image, target_brightness=100, threshold=10
|
|
31
|
+
) -> PIL.Image:
|
|
32
|
+
"""Attempts to change the brightness of an image to the target brightness."""
|
|
33
|
+
arr = np.array(img, dtype="float32")
|
|
34
|
+
mask = arr > threshold
|
|
35
|
+
rms = np.sqrt(np.mean(np.square(arr[mask])))
|
|
36
|
+
brightness_factor = target_brightness / rms
|
|
37
|
+
arr[mask] *= brightness_factor
|
|
38
|
+
return PIL.Image.fromarray(arr).convert("L")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def create_slice_img(
|
|
42
|
+
img_path: str,
|
|
43
|
+
out_dir: str,
|
|
44
|
+
ds_path: str,
|
|
45
|
+
display_mode="x",
|
|
46
|
+
cut_coords=np.array([0]),
|
|
47
|
+
colorbar=False,
|
|
48
|
+
ds_root=None,
|
|
49
|
+
downsample=None,
|
|
50
|
+
) -> None:
|
|
51
|
+
"""Creates a png of a slice(s) of a nifti. Defaults to a single midline
|
|
52
|
+
sagittal slice."""
|
|
53
|
+
|
|
54
|
+
logger.debug(f"Creating png from {img_path}")
|
|
55
|
+
try:
|
|
56
|
+
img = nb.load(img_path)
|
|
57
|
+
except FileNotFoundError:
|
|
58
|
+
logger.warning("%s was not found." % img_path)
|
|
59
|
+
return
|
|
60
|
+
|
|
61
|
+
if ds_root:
|
|
62
|
+
relpath = os.path.relpath(img_path, ds_path)
|
|
63
|
+
out_file = relpath.replace("/", ":") + ".png"
|
|
64
|
+
else:
|
|
65
|
+
out_file = os.path.basename(img_path) + ".png"
|
|
66
|
+
|
|
67
|
+
out_path = os.path.join(out_dir, out_file)
|
|
68
|
+
|
|
69
|
+
plot_img(
|
|
70
|
+
img,
|
|
71
|
+
display_mode=display_mode,
|
|
72
|
+
cut_coords=cut_coords,
|
|
73
|
+
colorbar=colorbar,
|
|
74
|
+
annotate=False,
|
|
75
|
+
)
|
|
76
|
+
plt.savefig(out_path, transparent=True)
|
|
77
|
+
plt.close()
|
|
78
|
+
|
|
79
|
+
# Remove transparent margins
|
|
80
|
+
png = PIL.Image.open(out_path)
|
|
81
|
+
new_png = png.crop(png.getbbox()).convert("L")
|
|
82
|
+
|
|
83
|
+
if downsample:
|
|
84
|
+
height, width = new_png.size
|
|
85
|
+
new_size = (round(height / downsample), round(width / downsample))
|
|
86
|
+
new_png = new_png.resize(new_size)
|
|
87
|
+
|
|
88
|
+
new_png = enhance_brightness(new_png)
|
|
89
|
+
|
|
90
|
+
new_png.save(out_path)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def create_sized_img(img_path: str, new_height: int) -> Image:
|
|
94
|
+
"""Creates a reportlab Image from a .png. Resizes using new_height
|
|
95
|
+
and calculating new_width to maintain aspect ratio."""
|
|
96
|
+
img = PIL.Image.open(img_path)
|
|
97
|
+
width, height = img.size
|
|
98
|
+
new_width = (new_height / height) * width
|
|
99
|
+
return Image(img_path, height=new_height, width=new_width)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def create_filename_caption(img_path: str) -> Paragraph:
|
|
103
|
+
"""Creates a reportlab Paragraph containing the filename of the image."""
|
|
104
|
+
caption_text = os.path.basename(img_path)
|
|
105
|
+
caption_text = caption_text.replace(":", "/")
|
|
106
|
+
caption_text = os.path.relpath(caption_text)
|
|
107
|
+
caption_text = caption_text.removesuffix(".png")
|
|
108
|
+
return caption_text
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def create_mosaic_table(img_dir_path: str, page_width: int, styles) -> Table:
|
|
112
|
+
"""Creates reportlab Table of slice images with image-name captions."""
|
|
113
|
+
img_height = 80
|
|
114
|
+
caption_style = ParagraphStyle(
|
|
115
|
+
"Caption",
|
|
116
|
+
parent=styles["Normal"],
|
|
117
|
+
fontSize=6,
|
|
118
|
+
leading=6,
|
|
119
|
+
textColor=colors.black,
|
|
120
|
+
alignment="CENTER",
|
|
121
|
+
leftIndent=0,
|
|
122
|
+
rightIndent=0,
|
|
123
|
+
spaceAfter=0,
|
|
124
|
+
spaceBefore=0,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
image_path_list = sorted(glob.glob(img_dir_path + "/*"))
|
|
128
|
+
|
|
129
|
+
if not image_path_list:
|
|
130
|
+
logger.error(f"No images found in {img_dir_path}")
|
|
131
|
+
return
|
|
132
|
+
|
|
133
|
+
table_data = [
|
|
134
|
+
[
|
|
135
|
+
create_sized_img(img_path, img_height),
|
|
136
|
+
Paragraph(
|
|
137
|
+
f"<para align=center spaceb=3>{create_filename_caption(img_path)}</para>",
|
|
138
|
+
caption_style,
|
|
139
|
+
),
|
|
140
|
+
]
|
|
141
|
+
for img_path in image_path_list
|
|
142
|
+
]
|
|
143
|
+
img_width = table_data[0][0]._width
|
|
144
|
+
num_col = int(page_width / img_width)
|
|
145
|
+
col_width = int(page_width / num_col)
|
|
146
|
+
|
|
147
|
+
table_data_rows = [
|
|
148
|
+
table_data[i : i + num_col] for i in range(0, len(image_path_list), num_col)
|
|
149
|
+
]
|
|
150
|
+
|
|
151
|
+
table_style = TableStyle(
|
|
152
|
+
[
|
|
153
|
+
("ALIGN", (0, 0), (-1, -1), "CENTER"),
|
|
154
|
+
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
|
|
155
|
+
("LEFTPADDING", (0, 0), (-1, -1), 2),
|
|
156
|
+
("RIGHTPADDING", (0, 0), (-1, -1), 2),
|
|
157
|
+
("TOPPADDING", (0, 0), (-1, -1), 2),
|
|
158
|
+
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
|
|
159
|
+
("INNERGRID", (0, 0), (-1, -1), 0.25, colors.grey),
|
|
160
|
+
("BOX", (0, 0), (-1, -1), 0.25, colors.black),
|
|
161
|
+
]
|
|
162
|
+
)
|
|
163
|
+
table = Table(table_data_rows, colWidths=col_width)
|
|
164
|
+
table.setStyle(table_style)
|
|
165
|
+
|
|
166
|
+
return table
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def create_metadata_table(metadata: str) -> Table:
|
|
170
|
+
"""Creates a reportlab Table containing user-inputted metadata."""
|
|
171
|
+
metadata_dict = json.loads(metadata)
|
|
172
|
+
metadata_list = list(metadata_dict.items())
|
|
173
|
+
|
|
174
|
+
table_style = TableStyle(
|
|
175
|
+
[
|
|
176
|
+
("ALIGN", (0, 0), (-1, -1), "CENTER"),
|
|
177
|
+
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
|
|
178
|
+
("LEFTPADDING", (0, 0), (-1, -1), 5),
|
|
179
|
+
("RIGHTPADDING", (0, 0), (-1, -1), 5),
|
|
180
|
+
("TOPPADDING", (0, 0), (-1, -1), 5),
|
|
181
|
+
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
|
|
182
|
+
("INNERGRID", (0, 0), (-1, -1), 0.25, colors.grey),
|
|
183
|
+
("BOX", (0, 0), (-1, -1), 0.25, colors.black),
|
|
184
|
+
]
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
table = Table(metadata_list)
|
|
188
|
+
table.setStyle(table_style)
|
|
189
|
+
|
|
190
|
+
return table
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def create_pdf(img_dir_path: str, out_path: str, metadata=None) -> None:
|
|
194
|
+
"""Creates a pdf containing images aligned in a grid"""
|
|
195
|
+
styles = getSampleStyleSheet()
|
|
196
|
+
pdf = SimpleDocTemplate(
|
|
197
|
+
out_path,
|
|
198
|
+
leftMargin=18,
|
|
199
|
+
rightMargin=18,
|
|
200
|
+
topMargin=36,
|
|
201
|
+
bottomMargin=36,
|
|
202
|
+
)
|
|
203
|
+
page_width = int(pdf.width)
|
|
204
|
+
|
|
205
|
+
flowables = []
|
|
206
|
+
|
|
207
|
+
for d in glob.glob(os.path.join(img_dir_path, "*")):
|
|
208
|
+
title_text = os.path.basename(d) + " Images"
|
|
209
|
+
title = Paragraph(title_text, styles["Title"])
|
|
210
|
+
flowables.append(title)
|
|
211
|
+
flowables.append(Spacer(0, 15))
|
|
212
|
+
|
|
213
|
+
mosaic_table = create_mosaic_table(d, page_width, styles)
|
|
214
|
+
flowables.append(mosaic_table)
|
|
215
|
+
|
|
216
|
+
flowables.append(PageBreak())
|
|
217
|
+
|
|
218
|
+
if metadata:
|
|
219
|
+
title = Paragraph("Metadata", styles["Title"])
|
|
220
|
+
flowables.append(title)
|
|
221
|
+
flowables.append(Spacer(0, 15))
|
|
222
|
+
|
|
223
|
+
metadata_table = create_metadata_table(metadata)
|
|
224
|
+
flowables.append(metadata_table)
|
|
225
|
+
|
|
226
|
+
pdf.build(flowables)
|
|
227
|
+
|
|
228
|
+
logger.info("Successfully created pdf")
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def create_anat_images(layout: BIDSLayout, png_dir: str, downsample=None) -> None:
|
|
232
|
+
"""Creates anatomical mosaic .png files."""
|
|
233
|
+
anat_layout_kwargs = {
|
|
234
|
+
"datatype": "anat",
|
|
235
|
+
"extension": ["nii", "nii.gz"],
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
files = layout.get(**anat_layout_kwargs)
|
|
239
|
+
anat_png_dir = os.path.join(png_dir, "Anatomical")
|
|
240
|
+
os.makedirs(anat_png_dir, exist_ok=True)
|
|
241
|
+
|
|
242
|
+
for file in files:
|
|
243
|
+
create_slice_img(file.path, anat_png_dir, layout.root, downsample=downsample)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def create_fs_images(fs_dir: str, png_dir: str, downsample=None) -> None:
|
|
247
|
+
"""Creates freesurfer mosaic .png files."""
|
|
248
|
+
fs_png_dir = os.path.join(png_dir, "Freesurfer")
|
|
249
|
+
os.makedirs(fs_png_dir, exist_ok=True)
|
|
250
|
+
|
|
251
|
+
for file_path in glob.glob(os.path.join(fs_dir, "sub-*/mri/orig/*")):
|
|
252
|
+
create_slice_img(
|
|
253
|
+
file_path, fs_png_dir, fs_dir, ds_root=fs_dir, downsample=downsample
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def create_mosaic_pdf(
|
|
258
|
+
dataset: str,
|
|
259
|
+
out_file: str,
|
|
260
|
+
anat=True,
|
|
261
|
+
png_out_dir=None,
|
|
262
|
+
downsample=None,
|
|
263
|
+
freesurfer=None,
|
|
264
|
+
metadata=None,
|
|
265
|
+
) -> None:
|
|
266
|
+
"""Creates a mosaic pdf."""
|
|
267
|
+
if png_out_dir:
|
|
268
|
+
png_dir = png_out_dir
|
|
269
|
+
else:
|
|
270
|
+
temp_dir_obj = tempfile.TemporaryDirectory()
|
|
271
|
+
png_dir = temp_dir_obj.name
|
|
272
|
+
|
|
273
|
+
layout = BIDSLayout(dataset, validate=False)
|
|
274
|
+
|
|
275
|
+
if anat:
|
|
276
|
+
logger.info(f"Creating anat images in {png_dir}")
|
|
277
|
+
create_anat_images(layout, png_dir, downsample=downsample)
|
|
278
|
+
if freesurfer:
|
|
279
|
+
logger.info(f"Creating freesurfer images in {png_dir}")
|
|
280
|
+
create_fs_images(freesurfer, png_dir, downsample=downsample)
|
|
281
|
+
|
|
282
|
+
logger.info(f"Creating pdf at {out_file}")
|
|
283
|
+
create_pdf(png_dir, out_file, metadata)
|
|
284
|
+
|
|
285
|
+
if not png_out_dir:
|
|
286
|
+
temp_dir_obj.cleanup()
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def main():
|
|
290
|
+
logging.basicConfig(level=logging.INFO)
|
|
291
|
+
|
|
292
|
+
parser = argparse.ArgumentParser()
|
|
293
|
+
parser.add_argument("dataset", type=str, help="Path to dataset")
|
|
294
|
+
parser.add_argument(
|
|
295
|
+
"-o",
|
|
296
|
+
"--out-file",
|
|
297
|
+
type=str,
|
|
298
|
+
help="Path to output pdf. Defaults to <input dir name>_mosaics.pdf in working directory.",
|
|
299
|
+
)
|
|
300
|
+
parser.add_argument(
|
|
301
|
+
"--png-in-dir",
|
|
302
|
+
type=str,
|
|
303
|
+
help="Path to existing directory of .png files, bypassing creation of those from .nii files.",
|
|
304
|
+
)
|
|
305
|
+
parser.add_argument(
|
|
306
|
+
"--png-out-dir",
|
|
307
|
+
type=str,
|
|
308
|
+
help="Path to directory to output .png slice images too, instead of creating a temp directory.",
|
|
309
|
+
)
|
|
310
|
+
parser.add_argument(
|
|
311
|
+
"-m",
|
|
312
|
+
"--metadata",
|
|
313
|
+
type=str,
|
|
314
|
+
help="JSON string to include as metadata at the end of the output file.",
|
|
315
|
+
)
|
|
316
|
+
parser.add_argument(
|
|
317
|
+
"--no-anat",
|
|
318
|
+
action="store_false",
|
|
319
|
+
dest="anat",
|
|
320
|
+
help="Do not include anatomical images.",
|
|
321
|
+
)
|
|
322
|
+
parser.add_argument(
|
|
323
|
+
"--freesurfer",
|
|
324
|
+
type=str,
|
|
325
|
+
help="Path to freesurfer data.",
|
|
326
|
+
)
|
|
327
|
+
parser.add_argument(
|
|
328
|
+
"--downsample",
|
|
329
|
+
type=int,
|
|
330
|
+
help="Factor by which to downsample images.",
|
|
331
|
+
)
|
|
332
|
+
parser.add_argument(
|
|
333
|
+
"--debug",
|
|
334
|
+
action="store_true",
|
|
335
|
+
help="Set logging level to DEBUG.",
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
args = parser.parse_args()
|
|
339
|
+
|
|
340
|
+
if args.debug:
|
|
341
|
+
logger.setLevel(logging.DEBUG)
|
|
342
|
+
|
|
343
|
+
if args.out_file:
|
|
344
|
+
out_file = args.out_file
|
|
345
|
+
else:
|
|
346
|
+
in_abs = os.path.abspath(args.dataset)
|
|
347
|
+
out_file = os.path.basename(in_abs) + "_mosaic.pdf"
|
|
348
|
+
|
|
349
|
+
if not args.png_in_dir:
|
|
350
|
+
create_mosaic_pdf(
|
|
351
|
+
args.dataset,
|
|
352
|
+
out_file,
|
|
353
|
+
anat=args.anat,
|
|
354
|
+
png_out_dir=args.png_out_dir,
|
|
355
|
+
downsample=args.downsample,
|
|
356
|
+
freesurfer=args.freesurfer,
|
|
357
|
+
metadata=args.metadata,
|
|
358
|
+
)
|
|
359
|
+
else:
|
|
360
|
+
logger.info(f"Creating pdf at {out_file}")
|
|
361
|
+
create_pdf(args.png_in_dir, out_file, args.metadata)
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
if __name__ == "__main__":
|
|
365
|
+
main()
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "bids-mosaic"
|
|
7
|
+
description = "A BIDS tool for creating PDFs containing slices of nifti images"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
license = "MIT"
|
|
10
|
+
authors = [
|
|
11
|
+
{ name = "Joseph Wexler", email = "jbwexler@stanford.edu" },
|
|
12
|
+
]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 4 - Beta",
|
|
15
|
+
"Operating System :: OS Independent",
|
|
16
|
+
"Programming Language :: Python",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
]
|
|
19
|
+
version = "0.0.1"
|
|
20
|
+
requires-python = ">=3.10"
|
|
21
|
+
dependencies = [
|
|
22
|
+
"numpy>=1.24.0",
|
|
23
|
+
"pybids>=0.16.0",
|
|
24
|
+
"nilearn>=0.10.0",
|
|
25
|
+
"nibabel>=5.0.0",
|
|
26
|
+
"reportlab>=3.6.12",
|
|
27
|
+
"pillow>=9.3.0",
|
|
28
|
+
"matplotlib>=3.7.0"
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Source = "https://github.com/jbwexler/bids-mosaic"
|
|
33
|
+
|
|
34
|
+
[project.scripts]
|
|
35
|
+
bids-mosaic = "bidsmosaic.mosaic:main"
|
|
36
|
+
|
|
37
|
+
[tool.setuptools]
|
|
38
|
+
packages = ["bidsmosaic"]
|