-
-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Fixed hatching in PatchCollection class #27937
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 our terms of service and privacy 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 from 5 commits
eba3d76
a563671
254f145
f0375b6
85cbdc7
f62a8ea
d8cf3a0
e1fe14d
a4275a1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -990,7 +990,7 @@ def get_hatch(self): | |
| def get_hatch_path(self, density=6.0): | ||
| """Return a `.Path` for the current hatch.""" | ||
| hatch = self.get_hatch() | ||
| if hatch is None: | ||
| if hatch is None or all(h is None for h in hatch): | ||
| return None | ||
| return Path.hatch(hatch, density) | ||
|
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. will this need to be looped if passed a list of hatches? |
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -171,6 +171,7 @@ def __init__(self, *, | |
| # Flags set by _set_mappable_flags: are colors from mapping an array? | ||
| self._face_is_mapped = None | ||
| self._edge_is_mapped = None | ||
| self._match_original = False | ||
|
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. where is this set? |
||
| self._mapped_colors = None # calculated in update_scalarmappable | ||
| self._hatch_color = mcolors.to_rgba(mpl.rcParams['hatch.color']) | ||
| self.set_facecolor(facecolors) | ||
|
|
@@ -423,13 +424,31 @@ def draw(self, renderer): | |
| self._antialiaseds, self._urls, | ||
| "screen") | ||
|
|
||
| renderer.draw_path_collection( | ||
| gc, transform.frozen(), paths, | ||
| self.get_transforms(), offsets, offset_trf, | ||
| self.get_facecolor(), self.get_edgecolor(), | ||
| self._linewidths, self._linestyles, | ||
| self._antialiaseds, self._urls, | ||
| "screen") # offset_position, kept for backcompat. | ||
| fcolor = itertools.cycle(facecolors) if facecolors.any() \ | ||
| else itertools.repeat([]) | ||
| ecolor = itertools.cycle(edgecolors) if edgecolors.any() \ | ||
| else itertools.repeat([]) | ||
| lwidth = itertools.cycle(self._linewidths) | ||
| lstyle = itertools.cycle(self._linestyles) | ||
| antialiased = itertools.cycle(self._antialiaseds) | ||
|
|
||
| if self._match_original: | ||
| for idx in range(len(paths)): | ||
| gc.set_hatch(self._hatch[idx]) | ||
| renderer.draw_path_collection( | ||
| gc, transform.frozen(), [paths[idx]], | ||
| self.get_transforms(), offsets, offset_trf, | ||
| [next(fcolor)], [next(ecolor)], [next(lwidth)], [next(lstyle)], | ||
| [next(antialiased)], self._urls, | ||
| "screen") # offset_position, kept for backcompat. | ||
| else: | ||
| renderer.draw_path_collection( | ||
| gc, transform.frozen(), paths, | ||
| self.get_transforms(), offsets, offset_trf, | ||
| self.get_facecolor(), self.get_edgecolor(), | ||
|
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. these return lists too, so why can't self.get_hatches, w/ changes as needed being implemented down in .draw_path_collection?
Contributor
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. Makes sense |
||
| self._linewidths, self._linestyles, | ||
| self._antialiaseds, self._urls, | ||
| "screen") | ||
|
|
||
| gc.restore() | ||
| renderer.close_group(self.__class__.__name__) | ||
|
|
@@ -1846,8 +1865,9 @@ def __init__(self, patches, *, match_original=False, **kwargs): | |
| a heterogeneous assortment of different patch types. | ||
|
|
||
| match_original : bool, default: False | ||
| If True, use the colors and linewidths of the original | ||
| patches. If False, new colors may be assigned by | ||
| If True, use the colors, linewidths, linestyles | ||
| and the hatch of the original patches. | ||
| If False, new colors may be assigned by | ||
|
Comment on lines
+1853
to
+1855
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. how are new colors assigned if not passed in as part of the original patches? |
||
| providing the standard collection arguments, facecolor, | ||
| edgecolor, linewidths, norm or cmap. | ||
|
|
||
|
|
@@ -1867,16 +1887,17 @@ def __init__(self, patches, *, match_original=False, **kwargs): | |
| """ | ||
|
|
||
| if match_original: | ||
| def determine_facecolor(patch): | ||
| if patch.get_fill(): | ||
| return patch.get_facecolor() | ||
| return [0, 0, 0, 0] | ||
|
|
||
| kwargs['facecolors'] = [determine_facecolor(p) for p in patches] | ||
| kwargs['edgecolors'] = [p.get_edgecolor() for p in patches] | ||
| kwargs['linewidths'] = [p.get_linewidth() for p in patches] | ||
| kwargs['linestyles'] = [p.get_linestyle() for p in patches] | ||
| kwargs['antialiaseds'] = [p.get_antialiased() for p in patches] | ||
| self._match_original = True | ||
| kwargs['facecolors'] = tuple([p.get_facecolor() for p in patches]) | ||
|
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. why does it need to be a tuple? |
||
| kwargs['linewidths'] = tuple([p.get_linewidth() for p in patches]) | ||
| kwargs['linestyles'] = tuple([p.get_linestyle() for p in patches]) | ||
| kwargs['antialiaseds'] = tuple([p.get_antialiased() for p in patches]) | ||
| kwargs['hatch'] = tuple([p.get_hatch() for p in patches]) | ||
|
|
||
| # Edgecolors are handled separately because are defaulted to None | ||
| # and the Hatch colors depend on them. | ||
| if all(p._original_edgecolor is not None for p in patches): | ||
| kwargs["edgecolors"] = tuple([p.get_edgecolor() for p in patches]) | ||
|
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. how do you handle a patch collection where some edges are none and some aren't? |
||
|
|
||
| super().__init__(**kwargs) | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -180,7 +180,7 @@ def __init__(self, hatch, density): | |
|
|
||
|
|
||
| def _validate_hatch_pattern(hatch): | ||
| valid_hatch_patterns = set(r'-+|/\xXoO.*') | ||
| valid_hatch_patterns = set(r'-+|/\xXoO.*').union({None}) | ||
|
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. why do you need to add None if next line you only validate if not none?
Contributor
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. In the case of a list of Nones, the set function makes it into a singleton set with None. So it fails the if hatch is not None:condition
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. Ok, but then I think you don't need the |
||
| if hatch is not None: | ||
| invalids = set(hatch).difference(valid_hatch_patterns) | ||
| if invalids: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
h is not None will trigger checking the second condition, which will then try to iterate over a maybe not iterable hatch.