Repository: nilearn/nilearn

Issue:
[FIX] Preventing plot title overlapping content
<!---
This is a suggested pull request template for nilearn.
It's designed to capture information we've found to be useful in reviewing pull requests.

If there is other information that would be helpful to include, please don't hesitate to add it!

See here for more information on what is expected for pull requests:
https://github.com/nilearn/nilearn/blob/master/CONTRIBUTING.rst#pull-requests
-->

<!-- Please indicate after the # which issue you're closing with this PR.
This is helpful for the maintainers AND will magically close the issue when this
pull request is merged!
If the PR closes multiple issues, includes "closes" before each one is listed.
https://help.github.com/articles/closing-issues-using-keywords -->
Closes #2054.

<!-- Please give a brief overview of what has changed in the PR.
If you're not sure what to write, consider it a note to the maintainers to indicate
what they should be looking for when they review the pull request. -->
Changes proposed in this pull request:

- Changed the default y position for the title function in BaseSlicer class. Set to 1.08 rather that 0.99, enough to prevent even really long titles overlapping other elements.
<img width="985" alt="Screenshot 2021-05-06 at 10 00 46" src="https://user-images.githubusercontent.com/48333946/117271303-f28f6580-ae51-11eb-99e8-73bb8bfc7bd1.png">

Plot title overlays the image
Currently adding a title to a plot results in the title being drawn over the image, especially prominent if the title is long:

