class MPlotWidget(QtGui.QWidget): def __init__(self, parent=None): super(MPlotWidget, self).__init__(parent) self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() self.plotbutton = QtGui.QPushButton('Plot') self.zoombutton = QtGui.QPushButton('Zoom') self.zoombutton.clicked.connect(self.zoom) self.panbutton = QtGui.QPushButton('Pan') self.panbutton.clicked.connect(self.pan) self.homebutton = QtGui.QPushButton('Home') self.homebutton.clicked.connect(self.home) self.savebutton = QtGui.QPushButton('Save') self.savebutton.clicked.connect(self.save) layout = QtGui.QVBoxLayout() layout.addWidget(self.toolbar) layout.addWidget(self.canvas) buttonbox = QtGui.QHBoxLayout() buttonbox.addWidget(self.plotbutton) buttonbox.addWidget(self.zoombutton) buttonbox.addWidget(self.panbutton) buttonbox.addWidget(self.homebutton) buttonbox.addWidget(self.savebutton) layout.addLayout(buttonbox) self.setLayout(layout) self.ax = self.figure.add_subplot(111) self.ax.hold(False) def home(self): self.toolbar.home() def zoom(self): self.toolbar.zoom() def pan(self): self.toolbar.pan() def save(self): self.figure.savefig('1.png') """
class Window(QtGui.QDialog): def __init__(self, parent=None): super(Window, self).__init__(parent) self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() # Just some button self.button = QtGui.QPushButton('Plot') self.button.clicked.connect(self.plot) self.button1 = QtGui.QPushButton('Zoom') self.button1.clicked.connect(self.zoom) self.button2 = QtGui.QPushButton('Pan') self.button2.clicked.connect(self.pan) self.button3 = QtGui.QPushButton('Home') self.button3.clicked.connect(self.home) # set the layout layout = QtGui.QVBoxLayout() layout.addWidget(self.toolbar) layout.addWidget(self.canvas) layout.addWidget(self.button) layout.addWidget(self.button1) layout.addWidget(self.button2) layout.addWidget(self.button3) self.setLayout(layout) def home(self): self.toolbar.home() def zoom(self): self.toolbar.zoom() def pan(self): self.toolbar.pan() def plot(self): ''' plot some random stuff ''' data = [random.random() for i in range(25)] ax = self.figure.add_subplot(111) ax.hold(False) ax.plot(data, '*-') self.canvas.draw()
class Window(QtGui.QDialog): def __init__(self, parent=None): super(Window, self).__init__(parent) self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() # Just some button self.button = QtGui.QPushButton('Plot') self.button.clicked.connect(self.plot) self.button1 = QtGui.QPushButton('Zoom') self.button1.clicked.connect(self.zoom) self.button2 = QtGui.QPushButton('Pan') self.button2.clicked.connect(self.pan) self.button3 = QtGui.QPushButton('Home') self.button3.clicked.connect(self.home) # set the layout layout = QtGui.QVBoxLayout() layout.addWidget(self.toolbar) layout.addWidget(self.canvas) layout.addWidget(self.button) layout.addWidget(self.button1) layout.addWidget(self.button2) layout.addWidget(self.button3) self.setLayout(layout) def home(self): self.toolbar.home() def zoom(self): self.toolbar.zoom() def pan(self): self.toolbar.pan() def plot(self): ''' plot some random stuff ''' data = [random.random() for i in range(25)] ax = self.figure.add_subplot(111) ax.hold(False) ax.plot(data, '*-') self.canvas.draw()
class Window(QtGui.QDialog): def __init__(self, parent=None): super(Window, self).__init__(parent) self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() ## # Start Button ## self.button = QtGui.QPushButton('Start') ## self.button.clicked.connect(self.plot) ## # set the layout layout = QtGui.QVBoxLayout() layout.addWidget(self.canvas) ## layout.addWidget(self.button) self.setLayout(layout) global ser, Array, num_rows, num_cols, Matrix, count, sensor_num ser = sensorInit() num_rows = 7 num_cols = 4 Array = bytearray(num_rows*num_cols) Matrix = np.zeros((num_cols,num_rows)) count = 33 sensor_num = 24 #timer info self.timer = QtCore.QBasicTimer() self.timer.start(count, self) self.step = 0 def timerEvent(self, event): if event.timerId() == self.timer.timerId(): self.update() Array = readSensors(ser, sensor_num) Matrix = matrixConvert(Array, num_rows, num_cols) ax = self.figure.add_subplot(111) ax.imshow(Matrix, interpolation='nearest', cmap='Spectral') self.canvas.draw() super(Window, self).timerEvent(event)
class Grafica(QWidget): valores = (20, 35, 30, 35, 27) # valores de ejemplo def __init__(self, parent=None): super(Grafica, self).__init__() # FIGUREANDO self.ordenadas = np.arange(5) self.width = 1 # the width of the bars self.figure, self.ax = plt.subplots() #self.figure = plt.figure() self.line = self.ax.bar(self.ordenadas, self.valores, self.width, color='g') #self.line, = plt.plot(self.data) plt.ion() # animate N = 10 self.xs = collections.deque(maxlen=N) self.ys = collections.deque(maxlen=N) self.xs.append(0) self.ys.append(0) self.ax = self.figure.add_subplot(111) self.ax.hold(False) self.ax.set_ylim([0, 360]) self.canvas = FigureCanvas(self.figure) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() self.canvas.show() # set the layout self.layout = QVBoxLayout() self.layout.addWidget(self.toolbar) self.layout.addWidget(self.canvas) self.setLayout(self.layout) def add_sample(self, valores): self.valores = valores self.line = self.ax.bar(self.ordenadas, self.valores, self.width, color='g') self.canvas.draw() # update the plot
class Window(QtGui.QDialog): def __init__(self, parent=None): super(Window, self).__init__(parent) self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.canvas.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() # Timestream info self.timestreamLabel = QtGui.QLabel('Time-stream root path:') self.timestreamText = QtGui.QLineEdit('') self.timestreamText.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed) self.timestreamDateLabel = QtGui.QLabel('Start date (yyyy_mm_dd_hh_mm_ss):') self.timestreamDateText = QtGui.QLineEdit('') self.timestreamDateText.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed) self.timestreamTimeLabel = QtGui.QLabel('Time interval (seconds):') self.timestreamTimeText = QtGui.QLineEdit('') self.timestreamTimeText.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed) self.initStreamTimeButton = QtGui.QPushButton('&Initialise timestream by time') self.initStreamTimeButton.clicked.connect(self.initialiseTimestreamByTime) self.initStreamFileButton = QtGui.QPushButton('&Initialise timestream by files') self.initStreamFileButton.clicked.connect(self.initialiseTimestreamByFiles) # Image loading and processing self.loadImageButton = QtGui.QPushButton('&Load (next) image') self.loadImageButton.clicked.connect(self.loadImage) self.rotateImageButton = QtGui.QPushButton('&Rotate 90-deg') self.rotateImageButton.clicked.connect(self.rotateImage90Degrees) self.slider = QtGui.QSlider(QtCore.Qt.Horizontal) self.slider.setFocusPolicy(QtCore.Qt.StrongFocus) self.slider.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed) self.slider.setTickPosition(QtGui.QSlider.TicksBothSides) self.slider.setMinimum(-16) self.slider.setMaximum(16) self.slider.setValue(0) self.slider.setTickInterval(4) self.slider.setSingleStep(1) self.slider.valueChanged.connect(self.rotateSmallAngle) self.applySmallRotationButton = QtGui.QPushButton('&Apply') self.applySmallRotationButton.clicked.connect(self.applySmallRotation) self.loadCamCalibButton = QtGui.QPushButton('Load &cam. param.') self.loadCamCalibButton.clicked.connect(self.loadCamCalib) self.colorcardRadioButton = QtGui.QRadioButton('Select color car&d') self.colorcardRadioButton.setChecked(False) self.colorcardRadioButton.clicked.connect(self.selectWhat) self.trayRadioButton = QtGui.QRadioButton('Select &tray') self.trayRadioButton.setChecked(False) self.trayRadioButton.clicked.connect(self.selectWhat) self.trayRoundCheckBox = QtGui.QCheckBox('Round') self.trayRoundCheckBox.setChecked(True) self.potRadioButton = QtGui.QRadioButton('Select &pot') self.potRadioButton.setChecked(False) self.potRadioButton.clicked.connect(self.selectWhat) self.zoomButton = QtGui.QPushButton('&Zoom') self.zoomButton.setCheckable(True) self.zoomButton.clicked.connect(self.zoom) self.panButton = QtGui.QPushButton('&Pan') self.panButton.setCheckable(True) self.panButton.clicked.connect(self.pan) self.homeButton = QtGui.QPushButton('&Home') self.homeButton.clicked.connect(self.home) self.correctColorButton = QtGui.QPushButton('Correct colo&r') self.correctColorButton.clicked.connect(self.correctColor) self.save2PipelineButton = QtGui.QPushButton('&Save as pipeline settings') self.save2PipelineButton.clicked.connect(self.savePipelineSettings) self.testPipelineButton = QtGui.QPushButton('Test &pipeline processing') self.testPipelineButton.clicked.connect(self.testPipeline) self.status = QtGui.QTextEdit('') self.status.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding) self.mousePosition = QtGui.QLabel('') # set the layout layout = QtGui.QHBoxLayout() rightWidget = QtGui.QWidget() buttonlayout = QtGui.QVBoxLayout(rightWidget) buttonlayout.addWidget(self.timestreamLabel) buttonlayout.addWidget(self.timestreamText) buttonlayout.addWidget(self.timestreamDateLabel) buttonlayout.addWidget(self.timestreamDateText) buttonlayout.addWidget(self.timestreamTimeLabel) buttonlayout.addWidget(self.timestreamTimeText) buttonlayout.addWidget(self.initStreamTimeButton) buttonlayout.addWidget(self.initStreamFileButton) buttonlayout.addWidget(self.loadImageButton) buttonlayout.addWidget(self.loadCamCalibButton) buttonlayout.addWidget(self.rotateImageButton) layoutSmallRotation = QtGui.QHBoxLayout() layoutSmallRotation.addWidget(self.slider) layoutSmallRotation.addWidget(self.applySmallRotationButton) buttonlayout.addLayout(layoutSmallRotation) buttonlayout.addWidget(self.colorcardRadioButton) layoutTrayShape = QtGui.QHBoxLayout() layoutTrayShape.addWidget(self.trayRadioButton) layoutTrayShape.addWidget(self.trayRoundCheckBox) buttonlayout.addLayout(layoutTrayShape) buttonlayout.addWidget(self.potRadioButton) buttonlayout.addWidget(self.zoomButton) buttonlayout.addWidget(self.panButton) buttonlayout.addWidget(self.homeButton) buttonlayout.addWidget(self.correctColorButton) buttonlayout.addWidget(self.save2PipelineButton) buttonlayout.addWidget(self.testPipelineButton) buttonlayout.addWidget(self.status) buttonlayout.addWidget(self.mousePosition) rightWidget.setMaximumWidth(250) leftLayout = QtGui.QVBoxLayout() leftLayout.addWidget(self.toolbar) leftLayout.addWidget(self.canvas) layout.addWidget(rightWidget) layout.addLayout(leftLayout) self.setLayout(layout) self.group = QtGui.QButtonGroup() self.group.addButton(self.colorcardRadioButton) self.group.addButton(self.trayRadioButton) self.group.addButton(self.potRadioButton) self.loadPreviousInputs() self.panMode = False self.zoomMode = False self.ts = None self.tsImages = None self.ax = None self.plotRect = None self.plotImg = None self.image = None self.potTemplate = None self.UndistMapX = None self.UndistMapY = None self.trayAspectRatio = 0.835 self.colorcardAspectRatio = 1.5 self.potAspectRatio = 1.0 self.leftClicks = [] self.colorcardParams = None self.scriptPath = os.path.dirname(os.path.realpath(__file__)) self.timestreamRootPath = None self.pl = None # Ouput parameters self.ImageSize = None self.colorcardList = [] self.trayList = [] self.potList = [] self.rotationAngle = 0.0 self.smaleRotationAngle = 0.0 self.CameraMatrix = None self.DistCoefs = None self.isDistortionCorrected = False self.settingFileName = None def selectWhat(self): if self.trayRadioButton.isChecked(): self.status.append('Start selecting tray.') elif self.colorcardRadioButton.isChecked(): self.status.append('Start selecting color bar.') else: self.status.append('Start selecting pot.') def home(self): self.toolbar.home() def zoom(self): self.toolbar.zoom() if not self.zoomMode: self.zoomMode = True self.panMode = False self.panButton.setChecked(False) else: self.zoomMode = False def pan(self): self.toolbar.pan() if not self.panMode: self.panMode = True self.zoomMode = False self.zoomButton.setChecked(False) else: self.panMode = False def initialiseTimestreamByTime(self): self.timestreamRootPath = str(self.timestreamText.text()) if len(self.timestreamRootPath) > 0: self.status.append('Initialise a timestream at ' + str(self.timestreamRootPath)) self.ts = timestream.TimeStream() self.ts.load(self.timestreamRootPath) self.status.append('Done') startDate = None timeInterval = None date = str(self.timestreamDateText.text()) if len(date) > 0: startDate = timestream.parse.ts_parse_date(date) time = str(self.timestreamTimeText.text()) if len(time) > 0: timeInterval = int(eval(time)) self.tsImages = self.ts.iter_by_timepoints(start = startDate, interval = timeInterval, remove_gaps=False) self.loadImage() else: self.status.append('Please provide timestream root path.') def initialiseTimestreamByFiles(self): self.timestreamRootPath = str(self.timestreamText.text()) if len(self.timestreamRootPath) > 0: self.status.append('Initialise a timestream at ' + str(self.timestreamRootPath)) self.ts = timestream.TimeStream() self.ts.load(self.timestreamRootPath) self.status.append('Done') self.tsImages = self.ts.iter_by_files() self.loadImage() else: self.status.append('Please provide timestream root path.') def loadImage(self): ''' load and show an image''' if self.tsImages != None: try: tsImage = self.tsImages.next() if tsImage.pixels == np.array([]): self.status.append('Missing image.') except: tsImage.pixels == np.array([]) self.status.append('There is no more images.') if tsImage.pixels == np.array([]): self.image = None self.updateFigure() return self.image = tsImage.pixels fname = tsImage.path else: fname = QtGui.QFileDialog.getOpenFileName(self, 'Open image', '/mnt/phenocam/a_data/TimeStreams/Borevitz/BVZ0036/BVZ0036-GC02L-C01~fullres-orig/2014/2014_06/2014_06_24/2014_06_24_08/') app.processEvents() if len(fname) == 0: return self.image = cv2.imread(str(fname))[:,:,::-1] self.status.append('Loaded image from ' + str(fname)) # reset all outputs # self.colorcardList = [] # self.trayList = [] # self.potList = [] self.isDistortionCorrected = False if self.rotationAngle != None: self.image = cd.rotateImage(self.image, self.rotationAngle + self.smaleRotationAngle) # Undistort image if mapping available if not self.isDistortionCorrected and self.UndistMapX != None and self.UndistMapY != None: self.image = cv2.remap(self.image.astype(np.uint8), self.UndistMapX, self.UndistMapY, cv2.INTER_CUBIC) self.isDistortionCorrected = True self.updateFigure() def changeCursor(self, event): # cursor = Cursor(self.ax, useblit=True, color='red', linewidth=1) self.canvas.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor )) def updateFigure(self, image = None, resetFigure = False): if self.image != None: if image == None: image = self.image if self.ax == None: self.ax = self.figure.add_subplot(111) self.ax.figure.canvas.mpl_connect('button_press_event', self.onMouseClicked) self.ax.figure.canvas.mpl_connect('motion_notify_event', self.onMouseMoves) self.ax.figure.canvas.mpl_connect('figure_enter_event', self.changeCursor) self.ax.hold(False) if self.plotImg == None or resetFigure: self.plotImg = self.ax.imshow(image) else: self.plotImg.set_data(image) self.figure.tight_layout() xs, ys = [], [] for Rect in self.colorcardList: tl, bl, br, tr = Rect xs = xs + [tl[0], bl[0], br[0], tr[0], tl[0], np.nan] ys = ys + [tl[1], bl[1], br[1], tr[1], tl[1], np.nan] for Rect in self.trayList: tl, bl, br, tr = Rect xs = xs + [tl[0], bl[0], br[0], tr[0], tl[0], np.nan] ys = ys + [tl[1], bl[1], br[1], tr[1], tl[1], np.nan] for Rect in self.potList: tl, bl, br, tr = Rect xs = xs + [tl[0], bl[0], br[0], tr[0], tl[0], np.nan] ys = ys + [tl[1], bl[1], br[1], tr[1], tl[1], np.nan] for x,y in self.leftClicks: xs = xs + [x] ys = ys + [y] # if self.crosshair != None: # xs = xs + [np.nan, 0, self.image.shape[1], np.nan, self.crosshair[0], self.crosshair[0], np.nan] # ys = ys + [np.nan, self.crosshair[1], self.crosshair[1], np.nan, 0, self.image.shape[0], np.nan] if len(xs) > 0 and len(ys) > 0: if self.plotRect == None: self.ax.hold(True) self.plotRect, = self.ax.plot(xs, ys, 'b') self.ax.hold(False) self.ax.set_xlim([0,self.image.shape[1]]) self.ax.set_ylim([0,self.image.shape[0]]) self.ax.invert_yaxis() else: self.plotRect.set_data(xs, ys) self.canvas.draw() app.processEvents() def loadCamCalib(self): ''' load camera calibration image and show an image''' calibPath = os.path.join(self.scriptPath, './data') CalibFile = QtGui.QFileDialog.getOpenFileName(self, 'Open image', calibPath) self.ImageSize, SquareSize, self.CameraMatrix, self.DistCoefs, RVecs, TVecs = cd.readCalibration(CalibFile) self.status.append('Loaded camera parameters from ' + CalibFile) print('CameraMatrix =', self.CameraMatrix) print('DistCoefs =', self.DistCoefs) self.UndistMapX, self.UndistMapY = cv2.initUndistortRectifyMap(self.CameraMatrix, self.DistCoefs, \ None, self.CameraMatrix, self.ImageSize, cv2.CV_32FC1) if self.image != None: self.image = cv2.remap(self.image.astype(np.uint8), self.UndistMapX, self.UndistMapY, cv2.INTER_CUBIC) self.isDistortionCorrected = True self.status.append('Corrected image distortion.') self.updateFigure() # def loadPotTemplate(self): # ''' load pot template image''' # fname = QtGui.QFileDialog.getOpenFileName(self, 'Open image', '/home/chuong/Workspace/traitcapture-bin/unwarp_rectify/data') # self.status.append('Loading image...') # app.processEvents() # self.potTemplate = cv2.imread(str(fname))[:,:,::-1] # if len(self.potList) > 0: def correctColor(self): if self.colorcardParams == None: if len(self.colorcardList) > 0: medianSize = cd.getMedianRectSize(self.colorcardList) capturedColorcards = cd.rectifyRectImages(self.image, self.colorcardList, medianSize) self.colorcardColors, _ = cd.getColorcardColors(capturedColorcards[0], GridSize = [6, 4]) self.colorcardParams = cd.estimateColorParameters(cd.CameraTrax_24ColorCard, self.colorcardColors) else: self.status.append('Need to select a color card first.') return colorMatrix, colorConstant, colorGamma = self.colorcardParams self.imageCorrected = cd.correctColorVectorised(self.image.astype(np.float), colorMatrix, colorConstant, colorGamma) self.imageCorrected[np.where(self.imageCorrected < 0)] = 0 self.imageCorrected[np.where(self.imageCorrected > 255)] = 255 self.imageCorrected = self.imageCorrected.astype(np.uint8) self.updateFigure(self.imageCorrected) def savePipelineSettings(self): ''' save to pipeline setting file''' self.settingFileName = str(QtGui.QFileDialog.getSaveFileName(self, \ 'Save selection (default in ./_data)', self.timestreamRootPath)) if len(self.settingFileName) == 0: return self.settingPath = os.path.relpath(os.path.dirname(self.settingFileName), self.timestreamRootPath) self.settings = {} if self.ImageSize != None and self.CameraMatrix != None and self.DistCoefs != None: undistortDic = {'cameraMatrix': self.CameraMatrix.tolist(), \ 'distortCoefs': self.DistCoefs.tolist(), \ 'imageSize': list(self.ImageSize), 'rotationAngle': self.rotationAngle + self.smaleRotationAngle } else: undistortDic = {} self.settings['undistort'] = undistortDic if len(self.colorcardList) > 0: medianSize = cd.getMedianRectSize(self.colorcardList) capturedColorcards = cd.rectifyRectImages(self.image, self.colorcardList, medianSize) colorCardFile = 'CapturedColorcard.png' cv2.imwrite(os.path.join(self.timestreamRootPath, self.settingPath, colorCardFile), capturedColorcards[0][:,:,::-1].astype(np.uint8)) colorcardColors, colorStd = cd.getColorcardColors(capturedColorcards[0], GridSize = [6,4]) colorcardPosition, Width, Height, Angle = cd.getRectangleParamters(self.colorcardList[0]) colorcardDic = {'colorcardFile': colorCardFile,\ 'colorcardPosition': colorcardPosition.tolist(),\ 'colorcardTrueColors': cd.CameraTrax_24ColorCard,\ 'settingPath': '_data' } else: colorcardDic = {} self.settings['colorcarddetect'] = colorcardDic self.settings['colorcorrect'] = {'minIntensity': 15} if len(self.trayList) > 0: trayMedianSize = cd.getMedianRectSize(self.trayList) trayImages = cd.rectifyRectImages(self.image, self.trayList, trayMedianSize) trayDict = {} trayDict['settingPath'] = '_data' trayDict['trayNumber'] = len(self.trayList) trayDict['trayFiles'] = 'Tray_%02d.png' trayPositions = [] for i,tray in enumerate(trayImages): cv2.imwrite(os.path.join(self.timestreamRootPath, self.settingPath, trayDict['trayFiles'] %i), tray[:,:,::-1].astype(np.uint8)) trayPosition, Width, Height, Angle = cd.getRectangleParamters(self.trayList[i]) trayPositions.append(trayPosition.tolist()) trayDict['trayPositions'] = trayPositions else: trayDict = {} self.settings['traydetect'] = trayDict if len(self.potList) > 0: trayMedianSize = cd.getMedianRectSize(self.trayList) potPosition, Width, Height, Angle = cd.getRectangleParamters(self.potList[0]) Width, Height = int(Width), int(Height) topLeft = [int(self.potList[0][0][0]), int(self.potList[0][0][1])] self.potImage = self.image[topLeft[1]:topLeft[1]+Height, topLeft[0]:topLeft[0]+Width, :] potFile = 'Pot.png' cv2.imwrite(os.path.join(self.timestreamRootPath, self.settingPath, potFile), self.potImage[:,:,::-1].astype(np.uint8)) potDict = {} potDict['potPositions'] = potPosition.tolist() potDict['potSize'] = [int(Width), int(Height)] potDict['traySize'] = [int(trayMedianSize[0]), int(trayMedianSize[1])] potDict['potFile'] = potFile potDict['potTemplateFile'] = 'PotTemplate.png' potDict['settingPath'] = '_data' potTemplatePathIn = os.path.join(self.scriptPath, './data/PotTemplate.png') potTemplatePathOut = os.path.join(self.timestreamRootPath, self.settingPath, potDict['potTemplateFile']) shutil.copyfile(potTemplatePathIn, potTemplatePathOut) if self.potTemplate != None: potTemplateFile = 'potTemplate.png' cv2.imwrite(os.path.join(self.timestreamRootPath, self.settingPath, potTemplateFile), self.potTemplate[:,:,::-1]) potDict['potTemplateFile'] = potTemplateFile else: potDict = {} self.settings['potdetect'] = potDict self.settings['plantextract'] = {'meth': 'method1', 'methargs': {'threshold' : 0.6, 'kSize' : 5, 'blobMinSize' : 50} } with open(self.settingFileName, 'w') as outfile: outfile.write( yaml.dump(self.settings, default_flow_style=None) ) self.status.append('Saved initial data to ' + self.settingFileName) def testPipeline(self): ''' try running processing pipeline based on user inputs''' if self.tsImages != None: # load setting file if missing if self.settingFileName == None: settingFileName = str(QtGui.QFileDialog.getOpenFileName(self, 'Open pipeline setting file', self.ts.path)) if len(settingFileName) > 0: self.settingFileName = settingFileName else: return # initialise pipeline if self.pl == None: f = file(self.settingFileName) self.settings = yaml.load(f) self.ts.data["settings"] = self.settings self.pl = pipeline.ImagePipeline(self.settings) # process only from undistortion to pot detection self.pl.pipeline = self.pl.pipeline[:5] # read next image instant of pipeline try: tsImage = self.tsImages.next() if tsImage == None: self.status.append('Missing image.') return except: tsImage = None self.status.append('There is no more images.') return self.status.append('Processing ' + tsImage.path) context = {"rts":self.ts, "wts":None, "img":tsImage} result = self.pl.process(context, [tsImage]) self.image, potPosList2 = result potSize = self.settings[4][1]["potSize"] self.potList = [] for potPosList in potPosList2: if potPosList == None: continue for potPos in potPosList: tl = [potPos[0] - potSize[0]//2, potPos[1] - potSize[1]//2] bl = [potPos[0] - potSize[0]//2, potPos[1] + potSize[1]//2] br = [potPos[0] + potSize[0]//2, potPos[1] + potSize[1]//2] tr = [potPos[0] + potSize[0]//2, potPos[1] - potSize[1]//2] self.potList.append([tl, bl, br, tr]) self.updateFigure() self.status.append('Done') else: self.status.append('Pipeline or setting file is missing.') def rotateImage90Degrees(self): if self.image == None: self.status.append('No image to rotate.') return self.rotationAngle = self.rotationAngle + 90 if self.rotationAngle >= 360: self.rotationAngle = self.rotationAngle - 360 self.image = np.rot90(self.image) #.astype(uint8) self.status.append('Rot. angle = %d deg' %self.rotationAngle) self.updateFigure(resetFigure = True) def rotateSmallAngle(self, value): self.smaleRotationAngle = float(value)/4.0 if self.image != None: self.rotatedImage = cd.rotateImage(self.image, self.smaleRotationAngle) self.updateFigure(self.rotatedImage) self.status.append('Rot. angle = %f deg' %(self.rotationAngle + self.smaleRotationAngle)) def applySmallRotation(self): if self.image != None: self.image = cd.rotateImage(self.image, self.smaleRotationAngle) self.updateFigure() self.status.append('Apply small angle rotation') def onMouseClicked(self, event): if self.panMode or self.zoomMode: return print('click', event.button, event.xdata, event.ydata) if event.button == 1 and event.xdata != None and event.ydata != None: self.leftClicks.append([event.xdata, event.ydata]) print('self.leftClicks =', self.leftClicks) Rect = [] AspectRatio = None if self.trayRadioButton.isChecked(): AspectRatio = self.trayAspectRatio elif self.colorcardRadioButton.isChecked(): AspectRatio = self.colorcardAspectRatio elif self.potRadioButton.isChecked(): AspectRatio = self.potAspectRatio if len(self.leftClicks) == 2 and AspectRatio != None: if self.colorcardRadioButton.isChecked(): Rect = cd.getRectCornersFrom2Points(self.image, self.leftClicks, AspectRatio) if self.trayRadioButton.isChecked(): Rect = cd.getRectCornersFrom2Points(self.image, self.leftClicks, AspectRatio, Rounded = self.trayRoundCheckBox.isChecked()) elif self.potRadioButton.isChecked(): Rect = cd.getRectCornersFrom2Points(self.image, self.leftClicks, AspectRatio, Rounded = True) self.leftClicks = [] elif len(self.leftClicks) == 4: Rect = [[x,y] for x,y in self.leftClicks] Rect = cd.correctPointOrder(Rect) self.leftClicks = [] if len(Rect) > 0: if self.trayRadioButton.isChecked(): self.trayList.append(Rect) self.status.append('Added tray selection.') elif self.colorcardRadioButton.isChecked(): self.colorcardList.append(Rect) self.status.append('Added color card selection.') else: self.potList.append(Rect) self.status.append('Added pot selection.') self.updateFigure() elif event.button == 3: # remove the last selection if len(self.leftClicks) > 0: self.leftClicks = self.leftClicks[:-1] self.status.append('Removed a previous click') else: if self.trayRadioButton.isChecked() and len(self.trayList) > 0: self.trayList = self.trayList[:-1] self.status.append('Removed a previous tray selection') elif self.colorcardRadioButton.isChecked() and len(self.colorcardList) > 0: self.colorcardList = self.colorcardList[:-1] self.status.append('Removed a previous color card selection.') elif self.potRadioButton.isChecked() and len(self.potList) > 0: self.potList = self.potList[:-1] self.status.append('Removed a previous pot selection') self.updateFigure() else: print('Ignored click') def onMouseMoves(self, event): if event.inaxes == self.ax: self.mousePosition.setText('x=%d, y=%d' %(event.xdata, event.ydata)) # self.crosshair = [event.xdata, event.ydata] else: self.mousePosition.setText('') # self.crosshair = None # self.updateFigure() def keyPressEvent(self, e): if e.key() == QtCore.Qt.Key_Escape: self.close() def closeEvent(self, event): quit_msg = "Are you sure you want to exit the program?" reply = QtGui.QMessageBox.question(self, 'Message', quit_msg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: self.saveInputs() event.accept() else: event.ignore() def saveInputs(self): with open('./.inputs.yml', 'w') as myfile: dicInputs = {'rootPath': str(self.timestreamText.text()), 'startDate': str(self.timestreamDateText.text()), 'timeInterval': str(self.timestreamTimeText.text()), } myfile.write( yaml.dump(dicInputs, default_flow_style=None) ) def loadPreviousInputs(self): try: with open('./.inputs.yml', 'r') as myfile: dicInputs = yaml.load(myfile) self.timestreamText.setText(dicInputs['rootPath']) self.timestreamDateText.setText(dicInputs['startDate']) self.timestreamTimeText.setText(dicInputs['timeInterval']) except: pass
class PlotWidget(Canvas): def __init__(self, parent, x_dimension, y_dimension): super(PlotWidget, self).__init__(Figure()) self.setParent(parent) self.figure = Figure((x_dimension, y_dimension)) self.canvas = Canvas(self.figure) self.axes = self.figure.add_subplot(111) # navigation toolbar self.nav = NavigationToolbar(self.canvas, self) self.nav.hide() # background color = white self.figure.set_facecolor('white') # global variables self.x_limit = None self.plot_style() def plot_properties(self, x_label, y_label, x_limit=None): """ Plot properties and variables axis labels x axis label (limit) :param x_label: x axis labels :param y_label: y axis labels :param x_limit: number of x axis labels to display """ if x_label and y_label is not None: self.axes.set_xlabel(x_label) self.axes.set_ylabel(y_label) self.x_limit = x_limit def plot_style(self): # change axes colors - grey axes = ["bottom", "top", "left", "right"] for ax in axes: self.axes.spines[ax].set_color(chart_colors["grey"]) # change x-label and y-label color self.axes.xaxis.label.set_color(chart_colors["dark_grey"]) self.axes.yaxis.label.set_color(chart_colors["dark_grey"]) # change tick color self.axes.tick_params(axis='x', colors=chart_colors["grey"]) self.axes.tick_params(axis='y', colors=chart_colors["grey"]) # change font size - labels rc('font', **chart_font) # add grid - soft grey self.axes.grid(True) def plot_lines(self, x_values, y_values, *args): # number of columns - range columns = len(x_values) ind = np.arange(columns) # convert x_values to string and y_values to float - review! x_labels = np.array(x_values, dtype=str) y = np.array(y_values, dtype=float) # tick labels with dates if columns <= self.x_limit: self.axes.set_xticks(np.arange(columns)) self.axes.xaxis.get_majorticklocs() self.axes.set_xticklabels(x_labels) # show y_values if not args: self.axes.plot(ind, y) else: # multiple series - to be implemented for arg in args: print arg pass self.figure.tight_layout() def plot_bars(self): pass def plot_stats(self): pass def plot_pie(self): pass def plot_polar(self): pass
class LMatplotlibWidget(LWidget): def __init__(self, parent=None): super(LMatplotlibWidget, self).__init__(parent) self.setName(WIDGET_NAME) self.buildUi() self.dataContainer = LMyDataContainer(self) self.actions = LMyActions(self.dataContainer,self) self.setDebugLevel(5) self.updateUi() @LInAndOut(DEBUG & WIDGETS) def buildUi(self): self.verticalLayout = QVBoxLayout(self) self.figure = Figure() self.canvas = Canvas(self.figure) # <-- figure required self.navigationToolbar = NavigationToolbar(self.canvas, self) self.verticalLayout.addWidget(self.canvas) self.verticalLayout.addWidget(self.navigationToolbar) #Canvas.setSizePolicy(self.canvas, QSizePolicy.Expanding, QSizePolicy.Expanding) #Canvas.updateGeometry(self.canvas) @LInAndOut(DEBUG & WIDGETS) def updateUi(self): left = self.dataContainer.leftMargin bottom = self.dataContainer.bottomMargin right = self.dataContainer.rightMargin top = self.dataContainer.topMargin wspace = self.dataContainer.verticalSeparation hspace = self.dataContainer.horizontalSeparation self.figure.subplots_adjust(left, bottom, right, top, wspace, hspace) if self.dataContainer.showNavigationToolbar: self.navigationToolbar.show() else: self.navigationToolbar.hide() #---------------------------------------------------------------------- # Interface (set) @LInAndOut(DEBUG & WIDGETS) def setOptions(self, options): super(LMatplotlibWidget, self).setOptions(options) if options.verboseLevel is not None: self.setVerboseLevel(options.verboseLevel) if options.navigationToolbar is not None: self.showNavigationToolbar(options.navigationToolbar) self.updateUi() @LInAndOut(DEBUG & WIDGETS) def setVerboseLevel(self, level): self.dataContainer.verboseLevel = level #---------------------------------------------------------------------- # Interface (get) def getFigure(self): return self.figure #---------------------------------------------------------------------- # Interface (misc) @LInAndOut(DEBUG & WIDGETS) def showNavigationToolbar(self, flag=True): self.dataContainer.showNavigationToolbar = flag self.updateUi() @LInAndOut(DEBUG & WIDGETS) def snapshot(self, fileName = None): if fileName is None: caption = "%s - Save File" % self.name filter = "PNG Image (*.png);;All files (*.*)" fileName = QFileDialog.getSaveFileName(self.parent(), caption=caption,filter=filter ) fileName = "%s" % fileName if len(fileName) > 0: self.figure.savefig(fileName, facecolor='w', edgecolor='w', orientation='portrait', papertype=None, format=None, transparent=False, bbox_inches=None, pad_inches=0.1) @LInAndOut(DEBUG & WIDGETS) def draw(self): self.canvas.draw()
class MplCanvas(FigureCanvas): ''' 描述:将matplotlib的figure嵌入到Qt中 成员: figure:画图的窗口,是matplotlib中的figure对象 axes:画布,matplotlib.Axes对象 方法:这些方法可以重新实现 getSnn:返回画的曲线,是s11.s21,s12,或者s22 getDrawedLineType:S,群时延 getFigure: 返回figure对象 使用: 得到axes直接进行画图 ''' def __init__(self, parent=None, width=5, height=4, dpi=100): self.figure = Figure(figsize=(width, height), dpi=dpi) self.axes = self.figure.add_subplot(111) self.axes.hold(False) FigureCanvas.__init__(self, self.figure) self.setParent(parent) FigureCanvas.setSizePolicy(self, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) FigureCanvas.updateGeometry(self) self.toolbar = NavigationToolbar(self, self) self.toolbar.hide() self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.createPopMenu() def createPopMenu(self): #actions self.popmenu = QtGui.QMenu(self) self.snn_ac_group = QtGui.QActionGroup(self.popmenu) self.snn_ac_group.setExclusive(True) self.ac_s11 = QtGui.QAction('S11', self.popmenu) self.ac_s21 = QtGui.QAction('S21', self.popmenu) self.ac_s12 = QtGui.QAction('S12', self.popmenu) self.ac_s22 = QtGui.QAction('S22', self.popmenu) snn_actions = [self.ac_s11, self.ac_s21, self.ac_s12, self.ac_s22] for ac in snn_actions: ac.setCheckable(True) self.snn_ac_group.addAction(ac) self.ac_s11.setChecked(True) self.popmenu.addActions(snn_actions) self.ac_delay = QtGui.QAction('show delay', self.popmenu) self.ac_phase = QtGui.QAction('show phase', self.popmenu) self.ac_expanded = QtGui.QAction('show expanded', self.popmenu) self.type_ac_group = QtGui.QActionGroup(self.popmenu) types_actions = [self.ac_delay, self.ac_phase, self.ac_expanded] for ac in types_actions: ac.setCheckable(True) self.type_ac_group.addAction(ac) self.ac_phase.setChecked(True) self.popmenu.addActions(types_actions) self.setShowPopMenu(True) def setShowPopMenu(self, isShow): if isShow: self.connect(self, SIGNAL('customContextMenuRequested(const QPoint &)'), self.show_popmenu) else: self.disconnect( self, SIGNAL('customContextMenuRequested(const QPoint &)'), self.show_popmenu) def show_popmenu(self, pos): #self.popmenu.popup(self.mapToGlobal(pos)) pass def getSnn(self): snn = self.snn_ac_group.checkedAction().text() if snn == 'S11': return 1 elif snn == 'S21': return 2 elif snn == 'S12': return 3 else: return 4 def getDrawedLineType(self): linetype = self.type_ac_group.checkedAction().text() if linetype == 'show delay': return 'delay' elif linetype == 'show phase': return 'phase' elif linetype == 'show expanded': return 'expanded' def getFigure(self): return self.figure
class MatplotlibWidget(QtGui.QWidget): """ This subclass of QtWidget will manage the widget drawing; name matches the class in the *_ui.py file""" # Global colors dictionary colors_dict = { "Discharge": "b", "Subsurface Flow": "g", "Impervious Flow": "SteelBlue", "Infiltration Excess": "SeaGreen", "Initial Abstracted Flow": "MediumBlue", "Overland Flow": "RoyalBlue", "PET": "orange", "AET": "DarkOrange", "Average Soil Root zone": "Gray", "Average Soil Unsaturated Zone": "DarkGray", "Snow Pack": "PowderBlue", "Precipitation": "SkyBlue", "Storage Deficit": "Brown", "Return Flow": "Aqua", "Water Use": "DarkCyan", "Discharge + Water Use": "DarkBlue" } def __init__(self, parent=None): super(MatplotlibWidget, self).__init__(parent) # create object scope variables for watertxt data plot; used by radio buttons and span selector self.watertxt_data = None self.parameter = None self.color_str = None self.axes_text = None self.axes_radio = None self.parent = parent # create figure self.figure = Figure() # create canvas and set some of its properties self.canvas = FigureCanvas(self.figure) self.canvas.setParent(parent) self.canvas.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.canvas.updateGeometry() self.canvas.setFocusPolicy(QtCore.Qt.StrongFocus) self.canvas.setFocus() # set up axes and its properties self.ax = self.figure.add_subplot(111) self.ax.grid(True) # create toolbar self.matplotlib_toolbar = NavigationToolbar( self.canvas, parent) # the matplotlib toolbar object # create the layout self.layout = QtGui.QVBoxLayout() # add the widgets to the layout self.layout.addWidget(self.matplotlib_toolbar) self.layout.addWidget(self.canvas) # set the layout self.setLayout(self.layout) #-------------------------------- WATER.txt Parameter Plot ------------------------------------ def setup_watertxt_plot(self): """ Setup the watertxt plot """ self.clear_watertxt_plot() # set up axes and its properties self.axes = self.figure.add_subplot(111) self.axes.grid(True) # create radio buttons self.axes_radio = self.figure.add_axes( [0.01, 0.02, 0.10, 0.15] ) # [left, bottom, width, height] = fractions of figure width and height self.figure.subplots_adjust(bottom=0.2) self.radio_buttons = RadioButtons(ax=self.axes_radio, labels=("Span On", "Span Off"), active=1, activecolor="r") self.radio_buttons.on_clicked(self.toggle_selector) # create SpanSelector; invisble at first unless activated with toggle selector self.span_selector = SpanSelector(self.axes, self.on_select_axes, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='red')) self.span_selector.visible = False def plot_watertxt_parameter(self, watertxt_data, name): """ Plot a parameter from a WATER.txt file """ self.reset_watertxt_plot() self.dates = watertxt_data["dates"] self.watertxt_data = watertxt_data self.parameter = watertxt.get_parameter(watertxt_data, name=name) assert self.parameter is not None, "Parameter name {} is not in watertxt_data".format( name) self.axes.set_title("Parameter: {}".format(self.parameter["name"])) self.axes.set_xlabel("Date") ylabel = "\n".join(wrap(self.parameter["name"], 60)) self.axes.set_ylabel(ylabel) # get proper color that corresponds to parameter name self.color_str = self.colors_dict[name.split('(')[0].strip()] # plot parameter self.axes.plot(self.dates, self.parameter["data"], color=self.color_str, label=self.parameter["name"], linewidth=2) # legend; make it transparent handles, labels = self.axes.get_legend_handles_labels() legend = self.axes.legend(handles, labels, fancybox=True) legend.get_frame().set_alpha(0.5) legend.draggable(state=True) # show text of mean, max, min values on graph; use matplotlib.patch.Patch properies and bbox text = "mean = {:.2f}\nmax = {:.2f}\nmin = {:.2f}".format( self.parameter["mean"], self.parameter["max"], self.parameter["min"]) patch_properties = { "boxstyle": "round", "facecolor": "wheat", "alpha": 0.5 } self.axes_text = self.axes.text(0.05, 0.95, text, transform=self.axes.transAxes, fontsize=14, verticalalignment="top", horizontalalignment="left", bbox=patch_properties) # use a more precise date string for the x axis locations in the toolbar and rotate labels self.axes.fmt_xdata = mdates.DateFormatter("%Y-%m-%d") # rotate and align the tick labels so they look better; note that self.figure.autofmt_xdate() does not work because of the radio button axes for label in self.axes.get_xticklabels(): label.set_ha("right") label.set_rotation(30) # draw the plot self.canvas.draw() def on_select_helper(self, xmin, xmax): """ Helper for on_select methods """ # convert matplotlib float dates to a datetime format date_min = mdates.num2date(xmin) date_max = mdates.num2date(xmax) # put the xmin and xmax in datetime format to compare date_min = datetime.datetime(date_min.year, date_min.month, date_min.day, date_min.hour, date_min.minute) date_max = datetime.datetime(date_max.year, date_max.month, date_max.day, date_max.hour, date_max.minute) # find the indices that were selected indices = np.where((self.dates >= date_min) & (self.dates <= date_max)) indices = indices[0] # get the selected dates and values selected_dates = self.dates[indices] selected_values = self.parameter["data"][indices] # compute simple stats on selected values selected_values_mean = nanmean(selected_values) selected_value_max = np.nanmax(selected_values) selected_value_min = np.nanmin(selected_values) return selected_dates, selected_values, selected_values_mean, selected_value_max, selected_value_min def on_select_axes(self, xmin, xmax): """ A select handler for SpanSelector that updates axes with the new x and y limits selected by user """ selected_dates, selected_values, selected_values_mean, selected_value_max, selected_value_min = self.on_select_helper( xmin, xmax) # plot the selected values and update plots limits and text self.axes.plot(selected_dates, selected_values, self.color_str) self.axes.set_xlim(selected_dates[0], selected_dates[-1]) self.axes.set_ylim(selected_values.min(), selected_values.max()) text = 'mean = %.2f\nmax = %.2f\nmin = %.2f' % ( selected_values_mean, selected_value_max, selected_value_min) self.axes_text.set_text(text) # draw the updated plot self.canvas.draw() def toggle_selector(self, radio_button_label): """ A toggle radio buttons for the matplotlib SpanSelector widget. """ if radio_button_label == "Span On": self.span_selector.visible = True self.matplotlib_toolbar.hide() elif radio_button_label == "Span Off": self.span_selector.visible = False self.matplotlib_toolbar.show() self.plot_watertxt_parameter(watertxt_data=self.watertxt_data, name=self.parameter["name"]) def clear_watertxt_plot(self): """ Clear the plot axes """ self.figure.clear() self.canvas.draw() def reset_watertxt_plot(self): """ Clear the plot axes """ self.axes.clear() self.canvas.draw() self.axes.grid(True) #-------------------------------- WATER.txt Parameter Comparison Plot ------------------------------------ def setup_watertxtcmp_plot(self): """ Setup the watertxt plot """ self.clear_watertxtcmp_plot() # set up axes and its properties self.axes1 = self.figure.add_subplot(211) self.axes2 = self.figure.add_subplot(212, sharex=self.axes1) self.axes1.grid(True) self.axes2.grid(True) def plot_watertxtcmp_parameter(self, watertxt_data1, watertxt_data2, filename1, filename2, name): """ Plot a parameter from a WATER.txt file """ self.reset_watertxtcmp_plot() dates = watertxt_data1["dates"] parameter1 = watertxt.get_parameter(watertxt_data=watertxt_data1, name=name) parameter2 = watertxt.get_parameter(watertxt_data=watertxt_data2, name=name) assert parameter1 is not None, "Parameter name {} is not in watertxt_data".format( name) assert parameter2 is not None, "Parameter name {} is not in watertxt_data".format( name) # calculate the difference diff = parameter2["data"] - parameter1["data"] # plot parameters on axes1 self.axes1.plot(dates, parameter1["data"], color="b", label=filename1 + ": " + parameter1["name"], linewidth=2) self.axes1.hold(True) self.axes1.plot(dates, parameter2["data"], color="r", label=filename2 + ": " + parameter2["name"], linewidth=2) # plot the difference on axes2 self.axes2.plot(dates, diff, color="k", linewidth=2) # add title, labels, legend self.axes1.set_title(parameter1["name"]) self.axes2.set_xlabel("Date") self.axes2.set_ylabel("Difference") handles1, labels1 = self.axes1.get_legend_handles_labels() legend1 = self.axes1.legend(handles1, labels1, fancybox=True) legend1.get_frame().set_alpha(0.5) legend1.draggable(state=True) # show text of mean, max, min values on graph; use matplotlib.patch.Patch properies and bbox text1 = "mean = {:.2f}\nmax = {:.2f}\nmin = {:.2f}".format( parameter1["mean"], parameter1["max"], parameter1["min"]) text2 = "mean = {:.2f}\nmax = {:.2f}\nmin = {:.2f}".format( parameter2["mean"], parameter2["max"], parameter2["min"]) text_diff = "mean = {:.2f}\nmax = {:.2f}\nmin = {:.2f}".format( nanmean(diff), np.max(diff), np.min(diff)) patch_properties1 = { "boxstyle": "round", "facecolor": "b", "alpha": 0.5 } patch_properties2 = { "boxstyle": "round", "facecolor": "r", "alpha": 0.5 } patch_properties_diff = { "boxstyle": "round", "facecolor": "wheat", "alpha": 0.5 } self.axes1.text(0.02, 0.95, text1, transform=self.axes1.transAxes, fontsize=12, verticalalignment="top", horizontalalignment="left", bbox=patch_properties1) self.axes1.text(0.02, 0.45, text2, transform=self.axes1.transAxes, fontsize=12, verticalalignment="top", horizontalalignment="left", bbox=patch_properties2) self.axes2.text(0.02, 0.95, text_diff, transform=self.axes2.transAxes, fontsize=12, verticalalignment="top", horizontalalignment="left", bbox=patch_properties_diff) # use a more precise date string for the x axis locations in the toolbar and rotate labels self.axes2.fmt_xdata = mdates.DateFormatter("%Y-%m-%d") # rotate and align the tick labels so they look better self.figure.autofmt_xdate() # draw the plot self.canvas.draw() def clear_watertxtcmp_plot(self): """ Clear the plot axes """ self.figure.clear() self.canvas.draw() def reset_watertxtcmp_plot(self): """ Clear the plot axes """ self.axes1.clear() self.axes2.clear() self.canvas.draw() self.axes1.grid(True) self.axes2.grid(True) #-------------------------------- Basemap Plot ------------------------------------ def setup_basemap_plot(self): """ Setup the watertxt plot """ self.clear_basemap_plot() # set up axes and its properties self.basemap_axes = self.figure.add_subplot(111) self.basemap_axes.grid(True) def get_map_extents(self, shapefiles, shp_name=None): """ Get max and min extent coordinates from a list of shapefiles to use as the extents on the map. Use the map extents to calculate the map center and the standard parallels. Parameters ---------- shapefiles : list List of shapefile_data dictionaries shp_name : string String name of shapefile to use for getting map extents Returns ------- extent_coords : dictionary Dictionary containing "lon_min", "lon_max", "lat_max", "lat_min" keys with respective calculated values center_coords : dictionary Dictionary containing "lon", "lat" keys with respective calculated values standard_parallels : dictionary Dictionary containing "first", "second" keys with respective calculated values (first = min(lat), second = max(lat)) """ extent_coords = {} center_coords = {} standard_parallels = {} lons = [] lats = [] if shp_name: for shapefile_data in shapefiles: if shp_name in shapefile_data["name"].split("_")[0]: lons.append(shapefile_data["extents"][0:2]) lats.append(shapefile_data["extents"][2:]) else: for shapefile_data in shapefiles: lons.append(shapefile_data["extents"][0:2]) lats.append(shapefile_data["extents"][2:]) extent_coords["lon_min"] = np.min(lons) extent_coords["lon_max"] = np.max(lons) extent_coords["lat_min"] = np.min(lats) extent_coords["lat_max"] = np.max(lats) center_coords["lon"] = np.mean( [extent_coords["lon_min"], extent_coords["lon_max"]]) center_coords["lat"] = np.mean( [extent_coords["lat_min"], extent_coords["lat_max"]]) standard_parallels["first"] = extent_coords["lat_min"] standard_parallels["second"] = extent_coords["lat_max"] return extent_coords, center_coords, standard_parallels def plot_shapefiles_map(self, shapefiles, display_fields=[], colors=[], title=None, shp_name=None, buff=1.0): """ Generate a map showing all the shapefiles in the shapefile_list. Shapefiles should be in a Geographic Coordinate System (longitude and latitude coordinates) such as World WGS84; Matplotlib"s basemap library does the proper transformation to a projected coordinate system. The projected coordinate system used is Albers Equal Area. Parameters ---------- shapefiles : list List of dictionaries containing shapefile information title : string String title for plot display_fields : list List of strings that correspond to a shapefile field where the corresponding value(s) will be displayed. colors : list List of strings that correspond to colors to be displayed shp_name : string String name of shapefile to use for getting map extents buff : float Float value in coordinate degrees to buffer the map with """ self.setup_basemap_plot() extent_coords, center_coords, standard_parallels = self.get_map_extents( shapefiles, shp_name=shp_name) # create the basemap object with Albers Equal Area Conic Projection bmap = Basemap(projection="aea", llcrnrlon=extent_coords["lon_min"] - buff, llcrnrlat=extent_coords["lat_min"] - buff, urcrnrlon=extent_coords["lon_max"] + buff, urcrnrlat=extent_coords["lat_max"] + buff, lat_1=standard_parallels["first"], lat_2=standard_parallels["second"], lon_0=center_coords["lon"], lat_0=center_coords["lat"], resolution="h", area_thresh=10000, ax=self.basemap_axes) # have basemap object plot background stuff bmap.drawcoastlines() bmap.drawcountries() bmap.drawrivers(linewidth=1, color="blue") bmap.drawstates() bmap.drawmapboundary(fill_color="aqua") bmap.fillcontinents(color="coral", lake_color="aqua") bmap.drawparallels(np.arange(-80., 81., 1.), labels=[1, 0, 0, 0], linewidth=0.5) bmap.drawmeridians(np.arange(-180., 181., 1.), labels=[0, 0, 0, 1], linewidth=0.5) # plot each shapefile on the basemap legend_handles = [] legend_labels = [] colors_index = 0 colors_list = [ "b", "g", "y", "r", "c", "y", "m", "orange", "aqua", "darksalmon", "gold", "k" ] for shapefile_data in shapefiles: # set up colors to use if colors: color = colors[colors_index] elif colors_index > len(colors_list) - 1: color = np.random.rand(3, ) else: color = colors_list[colors_index] full_path = os.path.join(shapefile_data["path"], shapefile_data["name"].split(".")[0]) shp_tuple = bmap.readshapefile( full_path, "shp", drawbounds=False ) # use basemap shapefile reader for ease of plotting for shape_dict, shape in zip( bmap.shp_info, bmap.shp ): # zip the shapefile information and its shape as defined by basemap if shapefile_data["type"] == "POLYGON": p1 = Polygon(shape, facecolor=color, edgecolor="k", linewidth=1, alpha=0.7, label=shapefile_data["name"]) self.basemap_axes.add_patch(p1) xx, yy = zip(*shape) txt_x = str(np.mean(xx)) txt_y = str(np.mean(yy)) elif shapefile_data["type"] == "POINT": x, y = shape if "usgsgages" in shapefile_data["name"].split("_")[0]: p1 = bmap.plot(x, y, color=color, marker="^", markersize=10, label=shapefile_data["name"]) elif "wateruse" in shapefile_data["name"].split("_")[0]: p1 = bmap.plot(x, y, color=color, marker="o", markersize=5, label=shapefile_data["name"]) else: print("what!!") p1 = bmap.plot(x, y, color=color, marker="o", markersize=10, label=shapefile_data["name"]) txt_x = str(x) txt_y = str(y) else: xx, yy = zip(*shape) p1 = bmap.plot(xx, yy, linewidth=1, color=color, label=shapefile_data["name"]) txt_x = str(np.mean(xx)) txt_y = str(np.mean(yy)) if isinstance(p1, list): p1 = p1[0] # control text display of shapefile fields for display_field in display_fields: if display_field in shape_dict.keys(): self.basemap_axes.text(txt_x, txt_y, shape_dict[display_field], color="k", fontsize=12, fontweight="bold") colors_index += 1 legend_handles.append(p1) legend_labels.append(shapefile_data["name"].split("_")[0]) handles, labels = self.basemap_axes.get_legend_handles_labels() # edit the contents of handles and labels to only show 1 legend per shape handles = legend_handles labels = legend_labels legend = self.basemap_axes.legend(handles, labels, fancybox=True, numpoints=1) legend.get_frame().set_alpha(0.5) legend.draggable(state=True) # draw the plot self.canvas.draw() def clear_basemap_plot(self): """ Clear the plot axes """ self.figure.clear() self.canvas.draw() def reset_basemap_plot(self): """ Clear the plot axes """ self.basemap_axes.clear() self.canvas.draw()
class Window(QtGui.QWidget): def __init__(self, parent=None): super(Window, self).__init__(parent) self.setWindowTitle('OpenWave-2KE') icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap("openwave.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.setWindowIcon(icon) #Waveform area. self.figure = plt.figure() self.figure.set_facecolor('white') self.canvas = FigureCanvas(self.figure) self.canvas.setMinimumSize(800, 400) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() #Zoom In/out and Capture Buttons self.zoomBtn = QtGui.QPushButton('Zoom') self.zoomBtn.setFixedSize(100, 30) self.zoomBtn.clicked.connect(self.toolbar.zoom) self.panBtn = QtGui.QPushButton('Pan') self.panBtn.setFixedSize(100, 30) self.panBtn.clicked.connect(self.toolbar.pan) self.homeBtn = QtGui.QPushButton('Home') self.homeBtn.setFixedSize(100, 30) self.homeBtn.clicked.connect(self.toolbar.home) self.captureBtn = QtGui.QPushButton('Capture') self.captureBtn.setFixedSize(100, 50) self.captureBtn.clicked.connect(self.captureAction) if(portNum==-1): self.captureBtn.setEnabled(False) #Type: Raw Data/Image self.typeBtn = QtGui.QPushButton('Raw Data') self.typeBtn.setToolTip("Switch to get raw data or image from DSO.") self.typeBtn.setFixedSize(120, 50) self.typeFlag=True #Initial state -> Get raw data self.typeBtn.setCheckable(True) self.typeBtn.setChecked(True) self.typeBtn.clicked.connect(self.typeAction) #Channel Selection. self.ch1checkBox = QtGui.QCheckBox('CH1') self.ch1checkBox.setFixedSize(60, 30) self.ch2checkBox = QtGui.QCheckBox('CH2') self.ch2checkBox.setFixedSize(60, 30) if(dso.chnum==4): self.ch3checkBox = QtGui.QCheckBox('CH3') self.ch3checkBox.setFixedSize(60, 30) self.ch4checkBox = QtGui.QCheckBox('CH4') self.ch4checkBox.setFixedSize(60, 30) #Set channel selection layout. self.selectLayout = QtGui.QHBoxLayout() self.selectLayout.addWidget(self.ch1checkBox) self.selectLayout.addWidget(self.ch2checkBox) if(dso.chnum==4): self.selectLayout2 = QtGui.QHBoxLayout() self.selectLayout2.addWidget(self.ch3checkBox) self.selectLayout2.addWidget(self.ch4checkBox) self.typeLayout = QtGui.QHBoxLayout() self.typeLayout.addWidget(self.typeBtn) self.typeLayout.addLayout(self.selectLayout) if(dso.chnum==4): self.typeLayout.addLayout(self.selectLayout2) #Save/Load/Quit button self.saveBtn = QtGui.QPushButton('Save') self.saveBtn.setFixedSize(100, 50) self.saveMenu = QtGui.QMenu(self) self.csvAction = self.saveMenu.addAction("&As CSV File") self.pictAction = self.saveMenu.addAction("&As PNG File") self.saveBtn.setMenu(self.saveMenu) self.saveBtn.setToolTip("Save waveform to CSV file or PNG file.") self.connect(self.csvAction, QtCore.SIGNAL("triggered()"), self.saveCsvAction) self.connect(self.pictAction, QtCore.SIGNAL("triggered()"), self.savePngAction) self.loadBtn = QtGui.QPushButton('Load') self.loadBtn.setToolTip("Load CHx's raw data from file(*.csv, *.lsf).") self.loadBtn.setFixedSize(100, 50) self.loadBtn.clicked.connect(self.loadAction) self.quitBtn = QtGui.QPushButton('Quit') self.quitBtn.setFixedSize(100, 50) self.quitBtn.clicked.connect(self.quitAction) # set the layout self.waveLayout = QtGui.QHBoxLayout() self.waveLayout.addWidget(self.canvas) self.wave_box=QtGui.QVBoxLayout() self.wave_box.addLayout(self.waveLayout) self.wavectrlLayout = QtGui.QHBoxLayout() self.wavectrlLayout.addWidget(self.zoomBtn) self.wavectrlLayout.addWidget(self.panBtn) self.wavectrlLayout.addWidget(self.homeBtn) self.wavectrlLayout.addWidget(self.captureBtn) self.saveloadLayout = QtGui.QHBoxLayout() self.saveloadLayout.addWidget(self.saveBtn) self.saveloadLayout.addWidget(self.loadBtn) self.saveloadLayout.addWidget(self.quitBtn) self.ctrl_box=QtGui.QHBoxLayout() self.ctrl_box.addLayout(self.typeLayout) self.ctrl_box.addLayout(self.saveloadLayout) main_box=QtGui.QVBoxLayout() main_box.addLayout(self.wave_box) #Waveform area. main_box.addLayout(self.wavectrlLayout) #Zoom In/Out... main_box.addLayout(self.ctrl_box) #Save/Load/Quit self.setLayout(main_box) def typeAction(self): if(self.typeFlag==True): self.typeFlag=False self.typeBtn.setText("Image") self.csvAction.setEnabled(False) else: self.typeFlag=True self.typeBtn.setText("Raw Data") self.csvAction.setEnabled(True) self.typeBtn.setChecked(self.typeFlag) self.ch1checkBox.setEnabled(self.typeFlag) self.ch2checkBox.setEnabled(self.typeFlag) if(dso.chnum==4): self.ch3checkBox.setEnabled(self.typeFlag) self.ch4checkBox.setEnabled(self.typeFlag) def saveCsvAction(self): if(self.typeFlag==True): #Save raw data to csv file. file_name=QtGui.QFileDialog.getSaveFileName(self, "Save as", '', "Fast CSV File(*.csv)")[0] num=len(dso.ch_list) #print num for ch in xrange(num): if(dso.info[ch]==[]): print('Failed to save data, raw data information is required!') return f = open(file_name, 'w') item=len(dso.info[0]) #Write file header. f.write('%s, \n' % dso.info[0][0]) for x in xrange(1, 25): str='' for ch in xrange(num): str+=('%s,' % dso.info[ch][x]) str+='\n' f.write(str) str='' if(num==1): str+=('%s,' % dso.info[0][25]) else: for ch in xrange(num): str+=('%s,,' % dso.info[ch][25]) str+='\n' f.write(str) #Write raw data. item=len(dso.iWave[0]) #print item tenth=int(item/10) n_tenth=tenth-1 percent=10 for x in xrange(item): str='' if(num==1): str+=('%s,' % dso.iWave[0][x]) else: for ch in xrange(num): str+=('%s,,' % dso.iWave[ch][x]) str+='\n' f.write(str) if(x==n_tenth): n_tenth+=tenth print('%3d %% Saved\r'%percent), percent+=10 f.close() def savePngAction(self): #Save figure to png file. file_name=QtGui.QFileDialog.getSaveFileName(self, "Save as", '', "PNG File(*.png)")[0] if(file_name==''): return if(self.typeFlag==True): #Save raw data waveform as png file. main.figure.savefig(file_name) print('Saved image to %s.'%file_name) else: #Save figure to png file. dso.im.save(file_name) print('Saved image to %s.'%file_name) def loadAction(self): dso.ch_list=[] full_path_name=QtGui.QFileDialog.getOpenFileName(self,self.tr("Open File"),".","CSV/LSF files (*.csv *.lsf);;All files (*.*)") sFileName=unicode(full_path_name).split(',')[0][3:-1] #For PySide print sFileName if(len(sFileName)<=0): return if os.path.exists(sFileName): print 'Reading file...' count=dso.readRawDataFile(sFileName) #Draw waveform. if(count>0): total_chnum=len(dso.ch_list) if(total_chnum==0): return if(dso.dataMode=='Fast'): self.drawWaveform(0) else: self.drawWaveform(0) else: print('File not found!') def quitAction(self): if(portNum!=-1): dso.IO.close() self.close() def captureAction(self): dso.iWave=[[], [], [], []] dso.ch_list=[] if(self.typeFlag==True): #Get raw data. draw_flag=False #Turn on the selected channels. if((self.ch1checkBox.isChecked()==True) and (dso.isChannelOn(1)==False)): dso.write(":CHAN1:DISP ON\n") #Set CH1 on. if((self.ch2checkBox.isChecked()==True) and (dso.isChannelOn(2)==False)): dso.write(":CHAN2:DISP ON\n") #Set CH2 on. if(dso.chnum==4): if((self.ch3checkBox.isChecked()==True) and (dso.isChannelOn(3)==False)): dso.write(":CHAN3:DISP ON\n") #Set CH3 on. if((self.ch4checkBox.isChecked()==True) and (dso.isChannelOn(4)==False)): dso.write(":CHAN4:DISP ON\n") #Set CH4 on. #Get all the selected channel's raw datas. if(self.ch1checkBox.isChecked()==True): dso.getRawData(True, 1) #Read CH1's raw data from DSO (including header). if(self.ch2checkBox.isChecked()==True): dso.getRawData(True, 2) #Read CH2's raw data from DSO (including header). if(dso.chnum==4): if(self.ch3checkBox.isChecked()==True): dso.getRawData(True, 3) #Read CH3's raw data from DSO (including header). if(self.ch4checkBox.isChecked()==True): dso.getRawData(True, 4) #Read CH4's raw data from DSO (including header). #Draw waveform. total_chnum=len(dso.ch_list) if(total_chnum==0): return if(self.drawWaveform(1)==-1): time.sleep(5) self.drawWaveform(0) else: #Get image. dso.write(':DISP:OUTP?\n') #Send command to get image from DSO. dso.getBlockData() dso.RleDecode() self.showImage() plt.tight_layout(True) self.canvas.draw() print('Image is ready!') def showImage(self): #Turn the ticks off and show image. plt.clf() ax = plt.gca() ax.xaxis.set_visible(False) ax.yaxis.set_visible(False) plt.imshow(dso.im) def drawWaveform(self, mode): total_chnum=len(dso.ch_list) num=dso.points_num ch_colortable=['#C0B020', '#0060FF', '#FF0080', '#00FF60'] ch=int(dso.ch_list[0][2])-1 #Get the channel of first waveform. plt.cla() plt.clf() #Due to the memory limitation of matplotlib, we must reduce the sample points. if(num==10000000): if(total_chnum>2): down_sample_factor=4 elif(total_chnum==2): down_sample_factor=4 else: down_sample_factor=1 num=num/down_sample_factor else: down_sample_factor=1 dt=dso.dt[0] #Get dt from the first opened channel. t_start=dso.hpos[0]-num*dt/2 t_end =dso.hpos[0]+num*dt/2 t = np.arange(t_start, t_end, dt) #print t_start, t_end, dt, len(t) if((len(t)-num)==1): #Avoid floating point rounding error. t=t[:-1] wave_type='-' #Set waveform type to vector. #Draw waveforms. ax=[[], [], [], []] p=[] for ch in xrange(total_chnum): if(ch==0): ax[ch]=host_subplot(111, axes_class=AA.Axes) ax[ch].set_xlabel("Time (sec)") else: ax[ch]=ax[0].twinx() ax[ch].set_ylabel("%s Units: %s" %(dso.ch_list[ch], dso.vunit[ch])) ch_color=ch_colortable[int(dso.ch_list[ch][2])-1] if(ch>1): new_fixed_axis = ax[ch].get_grid_helper().new_fixed_axis ax[ch].axis["right"] = new_fixed_axis(loc="right", axes=ax[ch], offset=(60*(ch-1), 0)) ax[ch].set_xlim(t_start, t_end) ax[ch].set_ylim(-4*dso.vdiv[ch]-dso.vpos[ch], 4*dso.vdiv[ch]-dso.vpos[ch]) #Setup vertical display range. fwave=dso.convertWaveform(ch, down_sample_factor) #print('Length=%d'%(len(fwave))) if(ch==0): try: p=ax[ch].plot(t, fwave, color=ch_color, ls=wave_type, label = dso.ch_list[ch]) except: if(mode==1): #print sys.exc_info()[0] time.sleep(5) print 'Trying to plot again!', return -1 else: try: p+=ax[ch].plot(t, fwave, color=ch_color, ls=wave_type, label = dso.ch_list[ch]) except: if(mode==1): #print sys.exc_info()[0] time.sleep(5) print 'Trying to plot again!', return -1 if(total_chnum>1): labs = [l.get_label() for l in p] plt.legend(p, labs, loc='upper right') plt.tight_layout() self.canvas.draw() del ax, t, p return 0
class MatplotlibWidget(QtGui.QWidget): """ This subclass of QtWidget will manage the widget drawing; name matches the class in the *_ui.py file""" # Global colors dictionary colors_dict = { "Discharge": "b", "Subsurface Flow": "g", "Impervious Flow": "SteelBlue", "Infiltration Excess": "SeaGreen", "Initial Abstracted Flow": "MediumBlue", "Overland Flow": "RoyalBlue", "PET": "orange", "AET": "DarkOrange", "Average Soil Root zone": "Gray", "Average Soil Unsaturated Zone": "DarkGray", "Snow Pack": "PowderBlue", "Precipitation": "SkyBlue", "Storage Deficit": "Brown", "Return Flow": "Aqua", "Water Use": "DarkCyan", "Discharge + Water Use": "DarkBlue" } def __init__(self, parent = None): super(MatplotlibWidget, self).__init__(parent) # create object scope variables for watertxt data plot; used by radio buttons and span selector self.watertxt_data = None self.parameter = None self.color_str = None self.axes_text = None self.axes_radio = None self.parent = parent # create figure self.figure = Figure() # create canvas and set some of its properties self.canvas = FigureCanvas(self.figure) self.canvas.setParent(parent) self.canvas.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.canvas.updateGeometry() self.canvas.setFocusPolicy(QtCore.Qt.StrongFocus) self.canvas.setFocus() # set up axes and its properties self.ax = self.figure.add_subplot(111) self.ax.grid(True) # create toolbar self.matplotlib_toolbar = NavigationToolbar(self.canvas, parent) # the matplotlib toolbar object # create the layout self.layout = QtGui.QVBoxLayout() # add the widgets to the layout self.layout.addWidget(self.matplotlib_toolbar) self.layout.addWidget(self.canvas) # set the layout self.setLayout(self.layout) #-------------------------------- WATER.txt Parameter Plot ------------------------------------ def setup_watertxt_plot(self): """ Setup the watertxt plot """ self.clear_watertxt_plot() # set up axes and its properties self.axes = self.figure.add_subplot(111) self.axes.grid(True) # create radio buttons self.axes_radio = self.figure.add_axes([0.01, 0.02, 0.10, 0.15]) # [left, bottom, width, height] = fractions of figure width and height self.figure.subplots_adjust(bottom=0.2) self.radio_buttons = RadioButtons(ax = self.axes_radio, labels = ("Span On", "Span Off"), active = 1, activecolor= "r") self.radio_buttons.on_clicked(self.toggle_selector) # create SpanSelector; invisble at first unless activated with toggle selector self.span_selector = SpanSelector(self.axes, self.on_select_axes, 'horizontal', useblit = True, rectprops = dict(alpha=0.5, facecolor='red')) self.span_selector.visible = False def plot_watertxt_parameter(self, watertxt_data, name): """ Plot a parameter from a WATER.txt file """ self.reset_watertxt_plot() self.dates = watertxt_data["dates"] self.watertxt_data = watertxt_data self.parameter = watertxt.get_parameter(watertxt_data, name = name) assert self.parameter is not None, "Parameter name {} is not in watertxt_data".format(name) self.axes.set_title("Parameter: {}".format(self.parameter["name"])) self.axes.set_xlabel("Date") ylabel = "\n".join(wrap(self.parameter["name"], 60)) self.axes.set_ylabel(ylabel) # get proper color that corresponds to parameter name self.color_str = self.colors_dict[name.split('(')[0].strip()] # plot parameter self.axes.plot(self.dates, self.parameter["data"], color = self.color_str, label = self.parameter["name"], linewidth = 2) # legend; make it transparent handles, labels = self.axes.get_legend_handles_labels() legend = self.axes.legend(handles, labels, fancybox = True) legend.get_frame().set_alpha(0.5) legend.draggable(state=True) # show text of mean, max, min values on graph; use matplotlib.patch.Patch properies and bbox text = "mean = {:.2f}\nmax = {:.2f}\nmin = {:.2f}".format(self.parameter["mean"], self.parameter["max"], self.parameter["min"]) patch_properties = {"boxstyle": "round", "facecolor": "wheat", "alpha": 0.5} self.axes_text = self.axes.text(0.05, 0.95, text, transform = self.axes.transAxes, fontsize = 14, verticalalignment = "top", horizontalalignment = "left", bbox = patch_properties) # use a more precise date string for the x axis locations in the toolbar and rotate labels self.axes.fmt_xdata = mdates.DateFormatter("%Y-%m-%d") # rotate and align the tick labels so they look better; note that self.figure.autofmt_xdate() does not work because of the radio button axes for label in self.axes.get_xticklabels(): label.set_ha("right") label.set_rotation(30) # draw the plot self.canvas.draw() def on_select_helper(self, xmin, xmax): """ Helper for on_select methods """ # convert matplotlib float dates to a datetime format date_min = mdates.num2date(xmin) date_max = mdates.num2date(xmax) # put the xmin and xmax in datetime format to compare date_min = datetime.datetime(date_min.year, date_min.month, date_min.day, date_min.hour, date_min.minute) date_max = datetime.datetime(date_max.year, date_max.month, date_max.day, date_max.hour, date_max.minute) # find the indices that were selected indices = np.where((self.dates >= date_min) & (self.dates <= date_max)) indices = indices[0] # get the selected dates and values selected_dates = self.dates[indices] selected_values = self.parameter["data"][indices] # compute simple stats on selected values selected_values_mean = nanmean(selected_values) selected_value_max = np.nanmax(selected_values) selected_value_min = np.nanmin(selected_values) return selected_dates, selected_values, selected_values_mean, selected_value_max, selected_value_min def on_select_axes(self, xmin, xmax): """ A select handler for SpanSelector that updates axes with the new x and y limits selected by user """ selected_dates, selected_values, selected_values_mean, selected_value_max, selected_value_min = self.on_select_helper(xmin, xmax) # plot the selected values and update plots limits and text self.axes.plot(selected_dates, selected_values, self.color_str) self.axes.set_xlim(selected_dates[0], selected_dates[-1]) self.axes.set_ylim(selected_values.min(), selected_values.max()) text = 'mean = %.2f\nmax = %.2f\nmin = %.2f' % (selected_values_mean, selected_value_max, selected_value_min) self.axes_text.set_text(text) # draw the updated plot self.canvas.draw() def toggle_selector(self, radio_button_label): """ A toggle radio buttons for the matplotlib SpanSelector widget. """ if radio_button_label == "Span On": self.span_selector.visible = True self.matplotlib_toolbar.hide() elif radio_button_label == "Span Off": self.span_selector.visible = False self.matplotlib_toolbar.show() self.plot_watertxt_parameter(watertxt_data = self.watertxt_data, name = self.parameter["name"]) def clear_watertxt_plot(self): """ Clear the plot axes """ self.figure.clear() self.canvas.draw() def reset_watertxt_plot(self): """ Clear the plot axes """ self.axes.clear() self.canvas.draw() self.axes.grid(True) #-------------------------------- WATER.txt Parameter Comparison Plot ------------------------------------ def setup_watertxtcmp_plot(self): """ Setup the watertxt plot """ self.clear_watertxtcmp_plot() # set up axes and its properties self.axes1 = self.figure.add_subplot(211) self.axes2 = self.figure.add_subplot(212, sharex = self.axes1) self.axes1.grid(True) self.axes2.grid(True) def plot_watertxtcmp_parameter(self, watertxt_data1, watertxt_data2, filename1, filename2, name): """ Plot a parameter from a WATER.txt file """ self.reset_watertxtcmp_plot() dates = watertxt_data1["dates"] parameter1 = watertxt.get_parameter(watertxt_data = watertxt_data1, name = name) parameter2 = watertxt.get_parameter(watertxt_data = watertxt_data2, name = name) assert parameter1 is not None, "Parameter name {} is not in watertxt_data".format(name) assert parameter2 is not None, "Parameter name {} is not in watertxt_data".format(name) # calculate the difference diff = parameter2["data"] - parameter1["data"] # plot parameters on axes1 self.axes1.plot(dates, parameter1["data"], color = "b", label = filename1 + ": " + parameter1["name"], linewidth = 2) self.axes1.hold(True) self.axes1.plot(dates, parameter2["data"], color = "r", label = filename2 + ": " + parameter2["name"], linewidth = 2) # plot the difference on axes2 self.axes2.plot(dates, diff, color = "k", linewidth = 2) # add title, labels, legend self.axes1.set_title(parameter1["name"]) self.axes2.set_xlabel("Date") self.axes2.set_ylabel("Difference") handles1, labels1 = self.axes1.get_legend_handles_labels() legend1 = self.axes1.legend(handles1, labels1, fancybox = True) legend1.get_frame().set_alpha(0.5) legend1.draggable(state=True) # show text of mean, max, min values on graph; use matplotlib.patch.Patch properies and bbox text1 = "mean = {:.2f}\nmax = {:.2f}\nmin = {:.2f}".format(parameter1["mean"], parameter1["max"], parameter1["min"]) text2 = "mean = {:.2f}\nmax = {:.2f}\nmin = {:.2f}".format(parameter2["mean"], parameter2["max"], parameter2["min"]) text_diff = "mean = {:.2f}\nmax = {:.2f}\nmin = {:.2f}".format(nanmean(diff), np.max(diff), np.min(diff)) patch_properties1 = {"boxstyle": "round", "facecolor": "b", "alpha": 0.5} patch_properties2 = {"boxstyle": "round", "facecolor": "r", "alpha": 0.5} patch_properties_diff = {"boxstyle": "round", "facecolor": "wheat", "alpha": 0.5} self.axes1.text(0.02, 0.95, text1, transform = self.axes1.transAxes, fontsize = 12, verticalalignment = "top", horizontalalignment = "left", bbox = patch_properties1) self.axes1.text(0.02, 0.45, text2, transform = self.axes1.transAxes, fontsize = 12, verticalalignment = "top", horizontalalignment = "left", bbox = patch_properties2) self.axes2.text(0.02, 0.95, text_diff, transform = self.axes2.transAxes, fontsize = 12, verticalalignment = "top", horizontalalignment = "left", bbox = patch_properties_diff) # use a more precise date string for the x axis locations in the toolbar and rotate labels self.axes2.fmt_xdata = mdates.DateFormatter("%Y-%m-%d") # rotate and align the tick labels so they look better self.figure.autofmt_xdate() # draw the plot self.canvas.draw() def clear_watertxtcmp_plot(self): """ Clear the plot axes """ self.figure.clear() self.canvas.draw() def reset_watertxtcmp_plot(self): """ Clear the plot axes """ self.axes1.clear() self.axes2.clear() self.canvas.draw() self.axes1.grid(True) self.axes2.grid(True) #-------------------------------- Basemap Plot ------------------------------------ def setup_basemap_plot(self): """ Setup the watertxt plot """ self.clear_basemap_plot() # set up axes and its properties self.basemap_axes = self.figure.add_subplot(111) self.basemap_axes.grid(True) def get_map_extents(self, shapefiles, shp_name = None): """ Get max and min extent coordinates from a list of shapefiles to use as the extents on the map. Use the map extents to calculate the map center and the standard parallels. Parameters ---------- shapefiles : list List of shapefile_data dictionaries shp_name : string String name of shapefile to use for getting map extents Returns ------- extent_coords : dictionary Dictionary containing "lon_min", "lon_max", "lat_max", "lat_min" keys with respective calculated values center_coords : dictionary Dictionary containing "lon", "lat" keys with respective calculated values standard_parallels : dictionary Dictionary containing "first", "second" keys with respective calculated values (first = min(lat), second = max(lat)) """ extent_coords = {} center_coords = {} standard_parallels = {} lons = [] lats = [] if shp_name: for shapefile_data in shapefiles: if shp_name in shapefile_data["name"].split("_")[0]: lons.append(shapefile_data["extents"][0:2]) lats.append(shapefile_data["extents"][2:]) else: for shapefile_data in shapefiles: lons.append(shapefile_data["extents"][0:2]) lats.append(shapefile_data["extents"][2:]) extent_coords["lon_min"] = np.min(lons) extent_coords["lon_max"] = np.max(lons) extent_coords["lat_min"] = np.min(lats) extent_coords["lat_max"] = np.max(lats) center_coords["lon"] = np.mean([extent_coords["lon_min"], extent_coords["lon_max"]]) center_coords["lat"] = np.mean([extent_coords["lat_min"], extent_coords["lat_max"]]) standard_parallels["first"] = extent_coords["lat_min"] standard_parallels["second"] = extent_coords["lat_max"] return extent_coords, center_coords, standard_parallels def plot_shapefiles_map(self, shapefiles, display_fields = [], colors = [], title = None, shp_name = None, buff = 1.0): """ Generate a map showing all the shapefiles in the shapefile_list. Shapefiles should be in a Geographic Coordinate System (longitude and latitude coordinates) such as World WGS84; Matplotlib"s basemap library does the proper transformation to a projected coordinate system. The projected coordinate system used is Albers Equal Area. Parameters ---------- shapefiles : list List of dictionaries containing shapefile information title : string String title for plot display_fields : list List of strings that correspond to a shapefile field where the corresponding value(s) will be displayed. colors : list List of strings that correspond to colors to be displayed shp_name : string String name of shapefile to use for getting map extents buff : float Float value in coordinate degrees to buffer the map with """ self.setup_basemap_plot() extent_coords, center_coords, standard_parallels = self.get_map_extents(shapefiles, shp_name = shp_name) # create the basemap object with Albers Equal Area Conic Projection bmap = Basemap(projection = "aea", llcrnrlon = extent_coords["lon_min"] - buff, llcrnrlat = extent_coords["lat_min"] - buff, urcrnrlon = extent_coords["lon_max"] + buff, urcrnrlat = extent_coords["lat_max"] + buff, lat_1 = standard_parallels["first"], lat_2 = standard_parallels["second"], lon_0 = center_coords["lon"], lat_0 = center_coords["lat"], resolution = "h", area_thresh = 10000, ax = self.basemap_axes) # have basemap object plot background stuff bmap.drawcoastlines() bmap.drawcountries() bmap.drawrivers(linewidth = 1, color = "blue") bmap.drawstates() bmap.drawmapboundary(fill_color = "aqua") bmap.fillcontinents(color = "coral", lake_color = "aqua") bmap.drawparallels(np.arange(-80., 81., 1.), labels = [1, 0, 0, 0], linewidth = 0.5) bmap.drawmeridians(np.arange(-180., 181., 1.), labels = [0, 0, 0, 1], linewidth = 0.5) # plot each shapefile on the basemap legend_handles = [] legend_labels = [] colors_index = 0 colors_list = ["b", "g", "y", "r", "c", "y", "m", "orange", "aqua", "darksalmon", "gold", "k"] for shapefile_data in shapefiles: # set up colors to use if colors: color = colors[colors_index] elif colors_index > len(colors_list) - 1: color = np.random.rand(3,) else: color = colors_list[colors_index] full_path = os.path.join(shapefile_data["path"], shapefile_data["name"].split(".")[0]) shp_tuple = bmap.readshapefile(full_path, "shp", drawbounds = False) # use basemap shapefile reader for ease of plotting for shape_dict, shape in zip(bmap.shp_info, bmap.shp): # zip the shapefile information and its shape as defined by basemap if shapefile_data["type"] == "POLYGON": p1 = Polygon(shape, facecolor = color, edgecolor = "k", linewidth = 1, alpha = 0.7, label = shapefile_data["name"]) self.basemap_axes.add_patch(p1) xx, yy = zip(*shape) txt_x = str(np.mean(xx)) txt_y = str(np.mean(yy)) elif shapefile_data["type"] == "POINT": x, y = shape if "usgsgages" in shapefile_data["name"].split("_")[0]: p1 = bmap.plot(x, y, color = color, marker = "^", markersize = 10, label = shapefile_data["name"]) elif "wateruse" in shapefile_data["name"].split("_")[0]: p1 = bmap.plot(x, y, color = color, marker = "o", markersize = 5, label = shapefile_data["name"]) else: print("what!!") p1 = bmap.plot(x, y, color = color, marker = "o", markersize = 10, label = shapefile_data["name"]) txt_x = str(x) txt_y = str(y) else: xx, yy = zip(*shape) p1 = bmap.plot(xx, yy, linewidth = 1, color = color, label = shapefile_data["name"]) txt_x = str(np.mean(xx)) txt_y = str(np.mean(yy)) if isinstance(p1, list): p1 = p1[0] # control text display of shapefile fields for display_field in display_fields: if display_field in shape_dict.keys(): self.basemap_axes.text(txt_x, txt_y, shape_dict[display_field], color = "k", fontsize = 12, fontweight = "bold") colors_index += 1 legend_handles.append(p1) legend_labels.append(shapefile_data["name"].split("_")[0]) handles, labels = self.basemap_axes.get_legend_handles_labels() # edit the contents of handles and labels to only show 1 legend per shape handles = legend_handles labels = legend_labels legend = self.basemap_axes.legend(handles, labels, fancybox = True, numpoints = 1) legend.get_frame().set_alpha(0.5) legend.draggable(state = True) # draw the plot self.canvas.draw() def clear_basemap_plot(self): """ Clear the plot axes """ self.figure.clear() self.canvas.draw() def reset_basemap_plot(self): """ Clear the plot axes """ self.basemap_axes.clear() self.canvas.draw()
class Window(QtGui.QWidget): def __init__(self, parent=None): super(Window, self).__init__(parent) self.setWindowTitle('OpenWave-1KB') icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap("openwave.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.setWindowIcon(icon) #Waveform area. self.figure = plt.figure() self.figure.set_facecolor('white') self.canvas = FigureCanvas(self.figure) self.canvas.setMinimumSize(800, 400) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() #Zoom In/out and Capture Buttons self.zoomBtn = QtGui.QPushButton('Zoom') self.zoomBtn.setFixedSize(100, 30) self.zoomBtn.clicked.connect(self.toolbar.zoom) self.panBtn = QtGui.QPushButton('Pan') self.panBtn.setFixedSize(100, 30) self.panBtn.clicked.connect(self.toolbar.pan) self.homeBtn = QtGui.QPushButton('Home') self.homeBtn.setFixedSize(100, 30) self.homeBtn.clicked.connect(self.toolbar.home) self.captureBtn = QtGui.QPushButton('Capture') self.captureBtn.setFixedSize(100, 50) self.captureBtn.clicked.connect(self.captureAction) if (portNum == -1): self.captureBtn.setEnabled(False) #Type: Raw Data/Image self.typeBtn = QtGui.QPushButton('Raw Data') self.typeBtn.setToolTip("Switch to get raw data or image from DSO.") self.typeBtn.setFixedSize(120, 50) self.typeFlag = True #Initial state -> Get raw data self.typeBtn.setCheckable(True) self.typeBtn.setChecked(True) self.typeBtn.clicked.connect(self.typeAction) #Channel Selection. self.ch1checkBox = QtGui.QCheckBox('CH1') self.ch1checkBox.setFixedSize(60, 30) self.ch2checkBox = QtGui.QCheckBox('CH2') self.ch2checkBox.setFixedSize(60, 30) if (dso.chnum == 4): self.ch3checkBox = QtGui.QCheckBox('CH3') self.ch3checkBox.setFixedSize(60, 30) self.ch4checkBox = QtGui.QCheckBox('CH4') self.ch4checkBox.setFixedSize(60, 30) #Set channel selection layout. self.selectLayout = QtGui.QHBoxLayout() self.selectLayout.addWidget(self.ch1checkBox) self.selectLayout.addWidget(self.ch2checkBox) if (dso.chnum == 4): self.selectLayout2 = QtGui.QHBoxLayout() self.selectLayout2.addWidget(self.ch3checkBox) self.selectLayout2.addWidget(self.ch4checkBox) self.typeLayout = QtGui.QHBoxLayout() self.typeLayout.addWidget(self.typeBtn) self.typeLayout.addLayout(self.selectLayout) if (dso.chnum == 4): self.typeLayout.addLayout(self.selectLayout2) #Save/Load/Quit button self.saveBtn = QtGui.QPushButton('Save') self.saveBtn.setFixedSize(100, 50) self.saveMenu = QtGui.QMenu(self) self.csvAction = self.saveMenu.addAction("&As CSV File") self.pictAction = self.saveMenu.addAction("&As PNG File") self.saveBtn.setMenu(self.saveMenu) self.saveBtn.setToolTip("Save waveform to CSV file or PNG file.") self.connect(self.csvAction, QtCore.SIGNAL("triggered()"), self.saveCsvAction) self.connect(self.pictAction, QtCore.SIGNAL("triggered()"), self.savePngAction) self.loadBtn = QtGui.QPushButton('Load') self.loadBtn.setToolTip("Load CHx's raw data from file(*.csv, *.lsf).") self.loadBtn.setFixedSize(100, 50) self.loadBtn.clicked.connect(self.loadAction) self.quitBtn = QtGui.QPushButton('Quit') self.quitBtn.setFixedSize(100, 50) self.quitBtn.clicked.connect(self.quitAction) # set the layout self.waveLayout = QtGui.QHBoxLayout() self.waveLayout.addWidget(self.canvas) self.wave_box = QtGui.QVBoxLayout() self.wave_box.addLayout(self.waveLayout) self.wavectrlLayout = QtGui.QHBoxLayout() self.wavectrlLayout.addWidget(self.zoomBtn) self.wavectrlLayout.addWidget(self.panBtn) self.wavectrlLayout.addWidget(self.homeBtn) self.wavectrlLayout.addWidget(self.captureBtn) self.saveloadLayout = QtGui.QHBoxLayout() self.saveloadLayout.addWidget(self.saveBtn) self.saveloadLayout.addWidget(self.loadBtn) self.saveloadLayout.addWidget(self.quitBtn) self.ctrl_box = QtGui.QHBoxLayout() self.ctrl_box.addLayout(self.typeLayout) self.ctrl_box.addLayout(self.saveloadLayout) main_box = QtGui.QVBoxLayout() main_box.addLayout(self.wave_box) #Waveform area. main_box.addLayout(self.wavectrlLayout) #Zoom In/Out... main_box.addLayout(self.ctrl_box) #Save/Load/Quit self.setLayout(main_box) def typeAction(self): if (self.typeFlag == True): self.typeFlag = False self.typeBtn.setText("Image") self.csvAction.setEnabled(False) else: self.typeFlag = True self.typeBtn.setText("Raw Data") self.csvAction.setEnabled(True) self.typeBtn.setChecked(self.typeFlag) self.ch1checkBox.setEnabled(self.typeFlag) self.ch2checkBox.setEnabled(self.typeFlag) if (dso.chnum == 4): self.ch3checkBox.setEnabled(self.typeFlag) self.ch4checkBox.setEnabled(self.typeFlag) def saveCsvAction(self): if (self.typeFlag == True): #Save raw data to csv file. file_name = QtGui.QFileDialog.getSaveFileName( self, "Save as", '', "Fast CSV File(*.csv)")[0] num = len(dso.ch_list) #print num for ch in xrange(num): if (dso.info[ch] == []): print( 'Failed to save data, raw data information is required!' ) return f = open(file_name, 'wb') item = len(dso.info[0]) #Write file header. f.write('%s, \n' % dso.info[0][0]) for x in xrange(1, 23): str = '' for ch in xrange(num): str += ('%s,' % dso.info[ch][x]) str += '\n' f.write(str) if (num == 1): str = 'Mode,Fast,\n' f.write(str) str = 'Waveform Data,\n' f.write(str) else: str = '' for ch in xrange(num): str += ('Mode,Fast,') str += '\n' f.write(str) str = '' for ch in xrange(num): str += ('Waveform Data,,') str += '\n' f.write(str) #Write raw data. item = len(dso.iWave[0]) #print item tenth = int(item / 10) n_tenth = tenth - 1 percent = 10 for x in xrange(item): str = '' if (num == 1): str += ('%s,' % dso.iWave[0][x]) else: for ch in xrange(num): str += ('%s, ,' % dso.iWave[ch][x]) str += '\n' f.write(str) if (x == n_tenth): n_tenth += tenth print('%3d %% Saved\r' % percent), percent += 10 f.close() def savePngAction(self): #Save figure to png file. file_name = QtGui.QFileDialog.getSaveFileName(self, "Save as", '', "PNG File(*.png)")[0] if (file_name == ''): return if (self.typeFlag == True): #Save raw data waveform as png file. main.figure.savefig(file_name) print('Saved image to %s.' % file_name) else: #Save figure to png file. if (dso.nodename == 'pi'): #For raspberry pi only. img = dso.im.transpose(Image.FLIP_TOP_BOTTOM) img.save(file_name) else: dso.im.save(file_name) print('Saved image to %s.' % file_name) def loadAction(self): dso.ch_list = [] full_path_name = QtGui.QFileDialog.getOpenFileName( self, self.tr("Open File"), ".", "CSV/LSF files (*.csv *.lsf);;All files (*.*)") sFileName = unicode(full_path_name).split(',')[0][3:-1] #For PySide print sFileName if (len(sFileName) <= 0): return if os.path.exists(sFileName): print 'Reading file...' count = dso.readRawDataFile(sFileName) #Draw waveform. if (count > 0): total_chnum = len(dso.ch_list) if (total_chnum == 0): return if (dso.dataMode == 'Fast'): self.drawWaveform(0) else: self.drawWaveform(0) else: print('File not found!') def quitAction(self): if (portNum != -1): dso.IO.close() self.close() def captureAction(self): dso.iWave = [[], [], [], []] dso.ch_list = [] if (self.typeFlag == True): #Get raw data. draw_flag = False #Turn on the selected channels. if ((self.ch1checkBox.isChecked() == True) and (dso.isChannelOn(1) == False)): dso.write(":CHAN1:DISP ON\n") #Set CH1 on. if ((self.ch2checkBox.isChecked() == True) and (dso.isChannelOn(2) == False)): dso.write(":CHAN2:DISP ON\n") #Set CH2 on. if (dso.chnum == 4): if ((self.ch3checkBox.isChecked() == True) and (dso.isChannelOn(3) == False)): dso.write(":CHAN3:DISP ON\n") #Set CH3 on. if ((self.ch4checkBox.isChecked() == True) and (dso.isChannelOn(4) == False)): dso.write(":CHAN4:DISP ON\n") #Set CH4 on. #Get all the selected channel's raw datas. if (self.ch1checkBox.isChecked() == True): dso.getRawData( True, 1) #Read CH1's raw data from DSO (including header). if (self.ch2checkBox.isChecked() == True): dso.getRawData( True, 2) #Read CH2's raw data from DSO (including header). if (dso.chnum == 4): if (self.ch3checkBox.isChecked() == True): dso.getRawData( True, 3) #Read CH3's raw data from DSO (including header). if (self.ch4checkBox.isChecked() == True): dso.getRawData( True, 4) #Read CH4's raw data from DSO (including header). #Draw waveform. total_chnum = len(dso.ch_list) if (total_chnum == 0): return if (self.drawWaveform(1) == -1): time.sleep(5) self.drawWaveform(0) else: #Get image. dso.write(':DISP:OUTP?\n') #Send command to get image from DSO. dso.getBlockData() dso.RleDecode() self.showImage() plt.tight_layout(True) self.canvas.draw() print('Image is ready!') def showImage(self): #Turn the ticks off and show image. plt.clf() ax = plt.gca() ax.xaxis.set_visible(False) ax.yaxis.set_visible(False) plt.imshow(dso.im) def drawWaveform(self, mode): total_chnum = len(dso.ch_list) num = dso.points_num ch_colortable = ['#C0B020', '#0060FF', '#FF0080', '#00FF60'] ch = int(dso.ch_list[0][2]) - 1 #Get the channel of first waveform. plt.cla() plt.clf() #Due to the memory limitation of matplotlib, we must reduce the sample points. if (num == 10000000): if (total_chnum > 2): down_sample_factor = 4 elif (total_chnum == 2): down_sample_factor = 4 else: down_sample_factor = 1 num = num / down_sample_factor else: down_sample_factor = 1 dt = dso.dt[0] #Get dt from the first opened channel. t_start = dso.hpos[0] - num * dt / 2 t_end = dso.hpos[0] + num * dt / 2 t = np.arange(t_start, t_end, dt) #print t_start, t_end, dt, len(t) if ((len(t) - num) == 1): #Avoid floating point rounding error. t = t[:-1] wave_type = '-' #Set waveform type to vector. #Draw waveforms. ax = [[], [], [], []] p = [] for ch in xrange(total_chnum): if (ch == 0): ax[ch] = host_subplot(111, axes_class=AA.Axes) ax[ch].set_xlabel("Time (sec)") else: ax[ch] = ax[0].twinx() ax[ch].set_ylabel("%s Units: %s" % (dso.ch_list[ch], dso.vunit[ch])) ch_color = ch_colortable[int(dso.ch_list[ch][2]) - 1] if (ch > 1): new_fixed_axis = ax[ch].get_grid_helper().new_fixed_axis ax[ch].axis["right"] = new_fixed_axis(loc="right", axes=ax[ch], offset=(60 * (ch - 1), 0)) ax[ch].set_xlim(t_start, t_end) ax[ch].set_ylim(-4 * dso.vdiv[ch] - dso.vpos[ch], 4 * dso.vdiv[ch] - dso.vpos[ch]) #Setup vertical display range. fwave = dso.convertWaveform(ch, down_sample_factor) #print('Length=%d'%(len(fwave))) if (ch == 0): try: p = ax[ch].plot(t, fwave, color=ch_color, ls=wave_type, label=dso.ch_list[ch]) except: if (mode == 1): #print sys.exc_info()[0] time.sleep(5) print 'Trying to plot again!', return -1 else: try: p += ax[ch].plot(t, fwave, color=ch_color, ls=wave_type, label=dso.ch_list[ch]) except: if (mode == 1): #print sys.exc_info()[0] time.sleep(5) print 'Trying to plot again!', return -1 if (total_chnum > 1): labs = [l.get_label() for l in p] plt.legend(p, labs, loc='upper right') plt.tight_layout() self.canvas.draw() del ax, t, p return 0
def rebuild_widget(self, number_of_plots, plot_stretching): self.__number_of_plots = number_of_plots self.__plot_stretching = plot_stretching ids = [] if self.__top_vbox.count() < self.__number_of_plots: ids = range(self.__top_vbox.count(), self.__number_of_plots) for i in ids: label = QLabel() label.setFont(self.__font) label.setAlignment(Qt.AlignCenter) # Create the mpl Figure and FigCanvas objects. # 5x4 inches, 100 dots-per-inch # #dpi = 100 #self.fig = Figure((5.0, 4.0), dpi=self.dpi) fig = pyplot.figure() canvas = FigureCanvas(fig) canvas.setParent(self) # Since we have only one plot, we can use add_axes # instead of add_subplot, but then the subplot # configuration tool in the navigation toolbar wouldn't # work. # axes = fig.add_subplot(111) # Create the navigation toolbar, tied to the canvas # mpl_toolbar = NavigationToolbar(canvas, self, False) if self.__show_toolbar: mpl_toolbar.show() else: mpl_toolbar.hide() # Other GUI controls # tmp_vbox = QVBoxLayout() tmp_vbox.addWidget(label) tmp_vbox.addWidget(canvas, 1) tmp_vbox.addWidget(mpl_toolbar) widget = QWidget() widget.setLayout(tmp_vbox) self.__plots.append((label, canvas, fig, axes, mpl_toolbar, widget)) self.__plot_infos.append((self.PLOT_TYPE_NONE, '', None, {})) self.__top_vbox.addWidget(widget) for i in xrange(self.__number_of_plots): stretch = 0 if plot_stretching != None: stretch = plot_stretching[i] self.__top_vbox.setStretch(i, stretch) else: self.__top_vbox.setStretch(i, 1) plot = self.__plots[i] label, canvas, fig, axes, mpl_toolbar, widget = plot widget.show() for i in xrange(self.__number_of_plots, self.__top_vbox.count()): plot = self.__plots[i] label, canvas, fig, axes, mpl_toolbar, widget = plot widget.hide() if self.__show_menu: menubar = QMenuBar() save_menu = menubar.addMenu("&Save") menu_items = [] for i,plot_info in enumerate(self.__plot_infos): plot_caption = plot_info[1] menu_name = "Save &plot '%s' [%d]" % (plot_caption, i+1) if len(plot_caption) == 0: menu_name = "Save &plot #%d" % (i+1) save_plot_action = self.__make_action(menu_name, shortcut="Ctrl+P", slot=functools.partial(self.on_save_plot, i)) menu_items.append(save_plot_action) menu_items.append(None) save_all_action = self.__make_action("Save &all plots", shortcut="Ctrl+A", slot=self.on_save_all_plots) menu_items.append(save_all_action) self.__add_actions(save_menu, menu_items) self.layout().setMenuBar(menubar)
class MplCanvas(QWidget): """Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.).""" def __init__(self, parent=None): super(MplCanvas, self).__init__(parent) #屏幕图片分辨率 self.fig = Figure(figsize=(8, 6), dpi=100) self.canvas = FigureCanvas(self.fig) self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.canvas.setParent(parent) #调整画布区 self.fig.subplots_adjust(left=0.02, bottom=0.08, top=0.95, right=0.95) self.fig.clear() self.layout = QVBoxLayout() self.layout.setContentsMargins(0, 0, 0, 0) self.layout.addWidget(self.canvas) self.mpl_toolbar = NavigationToolbar(self.canvas, parent, coordinates=False) #self._init_MplToolBar() self.mpl_toolbar.hide() #self.layout.addWidget(self.mpl_toolbar) self.setLayout(self.layout) self._init_Axes() def _init_MplToolBar(self): """设置toolbar上的功能键""" a = self.mpl_toolbar.actions() for i in a: if i.iconText() == 'Home': i.setToolTip(u'初始视图') elif i.iconText() == 'Back': i.setToolTip(u'后退') elif i.iconText() == 'Forward': i.setToolTip(u'前进') elif i.iconText() == 'Pan': i.setToolTip(u'鼠标左键平移,右键横竖缩放') elif i.iconText() == 'Zoom': i.setToolTip(u'局部缩放') elif i.iconText() == 'Subplots': self.mpl_toolbar.removeAction(i) elif i.iconText() == 'Customize': self.mpl_toolbar.removeAction(i) elif i.iconText() == 'Save': i.setToolTip(u'保存图片') def _init_Axes(self): self.axes = self.fig.add_subplot(111) self.axes.yaxis.set_visible(False) #self.axes.tick_params(axis='y', left='off', labelleft='off', width=0) self.axes.tick_params(axis='x', top='off') self.axes.spines['right'].set_visible(False) self.axes.spines['top'].set_visible(False) self.axes.spines['left'].set_visible(False) self.axes.spines['bottom'].set_visible(True) self.axes.set_xlabel(u'时间(s)') self.cur_axes = self.axes self.x_left, self.x_right = self.cur_axes.get_xlim() self.y_bottom, self.y_top = self.cur_axes.get_ylim() def _init_View(self): """ 记录当前canvas """ self.mpl_toolbar.update() self.mpl_toolbar.push_current() self.x_left, self.x_right = self.cur_axes.get_xlim() self.y_bottom, self.y_top = self.cur_axes.get_ylim()
class MplWidget(QtGui.QWidget): """Widget defined in Qt Designer""" def __init__(self, tools, toolbar=True, menu=True, parent=None): # initialization of Qt MainWindow widget QtGui.QWidget.__init__(self, parent) # set the canvas to the Matplotlib widget self.canvas = MplCanvas() # create a vertical box layout self.layout = QtGui.QVBoxLayout() # add mpl widget to layout self.layout.addWidget(self.canvas) # reference to toolsFrame self.tool = tools if toolbar: # add navigation toolbar to layout self.toolbar = NavigationToolbar(self.canvas, self) self.layout.addWidget(self.toolbar) # enable hover event handling self.setAttribute(Qt.WA_Hover) # create and install event filter self.filter = Filter(self) self.installEventFilter(self.filter) # hide toolbar self.initComponents() else: self.toolbar = None # set the layout to th vertical box self.setLayout(self.layout) # active lines list self.lines = [] # legend self.legend = None # autoscale self.canvas.ax.autoscale_view(True, True, True) if menu: # setup context menu self.setContextMenuPolicy(Qt.ActionsContextMenu) self.initActions() self.alwaysAutoScale.setChecked(True) #-------------- initialization ---------------# def initComponents(self): if self.toolbar is not None: self.toolbar.hide() self.newIcons() def initActions(self): # toolbar self.toggleLegendAction = QtGui.QAction(QtGui.QIcon(RES + ICONS + LEGEND), 'Toggle legend', self, triggered=self.toggleLegend) self.toggleLegendAction.setCheckable(True) if self.toolbar is not None: self.toolbar.addAction(self.toggleLegendAction) # context menu self.addAction(self.toggleLegendAction) self.addAction(QtGui.QAction(QtGui.QIcon(RES + ICONS + COPY),'Copy data to table', self, triggered=self.toTable)) self.addAction(QtGui.QAction(QtGui.QIcon(RES + ICONS + GRAPH),'Plot data in tools', self, triggered=self.toGraphTool)) self.addAction(QtGui.QAction(QtGui.QIcon(RES + ICONS + SCALE), 'Autoscale', self, triggered=self.updateScale)) self.alwaysAutoScale = QtGui.QAction('Scale on update', self) self.alwaysAutoScale.setCheckable(True) self.selectLinesMenu = QtGui.QMenu() self.selectLines = (QtGui.QAction('Plots', self)) self.selectLines.setMenu(self.selectLinesMenu) aSep = QtGui.QAction('', self) aSep.setSeparator(True) self.addAction(aSep) self.addAction(self.selectLines) self.addAction(self.alwaysAutoScale) def newIcons(self): for position in range(0, self.toolbar.layout().count()): widget = self.toolbar.layout().itemAt(position).widget() if isinstance(widget, QtGui.QToolButton): icon = QtGui.QIcon(RES + ICONS + TOOLBAR_ICONS[position]) self.toolbar.layout().itemAt(position).widget().setIcon(icon) self.toolbar.setIconSize(QSize(ICO_GRAPH, ICO_GRAPH)) def resetGraphicEffect(self): if self.graphicsEffect() is not None: self.graphicsEffect().setEnabled(False) #------------- plotting methods ---------------# ## Hides axes in widget. # @param axes Widget axes form canvas. @staticmethod def hideAxes(axes): axes.get_xaxis().set_visible(False) axes.get_yaxis().set_visible(False) ## Clears widget canvas, removing all data and clearing figure. # @param repaint_axes Add standard plot after clearing figure. def clearCanvas(self, repaint_axes=True): self.canvas.ax.clear() self.canvas.fig.clear() if repaint_axes: self.canvas.ax = self.canvas.fig.add_subplot(111) ## Update existing data or plot anew. # @param data List or array to plot/update. # @param line Which line (by index) to update (if any). # @param label Data label (new or existing). # @param style Line style (solid, dashed, dotted). # @param color Line color. def updatePlot(self, data, line=0, label=None, style='solid', color=None): if not self.canvas.ax.has_data(): if label is not None: if color is not None: self.lines = self.canvas.ax.plot(data, label=label, linestyle=style, color=color) else: self.lines = self.canvas.ax.plot(data, label=label, linestyle=style) else: if color is not None: self.lines = self.canvas.ax.plot(data, linestyle=style, color=color) else: self.lines = self.canvas.ax.plot(data, linestyle=style) else: if not self.lines: self.lines = self.canvas.ax.get_lines() if label is not None: if label not in [l._label for l in self.lines]: if color is not None: self.lines.extend(self.canvas.ax.plot(data, label=label, linestyle=style, color=color)) else: self.lines.extend(self.canvas.ax.plot(data, label=label, linestyle=style)) line = len(self.lines) - 1 else: line = [l._label for l in self.lines].index(label) line_to_update = self.lines[line] if len(data) != len(line_to_update._x): # x, y ~ data in y line_to_update.set_data(np.arange(len(data)), data) else: # in case data length stays the same line_to_update.set_data(line_to_update._x, data) self.canvas.draw() self.updateLegend() self.updateLinesSubmenu() if self.alwaysAutoScale.isChecked(): self.updateScale() ## Plots scalogram for wavelet decomposition. # @param data Wavelet coefficients in matrix. # @param top Axis position. # @param colorbar Shows colorbar for data levels. # @param power Scales resulting graph by power of 2. def scalogram(self, data, top=True, colorbar=True, power=False): # self.resetGraphicEffect() self.clearCanvas() x = np.arange(len(data[0])) y = np.arange(len(data)) if power: contour = self.canvas.ax.contourf(x, y, np.abs(data) ** 2) else: contour = self.canvas.ax.contourf(x, y, np.abs(data)) if colorbar: self.canvas.fig.colorbar(contour, ax=self.canvas.ax, orientation='vertical', format='%2.1f') if top: self.canvas.ax.set_ylim((y[-1], y[0])) else: self.canvas.ax.set_ylim((y[0], y[-1])) self.canvas.ax.set_xlim((x[0], x[-1])) # self.canvas.ax.set_ylabel('scales') self.canvas.draw() ## Plots list of arrays with shared x/y axes. # @param data Arrays to plot (list or matrix). def multiline(self, data): # self.resetGraphicEffect() # abscissa axprops = dict(yticks=[]) # ordinate yprops = dict(rotation=0, horizontalalignment='right', verticalalignment='center', x=-0.01) # level/figure ratio ratio = 1. / len(data) # positioning (fractions of total figure) left = 0.1 bottom = 1.0 width = 0.85 space = 0.035 height = ratio - space # legend label = 'Lvl %d' i = 0 bottom -= height ax = self.canvas.fig.add_axes([left, bottom - space, width, height], **axprops) ax.plot(data[i]) setp(ax.get_xticklabels(), visible=False) ax.set_ylabel(label % i, **yprops) i += 1 axprops['sharex'] = ax axprops['sharey'] = ax while i < len(data): bottom -= height ax = self.canvas.fig.add_axes([left, bottom, width, height], **axprops) ax.plot(data[i], label='Lvl' + str(i)) ax.set_ylabel(label % i, **yprops) i += 1 if i != len(data): setp(ax.get_xticklabels(), visible=False) #----------------- actions -----------------# def getTopParent(self): widget = self.parentWidget() while True: if widget.parentWidget() is None: return widget else: widget = widget.parentWidget() def toggleLegend(self): self.updateLegend() def updateLegend(self): #NB: sometimes induces random exceptions from legend.py -> offsetbox.py try: prop = font_manager.FontProperties(size=11) self.legend = DraggableLegend(self.canvas.ax.legend(fancybox=True, shadow=True, prop=prop)) if self.toggleLegendAction.isChecked(): self.legend.legend.set_visible(True) else: self.legend.legend.set_visible(False) self.canvas.draw() except Exception, e: pass
class MplWidget(QtGui.QWidget): """Widget defined in Qt Designer""" def __init__(self, toolbar=True, menu=True, parent=None): # initialization of Qt MainWindow widget QtGui.QWidget.__init__(self, parent) # set the canvas to the Matplotlib widget self.canvas = MplCanvas() # create a vertical box layout self.layout = QtGui.QVBoxLayout() # add mpl widget to layout self.layout.addWidget(self.canvas) if toolbar: # add navigation toolbar to layout self.toolbar = NavigationToolbar(self.canvas, self) self.layout.addWidget(self.toolbar) # enable hover event handling self.setAttribute(Qt.WA_Hover) # create and install event filter self.filter = Filter(self) self.installEventFilter(self.filter) # hide toolbar self.initComponents() else: self.toolbar = None # set the layout to th vertical box self.setLayout(self.layout) # active lines list self.lines = [] # legend self.legend = None # autoscale self.canvas.ax.autoscale_view(True, True, True) if menu: # setup context menu self.setContextMenuPolicy(Qt.ActionsContextMenu) self.initActions() self.alwaysAutoScale.setChecked(True) #-------------- initialization ---------------# def initComponents(self): if self.toolbar is not None: self.toolbar.hide() self.newIcons() def initActions(self): # toolbar #self.toggleLegendAction = QtGui.QAction(QtGui.QIcon(RES + ICONS + LEGEND), 'Toggle legend', #self, triggered=self.toggleLegend) #self.toggleLegendAction.setCheckable(True) #if self.toolbar is not None: #self.toolbar.addAction(self.toggleLegendAction) # context menu #self.addAction(self.toggleLegendAction) #self.addAction(QtGui.QAction(QtGui.QIcon(RES + ICONS + COPY),'Copy data to table', #self, triggered=self.toTable)) #self.addAction(QtGui.QAction(QtGui.QIcon(RES + ICONS + GRAPH),'Plot data in tools', #self, triggered=self.toGraphTool)) #self.addAction(QtGui.QAction(QtGui.QIcon(RES + ICONS + SCALE), 'Autoscale', #self, triggered=self.updateScale)) self.alwaysAutoScale = QtGui.QAction('Scale on update', self) self.alwaysAutoScale.setCheckable(True) self.selectLinesMenu = QtGui.QMenu() self.selectLines = (QtGui.QAction('Plots', self)) self.selectLines.setMenu(self.selectLinesMenu) aSep = QtGui.QAction('', self) aSep.setSeparator(True) self.addAction(aSep) self.addAction(self.selectLines) self.addAction(self.alwaysAutoScale) def newIcons(self): for position in range(0, self.toolbar.layout().count()): widget = self.toolbar.layout().itemAt(position).widget() #if isinstance(widget, QtGui.QToolButton): #icon = QtGui.QIcon(RES + ICONS + TOOLBAR_ICONS[position]) #self.toolbar.layout().itemAt(position).widget().setIcon(icon) #self.toolbar.setIconSize(QSize(ICO_GRAPH, ICO_GRAPH)) def resetGraphicEffect(self): if self.graphicsEffect() is not None: self.graphicsEffect().setEnabled(False) #------------- plotting methods ---------------# def histogram(self, data): pass def kanjiStats(self, data): self.clearCanvas() picked, freqs = data # will lag #self.statPlot.canvas.ax.bar(freqs, picked) self.canvas.ax.plot(freqs, picked) self.canvas.ax.set_xlabel('Frequency') self.canvas.ax.set_ylabel('Number of times picked') self.canvas.ax.set_title('Distribution of (pseudo)randomly selected kanji') #self.statPlot.canvas.ax.text(max(freqs)/2, max(picked), #"""This distribution illustrates how much times (max %d) #kanji with different frequencies (max %d) has been picked""" #% (max(picked), max(freqs)), bbox=dict(facecolor='blue', alpha=0.1)) self.canvas.ax.grid(True) self.canvas.ax.fill_between(freqs, picked, 1, facecolor='blue', alpha=0.5) self.canvas.draw() ## Hides axes in widget. # @param axes Widget axes form canvas. @staticmethod def hideAxes(axes): axes.get_xaxis().set_visible(False) axes.get_yaxis().set_visible(False) ## Clears widget canvas, removing all data and clearing figure. # @param repaint_axes Add standard plot after clearing figure. def clearCanvas(self, repaint_axes=True): self.canvas.ax.clear() self.canvas.fig.clear() if repaint_axes: self.canvas.ax = self.canvas.fig.add_subplot(111) ## Update existing data or plot anew. # @param data List or array to plot/update. # @param line Which line (by index) to update (if any). # @param label Data label (new or existing). # @param style Line style (solid, dashed, dotted). # @param color Line color. def updatePlot(self, data, line=0, label=None, style='solid', color=None): if not self.canvas.ax.has_data(): if label is not None: if color is not None: self.lines = self.canvas.ax.plot(data, label=label, linestyle=style, color=color) else: self.lines = self.canvas.ax.plot(data, label=label, linestyle=style) else: if color is not None: self.lines = self.canvas.ax.plot(data, linestyle=style, color=color) else: self.lines = self.canvas.ax.plot(data, linestyle=style) else: if not self.lines: self.lines = self.canvas.ax.get_lines() if label is not None: if label not in [l._label for l in self.lines]: if color is not None: self.lines.extend(self.canvas.ax.plot(data, label=label, linestyle=style, color=color)) else: self.lines.extend(self.canvas.ax.plot(data, label=label, linestyle=style)) line = len(self.lines) - 1 else: line = [l._label for l in self.lines].index(label) line_to_update = self.lines[line] if len(data) != len(line_to_update._x): # x, y ~ data in y line_to_update.set_data(np.arange(len(data)), data) else: # in case data length stays the same line_to_update.set_data(line_to_update._x, data) self.canvas.draw() self.updateLegend() self.updateLinesSubmenu() if self.alwaysAutoScale.isChecked(): self.updateScale() ## Plots scalogram for wavelet decomposition. # @param data Wavelet coefficients in matrix. # @param top Axis position. # @param colorbar Shows colorbar for data levels. # @param power Scales resulting graph by power of 2. def scalogram(self, data, top=True, colorbar=True, power=False): # self.resetGraphicEffect() self.clearCanvas() x = np.arange(len(data[0])) y = np.arange(len(data)) if power: contour = self.canvas.ax.contourf(x, y, np.abs(data) ** 2) else: contour = self.canvas.ax.contourf(x, y, np.abs(data)) if colorbar: self.canvas.fig.colorbar(contour, ax=self.canvas.ax, orientation='vertical', format='%2.1f') if top: self.canvas.ax.set_ylim((y[-1], y[0])) else: self.canvas.ax.set_ylim((y[0], y[-1])) self.canvas.ax.set_xlim((x[0], x[-1])) # self.canvas.ax.set_ylabel('scales') self.canvas.draw() ## Plots list of arrays with shared x/y axes. # @param data Arrays to plot (list or matrix). def multiline(self, data): # self.resetGraphicEffect() # abscissa axprops = dict(yticks=[]) # ordinate yprops = dict(rotation=0, horizontalalignment='right', verticalalignment='center', x=-0.01) # level/figure ratio ratio = 1. / len(data) # positioning (fractions of total figure) left = 0.1 bottom = 1.0 width = 0.85 space = 0.035 height = ratio - space # legend label = 'Lvl %d' i = 0 bottom -= height ax = self.canvas.fig.add_axes([left, bottom - space, width, height], **axprops) ax.plot(data[i]) setp(ax.get_xticklabels(), visible=False) ax.set_ylabel(label % i, **yprops) i += 1 axprops['sharex'] = ax axprops['sharey'] = ax while i < len(data): bottom -= height ax = self.canvas.fig.add_axes([left, bottom, width, height], **axprops) ax.plot(data[i], label='Lvl' + str(i)) ax.set_ylabel(label % i, **yprops) i += 1 if i != len(data): setp(ax.get_xticklabels(), visible=False) #----------------- actions -----------------# def getTopParent(self): widget = self.parentWidget() while True: if widget.parentWidget() is None: return widget else: widget = widget.parentWidget() def toggleLegend(self): self.updateLegend() def updateLegend(self): #NB: sometimes induces random exceptions from legend.py -> offsetbox.py try: prop = font_manager.FontProperties(size=11) self.legend = DraggableLegend(self.canvas.ax.legend(fancybox=True, shadow=True, prop=prop)) if self.toggleLegendAction.isChecked(): self.legend.legend.set_visible(True) else: self.legend.legend.set_visible(False) self.canvas.draw() except Exception, e: pass
class Window(QtGui.QDialog): def __init__(self, parent=None): super(Window, self).__init__(parent) self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.canvas.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.hide() # Just some button self.colorcardRadioButton = QtGui.QRadioButton('Select color car&d') self.colorcardRadioButton.setChecked(False) self.colorcardRadioButton.clicked.connect(self.selectWhat) self.trayRadioButton = QtGui.QRadioButton('Select &tray') self.trayRadioButton.setChecked(False) self.trayRadioButton.clicked.connect(self.selectWhat) self.potRadioButton = QtGui.QRadioButton('Select &pot') self.potRadioButton.setChecked(False) self.potRadioButton.clicked.connect(self.selectWhat) self.loadImageButton = QtGui.QPushButton('&Load image') self.loadImageButton.clicked.connect(self.loadImage) self.rotateImageButton = QtGui.QPushButton('&Rotate 90-deg') self.rotateImageButton.clicked.connect(self.rotateImage90Degrees) self.loadCamCalibButton = QtGui.QPushButton('Load &cam. param.') self.loadCamCalibButton.clicked.connect(self.loadCamCalib) self.saveGeometriesButton = QtGui.QPushButton('&Save selected geometries') self.saveGeometriesButton.clicked.connect(self.saveSelectedGeometries) self.saveTraysButton = QtGui.QPushButton('&Save selected tray images') self.saveTraysButton.clicked.connect(self.saveSelectedTrayImages) self.saveColorcadButton = QtGui.QPushButton('&Save sel. col. card images') self.saveColorcadButton.clicked.connect(self.saveSelectedColorcardImages) self.save2PipelineButton = QtGui.QPushButton('&Save as pipeline settings') self.save2PipelineButton.clicked.connect(self.savePipelineSettings) self.zoomButton = QtGui.QPushButton('&Zoom') self.zoomButton.setCheckable(True) self.zoomButton.clicked.connect(self.zoom) self.panButton = QtGui.QPushButton('&Pan') self.panButton.setCheckable(True) self.panButton.clicked.connect(self.pan) self.homeButton = QtGui.QPushButton('&Home') self.homeButton.clicked.connect(self.home) self.status = QtGui.QTextEdit('') self.status.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding) self.mousePosition = QtGui.QLabel('') # set the layout layout = QtGui.QHBoxLayout() rightWidget = QtGui.QWidget() buttonlayout = QtGui.QVBoxLayout(rightWidget) buttonlayout.addWidget(self.loadImageButton) buttonlayout.addWidget(self.rotateImageButton) buttonlayout.addWidget(self.loadCamCalibButton) buttonlayout.addWidget(self.colorcardRadioButton) buttonlayout.addWidget(self.trayRadioButton) buttonlayout.addWidget(self.potRadioButton) buttonlayout.addWidget(self.zoomButton) buttonlayout.addWidget(self.panButton) buttonlayout.addWidget(self.homeButton) buttonlayout.addWidget(self.saveGeometriesButton) buttonlayout.addWidget(self.saveColorcadButton) buttonlayout.addWidget(self.saveTraysButton) buttonlayout.addWidget(self.save2PipelineButton) buttonlayout.addWidget(self.status) buttonlayout.addWidget(self.mousePosition) rightWidget.setMaximumWidth(200) leftLayout = QtGui.QVBoxLayout() leftLayout.addWidget(self.toolbar) leftLayout.addWidget(self.canvas) layout.addWidget(rightWidget) layout.addLayout(leftLayout) self.setLayout(layout) self.group = QtGui.QButtonGroup() self.group.addButton(self.colorcardRadioButton) self.group.addButton(self.trayRadioButton) self.group.addButton(self.potRadioButton) self.panMode = False self.zoomMode = False self.ax = None self.plotRect = None self.plotImg = None self.image = None self.potTemplate = None self.UndistMapX = None self.UndistMapY = None self.trayAspectRatio = 0.835 self.colorcardAspectRatio = 1.5 self.potAspectRatio = 1.0 self.leftClicks = [] self.ImageSize = None self.CameraMatrix = None self.DistCoefs = None # # change cursor shape # self.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor )) # Ouput parameters self.colorcardList = [] self.trayList = [] self.potList = [] self.rotationAngle = 0 self.isDistortionCorrected = False def selectWhat(self): if self.trayRadioButton.isChecked(): self.status.append('Start selecting tray.') elif self.colorcardRadioButton.isChecked(): self.status.append('Start selecting color bar.') else: self.status.append('Start selecting pot.') def home(self): self.toolbar.home() def zoom(self): self.toolbar.zoom() if not self.zoomMode: self.zoomMode = True self.panMode = False self.panButton.setChecked(False) else: self.zoomMode = False def pan(self): self.toolbar.pan() if not self.panMode: self.panMode = True self.zoomMode = False self.zoomButton.setChecked(False) else: self.panMode = False def loadImage(self): ''' load and show an image''' fname = QtGui.QFileDialog.getOpenFileName(self, 'Open image', '/mnt/phenocam/a_data/TimeStreams/BorevitzTest/BVZ0036/BVZ0036-GC02L~fullres-orig/2014/2014_06/2014_06_20/2014_06_20_12') self.status.append('Loading image...') app.processEvents() self.image = cv2.imread(str(fname))[:,:,::-1] self.status.append('Loaded image from ' + str(fname)) # reset all outputs self.colorcardList = [] self.trayList = [] self.potList = [] self.rotationAngle = 0 self.isDistortionCorrected = False # Undistort image if mapping available if not self.isDistortionCorrected and self.UndistMapX != None and self.UndistMapY != None: self.image = cv2.remap(self.image.astype(np.uint8), self.UndistMapX, self.UndistMapY, cv2.INTER_CUBIC) self.isDistortionCorrected = True if self.image != None: if self.ax == None: self.ax = self.figure.add_subplot(111) self.ax.figure.canvas.mpl_connect('button_press_event', self.onMouseClicked) self.ax.figure.canvas.mpl_connect('motion_notify_event', self.onMouseMoves) self.ax.figure.canvas.mpl_connect('figure_enter_event', self.changeCursor) self.ax.hold(False) if self.plotImg == None: self.plotImg = self.ax.imshow(self.image) else: self.plotImg.set_data(self.image) self.figure.tight_layout() self.canvas.draw() def changeCursor(self, event): # cursor = Cursor(self.ax, useblit=True, color='red', linewidth=1) self.canvas.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor )) def updateFigure(self): xs, ys = [], [] for Rect in self.colorcardList: tl, bl, br, tr = Rect xs = xs + [tl[0], bl[0], br[0], tr[0], tl[0], np.nan] ys = ys + [tl[1], bl[1], br[1], tr[1], tl[1], np.nan] for Rect in self.trayList: tl, bl, br, tr = Rect xs = xs + [tl[0], bl[0], br[0], tr[0], tl[0], np.nan] ys = ys + [tl[1], bl[1], br[1], tr[1], tl[1], np.nan] for Rect in self.potList: tl, bl, br, tr = Rect xs = xs + [tl[0], bl[0], br[0], tr[0], tl[0], np.nan] ys = ys + [tl[1], bl[1], br[1], tr[1], tl[1], np.nan] for x,y in self.leftClicks: xs = xs + [x] ys = ys + [y] # if self.crosshair != None: # xs = xs + [np.nan, 0, self.image.shape[1], np.nan, self.crosshair[0], self.crosshair[0], np.nan] # ys = ys + [np.nan, self.crosshair[1], self.crosshair[1], np.nan, 0, self.image.shape[0], np.nan] if len(xs) > 0 and len(ys) > 0: if self.plotRect == None: self.ax.hold(True) self.plotRect, = self.ax.plot(xs, ys, 'b') self.ax.hold(False) self.ax.set_xlim([0,self.image.shape[1]]) self.ax.set_ylim([0,self.image.shape[0]]) self.ax.invert_yaxis() else: self.plotRect.set_data(xs, ys) self.canvas.draw() app.processEvents() def loadCamCalib(self): ''' load camera calibration image and show an image''' CalibFile = QtGui.QFileDialog.getOpenFileName(self, 'Open image', '/home/chuong/Workspace/traitcapture-bin/unwarp_rectify/data') self.ImageSize, SquareSize, self.CameraMatrix, self.DistCoefs, RVecs, TVecs = utils.readCalibration(CalibFile) self.status.append('Loaded camera parameters from ' + CalibFile) print('CameraMatrix =', self.CameraMatrix) print('DistCoefs =', self.DistCoefs) self.UndistMapX, self.UndistMapY = cv2.initUndistortRectifyMap(self.CameraMatrix, self.DistCoefs, \ None, self.CameraMatrix, self.ImageSize, cv2.CV_32FC1) if self.image != None: self.image = cv2.remap(self.image.astype(np.uint8), self.UndistMapX, self.UndistMapY, cv2.INTER_CUBIC) self.isDistortionCorrected = True self.status.append('Corrected image distortion.') if self.plotImg == None: self.plotImg = self.ax.imshow(self.image) else: self.plotImg.set_data(self.image) self.canvas.draw() # def loadPotTemplate(self): # ''' load pot template image''' # fname = QtGui.QFileDialog.getOpenFileName(self, 'Open image', '/home/chuong/Workspace/traitcapture-bin/unwarp_rectify/data') # self.status.append('Loading image...') # app.processEvents() # self.potTemplate = cv2.imread(str(fname))[:,:,::-1] # if len(self.potList) > 0: def saveSelectedGeometries(self): ''' save selected geometries''' fname = QtGui.QFileDialog.getSaveFileName(self, 'Save selected geometries', '/home/chuong/Workspace/traitcapture-bin/unwarp_rectify/data') colorcardList2 = [] for colorcard in self.colorcardList: colorcardList2 = colorcardList2 + colorcard trayList2 = [] for tray in self.trayList: trayList2 = trayList2 + tray potList2 = [] for pot in self.potList: potList2 = potList2 + pot dicdata = {'colorcardself.crosshair = NoneList':np.asarray(colorcardList2), \ 'trayList':np.asarray(trayList2), \ 'potList':np.asarray(potList2), \ 'rotationAngle':self.rotationAngle, \ 'distortionCorrected':int(self.isDistortionCorrected)} cv2yml.dic2yml(fname, dicdata) self.status.append('Saved selected geometries to ' + fname) def saveSelectedTrayImages(self): ''' save selected trays''' fname = QtGui.QFileDialog.getSaveFileName(self, 'Save selected tray images', '/home/chuong/Workspace/traitcapture-bin/unwarp_rectify/data') medianWidth, medianHeight = utils.getMedianRectSize(self.trayList) rectifiedTrayImages = utils.rectifyRectImages(self.image, self.trayList, MedianSize = [medianWidth, medianHeight]) for i,rectifiedImage in enumerate(rectifiedTrayImages): cv2.imwrite(str(fname) %i, rectifiedImage) def saveSelectedColorcardImages(self): ''' save selected trays''' fname = QtGui.QFileDialog.getSaveFileName(self, 'Save selected color card images', '/home/chuong/Workspace/traitcapture-bin/unwarp_rectify/data') medianWidth, medianHeight = utils.getMedianRectSize(self.colorcardList) rectifiedColorcardImages = utils.rectifyRectImages(self.image, self.colorcardList, MedianSize = [medianWidth, medianHeight]) for i,rectifiedImage in enumerate(rectifiedColorcardImages): cv2.imwrite(str(fname) %i, rectifiedImage) def savePipelineSettings(self): ''' save to pipeline setting file''' fname = QtGui.QFileDialog.getSaveFileName(self, 'Save selection to pipeline settings', '/home/chuong/Workspace/traitcapture-bin/unwarp_rectify/data') settingPath = os.path.dirname(str(fname)) settings = [] if self.ImageSize != None and self.CameraMatrix != None and self.DistCoefs != None: undistort = ['undistort', \ {'mess': 'perform optical undistortion', \ 'cameraMatrix': self.CameraMatrix.tolist(), \ 'distortCoefs': self.DistCoefs.tolist(), \ 'imageSize': list(self.ImageSize), 'rotationAngle': self.rotationAngle } \ ] else: undistort = ['undistort', {'mess': '---skip optical undistortion---'}] settings.append(undistort) if len(self.colorcardList) > 0: medianSize = utils.getMedianRectSize(self.colorcardList) capturedColorcards = utils.rectifyRectImages(self.image, self.colorcardList, medianSize) colorCardFile = 'CapturedColorcard.png' cv2.imwrite(os.path.join(settingPath, colorCardFile), capturedColorcards[0][:,:,::-1].astype(np.uint8)) colorcardColors, colorStd = utils.getColorcardColors(capturedColorcards[0], GridSize = [6,4]) colorcardPosition, Width, Height, Angle = utils.getRectangleParamters(self.colorcardList[0]) colorcarddetect = ['colorcarddetect', \ {'mess': '---perform color card detection---', \ 'colorcardFile': colorCardFile,\ 'colorcardPosition': colorcardPosition.tolist(),\ 'colorcardTrueColors': utils.CameraTrax_24ColorCard } ] else: colorcarddetect = ['colorcarddetect', {'mess': '---skip color card detection---'}] settings.append(colorcarddetect) colorcorrect = ['colorcorrect', {'mess': '---perform color correction---'}] settings.append(colorcorrect) if len(self.trayList) > 0: trayMedianSize = utils.getMedianRectSize(self.trayList) trayImages = utils.rectifyRectImages(self.image, self.trayList, trayMedianSize) colorcardColors, colorStd = utils.getColorcardColors(capturedColorcards[0], GridSize = [6,4]) trayDict = {'mess': '---perform tray detection---'} trayDict['trayNumber'] = len(self.trayList) trayDict['trayFiles'] = 'Tray_%02d.png' trayPositions = [] for i,tray in enumerate(trayImages): cv2.imwrite(os.path.join(settingPath, trayDict['trayFiles'] %i), tray[:,:,::-1].astype(np.uint8)) trayPosition, Width, Height, Angle = utils.getRectangleParamters(self.trayList[i]) trayPositions.append(trayPosition.tolist()) trayDict['trayPositions'] = trayPositions traydetect = ['traydetect', trayDict] else: traydetect = ['traydetect', {'mess': '---skip tray detection---'}] settings.append(traydetect) if len(self.potList) > 0: trayMedianSize = utils.getMedianRectSize(self.trayList) potPosition, Width, Height, Angle = utils.getRectangleParamters(self.potList[0]) Width, Height = int(Width), int(Height) topLeft = [int(self.potList[0][0][0]), int(self.potList[0][0][1])] self.potImage = self.image[topLeft[1]:topLeft[1]+Height, topLeft[0]:topLeft[0]+Width, :] potFile = 'Pot.png' cv2.imwrite(os.path.join(settingPath, potFile), self.potImage[:,:,::-1].astype(np.uint8)) potDict = {'mess': '---perform pot detection---'} potDict['potPosition'] = potPosition.tolist() potDict['potSize'] = [int(Width), int(Height)] potDict['traySize'] = [int(trayMedianSize[0]), int(trayMedianSize[1])] potDict['potFile'] = potFile if self.potTemplate != None: potTemplateFile = 'potTemplate.png' cv2.imwrite(os.path.join(settingPath, potTemplateFile), self.potTemplate[:,:,::-1]) potDict['potTemplateFile'] = potTemplateFile potdetect = ['potdetect', potDict] else: potdetect = ['potdetect', {'mess': '---skip pot detection---'}] settings.append(potdetect) plantextract = ['plantextract', {'mess': '---perfrom plant biometrics extraction---'}] settings.append(plantextract) with open(fname, 'w') as outfile: outfile.write( yaml.dump(settings, default_flow_style=None) ) def rotateImage90Degrees(self): if self.image == None: self.status.append('No image to rotate.') return self.rotationAngle = self.rotationAngle + 90 if self.rotationAngle >= 360: self.rotationAngle = self.rotationAngle - 360 self.image = np.rot90(self.image) #.astype(uint8) self.status.append('Rot. angle = %d deg' %self.rotationAngle) if self.plotImg == None: self.plotImg = self.ax.imshow(self.image) else: self.plotImg.set_data(self.image) self.canvas.draw() def onMouseClicked(self, event): if self.panMode or self.zoomMode: return print('click', event.button, event.xdata, event.ydata) if event.button == 1 and event.xdata != None and event.ydata != None: self.leftClicks.append([event.xdata, event.ydata]) print('self.leftClicks =', self.leftClicks) Rect = [] AspectRatio = None if self.trayRadioButton.isChecked(): AspectRatio = self.trayAspectRatio elif self.colorcardRadioButton.isChecked(): AspectRatio = self.colorcardAspectRatio elif self.potRadioButton.isChecked(): AspectRatio = self.potAspectRatio if len(self.leftClicks) == 2 and AspectRatio != None: if self.potRadioButton.isChecked(): Rect = utils.getRectCornersFrom2Points(self.image, self.leftClicks, AspectRatio, Rounded = True) else: Rect = utils.getRectCornersFrom2Points(self.image, self.leftClicks, AspectRatio) self.leftClicks = [] elif len(self.leftClicks) == 4: Rect = [[x,y] for x,y in self.leftClicks] Rect = utils.correctPointOrder(Rect) self.leftClicks = [] if len(Rect) > 0: if self.trayRadioButton.isChecked(): self.trayList.append(Rect) self.status.append('Added tray selection.') elif self.colorcardRadioButton.isChecked(): self.colorcardList.append(Rect) self.status.append('Added color card selection.') else: self.potList.append(Rect) self.status.append('Added pot selection.') self.updateFigure() elif event.button == 3: # remove the last selection if len(self.leftClicks) > 0: self.leftClicks = self.leftClicks[:-1] self.status.append('Removed a previous click') else: if self.trayRadioButton.isChecked() and len(self.trayList) > 0: self.trayList = self.trayList[:-1] self.status.append('Removed a previous tray selection') elif self.colorcardRadioButton.isChecked() and len(self.colorcardList) > 0: self.colorcardList = self.colorcardList[:-1] self.status.append('Removed a previous color card selection.') elif self.potRadioButton.isChecked() and len(self.potList) > 0: self.potList = self.potList[:-1] self.status.append('Removed a previous pot selection') self.updateFigure() else: print('Ignored click') def onMouseMoves(self, event): if event.inaxes == self.ax: self.mousePosition.setText('x=%d, y=%d' %(event.xdata, event.ydata)) # self.crosshair = [event.xdata, event.ydata] else: self.mousePosition.setText('') # self.crosshair = None # self.updateFigure() def keyPressEvent(self, e): if e.key() == QtCore.Qt.Key_Escape: self.close() def closeEvent(self, event): quit_msg = "Are you sure you want to exit the program?" reply = QtGui.QMessageBox.question(self, 'Message', quit_msg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: event.accept() else: event.ignore()