subcortex-visualization 0.1.2__py3-none-any.whl

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.
Files changed (45) hide show
  1. subcortex_visualization/__init__.py +1 -0
  2. subcortex_visualization/data/__init__.py +0 -0
  3. subcortex_visualization/data/subcortex_AICHA_L.svg +883 -0
  4. subcortex_visualization/data/subcortex_AICHA_L_ordering.csv +36 -0
  5. subcortex_visualization/data/subcortex_AICHA_R.svg +883 -0
  6. subcortex_visualization/data/subcortex_AICHA_R_ordering.csv +36 -0
  7. subcortex_visualization/data/subcortex_AICHA_both.svg +1920 -0
  8. subcortex_visualization/data/subcortex_AICHA_both_ordering.csv +71 -0
  9. subcortex_visualization/data/subcortex_Brainnetome_L.svg +788 -0
  10. subcortex_visualization/data/subcortex_Brainnetome_L_ordering.csv +33 -0
  11. subcortex_visualization/data/subcortex_Brainnetome_R.svg +953 -0
  12. subcortex_visualization/data/subcortex_Brainnetome_R_ordering.csv +33 -0
  13. subcortex_visualization/data/subcortex_Brainnetome_both.svg +1687 -0
  14. subcortex_visualization/data/subcortex_Brainnetome_both_ordering.csv +65 -0
  15. subcortex_visualization/data/subcortex_Melbourne_S1_L.svg +609 -0
  16. subcortex_visualization/data/subcortex_Melbourne_S1_L_ordering.csv +16 -0
  17. subcortex_visualization/data/subcortex_Melbourne_S1_R.svg +609 -0
  18. subcortex_visualization/data/subcortex_Melbourne_S1_R_ordering.csv +16 -0
  19. subcortex_visualization/data/subcortex_Melbourne_S1_both.svg +1071 -0
  20. subcortex_visualization/data/subcortex_Melbourne_S1_both_ordering.csv +31 -0
  21. subcortex_visualization/data/subcortex_Melbourne_S2_L.svg +736 -0
  22. subcortex_visualization/data/subcortex_Melbourne_S2_L_ordering.csv +30 -0
  23. subcortex_visualization/data/subcortex_Melbourne_S2_R.svg +736 -0
  24. subcortex_visualization/data/subcortex_Melbourne_S2_R_ordering.csv +30 -0
  25. subcortex_visualization/data/subcortex_Melbourne_S2_both.svg +1344 -0
  26. subcortex_visualization/data/subcortex_Melbourne_S2_both_ordering.csv +59 -0
  27. subcortex_visualization/data/subcortex_Thalamus_Nuclei_HCP_L.svg +316 -0
  28. subcortex_visualization/data/subcortex_Thalamus_Nuclei_HCP_L_ordering.csv +14 -0
  29. subcortex_visualization/data/subcortex_Thalamus_Nuclei_HCP_R.svg +316 -0
  30. subcortex_visualization/data/subcortex_Thalamus_Nuclei_HCP_R_ordering.csv +14 -0
  31. subcortex_visualization/data/subcortex_Thalamus_Nuclei_HCP_both.svg +588 -0
  32. subcortex_visualization/data/subcortex_Thalamus_Nuclei_HCP_both_ordering.csv +27 -0
  33. subcortex_visualization/data/subcortex_aseg_L.svg +429 -0
  34. subcortex_visualization/data/subcortex_aseg_L_ordering.csv +14 -0
  35. subcortex_visualization/data/subcortex_aseg_R.svg +429 -0
  36. subcortex_visualization/data/subcortex_aseg_R_ordering.csv +14 -0
  37. subcortex_visualization/data/subcortex_aseg_both.svg +681 -0
  38. subcortex_visualization/data/subcortex_aseg_both_ordering.csv +27 -0
  39. subcortex_visualization/data/subcortical_aseg_paths_lookup.csv +49 -0
  40. subcortex_visualization/plotting.py +371 -0
  41. subcortex_visualization-0.1.2.dist-info/METADATA +153 -0
  42. subcortex_visualization-0.1.2.dist-info/RECORD +45 -0
  43. subcortex_visualization-0.1.2.dist-info/WHEEL +5 -0
  44. subcortex_visualization-0.1.2.dist-info/licenses/LICENSE.txt +674 -0
  45. subcortex_visualization-0.1.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,27 @@
