Source code for sharppy.viz.ensemble

import numpy as np
import os
from qtpy import QtGui, QtCore, QtWidgets
import sharppy.sharptab.params as params
import sharppy.sharptab.winds as winds
import sharppy.sharptab.interp as interp
import sharppy.databases.inset_data as inset_data
from sharppy.sharptab.constants import *

## routine written by Kelton Halbert and Greg Blumberg
## keltonhalbert@ou.edu and wblumberg@ou.edu

__all__ = ['backgroundENS', 'plotENS']

[docs]class backgroundENS(QtWidgets.QFrame): ''' Draw the background frame and lines for the Theta-E plot frame ''' def __init__(self): super(backgroundENS, self).__init__() self.initUI()
[docs] def initUI(self): ## window configuration settings, ## sich as padding, width, height, and ## min/max plot axes self.setStyleSheet("QFrame {" " background-color: rgb(0, 0, 0);" " border-width: 1px;" " border-style: solid;" " border-color: #3399CC;}") if self.physicalDpiX() > 75: fsize = 10 else: fsize = 11 fsize = np.floor(.055 * self.size().height()) self.fsize = fsize self.plot_font = QtGui.QFont('Helvetica', fsize + 1) self.box_font = QtGui.QFont('Helvetica', fsize) self.plot_metrics = QtGui.QFontMetrics( self.plot_font ) self.box_metrics = QtGui.QFontMetrics(self.box_font) self.plot_height = self.plot_metrics.xHeight() + 5 self.box_height = self.box_metrics.xHeight() + 5 self.lpad = 40; self.rpad = 40. self.tpad = fsize * 2 + 5; self.bpad = fsize self.wid = self.size().width() - self.rpad self.hgt = self.size().height() - self.bpad self.tlx = self.rpad; self.tly = self.tpad self.brx = self.wid; self.bry = self.hgt self.ymax = 3000.; self.ymin = 0. self.xmax = 3000.; self.xmin = 0. self.plotBitMap = QtGui.QPixmap(self.width()-2, self.height()-2) self.plotBitMap.fill(self.bg_color) self.plotBackground()
[docs] def resizeEvent(self, e): ''' Handles the event the window is resized ''' self.initUI()
[docs] def plotBackground(self): ''' Handles painting the frame. ''' ## initialize a painter object and draw the frame qp = QtGui.QPainter() qp.begin(self.plotBitMap) qp.setRenderHint(qp.Antialiasing) qp.setRenderHint(qp.TextAntialiasing) self.draw_frame(qp) qp.end()
[docs] def setBlackPen(self, qp): color = QtGui.QColor('#000000') color.setAlphaF(.5) pen = QtGui.QPen(color, 0, QtCore.Qt.SolidLine) brush = QtGui.QBrush(QtCore.Qt.SolidPattern) qp.setPen(pen) qp.setBrush(brush) return qp
[docs] def draw_frame(self, qp): ''' Draw the background frame. qp: QtGui.QPainter object ''' ## set a new pen to draw with EF1_color = "#006600" EF2_color = "#FFCC33" EF3_color = "#FF0000" EF4_color = "#FF00FF" pen = QtGui.QPen(self.fg_color, 2, QtCore.Qt.SolidLine) qp.setPen(pen) qp.setFont(self.plot_font) rect1 = QtCore.QRectF(1.5, 2, self.brx, self.plot_height) qp.drawText(rect1, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter, 'Ensemble Indices') pen = QtGui.QPen(QtCore.Qt.blue, 1, QtCore.Qt.DashLine) qp.setPen(pen) ytick_fontsize = self.fsize-1 y_ticks_font = QtGui.QFont('Helvetica', ytick_fontsize) qp.setFont(y_ticks_font) efstp_inset_data = inset_data.condSTPData() #texts = efstp_inset_data['ytexts'] spacing = self.bry / 10. texts = ['0','1000','2000','3000'] y_ticks = [0,1000,2000,3000]#np.arange(self.tpad, self.bry+spacing, spacing) for i in range(len(y_ticks)): #print y_ticks[i] pen = QtGui.QPen(QtGui.QColor("#0080FF"), 1, QtCore.Qt.DashLine) qp.setPen(pen) try: qp.drawLine(self.tlx, self.y_to_ypix(int(texts[i])), self.brx, self.y_to_ypix(int(texts[i]))) except: continue color = QtGui.QColor('#000000') pen = QtGui.QPen(color, 1, QtCore.Qt.SolidLine) qp.setPen(pen) ypos = spacing*(i+1) - (spacing/4.) ypos = self.y_to_ypix(int(texts[i])) - ytick_fontsize/2 xpos = self.tlx - 50/2. rect = QtCore.QRect(xpos, ypos, 50, ytick_fontsize) pen = QtGui.QPen(self.fg_color, 1, QtCore.Qt.SolidLine) qp.setPen(pen) qp.drawText(rect, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter, texts[i]) width = self.brx / 12 spacing = self.brx / 12 # Draw the x tick marks qp.setFont(QtGui.QFont('Helvetica', self.fsize-1)) for i in range(np.asarray(texts).shape[0]): pen = QtGui.QPen(QtGui.QColor("#0080FF"), 1, QtCore.Qt.DashLine) qp.setPen(pen) try: qp.drawLine(self.x_to_xpix(int(texts[i])), self.tly, self.x_to_xpix(int(texts[i])),self.bry) except: continue color = QtGui.QColor('#000000') color.setAlpha(0) pen = QtGui.QPen(color, 1, QtCore.Qt.SolidLine) ypos = self.y_to_ypix(0) xpos = self.x_to_xpix(float(texts[i])) - 50 / 2. rect = QtCore.QRect(xpos, ypos, 50, ytick_fontsize) # Change to a white pen to draw the text below the box and whisker plot pen = QtGui.QPen(self.fg_color, 1, QtCore.Qt.SolidLine) qp.setPen(pen) qp.drawText(rect, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter, texts[i])
[docs] def y_to_ypix(self, y): scl1 = self.ymax - self.ymin scl2 = self.ymin + y #print scl1, scl2, self.bry, self.tpad, self.tly return self.bry - (scl2 / scl1) * (self.bry - self.tpad)
[docs] def x_to_xpix(self, x): scl1 = self.xmax - self.xmin scl2 = self.xmax - x return self.brx - (scl2 / scl1) * (self.brx - self.rpad)
[docs]class plotENS(backgroundENS): ''' Plot the data on the frame. Inherits the background class that plots the frame. ''' def __init__(self): self.bg_color = QtGui.QColor('#000000') self.fg_color = QtGui.QColor('#ffffff') self.use_left = False super(plotENS, self).__init__() self.prof = None self.pc_idx = 0 self.prof_collections = []
[docs] def addProfileCollection(self, prof_coll): # Add a profile collection to the scatter plot self.prof_collections.append(prof_coll)
[docs] def rmProfileCollection(self, prof_coll): # Remove a profile collection from the scatter plot self.prof_collections.remove(prof_coll)
[docs] def setActiveCollection(self, pc_idx, **kwargs): # Set the active profile collection that is being shown in SPCWindow. self.pc_idx = pc_idx prof = self.prof_collections[pc_idx].getHighlightedProf() self.prof = prof self.hght = prof.hght self.clearData() self.plotData() self.update()
[docs] def setProf(self, prof): # Set the current profile being viewed in the SPC window. self.prof = prof # Some code to show whether or not the left or right mover is being used. #if self.use_left: # self.stpc = prof.left_stp_cin #else: # self.stpc = prof.right_stp_cin self.clearData() self.plotBackground() self.plotData() self.update()
[docs] def setPreferences(self, update_gui=True, **prefs): # Set the preferences for the inset. self.bg_color = QtGui.QColor(prefs['bg_color']) self.fg_color = QtGui.QColor(prefs['fg_color']) if update_gui: if self.use_left: self.stpc = self.prof.left_stp_cin else: self.stpc = self.prof.right_stp_cin self.clearData() self.plotBackground() self.plotData() self.update()
[docs] def setDeviant(self, deviant): # Set the variable to indicate whether or not the right or left mover is being used. self.use_left = deviant == 'left' if self.use_left: self.stpc = self.prof.left_stp_cin else: self.stpc = self.prof.right_stp_cin self.clearData() self.plotBackground() self.plotData() self.update()
[docs] def resizeEvent(self, e): ''' Handles when the window is resized ''' super(plotENS, self).resizeEvent(e) self.plotData()
[docs] def paintEvent(self, e): super(plotENS, self).paintEvent(e) qp = QtGui.QPainter() qp.begin(self) qp.drawPixmap(1, 1, self.plotBitMap) qp.end()
[docs] def clearData(self): ''' Handles the clearing of the pixmap in the frame. ''' self.plotBitMap = QtGui.QPixmap(self.width(), self.height()) self.plotBitMap.fill(self.bg_color)
[docs] def plotData(self): ''' Handles drawing of data on the frame. ''' if self.prof is None: return ## this function handles painting the plot ## create a new painter obkect qp = QtGui.QPainter() qp.begin(self.plotBitMap) qp.setRenderHint(qp.Antialiasing) qp.setRenderHint(qp.TextAntialiasing) cur_dt = self.prof_collections[self.pc_idx].getCurrentDate() bc_idx = 0 for idx, prof_coll in enumerate(self.prof_collections): # Draw all unhighlighed ensemble members if prof_coll.getCurrentDate() == cur_dt: proflist = list(prof_coll.getCurrentProfs().values()) if idx == self.pc_idx: for prof in proflist: self.draw_ensemble_point(qp, prof) else: for prof in proflist: self.draw_ensemble_point(qp, prof) #%bc_idx = (bc_idx + 1) % len(self.background_colors) bc_idx = 0 for idx, prof_coll in enumerate(self.prof_collections): # Draw all highlighted members that aren't the active one. if idx != self.pc_idx and (prof_coll.getCurrentDate() == cur_dt or self.all_observed): prof = prof_coll.getHighlightedProf() self.draw_ensemble_point(qp, prof)
#bc_idx = (bc_idx + 1) % len(self.background_colors)
[docs] def draw_ensemble_point(self, qp, prof): # Plot the profile index on the scatter plot if 'pbl_h' not in dir(prof): # Make sure a PBL top has been found in the profile object ppbl_top = params.pbl_top(prof) setattr(prof, 'pbl_h', interp.to_agl(prof, interp.hght(prof, ppbl_top))) if 'sfcpcl' not in dir(prof): # Make sure a surface parcel has been lifted in the profile object setattr(prof, 'sfcpcl', params.parcelx(prof, flag=1 )) #x = self.x_to_xpix() #y = self.y_to_ypix() color = QtCore.Qt.red qp.setPen(QtGui.QPen(color)) qp.setBrush(QtGui.QBrush(color)) x = self.x_to_xpix(prof.pbl_h) - 50 / 2. y = self.y_to_ypix(prof.sfcpcl.bplus) - (self.fsize-1) / 2 qp.drawEllipse(x, y, 3, 3) return
class DrawTest(QtWidgets.QMainWindow): def __init__(self, parent=None): super(DrawTest, self).__init__(parent) # x = np.asarray([1,2,3,4]) # y = np.asarray([2,2,3,4]) length = 10 x = np.random.rand(length) + np.random.randint(0, 10, length) y = np.random.rand(length) + np.random.randint(0, 10, length) x = np.asarray([0, 5, 10, 0], dtype=float) y = np.asarray([0, 5, 10, 20], dtype=float) self.frame = plotENS() self.frame.addProfileCollection(prof_coll) self.frame.setActiveCollection(0) self.setCentralWidget(self.frame) if __name__ == "__main__": import sys import sharppy.io.buf_decoder as buf_decoder path = 'ftp://ftp.meteo.psu.edu/pub/bufkit/SREF/21/sref_oun.buf' dec = buf_decoder.BufDecoder(path) prof_coll = dec._parse() app = QtGui.QApplication(sys.argv) mySW = DrawTest() mySW.show() sys.exit(app.exec_())