Repository: nilearn/nilearn

Issue:
[request feature] suggesting features for animal imaging data
Hi Nilearn team,

I’m a preclinical fMRI researcher and want to conduct the Nilearn for my data analysis as well as visualization. One major concern is most of the visualization features are too optimized for human research in terms of generating the publishable level of figures while it also provides some flexibility to plot animal data.

So hope to suggest the following features as API to develop some animal-research-friendly features. This has been posted originally at Neurostars (https://neurostars.org/t/request-feature-suggesting-features-for-animal-imaging-data/6959?u=dvm-shlee) but copying here since this seems the better place.

Low-level API guide or instruction to tweak glassy template: Since I’m an animal-oriented researcher, I’m focussing a few species that others not formally do. The code seems only allowed MNI space, and there is no option currently to add additional space for this (hard codded to use only ‘brain_schematics_XX.json’ in ‘glass_brain_files’). So I’m suggesting to tweak the original code as below.
“glass_brain.py”

line 87, add
def _get_json_and_transform(direction, dirname = None):

line 104-105, add
____if dirname is None:
____[indent] dirname = os.path.dirname(os.path.abspath(__file__))
____[indent] dirname = os.path.join(dirname, ‘glass_brain_files’)

line 167, insert
________if ‘dirname’ in kwargs.keys():
____________dirname = kwargs[‘dirname’]
____________del kwargs[‘dirname’]
________else:
____________dirname = None

line 175, add
____json_filename, transform = _get_json_and_transform(direction, dirname)

The next feature will be decimal position annotation for the smaller brain., Below is my suggestion on updating a code.
“display.py”

line 260, add
____def draw_position(self, size, bg_color, decimal=False, **kwargs):
________if decimal:
____________text = ‘%s=%.{}f’.format(decimal)
________else:
____________text = '%s=%i’
line 262, modify ‘%s=%i’ to text as below
________ax.text(0, 0, text % (self.direction, self.coord),

line 1001, insert
________# use decimal for annotate position
________if ‘decimal’ in kwargs.keys():
____________decimal = kwargs[‘decimal’]
____________del kwargs[‘decimal’]
________else:
____________decimal = False

line 1011, add
________________display_axis.draw_position(size=size, bg_color=bg_color, decimal=decimal, **kwargs)

“img_plotting.py”

line 135, add
____if ‘decimal’ in kwargs.keys():
________decimal = kwargs[‘decimal’]
________del kwargs[‘decimal’]
____else:
________decimal = False

line 194, add
________display.annotate(decimal=decimal)

After adding the above code, with passing ‘decimal=2’ on any plotting method, the image will be as below.

![decimal](https://user-images.githubusercontent.com/7221078/82829358-16e07500-9e81-11ea-9b1b-bb1127695d42.png)

I haven’t tested the glass_brain, though, so I need the additional test to validate it. But I hope these features could be accepted into the Nilearn for animal researchers, and if this looks acceptable, I will generate a pull request according to your development guideline.

Thanks!




Discussion:

Resolving patch:
diff --git a/nilearn/plotting/displays.py b/nilearn/plotting/displays.py
--- a/nilearn/plotting/displays.py
+++ b/nilearn/plotting/displays.py
@@ -257,9 +257,15 @@ def transform_to_2d(self, data, affine):
                              self.direction)
         return cut
 
-    def draw_position(self, size, bg_color, **kwargs):
+    def draw_position(self, size, bg_color, decimals=False, **kwargs):
+        if decimals:
+            text = '%s=%.{}f'.format(decimals)
+            coord = float(self.coord)
+        else:
+            text = '%s=%i'
+            coord = self.coord
         ax = self.ax
-        ax.text(0, 0, '%s=%i' % (self.direction, self.coord),
+        ax.text(0, 0, text % (self.direction, coord),
                 transform=ax.transAxes,
                 horizontalalignment='left',
                 verticalalignment='bottom',
@@ -957,7 +963,7 @@ def add_markers(self, marker_coords, marker_color='r', marker_size=30,
 
     def annotate(self, left_right=True, positions=True, scalebar=False,
                  size=12, scale_size=5.0, scale_units='cm', scale_loc=4,
-                 **kwargs):
+                 decimals=0, **kwargs):
         """ Add annotations to the plot.
 
         Parameters
@@ -991,6 +997,9 @@ def annotate(self, left_right=True, positions=True, scalebar=False,
                     'lower center' : 8,
                     'upper center' : 9,
                     'center'       : 10
+        decimals: integer, optional
+            Number of decimal places on slice position annotation. If False (default),
+            the slice position is integer without decimal point.
         kwargs:
             Extra keyword arguments are passed to matplotlib's text
             function.
@@ -1012,6 +1021,7 @@ def annotate(self, left_right=True, positions=True, scalebar=False,
         if positions:
             for display_axis in self.axes.values():
                 display_axis.draw_position(size=size, bg_color=bg_color,
+                                           decimals=decimals,
                                            **kwargs)
 
         if scalebar:
diff --git a/nilearn/plotting/img_plotting.py b/nilearn/plotting/img_plotting.py
--- a/nilearn/plotting/img_plotting.py
+++ b/nilearn/plotting/img_plotting.py
@@ -117,6 +117,7 @@ def _plot_img_with_bg(img, bg_img=None, cut_coords=None,
                       display_factory=get_slicer,
                       cbar_vmin=None, cbar_vmax=None,
                       brain_color=(0.5, 0.5, 0.5),
+                      decimals=False,
                       **kwargs):
     """ Internal function, please refer to the docstring of plot_img for
         parameters not listed below.
@@ -191,7 +192,7 @@ def _plot_img_with_bg(img, bg_img=None, cut_coords=None,
                             **kwargs)
 
     if annotate:
-        display.annotate()
+        display.annotate(decimals=decimals)
     if draw_cross:
         display.draw_cross()
     if title is not None and not title == '':
@@ -289,6 +290,9 @@ def plot_img(img, cut_coords=None, output_file=None, display_mode='ortho',
         annotate: boolean, optional
             If annotate is True, positions and left/right annotation
             are added to the plot.
+        decimals: integer, optional
+            Number of decimal places on slice position annotation. If False (default),
+            the slice position is integer without decimal point.
         draw_cross: boolean, optional
             If draw_cross is True, a cross is drawn on the plot to
             indicate the cut plosition.


Test patch:
diff --git a/nilearn/plotting/tests/test_displays.py b/nilearn/plotting/tests/test_displays.py
--- a/nilearn/plotting/tests/test_displays.py
+++ b/nilearn/plotting/tests/test_displays.py
@@ -137,6 +137,12 @@ def test_annotations():
                          scale_size=2.5,
                          scale_units='cm',
                          scale_loc=3)
+
+
+def test_position_annotation_with_decimals():
+    # Test of decimals position annotation with precision of 2
+    orthoslicer = OrthoSlicer(cut_coords=(0, 0, 0))
+    orthoslicer.annotate(positions=True, decimals=2)
     orthoslicer.close()