Search code examples
pythonipythonjupyter-notebookpyqtgraph

pyqtgraph: simplest way to pause ipython script until user has placed a roi object


I would like to implement the following sequence in a script and keep it as simple as possible (i.e., if possible avoid explicit multi-threading):

  1. Process some data. The result is a 2d numpy array, say a

  2. Show a using pw = pg.show(a) (after import pyqtgraph as qt and using pyqt5)

  3. Define a circular roi, e.g. via

circ = pg.CircleROI([1024,1024],300) pw.addItem(circ)

  1. The user moves the roi to the relevant place

  2. Read out the roi coordinates, continue with the script (where the roi coordinates are used)

My question is: How can I define a break in the script between 3. and 5. such that the user has time to do 4., in a way that the pyqtgraph is not blocked? Ideally, the user would confirm the correct roi position by pressing enter or clicking a button.

Edit: The script is executed in IPython with qt gui.

Edit2: Here is a full test script to be executed in IPython. What I want is that the user can move the circle before the roi is evaluated, i.e., that the print output is something different than (slice(1024, 1174, None), slice(1024, 1174, None))

import numpy as np
import pyqtgraph as pg

a = np.array(range(2048**2)).reshape((2048,2048))
pw = pg.show(a)
circ = pg.CircleROI([1024,1024],300)
pw.addItem(circ)



roi = np.s_[int(circ.pos().x()):int(circ.pos().x()+circ.size().x()/2),\
            int(circ.pos().y()):int(circ.pos().y()+circ.size().x()/2)]

print(roi)

Solution

  • 1. raw_input('') in an IPython console

    If the script is running in an IPython console, you could try adding a

    raw_input("Press Enter to continue...")
    

    or input() in python3 to pause the script. The user has to go back and press enter in the ipython console but the code is simple.

    import numpy as np
    import pyqtgraph as pg
    
    a = np.array(range(2048**2)).reshape((2048,2048))
    pw = pg.show(a)
    circ = pg.CircleROI([1024,1024],300)
    pw.addItem(circ)
    
    raw_input("Press Enter to continue...")
    
    roi = np.s_[int(circ.pos().x()):int(circ.pos().x()+circ.size().x()/2),\
                int(circ.pos().y()):int(circ.pos().y()+circ.size().x()/2)]
    
    print(roi)
    

    2. Monkey patching keyPressEvent

    Another solution could be to monkey patch the keyPressEvent in the ImageWindow.

    Beware that this solution uses both globals and monkey patching, please make sure you know what this means.

    import numpy as np
    from PyQt4 import QtCore, QtGui
    import pyqtgraph as pg
    
    
    a = np.array(range(2048**2)).reshape((2048,2048))
    pw = pg.show(a)
    circ = pg.CircleROI([1024,1024],300)
    pw.addItem(circ)
    
    def myKeyPressEvent(e):
        if e.key() == QtCore.Qt.Key_Enter or e.key() == QtCore.Qt.Key_Return:
            global selectionFinished
            selectionFinished = True
    
    # Monkey patch
    selectionFinished = False
    pw.keyPressEvent = myKeyPressEvent
    
    while not selectionFinished:
        QtGui.QApplication.processEvents()
    
    roi = np.s_[int(circ.pos().x()):int(circ.pos().x()+circ.size().x()/2),\
                int(circ.pos().y()):int(circ.pos().y()+circ.size().x()/2)]
    
    print(roi)