-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
endless looping GIFs with PillowWriter #11789
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
Conversation
Checklist 1: I have no idea how I would create a pytest for this. Checklist 3,4: I want to add the loop parameter to the Checklist 5: It's a minor new feature. So, I shouldn't add this? |
3/4 Maybe just in the MovieWriter doc string say that loop exists if the writer is Pillow. For triple bonus points you could look into the other writers and see if there is a loop method for those. |
In some respects, this could be considered a bugfix. The original gif
writer that uses ImageMagick produces endless loop GIFs. I don't think
there is an API parameter for that writer as well.
…On Sat, Jul 28, 2018 at 9:34 AM, Jody Klymak ***@***.***> wrote:
1. can you interrogate the gif header for the loop parameter? Probably
not so important for a test here.
3/4 Maybe just in the MovieWriter doc string say that loop exists if the
writer is Pillow. For triple bonus points you could look into the other
writers and see if there is a loop method for those.
5/6 I think a whats new entry is good, but no need for an API entry -
thats generally only if API is changed, not if some is added.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#11789 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AARy-EvtAIRCtbVQ0avD7vZOmx1C2g9Vks5uLGhZgaJpZM4Vk6qM>
.
|
Oh, well in that case it’d be good to quickly go through the writers and document their behaviour. |
I think this is just since the next_whats_new toctree is commented out in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
anyone can dismiss once comments handled
lib/matplotlib/animation.py
Outdated
@@ -557,6 +557,7 @@ def isAvailable(cls): | |||
def __init__(self, *args, **kwargs): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
__init__(self, *args, loop=False, **kwargs)
or at least make it a boolean.
Argument needs to be documented in some docstring.
Please check for API consistency across writers; if the behavior of other writers is to loop then the default should be changed here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Pillow image.save function takes the loop
parameter as an integer, so a gif could be make to loop a set number of times. Also, loop=False
might make sense in the docstring, but loop=self.loop
where self.loop
is False
is an endless loop since False==0
. I suppose I could change it to loop=not self.loop
, but should we not allow setting to loop say 5 times?
I'll change it to a Boolean if you still want. (I suppose no one needs a gif to loop exactly 137 times!)
I like the move to the loop
kwarg in the __init__
function definition. I'll do that for sure.
HTMLWriter and ImageMagick both default to looping I believe, but the ffmpegwriter writing to a .mp4 wouldn't loop. Whether defaulting to loop or not really depends on the format. Gif's should loop, mp4's can't. Different formats have different looping properties (HTMLWriter has a 'reflect' option, so it has a default_mode
parameter that takes a string instead of a loop
parameter.
I'll default it to looping (unless you object).
I know that I need to put it in a docstring, but I'm having difficulty figuring out where. I'm not familiar with sphinx-autodoc. I really could use help here. I could write an entire new docstring based off the base class and add the parameter. Or I could do as @jklymak suggested, but then other writers would have a "loop parameter only available in PillowWriter".
@@ -0,0 +1,7 @@ | |||
Looping GIFs with PillowWriter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something went wrong with the formatting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the file has windows line endings. I will change that. Other than that I don't know.
I think you could accept a Boolean and convert to an integer internally; just check if a Boolean. OTOH it’s a bit confusing that 0 is loop and 1 is loop only once. Agree that specifying the number loops is desiarable option |
I suppose I could do
then set the default to What do people think? |
More that I think about it maybe just make it an integer and value error on anything else so the Boolean doesn’t get passed by accident. Maybe just lay out the options here and folks can vote 🗳 (I’d do it but am on phone). Sorry to drag out a simple change but may as well get it right. |
Option 1:
Cons:
Implemented as self.loop = not loop Option 2:
Cons:
Implemented as # can't use isinstance since bools are ints
if type(loop) == int:
self.loop = loop
else:
raise ValueError("loop must be an int") Option 3:
Cons:
Implemented as self.loop = not loop if isinstance(loop, bool) else loop Documentation will be updated to reflect whatever choice. |
I vote 2 + ValueError, just because I think loop=False will actually pass loop=0 if its not caught, but I may be wrong. |
I added the ValueError. If we did want to support both bools and ints in the future, then it is easier to add that, then it is to remove support for bools after the fact. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 on the functionality. Minor tweak to the int
check if you're interested.
lib/matplotlib/animation.py
Outdated
@@ -554,7 +554,38 @@ def isAvailable(cls): | |||
return False | |||
return True | |||
|
|||
def __init__(self, *args, **kwargs): | |||
def __init__(self, *args, loop=0, **kwargs): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So much easier to do this now that we're Python 3 only.
lib/matplotlib/animation.py
Outdated
output file. Some keys that may be of use include: | ||
title, artist, genre, subject, copyright, srcform, comment. | ||
''' | ||
if type(loop) == int: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if not isinstance(loop, int):
raise ValueError(...)
self.loop = loop
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bools are ints. So not isinstance(True, int)
will return false. Which will result in passing a value of True
aka 1
to loop which won't loop, but one would expect loop=True to loop. See my option 3 for a way to implement support for both bools and ints, but this will force just ints
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Though I suppose
if type(loop) != int:
raise ValueError(...)
self.loop=loop
But it only saves one of code, and I don't really feel like pushing another commit to this unless I have too 😛.
One other question on further thought: since this is not a boolean flag, but a number of loops, should the parameter be |
That's not a bad point. But I think that the plural |
I am looking through the animation module at the moment and based on the available options in all writers at the moment I would say that we could just add unlimited looping also in the pillow writer without any option to change it. Most people want it anyway (but I am not against the option). I think that a refractoring or at least change in documentation about kwargs should be done in the animation module. At the moment the parameters to the pillow writer are something like, So a new API or documentation that clearly show what options that are used in a writer and adding new relevant options should be good. I have started to change some of the documentation to show which kwargs that are actually used and how. I would suggest to just add the unlimited looping functionality in a pr and the rest in other prs. Do this really need a test? |
lib/matplotlib/animation.py
Outdated
loop: int | ||
The number of times that the gif will loop. | ||
A value of 0 is endless. | ||
codec: string or None, optional |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The rest of the options are just ignored in the pillow writer so I don't think that they should be documented.
Changing that line worked for me. I think that both the pillow- and imagemagick writer API should be the same. One possibility that are not perfect but is in accordance with the current implementation is to put the new kwarg in When both imagemagick and pillow seems to use ints for number of loops with 0 as infinity I think that we should stick to that notation. Edit: So I believe that all new kwargs should be in |
Sorry it's been a while. In the interest in getting this bug fix done (and leaving me time for my thousand other projects), I've removed all API changes. This PR now does 2 things:
I'll leave any refractoring/API changes to someone more familiar with this API than me. This PR is now the minimum needed to fix #11789. The suggested |
lib/matplotlib/animation.py
Outdated
---------- | ||
fps: int | ||
Framerate for the gif. | ||
''' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kill the docstring as well for now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure.
Endless Looping GIFs with PillowWriter | ||
-------------------------------------- | ||
|
||
We acknowledge that most people want to watch a gif more than once. Saving an animatation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo (animatation)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Silly me. Fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
modulo typo in whatsnew
@dopplershift I dismissed your review as the scope of the PR has changed; can you check it again?
Ok, I fixed the typo. I believe the doc failures are due to sphinx 1.8.0. |
We should have fixed the doc builds now; can you rebase to see if everything's working again? |
Last time I tried to rebase a fork, I really messed up the commit history. Any advice? |
You should have branched your fork before submitting this PR. Right now your PR is based on your master branch, and that will make your life hard. After that, you'd best give https://matplotlib.org/devel/gitwash/index.html a thorough look. In particular pay attention to backing up your branch. With your setup, I would do:
If you mess up:
will get you locally back to where you were. |
This is some redundant branch switching:
|
Adds an optional parameter to PillowWriter that will set the number of times that a gif should loop for. Defaults to 0 meaning endless
@jklymak Your advice seems to have worked. Thank you. I've rebased. |
Can whoever merges this squash-merge it? |
* master: (51 commits) Disable sticky edge accumulation if no autoscaling. Avoid quadratic behavior when accumulating stickies. Rectified plot error (matplotlib#12501) endless looping GIFs with PillowWriter (matplotlib#11789) TST: add test for re-normalizing image FIX: colorbar re-check norm before draw for autolabels Fix search for sphinx >=1.8 (matplotlib#12216) Fix some flake8 issues Don't handle impossible values for `align` in hist() DOC: add section about test / doc dependencies DOC: clarify time windows for support TST: test colorbar tick labels correct FIX: make minor ticks formatted with science formatter as well DOC: clarify what 'minor version' means Adjust the widths of the messages during the build. Simplify radar_chart example. Fix duplicate condition in pathpatch3d example (matplotlib#12495) Fix typo in documentation FIX: make unused spines invisible Kill FontManager.update_fonts. ...
PR Summary
Closes #11787 .
Adds an optional parameter to PillowWriter that will set the number of times that a GIF will loop for. Defaults to 0 meaning endless looping. Previously defaulted to 1 (never looping) without a way to change it.API change removed.Makes PillowWriter produce endless looping gifs like ImageMagickWriter and ImageMagickFileWriter.
PR Checklist
[ ] Has Pytest style unit tests[ ] Documented in doc/api/api_changes.rst if API changed in a backward-incompatible way