@@ -278,8 +278,6 @@ def isInitialized(self):
278
278
279
279
# line ########################################################################
280
280
281
- SOLID , DASHED , DASHDOT , DOTTED = "-" , "--" , "-." , ":"
282
-
283
281
284
282
class GLLines2D (object ):
285
283
"""Object rendering curve as a polyline
@@ -288,17 +286,16 @@ class GLLines2D(object):
288
286
:param yVboData: Y coordinates VBO
289
287
:param colorVboData: VBO of colors
290
288
:param distVboData: VBO of distance along the polyline
291
- :param str style: Line style in: '-', '--', '-.', ':'
292
289
:param List[float] color: RGBA color as 4 float in [0, 1]
293
290
:param float width: Line width
294
- :param float dashPeriod: Period of dashes
291
+ :param List[float] dashPattern:
292
+ "unscaled" dash pattern as 4 lengths in points (dash1, gap1, dash2, gap2).
293
+ This pattern is scaled with the line width.
294
+ Set to () to draw solid lines (default), and to None to disable rendering.
295
295
:param drawMode: OpenGL drawing mode
296
296
:param List[float] offset: Translation of coordinates (ox, oy)
297
297
"""
298
298
299
- STYLES = SOLID , DASHED , DASHDOT , DOTTED
300
- """Supported line styles"""
301
-
302
299
_SOLID_PROGRAM = Program (
303
300
vertexShader = """
304
301
#version 120
@@ -383,11 +380,10 @@ def __init__(
383
380
yVboData = None ,
384
381
colorVboData = None ,
385
382
distVboData = None ,
386
- style = SOLID ,
387
383
color = (0.0 , 0.0 , 0.0 , 1.0 ),
388
384
gapColor = None ,
389
385
width = 1 ,
390
- dashPeriod = 10.0 ,
386
+ dashPattern = () ,
391
387
drawMode = None ,
392
388
offset = (0.0 , 0.0 ),
393
389
):
@@ -419,26 +415,11 @@ def __init__(
419
415
self .color = color
420
416
self .gapColor = gapColor
421
417
self .width = width
422
- self ._style = None
423
- self .style = style
424
- self .dashPeriod = dashPeriod
418
+ self .dashPattern = dashPattern
425
419
self .offset = offset
426
420
427
421
self ._drawMode = drawMode if drawMode is not None else gl .GL_LINE_STRIP
428
422
429
- @property
430
- def style (self ):
431
- """Line style (Union[str,None])"""
432
- return self ._style
433
-
434
- @style .setter
435
- def style (self , style ):
436
- if style in _MPL_NONES :
437
- self ._style = None
438
- else :
439
- assert style in self .STYLES
440
- self ._style = style
441
-
442
423
@classmethod
443
424
def init (cls ):
444
425
"""OpenGL context initialization"""
@@ -449,39 +430,23 @@ def render(self, context):
449
430
450
431
:param RenderContext context:
451
432
"""
452
- width = self .width / 72.0 * context .dpi
453
-
454
- style = self .style
455
- if style is None :
433
+ if self .dashPattern is None : # Nothing to display
456
434
return
457
435
458
- elif style == SOLID :
436
+ if self . dashPattern == (): # No dash: solid line
459
437
program = self ._SOLID_PROGRAM
460
438
program .use ()
461
439
462
- else : # DASHED, DASHDOT, DOTTED
440
+ else : # Dashed line defined by 4 control points
463
441
program = self ._DASH_PROGRAM
464
442
program .use ()
465
443
466
- dashPeriod = self .dashPeriod * width
467
- if self .style == DOTTED :
468
- dash = (
469
- 0.2 * dashPeriod ,
470
- 0.5 * dashPeriod ,
471
- 0.7 * dashPeriod ,
472
- dashPeriod ,
473
- )
474
- elif self .style == DASHDOT :
475
- dash = (
476
- 0.3 * dashPeriod ,
477
- 0.5 * dashPeriod ,
478
- 0.6 * dashPeriod ,
479
- dashPeriod ,
480
- )
481
- else :
482
- dash = (0.5 * dashPeriod , dashPeriod , dashPeriod , dashPeriod )
483
-
484
- gl .glUniform4f (program .uniforms ["dash" ], * dash )
444
+ # Scale pattern by width, convert from lengths in points to offsets in pixels
445
+ scale = self .width / 72.0 * context .dpi
446
+ dashOffsets = tuple (
447
+ offset * scale for offset in numpy .cumsum (self .dashPattern )
448
+ )
449
+ gl .glUniform4f (program .uniforms ["dash" ], * dashOffsets )
485
450
486
451
if self .gapColor is None :
487
452
# Use fully transparent color which gets discarded in shader
@@ -540,7 +505,7 @@ def render(self, context):
540
505
yPosAttrib , 1 , gl .GL_FLOAT , False , 0 , self .yVboData
541
506
)
542
507
543
- gl .glLineWidth (width )
508
+ gl .glLineWidth (self . width / 72.0 * context . dpi )
544
509
gl .glDrawArrays (self ._drawMode , 0 , self .xVboData .size )
545
510
546
511
gl .glDisable (gl .GL_LINE_SMOOTH )
@@ -1220,11 +1185,10 @@ def __init__(
1220
1185
colorData = None ,
1221
1186
xError = None ,
1222
1187
yError = None ,
1223
- lineStyle = SOLID ,
1224
1188
lineColor = (0.0 , 0.0 , 0.0 , 1.0 ),
1225
1189
lineGapColor = None ,
1226
1190
lineWidth = 1 ,
1227
- lineDashPeriod = 20 ,
1191
+ lineDashPattern = () ,
1228
1192
marker = SQUARE ,
1229
1193
markerColor = (0.0 , 0.0 , 0.0 , 1.0 ),
1230
1194
markerSize = 7 ,
@@ -1311,11 +1275,10 @@ def deduce_baseline(baseline):
1311
1275
)
1312
1276
1313
1277
self .lines = GLLines2D ()
1314
- self .lines .style = lineStyle
1315
1278
self .lines .color = lineColor
1316
1279
self .lines .gapColor = lineGapColor
1317
1280
self .lines .width = lineWidth
1318
- self .lines .dashPeriod = lineDashPeriod
1281
+ self .lines .dashPattern = lineDashPattern
1319
1282
self .lines .offset = self .offset
1320
1283
1321
1284
self .points = Points2D ()
@@ -1336,15 +1299,13 @@ def deduce_baseline(baseline):
1336
1299
1337
1300
distVboData = _proxyProperty (("lines" , "distVboData" ))
1338
1301
1339
- lineStyle = _proxyProperty (("lines" , "style" ))
1340
-
1341
1302
lineColor = _proxyProperty (("lines" , "color" ))
1342
1303
1343
1304
lineGapColor = _proxyProperty (("lines" , "gapColor" ))
1344
1305
1345
1306
lineWidth = _proxyProperty (("lines" , "width" ))
1346
1307
1347
- lineDashPeriod = _proxyProperty (("lines" , "dashPeriod " ))
1308
+ lineDashPattern = _proxyProperty (("lines" , "dashPattern " ))
1348
1309
1349
1310
marker = _proxyProperty (("points" , "marker" ))
1350
1311
@@ -1362,7 +1323,7 @@ def prepare(self):
1362
1323
"""Rendering preparation: build indices and bounding box vertices"""
1363
1324
if self .xVboData is None :
1364
1325
xAttrib , yAttrib , cAttrib , dAttrib = None , None , None , None
1365
- if self .lineStyle in ( DASHED , DASHDOT , DOTTED ) :
1326
+ if self .lineDashPattern :
1366
1327
dists = distancesFromArrays (self .xData , self .yData , self ._ratio )
1367
1328
if self .colorData is None :
1368
1329
xAttrib , yAttrib , dAttrib = vertexBuffer (
@@ -1393,7 +1354,7 @@ def render(self, context):
1393
1354
1394
1355
:param RenderContext context: Rendering information
1395
1356
"""
1396
- if self .lineStyle in ( DASHED , DASHDOT , DOTTED ) :
1357
+ if self .lineDashPattern :
1397
1358
visibleRanges = context .plotFrame .transformedDataRanges
1398
1359
xLimits = visibleRanges .x
1399
1360
yLimits = visibleRanges .y if self .yaxis == "left" else visibleRanges .y2
@@ -1450,7 +1411,7 @@ def pick(self, xPickMin, yPickMin, xPickMax, yPickMax):
1450
1411
:rtype: Union[List[int],None]
1451
1412
"""
1452
1413
if (
1453
- (self .marker is None and self .lineStyle is None )
1414
+ (self .marker is None and self .lineDashPattern is None )
1454
1415
or self .xMin > xPickMax
1455
1416
or xPickMin > self .xMax
1456
1417
or self .yMin > yPickMax
@@ -1464,7 +1425,7 @@ def pick(self, xPickMin, yPickMin, xPickMax, yPickMax):
1464
1425
yPickMin = yPickMin - self .offset [1 ]
1465
1426
yPickMax = yPickMax - self .offset [1 ]
1466
1427
1467
- if self .lineStyle is not None :
1428
+ if self .lineDashPattern is not None :
1468
1429
# Using Cohen-Sutherland algorithm for line clipping
1469
1430
with numpy .errstate (invalid = "ignore" ): # Ignore NaN comparison warnings
1470
1431
codes = (
0 commit comments