VerticalLines

216 views
Skip to first unread message

Edmondo Giovannozzi

unread,
Apr 18, 2020, 12:25:06 PM4/18/20
to pyqtgraph
I needed to plot hundreds of vertical lines corresponding to some transitions.
At the beginning I tried to use InfiniteLine but it was too slow. At the end I arrived at this solution that seems to work.

class plotVerticalLines(pg.PlotDataItem):
    
    def dataBounds(self, ax, frac=1.0, orthoRange=None):
        return [None, None]

    def setVerticalLines(self, x):
        
        x = np.vstack((x,x)).T.astype(float)
        y = np.zeros_like(x)

        vb = self.getViewBox()
        xr, yr = vb.viewRange()
        
        y[:,0] = yr[0]
        y[:,1] = yr[1]
        
        self.setData(x.ravel(), y.ravel(), connect='pairs')
        
        vb.sigYRangeChanged.connect(self._y_range_changed)
    
    def _y_range_changed(self, viewbox):
        xr, yr = viewbox.viewRange()
        # get the original not transfomed clipped etc.
        x = self.xData
        y = self.yData
        y[0::2] = yr[0]
        y[1::2] = yr[1]
        self.setData(x, y, connect='pairs')


Have you comment?
or way to improve it?

I really thanks the author of this really great library. I was able to get what I wanted with just few lines of code.

Cheers



Oier Arcelus

unread,
Jan 20, 2022, 8:53:27 AM1/20/22
to pyqtgraph
Hi!

I am having the same problem, everything about pyqtgraph is so fast. But I have the same problem. I have to plot several vertical lines, at different heights, using spans depending on the number of different levels I need to set.

It looks something like this 

for key, values in prf.reflections.items():
     span = ((float(key) - 1)/prf.nphase, float(key)/prf.nphase)

for val in values:
     line = pg.InfiniteLine(pos=val, angle=90, pen=self.pen8, span=span)
     self.ui_mainwindow.peaks_graph.addItem(line)

This is painfully slow so I am wondering if there is a better way.


edmondo.g...@gmail.com

unread,
Jan 24, 2022, 6:06:36 AM1/24/22
to pyqtgraph
The span is the fraction of the View (that in my previous case was all the View) that the line span. Even if you are zooming. But from what I see in your case it seems that it has instead a physical meaning not related to your view (I may be wrong of course).

In may case I reset the span whenever the view change (due for example to a zoom or a pan action by the user). It will be easy to add the span in the object itself then use the memorized span  to calculate the correct y position in the  _y_range_changed method.

Add an arguments to the setVerticalLines:
 def setVerticalLines(self, x, spans):
        self.spans = spans

In _range_changesd retrieve the spans (Assuming they are (n,2) matrices) and normalize them to the viewBox and set the y array.
Add also a check to test if the spans are defined like:
if not hasattr(self,'spans'):
    return 

y[0::2] = self.spans[:,0] * (yr[1] - yr[0]) + yr[0]
y[1::2] = self.spans[:,1] * (yr[1] - yr[0]) + yr[0]

If instead your y positions are fixed it will be even easier as you don't need a method that change them when the viewbox changes.

keys = prf.reflections.keys()
values = prf.reflections.values()
x =  np.vstack((values,values)).T.astype(float)
y = np.zeros_like(x)
y[:,0] = (float(keys) - 1)/prf.nphase
y[:,1] =  float(key)/prf.nphase

.....setData(x.ravel(), y.ravel(), connect='pairs')

or plot or which ever you prefer
Reply all
Reply to author
Forward
0 new messages