holoviz / holoviews

With Holoviews, your data visualizes itself.
https://holoviews.org
BSD 3-Clause "New" or "Revised" License
2.7k stars 402 forks source link

Avoiding <matplotlib.figure.Figure at ......> #68

Closed basnijholt closed 9 years ago

basnijholt commented 9 years ago

I'm working with IPython notebook on a server over ssh. In order to avoid the error:


Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/holoviews/ipython/display_hooks.py", line 203, in wrapped
    **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/holoviews/ipython/display_hooks.py", line 233, in element_display
    **opts(element, get_plot_size(element, size)))()
  File "/usr/local/lib/python2.7/dist-packages/holoviews/plotting/raster.py", line 34, in __init__
    super(RasterPlot, self).__init__(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/holoviews/plotting/element.py", line 132, in __init__
    uniform=uniform, **dict(params, **plot_opts))
  File "/usr/local/lib/python2.7/dist-packages/holoviews/plotting/plot.py", line 114, in __init__
    self.handles['axis'] = self._init_axis(axis)
  File "/usr/local/lib/python2.7/dist-packages/holoviews/plotting/plot.py", line 248, in _init_axis
    fig = plt.figure()
  File "/usr/local/lib/python2.7/dist-packages/matplotlib/pyplot.py", line 435, in figure
    **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_qt4agg.py", line 47, in new_figure_manager
    return new_figure_manager_given_figure(num, thisFig)
  File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_qt4agg.py", line 54, in new_figure_manager_given_figure
    canvas = FigureCanvasQTAgg(figure)
  File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_qt4agg.py", line 72, in __init__
    FigureCanvasQT.__init__(self, figure)
  File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_qt4.py", line 68, in __init__
    _create_qApp()
  File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_qt5.py", line 138, in _create_qApp
    raise RuntimeError('Invalid DISPLAY variable')
RuntimeError: Invalid DISPLAY variable

One must evaluate

%matplotlib inline

This always results in <matplotlib.figure.Figure at 0x7fb61b7849d0> being under a HoloMap screen shot 2015-05-13 at 19 38 02

Of course normally this won't be an issue, but I'm using a HoloMap in a IPython presentation that I'm preparing. Would you know a way to get rid of this?

philippjfr commented 9 years ago

Yes this one is pretty annoying. We recommend always using the 'agg' backend. You can either specify the backend in your matplotlibrc file or do it in the notebook using:

from matplotlib import pyplot as plt
plt.switch_backend('agg')
jlstevens commented 9 years ago

I wonder what %matplotlib inline is doing - I assume it is also switching the backend?

philippjfr commented 9 years ago

Yep %matplotlib inline switches to agg and %matplotlib nbagg obviously switches to nbagg. I've actually seen other people using the %matplotlib inline trick to avoid getting display and TkAgg errors, not sure how we can make the proper solution more visible. Would there be any harm in setting the backend to agg explicitly when loading the extension? Should we even support other backends?

jlstevens commented 9 years ago

Hmm.. I am in favour of making 'agg' the default as long as this behaviour can also be disabled easily. We don't want to be accused of being rude!

The fact that %matplotlib inline switches to 'agg' makes me far less wary of making this behaviour default in our own extension. If we do go ahead with this, I agree it should only happen when loading the ipython extension.

It is a shame that you don't seem able to supply arguments when loading the extension, otherwise it would be easier to customize. As it is, I would recommend:

  1. Setting a global variable default_backend in __init__.py of the extension
  2. Switch to that backend in the load_ipython_extension function.
  3. If default_backend is set to None we can ignore it and not switch to anything.

My main worry is that this might be too late to take effect if matplotlib has been used at all anywhere else. What do you think?

basnijholt commented 9 years ago

When I use ``%%output backend='nbagg' I'm getting a lot of errors and plots, and in the end the kernel crashes.

screen shot 2015-05-13 at 21 52 21

jlstevens commented 9 years ago

Do you have a very recent version of matplotlib? Technically, I believe nbagg is still classified as an experimental feature - although it does seem stable enough in the very latest matplotlib release.

basnijholt commented 9 years ago

I'm using the latest stable release (1.4.3). Now trying it on my MacBook instead of on a hpc.

basnijholt commented 9 years ago

