0

I am new to PyQt and Im developing a utility where a user can import data from an excel file and plot its X and Y in a 2d scatter plot using below code:

def plot_2d_scatter(graphWidget,x,z,color=(66, 245, 72)):
    graphWidget.clear()
    brush = pg.mkBrush(color)
    scatter = pg.ScatterPlotItem(size=5, brush=brush)
    scatter.addPoints(x,z)
    graphWidget.addItem(scatter)

Now I want a functionality which will allow the user to move his mouse over the scatter plot points using a cross hair / pointer / etc and select points on the scatter plot.

Whenever the user does a left click on the crosshair / marker on the scatter plot, I want its x,y coordinates to be saved for further use.

I have already tried the below snippet from somewhere on internet for using mouse events and getting my scatter points , but this didnt give me a cross hair that falls on my scatter points

def mouseMoved(self, evt):
    pos = evt
    if self.plotWidget.sceneBoundingRect().contains(pos):
        mousePoint = self.plotWidget.plotItem.vb.mapSceneToView(pos)
        mx = np.array([abs(float(i) - float(mousePoint.x())) for i in self.plotx])
        index = mx.argmin()
        if index >= 0 and index < len(self.plotx):
            self.cursorlabel.setHtml(
                "<span style='font-size: 12pt'>x={:0.1f}, \
                 <span style='color: red'>y={:0.1f}</span>".format(
                    self.plotx[index], self.ploty[index])
            )
        self.vLine.setPos(self.plotx[index])
        self.hLine.setPos(self.ploty[index])

Any guidance is thankfully appreciated

  • but this didnt give me a cross hair that falls on my scatter points ... what does it mean ? – pippo1980 Jun 08 '22 at 09:10
  • the code above mentioned does not produce a cross hair on top of the plotted points – Arjun Warrier Jun 08 '22 at 11:38
  • add setCursor() https://stackoverflow.com/questions/56145023/pyqt5-how-to-set-a-custom-mouse-pointer-for-each-role – pippo1980 Jun 08 '22 at 12:10
  • https://www.pythonguis.com/faq/pyqt-show-custom-cursor-pyqtgraph/ – pippo1980 Jun 08 '22 at 12:26
  • there are expert here, but think they need an mre https://stackoverflow.com/help/minimal-reproducible-example – pippo1980 Jun 08 '22 at 12:29
  • tried my best below, I would be interested in a way to be able to navigate scatter plots, where I've more than one y value for the same x value, your def mouseMoved(self, evt): won't work in this case – pippo1980 Jun 08 '22 at 22:31

1 Answers1

0

my best fast effort, never used pg untill today:

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QDesktopWidget, QWidget

from PyQt5.QtCore import Qt

from PyQt5 import QtGui, QtCore, QtWidgets

import pyqtgraph as pg

import numpy as np

class MyApp(QMainWindow):
    
    def __init__(self, parent=None):
        super(MyApp, self).__init__(parent)
        
        
        self.resize(781, 523)
        
        self.graphWidget = pg.PlotWidget()
        self.setCentralWidget(self.graphWidget)
        
        self.show()
        
        self.x = [1,2,3,4,5,6,7,8,9,5,6,7,8]
        
        self.y = [1,2,3,4,5,6,7,8,9,5,6,7,8]
        
        
        # self.y.reverse()
        
            
        self.plot_2d_scatter(self.graphWidget, self.x, self.y)
        
        self.cursor = Qt.CrossCursor
        
        # self.cursor = Qt.BlankCursor
        
        self.graphWidget.setCursor(self.cursor)
       
        # Add crosshair lines.
        self.crosshair_v = pg.InfiniteLine(angle=90, movable=False)
        self.crosshair_h = pg.InfiniteLine(angle=0, movable=False)
        self.graphWidget.addItem(self.crosshair_v, ignoreBounds=True)
        self.graphWidget.addItem(self.crosshair_h, ignoreBounds=True)
        self.cursorlabel = pg.TextItem()

        
        self.graphWidget.addItem(self.cursorlabel)
        
        
        self.proxy = pg.SignalProxy(self.graphWidget.scene().sigMouseMoved, rateLimit=60, slot=self.update_crosshair)
        
        self.mouse_x = None
        
        self.mouse_y = None
        
    def plot_2d_scatter(self,graphWidget,x,z,color=(66, 245, 72)):
        # graphWidget.clear()
        brush = pg.mkBrush(color)
        scatter = pg.ScatterPlotItem(size=5, brush=brush)
        scatter.addPoints(x,z)
        graphWidget.addItem(scatter)
    
    

    def update_crosshair(self, e):
            
        pos = e[0]
        if self.graphWidget.sceneBoundingRect().contains(pos):
            mousePoint = self.graphWidget.plotItem.vb.mapSceneToView(pos)
            mx = np.array([abs(float(i) - float(mousePoint.x())) for i in self.x])
            index = mx.argmin()
            if index >= 0 and index < len(self.x):
                self.cursorlabel.setText(
                        str((self.x[index], self.y[index])))
                
                self.crosshair_v.setPos(self.x[index])
                self.crosshair_h.setPos(self.y[index]) 
                
                self.mouse_x = self.crosshair_v.setPos(self.x[index])
                self.mouse_y = self.crosshair_h.setPos(self.y[index])
                
                self.mouse_x = (self.x[index])
                self.mouse_y = (self.y[index])
            
            
    def mousePressEvent(self, e):
        if e.buttons() & QtCore.Qt.LeftButton:
            print('pressed')
            
            # if self.mouse_x in self.x and self.mouse_y in self.y:
           
            print(self.mouse_x, self.mouse_y)
            
    
if __name__ == '__main__':

    app = QApplication(sys.argv)
    myapp = MyApp()
    # myapp.show()

    try:
        sys.exit(app.exec_())
    except SystemExit:
        print('Closing Window...')

it just prints out the coordinate of pressed point in graph

copied from https://www.pythonguis.com/faq/pyqt-show-custom-cursor-pyqtgraph/ and your piece of code result looks like:

enter image description here

there are other examples on SO like Trying to get cursor with coordinate display within a pyqtgraph plotwidget in PyQt5 and others

pippo1980
  • 2,181
  • 3
  • 14
  • 30