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

Skip to content

Commit 5c564d4

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 753d330 commit 5c564d4

File tree

1 file changed

+51
-71
lines changed

1 file changed

+51
-71
lines changed

lib/matplotlib/patches.py

Lines changed: 51 additions & 71 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

@@ -525,21 +531,39 @@ def draw(self, renderer):
525531
if self.get_sketch_params() is not None:
526532
gc.set_sketch_params(*self.get_sketch_params())
527533

528-
path = self.get_path()
529-
transform = self.get_transform()
530-
tpath = transform.transform_path_non_affine(path)
531-
affine = transform.get_affine()
532-
533534
if self.get_path_effects():
534535
from matplotlib.patheffects import PathEffectRenderer
535536
renderer = PathEffectRenderer(self.get_path_effects(), renderer)
536537

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

539544
gc.restore()
540545
renderer.close_group('patch')
541546
self.stale = False
542547

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

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

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

4286-
gc.set_alpha(self._alpha)
4299+
if not cbook.iterable(fillable):
4300+
path = [path]
4301+
fillable = [fillable]
42874302

4288-
if self._hatch:
4289-
gc.set_hatch(self._hatch)
4290-
if self._hatch_color is not None:
4291-
try:
4292-
gc.set_hatch_color(self._hatch_color)
4293-
except AttributeError:
4294-
# if we end up with a GC that does not have this method
4295-
cbook.warn_deprecated(
4296-
"3.1", "Your backend does not support setting the "
4297-
"hatch color; such backends will become unsupported "
4298-
"in Matplotlib 3.3.")
4303+
affine = transforms.IdentityTransform()
42994304

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

43304310

43314311
class ConnectionPatch(FancyArrowPatch):

0 commit comments

Comments
 (0)