Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork8.1k
Enh/Add hatch pattern support to Axes.grouped_bar#30726
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:main
Are you sure you want to change the base?
Changes fromall commits
cd9ddcd6e3a7c8dc94475b40273090f0a220fad9661eb63f9960914cadf2717a8c8705d2f1943afb64cb485ef679fffd16af21213541bf68324d578File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -3050,7 +3050,7 @@ | ||
| @_docstring.interpd | ||
| def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing=0, | ||
| tick_labels=None, labels=None, orientation="vertical", colors=None, | ||
| hatch=None,**kwargs): | ||
| """ | ||
| Make a grouped bar plot. | ||
| @@ -3190,6 +3190,15 @@ | ||
| If not specified, the colors from the Axes property cycle will be used. | ||
| hatch : sequence of :mpltype:`hatch` or None, optional | ||
| Hatch pattern(s) to apply per dataset. | ||
| - If ``None`` (default), no hatching is applied. | ||
| - If a sequence of strings is provided (e.g., ``['//', 'xx', '..']``), | ||
| the patterns are cycled across datasets. | ||
| - If the sequence contains a single element (e.g., ``['//']``), | ||
| the same pattern is repeated for all datasets. | ||
| **kwargs : `.Rectangle` properties | ||
| %(Rectangle:kwdoc)s | ||
| @@ -3318,6 +3327,38 @@ | ||
| # TODO: do we want to be more restrictive and check lengths? | ||
| colors = itertools.cycle(colors) | ||
| if hatch is None: | ||
| # No hatch specified: disable hatching entirely by cycling [None]. | ||
| hatches = itertools.cycle([None]) | ||
| elif isinstance(hatch, str): | ||
| raise ValueError("'hatch' must be a sequence of strings " | ||
| "(e.g., ['//']) or None; " | ||
| "a single string like '//' is not allowed." | ||
| ) | ||
| else: | ||
| try: | ||
| hatch_list = list(hatch) | ||
| except TypeError: | ||
| raise ValueError("'hatch' must be a sequence of strings" | ||
| "(e.g., ['//']) or None") from None | ||
| if not hatch_list: | ||
| # Empty sequence is invalid → raise instead of treating as no hatch. | ||
| raise ValueError( | ||
| "'hatch' must be a non-empty sequence of strings or None; " | ||
| "use hatch=None for no hatching." | ||
| ) | ||
| elif not all(h is None or isinstance(h, str) for h in hatch_list): | ||
| raise TypeError("All entries in 'hatch' must be strings or None") | ||
| else: | ||
| # Sequence of hatch patterns: cycle through them as needed. | ||
| # Example: hatch=['//', 'xx', '..'] → patterns repeat across datasets. | ||
| hatches = itertools.cycle(hatch_list) | ||
Comment on lines +3332 to +3361 Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. can you condense the whitespace please? Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Also, why not just follow the pattern in hist and allow a string (since we're allowing 1d list) and therefore simplify the error checking - basically bar handles the hatch validation instead of grouped bar. Author There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. When hatch is given as a single string (e.g. "//"), we raise a ValueError. This prevents Matplotlib from incorrectly iterating over individual characters ('/', '/') instead of treating the hatch as a single pattern. Author There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. https://github.com/matplotlib/matplotlib/blob/dedfe9be48ad82cade86766ef89410844ff09b31/lib/matplotlib/axes/_axes.py#L7560C8-L7560C76 --->>>>>> the implementation cycles hatch patterns per patch, which breaks grouped bar semantics because each dataset generates multiple patches. This causes the hatch sequence to repeat incorrectly within the same dataset. Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more.
Sounds good to me, I think would also then allow for easier expansion into nesting (hatch per patch per dataset) if we wanted to go that direction. Author There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. [MNT]: Discussion : Normalize hatch patterns per dataset instead of per patch in grouped_bar#30789 I’ve created a new issue to address the hatch-normalization behavior in grouped_bar (i.e., switching from per-patch hatch cycling to per-dataset hatch assignment). This allows us to track that behavioral change separately from PR#30726, which is already large and focused on adding hatch support. Splitting this out avoids scope creep, keeps the current PR reviewable, and ensures the semantic change to hatch handling receives dedicated discussion and review. Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. @ilakkmanoharan I closed that issue b/c that behavioral discussion is necessary in this PR to move this PR forward - it's not scope creep b/c it's inherent to how you're handling the hatch argument and which errors to throw. If the current behavior of grouped hatch is one color per dataset, than the behavior of hatch should also be one color per dataset. This is also consistent with stackplot. Also, that's the behavior you've documented: ![]() Until you get better intuition for what would make a good issue, I strongly recommend you ask maintainers if a discussion warrants a stand alone issue before opening a new one. | ||
| bar_width = (group_distance / | ||
| (num_datasets + (num_datasets - 1) * bar_spacing + group_spacing)) | ||
| bar_spacing_abs = bar_spacing * bar_width | ||
| @@ -3331,15 +3372,19 @@ | ||
| # place the bars, but only use numerical positions, categorical tick labels | ||
| # are handled separately below | ||
| bar_containers = [] | ||
Check warning on line 3376 in lib/matplotlib/axes/_axes.py
| ||
| for i, (hs, label, color, hatch_pattern) in enumerate( | ||
| zip(heights, labels, colors, hatches) | ||
| ): | ||
| lefts = (group_centers - 0.5 * group_distance + margin_abs | ||
| + i * (bar_width + bar_spacing_abs)) | ||
| if orientation == "vertical": | ||
| bc = self.bar(lefts, hs, width=bar_width, align="edge", | ||
| label=label, color=color,hatch=hatch_pattern,**kwargs) | ||
| else: | ||
| bc = self.barh(lefts, hs, height=bar_width, align="edge", | ||
| label=label, color=color,hatch=hatch_pattern,**kwargs) | ||
| bar_containers.append(bc) | ||
| if tick_labels is not None: | ||
Uh oh!
There was an error while loading.Please reload this page.
