Title: PillowWriter GIF duration and loop · Issue #19169 · matplotlib/matplotlib · GitHub
Open Graph Title: PillowWriter GIF duration and loop · Issue #19169 · matplotlib/matplotlib
X Title: PillowWriter GIF duration and loop · Issue #19169 · matplotlib/matplotlib
Description: Current PillowWriter functionality does not allow me to specify the duration for each of the gif frames and it is not possible to not have the gif loop. Additionally, I frequently get a ValueError: buffer is not large enough when animati...
Open Graph Description: Current PillowWriter functionality does not allow me to specify the duration for each of the gif frames and it is not possible to not have the gif loop. Additionally, I frequently get a ValueError:...
X Description: Current PillowWriter functionality does not allow me to specify the duration for each of the gif frames and it is not possible to not have the gif loop. Additionally, I frequently get a ValueError:...
Opengraph URL: https://github.com/matplotlib/matplotlib/issues/19169
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"PillowWriter GIF duration and loop","articleBody":"\u003c!--\r\nWelcome! Thanks for thinking of a way to improve Matplotlib.\r\n\r\n\r\nBefore creating a new feature request please search the issues for relevant feature requests.\r\n--\u003e\r\n\r\n### Current PillowWriter functionality does not allow me to specify the duration for each of the gif frames and it is not possible to not have the gif loop.\r\nAdditionally, I frequently get a **ValueError: buffer is not large enough** when animating multi axes figures. (Not sure if this is a common problem).\r\n\r\nAnimation to help introduce a visual story can be quite beneficial to understanding and for that I would like to be able to not loop the gif and \"pause\" the gif via different durations for all frames.\r\n\r\n\u003c!--\r\nProvide a clear and concise description of the problem this feature will solve. \r\n\r\nFor example:\r\n* I'm always frustrated when [...] because [...]\r\n* I would like it if [...] happened when I [...] because [...]\r\n* Here is a sample image of what I am asking for [...]\r\n--\u003e\r\n\r\n### Proposed Solution\r\n\r\n1) add duration=None, loop=0 arguments to setup() and to a PillowWriter specific saving context_manager.\r\nTo not loop we can specify loop=None and then we specifically need to not pass the loop argument to save() in finish().\r\n\r\n2) What is the difference between Image.frombuffer and Image.open(buf)? I find that Image.open(buf) solves my problem of the ValueError: buffer is not large enough.\r\nIt seems to take more time for me though. (about +33%)\r\n\r\n3) removed unused variable assignment: renderer = self.fig.canvas.get_renderer() from grab_frame()\r\n\r\n```\r\nclass PillowWriter(AbstractMovieWriter):\r\n @classmethod\r\n def isAvailable(cls):\r\n return True\r\n\r\n def setup(self, fig, outfile, dpi=None, duration=None, loop=None):\r\n super().setup(fig, outfile, dpi=dpi)\r\n self.duration = duration\r\n self.loop = loop\r\n self._frames = []\r\n\r\n def grab_frame(self, **savefig_kwargs):\r\n buf = BytesIO()\r\n self.fig.savefig(\r\n buf, **{**savefig_kwargs, \"dpi\": self.dpi})\r\n self._frames.append(Image.open(buf))\r\n\r\n def finish(self):\r\n duration = self.duration or int(1000 / self.fps)\r\n\r\n # to not loop at all we need to avoid passing the loop argument to save\r\n if self.loop is None:\r\n self._frames[0].save(\r\n self.outfile, save_all=True, append_images=self._frames[1:],\r\n duration=duration)\r\n else:\r\n self._frames[0].save(\r\n self.outfile, save_all=True, append_images=self._frames[1:],\r\n duration=duration, loop=self.loop)\r\n\r\n @contextlib.contextmanager\r\n def saving(self, fig, outfile, dpi, duration=None, loop=0, *args, **kwargs):\r\n \"\"\"\r\n Context manager to facilitate writing the movie file.\r\n ``*args, **kw`` are any parameters that should be passed to `setup`.\r\n \"\"\"\r\n # This particular sequence is what contextlib.contextmanager wants\r\n self.setup(fig, outfile, dpi, duration, loop, *args, **kwargs)\r\n try:\r\n yield self\r\n finally:\r\n self.finish()\r\n```\r\n\r\n\r\n### Additional context and prior art\r\n\r\nendless looping for gifs was introduced here:\r\nhttps://github.com/matplotlib/matplotlib/pull/11789\r\n\r\nDocumentation would have to be updated I suppose.\r\nIf this seems like a useful improvement to the PillowWriter I could go ahead and create a PR.","author":{"url":"https://github.com/znstrider","@type":"Person","name":"znstrider"},"datePublished":"2020-12-23T14:23:14.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":9},"url":"https://github.com/19169/matplotlib/issues/19169"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:1fe0e9fd-86d5-39e9-f9a2-a94a1185cdee |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | E36C:F32D9:3DC8B49:57A06E6:6A56AC3B |
| html-safe-nonce | 3c4132c2e760c2699183e418bc79121c07840e6e944f3dca00494e0cb49f21d9 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJFMzZDOkYzMkQ5OjNEQzhCNDk6NTdBMDZFNjo2QTU2QUMzQiIsInZpc2l0b3JfaWQiOiI4OTIzNTM3OTYyMjI4NDI3ODM1IiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0= |
| visitor-hmac | bcf2c4fc249dd6a7ae0d8d9499fbcc34cc199ca4552d9d909adf9c51184d32ed |
| hovercard-subject-tag | issue:773828249 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/matplotlib/matplotlib/19169/issue_layout |
| twitter:image | https://opengraph.githubassets.com/27ae2df55b68feda4e794efc5ec4d150d6d22f7ad2bceeaf38befe02d50baa58/matplotlib/matplotlib/issues/19169 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/27ae2df55b68feda4e794efc5ec4d150d6d22f7ad2bceeaf38befe02d50baa58/matplotlib/matplotlib/issues/19169 |
| og:image:alt | Current PillowWriter functionality does not allow me to specify the duration for each of the gif frames and it is not possible to not have the gif loop. Additionally, I frequently get a ValueError:... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | znstrider |
| hostname | github.com |
| expected-hostname | github.com |
| None | 13efe7fe8ecc41eda1078cbde8206041ed92bc54e29bcb737e9353dd9c407aad |
| turbo-cache-control | no-preview |
| go-import | github.com/matplotlib/matplotlib git https://github.com/matplotlib/matplotlib.git |
| octolytics-dimension-user_id | 215947 |
| octolytics-dimension-user_login | matplotlib |
| octolytics-dimension-repository_id | 1385122 |
| octolytics-dimension-repository_nwo | matplotlib/matplotlib |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 1385122 |
| octolytics-dimension-repository_network_root_nwo | matplotlib/matplotlib |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 5466ebe023a0abf876a1e6c5d7602ee8f5e6a02b |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width