Tried it on my laptop (also latest stable versions of all packages, and master of HoloViews) and this time no errors, but a shitload of plots.

screen shot 2015-05-13 at 22 05 02

philippjfr commented 9 years ago

Ah sorry should have been clearer, %matplotlib nbagg should never be used directly when working with HoloViews. We do support %opts backend='nbagg' to select it as a backend for static figures and for widgets if %opts holomap='widgets' widgets='live' is enabled. %matplotlib nbagg enables plt.interactive(), which will generate a separate output for each frame in your HoloMap, as you see above.

basnijholt commented 9 years ago

Ah I see, but when I don't use %matplotlib nbagg or %matplotlib inline I get the following error:


Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/holoviews/ipython/display_hooks.py", line 203, in wrapped
    **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/holoviews/ipython/display_hooks.py", line 244, in map_display
    **opts(vmap, get_plot_size(vmap,size)))
  File "/usr/local/lib/python2.7/dist-packages/holoviews/plotting/element.py", line 497, in __init__
    super(OverlayPlot, self).__init__(overlay, ranges=ranges, **params)
  File "/usr/local/lib/python2.7/dist-packages/holoviews/plotting/element.py", line 132, in __init__
    uniform=uniform, **dict(params, **plot_opts))
  File "/usr/local/lib/python2.7/dist-packages/holoviews/plotting/plot.py", line 114, in __init__
    self.handles['axis'] = self._init_axis(axis)
  File "/usr/local/lib/python2.7/dist-packages/holoviews/plotting/plot.py", line 248, in _init_axis
    fig = plt.figure()
  File "/usr/local/lib/python2.7/dist-packages/matplotlib/pyplot.py", line 435, in figure
    **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_qt4agg.py", line 47, in new_figure_manager
    return new_figure_manager_given_figure(num, thisFig)
  File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_qt4agg.py", line 54, in new_figure_manager_given_figure
    canvas = FigureCanvasQTAgg(figure)
  File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_qt4agg.py", line 72, in __init__
    FigureCanvasQT.__init__(self, figure)
  File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_qt4.py", line 68, in __init__
    _create_qApp()
  File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_qt5.py", line 138, in _create_qApp
    raise RuntimeError('Invalid DISPLAY variable')
RuntimeError: Invalid DISPLAY variable
philippjfr commented 9 years ago

Did this suggestion not fix it?

Yes this one is pretty annoying. We recommend always using the 'agg' backend. You can either specify the backend in your matplotlibrc file or do it in the notebook using:

from matplotlib import pyplot as plt
plt.switch_backend('agg')
basnijholt commented 9 years ago

No, again a lot of plots.

Here http://stackoverflow.com/questions/2801882/generating-a-png-with-matplotlib-when-display-is-undefined

Someone says: "Important note: .use needs to be called before pyplot is imported. So if you are, for instance, just trying to import pyplot, you need to import matplotlib first, call use, and than import pyplot. "

Unfortunately this also doesn't make a difference.

basnijholt commented 9 years ago

OK, (maybe you already said this) but the trick is that I not use

%%output backend='nbagg'
philippjfr commented 9 years ago

Hmm.. I am in favour of making 'agg' the default as long as this behaviour can also be disabled easily. We don't want to be accused of being rude!

The fact that %matplotlib inline switches to 'agg' makes me far less wary of making this behaviour default in our own extension. If we do go ahead with this, I agree it should only happen when loading the ipython extension.

Agreed, 'agg' seems to be the only backend that's properly supported in the notebook. TkAgg and QtAgg both have issues when working remotely. I've encountered the same error as Bas on DICE machines and so have some of the guys on the Kaggle team.

It is a shame that you don't seem able to supply arguments when loading the extension, otherwise it would be easier to customize. As it is, I would recommend:

  1. Setting a global variable default_backend in __init__.py of the extension
  2. Switch to that backend in the load_ipython_extension function.
  3. If default_backend is set to None we can ignore it and not switch to anything.

My main worry is that this might be too late to take effect if matplotlib has been used at all anywhere else. What do you think?

plt.switch_backend seems to work pretty reliably for switching to 'agg' even if matplotlib has been used elsewhere so I think we don't have to worry too much.

philippjfr commented 9 years ago

OK, (maybe you already said this) but the trick is that I not use

%%output size=250 backend='nbagg'

