NSLS-II-CSX / csxtools

Useful python tools for CSX (23-ID)
http://nsls-ii-csx.github.io/csxtools
Other
4 stars 13 forks source link

image_stack_to_movie bug in srv1 #62

Closed mpmdean closed 1 year ago

mpmdean commented 6 years ago

The latest csxtools version on srv1 seems to have a bug in the image_stack_to_movie function.

import numpy as np
import matplotlib.pyplot as plt
from csxtools.ipynb import image_stack_to_movie

%matplotlib nbagg

X, Y = np.meshgrid(np.linspace(-1, 1), np.linspace(-1, 1))

def gauss(X, Y, A, sigma):
    return A*np.exp(-(X**2+Y**2)/(2*sigma**2))

As = np.linspace(0.8, 1.2, 10)
sigmas = np.linspace(0.5, 0.7, 10)
stack = np.array([gauss(X, Y, A, sigma) for A, sigma in zip(As, sigmas)])

image_stack_to_movie(stack)

---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)
<ipython-input-3-8dcbc2cc7342> in <module>()
----> 1 image_stack_to_movie(stack)

/opt/conda_envs/analysis-2018-1.0/lib/python3.6/site-packages/csxtools/ipynb/animation.py in image_stack_to_movie(images, frames, vmin, vmax, figsize, cmap, fps)
    102     plt.close(anim._fig)
    103     # return anim.to_html5_video()
--> 104     return HTML(_anim_to_html(anim, fps))
    105 
    106 

/opt/conda_envs/analysis-2018-1.0/lib/python3.6/site-packages/csxtools/ipynb/animation.py in _anim_to_html(anim, fps)
    115             anim.save(f.name, fps=fps,
    116                       extra_args=['-vcodec', 'libx264',
--> 117                                   '-pix_fmt', 'yuv420p'])
    118             video = open(f.name, "rb").read()
    119         anim._encoded_video = base64.b64encode(video)

/opt/conda_envs/analysis-2018-1.0/lib/python3.6/site-packages/matplotlib/animation.py in save(self, filename, writer, fps, dpi, codec, bitrate, extra_args, metadata, extra_anim, savefig_kwargs)
   1061                         # TODO: See if turning off blit is really necessary
   1062                         anim._draw_next_frame(d, blit=False)
-> 1063                     writer.grab_frame(**savefig_kwargs)
   1064 
   1065         # Reconnect signal for first draw if necessary

/opt/conda_envs/analysis-2018-1.0/lib/python3.6/contextlib.py in __exit__(self, type, value, traceback)
     97                 value = type()
     98             try:
---> 99                 self.gen.throw(type, value, traceback)
    100             except StopIteration as exc:
    101                 # Suppress StopIteration *unless* it's the same exception that

/opt/conda_envs/analysis-2018-1.0/lib/python3.6/site-packages/matplotlib/animation.py in saving(self, *args, **kw)
    287             yield self
    288         finally:
--> 289             self.finish()
    290 
    291     def _run(self):

/opt/conda_envs/analysis-2018-1.0/lib/python3.6/site-packages/matplotlib/animation.py in finish(self)
    307     def finish(self):
    308         'Finish any processing for writing the movie.'
--> 309         self.cleanup()
    310 
    311     def grab_frame(self, **savefig_kwargs):

/opt/conda_envs/analysis-2018-1.0/lib/python3.6/site-packages/matplotlib/animation.py in cleanup(self)
    346     def cleanup(self):
    347         'Clean-up and collect the process used to write the movie file.'
