Title: BUG: CompositeGenericTransform.contains_branch_separately only checks second component, ignoring first · Issue #32099 · matplotlib/matplotlib · GitHub
Open Graph Title: BUG: CompositeGenericTransform.contains_branch_separately only checks second component, ignoring first · Issue #32099 · matplotlib/matplotlib
X Title: BUG: CompositeGenericTransform.contains_branch_separately only checks second component, ignoring first · Issue #32099 · matplotlib/matplotlib
Description: Bug summary CompositeGenericTransform.contains_branch_separately() only checks the second component (_b) of the composite transform, completely ignoring the first component (_a). This means if a composed transform is A + B and the target...
Open Graph Description: Bug summary CompositeGenericTransform.contains_branch_separately() only checks the second component (_b) of the composite transform, completely ignoring the first component (_a). This means if a co...
X Description: Bug summary CompositeGenericTransform.contains_branch_separately() only checks the second component (_b) of the composite transform, completely ignoring the first component (_a). This means if a co...
Opengraph URL: https://github.com/matplotlib/matplotlib/issues/32099
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"BUG: CompositeGenericTransform.contains_branch_separately only checks second component, ignoring first","articleBody":"## Bug summary\n\n`CompositeGenericTransform.contains_branch_separately()` only checks the second component (`_b`) of the composite transform, completely ignoring the first component (`_a`). This means if a composed transform is `A + B` and the target transform is a subtree of `A`, it returns `(False, False)` instead of the correct result.\n\n## Code for reproduction\n\nA composite transform `A + B` where the query transform is found in component `A`:\n\n```python\nimport matplotlib.transforms as mtransforms\nfrom matplotlib.transforms import Transform, BlendedGenericTransform\n\n# Two independent non-affine transforms\nclass NonAffine(Transform):\n input_dims = 2\n output_dims = 2\n is_separable = True\n is_affine = False\n def transform_non_affine(self, values): return values\n\ntn1 = NonAffine()\ntn2 = NonAffine()\n\n# Blended transform: _x=tn1, _y=tn2\nblend = BlendedGenericTransform(tn1, tn2)\n\n# Composite: _a=blend, _b=tn1\ncomposite = blend + tn1\n\n# tn1 is a subtree of _a.x, but NOT of _b\nx, y = composite.contains_branch_separately(tn1)\nprint(f'x={x}, y={y}') # Got: False, False. Expected: True, False\n```\n\n## Actual outcome\n\n`contains_branch_separately` returns `(False, False)`.\n\n## Expected outcome\n\n`contains_branch_separately` should return `(True, False)` since `tn1` is in the `_a.x` branch.\n\n## Buggy code location\n\nhttps://github.com/matplotlib/matplotlib/blob/main/lib/matplotlib/transforms.py#L2450-L2457\n\n```python\ndef contains_branch_separately(self, other_transform):\n if self.output_dims != 2:\n raise ValueError('contains_branch_separately only supports '\n 'transforms with 2 output dimensions')\n if self == other_transform:\n return (True, True)\n return self._b.contains_branch_separately(other_transform) # \u003c-- only _b!\n```\n\nThe fix should check both children:\n\n```python\ndef contains_branch_separately(self, other_transform):\n if self.output_dims != 2:\n raise ValueError('contains_branch_separately only supports '\n 'transforms with 2 output dimensions')\n if self == other_transform:\n return (True, True)\n a_result = self._a.contains_branch_separately(other_transform)\n b_result = self._b.contains_branch_separately(other_transform)\n return (a_result[0] or b_result[0], a_result[1] or b_result[1])\n```\n\n## Impact\n\nThis bug affects any code that uses `contains_branch_separately` on composite transforms, including autoscaling and axis limit updates in `axes/_base.py`, `axes/_axes.py`, `collections.py`, and `contour.py`. When a composite transform's first component contains `transData`, the method would incorrectly return `False`, potentially causing autoscaling to not trigger.\n\n## Matplotlib version\n\nmain branch (all versions with this code).\n\nNote: `CompositeAffine2D` does NOT have this bug because it doesn't override `contains_branch_separately` and inherits the base `Transform` implementation which uses `contains_branch` -\u003e `_iter_break_from_left_to_right`, which correctly iterates both children.\n","author":{"url":"https://github.com/sanrishi","@type":"Person","name":"sanrishi"},"datePublished":"2026-07-22T21:27:22.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":4},"url":"https://github.com/32099/matplotlib/issues/32099"}
| 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:f94a7b5b-6a50-d48b-8f95-8246e39d6d6a |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | AEFA:16F3DB:696800:969514:6A6374B2 |
| html-safe-nonce | 87ed68e3442e37b63556209fe5ee1ca48bde01d11d5cd90fc9e0ed4bcfb70504 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJBRUZBOjE2RjNEQjo2OTY4MDA6OTY5NTE0OjZBNjM3NEIyIiwidmlzaXRvcl9pZCI6IjIyMjg1MjIxNzUwNTc1ODk0MjYiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | 76efefbf73be45ea94999eff2dc07790bc5339553901fc8d2fd2bac4c4965221 |
| hovercard-subject-tag | issue:4953316873 |
| 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/32099/issue_layout |
| twitter:image | https://opengraph.githubassets.com/e7bdd25d4463dbe9c572c6b3b39d3aea0ac80d9ad61da2bce73ca84aa648ae85/matplotlib/matplotlib/issues/32099 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/e7bdd25d4463dbe9c572c6b3b39d3aea0ac80d9ad61da2bce73ca84aa648ae85/matplotlib/matplotlib/issues/32099 |
| og:image:alt | Bug summary CompositeGenericTransform.contains_branch_separately() only checks the second component (_b) of the composite transform, completely ignoring the first component (_a). This means if a co... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | sanrishi |
| hostname | github.com |
| expected-hostname | github.com |
| None | 15e78334bb345f3864e70c5a376ed0383374123629b9e3022398d9431f6cd8bf |
| 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 | 51da2d8d0a841a1393b806a6559fa9ad757e1666 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width