Repository: nilearn/nilearn

Issue:
add_contours(filled=True) requires to specify color and alpha
Code to reproduce

<pre>
from nilearn import datasets

localizer_dataset = datasets.fetch_localizer_button_task()
localizer_tmap_filename = localizer_dataset.tmaps[0]

from nilearn import plotting
glass_brain = plotting.plot_glass_brain(None)

glass_brain.add_contours(localizer_tmap_filename, filled=True,
                         levels=[3, ], colors=['g', ], alpha=1)
</pre>


This doesn't run if I don't specify colors and alpha. It does if I don't use filled=True. I really should have to worry about colors, and alpha: it should work the same way in both cases.



Discussion:

Resolving patch:
diff --git a/examples/01_plotting/plot_demo_glass_brain_extensive.py b/examples/01_plotting/plot_demo_glass_brain_extensive.py
--- a/examples/01_plotting/plot_demo_glass_brain_extensive.py
+++ b/examples/01_plotting/plot_demo_glass_brain_extensive.py
@@ -87,8 +87,8 @@
                           plot_abs=False, display_mode='lyrz')
 
 ###############################################################################
-# Demo glass brain plotting with contours
-# ----------------------------------------
+# Demo glass brain plotting with contours and with fillings
+# ---------------------------------------------------------
 # To plot maps with contours, we call the plotting function into variable from
 # which we can use specific display features which are inherited automatically.
 # In this case, we focus on using add_contours
@@ -102,7 +102,17 @@
 display.title('"tmap_filename" on glass brain without threshold')
 
 ###############################################################################
-# With specific level (cut-off) in the statistical map
+# Plotting with `filled=True` implies contours with fillings. Here, we are not
+# specifying levels
+display = plotting.plot_glass_brain(None)
+# Here, we project statistical maps with filled=True
+display.add_contours(tmap_filename, filled=True)
+# and a title
+display.title('Same map but with fillings in the contours')
+
+###############################################################################
+# Here, we input specific level (cut-off) in the statistical map. In other way,
+# we are thresholding our statistical map
 
 # Here, we set the threshold using parameter called `levels` with value given
 # in a list and choosing color to Red.
@@ -110,42 +120,96 @@
 display.add_contours(tmap_filename, levels=[3.], colors='r')
 display.title('"tmap_filename" on glass brain with threshold')
 
+###############################################################################
+# Plotting with same demonstration but inlcudes now filled=True
+display = plotting.plot_glass_brain(None)
+display.add_contours(tmap_filename, filled=True, levels=[3.], colors='r')
+display.title('Same demonstration but using fillings inside contours')
+
 ##############################################################################
-# Black background
+# Plotting with black background, `black_bg` should be set with
+# `plot_glass_brain`
 
 # We can set black background using black_bg=True
 display = plotting.plot_glass_brain(None, black_bg=True)
 display.add_contours(tmap_filename, levels=[3.], colors='g')
 display.title('"tmap_filename" on glass brain with black background')
 
+##############################################################################
+# Black background plotting with filled in contours
+display = plotting.plot_glass_brain(None, black_bg=True)
+display.add_contours(tmap_filename, filled=True, levels=[3.], colors='g')
+display.title('Glass brain with black background and filled in contours')
+
 ##############################################################################
 # Display contour projections in both hemispheres
 # -------------------------------------------------
+# Key argument to vary here is `display_mode` for hemispheric plotting
 
 # Now, display_mode is chosen as 'lr' for both hemispheric plots
 display = plotting.plot_glass_brain(None, display_mode='lr')
 display.add_contours(tmap_filename, levels=[3.], colors='r')
 display.title('"tmap_filename" on glass brain only "l" "r" hemispheres')
+
+##############################################################################
+# Filled contours in both hemispheric plotting, just by adding filled=True
+display = plotting.plot_glass_brain(None, display_mode='lr')
+display.add_contours(tmap_filename, filled=True, levels=[3.], colors='r')
+display.title('Filled contours on glass brain only "l" "r" hemispheres')
+
 ##############################################################################
-# With positive and negative sign of activations
+# With positive and negative sign of activations with `plot_abs` in
+# `plot_glass_brain`
 
-# By default parameter `plot_abs` is True and sign of activations can done by
-# changing `plot_abs` to False
+# By default parameter `plot_abs` is True and sign of activations can be
+# displayed by changing `plot_abs` to False
 display = plotting.plot_glass_brain(None, plot_abs=False, display_mode='lzry')
 display.add_contours(tmap_filename)
 display.title("Contours with both sign of activations without threshold")
 
 ##############################################################################
-# Both sign (positive and negative) of activations with threshold
+# Now, adding just filled=True to get positive and negative sign activations
+# with fillings in the contours
+display = plotting.plot_glass_brain(None, plot_abs=False, display_mode='lzry')
+display.add_contours(tmap_filename, filled=True)
+display.title("Filled contours with both sign of activations without threshold")
+
 
-# positive threshold implies positive value in a list and negative threshold
-# implies negative value (both values are used as cut-off)
+##############################################################################
+# Displaying both signs (positive and negative) of activations with threshold
+# meaning thresholding by adding an argument `levels` in add_contours.
+
+import numpy as np
 display = plotting.plot_glass_brain(None, plot_abs=False, display_mode='lzry')