--> 348         out, err = self._proc.communicate()
    349         self._frame_sink().close()
    350         verbose.report('MovieWriter -- '

/opt/conda_envs/analysis-2018-1.0/lib/python3.6/subprocess.py in communicate(self, input, timeout)
    836 
    837             try:
--> 838                 stdout, stderr = self._communicate(input, endtime, timeout)
    839             finally:
    840                 self._communication_started = True

/opt/conda_envs/analysis-2018-1.0/lib/python3.6/subprocess.py in _communicate(self, input, endtime, orig_timeout)
   1492                     selector.register(self.stdin, selectors.EVENT_WRITE)
   1493                 if self.stdout:
-> 1494                     selector.register(self.stdout, selectors.EVENT_READ)
   1495                 if self.stderr:
   1496                     selector.register(self.stderr, selectors.EVENT_READ)

/opt/conda_envs/analysis-2018-1.0/lib/python3.6/selectors.py in register(self, fileobj, events, data)
    349 
    350         def register(self, fileobj, events, data=None):
--> 351             key = super().register(fileobj, events, data)
    352             poll_events = 0
    353             if events & EVENT_READ:

/opt/conda_envs/analysis-2018-1.0/lib/python3.6/selectors.py in register(self, fileobj, events, data)
    235             raise ValueError("Invalid events: {!r}".format(events))
    236 
--> 237         key = SelectorKey(fileobj, self._fileobj_lookup(fileobj), events, data)
    238 
    239         if key.fd in self._fd_to_key:

/opt/conda_envs/analysis-2018-1.0/lib/python3.6/selectors.py in _fileobj_lookup(self, fileobj)
    222         """
    223         try:
--> 224             return _fileobj_to_fd(fileobj)
    225         except ValueError:
    226             # Do an exhaustive search.

/opt/conda_envs/analysis-2018-1.0/lib/python3.6/selectors.py in _fileobj_to_fd(fileobj)
     37         except (AttributeError, TypeError, ValueError):
     38             raise ValueError("Invalid file object: "
---> 39                              "{!r}".format(fileobj)) from None
     40     if fd < 0:
     41         raise ValueError("Invalid file descriptor: {}".format(fd))

ValueError: Invalid file object: <_io.BufferedReader name=52>
'''
tacaswell commented 6 years ago

is ffmpeg installed on the server?

mpmdean commented 6 years ago

@tacaswell I don't know. All I can say is that other kernals on srv1 do work. e.g. CSX on srv1 (legacy 2017-2 v0)

tacaswell commented 6 years ago

xref https://github.com/matplotlib/matplotlib/issues/9205

tacaswell commented 6 years ago

and xref https://github.com/matplotlib/matplotlib/issues/8760

tacaswell commented 6 years ago

I also get these warnings

/opt/conda_envs/analysis-2018-1.0/lib/python3.6/site-packages/matplotlib/animation.py:1021: UserWarning: MovieWriter ffmpeg unavailable
  warnings.warn("MovieWriter %s unavailable" % writer)
/opt/conda_envs/analysis-2018-1.0/lib/python3.6/site-packages/matplotlib/animation.py:1026: MatplotlibDeprecationWarning: Support for mencoder is only partially functional, and will be removed entirely in 2.2. Please use ffmpeg instead.
  metadata=metadata)
tacaswell commented 6 years ago

The issue is that:

a) we are hitting the system ffmpeg b) this version of debian provides a ffmpeg which is shim around avconv c) due to avconv being a hostile fork of ffmeg the cli of the two projects is diverging (which is how Matplotlib accesses them to save the movies) Matplotlib tried to ban the usage of the shims. d) The ban was implemented between 2.0.1 and 2.0.2 (https://github.com/matplotlib/matplotlib/pull/8253) but was a bit too heavy-handed and also broke the AVConvWriter which was fixed in 2.1 (https://github.com/matplotlib/matplotlib/pull/8743) e) for some reason the version of Matplotlib installed in the current environment has 2.0.2 installed which is the exactly 1 version of Matplotlib that has this bug f) the memencoder backend is not expecting the inputs that are being passed (which assumes it is talking to ffmpeg/avconv) which is what is blowing up in a less than clear way.

The best solution is to get your enviroment upgraded to a newer version of Matplotlib, the very dirty way to get this working which I will deny having told you:

import matplotlib.animation as ma
ma.FFMpegWriter.isAvailable = lambda: True
ma.writers.register('ffmpeg')(ma.FFMpegWriter)
licode commented 6 years ago

During debugging process, we also find conflicts within several libraries in order to update matplotlib to newer version. So the current solution is to update packages at srv1 during beam shutdown time, will keep updated here.

ambarb commented 5 years ago

What happened with this? We have rolled on to a new version of the conda env and still have this issue, but maybe now it is a different issue?

I find this now to be a problem for srv1 and 2 using (current), which I believe to be: analysis-2018-2.1 /opt/conda_envs/analysis-2018-2.1 I also see this with srv3, same conda environment version.

matplotlib: '2.2.2' csxtools: '0.1.13'

These systems have now been upgraded to debian 8. I am using %matplotlib widget with other plots okay.

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-28-cba7760ebe81> in <module>()
----> 1 image_stack_to_movie(sub_images, vmin=np.percentile(sub_images[1],30), vmax=np.percentile(sub_images[1],90))

/opt/conda_envs/analysis-2018-2.1/lib/python3.6/site-packages/csxtools/ipynb/animation.py in image_stack_to_movie(images, frames, vmin, vmax, figsize, cmap, fps)
    102     plt.close(anim._fig)
    103     # return anim.to_html5_video()
--> 104     return HTML(_anim_to_html(anim, fps))
    105 
    106 

/opt/conda_envs/analysis-2018-2.1/lib/python3.6/site-packages/csxtools/ipynb/animation.py in _anim_to_html(anim, fps)
    115             anim.save(f.name, fps=fps,
    116                       extra_args=['-vcodec', 'libx264',
--> 117                                   '-pix_fmt', 'yuv420p'])
    118             video = open(f.name, "rb").read()
    119         anim._encoded_video = base64.b64encode(video)

/opt/conda_envs/analysis-2018-2.1/lib/python3.6/site-packages/matplotlib/animation.py in save(self, filename, writer, fps, dpi, codec, bitrate, extra_args, metadata, extra_anim, savefig_kwargs)
   1198                         # TODO: See if turning off blit is really necessary
   1199                         anim._draw_next_frame(d, blit=False)
-> 1200                     writer.grab_frame(**savefig_kwargs)
   1201 
   1202         # Reconnect signal for first draw if necessary

/opt/conda_envs/analysis-2018-2.1/lib/python3.6/contextlib.py in __exit__(self, type, value, traceback)
     97                 value = type()
     98             try:
---> 99                 self.gen.throw(type, value, traceback)
    100             except StopIteration as exc:
    101                 # Suppress StopIteration *unless* it's the same exception that

/opt/conda_envs/analysis-2018-2.1/lib/python3.6/site-packages/matplotlib/animation.py in saving(self, fig, outfile, dpi, *args, **kwargs)
    239             yield self
    240         finally:
--> 241             self.finish()
    242 
    243 

/opt/conda_envs/analysis-2018-2.1/lib/python3.6/site-packages/matplotlib/animation.py in finish(self)
    365     def finish(self):
    366         '''Finish any processing for writing the movie.'''
--> 367         self.cleanup()
    368 
    369     def grab_frame(self, **savefig_kwargs):

/opt/conda_envs/analysis-2018-2.1/lib/python3.6/site-packages/matplotlib/animation.py in cleanup(self)
    403     def cleanup(self):
    404         '''Clean-up and collect the process used to write the movie file.'''
--> 405         out, err = self._proc.communicate()
    406         self._frame_sink().close()
    407         _log.debug('MovieWriter -- Command stdout:\n%s', out)

/opt/conda_envs/analysis-2018-2.1/lib/python3.6/subprocess.py in communicate(self, input, timeout)
    841 
    842             try:
--> 843                 stdout, stderr = self._communicate(input, endtime, timeout)
    844             finally:
    845                 self._communication_started = True

/opt/conda_envs/analysis-2018-2.1/lib/python3.6/subprocess.py in _communicate(self, input, endtime, orig_timeout)
   1503                     selector.register(self.stdin, selectors.EVENT_WRITE)
   1504                 if self.stdout:
-> 1505                     selector.register(self.stdout, selectors.EVENT_READ)
   1506                 if self.stderr:
   1507                     selector.register(self.stderr, selectors.EVENT_READ)

/opt/conda_envs/analysis-2018-2.1/lib/python3.6/selectors.py in register(self, fileobj, events, data)
    349 
    350         def register(self, fileobj, events, data=None):
--> 351             key = super().register(fileobj, events, data)
    352             poll_events = 0
    353             if events & EVENT_READ:

/opt/conda_envs/analysis-2018-2.1/lib/python3.6/selectors.py in register(self, fileobj, events, data)
    235             raise ValueError("Invalid events: {!r}".format(events))
    236 
--> 237         key = SelectorKey(fileobj, self._fileobj_lookup(fileobj), events, data)
    238 
    239         if key.fd in self._fd_to_key:

/opt/conda_envs/analysis-2018-2.1/lib/python3.6/selectors.py in _fileobj_lookup(self, fileobj)
    222         """
    223         try:
--> 224             return _fileobj_to_fd(fileobj)
    225         except ValueError:
    226             # Do an exhaustive search.

/opt/conda_envs/analysis-2018-2.1/lib/python3.6/selectors.py in _fileobj_to_fd(fileobj)
     37         except (AttributeError, TypeError, ValueError):
     38             raise ValueError("Invalid file object: "
---> 39                              "{!r}".format(fileobj)) from None
     40     if fd < 0:
     41         raise ValueError("Invalid file descriptor: {}".format(fd))

ValueError: Invalid file object: <_io.BufferedReader name=68>
ambarb commented 5 years ago

note that srv3 gives a different traceback

MovieWriter ffmpeg unavailable.

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
/opt/conda_envs/analysis-2018-2.1/lib/python3.6/site-packages/PIL/Image.py in save(self, fp, format, **params)
   1914             try:
-> 1915                 format = EXTENSION[ext]
   1916             except KeyError:

KeyError: '.mp4'

During handling of the above exception, another exception occurred:

ValueError                                Traceback (most recent call last)
<ipython-input-16-cba7760ebe81> in <module>()
----> 1 image_stack_to_movie(sub_images, vmin=np.percentile(sub_images[1],30), vmax=np.percentile(sub_images[1],90))

/opt/conda_envs/analysis-2018-2.1/lib/python3.6/site-packages/csxtools/ipynb/animation.py in image_stack_to_movie(images, frames, vmin, vmax, figsize, cmap, fps)
    102     plt.close(anim._fig)
    103     # return anim.to_html5_video()
--> 104     return HTML(_anim_to_html(anim, fps))
    105 
    106 

/opt/conda_envs/analysis-2018-2.1/lib/python3.6/site-packages/csxtools/ipynb/animation.py in _anim_to_html(anim, fps)
    115             anim.save(f.name, fps=fps,
    116                       extra_args=['-vcodec', 'libx264',
--> 117                                   '-pix_fmt', 'yuv420p'])
    118             video = open(f.name, "rb").read()
    119         anim._encoded_video = base64.b64encode(video)

/opt/conda_envs/analysis-2018-2.1/lib/python3.6/site-packages/matplotlib/animation.py in save(self, filename, writer, fps, dpi, codec, bitrate, extra_args, metadata, extra_anim, savefig_kwargs)
   1198                         # TODO: See if turning off blit is really necessary
   1199                         anim._draw_next_frame(d, blit=False)
-> 1200                     writer.grab_frame(**savefig_kwargs)
   1201 
   1202         # Reconnect signal for first draw if necessary

/opt/conda_envs/analysis-2018-2.1/lib/python3.6/contextlib.py in __exit__(self, type, value, traceback)
     86         if type is None:
     87             try:
---> 88                 next(self.gen)
     89             except StopIteration:
     90                 return False

/opt/conda_envs/analysis-2018-2.1/lib/python3.6/site-packages/matplotlib/animation.py in saving(self, fig, outfile, dpi, *args, **kwargs)
    239             yield self
    240         finally:
--> 241             self.finish()
    242 
    243 

/opt/conda_envs/analysis-2018-2.1/lib/python3.6/site-packages/matplotlib/animation.py in finish(self)
    610         self._frames[0].save(
    611             self._outfile, save_all=True, append_images=self._frames[1:],
--> 612             duration=int(1000 / self.fps))
    613 
    614 

/opt/conda_envs/analysis-2018-2.1/lib/python3.6/site-packages/PIL/Image.py in save(self, fp, format, **params)
   1915                 format = EXTENSION[ext]
   1916             except KeyError:
-> 1917                 raise ValueError('unknown file extension: {}'.format(ext))
   1918 
   1919         if format.upper() not in SAVE:

ValueError: unknown file extension: .mp4
ambarb commented 5 years ago

came back to the problem with matplotlib at 2.2.2

ffmpeg was not installed on the computer and as Tom said, we cannot use the ffmpeg in python. This is the workaround that I found because the lines of code he provided still didn't work for me.

1) update apt-get and install ffmpeg on the server. (on srv1 only. still need to do this for srv2) 2) using the "current" srv1 kernel, add the following to notebook before creating the movie.

plt.rcParams['animation.ffmpeg_path'] = '/usr/bin/ffmpeg'

are we good with closing this for now? Or do we want to wait until there is a perfect solution?

ambarb commented 5 years ago

to download movie, use Classic Notebook View, under Help

ambarb commented 3 years ago

@ambarb verify for current matplotlib version

ambarb commented 1 year ago

@mpmdean this function works now magically at jupyter.nsls2.bnl.gov so I will close this issue.

mrakitin commented 1 year ago

I think it's because ffmpeg is now installed as a system package in Docker/Singularity as instructed in https://github.com/NSLS-II/scipy-binder/blob/a1a7e867e329b18ee18f05687727dff2eb3cc318/binder/apt.txt#L3.