import logging
import numpy as np
from qtpy import QtGui, QtCore, QtWidgets
import sharppy.sharptab as tab
from sharppy.viz.barbs import drawBarb
from sharppy.sharptab.constants import *
import platform
## routine written by Kelton Halbert
## keltonhalbert@ou.edu
__all__ = ['backgroundKinematics', 'plotKinematics']
[docs]class backgroundKinematics(QtWidgets.QFrame):
'''
Handles drawing the background frame.
'''
def __init__(self, **kwargs):
super(backgroundKinematics, self).__init__()
self.wind_units = kwargs.get('wind_units', 'knots')
self.initUI()
[docs] def initUI(self):
## initialize fram variables such as size,
## padding, etc.
self.setStyleSheet("QFrame {"
" background-color: rgb(0, 0, 0);"
" border-width: 1px;"
" border-style: solid;"
" border-color: #3399CC;}")
self.lpad = 5; self.rpad = 5
self.tpad = 5; self.bpad = 5
self.wid = self.size().width()
self.hgt = self.size().height()
self.tlx = self.rpad; self.tly = self.tpad
self.brx = self.wid; self.bry = self.hgt
fsize = np.floor(.06 * self.hgt)
self.tpad = np.floor(.03 * self.hgt)
self.label_font = QtGui.QFont('Helvetica')
self.label_font.setPixelSize(fsize)
self.label_metrics = QtGui.QFontMetrics( self.label_font )
self.label_height = self.label_metrics.xHeight() + self.tpad
self.ylast = self.label_height
self.barby = 0
self.plotBitMap = QtGui.QPixmap(self.width()-2, self.height()-2)
self.plotBitMap.fill(self.bg_color)
self.plotBackground()
[docs] def draw_frame(self, qp):
'''
Draws the background frame and the text headers for indices.
'''
## initialize a white pen with thickness 1 and a solid line
pen = QtGui.QPen(self.fg_color, 1, QtCore.Qt.SolidLine)
qp.setPen(pen)
qp.setFont(self.label_font)
## make the initial x value relative to the width of the frame
x1 = self.brx / 10
y1 = self.label_height + self.tpad
## draw the header
rect1 = QtCore.QRect(x1*2.5, 3, x1, self.label_height)
rect2 = QtCore.QRect(x1*5, 3, x1, self.label_height)
rect3 = QtCore.QRect(x1*7, 3, x1, self.label_height)
rect4 = QtCore.QRect(x1*9-self.rpad, 3, x1, self.label_height)
if self.wind_units == 'm/s':
disp_unit = 'm/s'
else:
disp_unit = 'kt'
qp.drawText(rect1, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter, 'SRH (m2/s2)')
qp.drawText(rect2, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter, "Shear (%s)" % disp_unit)
qp.drawText(rect3, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter, 'MnWind')
qp.drawText(rect4, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter, 'SRW')
## left column
## first block
texts = ['SFC-1km', 'SFC-3km', 'Eff Inflow Layer',]
for text in texts:
rect = QtCore.QRect(self.lpad, y1, x1, self.label_height)
qp.drawText(rect, QtCore.Qt.TextDontClip | QtCore.Qt.AlignLeft, text)
vspace = self.label_height
if platform.system() == "Windows":
vspace += self.label_metrics.descent()
y1 += vspace
self.ylast = y1
## second block
texts = ['SFC-6km', 'SFC-8km','LCL-EL (Cloud Layer)', 'Eff Shear (EBWD)']
y1 = self.ylast + self.tpad
for text in texts:
rect = QtCore.QRect(self.lpad, y1, x1, self.label_height)
qp.drawText(rect, QtCore.Qt.TextDontClip | QtCore.Qt.AlignLeft, text)
vspace = self.label_height
if platform.system() == "Windows":
vspace += self.label_metrics.descent()
y1 += vspace
self.ylast = y1
## third block
texts = ['BRN Shear = ', '4-6km SR Wind = ']
y1 = self.ylast + self.tpad
for text in texts:
rect = QtCore.QRect(self.lpad, y1, x1, self.label_height)
qp.drawText(rect, QtCore.Qt.TextDontClip | QtCore.Qt.AlignLeft, text)
vspace = self.label_height
if platform.system() == "Windows":
vspace += self.label_metrics.descent()
y1 += vspace
self.ylast = y1
## fourth block
texts = ['...Storm Motion Vectors...', 'Bunkers Right = ', 'Bunkers Left = ', 'Corfidi Downshear = ', 'Corfidi Upshear = ']
y1 = self.ylast + self.tpad
self.barby = y1 + self.tpad
for text in texts:
rect = QtCore.QRect(self.lpad, y1, x1, self.label_height)
qp.drawText(rect, QtCore.Qt.TextDontClip | QtCore.Qt.AlignLeft, text)
vspace = self.label_height
if platform.system() == "Windows":
vspace += self.label_metrics.descent()
y1 += vspace
self.ylast = vspace
## draw lines seperating the indices
qp.drawLine( 0, self.ylast+3, self.brx, self.ylast+3 )
[docs] def resizeEvent(self, e):
'''
Handles when the window gets resized.
'''
self.initUI()
[docs] def plotBackground(self):
'''
Handles drawing the text background.
'''
## initialize a QPainter objext
qp = QtGui.QPainter()
qp.begin(self.plotBitMap)
## draw the frame
self.draw_frame(qp)
qp.end()
[docs]class plotKinematics(backgroundKinematics):
'''
Handles plotting the indices in the frame.
'''
def __init__(self, **kwargs):
## get the surfce based, most unstable, and mixed layer
## parcels to use for indices, as well as the sounding
## profile itself.
self.bg_color = QtGui.QColor('#000000')
self.fg_color = QtGui.QColor('#ffffff')
self.use_left = False
super(plotKinematics, self).__init__(**kwargs)
self.prof = None
[docs] def setProf(self, prof):
self.ylast = self.label_height
self.prof = prof
if self.use_left:
self.srh1km = prof.left_srh1km
self.srh3km = prof.left_srh3km
self.esrh = prof.left_esrh
self.srw_1km = prof.left_srw_1km
self.srw_3km = prof.left_srw_3km
self.srw_6km = prof.left_srw_6km
self.srw_8km = prof.left_srw_8km
self.srw_lcl_el = prof.left_srw_lcl_el
self.srw_4_5km = prof.left_srw_4_5km
srw_eff = prof.left_srw_eff
srw_ebw = prof.left_srw_ebw
else:
self.srh1km = prof.right_srh1km
self.srh3km = prof.right_srh3km
self.esrh = prof.right_esrh
self.srw_1km = prof.right_srw_1km
self.srw_3km = prof.right_srw_3km
self.srw_6km = prof.right_srw_6km
self.srw_8km = prof.right_srw_8km
self.srw_lcl_el = prof.right_srw_lcl_el
self.srw_4_5km = prof.right_srw_4_5km
srw_eff = prof.right_srw_eff
srw_ebw = prof.right_srw_ebw
self.mean_1km = prof.mean_1km
self.mean_3km = prof.mean_3km
self.mean_6km = prof.mean_6km
self.mean_8km = prof.mean_8km
self.mean_lcl_el = prof.mean_lcl_el
mean_eff = prof.mean_eff
mean_ebw = prof.mean_ebw
self.sfc_1km_shear = prof.sfc_1km_shear
self.sfc_3km_shear = prof.sfc_3km_shear
self.sfc_6km_shear = prof.sfc_6km_shear
self.sfc_8km_shear = prof.sfc_8km_shear
self.lcl_el_shear = prof.lcl_el_shear
self.eff_shear = prof.eff_shear
self.ebwd = prof.ebwd
if prof.etop is np.ma.masked or prof.ebottom is np.ma.masked:
self.mean_eff = [np.ma.masked, np.ma.masked]
self.mean_ebw = [np.ma.masked, np.ma.masked]
self.srw_eff = [np.ma.masked, np.ma.masked]
self.srw_ebw = [np.ma.masked, np.ma.masked]
else:
self.mean_eff = tab.utils.comp2vec(mean_eff[0], mean_eff[1])
self.mean_ebw = tab.utils.comp2vec(mean_ebw[0], mean_ebw[1])
self.srw_eff = tab.utils.comp2vec(srw_eff[0], srw_eff[1])
self.srw_ebw = tab.utils.comp2vec(srw_ebw[0], srw_ebw[1])
self.brn_shear = prof.mupcl.brnshear
self.bunkers_right_vec = tab.utils.comp2vec(prof.bunkers[0], prof.bunkers[1])
self.bunkers_left_vec = tab.utils.comp2vec(prof.bunkers[2], prof.bunkers[3])
self.upshear = tab.utils.comp2vec(prof.upshear_downshear[0],prof.upshear_downshear[1])
self.downshear = tab.utils.comp2vec(prof.upshear_downshear[2],prof.upshear_downshear[3])
self.clearData()
self.plotBackground()
self.plotData()
self.update()
[docs] def setPreferences(self, update_gui=True, **prefs):
self.wind_units = prefs['wind_units']
self.bg_color = QtGui.QColor(prefs['bg_color'])
self.fg_color = QtGui.QColor(prefs['fg_color'])
if update_gui:
if self.use_left:
self.srh1km = self.prof.left_srh1km
self.srh3km = self.prof.left_srh3km
self.esrh = self.prof.left_esrh
self.srw_1km = self.prof.left_srw_1km
self.srw_3km = self.prof.left_srw_3km
self.srw_6km = self.prof.left_srw_6km
self.srw_8km = self.prof.left_srw_8km
self.srw_lcl_el = self.prof.left_srw_lcl_el
self.srw_4_5km = self.prof.left_srw_4_5km
srw_eff = self.prof.left_srw_eff
srw_ebw = self.prof.left_srw_ebw
else:
self.srh1km = self.prof.right_srh1km
self.srh3km = self.prof.right_srh3km
self.esrh = self.prof.right_esrh
self.srw_1km = self.prof.right_srw_1km
self.srw_3km = self.prof.right_srw_3km
self.srw_6km = self.prof.right_srw_6km
self.srw_8km = self.prof.right_srw_8km
self.srw_lcl_el = self.prof.right_srw_lcl_el
self.srw_4_5km = self.prof.right_srw_4_5km
srw_eff = self.prof.right_srw_eff
srw_ebw = self.prof.right_srw_ebw
if self.prof.etop is np.ma.masked or self.prof.ebottom is np.ma.masked:
self.srw_eff = [np.ma.masked, np.ma.masked]
self.srw_ebw = [np.ma.masked, np.ma.masked]
else:
self.srw_eff = tab.utils.comp2vec(srw_eff[0], srw_eff[1])
self.srw_ebw = tab.utils.comp2vec(srw_ebw[0], srw_ebw[1])
self.clearData()
self.plotBackground()
self.plotData()
self.update()
[docs] def setDeviant(self, deviant):
self.use_left = deviant == 'left'
if self.use_left:
self.srh1km = self.prof.left_srh1km
self.srh3km = self.prof.left_srh3km
self.esrh = self.prof.left_esrh
self.srw_1km = self.prof.left_srw_1km
self.srw_3km = self.prof.left_srw_3km
self.srw_6km = self.prof.left_srw_6km
self.srw_8km = self.prof.left_srw_8km
self.srw_lcl_el = self.prof.left_srw_lcl_el
self.srw_4_5km = self.prof.left_srw_4_5km
srw_eff = self.prof.left_srw_eff
srw_ebw = self.prof.left_srw_ebw
else:
self.srh1km = self.prof.right_srh1km
self.srh3km = self.prof.right_srh3km
self.esrh = self.prof.right_esrh
self.srw_1km = self.prof.right_srw_1km
self.srw_3km = self.prof.right_srw_3km
self.srw_6km = self.prof.right_srw_6km
self.srw_8km = self.prof.right_srw_8km
self.srw_lcl_el = self.prof.right_srw_lcl_el
self.srw_4_5km = self.prof.right_srw_4_5km
srw_eff = self.prof.right_srw_eff
srw_ebw = self.prof.right_srw_ebw
if self.prof.etop is np.ma.masked or self.prof.ebottom is np.ma.masked:
self.srw_eff = [np.ma.masked, np.ma.masked]
self.srw_ebw = [np.ma.masked, np.ma.masked]
else:
self.srw_eff = tab.utils.comp2vec(srw_eff[0], srw_eff[1])
self.srw_ebw = tab.utils.comp2vec(srw_ebw[0], srw_ebw[1])
self.clearData()
self.plotBackground()
self.plotData()
self.update()
[docs] def resizeEvent(self, e):
'''
Handles when the window is resized.
'''
super(plotKinematics, self).resizeEvent(e)
self.plotData()
[docs] def paintEvent(self, e):
super(plotKinematics, 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 the drawing of the text on the frame.
'''
if self.prof is None:
return
x1 = self.brx / 10
y1 = self.bry / 19
origin_x = x1*8.5
origin_y = y1*15
## initialize a QPainter object
qp = QtGui.QPainter()
qp.begin(self.plotBitMap)
qp.setRenderHint(qp.Antialiasing)
qp.setRenderHint(qp.TextAntialiasing)
## draw the indices
self.drawKinematics(qp)
self.drawBarbs(qp)
qp.end()
[docs] def drawBarbs(self, qp):
x1 = self.brx / 10
y1 = self.bry / 19
origin_x = x1*8.
pen = QtGui.QPen(QtGui.QColor('#0A74C6'), 1, QtCore.Qt.SolidLine)
qp.setPen(pen)
qp.setFont(self.label_font)
rect0 = QtCore.QRect(x1*7, self.ylast + self.tpad, x1*2, self.label_height)
qp.drawText(rect0, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter, '1km & 6km AGL\nWind Barbs' )
if self.wind_units == "m/s":
conv = tab.utils.KTS2MS
else:
conv = lambda s: s
try:
drawBarb(qp, origin_x, self.barby, self.prof.wind1km[0], conv(self.prof.wind1km[1]), color='#AA0000', shemis=(self.prof.latitude < 0))
drawBarb(qp, origin_x, self.barby, self.prof.wind6km[0], conv(self.prof.wind6km[1]), color='#0A74C6', shemis=(self.prof.latitude < 0))
except:
logging.debug("Couldn't draw the 1 or 6 km wind barbs on kinematics.py")
[docs] def drawKinematics(self, qp):
'''
This handles the severe indices, such as STP, sig hail, etc.
---------
qp: QtGui.QPainter object
'''
## initialize a pen to draw with.
pen = QtGui.QPen(self.fg_color, 1, QtCore.Qt.SolidLine)
qp.setPen(pen)
qp.setFont(self.label_font)
x1 = self.brx / 10
y1 = self.ylast + self.tpad
if self.wind_units == 'm/s':
disp_unit = ' m/s'
conv = tab.utils.KTS2MS
else:
disp_unit = ' kt'
conv = lambda s: s
## format the text
srh1km = tab.utils.INT2STR(self.srh1km[0])
srh3km = tab.utils.INT2STR(self.srh3km[0])
sfc1km = tab.utils.INT2STR(conv(tab.utils.mag(self.sfc_1km_shear[0], self.sfc_1km_shear[1])))
sfc3km = tab.utils.INT2STR(conv(tab.utils.mag(self.sfc_3km_shear[0], self.sfc_3km_shear[1])))
sfc6km = tab.utils.INT2STR(conv(tab.utils.mag(self.sfc_6km_shear[0], self.sfc_6km_shear[1])))
sfc8km = tab.utils.INT2STR(conv(tab.utils.mag(self.sfc_8km_shear[0], self.sfc_8km_shear[1])))
lcl_el = tab.utils.INT2STR(conv(tab.utils.mag(self.lcl_el_shear[0], self.lcl_el_shear[1])))
mean_1km = tab.utils.INT2STR(np.float64(self.mean_1km[0])) + '/' + tab.utils.INT2STR(conv(self.mean_1km[1]))
mean_3km = tab.utils.INT2STR(np.float64(self.mean_3km[0])) + '/' + tab.utils.INT2STR(conv(self.mean_3km[1]))
mean_6km = tab.utils.INT2STR(np.float64(self.mean_6km[0])) + '/' + tab.utils.INT2STR(conv(self.mean_6km[1]))
mean_8km = tab.utils.INT2STR(np.float64(self.mean_8km[0])) + '/' + tab.utils.INT2STR(conv(self.mean_8km[1]))
mean_lcl_el = tab.utils.INT2STR(np.float64(self.mean_lcl_el[0])) + '/' + tab.utils.INT2STR(conv(self.mean_lcl_el[1]))
srw_1km = tab.utils.INT2STR(np.float64(self.srw_1km[0])) + '/' + tab.utils.INT2STR(conv(self.srw_1km[1]))
srw_3km = tab.utils.INT2STR(np.float64(self.srw_3km[0])) + '/' + tab.utils.INT2STR(conv(self.srw_3km[1]))
srw_6km = tab.utils.INT2STR(np.float64(self.srw_6km[0])) + '/' + tab.utils.INT2STR(conv(self.srw_6km[1]))
srw_8km = tab.utils.INT2STR(np.float64(self.srw_8km[0])) + '/' + tab.utils.INT2STR(conv(self.srw_8km[1]))
srw_lcl_el = tab.utils.INT2STR(np.float64(self.srw_lcl_el[0])) + '/' + tab.utils.INT2STR(conv(self.srw_lcl_el[1]))
srw_4_5km = tab.utils.INT2STR(np.float64(self.srw_4_5km[0])) + '/' + tab.utils.INT2STR(conv(self.srw_4_5km[1])) + disp_unit
esrh = tab.utils.INT2STR(self.esrh[0])
eff_lr = tab.utils.INT2STR(conv(tab.utils.mag(self.eff_shear[0], self.eff_shear[1])))
efbwd = tab.utils.INT2STR(conv(tab.utils.mag(self.ebwd[0], self.ebwd[1])))
mean_eff = tab.utils.INT2STR(np.float64(self.mean_eff[0])) + '/' + tab.utils.INT2STR(conv(self.mean_eff[1]))
mean_ebw = tab.utils.INT2STR(np.float64(self.mean_ebw[0])) + '/' + tab.utils.INT2STR(conv(self.mean_ebw[1]))
srw_eff = tab.utils.INT2STR(np.float64(self.srw_eff[0])) + '/' + tab.utils.INT2STR(conv(self.srw_eff[1]))
srw_ebw = tab.utils.INT2STR(np.float64(self.srw_ebw[0])) + '/' + tab.utils.INT2STR(conv(self.srw_ebw[1]))
brn_shear = tab.utils.INT2STR(self.brn_shear) + ' m2/s2'
bunkers_left = tab.utils.INT2STR(np.float64(self.bunkers_left_vec[0])) + '/' + tab.utils.INT2STR(conv(self.bunkers_left_vec[1])) + disp_unit
bunkers_right = tab.utils.INT2STR(np.float64(self.bunkers_right_vec[0])) + '/' + tab.utils.INT2STR(conv(self.bunkers_right_vec[1])) + disp_unit
upshear = tab.utils.INT2STR(np.float64(self.upshear[0])) + '/' + tab.utils.INT2STR(conv(self.upshear[1])) + disp_unit
downshear = tab.utils.INT2STR(np.float64(self.downshear[0])) + '/' + tab.utils.INT2STR(conv(self.downshear[1])) + disp_unit
## sfc-1km
texts = [srh1km, sfc1km, mean_1km, srw_1km]
count = 3
for text in texts:
rect = QtCore.QRect(x1*count, y1, x1, self.label_height)
qp.drawText(rect, QtCore.Qt.TextDontClip | QtCore.Qt.AlignRight, text)
count += 2
vspace = self.label_height
if platform.system() == "Windows":
vspace += self.label_metrics.descent()
y1 += vspace
self.ylast = y1
## sfc-3km
texts = [srh3km, sfc3km, mean_3km, srw_3km]
count = 3
for text in texts:
rect = QtCore.QRect(x1*count, y1, x1, self.label_height)
qp.drawText(rect, QtCore.Qt.TextDontClip | QtCore.Qt.AlignRight, text)
count += 2
vspace = self.label_height
if platform.system() == "Windows":
vspace += self.label_metrics.descent()
y1 += vspace
self.ylast = y1
## Effective Inflow Layer
texts = [esrh, eff_lr, mean_eff, srw_eff]
count = 3
for text in texts:
rect = QtCore.QRect(x1*count, y1, x1, self.label_height)
qp.drawText(rect, QtCore.Qt.TextDontClip | QtCore.Qt.AlignRight, text)
count += 2
vspace = self.label_height + self.tpad
if platform.system() == "Windows":
vspace += self.label_metrics.descent()
y1 += vspace
self.ylast = y1
## sfc-6km
texts = [sfc6km, mean_6km, srw_6km]
count = 5
for text in texts:
rect = QtCore.QRect(x1*count, y1, x1, self.label_height)
qp.drawText(rect, QtCore.Qt.TextDontClip | QtCore.Qt.AlignRight, text)
count += 2
vspace = self.label_height
if platform.system() == "Windows":
vspace += self.label_metrics.descent()
y1 += vspace
self.ylast = y1
## sfc-8km
texts = [sfc8km, mean_8km, srw_8km]
count = 5
for text in texts:
rect = QtCore.QRect(x1*count, y1, x1, self.label_height)
qp.drawText(rect, QtCore.Qt.TextDontClip | QtCore.Qt.AlignRight, text)
count += 2
vspace = self.label_height
if platform.system() == "Windows":
vspace += self.label_metrics.descent()
y1 += vspace
self.ylast = y1
## LCL-EL
texts = [lcl_el, mean_lcl_el, srw_lcl_el]
count = 5
for text in texts:
rect = QtCore.QRect(x1*count, y1, x1, self.label_height)
qp.drawText(rect, QtCore.Qt.TextDontClip | QtCore.Qt.AlignRight, text)
count += 2
vspace = self.label_height
if platform.system() == "Windows":
vspace += self.label_metrics.descent()
y1 += vspace
self.ylast = y1
## Effective Shear
texts = [efbwd, mean_ebw, srw_ebw]
count = 5
for text in texts:
rect = QtCore.QRect(x1*count, y1, x1, self.label_height)
qp.drawText(rect, QtCore.Qt.TextDontClip | QtCore.Qt.AlignRight, text)
count += 2
vspace = self.label_height + self.tpad
if platform.system() == "Windows":
vspace += self.label_metrics.descent()
y1 += vspace
self.ylast = y1
## BRN Shear and 4-6km SR Wind
texts = [brn_shear, srw_4_5km]
for text in texts:
rect = QtCore.QRect(x1*5, y1, x1, self.label_height)
qp.drawText(rect, QtCore.Qt.TextDontClip | QtCore.Qt.AlignRight, text)
vspace = self.label_height
if platform.system() == "Windows":
vspace += self.label_metrics.descent()
y1 += vspace
self.ylast = y1
y1 += self.label_height + self.tpad # Not entirely sure why this doesn't
# need the extra pixels on Windows.
## bunkers motion
texts = [bunkers_right, bunkers_left]
colors =[QtGui.QColor('#0099CC'), QtGui.QColor('#FF6666')]
for text, color in zip(texts, colors):
rect = QtCore.QRect(x1*5, y1, x1, self.label_height)
pen = QtGui.QPen(color, 1, QtCore.Qt.SolidLine)
qp.setPen(pen)
qp.drawText(rect, QtCore.Qt.TextDontClip | QtCore.Qt.AlignRight, text)
vspace = self.label_height
if platform.system() == "Windows":
vspace += self.label_metrics.descent()
y1 += vspace
self.ylast = y1
pen = QtGui.QPen(self.fg_color, 1, QtCore.Qt.SolidLine)
qp.setPen(pen)
## upshear and downshear vectors
texts = [downshear, upshear]
for text in texts:
rect = QtCore.QRect(x1*5, y1, x1, self.label_height)
qp.drawText(rect, QtCore.Qt.TextDontClip | QtCore.Qt.AlignRight, text)
if platform.system() == "Windows":
vspace += self.label_metrics.descent()
y1 += vspace
if __name__ == '__main__':
app_frame = QtGui.QApplication([])
tester = plotKinematics()
tester.show()
app_frame.exec_()