Title: [MNT]: Revamp `draw_path_collection()` API · Issue #30547 · matplotlib/matplotlib · GitHub
Open Graph Title: [MNT]: Revamp `draw_path_collection()` API · Issue #30547 · matplotlib/matplotlib
X Title: [MNT]: Revamp `draw_path_collection()` API · Issue #30547 · matplotlib/matplotlib
Description: Summary I am opening this issue in order to discuss the possibility of enhancing the API of draw_path_collection() for the long term. This was initially discussed in this and the following comments by @anntzer and @timhoffm. Adding/ vect...
Open Graph Description: Summary I am opening this issue in order to discuss the possibility of enhancing the API of draw_path_collection() for the long term. This was initially discussed in this and the following comments...
X Description: Summary I am opening this issue in order to discuss the possibility of enhancing the API of draw_path_collection() for the long term. This was initially discussed in this and the following comments...
Opengraph URL: https://github.com/matplotlib/matplotlib/issues/30547
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"[MNT]: Revamp `draw_path_collection()` API","articleBody":"### Summary\n\nI am opening this issue in order to discuss the possibility of enhancing the API of `draw_path_collection()` for the long term. This was initially discussed in [this and the following comments](https://github.com/matplotlib/matplotlib/pull/29044#issuecomment-2656133496) by @anntzer and @timhoffm.\n\nAdding/ vectorizing new attributes in collections requires changing the signature of `draw_path_collection()`. This causes incompatibility with third party backends, such as `mplcairo` , because they still use the older signature.\n\nTo workaround this in #29044 (that added the `hatchcolors` argument) a provisional API was used, which relies on making an empty call to `draw_path_collection()` to infer the signature. This current API is temporary and requires a rewrite.\n\n### Proposed fix\n\nA solution proposed by @anntzer in [this comment](https://github.com/matplotlib/matplotlib/pull/29044#issuecomment-2656991777) is to use an API similar to `draw_path()` - send parameters through a dataclass and use getters to retrieve the required parameters, analogous to `GraphicsContextBase` in `draw_path()`. \nWe could call this dataclass something like `VectorizedGraphicsContextBase` . It is similar to `GraphicsContextBase`, but each attribute is vectorized. A simple draft of the proposed solution is shown below.\n\n### Why is this change needed?\n\nThis would cause a one time break for third party backends. However, in the long term, it would become much simpler to add / vectorize new attributes in collections, without completely breaking third party backends. For example, it would greatly simplify #27937, that aims to vectorize the `hatch` attribute.\n\n### Code Draft\n\n```python\n# backend_bases.py\nclass VectorizedGraphicsContextBase:\n def __init__(self):\n # vectorized attributes\n self._facecolor = [(0.0, 0.0, 0.0, 1.0)]\n self._rgb = [(0.0, 0.0, 0.0, 1.0)]\n self._linewidth = [1]\n ...\n\n # non-vectorized attributes\n self._cliprect = None\n self._clippath = None\n ...\n```\n\n```python\n# collections.py\n\n# `vgc` is an instance of VectorizedGraphicsComtextBase\ndef draw(self, renderer):\n ...\n transform, offset_trf, offsets, paths = self._prepare_points()\n\n vgc = renderer.new_vgc()\n self._set_gc_clip(vgc)\n\n vgc._facecolor = self.get_facecolor()\n vgc._rgb = self.get_edgecolor()\n vgc._linewidth = self.get_linewidth()\n ...\n\n renderer.draw_path_collection(vgc, transform.frozen(), paths, self.get_transforms(),\n offsets, offset_trf)\n```\n\n```python\n# backend_bases.py\ndef draw_path_collection(self, vgc, master_transform, paths, all_transforms,\n offsets, offset_trans):\n path_ids = self._iter_collection_raw_paths(\n master_transform, paths, all_transforms\n )\n\n for xo, yo, path_id, gc, rgbFace in self._iter_collection(\n vgc, list(path_ids), offsets, offset_trans\n ):\n path, transform = path_id\n\n if xo != 0 or yo != 0:\n transform = transform.frozen()\n transform.translate(xo, yo)\n self.draw_path(gc, path, transform, rgbFace)\n\n\ndef _iter_collection(self, vgc, path_ids, offsets, offset_trans):\n Npaths = len(path_ids)\n Noffsets = len(offsets)\n N = max(Npaths, Noffsets)\n Nfacecolors = len(vgc._facecolor)\n Nedgecolors = len(vgc._rgb)\n Nlinewidths = len(vgc._linewidth)\n\n pathids = cycle_or_default(path_ids)\n toffsets = cycle_or_default(offset_trans.transform(offsets), (0, 0))\n fcs = cycle_or_default(vgc._facecolor)\n ecs = cycle_or_default(vgc._rgb)\n lws = cycle_or_default(vgc._linewidth)\n\n gc = self.new_gc()\n # attributes that are not vectorized\n gc._clip_path = vgc._clip_path\n gc._clip_rect = vgc._clip_rect\n ...\n\n for pathid, (xo, yo), fc, ec, lw in itertools.islice(\n zip(pathids, toffsets, fcs, ecs, lws), N\n ):\n if not (np.isfinite(xo) and np.isfinite(yo)):\n continue\n\n if Nedgecolors:\n if Nlinewidths:\n gc.set_linewidth(lw)\n if len(ec) == 4 and ec[3] == 0.0:\n gc.set_linewidth(0)\n else:\n gc.set_foreground(ec)\n if fc is not None and len(fc) == 4 and fc[3] == 0:\n fc = None\n ...\n\n yield xo, yo, pathid, gc, fc\n\n gc.restore()\n```","author":{"url":"https://github.com/r3kste","@type":"Person","name":"r3kste"},"datePublished":"2025-09-11T10:01:47.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":1},"url":"https://github.com/30547/matplotlib/issues/30547"}
| 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:7c9997b2-f5bf-6c77-2744-b439d58e1bdf |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | BF30:350532:5AA53A:7A5E68:6A5254B1 |
| html-safe-nonce | 6569bbae78b4b949a727bccbb30c5d8631eacb2d48a83a127e5d4e245df23157 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJCRjMwOjM1MDUzMjo1QUE1M0E6N0E1RTY4OjZBNTI1NEIxIiwidmlzaXRvcl9pZCI6IjI3MjQ2NzQyMTU4MTUwNDIyMjUiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | 2f7f8c70d15f527230028cb88551a1c19c55e4ddb6ec9039ba5086b58da7cc94 |
| hovercard-subject-tag | issue:3405790382 |
| 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/30547/issue_layout |
| twitter:image | https://opengraph.githubassets.com/73edcb174ed13bf760bd9e8079b5a491ee8362380a0a328a96444620c0a36e82/matplotlib/matplotlib/issues/30547 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/73edcb174ed13bf760bd9e8079b5a491ee8362380a0a328a96444620c0a36e82/matplotlib/matplotlib/issues/30547 |
| og:image:alt | Summary I am opening this issue in order to discuss the possibility of enhancing the API of draw_path_collection() for the long term. This was initially discussed in this and the following comments... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | r3kste |
| 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 | 7aed05249554b889eb33d002851a973eebcc7e91 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width