Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 311e95e

Browse files
committed
Factor out common code between Patch.draw and FancyArrowPatch.draw.
The code setting up the renderer and gc are nearly identical, so we can factor it out as a helper contextmanager. The only difference is that FancyArrowPatch then calls draw_path multiple times with various arguments. Note that the refactoring exposed the fact that FancyArrowPatches are (incorrectly, IMO) ignoring joinstyles and capstyles (this is necessary to make image test pass, but we probably will want to generate new images with the "correct" (non-ignoring) behavior at some point).
1 parent f1b64ad commit 311e95e

File tree

1 file changed

+51
-69
lines changed

1 file changed

+51
-69
lines changed

lib/matplotlib/patches.py

Lines changed: 51 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import contextlib
12
import functools
23
import math
34
from numbers import Number
@@ -481,11 +482,16 @@ def get_hatch(self):
481482
'Return the current hatching pattern'
482483
return self._hatch
483484

484-
@artist.allow_rasterization
485-
def draw(self, renderer):
486-
'Draw the :class:`Patch` to the given *renderer*.'
487-
if not self.get_visible():
488-
return
485+
@contextlib.contextmanager
486+
def _bind_draw_path_function(self, renderer):
487+
"""
488+
``draw()`` helper factored out for sharing with `FancyArrowPatch`.
489+
490+
Yields a callable ``dp`` such that calling ``dp(*args, **kwargs)`` is
491+
equivalent to calling ``renderer1.draw_path(gc, *args, **kwargs)``
492+
where ``renderer1`` and ``gc`` have been suitably set from ``renderer``
493+
and the artist's properties.
494+
"""
489495

490496
renderer.open_group('patch', self.get_gid())
491497
gc = renderer.new_gc()
@@ -496,7 +502,7 @@ def draw(self, renderer):
496502
if self._edgecolor[3] == 0:
497503
lw = 0
498504
gc.set_linewidth(lw)
499-
gc.set_dashes(0, self._dashes)
505+
gc.set_dashes(self._dashoffset, self._dashes)
500506
gc.set_capstyle(self._capstyle)
501507
gc.set_joinstyle(self._joinstyle)
502508

@@ -523,21 +529,39 @@ def draw(self, renderer):
523529
if self.get_sketch_params() is not None:
524530
gc.set_sketch_params(*self.get_sketch_params())
525531

526-
path = self.get_path()
527-
transform = self.get_transform()
528-
tpath = transform.transform_path_non_affine(path)
529-
affine = transform.get_affine()
530-
531532
if self.get_path_effects():
532533
from matplotlib.patheffects import PathEffectRenderer
533534
renderer = PathEffectRenderer(self.get_path_effects(), renderer)
534535

535-
renderer.draw_path(gc, tpath, affine, rgbFace)
536+
# In `with _bind_draw_path_function(renderer) as draw_path: ...`
537+
# (in the implementations of `draw()` below), calls to `draw_path(...)`
538+
# will occur as if they took place here with `gc` inserted as
539+
# additional first argument.
540+
yield functools.partial(renderer.draw_path, gc)
536541

537542
gc.restore()
538543
renderer.close_group('patch')
539544
self.stale = False
540545

546+
@artist.allow_rasterization
547+
def draw(self, renderer):
548+
'Draw the :class:`Patch` to the given *renderer*.'
549+
if not self.get_visible():
550+
return
551+
552+
# Patch has traditionally ignored the dashoffset.
553+
with cbook._setattr_cm(self, _dashoffset=0), \
554+
self._bind_draw_path_function(renderer) as draw_path:
555+
path = self.get_path()
556+
transform = self.get_transform()
557+
tpath = transform.transform_path_non_affine(path)
558+
affine = transform.get_affine()
559+
draw_path(tpath, affine,
560+
# Work around a bug in the PDF and SVG renderers, which
561+
# do not draw the hatches if the facecolor is fully
562+
# transparent, but do if it is None.
563+
self._facecolor if self._facecolor[3] else None)
564+
541565
def get_path(self):
542566
"""
543567
Return the path of this patch
@@ -4261,67 +4285,25 @@ def draw(self, renderer):
42614285
if not self.get_visible():
42624286
return
42634287

4264-
renderer.open_group('patch', self.get_gid())
4265-
gc = renderer.new_gc()
4266-
4267-
gc.set_foreground(self._edgecolor, isRGBA=True)
4268-
4269-
lw = self._linewidth
4270-
if self._edgecolor[3] == 0:
4271-
lw = 0
4272-
gc.set_linewidth(lw)
4273-
gc.set_dashes(self._dashoffset, self._dashes)
4274-
4275-
gc.set_antialiased(self._antialiased)
4276-
self._set_gc_clip(gc)
4277-
gc.set_capstyle('round')
4278-
gc.set_snap(self.get_snap())
4288+
# FancyArrowPatch has traditionally forced the capstyle and joinstyle.
4289+
with cbook._setattr_cm(self, _capstyle='round', _joinstyle='round'), \
4290+
self._bind_draw_path_function(renderer) as draw_path:
42794291

4280-
rgbFace = self._facecolor
4281-
if rgbFace[3] == 0:
4282-
rgbFace = None # (some?) renderers expect this as no-fill signal
4292+
# FIXME : dpi_cor is for the dpi-dependecy of the linewidth. There
4293+
# could be room for improvement.
4294+
self.set_dpi_cor(renderer.points_to_pixels(1.))
4295+
path, fillable = self.get_path_in_displaycoord()
42834296

4284-
gc.set_alpha(self._alpha)
4297+
if not cbook.iterable(fillable):
4298+
path = [path]
4299+
fillable = [fillable]
42854300

4286-
if self._hatch:
4287-
gc.set_hatch(self._hatch)
4288-
if self._hatch_color is not None:
4289-
try:
4290-
gc.set_hatch_color(self._hatch_color)
4291-
except AttributeError:
4292-
# if we end up with a GC that does not have this method
4293-
warnings.warn("Your backend does not support setting the "
4294-
"hatch color.")
4301+
affine = transforms.IdentityTransform()
42954302

4296-
if self.get_sketch_params() is not None:
4297-
gc.set_sketch_params(*self.get_sketch_params())
4298-
4299-
# FIXME : dpi_cor is for the dpi-dependecy of the
4300-
# linewidth. There could be room for improvement.
4301-
#
4302-
# dpi_cor = renderer.points_to_pixels(1.)
4303-
self.set_dpi_cor(renderer.points_to_pixels(1.))
4304-
path, fillable = self.get_path_in_displaycoord()
4305-
4306-
if not cbook.iterable(fillable):
4307-
path = [path]
4308-
fillable = [fillable]
4309-
4310-
affine = transforms.IdentityTransform()
4311-
4312-
if self.get_path_effects():
4313-
from matplotlib.patheffects import PathEffectRenderer
4314-
renderer = PathEffectRenderer(self.get_path_effects(), renderer)
4315-
4316-
for p, f in zip(path, fillable):
4317-
if f:
4318-
renderer.draw_path(gc, p, affine, rgbFace)
4319-
else:
4320-
renderer.draw_path(gc, p, affine, None)
4321-
4322-
gc.restore()
4323-
renderer.close_group('patch')
4324-
self.stale = False
4303+
for p, f in zip(path, fillable):
4304+
draw_path(
4305+
p, affine,
4306+
self._facecolor if f and self._facecolor[3] else None)
43254307

43264308

43274309
class ConnectionPatch(FancyArrowPatch):

0 commit comments

Comments
 (0)