Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rendering HoloMap as GIF with matplotlib/pillow fails under Windows #3151

Closed
smillies opened this Issue Nov 7, 2018 · 7 comments

Comments

Projects
None yet
4 participants
@smillies
Copy link

smillies commented Nov 7, 2018

I am trying to create an animated gif image from a series of heat maps with HoloViews. I need to do this in a Python script, i. e. specifically not in a Jupyter notebook. I am using Python 3.7 under Windows 10.

When saving the image, Python throws a PermissionError originating from PIL\Image.py line 1966 while manipulating a temporary file. However, it doesn't seem like a user permission problem, as it happens also for users with unrestricted rights. At the point the exception happens, the temporary file has already been created on the file system.

The same code runs as expected under CentOS 7. Here's an SSCE

Here's another minimal example by ImportanceOfBeingErnest that removes holoviews from the picture by making a direct call to matplotlib's FuncAnimation.save("fname", writer="pillow", fps=5). That works OK under Windows. So it looks like the holoviews save function might be broken.

ImportanceOfBeingErnest also played around a bit in the source code of holoviews and it also fails to save via imagemagick or imagemagick_file. (Although fixing this part of the issue is probably not a priority in view of #2460)

The source of this issue is this discussion on StackOverflow.

@philippjfr philippjfr added bug mpl labels Nov 7, 2018

@philippjfr

This comment has been minimized.

Copy link
Contributor

philippjfr commented Nov 7, 2018

Thanks @smillies, this detailed investigation is very helpful. None of the core developers use windows, which is probably why this hasn't been caught. Let's aim to get a fix for this into holoviews 1.11.0 due to be released next week.

@philippjfr philippjfr added this to the v1.11.0 milestone Nov 7, 2018

@jbednar

This comment has been minimized.

Copy link
Contributor

jbednar commented Nov 7, 2018

I think the hv code in question is:

with NamedTemporaryFile(suffix='.%s' % fmt) as f:
                anim.save(f.name, writer=writer, **anim_kwargs)
                video = f.read()

According to the Python docs, NamedTemporaryFile has different behavior in Windows:

Whether the name can be used to open the file a second time, while the named temporary file is still open, varies across platforms (it can be so used on Unix; it cannot on Windows NT or later).

I'm not sure what anim.save is in this case, but from that description, maybe @smillies could see if the file could be closed before anim.save and opened after for the reading step? Otherwise it would seem that anim.save would need to be rewritten to take a file handle instead of a file name, and in that case it's hard to see what the point of NamedTemporaryFile is on Windows...

@smillies

This comment has been minimized.

Copy link
Author

smillies commented Nov 8, 2018

I don't think that the suggestion by @jbednar of closing and reopening the file is an option, because the Python docs also state that a temporary file will be destroyed as soon as it is closed.

@xavArtley

This comment has been minimized.

Copy link

xavArtley commented Nov 8, 2018

On Bokeh a small hack is performed to make NamedTemporaryFile works on windows

test_themes.py

class TestThemes(object):

def test_construct_empty_theme_from_file(self):
      # windows will throw permissions error with auto-delete
      with (tempfile.NamedTemporaryFile(delete=False)) as file:
          # create and apply empty theme with no exception thrown
          file.file.write("".encode('utf-8'))
          file.file.flush()
          theme = Theme(filename=file.name)
          theme.apply_to_model(ThemedModel())
      file.close()
      os.remove(file.name)
@smillies

This comment has been minimized.

Copy link
Author

smillies commented Nov 8, 2018

Thanks for the hint, @xavArtley . Importing os and doing the same in renderer.py seems to do the trick.

# Windows will throw PermissionError with auto-delete
with NamedTemporaryFile(suffix='.%s' % fmt, delete=False) as f:
    anim.save(f.name, writer=writer, **anim_kwargs)
    video = f.read()
f.close()
os.remove(f.name)

I do not feel up to testing such a change and submitting a pull request for it. Would be grateful if someone could investigate the viability of this fix.

@philippjfr

This comment has been minimized.

Copy link
Contributor

philippjfr commented Nov 8, 2018

Thank you both, I can confirm that this change works for me. I'll submit a PR.

@philippjfr

This comment has been minimized.

Copy link
Contributor

philippjfr commented Nov 8, 2018

Tentatively closing, please reopen if it doesn't work for you.

@philippjfr philippjfr closed this Nov 8, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.