import numpy as np
from qtpy import QtGui, QtCore, QtWidgets
import sharppy.sharptab as tab
from sharppy.sharptab.constants import *
## routine written by Kelton Halbert
## keltonhalbert@ou.edu
__all__ = ['backgroundSpeed', 'plotSpeed']
[docs]class backgroundSpeed(QtWidgets.QFrame):
'''
Handles drawing the plot background.
'''
def __init__(self):
super(backgroundSpeed, self).__init__()
self.initUI()
[docs] def initUI(self):
## initialize frame variables, such as length, width, and
## expected max/min values of data
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
## set the max and min pressure expected, and convert it to log space
self.pmax = 1050.; self.pmin = 100.
self.log_pmax = np.log(self.pmax); self.log_pmin = np.log(self.pmin)
## set the max/min wind speed expected
if self.wind_units == "knots":
self.smax = 140.; self.smin = 0. # knots
self.delta = 20.
elif self.wind_units == 'm/s':
self.smax = 80.; self.smin = 0. # m/s
self.delta = 10.
self.font_ratio = 0.12#0512
fsize = round(self.size().width() * self.font_ratio) + 2
self.label_font = QtGui.QFont('Helvetica', fsize)
self.plotBitMap = QtGui.QPixmap(self.width(), self.height())
self.plotBitMap.fill(QtGui.QColor(self.bg_color))
self.plotBackground()
[docs] def resizeEvent(self, e):
'''
Handles when the window is resized.
'''
self.initUI()
[docs] def plotBackground(self):
'''
Handles painting the frame.
'''
## initialize a QPainter object
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 vertical ticks for wind speed
for s in range(int(self.smin),int(self.smax),int(self.delta)):
if s % (int(self.delta)*2) == 0 and s != 0:
label=True
else:
label=False
self.draw_speed(s, qp, int(self.delta), label)
## Draw the title and units
pen = QtGui.QPen(QtGui.QColor(self.fg_color), 1, QtCore.Qt.DashLine)
qp.setPen(pen)
fsize = round(self.size().width() * self.font_ratio)
self.title_font = QtGui.QFont('Helvetica', fsize+1)
qp.setFont(self.title_font)
qp.drawText(self.tlx+2, self.tly+2, self.brx-self.tlx, 30,
QtCore.Qt.AlignTop | QtCore.Qt.AlignLeft | QtCore.Qt.TextWordWrap, "Wind Speed\n(" + self.wind_units + ")")
qp.end()
[docs] def draw_frame(self, qp):
'''
Draws the frame boarders.
'''
## initialize a pen with white color, thickness 2, solid line
pen = QtGui.QPen(QtGui.QColor(self.fg_color), 2, QtCore.Qt.SolidLine)
qp.setPen(pen)
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)
[docs] def draw_speed(self, s, qp, delta=0, drawlabel=True):
'''
Draw background speed ticks.
--------
s: wind speed
qp: QtGui.QPainter object
'''
## initialize a pen with an orange/brown color, thickness 1, dashed line
pen = QtGui.QPen(self.isotach_color, 1, QtCore.Qt.DashLine)
qp.setPen(pen)
qp.setFont(self.label_font)
## convert the speed value to pixel coordinates
x1 = self.speed_to_pix(s)
labelx1 = self.speed_to_pix(s - delta) # e.g. 20 - 20 = 0, 0 to 40
label_width = self.speed_to_pix(s+delta) - self.speed_to_pix(s-delta)
## draw a dashed line of constant wind speed value
qp.drawLine(x1, self.bry, x1, self.tly)
if drawlabel is True and s > 0:
pen = QtGui.QPen(QtGui.QColor(self.fg_color), 1, QtCore.Qt.DashLine)
qp.setPen(pen)
qp.drawText(labelx1, self.bry+5, label_width, 10,
QtCore.Qt.AlignTop | QtCore.Qt.AlignCenter, str(int(s)))
[docs] def pres_to_pix(self, p):
'''
Function to convert a pressure value to a Y pixel.
'''
scl1 = self.log_pmax - self.log_pmin
scl2 = self.log_pmax - np.log(p)
return self.bry - (scl2 / scl1) * (self.bry - self.tpad)
[docs] def speed_to_pix(self, s):
'''
Function to convert a wind speed value to a X pixel.
'''
scl1 = self.smax - self.smin
scl2 = self.smax - s
return self.brx - (scl2 / scl1) * (self.brx - self.rpad)
[docs]class plotSpeed(backgroundSpeed):
'''
Handles plotting the data in the frame.
'''
def __init__(self):
self.bg_color = '#000000'
self.fg_color = '#ffffff'
self.wind_units = 'knots'
self.isotach_color = QtGui.QColor("#9D5736")
super(plotSpeed, self).__init__()
## initialize values to be accessable to functions
self.prof = None
## give different colors for different height values.
## these are consistent with the hodograph colors.
self.low_level_color = QtGui.QColor("#FF0000")
self.mid_level_color = QtGui.QColor("#00FF00")
self.upper_level_color = QtGui.QColor("#FFFF00")
self.trop_level_color = QtGui.QColor("#00FFFF")
[docs] def setProf(self, prof):
self.prof = prof
self.u = prof.u; self.v = prof.v
self.hght = prof.hght; self.pres = prof.pres
self.clearData()
self.plotBackground()
self.plotData()
self.update()
[docs] def setPreferences(self, update_gui=True, **prefs):
self.bg_color = prefs['bg_color']
self.fg_color = prefs['fg_color']
self.wind_units = prefs['wind_units']
if self.wind_units == "knots":
self.smax = 140.; self.smin = 0. # knots
self.delta = 20.
elif self.wind_units == 'm/s':
self.smax = 80.; self.smin = 0. # m/s
self.delta = 10.
self.low_level_color = QtGui.QColor(prefs['0_3_color'])
self.mid_level_color = QtGui.QColor(prefs['3_6_color'])
self.upper_level_color = QtGui.QColor(prefs['6_9_color'])
self.trop_level_color = QtGui.QColor(prefs['9_12_color'])
self.isotach_color = QtGui.QColor(prefs['spd_itach_color'])
if update_gui:
self.clearData()
self.plotBackground()
self.plotData()
self.update()
[docs] def resizeEvent(self, e):
'''
Handles when the window is resized.
'''
super(plotSpeed, self).resizeEvent(e)
self.plotData()
[docs] def paintEvent(self, e):
super(plotSpeed, 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(QtGui.QColor(self.bg_color))
[docs] def plotData(self):
'''
Handles drawing the data on the frame.
'''
## initialize a QPainter object
if self.prof is None:
return
qp = QtGui.QPainter()
qp.begin(self.plotBitMap)
qp.setRenderHint(qp.Antialiasing)
qp.setRenderHint(qp.TextAntialiasing)
## draw the wind speed profile
self.draw_profile(qp)
qp.end()
[docs] def draw_profile(self, qp):
'''
Draw the Speed vs. Height profile.
--------
qp: QtGui.QPainter object
'''
## initialize a pen starting with the low level color,
## thickness of 2, solid line.
pen = QtGui.QPen(self.low_level_color, 1)
pen.setStyle(QtCore.Qt.SolidLine)
## if there are missing values, get the data mask
try:
mask = np.maximum(np.maximum(self.u.mask, self.v.mask), self.hght.mask)
hgt = tab.interp.to_agl(self.prof, self.hght[~mask])
pres = self.pres[~mask]
u = self.u[~mask]
v = self.v[~mask]
## calculate teh wind speed
spd = np.sqrt( u**2 + v**2 )
## otherwise, the data is fine.
except:
hgt = tab.interp.to_agl(self.prof, self.hght)
pres = self.pres
u = self.u; v = self.v
## calculate the windspeed
spd = np.sqrt( u**2 + v**2 )
if self.wind_units == 'm/s':
spd = tab.utils.KTS2MS(spd)
## loop through the profile
for i in range( pres.shape[0] ):
## get the important values from the profile
hgt1 = hgt[i]
p1 = pres[i]
spd1 = spd[i]
## convert the speed to x pixel coordinates
## and convert the pressure in log space to a
## y pixel coordinate
x1 = self.speed_to_pix(spd1)
y1 = self.pres_to_pix(p1)
## now color code the different heights
if hgt1 < 3000:
pen = QtGui.QPen(self.low_level_color, 2)
elif hgt1 < 6000:
pen = QtGui.QPen(self.mid_level_color, 2)
elif hgt1 < 9000:
pen = QtGui.QPen(self.upper_level_color, 2)
else:
pen = QtGui.QPen(self.trop_level_color, 2)
## Draw a horizontal line with the length of the wind speed
qp.setPen(pen)
qp.drawLine(0, y1, x1, y1)
if __name__ == '__main__':
app_frame = QtGui.QApplication([])
tester = plotSpeed()
tester.show()
app_frame.exec_()