1
+ ๏ปฟregion,face,plot_order,Hemisphere
2
+ accumbens,lateral,1,L
3
+ caudate,lateral,2,L
4
+ thalamus,lateral,3,L
5
+ hippocampus,lateral,4,L
6
+ amygdala,lateral,5,L
7
+ putamen,lateral,6,L
8
+ putamen,medial,7,L
9
+ pallidum,medial,8,L
10
+ accumbens,medial,9,L
11
+ caudate,medial,10,L
12
+ thalamus,medial,11,L
13
+ amygdala,medial,12,L
14
+ hippocampus,medial,13,L
15
+ accumbens,lateral,14,R
16
+ caudate,lateral,15,R
17
+ thalamus,lateral,16,R
18
+ hippocampus,lateral,17,R
19
+ amygdala,lateral,18,R
20
+ putamen,lateral,19,R
21
+ putamen,medial,20,R
22
+ pallidum,medial,21,R
23
+ accumbens,medial,22,R
24
+ caudate,medial,23,R
25
+ thalamus,medial,24,R
26
+ amygdala,medial,25,R
27
+ hippocampus,medial,26,R
@@ -0,0 +1,49 @@
1
+ region,view,path_number,Hemisphere,Num_Hemi
2
+ caudate,lateral,0,L,1
3
+ putamen,lateral,1,L,1
4
+ thalamus,lateral,2,L,1
5
+ hippocampus,lateral,3,L,1
6
+ amygdala,lateral,4,L,1
7
+ putamen,medial,5,L,1
8
+ caudate,medial,6,L,1
9
+ accumbens,medial,7,L,1
10
+ pallidum,medial,8,L,1
11
+ thalamus,medial,9,L,1
12
+ amygdala,medial,10,L,1
13
+ hippocampus,medial,11,L,1
14
+ caudate,lateral,0,R,1
15
+ putamen,lateral,1,R,1
16
+ thalamus,lateral,2,R,1
17
+ hippocampus,lateral,3,R,1
18
+ amygdala,lateral,4,R,1
19
+ putamen,medial,5,R,1
20
+ caudate,medial,6,R,1
21
+ accumbens,medial,7,R,1
22
+ pallidum,medial,8,R,1
23
+ thalamus,medial,9,R,1
24
+ amygdala,medial,10,R,1
25
+ hippocampus,medial,11,R,1
26
+ caudate,lateral,0,L,2
27
+ putamen,lateral,1,L,2
28
+ thalamus,lateral,2,L,2
29
+ hippocampus,lateral,3,L,2
30
+ amygdala,lateral,4,L,2
31
+ putamen,medial,5,L,2
32
+ caudate,medial,6,L,2
33
+ accumbens,medial,7,L,2
34
+ pallidum,medial,8,L,2
35
+ thalamus,medial,9,L,2
36
+ amygdala,medial,10,L,2
37
+ hippocampus,medial,11,L,2
38
+ caudate,lateral,12,R,2
39
+ putamen,lateral,13,R,2
40
+ thalamus,lateral,14,R,2
41
+ hippocampus,lateral,15,R,2
42
+ amygdala,lateral,16,R,2
43
+ putamen,medial,17,R,2
44
+ caudate,medial,18,R,2
45
+ accumbens,medial,19,R,2
46
+ pallidum,medial,20,R,2
47
+ thalamus,medial,21,R,2
48
+ amygdala,medial,22,R,2
49
+ hippocampus,medial,23,R,2
@@ -0,0 +1,371 @@
1
+ # Necessary imports
2
+ import pandas as pd
3
+ import numpy as np
4
+
5
+ # SVG parsing
6
+ import xml.etree.ElementTree as ET
7
+ from svgpath2mpl import parse_path
8
+
9
+ # matplotlib plotting
10
+ import matplotlib
11
+ import matplotlib.pyplot as plt
12
+ import matplotlib.colors as mcolors
13
+ from matplotlib.patches import PathPatch, Patch
14
+
15
+ # Files
16
+ from importlib.resources import files
17
+
18
+ def add_legend(ax, fig, atlas_ordering, ncols=4, value_column='value', cmap_colors=None, fill_title=None, cmap='plasma', norm=None):
19
+ """
20
+ Add a legend or colorbar to the plot based on the provided data.
21
+
22
+ Parameters
23
+ ----------
24
+ ax : matplotlib.axes.Axes
25
+ The axes object to which the legend or colorbar will be added.
26
+
27
+ fig : matplotlib.figure.Figure
28
+ The figure object containing the plot.
29
+
30
+ atlas_ordering : pandas.DataFrame
31
+ DataFrame containing the atlas ordering information.
32
+
33
+ value_column : str
34
+ The name of the column in `atlas_ordering` that contains the values to be visualized.
35
+
36
+ cmap_colors : list of str, optional
37
+ List of colors corresponding to the regions in the atlas.
38
+
39
+ fill_title : str, optional
40
+ Title for the legend or colorbar.
41
+
42
+ cmap : str or matplotlib.colors.Colormap, optional
43
+ Colormap to use for the colorbar. Default is 'plasma'.
44
+
45
+ norm : matplotlib.colors.Normalize or matplotlib.colors.TwoSlopeNorm, optional
46
+ Normalization object for the colorbar. If None, a discrete legend is created.
47
+
48
+ Returns
49
+ -------
50
+ None (adds to the plot directly)
51
+
52
+ """
53
+
54
+ if fill_title is None:
55
+ fill_title = "values"
56
+
57
+ if norm is None:
58
+ # Discrete legend
59
+ unique_regions = atlas_ordering[['region', value_column]].drop_duplicates()
60
+ legend_elements = [
61
+ Patch(facecolor=cmap_colors[row[value_column]], edgecolor='black', label=row['region'])
62
+ for _, row in unique_regions.iterrows()
63
+ ]
64
+ # Add legend to the plot
65
+ ax.legend(handles=legend_elements, loc='lower center',
66
+ bbox_to_anchor=(0.5, -0.25), ncols=ncols, frameon=False,
67
+ fontsize='medium', handleheight=1.2, handlelength=1.2,
68
+ title=fill_title,
69
+ handletextpad=0.4)
70
+ fig.subplots_adjust(bottom=0.5) # Reserve space for legend
71
+
72
+ else:
73
+ # Continuous colorbar
74
+ sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
75
+ sm.set_array([]) # Only needed for compatibility
76
+ cbar = fig.colorbar(sm, ax=ax, orientation='horizontal', fraction=0.046, pad=0.04)
77
+ cbar.set_label(fill_title)
78
+
79
+ def prep_data(atlas_ordering, value_column='value', subcortex_data=None, cmap=None, vmin=None, vmax=None, midpoint=None):
80
+ """
81
+ Prepare data for plotting by merging with subcortex_data and normalizing values.
82
+
83
+ Parameters
84
+ ----------
85
+ atlas_ordering : pandas.DataFrame
86
+ DataFrame containing the atlas ordering information.
87
+
88
+ value_column : str
89
+ The name of the column in `atlas_ordering` that contains the values to be visualized. Default is 'value'.
90
+
91
+ subcortex_data : pandas.DataFrame, optional
92
+ DataFrame with columns ['region', 'value', 'Hemisphere'].
93
+ If None, a default dataset is generated based on the selected hemisphere.
94
+
95
+ cmap : str or matplotlib.colors.Colormap, optional
96
+ Colormap to use for the colorbar. Default is 'plasma'.
97
+
98
+ vmin : float, optional
99
+ Minimum value for colormap normalization. If None, the minimum of the input values is used.
100
+
101
+ vmax : float, optional
102
+ Maximum value for colormap normalization. If None, the maximum of the input values is used.
103
+
104
+ midpoint : float, optional
105
+ If provided, uses a diverging colormap centered around this value.
106
+
107
+ Returns
108
+ -------
109
+ atlas_ordering : pandas.DataFrame
110
+ DataFrame with merged and normalized values.
111
+
112
+ color_lookup : dict
113
+ Dictionary mapping region names to colors for discrete colormap.
114
+
115
+ cmap_colors : list of str
116
+ List of colors corresponding to the regions in the atlas.
117
+
118
+ norm : matplotlib.colors.Normalize or matplotlib.colors.TwoSlopeNorm
119
+ Normalization object for the colorbar. If None, a discrete legend is created.
120
+
121
+ Notes
122
+ -----
123
+ - The function handles both discrete and continuous colormaps based on the presence of subcortex_data.
124
+ - If subcortex_data is None, a discrete colormap is created based on the unique regions in atlas_ordering.
125
+ - If subcortex_data is provided, the values are normalized and a continuous colormap is created.
126
+ - The function returns the updated atlas_ordering DataFrame, color lookup dictionary, and colormap colors.
127
+
128
+ """
129
+
130
+ if subcortex_data is None:
131
+ # Assign discrete indices per region
132
+ unique_regions = atlas_ordering['region'].unique()
133
+ region_to_index = {region: idx for idx, region in enumerate(unique_regions)}
134
+ atlas_ordering[value_column] = atlas_ordering['region'].map(region_to_index)
135
+
136
+ # Discrete colormap
137
+ num_regions = len(unique_regions)
138
+ cmap_colors = cmap(np.linspace(0, 1, num_regions))
139
+ color_lookup = {region: cmap_colors[i] for region, i in region_to_index.items()}
140
+
141
+ return atlas_ordering, color_lookup, cmap_colors
142
+
143
+ else:
144
+ # Merge and normalize
145
+ atlas_ordering = atlas_ordering.merge(subcortex_data, on=['region', 'Hemisphere'], how='left')
146
+
147
+ fill_values = atlas_ordering[value_column].values
148
+
149
+ if midpoint is not None:
150
+ max_dev = np.nanmax(np.abs(fill_values - midpoint))
151
+ if vmin is None:
152
+ vmin = midpoint - max_dev
153
+ if vmax is None:
154
+ vmax = midpoint + max_dev
155
+ norm = mcolors.TwoSlopeNorm(vmin=vmin, vcenter=midpoint, vmax=vmax)
156
+ else:
157
+ if vmin is None:
158
+ vmin = np.nanmin(fill_values)
159
+ if vmax is None:
160
+ vmax = np.nanmax(fill_values)
161
+ norm = mcolors.Normalize(vmin=vmin, vmax=vmax)
162
+
163
+ return atlas_ordering, norm, vmin, vmax, midpoint
164
+
165
+ def plot_helper(atlas_ordering, paths, value_column='value', hemisphere='L', subcortex_data=None, line_color='black', line_thickness=1.5,
166
+ color_lookup=None, cmap=None, norm=None):
167
+ """
168
+
169
+ Helper function to plot the SVG paths with the specified colors and line properties.
170
+
171
+ Parameters
172
+ ----------
173
+ atlas_ordering : pandas.DataFrame
174
+ DataFrame containing the atlas ordering information.
175
+
176
+ paths : list of xml.etree.ElementTree.Element
177
+ List of SVG path elements to be plotted.
178
+
179
+ value_column : str
180
+ The name of the column in `atlas_ordering` that contains the values to be visualized. Default is 'value'.
181
+
182
+ hemisphere : {'L', 'R', 'both'}, default='L'
183
+ Which hemisphere(s) to display. Use 'L' for left, 'R' for right, or 'both' for bilateral plots.
184
+
185
+ subcortex_data : pandas.DataFrame, optional
186
+ DataFrame with columns ['region', 'value', 'Hemisphere'].
187
+ If None, a default dataset is generated based on the selected hemisphere.
188
+
189
+ line_color : str, default='black'
190
+ Color of the outline around each subcortical region.
191
+
192
+ line_thickness : float, default=1.5
193
+ Thickness of the outline for each region (in mm)
194
+
195
+ color_lookup : dict, optional
196
+ Dictionary mapping region names to colors for discrete colormap.
197
+
198
+ cmap : str or matplotlib.colors.Colormap, optional
199
+ Colormap to use for the colorbar. Default is 'plasma'.
200
+
201
+ norm : matplotlib.colors.Normalize or matplotlib.colors.TwoSlopeNorm, optional
202
+ Normalization object for the colorbar. If None, a discrete legend is created.
203
+
204
+ Returns
205
+ -------
206
+ fig : matplotlib.figure.Figure
207
+ The generated figure object.
208
+
209
+ ax : matplotlib.axes.Axes
210
+ The axes object containing the plot.
211
+
212
+ """
213
+
214
+ # Start plotting
215
+ if hemisphere == 'both':
216
+ fig, ax = plt.subplots(figsize=(17,6))
217
+ else:
218
+ fig, ax = plt.subplots(figsize=(8, 6))
219
+ patches = []
220
+
221
+ for _, row in atlas_ordering.iterrows():
222
+ this_region = row['region']
223
+ this_region_side = row['face']
224
+ this_region_hemi = row['Hemisphere']
225
+
226
+ # Determine color
227
+ if subcortex_data is None:
228
+ this_region_color = color_lookup[this_region]
229
+ else:
230
+ val = row[value_column]
231
+ this_region_color = cmap(norm(val)) if not pd.isnull(val) else "#cccccc"
232
+
233
+ # Match title to region
234
+ for path in paths:
235
+ for child in path:
236
+ if child.tag.endswith('title') and child.text == f"{this_region}_{this_region_side}_{this_region_hemi}":
237
+ d = path.attrib['d']
238
+ path_obj = parse_path(d)
239
+ patch = PathPatch(path_obj, facecolor=this_region_color,
240
+ edgecolor=line_color, lw=line_thickness)
241
+ ax.add_patch(patch)
242
+ patches.append(patch)
243
+
244
+ ax.autoscale_view()
245
+ ax.set_aspect('equal')
246
+ ax.axis('off')
247
+ ax.invert_yaxis()
248
+
249
+ return fig, ax
250
+
251
+ def plot_subcortical_data(subcortex_data=None, atlas='aseg', value_column='value',
252
+ line_thickness=1.5, line_color='black',
253
+ hemisphere='L', fill_title="values", cmap='viridis',
254
+ vmin=None, vmax=None, midpoint=None, show_legend=True,
255
+ show_figure=True):
256
+
257
+ """
258
+ Visualize subcortical brain data on an SVG map using matplotlib.
259
+
260
+ Parameters
261
+ ----------
262
+ subcortex_data : pandas.DataFrame, optional
263
+ DataFrame with columns ['region', 'value', 'Hemisphere'].
264
+ If None, a default dataset is generated based on the selected hemisphere.
265
+
266
+ atlas : str, default='aseg'
267
+ The atlas used for the subcortical regions. Currently, two options are supported: 'aseg' and 'Tian_S1'.
268
+
269
+ value_column : str, default='value'
270
+ The name of the column in `subcortex_data` that contains the values to be visualized.
271
+
272
+ line_thickness : float, default=1.5
273
+ Thickness of the outline for each region.
274
+
275
+ line_color : str, default='black'
276
+ Color of the outline around each subcortical region.
277
+
278
+ hemisphere : {'L', 'R', 'both'}, default='L'
279
+ Which hemisphere(s) to display. Use 'L' for left, 'R' for right, or 'both' for bilateral plots.
280
+
281
+ fill_title : str, default="values"
282
+ Label for the colorbar indicating the meaning of the fill values.
283
+
284
+ cmap : str or matplotlib.colors.Colormap, default='viridis'
285
+ Colormap used to fill in the regions. Accepts a string name or a Colormap object.
286
+
287
+ vmin : float, optional
288
+ Minimum value for colormap normalization. If None, the minimum of the input values is used.
289
+
290
+ vmax : float, optional
291
+ Maximum value for colormap normalization. If None, the maximum of the input values is used.
292
+
293
+ midpoint : float, optional
294
+ If provided, uses a diverging colormap centered around this value.
295
+
296
+ show_legend : bool, default=True
297
+ If True, displays a legend or colorbar indicating the mapping of values to colors.
298
+
299
+ show_figure : bool, default=True
300
+ If True, displays the figure using `plt.show()`. If False, returns the matplotlib Figure object.
301
+
302
+ Returns
303
+ -------
304
+ matplotlib.figure.Figure or None
305
+ The generated figure, if `show_figure` is False. Otherwise, displays the plot and returns None.
306
+
307
+ Notes
308
+ -----
309
+ - The function loads SVG files and a lookup CSV bundled with the package, which can be found under `data/` directory.
310
+ - The input `subcortex_data` should align with regions defined in the lookup table.
311
+ """
312
+
313
+ # Load SVG
314
+ svg_path = files("subcortex_visualization.data").joinpath(f"subcortex_{atlas}_{hemisphere}.svg")
315
+ tree = ET.parse(svg_path)
316
+ root = tree.getroot()
317
+
318
+ # Define SVG namespace
319
+ ns = {'svg': 'http://www.w3.org/2000/svg'}
320
+ ET.register_namespace('', ns['svg'])
321
+
322
+ # Find path elements
323
+ paths = root.findall('.//svg:path', ns)
324
+
325
+ # Load ordering file
326
+ atlas_ordering = pd.read_csv(files("subcortex_visualization.data").joinpath(f"subcortex_{atlas}_{hemisphere}_ordering.csv"))
327
+
328
+ # Handle colormap
329
+ if isinstance(cmap, str):
330
+ cmap = matplotlib.colormaps.get_cmap(cmap)
331
+
332
+ # Prepare data for plotting
333
+ if subcortex_data is None:
334
+ atlas_ordering, color_lookup, cmap_colors = prep_data(atlas_ordering, value_column=value_column, subcortex_data=None, cmap=cmap)
335
+ else:
336
+ atlas_ordering, norm, vmin, vmax, midpoint = prep_data(atlas_ordering, value_column=value_column,
337
+ subcortex_data=subcortex_data,
338
+ cmap=cmap, vmin=vmin, vmax=vmax, midpoint=midpoint)
339
+
340
+ # Let's get plottin
341
+ if subcortex_data is None:
342
+
343
+ fig, ax = plot_helper(atlas_ordering, paths, value_column=value_column, hemisphere=hemisphere,
344
+ line_color=line_color, line_thickness=line_thickness,
345
+ color_lookup=color_lookup)
346
+
347
+ else:
348
+
349
+ fig, ax = plot_helper(atlas_ordering, paths, value_column=value_column, hemisphere=hemisphere,
350
+ line_color=line_color, line_thickness=line_thickness,
351
+ subcortex_data=subcortex_data, cmap=cmap, norm=norm)
352
+
353
+ # Add a legend if requested
354
+ if show_legend:
355
+
356
+ ncols = np.where(hemisphere == 'both', 8, 4)
357
+
358
+ # Call add_legend function to add the legend (discrete when subcortex_data is None) or colorbar (continuous when subcortex_data is not None)
359
+ if subcortex_data is None:
360
+ add_legend(ax=ax, fig=fig, value_column=value_column, atlas_ordering=atlas_ordering,
361
+ cmap_colors=cmap_colors, fill_title=fill_title, ncols=ncols)
362
+ else:
363
+ add_legend(ax=ax, fig=fig, value_column=value_column, atlas_ordering=atlas_ordering,
364
+ cmap=cmap, norm=norm, fill_title=fill_title)
365
+
366
+ plt.tight_layout()
367
+
368
+ if show_figure:
369
+ plt.show()
370
+ else:
371
+ return fig
@@ -0,0 +1,153 @@
1
+ Metadata-Version: 2.4
2
+ Name: subcortex_visualization
3
+ Version: 0.1.2
4
+ Summary: A package to visualize subcortical brain data in two dimensions.
5
+ Author: Annie G. Bryant
6
+ Author-email: "Annie G. Bryant" <anniegbryant@gmail.com>
7
+ License: GNU General Public License v3 (GPLv3)
8
+ Project-URL: Homepage, https://github.com/anniegbryant/subcortex_visualization
9
+ Project-URL: Issues, https://github.com/anniegbryant/subcortex_visualization/issues
10
+ Classifier: Programming Language :: Python
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Development Status :: 1 - Planning
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Environment :: Console
16
+ Classifier: Environment :: Other Environment
17
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
18
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
19
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
20
+ Requires-Python: >=3.9
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE.txt
23
+ Dynamic: author
24
+ Dynamic: license-file
25
+
26
+ # Subcortical data visualization in 2D
27
+
28
+ This python package currently includes the following six subcortical atlases for data visualization in two-dimensional vector graphics:
29
+
30
+ <img src="images/all_atlas_showcase.png" width="100%">
31
+
32
+ More information about these atlases, including the process of rendering the surfaces and tracing the outlines for each, can be found in the [`atlas_info/`](https://github.com/anniegbryant/subcortex_visualization/tree/main/atlas_info) directory.
33
+
34
+
35
+ ## ๐Ÿ™‹โ€โ™€๏ธ Motivation
36
+
37
+ This Python package was created to generate two-dimensional subcortex images in the style of the popular [`ggseg` package](https://github.com/ggseg/ggseg) in R.
38
+ We based our vector graphic outlines on the three-dimensional subcortical meshes either (1) provided as part of the [ENIGMA toolbox](https://github.com/MICA-MNI/ENIGMA) for the aseg atlas or (2) meshes generated in-house using rendering software from [Chris Rorden's lab](https://github.com/neurolabusc) (either [nii2mesh](https://github.com/neurolabusc/nii2mesh) or [Surf Ice](https://github.com/neurolabusc/surf-ice); check out [`custom_segmentation_pipeline/`](https://github.com/anniegbryant/subcortex_visualization/tree/main/custom_segmentation_pipeline) for more information).
39
+
40
+ The below graphic summarizes the transformation from 3D volumetric meshes to 2D surfaces, starting from the ENIGMA toolbox ('aseg' atlas, left) or a custom-rendered mesh from the [Melbourne Subcortex Atlas](https://github.com/yetianmed/subcortex/tree/master) as published in [Tian et al. (2020)]()https://www.nature.com/articles/s41593-020-00711-6 -- ('S1' granularity level, right).
41
+
42
+ <img src="images/aseg_and_Melbourne_S1_3D_to_2D_schematic.png" width="90%">
43
+
44
+
45
+ While `ggseg` offers subcortical plotting with the `aseg` atlas, it is [not currently possible](https://github.com/ggseg/ggseg/issues/104) to show data from all seven subcortical regions (accumbens, amygdala, caudate, hippocampus, pallidum, putamen, thalamus) in the same figure.
46
+ Moreover, there is currently no other software available to visualize any of the other above subcortical/thalamic atlases in 2D with real data, hence development here.
47
+
48
+
49
+ ## ๐Ÿ–ฅ๏ธ Installation
50
+
51
+ The package can be installed from GitHub in two ways.
52
+ First, you can install directly with pip from the [PyPI repository](https://pypi.org/project/subcortex-visualization/):
53
+
54
+ ```bash
55
+ pip install subcortex-visualization
56
+ ```
57
+
58
+ If you would like to make your own modifications before installing, you can also clone this repository first and then install from your local version:
59
+
60
+ ```bash
61
+ git clone https://github.com/anniegbryant/subcortex_visualization.git
62
+ cd subcortex_visualization
63
+ pip install .
64
+ ```
65
+
66
+ This will install the `subcortex_visualization` package so you have access to the `plot_subcortical_data` function and associated data.
67
+
68
+ ## ๐Ÿ‘จโ€๐Ÿ’ป Usage
69
+
70
+ ### โ—๏ธ Quick start
71
+
72
+ Running the below code will produce an image of the left subcortex in the aseg atlas (the default), each region colored by its index, with the plasma color scheme:
73
+
74
+ ```python
75
+ plot_subcortical_data(hemisphere='L', cmap='plasma',
76
+ fill_title = "Subcortical region index")
77
+ ```
78
+
79
+ <img src="images/example_aseg_subcortex_plot.png" width="80%">
80
+
81
+
82
+ ### ๐Ÿ“š Tutorial
83
+
84
+ For a guide that goes through all the functionality and atlases available in this package, we compiled a simple walkthrough tutorial in [tutorial.ipynb](https://github.com/anniegbryant/subcortex_visualization/blob/main/tutorial.ipynb).
85
+ To plot real data in the subcortex, your `subcortex_data` should be a `pandas.DataFrame` structured as follows (here we've just assigned an integer index to each region):
86
+
87
+ | region | value | Hemisphere |
88
+ | :--- | :---: | :---: |
89
+ | accumbens | 0 | L |
90
+ | amygdala | 1 | L |
91
+ | caudate | 2 | L |
92
+ | hippocampus | 3 | L |
93
+ | pallidum | 4 | L |
94
+ | putamen | 5 | L |
95
+ | thalamus | 6 | L |
96
+
97
+ Briefly, all functionality is contained within the `plot_subcortical_data` function, which takes in the following arguments:
98
+ * `subcortex_data`: The three-column dataframe in a format as shown above; this is optional, if left out the plot will just color each region by its index
99
+ * `atlas`: The name of the subcortical segmentation atlas (default is 'aseg', which is currently the only supported atlas)
100
+ * `value_column`: The name of the column in your `subcortex_data` to plot, defaults to 'value'
101
+ * `line_thickness`: How thick the lines around each subcortical region should be drawn, in mm (default is 1.5)
102
+ * `line_color`: What color the lines around each subcortical region should be (default is 'black')
103
+ * `hemisphere`: Which hemisphere ('L' or 'R') the `subcortex_data` is from; can also be 'both' (default is 'L')
104
+ * `fill_title`: Name to add to legend (default is 'values')
105
+ * `cmap`: name of colormap (e.g., 'plasma' or 'viridis') or a `matplotlib.colors.Colormap` (default is 'viridis')
106
+ * `vmin`: Min fill value; this is optional, and you would only want to use this to manually constrain the fill range to match another figure
107
+ * `vmax`: Max fill value; this is optional, and you would only want to use this to manually constrain the fill range to match another figure
108
+ * `midpoint`: Midpoint value to enforce for fill range; this is optional
109
+
110
+ Here's an example plotting both hemispheres, with data randomly sampled from a normal distribution, setting a color range from blue (low) to red (high) with white at the center (midpoint=0):
111
+
112
+ ```python
113
+ import matplotlib.colors as mcolors
114
+ import numpy as np
115
+
116
+ np.random.seed(127)
117
+
118
+ example_continuous_data_L = pd.DataFrame({"region": ["accumbens", "amygdala", "caudate", "hippocampus", "pallidum", "putamen", "thalamus"],
119
+ "value": np.random.normal(0, 1, 7)}).assign(Hemisphere = "L")
120
+ example_continuous_data_R = pd.DataFrame({"region": ["accumbens", "amygdala", "caudate", "hippocampus", "pallidum", "putamen", "thalamus"],
121
+ "value": np.random.normal(0, 1, 7)}).assign(Hemisphere = "R")
122
+ example_continuous_data = pd.concat([example_continuous_data_L, example_continuous_data_R], axis=0)
123
+
124
+ white_blue_red_cmap = mcolors.LinearSegmentedColormap.from_list("BlueWhiteRed", ["blue", "white", "red"])
125
+
126
+ plot_subcortical_data(subcortex_data=example_continuous_data, atlas='aseg',
127
+ hemisphere='both', fill_title = "Normal distribution sample",
128
+ cmap=white_blue_red_cmap, midpoint=0)
129
+ ```
130
+
131
+ <img src="images/example_aseg_subcortex_normdist.png" width="80%">
132
+
133
+
134
+ ## ๐Ÿ’ก Want to generate your own mesh and/or parcellation?
135
+
136
+ This package provides six subcortical atlases as a starting point.
137
+ The workflow can readily be extended to your favorite segmentation atlas, though!
138
+ We have a dedicated folder for a custom segmentation pipeline that will walk you through the two key steps:
139
+ 1. Rendering a series of triangulated surface meshes from your parcellation atlas (starting from a .nii.gz volume), using either the [`nii2mesh`](https://github.com/neurolabusc/nii2mesh) or [`surfice_atlas`](https://github.com/neurolabusc/surfice_atlas) software, both developed by Chris Rorden; and
140
+ 2. Tracing the outline of each region in the rendered mesh in vector graphic editing software (we use Inkscape in the tutorial as a powerful and free option), to yield a two-dimensional image of your atlas in scalable vector graphic (.svg) format.
141
+
142
+ Check out the walkthrough in the [`custom_segmentation_pipeline/`](https://github.com/anniegbryant/subcortex_visualization/tree/main/custom_segmentation_pipeline) folder for more information on how to render your own volumetric segmentation with an interactive mesh and convert to a two-dimensional vector graphic that can be integrated with this package.
143
+
144
+ ## ๐Ÿ™ Acknowledgments
145
+
146
+ Thank you very much to [Chris Rorden](https://github.com/rordenlab), [Ye Tian](https://github.com/yetianmed), and [Sid Chopra](https://github.com/sidchop) for their suggestions and continued development of open tools for neuroimaging visualization that enabled development of this project!
147
+
148
+ ## โ“๐Ÿ“ง Questions, comments, or suggestions always welcome!
149
+
150
+ Please feel free to ask questions, report bugs, or share suggestions by creating an issue or by emailing me (Annie) at ([anniegbryant@gmail.com](mailto:anniegbryant@gmail.com)) ๐Ÿ˜Š
151
+
152
+ As an [open-source tool](https://opensource.guide/how-to-contribute/), pull requests are always welcome from the community, too.
153
+ If you create your own custom vector graphic for your segmentation atlas of choice, feel free to create a pull request to incorporate and be acknowledged.
@@ -0,0 +1,45 @@
1
+ subcortex_visualization/__init__.py,sha256=jpAXYluGVENlJnvKDzL7RO3zeyCqp_ECl2fE8SnoEPU,43
2
+ subcortex_visualization/plotting.py,sha256=XO6jcdRubkNGnHZoeKwmVrxQE_M0gIZwLFo8P2Lz5Uk,14233
3
+ subcortex_visualization/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ subcortex_visualization/data/subcortex_AICHA_L.svg,sha256=WMwgtZUqfhLW-2lUfhFEBND3ESJXxlew94vtfQhl6VY,135504
5
+ subcortex_visualization/data/subcortex_AICHA_L_ordering.csv,sha256=thW6QuSAKNiI6uijz9ZpINIDrgFPiWGUF7k_UQUb_2s,864
6
+ subcortex_visualization/data/subcortex_AICHA_R.svg,sha256=htwTJHWolkxlC89Se5HzEngh5w60ACGnZEAHf6EygM8,134310
7
+ subcortex_visualization/data/subcortex_AICHA_R_ordering.csv,sha256=AJ9EcX5lFGMawkYEqPxP9rMdUx0NlCyWVhl4vbDFsb8,864
8
+ subcortex_visualization/data/subcortex_AICHA_both.svg,sha256=_Urr7-XER4k50Qfj_8UKG-CWUnsCglNKBFfQhBPXmxM,271481
9
+ subcortex_visualization/data/subcortex_AICHA_both_ordering.csv,sha256=RFcJx7dR_ekfBPgaXYumKFjCvQRthAygqtauPJemugE,1705
10
+ subcortex_visualization/data/subcortex_Brainnetome_L.svg,sha256=PT7HnG3PKuAmMOrPwIULAvnh8x5aOTNHKymYkiw-JvY,115635
11
+ subcortex_visualization/data/subcortex_Brainnetome_L_ordering.csv,sha256=UuVYc4lebice0PWKJbrL5WPNPZP2Rtk9OWAME6vWYcs,633
12
+ subcortex_visualization/data/subcortex_Brainnetome_R.svg,sha256=xtDsm1x3C93NUD2pFuS-uHxIFjSZs1zzKrxZW1GO40M,120348
13
+ subcortex_visualization/data/subcortex_Brainnetome_R_ordering.csv,sha256=gVp6eVJzhPzTfb3iI9vIBJQL5Apz9o0p6aCyYZheVls,633
14
+ subcortex_visualization/data/subcortex_Brainnetome_both.svg,sha256=QR8r5FBq4b021XyWbcYd1V-EBofPkj0OjGBPT0cP284,233730
15
+ subcortex_visualization/data/subcortex_Brainnetome_both_ordering.csv,sha256=EkhB1MiNYWU7w4Eg2EB0w2mPL7YtxZeZ3UtCJjz7znM,1239
16
+ subcortex_visualization/data/subcortex_Melbourne_S1_L.svg,sha256=IH9bCCzqALsoigtT8j9t44ZINwp4dxhoBqurIgjKBuE,60411
17
+ subcortex_visualization/data/subcortex_Melbourne_S1_L_ordering.csv,sha256=IvV_eOT3B_t6-Mzwx_AnsSfL5cOJ87-GGbxnKXkfYd8,406
18
+ subcortex_visualization/data/subcortex_Melbourne_S1_R.svg,sha256=VTS7YZC2twcvWrTwCLBMNNRDeZzEfmkjZW0JY2dmZmU,60502
19
+ subcortex_visualization/data/subcortex_Melbourne_S1_R_ordering.csv,sha256=kRbdHZGYiP_sejTQ0XP3Ntl232PSiXgkztw3_SxkmHk,406
20
+ subcortex_visualization/data/subcortex_Melbourne_S1_both.svg,sha256=QS8sq_1clx48CxwcfDwHUyAXAVYP14WRAQhX-T4zhA8,114974
21
+ subcortex_visualization/data/subcortex_Melbourne_S1_both_ordering.csv,sha256=3FkpewwtWo3aeZT-8soDzbfrLvAcIuO6NoK6HOLqkR8,785
22
+ subcortex_visualization/data/subcortex_Melbourne_S2_L.svg,sha256=uVd8nGv1odY6P5GSrQA16FC4BLOUt_VGVAOfyY2VeeE,89813
23
+ subcortex_visualization/data/subcortex_Melbourne_S2_L_ordering.csv,sha256=RvHVj5WRV7dPBZkK_yPe3mJevulfjusu0xgH06--V5Q,888
24
+ subcortex_visualization/data/subcortex_Melbourne_S2_R.svg,sha256=dLixnb0DHtXpj-X1akrXUyZSZL12yJWG2RF6qQ6mbYk,89315
25
+ subcortex_visualization/data/subcortex_Melbourne_S2_R_ordering.csv,sha256=rz65wZE0Ki2b2iimodQ2A0nuDax-0HxgaIt9sXIlPqs,888
26
+ subcortex_visualization/data/subcortex_Melbourne_S2_both.svg,sha256=-1zr5Ph2XC8_vebQ5m_0Lva1BAZyRJ3pxtJ3u8eJexU,173552
27
+ subcortex_visualization/data/subcortex_Melbourne_S2_both_ordering.csv,sha256=biljYiz-fzwDwu3_tJQQOv1McoaOf0m8KOweMahxJNY,1749
28
+ subcortex_visualization/data/subcortex_Thalamus_Nuclei_HCP_L.svg,sha256=RLOQqwcQoDkU6dU6Go_hAH39FxcQffPpnsKPC6gKpbo,36283
29
+ subcortex_visualization/data/subcortex_Thalamus_Nuclei_HCP_L_ordering.csv,sha256=PJR6NNGyFtF9lRpJV0Ce-Pr-_U3fAIiOUQRngJ0zfj4,438
30
+ subcortex_visualization/data/subcortex_Thalamus_Nuclei_HCP_R.svg,sha256=yMecggCGAN6Pgn0-3uUUy_YQ5wFotOgUVwxnJwlvrYQ,36344
31
+ subcortex_visualization/data/subcortex_Thalamus_Nuclei_HCP_R_ordering.csv,sha256=qX2AFXQkwFmyU2xWlbTZLG_kpjHkd_MI3L4CiT51SFI,438
32
+ subcortex_visualization/data/subcortex_Thalamus_Nuclei_HCP_both.svg,sha256=E6-oBTZ57Yh3czKfPBsr9KFNpuUXx1MCVf4O7IFW4nc,70473
33
+ subcortex_visualization/data/subcortex_Thalamus_Nuclei_HCP_both_ordering.csv,sha256=8Ny_CPquekB7UE2hFGXY3gS9amY6Q7mNnI2G9RC11LE,849
34
+ subcortex_visualization/data/subcortex_aseg_L.svg,sha256=LlG_-FSaTVY26mM3v8isexFAhzRBs09i4XsqCqGPYr4,50932
35
+ subcortex_visualization/data/subcortex_aseg_L_ordering.csv,sha256=TGCJ2mXcgoP_X6iKIqkyYYa2ONfOQ65qb-mluRn3TOE,323
36
+ subcortex_visualization/data/subcortex_aseg_R.svg,sha256=oqSCRJ1SvxNp58FYkejo7vT0WBp6MXIQF_8Xy6aTYks,50803
37
+ subcortex_visualization/data/subcortex_aseg_R_ordering.csv,sha256=LS87Sm74mtnhmm_mFNXJXm-o0JUvvDC_PkYFh2Gw1aQ,323
38
+ subcortex_visualization/data/subcortex_aseg_both.svg,sha256=PtHnjcch-xRg__1gH-8vKkVihhvP0U52R7wprkERyMs,96336
39
+ subcortex_visualization/data/subcortex_aseg_both_ordering.csv,sha256=v0ylkZQXleNsRPB6uzS9VcuxI86UmkCL_VdogkKoTeI,619
40
+ subcortex_visualization/data/subcortical_aseg_paths_lookup.csv,sha256=MQWisa4WyuYc0-h2o-GNVnW09RYGHDhOfnE6ySohgaM,1197
41
+ subcortex_visualization-0.1.2.dist-info/licenses/LICENSE.txt,sha256=XimfHe3DgLiY7Sd9GPyH3u_SjNfg0IF3QvCNBAYC6Rc,35137
42
+ subcortex_visualization-0.1.2.dist-info/METADATA,sha256=jqC5aZZEwtZzgnwygqBiCvB8O89vg79QgEwACUH0tQU,9661
43
+ subcortex_visualization-0.1.2.dist-info/WHEEL,sha256=GHB6lJx2juba1wDgXDNlMTyM13ckjBMKf-OnwgKOCtA,91
44
+ subcortex_visualization-0.1.2.dist-info/top_level.txt,sha256=NrC151UjYD1USCUAj_JFSZN6prg-WqbJWlP5CoC4r4E,24
45
+ subcortex_visualization-0.1.2.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.3.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+