Source code for sharppy.viz.srwinds

import numpy as np
from qtpy import QtGui, QtCore, QtWidgets
import sharppy.sharptab as tab
import sharppy.sharptab.utils as utils
from sharppy.sharptab.constants import *

## routine written by Kelton Halbert
## keltonhalbert@ou.edu

__all__ = ['backgroundWinds', 'plotWinds']

[docs]class backgroundWinds(QtWidgets.QFrame): ''' Handles the plotting of the frame boarders and ticks. Draws the frame onto a QPixmap. ''' def __init__(self): super(backgroundWinds, self).__init__() self.initUI()
[docs] def initUI(self): ''' Initializes the frame attributes and QPixmap. ''' ## initialize plot window variables, ## such as width, height, padding, and ## min/max axes variables self.lpad = 0; self.rpad = 0 self.tpad = 0; self.bpad = 20 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 ## minimum/maximum height (km) and wind values. ## used in converting to pixel units self.hmax = 16.; self.hmin = 0. self.smax = 80.; self.smin = 0. self.font_ratio = 0.0512 self.label_font = QtGui.QFont('Helvetica', round(self.size().height() * self.font_ratio)) ## initialize the QPixmap self.plotBitMap = QtGui.QPixmap(self.width(), self.height()) 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): ''' This paints the frame background onto the QPixmap. ''' ## initialize a QPainter object for drawing qp = QtGui.QPainter() qp.begin(self.plotBitMap) qp.setRenderHint(qp.Antialiasing) qp.setRenderHint(qp.TextAntialiasing) ## draw the background frame self.draw_frame(qp) ## draw the ticks for the plot. ## height is in km. for h in [2,4,6,8,10,12,14]: self.draw_height(h, qp) for s in range(0,100,10): self.draw_speed(s, qp) qp.end()
[docs] def draw_frame(self, qp): ''' Draws the background frame. Parameters ---------- qp: QtGui.QPainter object ''' ## initialize a new pen with white color, thickness of 2, solid line. pen = QtGui.QPen(self.fg_color, 2, QtCore.Qt.SolidLine) qp.setPen(pen) qp.setFont(self.label_font) qp.drawText(15, 5, 45, 35, QtCore.Qt.AlignVCenter | QtCore.Qt.AlignHCenter, 'SR Wind\nv.\nHeight') ## draw the frame borders qp.drawLine(self.tlx, self.tly, self.brx, self.tly) qp.drawLine(self.brx, self.tly, self.brx, self.bry) qp.drawLine(self.brx, self.bry, self.tlx, self.bry) qp.drawLine(self.tlx, self.bry, self.tlx, self.tly) pen = QtGui.QPen(self.fg_color, 1, QtCore.Qt.DashLine) qp.setPen(pen) zero = self.speed_to_pix(15.) qp.drawLine( zero, self.bry, zero, self.tly) lower = self.hgt_to_pix(8.) upper = self.hgt_to_pix(16.) classic1 = self.speed_to_pix(40.) classic2 = self.speed_to_pix(70.) pen = QtGui.QPen(self.clsc_color, 1, QtCore.Qt.DashLine) qp.setPen(pen) qp.drawLine( classic1, lower, classic1, upper ) qp.drawLine( classic2, lower, classic2, upper ) qp.drawText(classic1-5, 2, 50, 50, QtCore.Qt.AlignVCenter | QtCore.Qt.AlignHCenter, 'Classic\nSupercell')
## draw the plot description text
[docs] def draw_height(self, h, qp): ''' Draw background height ticks in km. Parameters ---------- h: height in km qp: QtGui.QPainter object ''' ## initialize a pen with color white, thickness 1, solid line pen = QtGui.QPen(self.fg_color, 1, QtCore.Qt.SolidLine) qp.setPen(pen) qp.setFont(self.label_font) ## convert the height value to pixel coordinates y1 = self.hgt_to_pix(h) ## length of tick to be drawn offset = 5 ## draw the tick and then label the tick with the value qp.drawLine(self.lpad, y1, self.lpad+offset, y1) qp.drawLine(self.brx+self.rpad-offset, y1, self.brx+self.rpad, y1) qp.drawText(0, y1-20, 20, 40, QtCore.Qt.AlignVCenter | QtCore.Qt.AlignRight, utils.INT2STR(h))
[docs] def draw_speed(self, s, qp): ''' Draw background speed ticks. Parameters ---------- s: windpeed qp: QtGui.QPainter object ''' ## initialize a pen with white color, thickness 1, solid line pen = QtGui.QPen(self.fg_color, 1, QtCore.Qt.SolidLine) qp.setPen(pen) qp.setFont(self.label_font) ## convert wind speed values to pixel values x1 = self.speed_to_pix(s) ## length of tick to be drawn offset = 5 qp.drawLine(x1, 0, x1, 0+offset) qp.drawLine(x1, self.bry+self.tpad-offset, x1, self.bry+self.rpad)
[docs] def hgt_to_pix(self, h): ''' Function to convert a height value (km) to a Y pixel. Parameters ---------- h: height in km ''' scl1 = self.hmax - self.hmin scl2 = self.hmin + h return (self.bry - 2) - (scl2 / scl1) * (self.bry - self.tpad)
[docs] def speed_to_pix(self, s): ''' Function to convert a wind speed value to a X pixel. Parameters ---------- s: speed in kts ''' scl1 = self.smax - self.smin scl2 = self.smax - s return self.bry - (scl2 / scl1) * (self.bry - self.rpad)
[docs]class plotWinds(backgroundWinds): ''' Draws the storm relative winds vs. height. Inherits from the backgroundWinds class that contains the QPixmap with the background frame drawn on it. ''' def __init__(self): ''' Initializes the data from the Profile object used to draw the profile. Parameters ---------- prof: a Profile object ''' self.bg_color = QtGui.QColor('#000000') self.fg_color = QtGui.QColor('#ffffff') self.clsc_color = QtGui.QColor('#b1019a') self.trace_color = QtGui.QColor('#ff0000') self.m0_2_color = QtGui.QColor('#8b0000') self.m4_6_color = QtGui.QColor('#6495ed') self.m9_11_color = QtGui.QColor('#9400d3') self.use_left = False super(plotWinds, self).__init__() ## make the data accessable to the functions self.prof = None
[docs] def setProf(self, prof): self.prof = prof self.u = prof.u; self.v = prof.v ## calculate the storm relative wind from the bunkers motion function self.srwind = prof.srwind if self.use_left: self.srw_0_2km = utils.comp2vec(self.prof.left_srw_0_2km[0], self.prof.left_srw_0_2km[1])[1] self.srw_4_6km = utils.comp2vec(self.prof.left_srw_4_6km[0], self.prof.left_srw_4_6km[1])[1] self.srw_9_11km = utils.comp2vec(self.prof.left_srw_9_11km[0], self.prof.left_srw_9_11km[1])[1] ## get only the left mover u and v components self.sru = self.u - self.srwind[2] self.srv = self.v - self.srwind[3] else: self.srw_0_2km = utils.comp2vec(self.prof.right_srw_0_2km[0], self.prof.right_srw_0_2km[1])[1] self.srw_4_6km = utils.comp2vec(self.prof.right_srw_4_6km[0], self.prof.right_srw_4_6km[1])[1] self.srw_9_11km = utils.comp2vec(self.prof.right_srw_9_11km[0], self.prof.right_srw_9_11km[1])[1] ## get only the right mover u and v components self.sru = self.u - self.srwind[0] self.srv = self.v - self.srwind[1] self.clearData() self.plotBackground() self.plotData() self.update()
[docs] def setPreferences(self, update_gui=True, **prefs): self.bg_color = QtGui.QColor(prefs['bg_color']) self.fg_color = QtGui.QColor(prefs['fg_color']) self.clsc_color = QtGui.QColor(prefs['srw_clsc_color']) self.trace_color = QtGui.QColor(prefs['srw_trace_color']) self.m0_2_color = QtGui.QColor(prefs['srw_0_2_color']) self.m4_6_color = QtGui.QColor(prefs['srw_4_6_color']) self.m9_11_color = QtGui.QColor(prefs['srw_9_11_color']) if update_gui: if self.use_left: self.srw_0_2km = utils.comp2vec(self.prof.left_srw_0_2km[0], self.prof.left_srw_0_2km[1])[1] self.srw_4_6km = utils.comp2vec(self.prof.left_srw_4_6km[0], self.prof.left_srw_4_6km[1])[1] self.srw_9_11km = utils.comp2vec(self.prof.left_srw_9_11km[0], self.prof.left_srw_9_11km[1])[1] ## get only the left mover u and v components self.sru = self.u - self.srwind[2] self.srv = self.v - self.srwind[3] else: self.srw_0_2km = utils.comp2vec(self.prof.right_srw_0_2km[0], self.prof.right_srw_0_2km[1])[1] self.srw_4_6km = utils.comp2vec(self.prof.right_srw_4_6km[0], self.prof.right_srw_4_6km[1])[1] self.srw_9_11km = utils.comp2vec(self.prof.right_srw_9_11km[0], self.prof.right_srw_9_11km[1])[1] ## get only the right mover u and v components self.sru = self.u - self.srwind[0] self.srv = self.v - self.srwind[1] self.clearData() self.plotBackground() self.plotData() self.update()
[docs] def setDeviant(self, deviant): self.use_left = deviant == 'left' if self.use_left: self.srw_0_2km = utils.comp2vec(self.prof.left_srw_0_2km[0], self.prof.left_srw_0_2km[1])[1] self.srw_4_6km = utils.comp2vec(self.prof.left_srw_4_6km[0], self.prof.left_srw_4_6km[1])[1] self.srw_9_11km = utils.comp2vec(self.prof.left_srw_9_11km[0], self.prof.left_srw_9_11km[1])[1] ## get only the left mover u and v components self.sru = self.u - self.srwind[2] self.srv = self.v - self.srwind[3] else: self.srw_0_2km = utils.comp2vec(self.prof.right_srw_0_2km[0], self.prof.right_srw_0_2km[1])[1] self.srw_4_6km = utils.comp2vec(self.prof.right_srw_4_6km[0], self.prof.right_srw_4_6km[1])[1] self.srw_9_11km = utils.comp2vec(self.prof.right_srw_9_11km[0], self.prof.right_srw_9_11km[1])[1] ## get only the right mover u and v components self.sru = self.u - self.srwind[0] self.srv = self.v - self.srwind[1] self.clearData() self.plotBackground() self.plotData() self.update()
[docs] def resizeEvent(self, e): ''' Handles when the window is resized. Parameters ---------- e: an Event object ''' super(plotWinds, self).resizeEvent(e) self.plotData()
[docs] def paintEvent(self, e): ''' Handles the painting of the QPixmap onto the QWidget. Parameters ---------- e: an Event object ''' super(plotWinds, self).paintEvent(e) qp = QtGui.QPainter() qp.begin(self) qp.drawPixmap(0, 0, 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 painting the plot data onto the QPixmap. ''' if self.prof is None: return ## initialize a QPainter objext qp = QtGui.QPainter() qp.begin(self.plotBitMap) qp.setRenderHint(qp.Antialiasing) qp.setRenderHint(qp.TextAntialiasing) ## draw the wind profile self.draw_profile(qp) qp.end()
[docs] def draw_profile(self, qp): ''' Draws the storm relative wind profile. Parameters ---------- qp: QtGui.QPainter object ''' ## initialize a pen with a red color, thickness of 1, solid line if self.prof.wdir.count() == 0: return pen = QtGui.QPen(self.trace_color, 1) pen.setStyle(QtCore.Qt.SolidLine) ## if there are missing values, get the mask try: mask = np.maximum(self.sru.mask, self.srv.mask) sru = self.sru[~mask] srv = self.srv[~mask] hgt = self.prof.hght[~mask] ## otherwise the data is fine except: sru = self.sru srv = self.srv hgt = self.prof.hght if len(sru) == 0 or len(srv) == 0 or len(hgt) == 0: return max_hght_idx = len(hgt) - 1 while type(hgt[max_hght_idx]) == type(np.ma.masked): max_hght_idx -= 1 interp_hght = np.arange(self.prof.hght[self.prof.sfc], min(hgt[max_hght_idx], self.hmax * 1000.), 10) interp_sru = np.interp(interp_hght, hgt[:(max_hght_idx + 1)], sru[:(max_hght_idx + 1)]) interp_srv = np.interp(interp_hght, hgt[:(max_hght_idx + 1)], srv[:(max_hght_idx + 1)]) sr_spd = np.hypot(interp_sru, interp_srv) qp.setPen(pen) for i in range(interp_hght.shape[0] - 1): spd1 = sr_spd[i]; spd2 = sr_spd[i+1] if utils.QC(spd1) and utils.QC(spd2): hgt1 = (interp_hght[i] - interp_hght[0]) / 1000; hgt2 = (interp_hght[i+1] - interp_hght[0]) / 1000 ## convert the wind speeds to x pixels x1 = self.speed_to_pix(spd1); x2 = self.speed_to_pix(spd2) ## convert the height values to y pixels y1 = self.hgt_to_pix(hgt1); y2 = self.hgt_to_pix(hgt2) ## draw a line between the two points qp.drawLine(x1, y1, x2, y2) if utils.QC(self.srw_0_2km): # Plot the 0-2 km mean SRW pen = QtGui.QPen(self.m0_2_color, 2) pen.setStyle(QtCore.Qt.SolidLine) qp.setPen(pen) x1 = self.speed_to_pix(self.srw_0_2km); x2 = self.speed_to_pix(self.srw_0_2km) y1 = self.hgt_to_pix(0.0); y2 = self.hgt_to_pix(2.0) qp.drawLine(x1, y1, x2, y2) if utils.QC(self.srw_4_6km): # Plot the 4-6 km mean SRW pen = QtGui.QPen(self.m4_6_color, 2) pen.setStyle(QtCore.Qt.SolidLine) qp.setPen(pen) x1 = self.speed_to_pix(self.srw_4_6km); x2 = self.speed_to_pix(self.srw_4_6km) y1 = self.hgt_to_pix(4.0); y2 = self.hgt_to_pix(6.0) qp.drawLine(x1, y1, x2, y2) if utils.QC(self.srw_9_11km): # Plot the 9-11 km mean SRW pen = QtGui.QPen(self.m9_11_color, 2) pen.setStyle(QtCore.Qt.SolidLine) qp.setPen(pen) x1 = self.speed_to_pix(self.srw_9_11km); x2 = self.speed_to_pix(self.srw_9_11km) y1 = self.hgt_to_pix(9.0); y2 = self.hgt_to_pix(11.0) qp.drawLine(x1, y1, x2, y2)
if __name__ == '__main__': app_frame = QtGui.QApplication([]) tester = plotWinds() tester.show() app_frame.exec_()