Skip to content

Fix #5917. New dash patterns. Scale dashes by lw #5926

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 8, 2016
Merged
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
39 changes: 16 additions & 23 deletions lib/matplotlib/backend_bases.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
from matplotlib import is_interactive
from matplotlib import get_backend
from matplotlib._pylab_helpers import Gcf
from matplotlib import lines

from matplotlib.transforms import Bbox, TransformedBbox, Affine2D

Expand Down Expand Up @@ -771,14 +772,6 @@ class GraphicsContextBase(object):
An abstract base class that provides color, line styles, etc...
"""

# a mapping from dash styles to suggested offset, dash pairs
dashd = {
'solid': (None, None),
'dashed': (0, (6.0, 6.0)),
'dashdot': (0, (3.0, 5.0, 1.0, 5.0)),
'dotted': (0, (1.0, 3.0)),
}

def __init__(self):
self._alpha = 1.0
self._forced_alpha = False # if True, _alpha overrides A from RGBA
Expand Down Expand Up @@ -870,7 +863,16 @@ def get_dashes(self):

Default value is None
"""
return self._dashes
if rcParams['_internal.classic_mode']:
return self._dashes
else:
scale = max(1.0, self.get_linewidth())
offset, dashes = self._dashes
if offset is not None:
offset = offset * scale
if dashes is not None:
dashes = [x * scale for x in dashes]
return offset, dashes

def get_forced_alpha(self):
"""
Expand Down Expand Up @@ -1047,21 +1049,12 @@ def set_linewidth(self, w):
def set_linestyle(self, style):
"""
Set the linestyle to be one of ('solid', 'dashed', 'dashdot',
'dotted'). One may specify customized dash styles by providing
a tuple of (offset, dash pairs). For example, the predefiend
linestyles have following values.:

'dashed' : (0, (6.0, 6.0)),
'dashdot' : (0, (3.0, 5.0, 1.0, 5.0)),
'dotted' : (0, (1.0, 3.0)),
'dotted'). These are defined in the rcParams
`lines.dashed_pattern`, `lines.dashdot_pattern` and
`lines.dotted_pattern`. One may also specify customized dash
styles by providing a tuple of (offset, dash pairs).
"""

if style in self.dashd:
offset, dashes = self.dashd[style]
elif isinstance(style, tuple):
offset, dashes = style
else:
raise ValueError('Unrecognized linestyle: %s' % str(style))
offset, dashes = lines.get_dash_pattern(style)

self._linestyle = style
self.set_dashes(offset, dashes)
Expand Down
12 changes: 3 additions & 9 deletions lib/matplotlib/collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import matplotlib.path as mpath
from matplotlib import _path
import matplotlib.mlab as mlab
import matplotlib.lines as mlines


CIRCLE_AREA_FACTOR = 1.0 / np.sqrt(np.pi)
Expand Down Expand Up @@ -531,23 +532,16 @@ def set_linestyle(self, ls):
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]]
else:
raise ValueError()
dashes = [mlines.get_dash_pattern(ls)]
elif cbook.iterable(ls):
try:
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])
else:
raise ValueError()
dashes.append(mlines.get_dash_pattern(x))
elif cbook.iterable(x) and len(x) == 2:
dashes.append(x)
else:
Expand Down
18 changes: 18 additions & 0 deletions lib/matplotlib/lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,24 @@
from matplotlib import _path


def get_dash_pattern(style):
"""
Given a dash pattern name from 'solid', 'dashed', 'dashdot' or
'dotted', returns the (offset, dashes) pattern.
"""
if style == 'solid':
offset, dashes = None, None
elif style in ['dashed', 'dashdot', 'dotted']:
offset = 0
dashes = tuple(rcParams['lines.{}_pattern'.format(style)])
elif isinstance(style, tuple):
offset, dashes = style
else:
raise ValueError('Unrecognized linestyle: %s' % str(style))

return offset, dashes


def segment_hits(cx, cy, x, y, radius):
"""
Determine if any line segments are within radius of a
Expand Down
3 changes: 3 additions & 0 deletions lib/matplotlib/mpl-data/stylelib/classic.mplstyle
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ lines.dash_capstyle : butt # butt|round|projecting
lines.solid_joinstyle : round # miter|round|bevel
lines.solid_capstyle : projecting # butt|round|projecting
lines.antialiased : True # render lines in antialiased (no jaggies)
lines.dashed_pattern : 6, 6
lines.dashdot_pattern : 3, 5, 1, 5
lines.dotted_pattern : 1, 3