![image](https://user-images.githubusercontent.com/8203204/57656689-6dae4000-75d9-11e9-90be-3e2d21486f67.png)

Ideally, there should be a space between the title and the image below that.


Discussion:
# [Codecov](https://codecov.io/gh/nilearn/nilearn/pull/2804?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=nilearn) Report
> Merging [#2804](https://codecov.io/gh/nilearn/nilearn/pull/2804?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=nilearn) (78e7f33) into [master](https://codecov.io/gh/nilearn/nilearn/commit/034a0bc2df7e7242fafaf788c3eae2b5a94fa17f?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=nilearn) (034a0bc) will **increase** coverage by `0.02%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/nilearn/nilearn/pull/2804/graphs/tree.svg?width=650&height=150&src=pr&token=KpYArSdyXv&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=nilearn)](https://codecov.io/gh/nilearn/nilearn/pull/2804?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=nilearn)

```diff
@@            Coverage Diff             @@
##           master    #2804      +/-   ##
==========================================
+ Coverage   88.54%   88.56%   +0.02%     
==========================================
  Files         100      100              
  Lines       13392    13392              
  Branches     2608     2608              
==========================================
+ Hits        11858    11861       +3     
+ Misses        953      951       -2     
+ Partials      581      580       -1     
```


| [Impacted Files](https://codecov.io/gh/nilearn/nilearn/pull/2804?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=nilearn) | Coverage Δ | |
|---|---|---|
| [nilearn/plotting/displays.py](https://codecov.io/gh/nilearn/nilearn/pull/2804/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=nilearn#diff-bmlsZWFybi9wbG90dGluZy9kaXNwbGF5cy5weQ==) | `89.52% <100.00%> (ø)` | |
| [nilearn/plotting/img\_plotting.py](https://codecov.io/gh/nilearn/nilearn/pull/2804/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=nilearn#diff-bmlsZWFybi9wbG90dGluZy9pbWdfcGxvdHRpbmcucHk=) | `90.14% <0.00%> (ø)` | |
| [nilearn/reporting/\_get\_clusters\_table.py](https://codecov.io/gh/nilearn/nilearn/pull/2804/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=nilearn#diff-bmlsZWFybi9yZXBvcnRpbmcvX2dldF9jbHVzdGVyc190YWJsZS5weQ==) | `100.00% <0.00%> (+2.88%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/nilearn/nilearn/pull/2804?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=nilearn).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=nilearn)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/nilearn/nilearn/pull/2804?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=nilearn). Last update [034a0bc...78e7f33](https://codecov.io/gh/nilearn/nilearn/pull/2804?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=nilearn). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=nilearn).

I think it's done. @NicolasGensollen please could you make sure this is fine? I get a little confused in the updating pull requests world!
LGTM, but I think we should trigger a full doc rebuild to check that example figs render well...
Great, thanks! 
Let's wait for the CI to finish...
The problem now is that the title gets cut out of the img on plot_stat_map examples (see CircleCI).
> The problem now is that the title gets cut out of the img on plot_stat_map examples (see CircleCI).

Ah yep, I see what you mean. I guess the figure size works differently in Jupyter? I'll have another go!
I think part of the difficulty comes from the fact that the nilearn plotting functions make extensive use of `add_axes` to place axes in arbitrary, hard-coded positions in the figure as [here for example](https://github.com/nilearn/nilearn/blob/ae30ef6a4b622eff8a14750535449d4b38feee64/nilearn/plotting/displays.py#L1750) . using this approach rather than positions on grids with GridSpec and add_subplot prevents tight_layout from working and makes the layout more tricky to get right, especially when inputs can vary
addressing that would be a bigger change than was intended in this PR though, so maybe here if there really isn't enough space you can slightly increase the figure size (the `_default_figsize` of the `*Slicer` objects that need it)
Thanks @jeromedockes, I'll try increasing the default size. Is there a way to get the same outputs as running CircleCI when I'm checking my changes locally? The outputs of running the plotting examples either in jupyter or just as a script look different to me from the CircleCI outputs.
@OliverWarrington if you want to check the rendering of the docs locally, you can build it by running `make html-strict` from the `doc` subfolder. Note that this will build the whole documentation which usually takes around 1h30...
If you have already built it once, you can only rebuild the examples that you modified (see [here](http://nilearn.github.io/development.html#contributing-to-the-documentation) for more details).
@jeromedockes I was wondering regarding your proposed solution of changing the hardcoded `_default_figsize` if this could be done in a way that if a title is given a value can be added to the figsize y axis? This would be kind of like what is done with the colorbar in https://github.com/nilearn/nilearn/blob/1b7994104d08a117b859e784f3de567be87f0e59/nilearn/plotting/displays/_slicers.py#L136-L138

Do you think it could work?
> Do you think it could work?

I think so! although it probably isn't a big deal to increase a bit the figure size in all cases
That's indeed a bit annoying.
In `BaseSlicer` a title is added as just a text box, which makes it impossible to use matplotlib functionality like `tight_layout` to automatically adjust the subplots.
I can see two options to fix that: either add it as a title to the plot, then use `tight_layout` or check in the `title`function for the size of the created text and use `subplots_adjust` to shift the rest of the axes.
There are potentially some deep reasons that I couldn't glance from the code in `BaseSlicer` that prohibit using a title directly, but I can the first option a try in the next couple of days, and if it breaks revert to the second one.
I'd like to have a go at this please! Can I ask if there was any reason that prohibits using a title directly (mentioned above)? 
note the axes in which brains are shown don't provide `get_subplotspec` so `tight_layout` will show a warning and probably not work

Resolving patch:
diff --git a/nilearn/plotting/displays/_projectors.py b/nilearn/plotting/displays/_projectors.py
--- a/nilearn/plotting/displays/_projectors.py
+++ b/nilearn/plotting/displays/_projectors.py
@@ -297,7 +297,7 @@ class XProjector(OrthoProjector):
     """
 
     _cut_displayed = "x"
-    _default_figsize = [2.6, 2.3]
+    _default_figsize = [2.6, 3.0]
 
 
 class YProjector(OrthoProjector):
@@ -330,7 +330,7 @@ class YProjector(OrthoProjector):
     """
 
     _cut_displayed = "y"
-    _default_figsize = [2.2, 2.3]
+    _default_figsize = [2.2, 3.0]
 
 
 class ZProjector(OrthoProjector):
@@ -363,7 +363,7 @@ class ZProjector(OrthoProjector):
     """
 
     _cut_displayed = "z"
-    _default_figsize = [2.2, 2.3]
+    _default_figsize = [2.2, 3.4]
 
 
 class XZProjector(OrthoProjector):
@@ -468,6 +468,7 @@ class YZProjector(OrthoProjector):
     """
 
     _cut_displayed = "yz"
+    _default_figsize = [2.2, 3.4]
 
 
 class LYRZProjector(OrthoProjector):
@@ -663,7 +664,7 @@ class LProjector(OrthoProjector):
     """
 
     _cut_displayed = "l"
-    _default_figsize = [2.6, 2.3]
+    _default_figsize = [2.6, 3.0]
 
 
 class RProjector(OrthoProjector):
@@ -695,7 +696,7 @@ class RProjector(OrthoProjector):
     """
 
     _cut_displayed = "r"
-    _default_figsize = [2.6, 2.3]
+    _default_figsize = [2.6, 2.8]
 
 
 PROJECTORS = dict(
diff --git a/nilearn/plotting/displays/_slicers.py b/nilearn/plotting/displays/_slicers.py
--- a/nilearn/plotting/displays/_slicers.py
+++ b/nilearn/plotting/displays/_slicers.py
@@ -850,6 +850,7 @@ class OrthoSlicer(BaseSlicer):
 
     _cut_displayed = "yxz"
     _axes_class = CutAxes
+    _default_figsize = [2.2, 3.5]
 
     @fill_doc
     @classmethod
@@ -1079,7 +1080,7 @@ class TiledSlicer(BaseSlicer):
 
     _cut_displayed = "yxz"
     _axes_class = CutAxes
-    _default_figsize = [2.0, 6.0]
+    _default_figsize = [2.0, 7.6]
 
     @classmethod
     def find_cut_coords(cls, img=None, threshold=None, cut_coords=None):
@@ -1624,7 +1625,7 @@ class YSlicer(BaseStackedSlicer):
     """
 
     _direction = "y"
-    _default_figsize = [2.2, 2.3]
+    _default_figsize = [2.2, 3.0]
 
 
 class ZSlicer(BaseStackedSlicer):
@@ -1662,7 +1663,7 @@ class ZSlicer(BaseStackedSlicer):
     """
 
     _direction = "z"
-    _default_figsize = [2.2, 2.3]
+    _default_figsize = [2.2, 3.2]
 
 
 class XZSlicer(OrthoSlicer):
@@ -1774,6 +1775,7 @@ class YZSlicer(OrthoSlicer):
     """
 
     _cut_displayed = "yz"
+    _default_figsize = [2.2, 3.0]
 
 
 class MosaicSlicer(BaseSlicer):
@@ -1816,7 +1818,7 @@ class MosaicSlicer(BaseSlicer):
 
     _cut_displayed = "yxz"
     _axes_class = CutAxes
-    _default_figsize = [11.1, 7.2]
+    _default_figsize = [11.1, 20.0]
 
     @classmethod
     def find_cut_coords(cls, img=None, threshold=None, cut_coords=None):


Test patch: