Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b8698ab

Browse filesBrowse files
authored
Merge pull request #6710 from tacaswell/fix_refactor_dash_scaling
FIX: refactor dash scaling
2 parents 1c08c16 + 3ef3f5b commit b8698ab
Copy full SHA for b8698ab

File tree

Expand file treeCollapse file tree

6 files changed

+179
-82
lines changed
Filter options
Expand file treeCollapse file tree

6 files changed

+179
-82
lines changed

‎lib/matplotlib/backend_bases.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backend_bases.py
+1-13Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -871,16 +871,7 @@ def get_dashes(self):
871871
872872
Default value is None
873873
"""
874-
if rcParams['_internal.classic_mode']:
875-
return self._dashes
876-
else:
877-
scale = max(1.0, self.get_linewidth())
878-
offset, dashes = self._dashes
879-
if offset is not None:
880-
offset = offset * scale
881-
if dashes is not None:
882-
dashes = [x * scale for x in dashes]
883-
return offset, dashes
874+
return self._dashes
884875

885876
def get_forced_alpha(self):
886877
"""
@@ -1062,10 +1053,7 @@ def set_linestyle(self, style):
10621053
`lines.dotted_pattern`. One may also specify customized dash
10631054
styles by providing a tuple of (offset, dash pairs).
10641055
"""
1065-
offset, dashes = lines.get_dash_pattern(style)
1066-
10671056
self._linestyle = style
1068-
self.set_dashes(offset, dashes)
10691057

10701058
def set_url(self, url):
10711059
"""

‎lib/matplotlib/collections.py

Copy file name to clipboardExpand all lines: lib/matplotlib/collections.py
+75-24Lines changed: 75 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,16 @@
1313

1414
import six
1515
from six.moves import zip
16+
try:
17+
from math import gcd
18+
except ImportError:
19+
# LPy workaround
20+
from fractions import gcd
1621
import warnings
22+
1723
import numpy as np
1824
import numpy.ma as ma
25+
1926
import matplotlib as mpl
2027
import matplotlib.cbook as cbook
2128
import matplotlib.colors as mcolors
@@ -24,13 +31,11 @@
2431
import matplotlib.transforms as transforms
2532
import matplotlib.artist as artist
2633
from matplotlib.artist import allow_rasterization
27-
import matplotlib.backend_bases as backend_bases
2834
import matplotlib.path as mpath
2935
from matplotlib import _path
3036
import matplotlib.mlab as mlab
3137
import matplotlib.lines as mlines
3238

33-
3439
CIRCLE_AREA_FACTOR = 1.0 / np.sqrt(np.pi)
3540

3641

@@ -117,6 +122,14 @@ def __init__(self,
117122
"""
118123
artist.Artist.__init__(self)
119124
cm.ScalarMappable.__init__(self, norm, cmap)
125+
# list of un-scaled dash patterns
126+
# this is needed scaling the dash pattern by linewidth
127+
self._us_linestyles = [(None, None)]
128+
# list of dash patterns
129+
self._linestyles = [(None, None)]
130+
# list of unbroadcast/scaled linewidths
131+
self._us_lw = [0]
132+
self._linewidths = [0]
120133

121134
self.set_edgecolor(edgecolors)
122135
self.set_facecolor(facecolors)
@@ -313,7 +326,7 @@ def draw(self, renderer):
313326
if do_single_path_optimization:
314327
gc.set_foreground(tuple(edgecolors[0]))
315328
gc.set_linewidth(self._linewidths[0])
316-
gc.set_linestyle(self._linestyles[0])
329+
gc.set_dashes(*self._linestyles[0])
317330
gc.set_antialiased(self._antialiaseds[0])
318331
gc.set_url(self._urls[0])
319332
renderer.draw_markers(
@@ -489,8 +502,12 @@ def set_linewidth(self, lw):
489502
lw = mpl.rcParams['lines.linewidth']
490503
else:
491504
lw = 0
505+
# get the un-scaled/broadcast lw
506+
self._us_lw = self._get_value(lw)
492507

493-
self._linewidths = self._get_value(lw)
508+
# scale all of the dash patterns.
509+
self._linewidths, self._linestyles = self._bcast_lwls(
510+
self._us_lw, self._us_linestyles)
494511
self.stale = True
495512

496513
def set_linewidths(self, lw):
@@ -534,29 +551,63 @@ def set_linestyle(self, ls):
534551
try:
535552
if cbook.is_string_like(ls) and cbook.is_hashable(ls):
536553
ls = cbook.ls_mapper.get(ls, ls)
537-
dashes = [mlines.get_dash_pattern(ls)]
538-
elif cbook.iterable(ls):
554+
dashes = [mlines._get_dash_pattern(ls)]
555+
else:
539556
try:
540-
dashes = []
541-
for x in ls:
542-
if cbook.is_string_like(x):
543-
x = cbook.ls_mapper.get(x, x)
544-
dashes.append(mlines.get_dash_pattern(x))
545-
elif cbook.iterable(x) and len(x) == 2:
546-
dashes.append(x)
547-
else:
548-
raise ValueError()
557+
dashes = [mlines._get_dash_pattern(ls)]
549558
except ValueError:
550-
if len(ls) == 2:
551-
dashes = [ls]
552-
else:
553-
raise ValueError()
554-
else:
555-
raise ValueError()
559+
dashes = [mlines._get_dash_pattern(x) for x in ls]
560+
556561
except ValueError:
557-
raise ValueError('Do not know how to convert %s to dashes' % ls)
558-
self._linestyles = dashes
559-
self.stale = True
562+
raise ValueError(
563+
'Do not know how to convert {!r} to dashes'.format(ls))
564+
565+
# get the list of raw 'unscaled' dash patterns
566+
self._us_linestyles = dashes
567+
568+
# broadcast and scale the lw and dash patterns
569+
self._linewidths, self._linestyles = self._bcast_lwls(
570+
self._us_lw, self._us_linestyles)
571+
572+
@staticmethod
573+
def _bcast_lwls(linewidths, dashes):
574+
'''Internal helper function to broadcast + scale ls/lw
575+
576+
In the collection drawing code the linewidth and linestyle are
577+
cycled through as circular buffers (via v[i % len(v)]). Thus,
578+
if we are going to scale the dash pattern at set time (not
579+
draw time) we need to do the broadcasting now and expand both
580+
lists to be the same length.
581+
582+
Parameters
583+
----------
584+
linewidths : list
585+
line widths of collection
586+
587+
dashes : list
588+
dash specification (offset, (dash pattern tuple))
589+
590+
Returns
591+
-------
592+
linewidths, dashes : list
593+
Will be the same length, dashes are scaled by paired linewidth
594+
595+
'''
596+
if mpl.rcParams['_internal.classic_mode']:
597+
return linewidths, dashes
598+
# make sure they are the same length so we can zip them
599+
if len(dashes) != len(linewidths):
600+
l_dashes = len(dashes)
601+
l_lw = len(linewidths)
602+
GCD = gcd(l_dashes, l_lw)
603+
dashes = list(dashes) * (l_lw // GCD)
604+
linewidths = list(linewidths) * (l_dashes // GCD)
605+
606+
# scale the dash patters
607+
dashes = [mlines._scale_dashes(o, d, lw)
608+
for (o, d), lw in zip(dashes, linewidths)]
609+
610+
return linewidths, dashes
560611

561612
def set_linestyles(self, ls):
562613
"""alias for set_linestyle"""

‎lib/matplotlib/lines.py

Copy file name to clipboardExpand all lines: lib/matplotlib/lines.py
+71-39Lines changed: 71 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313

1414
import numpy as np
1515
from numpy import ma
16-
from matplotlib import verbose
1716
from . import artist, colors as mcolors
1817
from .artist import Artist
1918
from .cbook import (iterable, is_string_like, is_numlike, ls_mapper_r,
20-
pts_to_prestep, pts_to_poststep, pts_to_midstep)
19+
pts_to_prestep, pts_to_poststep, pts_to_midstep, ls_mapper,
20+
is_hashable)
2121

2222
from .path import Path
2323
from .transforms import Bbox, TransformedPath, IdentityTransform
@@ -36,24 +36,49 @@
3636
from matplotlib import _path
3737

3838

39-
def get_dash_pattern(style):
40-
"""
41-
Given a dash pattern name from 'solid', 'dashed', 'dashdot' or
42-
'dotted', returns the (offset, dashes) pattern.
39+
def _get_dash_pattern(style):
40+
"""Convert linestyle -> dash pattern
41+
4342
"""
44-
if style == 'solid':
43+
# go from short hand -> full strings
44+
if is_string_like(style) and is_hashable(style):
45+
style = ls_mapper.get(style, style)
46+
# un-dashed styles
47+
if style in ['solid', 'None']:
4548
offset, dashes = None, None
49+
# dashed styles
4650
elif style in ['dashed', 'dashdot', 'dotted']:
4751
offset = 0
4852
dashes = tuple(rcParams['lines.{}_pattern'.format(style)])
53+
#
4954
elif isinstance(style, tuple):
5055
offset, dashes = style
5156
else:
5257
raise ValueError('Unrecognized linestyle: %s' % str(style))
5358

59+
# normalize offset to be positive and shorter than the dash cycle
60+
if dashes is not None and offset is not None:
61+
dsum = sum(dashes)
62+
if dsum:
63+
offset %= dsum
64+
5465
return offset, dashes
5566

5667

68+
def _scale_dashes(offset, dashes, lw):
69+
if rcParams['_internal.classic_mode']:
70+
return offset, dashes
71+
scale = max(1.0, lw)
72+
scaled_offset = scaled_dashes = None
73+
if offset is not None:
74+
scaled_offset = offset * scale
75+
if dashes is not None:
76+
scaled_dashes = [x * scale if x is not None else None
77+
for x in dashes]
78+
79+
return scaled_offset, scaled_dashes
80+
81+
5782
def segment_hits(cx, cy, x, y, radius):
5883
"""
5984
Determine if any line segments are within radius of a
@@ -360,10 +385,15 @@ def __init__(self, xdata, ydata,
360385

361386
self._linestyles = None
362387
self._drawstyle = None
363-
self._linewidth = None
388+
self._linewidth = linewidth
364389

390+
# scaled dash + offset
365391
self._dashSeq = None
366392
self._dashOffset = 0
393+
# unscaled dash + offset
394+
# this is needed scaling the dash pattern by linewidth
395+
self._us_dashSeq = None
396+
self._us_dashOffset = 0
367397

368398
self.set_linestyle(linestyle)
369399
self.set_drawstyle(drawstyle)
@@ -1013,9 +1043,13 @@ def set_linewidth(self, w):
10131043
ACCEPTS: float value in points
10141044
"""
10151045
w = float(w)
1046+
10161047
if self._linewidth != w:
10171048
self.stale = True
10181049
self._linewidth = w
1050+
# rescale the dashes + offset
1051+
self._dashOffset, self._dashSeq = _scale_dashes(
1052+
self._us_dashOffset, self._us_dashSeq, self._linewidth)
10191053

10201054
def _split_drawstyle_linestyle(self, ls):
10211055
'''Split drawstyle from linestyle string
@@ -1093,31 +1127,31 @@ def set_linestyle(self, ls):
10931127
ls : { ``'-'``, ``'--'``, ``'-.'``, ``':'``} and more see description
10941128
The line style.
10951129
"""
1096-
if not is_string_like(ls):
1097-
if len(ls) != 2:
1098-
raise ValueError()
1099-
1100-
self.set_dashes(ls[1])
1101-
self._dashOffset = ls[0]
1102-
self._linestyle = "--"
1103-
return
1104-
ds, ls = self._split_drawstyle_linestyle(ls)
1105-
if ds is not None:
1106-
self.set_drawstyle(ds)
1107-
1108-
if ls in [' ', '', 'none']:
1109-
ls = 'None'
1110-
1111-
if ls not in self._lineStyles:
1112-
try:
1113-
ls = ls_mapper_r[ls]
1114-
except KeyError:
1115-
raise ValueError(("You passed in an invalid linestyle, "
1116-
"`{0}`. See "
1117-
"docs of Line2D.set_linestyle for "
1118-
"valid values.").format(ls))
1130+
if is_string_like(ls):
1131+
ds, ls = self._split_drawstyle_linestyle(ls)
1132+
if ds is not None:
1133+
self.set_drawstyle(ds)
1134+
1135+
if ls in [' ', '', 'none']:
1136+
ls = 'None'
1137+
1138+
if ls not in self._lineStyles:
1139+
try:
1140+
ls = ls_mapper_r[ls]
1141+
except KeyError:
1142+
raise ValueError(("You passed in an invalid linestyle, "
1143+
"`{0}`. See "
1144+
"docs of Line2D.set_linestyle for "
1145+
"valid values.").format(ls))
1146+
self._linestyle = ls
1147+
else:
1148+
self._linestyle = '--'
11191149

1120-
self._linestyle = ls
1150+
# get the unscaled dashes
1151+
self._us_dashOffset, self._us_dashSeq = _get_dash_pattern(ls)
1152+
# compute the linewidth scaled dashes
1153+
self._dashOffset, self._dashSeq = _scale_dashes(
1154+
self._us_dashOffset, self._us_dashSeq, self._linewidth)
11211155

11221156
@docstring.dedent_interpd
11231157
def set_marker(self, marker):
@@ -1227,10 +1261,7 @@ def set_dashes(self, seq):
12271261
if seq == (None, None) or len(seq) == 0:
12281262
self.set_linestyle('-')
12291263
else:
1230-
self.set_linestyle('--')
1231-
if self._dashSeq != seq:
1232-
self.stale = True
1233-
self._dashSeq = seq # TODO: offset ignored for now
1264+
self.set_linestyle((0, seq))
12341265

12351266
def _draw_lines(self, renderer, gc, path, trans):
12361267
self._lineFunc(renderer, gc, path, trans)
@@ -1258,21 +1289,22 @@ def _draw_steps_mid(self, renderer, gc, path, trans):
12581289

12591290
def _draw_solid(self, renderer, gc, path, trans):
12601291
gc.set_linestyle('solid')
1292+
gc.set_dashes(self._dashOffset, self._dashSeq)
12611293
renderer.draw_path(gc, path, trans)
12621294

12631295
def _draw_dashed(self, renderer, gc, path, trans):
12641296
gc.set_linestyle('dashed')
1265-
if self._dashSeq is not None:
1266-
gc.set_dashes(self._dashOffset, self._dashSeq)
1267-
1297+
gc.set_dashes(self._dashOffset, self._dashSeq)
12681298
renderer.draw_path(gc, path, trans)
12691299

12701300
def _draw_dash_dot(self, renderer, gc, path, trans):
12711301
gc.set_linestyle('dashdot')
1302+
gc.set_dashes(self._dashOffset, self._dashSeq)
12721303
renderer.draw_path(gc, path, trans)
12731304

12741305
def _draw_dotted(self, renderer, gc, path, trans):
12751306
gc.set_linestyle('dotted')
1307+
gc.set_dashes(self._dashOffset, self._dashSeq)
12761308
renderer.draw_path(gc, path, trans)
12771309

12781310
def update_from(self, other):

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.