Source code for sharppy.viz.skew

import numpy as np
import sharppy.sharptab as tab
from sharppy.sharptab.constants import *
from sharppy.sharptab.profile import Profile, create_profile
from sharppy.viz.draggable import Draggable
from sharppy.viz.barbs import drawBarb
from qtpy import QtGui, QtCore, QtWidgets
from qtpy.QtGui import *
from qtpy.QtCore import *
from qtpy.QtWidgets import *
from qtpy.QtOpenGL import *
from sutils.utils import total_seconds
import logging

from datetime import datetime, timedelta

__all__ = ['backgroundSkewT', 'plotSkewT']

[docs]class backgroundSkewT(QWidget): def __init__(self, plot_omega=False): super(backgroundSkewT, self).__init__() self.plot_omega = plot_omega self.initUI()
[docs] def initUI(self): ''' Initialize the User Interface. ''' logging.debug("Initalizing the backgroundSkewT.") self.lpad = 30; self.rpad = 65 self.tpad = 20; self.bpad = 20 self.tlx = self.rpad; self.tly = self.tpad self.wid = self.size().width() - self.rpad self.hgt = self.size().height() - self.bpad self.brx = self.wid ; self.bry = self.hgt self.pmax = 1050.; self.pmin = 100. self.barbx = self.brx + self.rpad / 2 self.log_pmax = np.log(self.pmax); self.log_pmin = np.log(self.pmin) self.bltmpc = -50; self.brtmpc = 50; self.dt = 10 self.xskew = 100 / 3. self.xrange = self.brtmpc - self.bltmpc self.yrange = np.tan(np.deg2rad(self.xskew)) * self.xrange self.clip = QRect(QPoint(self.lpad, self.tly), QPoint(self.brx + self.rpad, self.bry)) self.originx = 0. # self.size().width() / 2 self.originy = 0. # self.size().height() / 2 self.scale = 1. #self.bg_color=QColor('#000000') if self.physicalDpiX() > 75: fsize = 6 fsizet = 10 else: fsize = 7 fsizet = 14 self.title_font = QtGui.QFont('Helvetica', fsizet + (self.hgt * 0.006)) self.title_metrics = QtGui.QFontMetrics( self.title_font ) #self.title_font.setBold(True) self.title_height = self.title_metrics.xHeight() + 5 + (self.hgt * 0.003) self.label_font = QtGui.QFont('Helvetica', fsize + 2 + (self.hgt * 0.0045)) self.environment_trace_font = QtGui.QFont('Helvetica', 11 + (self.hgt * 0.0045)) self.in_plot_font = QtGui.QFont('Helvetica', fsize + (self.hgt * 0.0045)) self.esrh_font = QtGui.QFont('Helvetica', fsize + 2 + (self.hgt * 0.0045)) self.hght_font = QtGui.QFont('Helvetica', 9 + (self.hgt * 0.0045)) self.esrh_metrics = QtGui.QFontMetrics( self.esrh_font ) self.esrh_height = self.esrh_metrics.xHeight() + 9 + (self.hgt * 0.0045) self.plotBitMap = QtGui.QPixmap(self.width(), self.height()) self.saveBitMap = None self.plotBitMap.fill(self.bg_color) self.plotBackground()
[docs] def plotBackground(self): logging.debug("Calling backgroundSkewT.plotBackground") qp = QtGui.QPainter() qp.begin(self.plotBitMap) qp.setClipRect(self.clip) qp.translate(self.originx, self.originy) qp.scale(1. / self.scale, 1. / self.scale) self.transform = qp.transform() qp.scale(self.scale, self.scale) qp.translate(-self.originx, -self.originy) qp.setRenderHint(qp.Antialiasing) qp.setRenderHint(qp.TextAntialiasing) for t in np.arange(self.bltmpc-100, self.brtmpc+self.dt, self.dt): self.draw_isotherm(t, qp) #for tw in range(self.bltmpc, self.brtmpc, 10): self.draw_moist_adiabat(tw, qp) for theta in np.arange(self.bltmpc, 80, 20): self.draw_dry_adiabat(theta, qp) for w in [2] + np.arange(4, 33, 4): self.draw_mixing_ratios(w, 600, qp) self.draw_frame(qp) for p in [1000, 850, 700, 500, 300, 200, 100]: self.draw_isobar(p, 1, qp) for t in np.arange(self.bltmpc, self.brtmpc+self.dt, self.dt): self.draw_isotherm_labels(t, qp) for p in range(int(self.pmax), int(self.pmin-50), -50): self.draw_isobar(p, 0, qp) qp.end() self.backgroundBitMap = self.plotBitMap.copy(0, 0, self.width(), self.height())
[docs] def resizeEvent(self, e): ''' Resize the plot based on adjusting the main window. ''' self.initUI()
[docs] def wheelEvent(self, e): centerx, centery = e.x(), e.y() # From map max_speed = 100. delta = max(min(-e.delta(), max_speed), -max_speed) scale_fac = 10 ** (delta / 1000.) if self.scale * scale_fac > 1.0: scale_fac = 1. / self.scale self.scale *= scale_fac self.originx = centerx - (centerx - self.originx) / scale_fac self.originy = centery - (centery - self.originy) / scale_fac ll_x = self.originx + self.width() / self.scale ll_y = self.originy + self.height() / self.scale if ll_x < self.width(): self.originx += (self.width() - ll_x) elif self.originx > 0: self.originx = 0 if ll_y < self.height(): self.originy += (self.height() - ll_y) elif self.originy > 0: self.originy = 0 self.plotBackground() self.update()
[docs] def draw_dry_adiabat(self, theta, qp): ''' Draw the given moist adiabat. ''' logging.debug("Drawing dry adiabat: " + str(theta)) qp.setClipping(True) pen = QtGui.QPen(self.adiab_color, 1) pen.setStyle(QtCore.Qt.SolidLine) qp.setPen(pen) dp = -10 presvals = np.arange(int(self.pmax), int(self.pmin)+dp, dp) thetas = ((theta + ZEROCNK) / (np.power((1000. / presvals),ROCP))) - ZEROCNK xvals = self.originx + self.tmpc_to_pix(thetas, presvals) / self.scale yvals = self.originy + self.pres_to_pix(presvals) / self.scale path = QPainterPath() path.moveTo(xvals[0], yvals[0]) for i in range(1, len(presvals) ): p = presvals[i] x = xvals[i] y = yvals[i] path.lineTo(x, y) qp.drawPath(path)
[docs] def draw_moist_adiabat(self, tw, qp): ''' Draw the given moist adiabat. ''' logging.debug("Drawing moist adiabat: " + str(tw)) pen = QtGui.QPen(QtGui.QColor("#663333"), 1) pen.setStyle(QtCore.Qt.SolidLine) qp.setPen(pen) dp = -10 for p in range(int(self.pmax), int(self.pmin)+dp, dp): t = tab.thermo.wetlift(1000., tw, p) x = self.tmpc_to_pix(t, p) y = self.pres_to_pix(p) if p == self.pmax: x2 = x; y2 = y else: x1 = x2; y1 = y2 x2 = x; y2 = y qp.drawLine(x1, y1, x2, y2)
[docs] def draw_mixing_ratios(self, w, pmin, qp): ''' Draw the mixing ratios. ''' logging.debug("Draw the water vapor mixing ratio line: " + str(w)) qp.setClipping(True) t = tab.thermo.temp_at_mixrat(w, self.pmax) x1 = self.originx + self.tmpc_to_pix(t, self.pmax) / self.scale y1 = self.originy + self.pres_to_pix(self.pmax) / self.scale t = tab.thermo.temp_at_mixrat(w, pmin) x2 = self.originx + self.tmpc_to_pix(t, pmin) / self.scale y2 = self.originy + self.pres_to_pix(pmin) / self.scale rectF = QtCore.QRectF(x2-5, y2-10, 10, 10) pen = QtGui.QPen(self.bg_color, 1, QtCore.Qt.SolidLine) brush = QtGui.QBrush(self.bg_color, QtCore.Qt.SolidPattern) qp.setPen(pen) qp.setBrush(brush) qp.drawRect(rectF) pen = QtGui.QPen(self.mixr_color, 1, QtCore.Qt.SolidLine) qp.setPen(pen) qp.setFont(self.in_plot_font) qp.drawLine(x1, y1, x2, y2) qp.drawText(rectF, QtCore.Qt.AlignBottom | QtCore.Qt.AlignCenter, tab.utils.INT2STR(w))
[docs] def draw_frame(self, qp): ''' Draw the frame around the Skew-T. ''' logging.debug("Drawing frame around the Skew-T.") qp.setClipping(False) pen = QtGui.QPen(self.bg_color, 0, QtCore.Qt.SolidLine) brush = QtGui.QBrush(self.bg_color, QtCore.Qt.SolidPattern) qp.setPen(pen) qp.setBrush(brush) qp.drawRect(0, 0, self.lpad, self.bry) qp.drawRect(0, self.pres_to_pix(self.pmax), self.brx, self.bry) qp.drawRect(self.brx, 0, self.wid+self.rpad, self.pres_to_pix(self.pmax)) pen = QtGui.QPen(self.fg_color, 2, QtCore.Qt.SolidLine) qp.setPen(pen) qp.drawLine(self.lpad, self.tpad, self.brx+self.rpad, self.tpad) qp.drawLine(self.brx+self.rpad, self.tpad, self.brx+self.rpad, self.bry) qp.drawLine(self.brx+self.rpad, self.bry, self.lpad, self.bry) qp.drawLine(self.lpad, self.bry, self.lpad, self.tpad)
[docs] def draw_isotherm_labels(self, t, qp): ''' Add Isotherm Labels. ''' logging.debug("Drawing isotherm label: " + str(t)) pen = QtGui.QPen(self.fg_color) self.label_font.setBold(True) qp.setFont(self.label_font) x1 = self.originx + self.tmpc_to_pix(t, self.pmax) / self.scale if x1 >= self.lpad and x1 <= self.wid: qp.setClipping(False) qp.drawText(x1-10, self.bry+2, 20, 20, QtCore.Qt.AlignTop | QtCore.Qt.AlignCenter, tab.utils.INT2STR(t)) self.label_font.setBold(False)
[docs] def draw_isotherm(self, t, qp): ''' Draw background isotherms. ''' logging.debug("Drawing background isotherm: " + str(t)) qp.setClipping(True) x1 = self.originx + self.tmpc_to_pix(t, self.pmax) / self.scale x2 = self.originx + self.tmpc_to_pix(t, self.pmin) / self.scale y1 = self.originy + self.bry / self.scale y2 = self.originy + self.tpad / self.scale if int(t) in [0, -20]: pen = QtGui.QPen(self.isotherm_hgz_color, 1) else: pen = QtGui.QPen(self.isotherm_color, 1) pen.setStyle(QtCore.Qt.CustomDashLine) pen.setDashPattern([4, 2]) qp.setPen(pen) qp.drawLine(x1, y1, x2, y2)
[docs] def draw_isobar(self, p, flag, qp): ''' Draw background isobars. ''' logging.debug("Drawing background isobar: " + str(p) + ' flag: ' + str(flag)) pen = QtGui.QPen(self.fg_color, 1, QtCore.Qt.SolidLine) qp.setPen(pen) self.label_font.setBold(True) qp.setFont(self.label_font) y1 = self.originy + self.pres_to_pix(p) / self.scale if y1 >= self.tpad and y1 <= self.hgt: offset = 5 if flag: qp.drawLine(self.lpad, y1, self.brx, y1) qp.drawText(1, y1-20, self.lpad-4, 40, QtCore.Qt.AlignVCenter | QtCore.Qt.AlignRight, tab.utils.INT2STR(p)) else: qp.drawLine(self.lpad, y1, self.lpad+offset, y1) qp.drawLine(self.brx+self.rpad-offset, y1, self.brx+self.rpad, y1) self.label_font.setBold(False)
[docs] def tmpc_to_pix(self, t, p): ''' Function to convert a (temperature, pressure) coordinate to an X pixel. ''' scl1 = self.brtmpc - (((self.bry - self.pres_to_pix(p)) / (self.bry - self.tpad)) * self.yrange) return self.brx - (((scl1 - t) / self.xrange) * (self.brx - self.lpad))
[docs] def pix_to_tmpc(self, x, y): ''' Function to convert an (x, y) pixel into a temperature ''' scl1 = self.brtmpc - (((self.bry - y) / float(self.bry - self.tpad)) * self.yrange) return scl1 - (((self.brx - x) / float(self.brx - self.lpad)) * self.xrange)
[docs] def pres_to_pix(self, p): ''' Function to convert a pressure value (level) 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 pix_to_pres(self, y): ''' Function to convert a Y pixel to a pressure level. ''' scl1 = np.log(self.pmax) - np.log(self.pmin) scl2 = self.bry - float(y) scl3 = self.bry - self.tly + 1 return self.pmax / np.exp((scl2 / scl3) * scl1)
[docs]class plotSkewT(backgroundSkewT): modified = Signal(int, dict) cursor_toggle = Signal(bool) cursor_move = Signal(float) parcel = Signal(tab.params.Parcel) reset = Signal(list) def __init__(self, **kwargs): logging.debug("Initializing plotSkewT.") self.bg_color = QtGui.QColor(kwargs.get('bg_color', '#000000')) self.fg_color = QtGui.QColor(kwargs.get('fg_color', '#FFFFFF')) self.isotherm_color = QtGui.QColor(kwargs.get('isotherm_color', '#555555')) self.isotherm_hgz_color = QtGui.QColor(kwargs.get('isotherm_hgz_color', '#0000FF')) self.adiab_color = QtGui.QColor(kwargs.get('adiab_color', '#333333')) self.mixr_color = QtGui.QColor(kwargs.get('mixr_color', '#006600')) self.readout_vars = [kwargs.get('readout_br', 'dwpc'), kwargs.get('readout_tr', 'temp')] self.alert_colors = [ QtGui.QColor('#775000'), QtGui.QColor('#996600'), QtGui.QColor('#ffffff'), QtGui.QColor('#ffff00'), QtGui.QColor('#ff0000'), QtGui.QColor('#e700df'), ] super(plotSkewT, self).__init__(plot_omega=False) ## get the profile data self.prof = None self.prof_collections = [] self.pc_idx = 0 self.pcl = None self.all_observed = False self.plotdgz = kwargs.get('dgz', False) # PBL marker plotting functionality added by Nickolai Reimer NWS Billings, MT self.plotpbl = kwargs.get('pbl', False) self.interpWinds = kwargs.get('interpWinds', True) ## ui stuff self.title = kwargs.get('title', '') self.dp = -25 self.temp_color = QtGui.QColor(kwargs.get('temp_color', '#FF0000')) self.ens_temp_color = QtGui.QColor(kwargs.get('ens_temp_color', '#880000')) self.dewp_color = QtGui.QColor(kwargs.get('dewp_color', '#00FF00')) self.ens_dewp_color = QtGui.QColor(kwargs.get('ens_dewp_color', '#008800')) self.wetbulb_color = QtGui.QColor(kwargs.get('wetbulb_color', '#00FFFF')) self.eff_layer_color = QtGui.QColor(kwargs.get('eff_layer_color', '#00FFFF')) #self.max_lapse_rate_color = QtGui.QColor('#FF6D6D') self.background_colors =[ QtGui.QColor(c) for c in kwargs.get('background_colors', ['#6666CC', '#CC9966', '#66CC99']) ] self.hgt_color = QtGui.QColor(kwargs.get('hgt_color', '#FF0000')) self.dgz_color = QtGui.QColor(kwargs.get('dgz_color', '#F5D800')) self.lcl_mkr_color = QtGui.QColor(kwargs.get('lcl_mkr_color', '#00FF00')) self.lfc_mkr_color = QtGui.QColor(kwargs.get('lfc_mkr_color', '#FFFF00')) self.el_mkr_color = QtGui.QColor(kwargs.get('el_mkr_color', '#FF00FF')) self.sig_temp_level_color = QtGui.QColor('#0A63FF') self.sfc_units = kwargs.get('sfc_units', 'Fahrenheit') self.wind_units = kwargs.get('wind_units', 'knots') self.use_left = False self.setMouseTracking(True) self.was_right_click = False self.track_cursor = False self.readout = False self.readout_pres = 1000. self.cursor_loc = None self.drag_tmpc = None self.drag_dwpc = None ## create the readout labels self.presReadout = QLabel(parent=self) self.hghtReadout = QLabel(parent=self) self.tmpcReadout = QLabel(parent=self) self.dwpcReadout = QLabel(parent=self) ## set their alignments self.presReadout.setAlignment(QtCore.Qt.AlignCenter) self.hghtReadout.setAlignment(QtCore.Qt.AlignCenter) self.tmpcReadout.setAlignment(QtCore.Qt.AlignCenter) self.dwpcReadout.setAlignment(QtCore.Qt.AlignCenter) ## initialize the width to 0 so that they don't show up ## on initialization self.presReadout.setFixedWidth(0) self.hghtReadout.setFixedWidth(0) self.tmpcReadout.setFixedWidth(0) self.dwpcReadout.setFixedWidth(0) ## set the style sheet for text size, color, etc ## There's something funky going on with the colors here. fg_hex = "#%02x%02x%02x" % (self.bg_color.red(), self.bg_color.green(), self.bg_color.blue()) bg_rgb = self.fg_color.getRgb() # print bg_rgb, self.fg_color.getRgb() #rgb_string = 'rgb(' + str(bg_rgb[0]) + ',' + str(bg_rgb[1]) + ',' + str(bg_rgb[2]) + ',100%)' rgb_string = kwargs.get('bg_color', '#000000') self.presReadout.setStyleSheet(self.getStyleSheet(self.fg_color.name())) self.hghtReadout.setStyleSheet(self.getStyleSheet("#FF0000")) self.tmpcReadout.setStyleSheet(self.getStyleSheet("#FF0000")) self.dwpcReadout.setStyleSheet(self.getStyleSheet("#00FF00")) self.rubberBand = QRubberBand(QRubberBand.Line, self) self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.showCursorMenu) self.parcelmenu = QMenu("Lift Parcel") #ag = QtGui.QActionGroup(self, exclusive=True) # List of parcels that can be lifted pcl1 = QAction(self) pcl1.setText("This Parcel") pcl1.triggered.connect(lambda: self.liftparcellevel(0)) #ag.addAction(pcl1) self.parcelmenu.addAction(pcl1) pcl2 = QAction(self) pcl2.setText("50 mb Layer Parcel") pcl2.triggered.connect(lambda: self.liftparcellevel(50)) #ag.addAction(pcl2) self.parcelmenu.addAction(pcl2) pcl3 = QAction(self) pcl3.setText("100 mb Layer Parcel") pcl3.triggered.connect(lambda: self.liftparcellevel(100)) #ag.addAction(pcl3) self.parcelmenu.addAction(pcl3) pcl4 = QAction(self) pcl4.setText("Custom Parcel") pcl4.triggered.connect(lambda: self.liftparcellevel(-9999)) #ag.addAction(pcl4) self.parcelmenu.addAction(pcl4) self.parcelmenu.setEnabled(False) self.popupmenu=QMenu("Cursor Type:") ag = QtWidgets.QActionGroup(self, exclusive=True) nocurs = QAction(self) nocurs.setText("No Cursor") nocurs.setCheckable(True) nocurs.setChecked(True) nocurs.triggered.connect(self.setNoCursor) a = ag.addAction(nocurs) self.popupmenu.addAction(a) storm_motion = QAction(self) storm_motion.setText("Readout Cursor") storm_motion.setCheckable(True) storm_motion.triggered.connect(self.setReadoutCursor) a = ag.addAction(storm_motion) self.popupmenu.addAction(a) self.popupmenu.addSeparator() self.popupmenu.addMenu(self.parcelmenu) modify_sfc = QAction(self) modify_sfc.setText("Modify Surface") modify_sfc.setCheckable(False) modify_sfc.triggered.connect(self.modifySfc) self.popupmenu.addAction(modify_sfc) self.popupmenu.addSeparator() reset = QAction(self) reset.setText("Reset Skew-T") reset.triggered.connect(lambda: self.reset.emit(['tmpc', 'dwpc'])) self.popupmenu.addAction(reset)
[docs] def getStyleSheet(self, color, fsize=11): rgb_string = self.bg_color.name() readout_stylesheet = "QLabel {" + \ " background-color: " + rgb_string + ";" + \ " border-width: 0px;" + \ " font-size: " + str(fsize) + "px;" + \ " color: " + color + ";}" return readout_stylesheet
[docs] def getPlotTitle(self, prof_coll): logging.debug("Calling plotSkewT.getPlotTitle") modified = prof_coll.isModified() or prof_coll.isInterpolated() modified_str = "; Modified" if modified else "" loc = prof_coll.getMeta('loc') date = prof_coll.getCurrentDate() run = prof_coll.getMeta('run').strftime("%HZ") model = prof_coll.getMeta('model') observed = prof_coll.getMeta('observed') ensemble = prof_coll.isEnsemble() plot_title = loc + ' ' + datetime.strftime(date, "%Y%m%d/%H%M") if model == "Archive": fhour_str = "" if not prof_coll.getMeta('observed'): fhour = int(total_seconds(date - prof_coll.getMeta('base_time')) / 3600) fhour_str = " F%03d" % fhour plot_title += " (User Selected" + fhour_str + modified_str + ")" elif model == "Analog": date = prof_coll.getAnalogDate() plot_title = loc + ' ' + datetime.strftime(date, "%Y%m%d/%H%M") plot_title += " (Analog" + modified_str + ")" elif observed: plot_title += " (Observed" + modified_str + ")" else: mem_string = "" if ensemble: mem_string = " " + prof_coll.getHighlightedMemberName() fhour = int(total_seconds(date - prof_coll.getMeta('base_time')) / 3600) plot_title += " (" + run + " " + model + mem_string + " " + ("F%03d" % fhour) + modified_str + ")" return plot_title
[docs] def liftparcellevel(self, i): pres = self.pix_to_pres( self.cursor_loc.y()) tmp = tab.interp.temp(self.prof, pres) dwp = tab.interp.dwpt(self.prof, pres) if i == 0: usrpcl = tab.params.parcelx(self.prof, flag=5, pres=pres, tmpc=tmp, dwpc=dwp) else: if i == -9999: depth, result = QInputDialog.getText(None, "Parcel Depth (" + str(int(pres)) + "to __)",\ "Mean Layer Depth (mb):") try: i = int(depth) except: return user_initpcl = tab.params.DefineParcel(self.prof, flag=4, pbot=pres, pres=i) usrpcl = tab.params.parcelx(self.prof, pres=user_initpcl.pres, tmpc=user_initpcl.tmpc,\ dwpc=user_initpcl.dwpc) self.parcel.emit(usrpcl) # Emit a signal that a new profile has been created
[docs] def addProfileCollection(self, prof_coll): logging.debug("Adding profile collection:" + str(prof_coll)) self.prof_collections.append(prof_coll)
[docs] def rmProfileCollection(self, prof_coll): logging.debug("Removing profile collection:" + str(prof_coll)) self.prof_collections.remove(prof_coll)
[docs] def setActiveCollection(self, pc_idx, **kwargs): logging.debug("Setting the active collection to the Skew-T...") self.pc_idx = pc_idx prof = self.prof_collections[pc_idx].getHighlightedProf() self.plot_omega = not self.prof_collections[pc_idx].getMeta('observed') self.prof = prof self.pres = prof.pres; self.hght = prof.hght self.tmpc = prof.tmpc; self.dwpc = prof.dwpc self.vtmp = prof.vtmp self.dew_stdev = prof.dew_stdev self.tmp_stdev = prof.tmp_stdev self.u = prof.u; self.v = prof.v self.wetbulb = prof.wetbulb self.interpWinds = kwargs.get('interpWinds', True) trans_tmx = self.originx + self.tmpc_to_pix(self.tmpc, self.pres) / self.scale trans_dwx = self.originx + self.tmpc_to_pix(self.dwpc, self.pres) / self.scale trans_y = self.originy + self.pres_to_pix(self.pres) / self.scale self.drag_tmpc = Draggable(trans_tmx, trans_y, self.plotBitMap, lock_dim='y', line_color=QtGui.QColor("#9F0101")) self.drag_dwpc = Draggable(trans_dwx, trans_y, self.plotBitMap, lock_dim='y', line_color=QtGui.QColor("#019B06")) if kwargs.get('update_gui', True): self.clearData() self.plotData() if self.readout: self.updateReadout() self.update()
[docs] def setParcel(self, parcel): logging.debug("Setting the parcel: " + str(parcel)) self.pcl = parcel self.clearData() self.plotData() if self.readout: self.updateReadout() self.update()
[docs] def setDGZ(self, flag): logging.debug("PlotDGZ Flag: " + str(flag)) self.plotdgz = flag self.clearData() self.plotData() self.update() return
[docs] def setPBLLevel(self, flag): self.plotpbl = flag self.clearData() self.plotData() self.update() return
[docs] def setAllObserved(self, all_observed, update_gui=True): self.all_observed = all_observed if update_gui: self.clearData() self.plotData() self.update()
[docs] def setPreferences(self, update_gui=True, **kwargs): self.bg_color = QtGui.QColor(kwargs['bg_color']) self.fg_color = QtGui.QColor(kwargs['fg_color']) self.isotherm_color = QtGui.QColor(kwargs['skew_itherm_color']) self.isotherm_hgz_color = QtGui.QColor(kwargs['skew_itherm_hgz_color']) self.adiab_color = QtGui.QColor(kwargs['skew_adiab_color']) self.mixr_color = QtGui.QColor(kwargs['skew_mixr_color']) self.temp_color = QtGui.QColor(kwargs['temp_color']) self.dewp_color = QtGui.QColor(kwargs['dewp_color']) self.wetbulb_color = QtGui.QColor(kwargs['wetb_color']) self.eff_layer_color = QtGui.QColor(kwargs['eff_inflow_color']) self.hgt_color = QtGui.QColor(kwargs['skew_hgt_color']) self.dgz_color = QtGui.QColor(kwargs['skew_dgz_color']) self.lcl_mkr_color = QtGui.QColor(kwargs['skew_lcl_mkr_color']) self.lfc_mkr_color = QtGui.QColor(kwargs['skew_lfc_mkr_color']) self.el_mkr_color = QtGui.QColor(kwargs['skew_el_mkr_color']) self.sfc_units = kwargs['temp_units'] self.wind_units = kwargs['wind_units'] # READOUT VARIABLES NOT SURE WHY THIS WAS THROWING AN EXCEPTION self.readout_vars = [kwargs['readout_tr'],kwargs['readout_br']] self.presReadout.setStyleSheet(self.getStyleSheet(self.fg_color.name())) self.hghtReadout.setStyleSheet(self.getStyleSheet("#FF0000")) #print(self.readout_vars) #self.readout_vars = ['tmpc', 'dwpc'] if update_gui: self.plotBitMap.fill(self.bg_color) self.plotBackground() self.clearData() self.plotData() if self.readout: self.updateReadout() self.update()
[docs] def setDeviant(self, deviant): self.use_left = deviant == 'left' self.clearData() self.plotData() self.update()
def _restTmpc(self, x, y): xs, ys = self.drag_dwpc.getCoords() idx = np.argmin(np.abs(y - ys)) return max(xs[idx], x), y def _restDwpc(self, x, y): xs, ys = self.drag_tmpc.getCoords() idx = np.argmin(np.abs(y - ys)) return min(xs[idx], x), y
[docs] def mouseReleaseEvent(self, e): logging.debug("Releasing the mouse in skew-T.") if self.prof is None: return if not self.was_right_click and self.readout: self.track_cursor = not self.track_cursor self.cursor_loc = e.pos() drag_idx = None if self.drag_tmpc.isDragging(): drag_idx, rls_x, rls_y = self.drag_tmpc.release(e.x(), e.y(), restrictions=self._restTmpc) prof_name = 'tmpc' elif self.drag_dwpc.isDragging(): drag_idx, rls_x, rls_y = self.drag_dwpc.release(e.x(), e.y(), restrictions=self._restDwpc) prof_name = 'dwpc' if drag_idx is not None: trans_x = (rls_x - self.originx) * self.scale trans_y = (rls_y - self.originy) * self.scale tmpc = self.pix_to_tmpc(trans_x, trans_y) # Example: 4 {'tmpc': 10.790866472309446} (changed the 4th point of the tmpc profile to the temperature value set in tmpc) # So, if we want to modify an entire layer of the sounding, we'll have to get creative. #print(drag_idx, {prof_name: tmpc}) self.modified.emit(drag_idx, {prof_name:tmpc}) self.was_right_click = False
[docs] def mousePressEvent(self, e): logging.debug("Pressing the mouse in the skew-T.") if self.prof is None: return self.was_right_click = e.button() & QtCore.Qt.RightButton if not self.was_right_click and not self.readout: drag_started = False for drag in [ self.drag_dwpc, self.drag_tmpc ]: if not drag_started: drag_started = drag.click(e.x(), e.y())
[docs] def mouseMoveEvent(self, e): if self.prof is None: return if self.track_cursor: self.readout_pres = self.pix_to_pres((e.y() - self.originy) * self.scale) self.updateReadout() for drag, rest in [ (self.drag_dwpc, self._restDwpc), (self.drag_tmpc, self._restTmpc) ]: drag.drag(e.x(), e.y(), restrictions=rest) self.update()
[docs] def modifySfc(self): box = SfcModifyDialog(self.sfc_units, None) box.exec_() result = box.result() if result == QDialog.Rejected: return def templvl(theta, p): ''' theta : potential temp in kelvin p : pressure in hPa Returns: temperature in C ''' return tab.thermo.ktoc(theta / np.power(1000./p, tab.constants.ROCP)) temp = box.getTemp() dwpt = box.getDewPoint() if box.getMix(): theta = tab.thermo.ctok(tab.thermo.theta(self.prof.pres[self.prof.sfc], float(temp))) theta_copy = self.prof.theta.copy() theta_copy[self.prof.sfc] = theta idx = np.ma.where(theta_copy <= theta)[0] tmp = templvl(theta, self.prof.pres[idx]) temp = self.prof.tmpc.copy() temp[idx] = tmp mixrat = tab.thermo.mixratio(self.prof.pres[self.prof.sfc], float(dwpt)) dwpt = self.prof.dwpc.copy() dwpt[idx] = tab.thermo.temp_at_mixrat(np.repeat(mixrat, len(idx)), self.prof.pres[idx]) self.modified.emit(-999, {'tmpc': temp, 'idx_range':idx, 'dwpc': dwpt}) else: self.modified.emit(self.prof.sfc, {'tmpc': temp, 'dwpc': dwpt})
[docs] def getReadoutVal(self, var): if var == 'tmpc': val = tab.interp.temp(self.prof, self.readout_pres) var_id = 'T=' unit = 'C' round_val = 1 color = self.temp_color.name() elif var == 'dwpc': val = tab.interp.dwpt(self.prof, self.readout_pres) var_id = 'Td=' unit = "C" round_val = 1 color = self.dewp_color.name() elif var == 'thetae': val = tab.interp.thetae(self.prof, self.readout_pres) var_id = u"\u03B8" + 'e=' unit = "K" round_val = 0 color = self.lfc_mkr_color.name() elif var == 'wetbulb': val = tab.interp.wetbulb(self.prof, self.readout_pres) var_id = 'Tw=' unit = "C" round_val = 1 color = self.wetbulb_color.name() elif var == 'theta': val = tab.interp.theta(self.prof, self.readout_pres) var_id = u"\u03B8" + '=' unit = "K" round_val = 0 color = self.lfc_mkr_color.name() elif var == 'wvmr': val = tab.interp.mixratio(self.prof, self.readout_pres) var_id = 'q=' unit = "g/kg" round_val = 1 color = self.dewp_color.name() else: try: val = tab.interp.omeg(self.prof, self.readout_pres) * 36 # to convert to mb/hr (multiply by 10 to get to microbars/s which is default acis value except: val = '--' var_id = u"\u03C9" + '=' unit = "mb/hr" color = self.el_mkr_color.name() round_val = 1 ss = self.getStyleSheet(color) text = var_id + tab.utils.FLOAT2STR(val, round_val) + ' ' + unit return ss, text
[docs] def updateReadout(self): y = self.originy + self.pres_to_pix(self.readout_pres) / self.scale self.rubberBand.setGeometry(QRect(QPoint(self.lpad,y), QPoint(self.brx,y)).normalized()) self.presReadout.setFixedWidth(60) self.hghtReadout.setFixedWidth(65) self.tmpcReadout.setFixedWidth(65) self.dwpcReadout.setFixedWidth(65) ss, text = self.getReadoutVal(self.readout_vars[0]) self.tmpcReadout.setStyleSheet(ss) self.tmpcReadout.setText(text) ss, text = self.getReadoutVal(self.readout_vars[1]) self.dwpcReadout.setStyleSheet(ss) self.dwpcReadout.setText(text) hgt = tab.interp.to_agl( self.prof, tab.interp.hght(self.prof, self.readout_pres) ) self.presReadout.setText(tab.utils.FLOAT2STR(self.readout_pres, 1) + ' hPa') # TODO: Also allow for an output in ft AGL vs m AGL self.hghtReadout.setText(tab.utils.FLOAT2STR(hgt, 1) + ' m') # Move the Readout self.presReadout.move(self.lpad, y+2) self.hghtReadout.move(self.lpad, y - 15) self.tmpcReadout.move(self.brx-self.rpad, y - 15) self.dwpcReadout.move(self.brx-self.rpad, y+2) self.rubberBand.show() self.cursor_move.emit(hgt)
[docs] def setReadoutCursor(self): logging.debug("Turning on the readout cursor.") self.parcelmenu.setEnabled(True) self.readout = True self.track_cursor = True self.presReadout.show() self.hghtReadout.show() self.tmpcReadout.show() self.dwpcReadout.show() self.rubberBand.show() self.cursor_toggle.emit(True) self.clearData() self.plotData() self.update() self.parentWidget().setFocus()
[docs] def setNoCursor(self): logging.debug("Turning off the readout cursor.") self.parcelmenu.setEnabled(False) self.readout = False self.track_cursor = False self.presReadout.hide() self.hghtReadout.hide() self.tmpcReadout.hide() self.dwpcReadout.hide() self.rubberBand.hide() self.cursor_toggle.emit(False) self.clearData() self.plotData() self.update() self.parentWidget().setFocus()
[docs] def resizeEvent(self, e): ''' Resize the plot based on adjusting the main window. ''' logging.debug("Calling plotSkewT.resizeEvent") super(plotSkewT, self).resizeEvent(e) self.plotData()
[docs] def closeEvent(self, e): pass
[docs] def showCursorMenu(self, pos): logging.debug("Displaying the cursor menu in plotSkewT.") if self.cursor_loc is None or self.track_cursor: self.cursor_loc = pos self.popupmenu.popup(self.mapToGlobal(pos))
[docs] def wheelEvent(self, e): super(plotSkewT, self).wheelEvent(e) trans_tmx = self.originx + self.tmpc_to_pix(self.tmpc, self.pres) / self.scale trans_dwx = self.originx + self.tmpc_to_pix(self.dwpc, self.pres) / self.scale trans_y = self.originy + self.pres_to_pix(self.pres) / self.scale self.drag_tmpc.setCoords(trans_tmx, trans_y) self.drag_dwpc.setCoords(trans_dwx, trans_y) self.plotBitMap.fill(self.bg_color) if self.readout: self.updateReadout() self.plotBackground() self.plotData()
[docs] def paintEvent(self, e): logging.debug("Calling plotSkewT.paintEvent") super(plotSkewT, 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. ''' logging.debug("Clearing the data from the Skew-T.") self.plotBitMap = self.backgroundBitMap.copy(0, 0, self.width(), self.height()) for drag in [ self.drag_dwpc, self.drag_tmpc ]: if drag is not None: drag.setBackground(self.plotBitMap)
[docs] def plotData(self): ''' Plot the data used in a Skew-T. ''' logging.debug("Plotting the data on the Skew-T") if self.prof is None: return qp = QtGui.QPainter() qp.begin(self.plotBitMap) qp.setClipRect(self.clip) qp.setRenderHint(qp.Antialiasing) qp.setRenderHint(qp.TextAntialiasing) self.drawTitles(qp) bg_color_idx = 0 cur_dt = self.prof_collections[self.pc_idx].getCurrentDate() for idx, prof_col in enumerate(self.prof_collections): # Plot all unhighlighted members at this time if prof_col.getCurrentDate() == cur_dt: proflist = list(prof_col.getCurrentProfs().values()) if idx == self.pc_idx: temp_color = self.ens_temp_color dewp_color = self.ens_dewp_color else: temp_color = self.background_colors[bg_color_idx] dewp_color = self.background_colors[bg_color_idx] bg_color_idx = (bg_color_idx + 1) % len(self.background_colors) for profile in proflist: self.drawTrace(profile.tmpc, temp_color, qp, p=profile.pres, width=1) self.drawTrace(profile.dwpc, dewp_color, qp, p=profile.pres, width=1) try: self.drawBarbs(profile, qp, color="#666666") except Exception as e: logging.debug("Couldn't draw wind barbs in skew.py") logging.exception(e) bg_color_idx = 0 for idx, prof_col in enumerate(self.prof_collections): if idx != self.pc_idx and (prof_col.getCurrentDate() == cur_dt or self.all_observed): profile = prof_col.getHighlightedProf() color = self.background_colors[bg_color_idx] self.drawTrace(profile.tmpc, color, qp, p=profile.pres) self.drawTrace(profile.dwpc, color, qp, p=profile.pres) try: self.drawBarbs(profile, qp, color=color) except Exception as e: logging.exception(e) logging.debug("Couldn't draw wind barbs in skew.py") bg_color_idx = (bg_color_idx + 1) % len(self.background_colors) self.drawTrace(self.wetbulb, self.wetbulb_color, qp, width=1) self.drawTrace(self.tmpc, self.temp_color, qp, stdev=self.tmp_stdev) self.drawTrace(self.vtmp, self.temp_color, qp, width=1, style=QtCore.Qt.DashLine, label=False) if self.plotdgz is True and (self.prof.dgz_pbot != self.prof.dgz_ptop): # idx = np.ma.where((self.prof.pres <= self.prof.dgz_pbot) & (self.prof.pres >= self.prof.dgz_ptop)) # idx_pbot, idx_ptop = np.searchsorted(np.array([self.prof.dgz_pbot, self.prof.dgz_ptop]), self.prof.pres) pres = np.ma.masked_invalid(np.arange(self.prof.dgz_ptop, self.prof.dgz_pbot, 5)[::-1]) tmpc = np.ma.masked_invalid(tab.interp.temp(self.prof, pres)) qp.setFont(self.hght_font) self.drawTrace(tmpc, self.dgz_color, qp, p=pres, label=False) self.draw_sig_levels(qp, plevel=self.prof.dgz_pbot, color=QtGui.QColor("#F5D800")) self.draw_sig_levels(qp, plevel=self.prof.dgz_ptop, color=QtGui.QColor("#F5D800")) # DRAW WBZ and FRZ but only if they exist wbz_plevel = tab.params.temp_lvl(self.prof, 0, wetbulb=True) frz_plevel = tab.params.temp_lvl(self.prof, 0) self.draw_sig_levels(qp, plevel=self.prof.dgz_pbot, color=QtGui.QColor("#F5D800")) self.draw_sig_levels(qp, plevel=self.prof.dgz_ptop, color=QtGui.QColor("#F5D800")) self.draw_sig_levels(qp, plevel=wbz_plevel, color=QtGui.QColor(self.dewp_color), var_id="WBZ=") self.draw_sig_levels(qp, plevel=frz_plevel, color=QtGui.QColor('#FFA500'), var_id="FRZ=") else: # DRAW THE MAX LAPSE RATE self.draw_max_lapse_rate_layer(qp) self.draw_temp_levels(qp) self.drawTrace(self.dwpc, self.dewp_color, qp, stdev=self.dew_stdev) for h in [0,1000.,3000.,6000.,9000.,12000.,15000.]: self.draw_height(h, qp) if self.pcl is not None: self.dpcl_ttrace = self.prof.dpcl_ttrace self.dpcl_ptrace = self.prof.dpcl_ptrace self.drawVirtualParcelTrace(self.pcl.ttrace, self.pcl.ptrace, qp) self.drawVirtualParcelTrace(self.dpcl_ttrace, self.dpcl_ptrace, qp, color=QtGui.QColor("#FF00FF")) if self.plotpbl: self.draw_pbl_level(qp) self.draw_parcel_levels(qp) qp.setRenderHint(qp.Antialiasing, False) try: self.drawBarbs(self.prof, qp) except Exception as e: logging.exception(e) logging.debug("Couldn't draw wind barbs in skew.py") qp.setRenderHint(qp.Antialiasing) self.draw_effective_layer(qp) if self.plot_omega: self.draw_omega_profile(qp) qp.end()
[docs] def drawBarbs(self, prof, qp, color=None): logging.debug("Drawing the wind barbs on the Skew-T.") if color is None: color = self.fg_color qp.setClipping(False) rect_size = self.clip.size() rect_size.setHeight(rect_size.height() + self.bpad) mod_clip = QRect(self.clip.topLeft(), rect_size) qp.setClipRect(mod_clip) if self.interpWinds is False: i = 0 mask1 = prof.u.mask mask2 = prof.pres.mask mask = np.maximum(mask1, mask2) pres = prof.pres[~mask] u = prof.u[~mask] v = prof.v[~mask] wdir, wspd = tab.utils.comp2vec(u, v) yvals = self.originy + self.pres_to_pix(pres) / self.scale for y in yvals: dd = wdir[i] ss = wspd[i] if self.wind_units == 'm/s': ss = tab.utils.KTS2MS(ss) drawBarb( qp, self.barbx, y, dd, vv, shemis=(prof.latitude < 0) ) i += 1 else: pres = np.arange(prof.pres[prof.sfc], prof.pres[prof.top], -40) wdir, wspd = tab.interp.vec(prof, pres) for p, dd, ss in zip(pres, wdir, wspd): if not tab.utils.QC(dd) or np.isnan(ss) or p < self.pmin: continue if self.wind_units == 'm/s': ss = tab.utils.KTS2MS(ss) y = self.originy + self.pres_to_pix(p) / self.scale drawBarb( qp, self.barbx, y, dd, ss, color=color, shemis=(prof.latitude < 0) ) qp.setClipRect(self.clip)
[docs] def drawTitles(self, qp): logging.debug("Drawing the titles on the Skew-T") box_width = 150 cur_dt = self.prof_collections[self.pc_idx].getCurrentDate() idxs, titles = list(zip(*[ (idx, self.getPlotTitle(pc)) for idx, pc in enumerate(self.prof_collections) if pc.getCurrentDate() == cur_dt or self.all_observed ])) titles = list(titles) main_title = titles.pop(idxs.index(self.pc_idx)) qp.setClipping(False) qp.setFont(self.title_font) pen = QtGui.QPen(self.fg_color, 1, QtCore.Qt.SolidLine) qp.setPen(pen) rect0 = QtCore.QRect(self.lpad, 2, box_width, self.title_height) qp.drawText(rect0, QtCore.Qt.TextDontClip | QtCore.Qt.AlignLeft, main_title) bg_color_idx = 0 for idx, title in enumerate(titles): pen = QtGui.QPen(QtGui.QColor(self.background_colors[bg_color_idx]), 1, QtCore.Qt.SolidLine) qp.setPen(pen) rect0 = QtCore.QRect(self.width() - box_width, 2 + idx * self.title_height, box_width, self.title_height) qp.drawText(rect0, QtCore.Qt.TextDontClip | QtCore.Qt.AlignRight, title) bg_color_idx = (bg_color_idx + 1) % len(self.background_colors)
[docs] def draw_height(self, h, qp): logging.debug("Drawing the height marker: " + str(h)) qp.setClipping(True) pen = QtGui.QPen(self.hgt_color, 1, QtCore.Qt.SolidLine) qp.setPen(pen) qp.setFont(self.hght_font) offset = 10 txt_offset = 15 sfc = tab.interp.hght( self.prof, self.prof.pres[self.prof.sfc] ) p1 = tab.interp.pres(self.prof, h+sfc) if np.isnan(p1) == False: y1 = self.originy + self.pres_to_pix(p1) / self.scale qp.drawLine(self.lpad, y1, self.lpad+offset, y1) qp.drawText(self.lpad+txt_offset, y1-20, self.lpad+txt_offset, 40, QtCore.Qt.AlignVCenter | QtCore.Qt.AlignLeft, tab.utils.INT2STR(h/1000)+' km')
[docs] def draw_sig_levels(self, qp, plevel=1000, color=None, var_id=""): logging.debug("Drawing significant levels.") if color is None: color = self.fg_color qp.setClipping(True) if not tab.utils.QC(plevel): return xbounds = [37,45] z = tab.utils.M2FT(tab.interp.hght(self.prof, plevel)) x = self.tmpc_to_pix(xbounds, [1000.,1000.]) y = self.originy + self.pres_to_pix(plevel) / self.scale pen = QtGui.QPen(color, 1, QtCore.Qt.SolidLine) qp.setPen(pen) qp.drawLine(x[0], y, x[1], y) left_bnd = self.tmpc_to_pix([20,36],[1000,1000]) rect1 = QtCore.QRectF(left_bnd[0], y-3, left_bnd[1] - left_bnd[0], 4) qp.drawText(rect1, QtCore.Qt.TextDontClip | QtCore.Qt.AlignRight, var_id + tab.utils.INT2STR(z) + '\'')
[docs] def draw_pbl_level(self, qp): logging.debug("Drawing the PBL top marker.") if self.prof is not None: qp.setClipping(True) xbounds = [37,41] x = self.tmpc_to_pix(xbounds, [1000.,1000.]) pblp = self.prof.ppbl_top if tab.utils.QC(pblp): y = self.originy + self.pres_to_pix(pblp) / self.scale pen = QtGui.QPen(QtCore.Qt.gray, 2, QtCore.Qt.SolidLine) qp.setPen(pen) qp.drawLine(x[0], y, x[1], y) rect1 = QtCore.QRectF(x[0], y+6, x[1] - x[0], 4) qp.drawText(rect1, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter, "PBL")
[docs] def draw_parcel_levels(self, qp): logging.debug("Drawing the parcel levels (LCL, LFC, EL).") qp.setClipping(True) xbounds = [37,41] x = self.tmpc_to_pix(xbounds, [1000.,1000.]) lclp = self.pcl.lclpres lfcp = self.pcl.lfcpres elp = self.pcl.elpres lvls = [[self.pcl.p0c,self.pcl.hght0c, '0 C'], [self.pcl.pm20c, self.pcl.hghtm20c, '-20 C'],[self.pcl.pm30c, self.pcl.hghtm30c, '-30 C']] qp.setFont(self.hght_font) # Plot LCL if tab.utils.QC(lclp): y = self.originy + self.pres_to_pix(lclp) / self.scale pen = QtGui.QPen(self.lcl_mkr_color, 2, QtCore.Qt.SolidLine) qp.setPen(pen) qp.drawLine(x[0], y, x[1], y) rect1 = QtCore.QRectF(x[0], y+6, x[1] - x[0], 4) qp.drawText(rect1, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter, "LCL") # Plot LFC if tab.utils.QC(lfcp): y = self.originy + self.pres_to_pix(lfcp) / self.scale pen = QtGui.QPen(self.lfc_mkr_color, 2, QtCore.Qt.SolidLine) qp.setPen(pen) qp.drawLine(x[0], y, x[1], y) rect2 = QtCore.QRectF(x[0], y-8, x[1] - x[0], 4) qp.drawText(rect2, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter, "LFC") # Plot EL if tab.utils.QC(elp) and elp != lclp: y = self.originy + self.pres_to_pix(elp) / self.scale pen = QtGui.QPen(self.el_mkr_color, 2, QtCore.Qt.SolidLine) qp.setPen(pen) qp.drawLine(x[0], y, x[1], y) rect3 = QtCore.QRectF(x[0], y-8, x[1] - x[0], 4) qp.drawText(rect3, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter, "EL")
[docs] def draw_temp_levels(self, qp): if self.pcl is None: return xbounds = [37,41] x = self.tmpc_to_pix(xbounds, [1000.,1000.]) lvls = [[self.pcl.p0c,self.pcl.hght0c, '0 C'], [self.pcl.pm20c, self.pcl.hghtm20c, '-20 C'],[self.pcl.pm30c, self.pcl.hghtm30c, '-30 C']] qp.setClipping(True) for p, h, t in lvls: try: if tab.utils.QC(p): y = self.originy + self.pres_to_pix(p) / self.scale pen = QtGui.QPen(self.sig_temp_level_color, 2, QtCore.Qt.SolidLine) qp.setPen(pen) qp.drawLine(x[0], y, x[1], y) rect3 = QtCore.QRectF(x[0], y-12, x[1] - x[0], 4) qp.drawText(rect3, QtCore.Qt.TextDontClip | QtCore.Qt.AlignLeft, t + '=' + tab.utils.INT2STR(tab.utils.M2FT(h)) + '\'') except: continue
[docs] def omeg_to_pix(self, omeg): plus10_bound = -49 minus10_bound = -41 x1_m10 = self.tmpc_to_pix(minus10_bound, 1000) x1_10 = self.tmpc_to_pix(plus10_bound, 1000) x1_0 = self.tmpc_to_pix((plus10_bound + minus10_bound)/2., 1000) if omeg > 0: return ((x1_0 - x1_10)/(0.-10.)) * omeg + x1_0 elif omeg < 0: return ((x1_0 - x1_m10)/(0.+10.)) * omeg + x1_0 else: return x1_0
[docs] def draw_omega_profile(self, qp): logging.debug("Drawing the omega profile.") qp.setClipping(True) plus10_bound = -49 minus10_bound = -41 x1_m10 = self.tmpc_to_pix(minus10_bound, 1000) y1_m10 = self.pres_to_pix(1000) y2_m10 = self.pres_to_pix(111) pen = QtGui.QPen(QtCore.Qt.magenta, 1, QtCore.Qt.DashDotLine) qp.setPen(pen) qp.drawLine(x1_m10, y1_m10, x1_m10, y2_m10) x1_10 = self.tmpc_to_pix(plus10_bound, 1000) y1_10 = self.pres_to_pix(1000) y2_10 = self.pres_to_pix(111) qp.drawLine(x1_10, y1_10, x1_10, y2_10) pen = QtGui.QPen(QtCore.Qt.magenta, 1, QtCore.Qt.SolidLine) qp.setPen(pen) x1 = self.tmpc_to_pix((plus10_bound + minus10_bound)/2., 1000) y1 = self.pres_to_pix(1000) y2 = self.pres_to_pix(111) qp.drawLine(x1, y1, x1, y2) rect3 = QtCore.QRectF(x1_10, y2 - 18, x1_m10 - x1_10, 4) qp.drawText(rect3, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter, "OMEGA") rect3 = QtCore.QRectF(x1_m10-3, y2 - 7, 5, 4) qp.drawText(rect3, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter, "-10") rect3 = QtCore.QRectF(x1_10-3, y2 - 7, 5, 4) qp.drawText(rect3, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter, "+10") x1 = self.tmpc_to_pix((plus10_bound + minus10_bound)/2., 1000) for i in range(len(self.prof.omeg)): pres_y = self.originy + self.pres_to_pix(self.prof.pres[i]) / self.scale if not tab.utils.QC(self.prof.omeg[i]) or self.prof.pres[i] < 111: continue if self.prof.omeg[i] > 0: pen = QtGui.QPen(QtGui.QColor("#0066CC"), 1.5, QtCore.Qt.SolidLine) elif self.prof.omeg[i] < 0: pen = QtGui.QPen(QtGui.QColor("#FF6666"), 1.5, QtCore.Qt.SolidLine) else: pen = QtGui.QPen(QtCore.Qt.magenta, 1, QtCore.Qt.SolidLine) qp.setPen(pen) x2 = self.omeg_to_pix(self.prof.omeg[i]*10.) qp.drawLine(x1, pres_y, x2, pres_y)
[docs] def draw_max_lapse_rate_layer(self, qp, bound=4.5): ''' Draw the bounds of the maximum lapse rate layer. ''' qp.setClipping(True) ptop = self.prof.max_lapse_rate_2_6[2]; pbot = self.prof.max_lapse_rate_2_6[1] line_length = 10 text_offset = 10 if tab.utils.QC(ptop) and tab.utils.QC(pbot) and self.prof.max_lapse_rate_2_6[0] >= bound: x1 = self.tmpc_to_pix(tab.interp.vtmp(self.prof, pbot) + 5, pbot) #x2 = self.tmpc_to_pix(32, 1000) y1 = self.originy + self.pres_to_pix(pbot) / self.scale y2 = self.originy + self.pres_to_pix(ptop) / self.scale rect3 = QtCore.QRectF(x1-15, y2-self.esrh_height, 50, self.esrh_height) pen = QtGui.QPen(self.bg_color, 0, QtCore.Qt.SolidLine) brush = QtGui.QBrush(self.bg_color, QtCore.Qt.SolidPattern) qp.setPen(pen) qp.setBrush(brush) qp.drawRect(rect3) if self.prof.max_lapse_rate_2_6[0] >= 8: # PURPLE color = self.alert_colors[5] elif self.prof.max_lapse_rate_2_6[0] >= 7: # RED color = self.alert_colors[4] elif self.prof.max_lapse_rate_2_6[0] >= 6: # BROWN color = self.alert_colors[1] else: color = self.alert_colors[0] pen = QtGui.QPen(color, 1.5, QtCore.Qt.SolidLine) qp.setPen(pen) qp.setFont(self.esrh_font) qp.drawLine(x1-line_length, y1, x1+line_length, y1) qp.drawLine(x1-line_length, y2, x1+line_length, y2) qp.drawLine(x1, y1, x1, y2) qp.setClipping(False) qp.drawText(rect3, QtCore.Qt.TextDontClip | QtCore.Qt.AlignLeft, tab.utils.FLOAT2STR(self.prof.max_lapse_rate_2_6[0],1 ) + ' C/km')
[docs] def draw_effective_layer(self, qp): ''' Draw the bounds of the effective inflow layer. ''' logging.debug("Drawing the effective inflow layer.") qp.setClipping(True) ptop = self.prof.etop; pbot = self.prof.ebottom len = 15 text_offset = 10 if tab.utils.QC(ptop) and tab.utils.QC(pbot): x1 = self.tmpc_to_pix(-20, 1000) x2 = self.tmpc_to_pix(-33, 1000) y1 = self.originy + self.pres_to_pix(pbot) / self.scale y2 = self.originy + self.pres_to_pix(ptop) / self.scale rect1 = QtCore.QRectF(x2, y1+4, 25, self.esrh_height) rect2 = QtCore.QRectF(x2, y2-self.esrh_height, 50, self.esrh_height) rect3 = QtCore.QRectF(x1-15, y2-self.esrh_height, 50, self.esrh_height) pen = QtGui.QPen(self.bg_color, 0, QtCore.Qt.SolidLine) brush = QtGui.QBrush(self.bg_color, QtCore.Qt.SolidPattern) qp.setPen(pen) qp.setBrush(brush) sfc = tab.interp.hght( self.prof, self.prof.pres[self.prof.sfc] ) if self.prof.pres[ self.prof.sfc ] == pbot: text_bot = 'SFC' else: text_bot = tab.interp.hght(self.prof, pbot) - sfc text_bot = tab.utils.INT2STR( text_bot ) + 'm' text_top = tab.interp.hght(self.prof, ptop) - sfc text_top = tab.utils.INT2STR( text_top ) + 'm' qp.drawRect(rect1) qp.drawRect(rect2) qp.drawRect(rect3) pen = QtGui.QPen(self.eff_layer_color, 2, QtCore.Qt.SolidLine) qp.setPen(pen) qp.setFont(self.esrh_font) qp.drawLine(x1-len, y1, x1+len, y1) qp.drawLine(x1-len, y2, x1+len, y2) qp.drawLine(x1, y1, x1, y2) qp.setClipping(False) qp.drawText(rect1, QtCore.Qt.TextDontClip | QtCore.Qt.AlignLeft, text_bot) qp.setClipping(True) qp.drawText(rect2, QtCore.Qt.TextDontClip | QtCore.Qt.AlignLeft, text_top) if self.use_left: esrh = self.prof.left_esrh[0] else: esrh = self.prof.right_esrh[0] qp.drawText(rect3, QtCore.Qt.TextDontClip | QtCore.Qt.AlignLeft, tab.utils.INT2STR(esrh) + ' m2s2')
# qp.drawText(x1-2*len, y1-text_offset, 40, 40, # QtCore.Qt.AlignVCenter | QtCore.Qt.AlignRight, # text_bot)
[docs] def drawVirtualParcelTrace(self, ttrace, ptrace, qp, width=1, color=None): ''' Draw a parcel trace. ''' logging.debug("Drawing the virtual parcel trace.") if color is None: color = self.fg_color qp.setClipping(True) pen = QtGui.QPen(color, width, QtCore.Qt.DashLine) brush = QtGui.QBrush(QtCore.Qt.NoBrush) qp.setPen(pen) qp.setBrush(brush) path = QPainterPath() if not tab.utils.QC(ptrace): return yvals = self.originy + self.pres_to_pix(ptrace) / self.scale xvals = self.originx + self.tmpc_to_pix(ttrace, ptrace) / self.scale path.moveTo(xvals[0], yvals[0]) for i in range(1, len(yvals)): x = xvals[i]; y = yvals[i] # if y < self.tpad: # break # else: path.lineTo(x, y) qp.drawPath(path)
[docs] def drawTrace(self, data, color, qp, width=3, style=QtCore.Qt.SolidLine, p=None, stdev=None, label=True): ''' Draw an environmental trace. ''' logging.debug("Drawing an environmental profile trace.") qp.setClipping(True) pen = QtGui.QPen(QtGui.QColor(color), width, style) brush = QtGui.QBrush(QtCore.Qt.NoBrush) qp.setPen(pen) qp.setBrush(brush) mask1 = data.mask if p is not None: mask2 = p.mask pres = p else: mask2 = self.pres.mask pres = self.pres mask = np.maximum(mask1, mask2) data = data[~mask] pres = pres[~mask] if stdev is not None: stdev = stdev[~mask] path = QPainterPath() x = self.originx + self.tmpc_to_pix(data, pres) / self.scale y = self.originy + self.pres_to_pix(pres) / self.scale path.moveTo(x[0], y[0]) for i in range(1, x.shape[0]): path.lineTo(x[i], y[i]) if stdev is not None: self.drawSTDEV(pres[i], data[i], stdev[i], color, qp) qp.drawPath(path) if label is True: qp.setClipping(False) if self.sfc_units == 'Celsius': label = data[0] else: label = tab.thermo.ctof(data[0]) #(1.8 * data[0]) + 32. pen = QtGui.QPen(self.bg_color, 0, QtCore.Qt.SolidLine) brush = QtGui.QBrush(self.bg_color, QtCore.Qt.SolidPattern) qp.setPen(pen) qp.setBrush(brush) rect = QtCore.QRectF(x[0]-8, y[0]+4, 16, 12) qp.drawRect(rect) pen = QtGui.QPen(QtGui.QColor(color), 3, QtCore.Qt.SolidLine) qp.setPen(pen) qp.setFont(self.environment_trace_font) qp.drawText(rect, QtCore.Qt.AlignCenter, tab.utils.INT2STR(label)) qp.setClipping(True)
[docs] def drawSTDEV(self, pres, data, stdev, color, qp, width=1): ''' Draw the error bars on the profile. ''' pen = QtGui.QPen(QtGui.QColor(color), width, QtCore.Qt.SolidLine) brush = QtGui.QBrush(QtCore.Qt.NoBrush) qp.setPen(pen) qp.setBrush(brush) path = QPainterPath() offset = 5. x = self.tmpc_to_pix(data, pres) y = self.pres_to_pix(pres) err_left = self.tmpc_to_pix(data - stdev, pres) err_right = self.tmpc_to_pix(data + stdev, pres) path.moveTo(err_left, y) path.lineTo(err_left, y-offset) path.lineTo(err_left, y+offset) path.moveTo(err_left, y) path.lineTo(err_right, y) path.lineTo(err_right, y-offset) path.lineTo(err_right, y+offset) qp.drawPath(path)
class SfcModifyDialog(QDialog): def __init__(self, units, parent=None): """ Construct the preferences dialog box. config: A Config object containing the user's configuration. """ super(SfcModifyDialog, self).__init__(parent=parent) self.units = units self.__initUI() def __initUI(self): """ Set up the user interface [private method]. """ self.setWindowTitle("Modify Surface") main_layout = QVBoxLayout() button_layout = QHBoxLayout() self.accept_button = QPushButton("Accept") self.accept_button.setDefault(True) self.accept_button.clicked.connect(self.accept) self.cancel_button = QPushButton("Cancel") self.cancel_button.clicked.connect(self.reject) button_layout.addWidget(self.accept_button) button_layout.addWidget(self.cancel_button) self.accept_button.setEnabled(False) self.layout = main_layout self.mix_check = QCheckBox("Mix") if self.units == 'Fahrenheit': self.unit = "F" else: self.unit = "C" label = QLabel("New Surface Temperature (" + self.unit + "):") self.new_temp = QLineEdit() double_valid = QDoubleValidator() double_valid.setRange(-273.15, 500, 3) self.new_temp.setValidator(double_valid) main_layout.addWidget(label) main_layout.addWidget(self.new_temp) main_layout.addWidget(QLabel("New Surface Dewpoint (" + self.unit + "):")) self.new_dwpt = QLineEdit() self.new_dwpt.setValidator(double_valid) main_layout.addWidget(self.new_dwpt) main_layout.addWidget(self.mix_check) main_layout.addLayout(button_layout) self.setLayout(main_layout) self.new_temp.textChanged.connect(self.validateText) self.new_dwpt.textChanged.connect(self.validateText) def validateText(self): if self.new_temp.hasAcceptableInput() and self.new_dwpt.hasAcceptableInput() and self.getTemp() >= self.getDewPoint(): self.accept_button.setEnabled(True) else: self.accept_button.setEnabled(False) def getTemp(self): if self.unit == "C": return float(self.new_temp.text()) else: return tab.thermo.ftoc(float(self.new_temp.text())) def getDewPoint(self): if self.unit == "C": return float(self.new_dwpt.text()) else: return tab.thermo.ftoc(float(self.new_dwpt.text())) def getMix(self): return self.mix_check.isChecked() if __name__ == "__main__": logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG) app_frame = QtGui.QApplication([]) title = "Window" width = 800 height = 600 #qp = QPainter() tester = plotSkewT() tester.show() # run the main Qt event loop app_frame.exec_()