diff --git a/doc/api/api_changes/2014-11-11_ELF_split_lsmapper.rst b/doc/api/api_changes/2014-11-11_ELF_split_lsmapper.rst
new file mode 100644
index 000000000000..e32da0a0898f
--- /dev/null
+++ b/doc/api/api_changes/2014-11-11_ELF_split_lsmapper.rst
@@ -0,0 +1,9 @@
+Split `matplotlib.cbook.ls_mapper` in two
+`````````````````````````````````````````
+
+The `matplotlib.cbook.ls_mapper` dictionary is split into two now to
+distinguish between qualified linestyle used by backends and
+unqualified ones. `ls_mapper` now maps from the short symbols
+(e.g. `"--"`) to qualified names (`"solid"`). The new ls_mapper_r is
+the reversed mapping.
+
diff --git a/doc/users/whats_new/linestyles.rst b/doc/users/whats_new/linestyles.rst
new file mode 100644
index 000000000000..53a273a7dfd0
--- /dev/null
+++ b/doc/users/whats_new/linestyles.rst
@@ -0,0 +1,8 @@
+Mostly unified linestyles for Lines, Patches and Collections
+````````````````````````````````````````````````````````````
+
+The handling of linestyles for Lines, Patches and Collections has been
+unified. Now they all support defining linestyles with short symbols,
+like `"--"`, as well as with full names, like `"dashed"`. Also the
+definition using a dash pattern (`(0., [3., 3.])`) is supported for all
+methods using Lines, Patches or Collections.
diff --git a/lib/matplotlib/cbook.py b/lib/matplotlib/cbook.py
index 814df14d9ab4..5c85ffdc59d6 100644
--- a/lib/matplotlib/cbook.py
+++ b/lib/matplotlib/cbook.py
@@ -2134,7 +2134,10 @@ def unmasked_index_ranges(mask, compressed=True):
(':', 'dotted')]
ls_mapper = dict(_linestyles)
-ls_mapper.update([(ls[1], ls[0]) for ls in _linestyles])
+# The ls_mapper maps short codes for line style to their full name used
+# by backends
+# The reverse mapper is for mapping full names to short ones
+ls_mapper_r = dict([(ls[1], ls[0]) for ls in _linestyles])
def align_iterators(func, *iterables):
diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py
index 8bffa9c11bfe..a37532f70c9b 100644
--- a/lib/matplotlib/collections.py
+++ b/lib/matplotlib/collections.py
@@ -482,16 +482,33 @@ def set_linestyle(self, ls):
"""
Set the linestyle(s) for the collection.
- ACCEPTS: ['solid' | 'dashed', 'dashdot', 'dotted' |
- (offset, on-off-dash-seq) ]
+ =========================== =================
+ linestyle description
+ =========================== =================
+ ``'-'`` or ``'solid'`` solid line
+ ``'--'`` or ``'dashed'`` dashed line
+ ``'-.'`` or ``'dash_dot'`` dash-dotted line
+ ``':'`` or ``'dotted'`` dotted line
+ =========================== =================
+
+ Alternatively a dash tuple of the following form can be provided::
+
+ (offset, onoffseq),
+
+ where ``onoffseq`` is an even length tuple of on and off ink
+ in points.
+
+ Parameters
+ ----------
+ ls : { '-', '--', '-.', ':'} and more see description
+ The line style.
"""
try:
dashd = backend_bases.GraphicsContextBase.dashd
if cbook.is_string_like(ls):
+ ls = cbook.ls_mapper.get(ls, ls)
if ls in dashd:
dashes = [dashd[ls]]
- elif ls in cbook.ls_mapper:
- dashes = [dashd[cbook.ls_mapper[ls]]]
else:
raise ValueError()
elif cbook.iterable(ls):
@@ -499,10 +516,9 @@ def set_linestyle(self, ls):
dashes = []
for x in ls:
if cbook.is_string_like(x):
+ x = cbook.ls_mapper.get(x, x)
if x in dashd:
dashes.append(dashd[x])
- elif x in cbook.ls_mapper:
- dashes.append(dashd[cbook.ls_mapper[x]])
else:
raise ValueError()
elif cbook.iterable(x) and len(x) == 2:
@@ -511,7 +527,7 @@ def set_linestyle(self, ls):
raise ValueError()
except ValueError:
if len(ls) == 2:
- dashes = ls
+ dashes = [ls]
else:
raise ValueError()
else:
diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py
index 3c0c39153118..4854ef045a51 100644
--- a/lib/matplotlib/lines.py
+++ b/lib/matplotlib/lines.py
@@ -16,7 +16,7 @@
from matplotlib import verbose
from . import artist
from .artist import Artist
-from .cbook import iterable, is_string_like, is_numlike, ls_mapper
+from .cbook import iterable, is_string_like, is_numlike, ls_mapper_r
from .colors import colorConverter
from .path import Path
from .transforms import Bbox, TransformedPath, IdentityTransform
@@ -921,55 +921,74 @@ def set_linewidth(self, w):
"""
self._linewidth = w
- def set_linestyle(self, linestyle):
+ def set_linestyle(self, ls):
"""
- Set the linestyle of the line (also accepts drawstyles)
+ Set the linestyle of the line (also accepts drawstyles,
+ e.g., ``'steps--'``)
- ================ =================
- linestyle description
- ================ =================
- ``'-'`` solid
- ``'--'`` dashed
- ``'-.'`` dash_dot
- ``':'`` dotted
- ``'None'`` draw nothing
- ``' '`` draw nothing
- ``''`` draw nothing
- ================ =================
+ =========================== =================
+ linestyle description
+ =========================== =================
+ ``'-'`` or ``'solid'`` solid line
+ ``'--'`` or ``'dashed'`` dashed line
+ ``'-.'`` or ``'dash_dot'`` dash-dotted line
+ ``':'`` or ``'dotted'`` dotted line
+ ``'None'`` draw nothing
+ ``' '`` draw nothing
+ ``''`` draw nothing
+ =========================== =================
'steps' is equivalent to 'steps-pre' and is maintained for
backward-compatibility.
+ Alternatively a dash tuple of the following form can be provided::
+
+ (offset, onoffseq),
+
+ where ``onoffseq`` is an even length tuple of on and off ink
+ in points.
+
.. seealso::
:meth:`set_drawstyle`
To set the drawing style (stepping) of the plot.
- ACCEPTS: [``'-'`` | ``'--'`` | ``'-.'`` | ``':'`` | ``'None'`` |
- ``' '`` | ``''``]
-
- and any drawstyle in combination with a linestyle, e.g., ``'steps--'``.
+ Parameters
+ ----------
+ ls : { '-', '--', '-.', ':'} and more see description
+ The line style.
"""
+ if not is_string_like(ls):
+ if len(ls) != 2:
+ raise ValueError()
+
+ self.set_dashes(ls[1])
+ self._linestyle = "--"
+ return
for ds in self.drawStyleKeys: # long names are first in the list
- if linestyle.startswith(ds):
+ if ls.startswith(ds):
self.set_drawstyle(ds)
- if len(linestyle) > len(ds):
- linestyle = linestyle[len(ds):]
+ if len(ls) > len(ds):
+ ls = ls[len(ds):]
else:
- linestyle = '-'
+ ls = '-'
break
- if linestyle not in self._lineStyles:
- if linestyle in ls_mapper:
- linestyle = ls_mapper[linestyle]
- else:
- verbose.report('Unrecognized line style %s, %s' %
- (linestyle, type(linestyle)))
- if linestyle in [' ', '']:
- linestyle = 'None'
- self._linestyle = linestyle
+ if ls in [' ', '', 'none']:
+ ls = 'None'
+
+ if ls not in self._lineStyles:
+ try:
+ ls = ls_mapper_r[ls]
+ except KeyError:
+ raise ValueError(("You passed in an invalid linestyle, "
+ "`{}`. See "
+ "docs of Line2D.set_linestyle for "
+ "valid values.").format(ls))
+
+ self._linestyle = ls
@docstring.dedent_interpd
def set_marker(self, marker):
diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py
index da9f1c964ea1..d795dca1a480 100644
--- a/lib/matplotlib/patches.py
+++ b/lib/matplotlib/patches.py
@@ -344,10 +344,31 @@ def set_linestyle(self, ls):
"""
Set the patch linestyle
- ACCEPTS: ['solid' | 'dashed' | 'dashdot' | 'dotted']
+ =========================== =================
+ linestyle description
+ =========================== =================
+ ``'-'`` or ``'solid'`` solid line
+ ``'--'`` or ``'dashed'`` dashed line
+ ``'-.'`` or ``'dash_dot'`` dash-dotted line
+ ``':'`` or ``'dotted'`` dotted line
+ =========================== =================
+
+ Alternatively a dash tuple of the following form can be provided::
+
+ (offset, onoffseq),
+
+ where ``onoffseq`` is an even length tuple of on and off ink
+ in points.
+
+ Parameters
+ ----------
+ ls : { '-', '--', '-.', ':'} and more see description
+ The line style.
"""
if ls is None:
ls = "solid"
+
+ ls = cbook.ls_mapper.get(ls, ls)
self._linestyle = ls
def set_ls(self, ls):
diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_ls_dash.pdf b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_ls_dash.pdf
new file mode 100644
index 000000000000..3952787106ec
Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_ls_dash.pdf differ
diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_ls_dash.png b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_ls_dash.png
new file mode 100644
index 000000000000..3312b2be5bbc
Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_ls_dash.png differ
diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_ls_dash.svg b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_ls_dash.svg
new file mode 100644
index 000000000000..08c6ee903948
--- /dev/null
+++ b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_ls_dash.svg
@@ -0,0 +1,226 @@
+
+
+
+
diff --git a/lib/matplotlib/tests/baseline_images/test_lines/line_dashes.pdf b/lib/matplotlib/tests/baseline_images/test_lines/line_dashes.pdf
new file mode 100644
index 000000000000..ca440b3adecb
Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_lines/line_dashes.pdf differ
diff --git a/lib/matplotlib/tests/baseline_images/test_lines/line_dashes.png b/lib/matplotlib/tests/baseline_images/test_lines/line_dashes.png
new file mode 100644
index 000000000000..3d1e7195797c
Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_lines/line_dashes.png differ
diff --git a/lib/matplotlib/tests/baseline_images/test_lines/line_dashes.svg b/lib/matplotlib/tests/baseline_images/test_lines/line_dashes.svg
new file mode 100644
index 000000000000..d693b936214a
--- /dev/null
+++ b/lib/matplotlib/tests/baseline_images/test_lines/line_dashes.svg
@@ -0,0 +1,335 @@
+
+
+
+
diff --git a/lib/matplotlib/tests/test_collections.py b/lib/matplotlib/tests/test_collections.py
index fb0f23d97051..604591ca21cc 100644
--- a/lib/matplotlib/tests/test_collections.py
+++ b/lib/matplotlib/tests/test_collections.py
@@ -325,6 +325,19 @@ def test__EventCollection__set_linestyle():
splt.set_title('EventCollection: set_linestyle')
+@image_comparison(baseline_images=['EventCollection_plot__set_ls_dash'],
+ remove_text=True)
+def test__EventCollection__set_linestyle_single_dash():
+ '''
+ check to make sure set_linestyle accepts a single dash pattern
+ '''
+ splt, coll, _ = generate_EventCollection_plot()
+ new_linestyle = (0, (6., 6.))
+ coll.set_linestyle(new_linestyle)
+ assert_equal(coll.get_linestyle(), [(0, (6.0, 6.0))])
+ splt.set_title('EventCollection: set_linestyle')
+
+
@image_comparison(baseline_images=['EventCollection_plot__set_linewidth'])
def test__EventCollection__set_linewidth():
'''
@@ -496,7 +509,7 @@ def test_polycollection_close():
vertsQuad * len(zpos), linewidth=0.25)
poly.set_alpha(0.7)
- ## need to have a z-value for *each* polygon = element!
+ # need to have a z-value for *each* polygon = element!
zs = []
cs = []
for z, c in zip(zpos, colors):
@@ -507,7 +520,7 @@ def test_polycollection_close():
ax.add_collection3d(poly, zs=zs, zdir='y')
- ## axis limit settings:
+ # axis limit settings:
ax.set_xlim3d(0, 4)
ax.set_zlim3d(0, 3)
ax.set_ylim3d(0, 4)
@@ -578,6 +591,12 @@ class MouseEvent(object):
assert_array_equal(indices['ind'], [0])
+@cleanup
+def test_linestyle_single_dashes():
+ plt.scatter([0, 1, 2], [0, 1, 2], linestyle=(0., [2., 2.]))
+ plt.draw()
+
+
if __name__ == '__main__':
import nose
nose.runmodule(argv=['-s', '--with-doctest'], exit=False)
diff --git a/lib/matplotlib/tests/test_lines.py b/lib/matplotlib/tests/test_lines.py
index 55aa360af737..8176728824aa 100644
--- a/lib/matplotlib/tests/test_lines.py
+++ b/lib/matplotlib/tests/test_lines.py
@@ -6,12 +6,14 @@
import six
-from nose.tools import assert_true
+import nose
+from nose.tools import assert_true, assert_raises
from timeit import repeat
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.testing.decorators import cleanup, image_comparison
+import sys
@cleanup
@@ -71,6 +73,14 @@ def test_set_line_coll_dash():
assert True
+@image_comparison(baseline_images=['line_dashes'], remove_text=True)
+def test_line_dashes():
+ fig = plt.figure()
+ ax = fig.add_subplot(1, 1, 1)
+
+ ax.plot(range(10), linestyle=(0, (3, 3)), lw=5)
+
+
@cleanup
def test_line_colors():
fig = plt.figure()
@@ -84,6 +94,29 @@ def test_line_colors():
assert True
+@cleanup
+def test_linestyle_variants():
+ fig = plt.figure()
+ ax = fig.add_subplot(1, 1, 1)
+ for ls in ["-", "solid", "--", "dashed",
+ "-.", "dashdot", ":", "dotted"]:
+ ax.plot(range(10), linestyle=ls)
+
+ fig.canvas.draw()
+ assert True
+
+
+@cleanup
+def test_valid_linestyles():
+ if sys.version_info[:2] < (2, 7):
+ raise nose.SkipTest("assert_raises as context manager "
+ "not supported with Python < 2.7")
+
+ line = mpl.lines.Line2D([], [])
+ with assert_raises(ValueError):
+ line.set_linestyle('aardvark')
+
+
@image_comparison(baseline_images=['line_collection_dashes'], remove_text=True)
def test_set_line_coll_dash_image():
fig = plt.figure()
@@ -101,5 +134,4 @@ def test_nan_is_sorted():
if __name__ == '__main__':
- import nose
nose.runmodule(argv=['-s', '--with-doctest'], exit=False)
diff --git a/lib/matplotlib/tests/test_patches.py b/lib/matplotlib/tests/test_patches.py
index 1c8549d29255..44856642b282 100644
--- a/lib/matplotlib/tests/test_patches.py
+++ b/lib/matplotlib/tests/test_patches.py
@@ -13,7 +13,7 @@
from matplotlib.patches import Polygon
from matplotlib.patches import Rectangle
-from matplotlib.testing.decorators import image_comparison
+from matplotlib.testing.decorators import image_comparison, cleanup
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import matplotlib.collections as mcollections
@@ -203,6 +203,36 @@ def test_patch_custom_linestyle():
ax.set_ylim([-1, 2])
+@cleanup
+def test_patch_linestyle_accents():
+ #: Test if linestyle can also be specified with short menoics
+ #: like "--"
+ #: c.f. Gihub issue #2136
+ star = mpath.Path.unit_regular_star(6)
+ circle = mpath.Path.unit_circle()
+ # concatenate the star with an internal cutout of the circle
+ verts = np.concatenate([circle.vertices, star.vertices[::-1]])
+ codes = np.concatenate([circle.codes, star.codes])
+
+ linestyles = ["-", "--", "-.", ":",
+ "solid", "dashed", "dashdot", "dotted"]
+
+ fig = plt.figure()
+ ax = fig.add_subplot(1, 1, 1)
+ for i, ls in enumerate(linestyles):
+ star = mpath.Path(verts + i, codes)
+ patch = mpatches.PathPatch(star,
+ linewidth=3, linestyle=ls,
+ facecolor=(1, 0, 0),
+ edgecolor=(0, 0, 1))
+ ax.add_patch(patch)
+
+ ax.set_xlim([-1, i + 1])
+ ax.set_ylim([-1, i + 1])
+ fig.canvas.draw()
+ assert True
+
+
def test_wedge_movement():
param_dict = {'center': ((0, 0), (1, 1), 'set_center'),
'r': (5, 8, 'set_radius'),