-# positive level and negative level and each level with different colors as a
-# list. Additionally, with thick line widths
+
+# In add_contours,
+# we give two values through the argument `levels` which corresponds to the
+# thresholds of the contour we want to draw: One is positive and the other one
+# is negative. We give a list of `colors` as argument to associate a different
+# color to each contour. Additionally, we also choose to plot contours with
+# thick line widths, For linewidths one value would be enough so that same
+# value is used for both contours.
 display.add_contours(tmap_filename, levels=[-2.8, 3.], colors=['b', 'r'],
                      linewidths=4.)
-display.title('Contours with both sign of activations with threshold')
+display.title('Contours with sign of activations with threshold')
+
+##############################################################################
+# Same display demonstration as above but just adding filled=True to get
+# fillings inside the contours.
+
+# Unlike in previous plot, here we specify each sign at a time. We call negative
+# values display first followed by positive values display.
+
+# First, we fetch our display object with same parametes used as above
+display = plotting.plot_glass_brain(None, plot_abs=False, display_mode='lzry')
+
+# Second, we plot negative sign of activation with levels given as negative
+# activation value in a list. Upper bound should be kept to -infinity
+display.add_contours(tmap_filename, filled=True, levels=[-np.inf, -2.8],
+                     colors='b')
+# Next, within same plotting object we plot positive sign of activation
+display.add_contours(tmap_filename, filled=True, levels=[3.], colors='r')
+display.title('Now same plotting but with filled contours')
 
 # Finally, displaying them
 plotting.show()
diff --git a/nilearn/datasets/func.py b/nilearn/datasets/func.py
--- a/nilearn/datasets/func.py
+++ b/nilearn/datasets/func.py
@@ -155,7 +155,7 @@ def fetch_haxby(data_dir=None, n_subjects=None, subjects=(2,),
     if isinstance(subjects, numbers.Number) and subjects > 6:
         subjects = 6
 
-    if subjects is not None and (isinstance(subjects, list) or 
+    if subjects is not None and (isinstance(subjects, list) or
                                  isinstance(subjects, tuple)):
         for sub_id in subjects:
             if sub_id not in [1, 2, 3, 4, 5, 6]:
diff --git a/nilearn/plotting/displays.py b/nilearn/plotting/displays.py
--- a/nilearn/plotting/displays.py
+++ b/nilearn/plotting/displays.py
@@ -596,7 +596,7 @@ def add_overlay(self, img, threshold=1e-6, colorbar=False, **kwargs):
 
         plt.draw_if_interactive()
 
-    def add_contours(self, img, filled=False, **kwargs):
+    def add_contours(self, img, threshold=1e-6, filled=False, **kwargs):
         """ Contour a 3D map in all the views.
 
         Parameters
@@ -604,26 +604,35 @@ def add_contours(self, img, filled=False, **kwargs):
         img: Niimg-like object
             See http://nilearn.github.io/manipulating_images/input_output.html.
             Provides image to plot.
+        threshold: a number, None
+            If None is given, the maps are not thresholded.
+            If a number is given, it is used to threshold the maps,
+            values below the threshold (in absolute value) are plotted
+            as transparent.
         filled: boolean, optional
             If filled=True, contours are displayed with color fillings.
         kwargs:
             Extra keyword arguments are passed to contour, see the
-            documentation of pylab.contour
+            documentation of pylab.contour and see pylab.contourf documentation
+            for arguments related to contours with fillings.
             Useful, arguments are typical "levels", which is a
-            list of values to use for plotting a contour, and
+            list of values to use for plotting a contour or contour
+            fillings (if filled=True), and
             "colors", which is one color or a list of colors for
             these contours.
+            Note: if colors are not specified, default coloring choices
+            (from matplotlib) for contours and contour_fillings can be
+            different.
         """
         self._map_show(img, type='contour', **kwargs)
         if filled:
-            colors = kwargs['colors']
-            levels = kwargs['levels']
-            if len(levels) <= 1:
-                # contour fillings levels should be given as (lower, upper).
-                levels.append(np.inf)
-            alpha = kwargs['alpha']
-            self._map_show(img, type='contourf', levels=levels, alpha=alpha,
-                           colors=colors[:3])
+            if 'levels' in kwargs:
+                levels = kwargs['levels']
+                if len(levels) <= 1:
+                    # contour fillings levels should be given as (lower, upper).
+                    levels.append(np.inf)
+
+            self._map_show(img, type='contourf', threshold=threshold, **kwargs)
 
         plt.draw_if_interactive()
 


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
@@ -52,3 +52,14 @@ def test_contour_fillings_levels_in_add_contours():
     # In this case, we simply omit appending inf
     oslicer.add_contours(img, filled=True, colors='b',
                          alpha=0.1, levels=[0., 0.2])
+
+    # without passing colors and alpha. In this case, default values are
+    # chosen from matplotlib
+    oslicer.add_contours(img, filled=True, levels=[0., 0.2])
+
+    # levels with only one value
+    oslicer.add_contours(img, filled=True, levels=[0.])
+
+    # without passing levels, should work with default levels from
+    # matplotlib
+    oslicer.add_contours(img, filled=True)