From 98ff4b4d0f57fb0741b72713d1225f3b5e74c383 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Mon, 18 May 2020 17:03:29 +0200 Subject: [PATCH] Support odd-length dash patterns in Agg. All vector backends already support passing an odd-length dash pattern, duplicating the on/off array (so that on the second repetition "on" becomes "off" and vice-versa). This is also explicitly supported by the svg spec for `stroke-dasharray` ("If an odd number of values is provided, then the list of values is repeated to yield an even number of values. Thus, 5,3,2 is equivalent to 5,3,2,5,3,2.") and less explicitly by the pdf and ps specs, and by cairo. So the backend needing support is Agg; iterating twice over the sequence is likely simplest. --- lib/matplotlib/tests/test_lines.py | 6 ++++++ src/py_converters.cpp | 16 +++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/matplotlib/tests/test_lines.py b/lib/matplotlib/tests/test_lines.py index d66509b0ee78..f03058610b16 100644 --- a/lib/matplotlib/tests/test_lines.py +++ b/lib/matplotlib/tests/test_lines.py @@ -217,3 +217,9 @@ def test_marker_as_markerstyle(): assert_array_equal(line2.get_marker().vertices, triangle1.vertices) assert_array_equal(line3.get_marker().vertices, triangle1.vertices) + + +@check_figures_equal() +def test_odd_dashes(fig_test, fig_ref): + fig_test.add_subplot().plot([1, 2], dashes=[1, 2, 3]) + fig_ref.add_subplot().plot([1, 2], dashes=[1, 2, 3, 1, 2, 3]) diff --git a/src/py_converters.cpp b/src/py_converters.cpp index b5e88dd0b2b5..d252da0eda55 100644 --- a/src/py_converters.cpp +++ b/src/py_converters.cpp @@ -226,7 +226,6 @@ int convert_dashes(PyObject *dashobj, void *dashesp) PyObject *dash_offset_obj = NULL; double dash_offset = 0.0; PyObject *dashes_seq = NULL; - Py_ssize_t nentries; if (!PyArg_ParseTuple(dashobj, "OO:dashes", &dash_offset_obj, &dashes_seq)) { return 0; @@ -256,18 +255,17 @@ int convert_dashes(PyObject *dashobj, void *dashesp) return 0; } - nentries = PySequence_Size(dashes_seq); - if (nentries % 2 != 0) { - PyErr_Format(PyExc_ValueError, "dashes sequence must have an even number of elements"); - return 0; - } + Py_ssize_t nentries = PySequence_Size(dashes_seq); + // If the dashpattern has odd length, iterate through it twice (in + // accordance with the pdf/ps/svg specs). + Py_ssize_t dash_pattern_length = (nentries % 2) ? 2 * nentries : nentries; - for (Py_ssize_t i = 0; i < nentries; ++i) { + for (Py_ssize_t i = 0; i < dash_pattern_length; ++i) { PyObject *item; double length; double skip; - item = PySequence_GetItem(dashes_seq, i); + item = PySequence_GetItem(dashes_seq, i % nentries); if (item == NULL) { return 0; } @@ -280,7 +278,7 @@ int convert_dashes(PyObject *dashobj, void *dashesp) ++i; - item = PySequence_GetItem(dashes_seq, i); + item = PySequence_GetItem(dashes_seq, i % nentries); if (item == NULL) { return 0; }