Repository: mne-tools/mne-python

Issue:
Anti-aliasing in plots
I've noticed that most plots in MNE use the MPL default of `antialiasing=True` except for `plot_raw`, which specifically disables antialiasing. I'd argue that anti-aliasing makes for a much nicer look (for example `plot_pds` is a really nice representation of the spectrum for all channels), so I'd enable it also in `plot_raw`. What is the reason that this was disabled? With the current behavior, lines appear rather thick on some platforms, which doesn't appear to be the case if antialiasing is turned on.


Discussion:
It's purely for performance. It's still a bit slow with data that has many channels. That's also why decim parameter was introduced.
Hmmm. You probably know what I'm going to ask now :wink:

Any chance we could make this configurable (doesn't have to be public)?
Fine by me. Just occurred to me that this (and the escape button thing) could also be done in the mne config file.
Yes, why not. Could you give me a quick pointer where I need to look for this?
You should have a ``.mne`` folder in your home directory.
Alright. What's the preferred way to do this? I just put `mne.get_config('close_key', 'escape')` everywhere I need this value? Do we ever write it to the config file? If not I don't know if I really like this approach better, because this would mean that to change the default behavior I'd explicitly need to change the config file externally.

Also, currently the only thing stored in the config file is the window size for `plot_raw` in my case.
can we do it as for escape_key ie wihtout adding a new param?

Oh yes, definitely - this would be my preferred option.
Also, I just checked if there is any performance difference on my machine between antialiasing on and off. It's not noticeable, but `antialiasing=True` (combined with a line width of around `0.5`) looks much nicer.
Anti-aliasing off, line width 0.1:
![antialiasing_off](https://user-images.githubusercontent.com/4377312/28718181-1a6bdade-73a5-11e7-870c-05c3b5fa4dc3.png)

Anti-aliasing on, line width 0.5:
![antialiasing_on](https://user-images.githubusercontent.com/4377312/28718184-201a2580-73a5-11e7-9168-ef334a8fcd18.png)

If there's no clear evidence that anti-aliasing negatively impacts performance, we should discuss using anti-aliasing in `plot_raw` by default like in all other plots.
I can confirm on OSX at least that with `Qt4Agg` backend it makes little difference (~5% speed loss) when toggling `antialiased=True` in `mne/viz/raw.py` and using:
```
import time
import matplotlib
matplotlib.use('QtAgg')
import matplotlib.pyplot as plt
import mne
plt.ion()
raw = mne.io.read_raw_fif(mne.datasets.sample.data_path() + '/MEG/sample/sample_audvis_raw.fif', preload=True)
fig = raw.plot()
t0 = time.time()
for ii in range(20):
    fig.canvas.key_press_event('right')
print(time.time() - t0)
plt.close(fig)
```
It would be good if someone could also confirm on Linux (no access to that machine for me currently).
Here are some results from running the test on Arch Linux and Windows 10 (in a VM with Arch Linux as host). The column shows the average time (in s) over 5 repetitions.
```
macos MacOSX antialiased=False       0.791953
macos MacOSX antialiased=True        0.797703
macos Qt5Agg antialiased=False       5.640340
macos Qt5Agg antialiased=True        5.796852
Arch Qt5Agg antialiased=False       15.258201
Arch Qt5Agg antialiased=True        15.278452
Windows Qt5Agg antialiased=False     5.278124
Windows Qt5Agg antialiased=True      5.259347
```

Apparently, anti-aliasing does not have a negative performance impact.

Besides, the numbers are interesting for other reasons as well. For example, the MacOSX backend is about 7x faster than Qt5Agg. On Windows, the Qt5Agg backend is about as fast as on macOS, but on Linux it is about 3x as slow (ironically Windows runs in a VM on Linux). @Eric89GXL do you think your test measures performance of backends, or are there other factors that influence the results? I'm wondering if this should be reported to the MPL devs...
should we recommend certain backends then?

+1 for antialiased=True by default

> should we recommend certain backends then?

I'm not sure if these numbers allow comparing backends. I don't notice any difference between `Qt5Agg` and `MacOSX` in interactive plotting despite the 7x difference. If anything, I always felt that `Qt5Agg` was faster in some applications, such as plotting (or rather rotating) a 3D montage plot.

> +1 for antialiased=True by default

Just plotted the example data, this looks so much better. Let's make really sure that despite @Eric89GXL's and my results we do not impact performance (significantly) though. 
It probably measures mostly backend performance, yeah. Also note I excluded
the first draw, not sure if the initial draw changes things.

+1 for reenabling AA, thanks for checking OSes

OK, so I guess I'll create a short PR that re-enables AA.

But if these numbers are true, I wonder why the MacOSX backend is so much faster than Qt5Agg (quite the opposite of my experience). Furthermore, why is the performance of Qt5Agg so bad on Linux (granted it can't be compared directly to the performance on a Mac because these are 2 different machines, but the Windows test ran on the same machine and is 3x faster). Should we worry/panic :smile: (i.e. drop a message to the MPL devs) or just ignore it?

Resolving patch:
diff --git a/mne/viz/epochs.py b/mne/viz/epochs.py
--- a/mne/viz/epochs.py
+++ b/mne/viz/epochs.py
@@ -726,7 +726,7 @@ def _prepare_mne_browse_epochs(params, projs, n_channels, n_epochs, scalings,
     for ch_idx in range(n_channels):
         if len(colors) - 1 < ch_idx:
             break
-        lc = LineCollection(list(), antialiased=False, linewidths=0.5,
+        lc = LineCollection(list(), antialiased=True, linewidths=0.5,
                             zorder=3, picker=3.)
         ax.add_collection(lc)
         lines.append(lc)
@@ -1299,7 +1299,7 @@ def _plot_onkey(event, params):
         offset = ylim[0] / n_channels
         params['offsets'] = np.arange(n_channels) * offset + (offset / 2.)
         params['n_channels'] = n_channels
-        lc = LineCollection(list(), antialiased=False, linewidths=0.5,
+        lc = LineCollection(list(), antialiased=True, linewidths=0.5,
                             zorder=3, picker=3.)
         params['ax'].add_collection(lc)
         params['ax'].set_yticks(params['offsets'])
@@ -1418,7 +1418,7 @@ def _prepare_butterfly(params):
             used_types += 1
 
         while len(params['lines']) < len(params['picks']):
-            lc = LineCollection(list(), antialiased=False, linewidths=0.5,
+            lc = LineCollection(list(), antialiased=True, linewidths=0.5,
                                 zorder=3, picker=3.)
             ax.add_collection(lc)
             params['lines'].append(lc)
@@ -1481,7 +1481,7 @@ def _update_channels_epochs(event, params):
         params['ax'].collections.pop()
         params['lines'].pop()
     while len(params['lines']) < n_channels:
-        lc = LineCollection(list(), linewidths=0.5, antialiased=False,
+        lc = LineCollection(list(), linewidths=0.5, antialiased=True,
                             zorder=3, picker=3.)
         params['ax'].add_collection(lc)
         params['lines'].append(lc)
diff --git a/mne/viz/raw.py b/mne/viz/raw.py
--- a/mne/viz/raw.py
+++ b/mne/viz/raw.py
@@ -862,7 +862,7 @@ def _prepare_mne_browse_raw(params, title, bgcolor, color, bad_color, inds,
     ax.set_xlim(params['t_start'], params['t_start'] + params['duration'],
                 False)
 
-    params['lines'] = [ax.plot([np.nan], antialiased=False, linewidth=0.1)[0]
+    params['lines'] = [ax.plot([np.nan], antialiased=True, linewidth=0.5)[0]
                        for _ in range(n_ch)]
     ax.set_yticklabels(['X' * max([len(ch) for ch in info['ch_names']])])
     params['fig_annotation'] = None


Test patch: