diff --git a/examples/ROIExamples.py b/examples/ROIExamples.py new file mode 100644 index 00000000..fbf5a255 --- /dev/null +++ b/examples/ROIExamples.py @@ -0,0 +1,222 @@ +#!/usr/bin/python -i +# -*- coding: utf-8 -*- +## Add path to library (just for examples; you do not need this) +import sys, os +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..')) + + +from pyqtgraph.Qt import QtCore, QtGui +import numpy as np +import pyqtgraph as pg + +## Create image to display +arr = np.ones((100, 100), dtype=float) +arr[45:55, 45:55] = 0 +arr[25, :] = 5 +arr[:, 25] = 5 +arr[75, :] = 5 +arr[:, 75] = 5 +arr[50, :] = 10 +arr[:, 50] = 10 +arr += np.sin(np.linspace(0, 20, 100)).reshape(1, 100) +arr += np.random.normal(size=(100,100)) + + +## create GUI +app = QtGui.QApplication([]) +w = pg.GraphicsWindow(size=(800,800), border=True) + +text = """Data Selection From Image.
\n +Drag an ROI or its handles to update the selected image.
+Hold CTRL while dragging to snap to pixel boundaries
+and 15-degree rotation angles. +""" +w1 = w.addLayout(row=0, col=0) +label1 = w1.addLabel(text, row=0, col=0) +v1a = w1.addViewBox(row=1, col=0, lockAspect=True) +v1b = w1.addViewBox(row=2, col=0, lockAspect=True) +img1a = pg.ImageItem(arr) +v1a.addItem(img1a) +img1b = pg.ImageItem() +v1b.addItem(img1b) + +rois = [] +rois.append(pg.RectROI([20, 20], [20, 20], pen=(0,9))) +rois[-1].addRotateHandle([1,0], [0.5, 0.5]) +rois.append(pg.LineROI([0, 60], [20, 80], width=5, pen=(1,9))) +rois.append(pg.MultiLineROI([[20, 90], [50, 60], [60, 90]], width=5, pen=(2,9))) +rois.append(pg.EllipseROI([60, 10], [30, 20], pen=(3,9))) +rois.append(pg.CircleROI([80, 50], [20, 20], pen=(4,9))) +#rois.append(pg.LineSegmentROI([[110, 50], [20, 20]], pen=(5,9))) +#rois.append(pg.PolyLineROI([[110, 60], [20, 30], [50, 10]], pen=(6,9))) + +def update(roi): + img1b.setImage(roi.getArrayRegion(arr, img1a), levels=(0, arr.max())) + v1b.autoRange() + +for roi in rois: + roi.sigRegionChanged.connect(update) + v1a.addItem(roi) + +update(rois[-1]) + + + +text = """Extraction of traces from image data""" +w2 = w.addLayout(row=0, col=1) +label2 = w2.addLabel(text, row=0, col=0) +v2a = w2.addViewBox(row=1, col=0, lockAspect=True) +v2b = w2.addPlot(row=2, col=0) + + +text = """Building custom ROI types
+ROIs can be built with a variety of different handle types
+that scale and rotate the roi around an arbitrary center location +""" +w3 = w.addLayout(row=1, col=0) +label3 = w3.addLabel(text, row=0, col=0) +v3 = w3.addViewBox(row=1, col=0, lockAspect=True) + +r3a = pg.ROI([0,0], [10,10]) +v3.addItem(r3a) +## handles scaling horizontally around center +r3a.addScaleHandle([1, 0.5], [0.5, 0.5]) +r3a.addScaleHandle([0, 0.5], [0.5, 0.5]) + +## handles scaling vertically from opposite edge +r3a.addScaleHandle([0.5, 0], [0.5, 1]) +r3a.addScaleHandle([0.5, 1], [0.5, 0]) + +## handles scaling both vertically and horizontally +r3a.addScaleHandle([1, 1], [0, 0]) +r3a.addScaleHandle([0, 0], [1, 1]) + +r3b = pg.ROI([20,0], [10,10]) +v3.addItem(r3b) +## handles rotating around center +r3b.addRotateHandle([1, 1], [0.5, 0.5]) +r3b.addRotateHandle([0, 0], [0.5, 0.5]) + +## handles rotating around opposite corner +r3b.addRotateHandle([1, 0], [0, 1]) +r3b.addRotateHandle([0, 1], [1, 0]) + +## handles rotating/scaling around center +r3b.addScaleRotateHandle([0, 0.5], [0.5, 0.5]) +r3b.addScaleRotateHandle([1, 0.5], [0.5, 0.5]) + + +text = """Transforming objects with ROI""" +w4 = w.addLayout(row=1, col=1) +label4 = w4.addLabel(text, row=0, col=0) +v4 = w4.addViewBox(row=1, col=0, lockAspect=True) +g = pg.GridItem() +v4.addItem(g) +r4 = pg.ROI([0,0], [100,100]) +r4.addRotateHandle([1,0], [0.5, 0.5]) +r4.addRotateHandle([0,1], [0.5, 0.5]) +img4 = pg.ImageItem(arr) +v4.addItem(r4) +img4.setParentItem(r4) + + + + + +#v = w.addViewBox(colspan=2) + +#v.invertY(True) ## Images usually have their Y-axis pointing downward +#v.setAspectLocked(True) + + + +### Create image items, add to scene and set position +#im1 = pg.ImageItem(arr) +#im2 = pg.ImageItem(arr) +#v.addItem(im1) +#v.addItem(im2) +#im2.moveBy(110, 20) +#v.setRange(QtCore.QRectF(0, 0, 200, 120)) + +#im3 = pg.ImageItem() +#v2 = w.addViewBox(1,0) +#v2.addItem(im3) +#v2.setRange(QtCore.QRectF(0, 0, 60, 60)) +#v2.invertY(True) +#v2.setAspectLocked(True) +##im3.moveBy(0, 130) +#im3.setZValue(10) + +#im4 = pg.ImageItem() +#v3 = w.addViewBox(1,1) +#v3.addItem(im4) +#v3.setRange(QtCore.QRectF(0, 0, 60, 60)) +#v3.invertY(True) +#v3.setAspectLocked(True) +##im4.moveBy(110, 130) +#im4.setZValue(10) + +### create the plot +#pi1 = w.addPlot(2,0, colspan=2) +##pi1 = pg.PlotItem() +##s.addItem(pi1) +##pi1.scale(0.5, 0.5) +##pi1.setGeometry(0, 170, 300, 100) + +#lastRoi = None + +#def updateRoi(roi): + #global im1, im2, im3, im4, arr, lastRoi + #if roi is None: + #return + #lastRoi = roi + #arr1 = roi.getArrayRegion(im1.image, img=im1) + #im3.setImage(arr1) + #arr2 = roi.getArrayRegion(im2.image, img=im2) + #im4.setImage(arr2) + #updateRoiPlot(roi, arr1) + +#def updateRoiPlot(roi, data=None): + #if data is None: + #data = roi.getArrayRegion(im1.image, img=im1) + #if data is not None: + #roi.curve.setData(data.mean(axis=1)) + + +### Create a variety of different ROI types +#rois = [] +#rois.append(pg.TestROI([0, 0], [20, 20], maxBounds=QtCore.QRectF(-10, -10, 230, 140), pen=(0,9))) +#rois.append(pg.LineROI([0, 0], [20, 20], width=5, pen=(1,9))) +#rois.append(pg.MultiLineROI([[0, 50], [50, 60], [60, 30]], width=5, pen=(2,9))) +#rois.append(pg.EllipseROI([110, 10], [30, 20], pen=(3,9))) +#rois.append(pg.CircleROI([110, 50], [20, 20], pen=(4,9))) +#rois.append(pg.LineSegmentROI([[110, 50], [20, 20]], pen=(5,9))) +#rois.append(pg.PolyLineROI([[110, 60], [20, 30], [50, 10]], pen=(6,9))) +##rois.append(pg.PolygonROI([[2,0], [2.1,0], [2,.1]], pen=(5,9))) +##rois.append(SpiralROI([20,30], [1,1], pen=mkPen(0))) + +### Add each ROI to the scene and link its data to a plot curve with the same color +#for r in rois: + #v.addItem(r) + #c = pi1.plot(pen=r.pen) + #r.curve = c + #r.sigRegionChanged.connect(updateRoi) + +#def updateImage(): + #global im1, arr, lastRoi + #r = abs(np.random.normal(loc=0, scale=(arr.max()-arr.min())*0.1, size=arr.shape)) + #im1.updateImage(arr + r) + #updateRoi(lastRoi) + #for r in rois: + #updateRoiPlot(r) + +### Rapidly update one of the images with random noise +#t = QtCore.QTimer() +#t.timeout.connect(updateImage) +#t.start(50) + + + +## Start Qt event loop unless running in interactive mode. +if sys.flags.interactive != 1: + app.exec_() diff --git a/graphicsItems/ImageItem.py b/graphicsItems/ImageItem.py index 2a0cb336..a814c0ca 100644 --- a/graphicsItems/ImageItem.py +++ b/graphicsItems/ImageItem.py @@ -343,9 +343,9 @@ class ImageItem(GraphicsObject): if ev.button() != QtCore.Qt.LeftButton: ev.ignore() return - - ev.accept() - self.drawAt(ev.pos(), ev) + elif self.drawKernel is not None: + ev.accept() + self.drawAt(ev.pos(), ev) def mouseClickEvent(self, ev): if ev.button() == QtCore.Qt.RightButton: diff --git a/graphicsItems/ROI.py b/graphicsItems/ROI.py index 24d50453..13bb5961 100644 --- a/graphicsItems/ROI.py +++ b/graphicsItems/ROI.py @@ -28,7 +28,7 @@ from .UIGraphicsItem import UIGraphicsItem __all__ = [ 'ROI', 'TestROI', 'RectROI', 'EllipseROI', 'CircleROI', 'PolygonROI', - 'LineROI', 'MultiLineROI', 'LineSegmentROI', 'SpiralROI', + 'LineROI', 'MultiLineROI', 'LineSegmentROI', 'PolyLineROI', 'SpiralROI', ]