Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions doc/users/next_whats_new/patch_dashoffset.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Patch dash offsets honored on patches
-------------------------------------

Patches now respect the dash offset specified via
`~matplotlib.patches.Patch.set_linestyle`, so edge stroking matches the
behaviour of lines across both vector (e.g. SVG) and raster (Agg) backends.
8 changes: 4 additions & 4 deletions lib/matplotlib/patches.py
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,8 @@ def set_linestyle(self, ls):
(offset, onoffseq)

where ``onoffseq`` is an even length tuple of on and off ink in points.
When ``rcParams['lines.scale_dashes']`` is True (the default), both the
offset and the on/off lengths are scaled by the linewidth.

Parameters
----------
Expand Down Expand Up @@ -586,10 +588,8 @@ def draw(self, renderer):
# docstring inherited
if not self.get_visible():
return
# Patch has traditionally ignored the dashoffset.
with cbook._setattr_cm(
self, _dash_pattern=(0, self._dash_pattern[1])), \
self._bind_draw_path_function(renderer) as draw_path:
# Preserve the computed dash offset via the bound draw_path.
with self._bind_draw_path_function(renderer) as draw_path:
path = self.get_path()
transform = self.get_transform()
tpath = transform.transform_path_non_affine(path)
Expand Down
59 changes: 59 additions & 0 deletions lib/matplotlib/tests/test_patches.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
"""
Tests specific to the patches module.
"""
import io
import re

import numpy as np
from numpy.testing import assert_almost_equal, assert_array_equal
import pytest

import matplotlib as mpl
from matplotlib.backends.backend_agg import RendererAgg
from matplotlib.backends.backend_svg import FigureCanvasSVG
from matplotlib.patches import (Annulus, Ellipse, Patch, Polygon, Rectangle,
FancyArrowPatch, FancyArrow, BoxStyle)
from matplotlib.testing.decorators import image_comparison, check_figures_equal
from matplotlib.transforms import Bbox
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
from matplotlib import (
collections as mcollections, colors as mcolors, patches as mpatches,
path as mpath, transforms as mtransforms, rcParams)
Expand Down Expand Up @@ -337,6 +343,59 @@ def test_patch_linestyle_none(fig_test, fig_ref):
ax_ref.set_ylim([-1, i + 1])


def test_patch_linestyle_respects_dashoffset_svg():
fig = Figure(figsize=(2, 1))
ax = fig.add_subplot()
ax.set_axis_off()
ax.set_xlim(0, 3)
ax.set_ylim(0, 1)

rect_no_offset = Rectangle(
(0.1, 0.1), 1, 0.8, fill=False, linewidth=2,
linestyle=(0, (3, 2)))
rect_with_offset = Rectangle(
(1.5, 0.1), 1, 0.8, fill=False, linewidth=2,
linestyle=(6, (3, 2)))

ax.add_patch(rect_no_offset)
ax.add_patch(rect_with_offset)

canvas = FigureCanvasSVG(fig)
buffer = io.StringIO()
canvas.print_svg(buffer)
svg = buffer.getvalue()

offsets = [
float(match)
for match in re.findall(r"stroke-dashoffset:\s*([0-9.]+)", svg)
]

assert len(offsets) >= 2
assert rect_no_offset._dash_pattern[0] == 0
assert offsets.count(rect_no_offset._dash_pattern[0]) >= 1
assert offsets.count(rect_with_offset._dash_pattern[0]) >= 1


def test_patch_linestyle_dashoffset_prop_agg(monkeypatch):
renderer = RendererAgg(200, 200, 72)
rect = Rectangle(
(0, 0), 1, 1, fill=False, linewidth=2,
linestyle=(6, (3, 2)))

recorded = []
original_draw_path = RendererAgg.draw_path

def capture(self, gc, path, transform, rgbFace=None):
recorded.append(gc.get_dashes())
return original_draw_path(self, gc, path, transform, rgbFace)

monkeypatch.setattr(RendererAgg, "draw_path", capture)
rect.draw(renderer)

assert recorded
assert rect._dash_pattern in recorded


def test_wedge_movement():
param_dict = {'center': ((0, 0), (1, 1), 'set_center'),
'r': (5, 8, 'set_radius'),
Expand Down