Hmm, that's worrying. %%opts backend='nbagg' should work. If you don't mind, could you run this in a fresh kernel and report what happens?

import holoviews as hv
import numpy as np
%load_ext holoviews.ipython
%output holomap='widgets' widgets='live' backend='nbagg'
hv.HoloMap({i: hv.Image(np.random.rand(25,25)) for i in range(10)})
basnijholt commented 9 years ago

I added %load_ext holoviews.ipython

because of this error:

ERROR: Line magic function `%output` not found.
Out[2]:
:HoloMap   [Default]
   :Image   [x,y]   (z)

and then I got:

Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/holoviews/ipython/display_hooks.py", line 203, in wrapped
    **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/holoviews/ipython/display_hooks.py", line 244, in map_display
    **opts(vmap, get_plot_size(vmap,size)))
  File "/usr/local/lib/python2.7/dist-packages/holoviews/plotting/raster.py", line 34, in __init__
    super(RasterPlot, self).__init__(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/holoviews/plotting/element.py", line 132, in __init__
    uniform=uniform, **dict(params, **plot_opts))
  File "/usr/local/lib/python2.7/dist-packages/holoviews/plotting/plot.py", line 114, in __init__
    self.handles['axis'] = self._init_axis(axis)
  File "/usr/local/lib/python2.7/dist-packages/holoviews/plotting/plot.py", line 248, in _init_axis
    fig = plt.figure()
  File "/usr/local/lib/python2.7/dist-packages/matplotlib/pyplot.py", line 435, in figure
    **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_qt4agg.py", line 47, in new_figure_manager
    return new_figure_manager_given_figure(num, thisFig)
  File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_qt4agg.py", line 54, in new_figure_manager_given_figure
    canvas = FigureCanvasQTAgg(figure)
  File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_qt4agg.py", line 72, in __init__
    FigureCanvasQT.__init__(self, figure)
  File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_qt4.py", line 68, in __init__
    _create_qApp()
  File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_qt5.py", line 138, in _create_qApp
    raise RuntimeError('Invalid DISPLAY variable')
RuntimeError: Invalid DISPLAY variable
Out[3]:
:HoloMap   [Default]
   :Image   [x,y]   (z)
philippjfr commented 9 years ago

Sorry, I meant:

import holoviews as hv
import numpy as np
from matplotlib import pyplot as plt
plt.switch_backend('agg')
%load_ext holoviews.ipython
%output holomap='widgets' widgets='live' backend='nbagg'
hv.HoloMap({i: hv.Image(np.random.rand(25,25)) for i in range(10)})
basnijholt commented 9 years ago

On my MacBook I got this: screen shot 2015-05-13 at 22 41 24

philippjfr commented 9 years ago

That's the correct behavior. Do you still get the same error via your remote connection with the updated code?

basnijholt commented 9 years ago

For the last code that you provided it they look like the screenshot too (both on MacBook and hpc).

basnijholt commented 9 years ago

Without holomap='widgets' widgets='live' it plots 10 of the same plots.

philippjfr commented 9 years ago

Okay, that's a bug I'll have to look into. I'd recommend that you create a matplotlibrc file in one of the following locations on your hpc machine ~/.config/matplotlib/matplotlibrc or ~/.matplotlibrc, containing the following:

backend: agg 
philippjfr commented 9 years ago

Just made sure that the cached widget no longer generates multiple nbagg outputs when backend='nbagg' and widgets='embed'.

philippjfr commented 9 years ago

I've also just added:

backend: agg

to our default rc file, which means that unless you override it explicitly HoloViews will now always use the Agg backend. I think this addresses all the problems raised in this issue so I'll close it now.

sandeepteja17 commented 5 years ago

Yes this one is pretty annoying. We recommend always using the 'agg' backend. You can either specify the backend in your matplotlibrc file or do it in the notebook using:

from matplotlib import pyplot as plt
plt.switch_backend('agg')

thanks philippjfr. it helped me

SSZ1 commented 5 years ago

Did this suggestion not fix it?

Yes this one is pretty annoying. We recommend always using the 'agg' backend. You can either specify the backend in your matplotlibrc file or do it in the notebook using:

from matplotlib import pyplot as plt
plt.switch_backend('agg')

It helped me.Thanks.

github-actions[bot] commented 1 week ago

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.