Title: [Bug]: Subsequent calls of tight_layout() slightly change figure layout · Issue #21742 · matplotlib/matplotlib · GitHub
Open Graph Title: [Bug]: Subsequent calls of tight_layout() slightly change figure layout · Issue #21742 · matplotlib/matplotlib
X Title: [Bug]: Subsequent calls of tight_layout() slightly change figure layout · Issue #21742 · matplotlib/matplotlib
Description: Bug summary Figure layout can change very slightly depending whether tight_layout() is called once or twice. Another presumably equivalent way in which this can show up is with set_tight_layout(True): when saving a figure twice for which...
Open Graph Description: Bug summary Figure layout can change very slightly depending whether tight_layout() is called once or twice. Another presumably equivalent way in which this can show up is with set_tight_layout(Tru...
X Description: Bug summary Figure layout can change very slightly depending whether tight_layout() is called once or twice. Another presumably equivalent way in which this can show up is with set_tight_layout(Tru...
Opengraph URL: https://github.com/matplotlib/matplotlib/issues/21742
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"[Bug]: Subsequent calls of tight_layout() slightly change figure layout","articleBody":"### Bug summary\n\nFigure layout can change very slightly depending whether `tight_layout()` is called once or twice. Another presumably equivalent way in which this can show up is with `set_tight_layout(True)`: when saving a figure twice for which this has been called, both figures will slightly differ.\n\n### Code for reproduction\n\n```python\nimport matplotlib.pyplot as plt\r\nfrom matplotlib.testing.compare import compare_images\r\n\r\n# import matplotlib as mpl\r\n# mpl.use(\"Agg\") # issue also observed with Agg\r\n\r\nprint(\"using set_tight_layout(True):\")\r\nfig, ax = plt.subplots()\r\nfig.set_tight_layout(True)\r\nfig.savefig(\"1.png\")\r\nfig.savefig(\"2.png\")\r\nfig.savefig(\"3.png\")\r\nprint(f\" 1 and 2 match? {compare_images('1.png', '2.png', 0) is None}\")\r\nprint(f\" 2 and 3 match? {compare_images('2.png', '3.png', 0) is None}\")\r\n\r\nprint(\"using tight_layout():\")\r\nfig, ax = plt.subplots()\r\nfig.tight_layout()\r\n# fig.tight_layout() # when uncommenting this, 4/5/6 will match\r\nfig.savefig(\"4.png\")\r\nfig.tight_layout() # when commenting this out, 4.png and 5.png will match\r\nfig.savefig(\"5.png\")\r\nfig.tight_layout()\r\nfig.savefig(\"6.png\")\r\nprint(f\" 4 and 5 match? {compare_images('4.png', '5.png', 0) is None}\")\r\nprint(f\" 5 and 6 match? {compare_images('5.png', '6.png', 0) is None}\")\r\n\r\nprint(\"using constrained_layout=True:\")\r\nfig, ax = plt.subplots(constrained_layout=True)\r\nfig.savefig(\"7.png\")\r\nfig.savefig(\"8.png\")\r\nfig.savefig(\"9.png\")\r\nprint(f\" 7 and 8 match? {compare_images('7.png', '8.png', 0) is None}\")\r\nprint(f\" 8 and 9 match? {compare_images('8.png', '9.png', 0) is None}\")\n```\n\n\n### Actual outcome\n\nOutput from running the example code:\r\n```\r\nusing set_tight_layout(True):\r\n 1 and 2 match? False\r\n 2 and 3 match? True\r\nusing tight_layout():\r\n 4 and 5 match? False\r\n 5 and 6 match? True\r\nusing constrained_layout=True:\r\n 7 and 8 match? True\r\n 8 and 9 match? True\r\n```\r\n\r\nWhen using `set_tight_layout(True)`, the first two figures being saved differ from each other. Subsequent figures look the same, the layout seems to have converged.\r\n\r\nWhen calling `tight_layout()` once before saving, and again before saving a second time, the resulting figures also differ. Calling it twice before saving for the first time results in consistent figures.\r\n\r\nNo such behavior is observed with `constrained_layout` in these tests.\n\n### Expected outcome\n\nI would expect all produced figures with `tight_layout` to be equivalent, similarly to how the layout with `constrained_layout` is stable.\n\n### Additional information\n\nThis was tested with `matplotlib` 3.5.0, but also seems to happen in some earlier versions. 3.3.0 shows the same behavior. I do not know whether there are other versions where the tight layout converges in one step.\r\n\r\nThe differences between figures in this example are very small, more complicated figures can show slightly larger differences in layout, though in all cases I have seen, the differences tend to be very hard to see by eye unless skipping back and forth. I am not sure whether there are cases where layout convergence happens after more than two iterations, or where things oscillate between layouts.\r\n\r\nI tested with MacOSX backend and a Retina display, though I see the same behavior in a container of `python:3.9-slim`.\r\n\r\nSwitching to AGG as backend results in the same behavior.\r\n\r\nThis may be related to #21673. When adding a `fig.dpi = 100` after each figure is created, the behavior is also unchanged.\r\n\r\nI've opened this as a bug but I am unsure whether it really is a bug, since the documentation for `tight_layout` does not make any statement about guaranteeing convergence.\n\n### Operating system\n\nmacOS 11.5.2\n\n### Matplotlib Version\n\n3.5.0\n\n### Matplotlib Backend\n\nMacOSX\n\n### Python version\n\nPython 3.8.10\n\n### Jupyter version\n\n6.4.0\n\n### Installation\n\npip","author":{"url":"https://github.com/alexander-held","@type":"Person","name":"alexander-held"},"datePublished":"2021-11-24T19:40:55.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":5},"url":"https://github.com/21742/matplotlib/issues/21742"}
| 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:a8a82191-7664-ab9a-a6f2-749fb92e103e |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | B00A:258FA1:2C02B5:3B8C51:6A528BFE |
| html-safe-nonce | 641f0768236e3a9ae0624feb5aef82b165f5cf2fc5952d6562b371e1eb688a90 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJCMDBBOjI1OEZBMToyQzAyQjU6M0I4QzUxOjZBNTI4QkZFIiwidmlzaXRvcl9pZCI6Ijc0NDAwNjA1MzU5NzcxODQyNTQiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | d3ea09e46b4bba2d956c878f1d6d5dfcadc35a0cc8d2cbc7d3bae9cde6140011 |
| hovercard-subject-tag | issue:1062833176 |
| 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/21742/issue_layout |
| twitter:image | https://opengraph.githubassets.com/c4954771ce6004998f1cd5e1fe3b7a9bc763b5389afe2b4ad1f199cc23ace8db/matplotlib/matplotlib/issues/21742 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/c4954771ce6004998f1cd5e1fe3b7a9bc763b5389afe2b4ad1f199cc23ace8db/matplotlib/matplotlib/issues/21742 |
| og:image:alt | Bug summary Figure layout can change very slightly depending whether tight_layout() is called once or twice. Another presumably equivalent way in which this can show up is with set_tight_layout(Tru... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | alexander-held |
| hostname | github.com |
| expected-hostname | github.com |
| None | b9a586c06a05a7a86fc7e3f4dbd03e42f6869085879aa184aa6369456dbd50fb |
| 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 | 07a982c1d40157c619b364352b704c3ce66bb332 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width