### Marker props
markers.fillstyle: full
Expand Down
15 changes: 9 additions & 6 deletions lib/matplotlib/rcsetup.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,18 +275,18 @@ def validate_maskedarray(v):


class validate_nseq_float(object):
def __init__(self, n):
def __init__(self, n=None):
self.n = n

def __call__(self, s):
"""return a seq of n floats or raise"""
if isinstance(s, six.string_types):
s = s.split(',')
s = [x.strip() for x in s.split(',')]
err_msg = _str_err_msg
else:
err_msg = _seq_err_msg

if len(s) != self.n:
if self.n is not None and len(s) != self.n:
raise ValueError(err_msg.format(n=self.n, num=len(s), s=s))

try:
Expand All @@ -296,18 +296,18 @@ def __call__(self, s):


class validate_nseq_int(object):
def __init__(self, n):
def __init__(self, n=None):
self.n = n

def __call__(self, s):
"""return a seq of n ints or raise"""
if isinstance(s, six.string_types):
s = s.split(',')
s = [x.strip() for x in s.split(',')]
err_msg = _str_err_msg
else:
err_msg = _seq_err_msg

if len(s) != self.n:
if self.n is not None and len(s) != self.n:
raise ValueError(err_msg.format(n=self.n, num=len(s), s=s))

try:
Expand Down Expand Up @@ -836,6 +836,9 @@ def validate_hist_bins(s):
'lines.solid_joinstyle': ['round', validate_joinstyle],
'lines.dash_capstyle': ['butt', validate_capstyle],
'lines.solid_capstyle': ['projecting', validate_capstyle],
'lines.dashed_pattern': [[2.8, 1.2], validate_nseq_float()],
'lines.dashdot_pattern': [[4.8, 1.2, 0.8, 1.2], validate_nseq_float()],
'lines.dotted_pattern': [[1.2, 0.6], validate_nseq_float()],

# marker props
'markers.fillstyle': ['full', validate_fillstyle],
Expand Down
5 changes: 5 additions & 0 deletions matplotlibrc.template
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ backend : $TEMPLATE_BACKEND
#lines.solid_capstyle : projecting # butt|round|projecting
#lines.antialiased : True # render lines in antialiased (no jaggies)

# The three standard dash patterns. These are scaled by the linewidth.
#lines.dashed_pattern : 2.8, 1.2
#lines.dashdot_pattern : 4.8, 1.2, 0.8, 1.2
#lines.dotted_pattern : 1.2, 0.6

#markers.fillstyle: full # full|left|right|bottom|top|none

### PATCHES
Expand Down
2 changes: 1 addition & 1 deletion src/py_converters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ int convert_gcagg(PyObject *pygc, void *gcp)
convert_from_attr(pygc, "_antialiased", &convert_bool, &gc->isaa) &&
convert_from_attr(pygc, "_capstyle", &convert_cap, &gc->cap) &&
convert_from_attr(pygc, "_joinstyle", &convert_join, &gc->join) &&
convert_from_attr(pygc, "_dashes", &convert_dashes, &gc->dashes) &&
convert_from_method(pygc, "get_dashes", &convert_dashes, &gc->dashes) &&
convert_from_attr(pygc, "_cliprect", &convert_rect, &gc->cliprect) &&
convert_from_method(pygc, "get_clip_path", &convert_clippath, &gc->clippath) &&
convert_from_method(pygc, "get_snap", &convert_snap, &gc->snap_mode) &&
Expand Down