cross hair for data analysis

847 views
Skip to first unread message

nicolas commaux

unread,
May 16, 2014, 6:33:41 PM5/16/14
to pyqt...@googlegroups.com
Hi
I have been looking for a fast plotting toolbox for python for a while.
Of course matplotlib does a very good job but it is definitely designed more for beauty and integration than for speed.
pyqtgraph does a much better job (especially when integrated to qt using pyside).
I have trying to develop a small visualization gui with pyside and pyqtgraph to study data.
I acquire those data through an mdsplus database and plot them in a GraphicsWindow through up to 16 plotitems (the dataset in each plotitem frame is about 160000 points long).
It works extremely well until I try to add a crosshair on each plot.
I used the multiple examples to get the crosshair through adding a pair of infiniteline and then updating their position through a sigMouseMoved event. The idea being that the crosshair on each plotitem would show exactly the position of the cursor on the plotitem where the mouse pointer is. The example I attach is for now set to only acquire the position in the first plotitem (called VB1 in the code)
It works but it affects tremendously the performance. The framerate drops down to maybe one fps. The crosshair lags terribly.
Same thing if I try to use the zoombox, the box gets drawn extremely slowly.
I tried changing the thickness of the lines (I read in some cases it could slow down the plot) or replace the infiniteline by a pair of points but it dos not change a thing.
I suspect that the problem is the fact that every time the position of the mouse changes, it redraws everything including the datasets despite the fact that they don't change every time I change the position of the window.
We have where I work another tool written in idl that does something similar and the crosshair on this tool doesn't lag despite being displyed simultaneously on dozens of plotitems. I think in the case of idl, you can pick not to redraw the whole thing but only what changed.
I am wondering if something like that could be implemented (only redraw one item of a plot and not everything.
Or maybe I am completely wrong and that's not the problem.
By the way I am running python on windows 8. Would it make a difference on linux ?
Thanks in advance


vb_ui_test.py
vb_mainwindow.py

Julio Trevisan

unread,
May 16, 2014, 6:59:19 PM5/16/14
to pyqt...@googlegroups.com
Hi Nicolas
I am not the expert but my application also has a crosshair and I used a signal proxy to limit the number of times the "mouse moved" signal is emitted. Here is a bit of code as an example (I hope it makes sense).

class MyPlot(gr.PlotItem):

    def __init__(self, *args, **kwargs):

        ...

        self.proxy = gr.SignalProxy(self.scene().sigMouseMoved,
                                    rateLimit=5, # signals per second
                                    slot=self.mouseMoved)

(gr is an alias for pyqtgraph)

As for avoiding redrawing the data that is behind the crosshair, I would be more than happy to learn how to do this as well.

Julio


--
You received this message because you are subscribed to the Google Groups "pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyqtgraph+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/pyqtgraph/85860056-7b08-4328-a604-d613ee86d156%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

nicolas commaux

unread,
May 19, 2014, 8:18:28 PM5/19/14
to pyqt...@googlegroups.com
Hi Julio
Unfortunately I tried using a signal proxy to limit the frequency of the signal processing.
Unfortunately it didn't help.
This proves that the fact that the GUI is slow is probably due to the redrawing and not the event processing.
So it would be really nice if we could selectively redraw only the items that get updated.
Hopefully one the developers will notice the request since apparently I am not the only one who would be interested in that possibility.
Cheers

Luke Campagnola

unread,
May 30, 2014, 12:11:33 AM5/30/14
to pyqt...@googlegroups.com
When I run this (with MDS stuff replaced with numpy.random), moving the mouse updates the crosshair on all 16 plots, which of course forces all 16 plots to completely redraw. Was that the intent? Qt will automatically avoid redrawing items whenever possible, but it is not able to redraw only part of an item.

That should significantly reduce the load while drawing.


nicolas commaux

unread,
Jun 2, 2014, 5:14:34 PM6/2/14
to pyqt...@googlegroups.com
Hi Luke
Thanks for your reply.
The intent is to have the crosshair update on every plot simultaneously but the issue is that it is extremely slow (the crosshair position gets updated maybe once every second instead of smoothly tracking the position of the cursor) on my machine. I think it is redrawing every plot completely instead of just redrawing the crosshair while leaving the item containing the data (the plotitem).
I tried playing with downslampling. It didn't seem to change much.
I was wondering if there would be a possibility of redrawing only the infinitelines while leaving alone the other items on the plot (for example the data contained in the plotitem I create).
It would be very efficient not to redraw every single item on each window but just the one really changing. Do you think it would be possible ?

Michael Martin

unread,
Jun 3, 2014, 9:15:19 AM6/3/14
to pyqt...@googlegroups.com
Actually, I've done this, and you can move just the InfiniteLines by using their setPos() method. If you store the InfiniteLines with an alias (and didn't just addItem(InfiniteLine(...)) ), you can call the method from the alias, getting exactly the InfiniteLine you want without having to dig through the plot(s) you've added InfiniteLines to. 

nicolas commaux

unread,
Jun 3, 2014, 5:50:28 PM6/3/14
to pyqt...@googlegroups.com
Hi Michael.
That's what I did. I declared the infiniteline under an alias and then added the item.
Then I call the setpos method through the alias to change their position in the slot triggered by the sigmousemoved event (through a proxy limited to 15 updates a second not to generate too many events).
but it is very slow (an update of the crosshair maybe every second).
So that's probably not the trick.
I reattach the python files in case you want to ahve a look at them
Thanks
vb_mainwindow_2.py
vb_ui_test_2.py

Luke Campagnola

unread,
Jun 4, 2014, 10:28:59 AM6/4/14
to pyqt...@googlegroups.com
If you want per-item caching, then you might have a look at QGraphicsItem.CacheMode. I tried this many years ago and had trouble with it, but it may be worth a try again. It is disabled by default because it causes excessive memory use in many cases. If that doesn't work, then it would be helpful if you can send a version of your script that I can execute and that demonstrates the problem you are having. That way, we can actually profile it and determine the best way to improve performance.
 

mitjan...@gmail.com

unread,
Mar 13, 2017, 12:20:27 PM3/13/17
to pyqtgraph
Hi Nicholas,

I don't know if I'll get a reply, but I would really like to know if you solved the issue. I am having same problems, and there is not much info available on the issue.

mitjan...@gmail.com

unread,
Mar 16, 2017, 3:46:21 AM3/16/17
to pyqtgraph
This goes to anybody who stumbles upon same issue.

I ended disabling line updating through setPos method in mousemoved event. Instead I update line position only at data update events, which happen 10 times per second in my case, which is fast enough for me.
Reply all
Reply to author
Forward
0 new messages