Repository: nilearn/nilearn

Issue:
BUG: nilearn.plotting forces matplotlib backend change to Agg on macOS
on macOS:
```
>>> import matplotlib
>>> assert matplotlib.get_backend() == 'Qt5Agg'
>>> import nilearn.plotting
>>> assert matplotlib.get_backend() == 'Qt5Agg', matplotlib.get_backend()
AssertionError: agg
```
I have `backend : Qt5Agg\ninteractive : True` in `~/.matplotlib/matplotlibrc`. I assume it's due to this line:

https://github.com/nilearn/nilearn/blob/master/nilearn/plotting/__init__.py#L37

It seems like unwanted behavior that the backend is changed.


Discussion:
@kchawla-pi  can you give any hint on why this was added ? 

What other backend should be used instead (sorry I don't know that well) ?
My 2c is that in general libraries should not set the matplotlib backend at all but respect whatever the given user's configuration is (even if it's just "use the matplotlib default")

> My 2c is that in general libraries should not set the matplotlib backend at all but respect whatever the given user's configuration is (even if it's just "use the matplotlib default")

I agree.
(if CI was the motivation for doing this we can set the `MPLBACKEND` env
variable)

The motivation for doing this was that non technical users ssh into a remote  computer, run calculations, and then things crash after two hours of computation because there is no X server available. 

We tried to put some guards so that the switch happens only in a case where it's likely to be useful. Maybe those guards aren't fine enough. I believe that they are in plotting/__init__.py

⁣Sent from my phone. Please forgive typos and briefness.​

On Aug 27, 2020, 23:55, at 23:55, jeromedockes <notifications@github.com> wrote:
>
>> My 2c is that in general libraries should not set the matplotlib
>backend at all but respect whatever the given user's configuration is
>(even if it's just "use the matplotlib default")
>
>I agree.
>(if CI was the motivation for doing this we can set the `MPLBACKEND`
>env
>variable)
>
>
>-- 
>You are receiving this because you are subscribed to this thread.
>Reply to this email directly or view it on GitHub:
>https://github.com/nilearn/nilearn/issues/2560#issuecomment-682210850

This should not be a problem on MacOS. The code is specifically checking
for that and not changing the backend on MacOS. Perhaps the check is too
stringent with a new version of MacOS?

On Fri, Aug 28, 2020, 07:30 Gael Varoquaux <notifications@github.com> wrote:

> The motivation for doing this was that non technical users ssh into a
> remote  computer, run calculations, and then things crash after two hours
> of computation because there is no X server available.
>
> We tried to put some guards so that the switch happens only in a case
> where it's likely to be useful. Maybe those guards aren't fine enough. I
> believe that they are in plotting/__init__.py
>
> ⁣Sent from my phone. Please forgive typos and briefness.​
>
> On Aug 27, 2020, 23:55, at 23:55, jeromedockes <notifications@github.com>
> wrote:
> >
> >> My 2c is that in general libraries should not set the matplotlib
> >backend at all but respect whatever the given user's configuration is
> >(even if it's just "use the matplotlib default")
> >
> >I agree.
> >(if CI was the motivation for doing this we can set the `MPLBACKEND`
> >env
> >variable)
> >
> >
> >--
> >You are receiving this because you are subscribed to this thread.
> >Reply to this email directly or view it on GitHub:
> >https://github.com/nilearn/nilearn/issues/2560#issuecomment-682210850
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <https://github.com/nilearn/nilearn/issues/2560#issuecomment-682333518>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AB6SXRAWDHDXQYOQ3RXRUNTSC46GLANCNFSM4QNH3HNQ>
> .
>

The conditional is:
```
        if (os.name == 'posix' and 'DISPLAY' not in os.environ
                and not (sys.platform == 'darwin'
                         and 'macosx' in current_backend)
        ):
            matplotlib.use('Agg')
```
So if someone is on macOS and their backend is not `macosx`, their backend will be set to `agg`. In my case, my backend is `Qt5Agg`, so it gets set to `agg`, which is not good.
@larsoner Sorry for the inconvenience. Would you like to open a PR ?
Best,
Personally I would chalk this up to a matplotlib / user config problem -- mpl or the user should choose a backend that works on their system.

But assuming you want to keep some fix in place, one option would be to `try/except` something like `plt.figure()` and force to Agg if it fails.

Beyond that, I'm still not entirely clear on why there is even a check for `darwin` as the platform. Shouldn't it rather be a check that the platform is Linux but there is no display, so just `sys.platform == 'linux' and 'DISPLAY' not in environ`? I've never seen a macOS headless system. On CIs they always fall back to software rendering at least...
> Beyond that, I'm still not entirely clear on why there is even a check for darwin as the platform. Shouldn't it rather be a check that the platform is Linux but there is no display, so just sys.platform == 'linux' and 'DISPLAY' not in environ?

There are other unices than macosx and linux. Maybe these are no much
used these days. I used to encounter them in high performance and
academic environments.


So perhaps the check should just be `if sys.platform not in ('darwin', 'win32') and 'DISPLAY' not in os.environ`?
Sounds right to me.

Resolving patch:
diff --git a/nilearn/plotting/__init__.py b/nilearn/plotting/__init__.py
--- a/nilearn/plotting/__init__.py
+++ b/nilearn/plotting/__init__.py
@@ -30,12 +30,12 @@ def _set_mpl_backend():
         if 'inline' in current_backend or 'nbagg' in current_backend:
             return
         # Set the backend to a non-interactive one for unices without X
-        if (os.name == 'posix' and 'DISPLAY' not in os.environ
-                and not (sys.platform == 'darwin'
-                         and 'macosx' in current_backend)
-        ):
+        # (see gh-2560)
+        if (sys.platform not in ('darwin', 'win32') and
+                'DISPLAY' not in os.environ):
             matplotlib.use('Agg')
 
+
 _set_mpl_backend()
 
 ###############################################################################


Test patch: