4
4
import numpy as np
5
5
from collections import OrderedDict
6
6
from typing import List , Optional
7
- from pyqtgraph import DateAxisItem , ErrorBarItem
7
+ from pyqtgraph import DateAxisItem , ErrorBarItem , mkPen
8
8
from pydm .utilities import remove_protocol , is_qt_designer
9
9
from pydm .widgets .channel import PyDMChannel
10
10
from pydm .widgets .timeplot import TimePlotCurveItem
11
11
from pydm .widgets import PyDMTimePlot
12
- from qtpy .QtCore import QObject , QTimer , Property , Signal , Slot
12
+ from qtpy .QtCore import QObject , QTimer , Property , Signal , Slot , Qt
13
13
from qtpy .QtGui import QColor
14
14
import logging
15
15
from math import * # noqa
@@ -51,9 +51,15 @@ class ArchivePlotCurveItem(TimePlotCurveItem):
51
51
archive_data_received_signal = Signal ()
52
52
archive_channel_connection = Signal (bool )
53
53
prompt_archive_request = Signal ()
54
+ axis_time_plot = Signal (str )
54
55
55
56
def __init__ (
56
- self , channel_address : Optional [str ] = None , use_archive_data : bool = True , liveData : bool = True , ** kws
57
+ self ,
58
+ channel_address : Optional [str ] = None ,
59
+ use_archive_data : bool = True ,
60
+ liveData : bool = True ,
61
+ current_point_always_vis : bool = False ,
62
+ ** kws
57
63
):
58
64
self .archive_channel = None
59
65
super (ArchivePlotCurveItem , self ).__init__ (** kws )
@@ -62,6 +68,11 @@ def __init__(
62
68
self ._archiveBufferSize = DEFAULT_ARCHIVE_BUFFER_SIZE
63
69
self .archive_data_buffer = np .zeros ((2 , self ._archiveBufferSize ), order = "f" , dtype = float )
64
70
self ._liveData = liveData
71
+ self .current_point_always_vis = current_point_always_vis
72
+ self ._extension_line = BasePlotCurveItem ()
73
+
74
+ if not self .current_point_always_vis :
75
+ self ._extension_line .hide ()
65
76
66
77
# When optimized or mean value data is requested, we can display error bars representing
67
78
# the full range of values retrieved
@@ -242,10 +253,46 @@ def redrawCurve(self, min_x=None, max_x=None) -> None:
242
253
)
243
254
244
255
self .setData (y = y , x = x )
256
+
257
+ if self .current_point_always_vis :
258
+ self .add_infinite_line ()
259
+ else :
260
+ self ._extension_line .hide ()
261
+
245
262
except (ZeroDivisionError , OverflowError , TypeError ):
246
263
# Solve an issue with pyqtgraph and initial downsampling
247
264
pass
248
265
266
+ def add_infinite_line (self ) -> None :
267
+ """
268
+ Creates a dotted line from the lastest point in the buffer
269
+ (live or archived depending on if live data is active).
270
+ """
271
+ if self ._liveData :
272
+ if self .data_buffer .size == 0 :
273
+ return
274
+ x_last = self .data_buffer [:, - 1 ]
275
+ y_last = self .data_buffer [:, - 1 ]
276
+ else :
277
+ if self .archive_data_buffer .size == 0 :
278
+ return
279
+ x_last = self .archive_data_buffer [:, - 1 ]
280
+ y_last = self .archive_data_buffer [:, - 1 ]
281
+
282
+ x_infinity = x_last [0 ] + APPROX_SECONDS_300_YEARS
283
+
284
+ x_line = np .array ([x_last [0 ], x_infinity ])
285
+ y_line = np .array ([y_last [1 ], y_last [1 ]])
286
+
287
+ dotted_pen = mkPen (self ._pen .color (), width = self ._pen .width (), style = Qt .DotLine )
288
+
289
+ self ._extension_line .setFillLevel = None
290
+ self ._extension_line .setBrush = None
291
+ self ._extension_line .setPen (dotted_pen )
292
+ self ._extension_line .setData (x_line , y_line )
293
+
294
+ self ._extension_line .show ()
295
+
249
296
def initializeArchiveBuffer (self ) -> None :
250
297
"""
251
298
Initialize the archive data buffer used for this curve.
@@ -319,6 +366,18 @@ def receiveNewValue(self, new_value):
319
366
if self ._liveData :
320
367
super ().receiveNewValue (new_value )
321
368
369
+ @BasePlotCurveItem .y_axis_name .setter
370
+ def y_axis_name (self , axis_name : str ) -> None :
371
+ """
372
+ Set the name of the y-axis that should be associated with this curve.
373
+ Also move's the curve's error bar item.
374
+ Parameters
375
+ ----------
376
+ axis_name: str
377
+ """
378
+ BasePlotCurveItem .y_axis_name .fset (self , axis_name )
379
+ self .axis_time_plot .emit (axis_name )
380
+
322
381
323
382
class FormulaCurveItem (BasePlotCurveItem ):
324
383
"""
@@ -1009,10 +1068,20 @@ def addYChannel(
1009
1068
)
1010
1069
if not is_qt_designer ():
1011
1070
self .requestDataFromArchiver ()
1071
+
1072
+ if yAxisName is not None :
1073
+ self .plotItem .linkDataToAxis (curve ._extension_line , yAxisName )
1074
+ curve .axis_time_plot .connect (self .moveExtensionLine )
1075
+
1012
1076
return curve
1013
1077
1014
1078
def addFormulaChannel (self , yAxisName : str , ** kwargs ) -> FormulaCurveItem :
1015
1079
"""Creates a FormulaCurveItem and links it to the given y axis"""
1016
1080
FormulaCurve = FormulaCurveItem (yAxisName = yAxisName , ** kwargs )
1017
1081
self .plotItem .linkDataToAxis (FormulaCurve , yAxisName )
1018
1082
return FormulaCurve
1083
+
1084
+ @Slot (str )
1085
+ def moveExtensionLine (self , name : str ) -> None :
1086
+ curve = self .sender ()
1087
+ self .plotItem .linkDataToAxis (curve ._extension_line , name )
0 commit comments