Source code for sharppy.viz.preferences


from qtpy.QtCore import *
from qtpy.QtGui import *
from qtpy.QtWidgets import *

from collections import OrderedDict
import numpy as np

import os
import sys

[docs]def resource_path(): if hasattr(sys, '_MEIPASS'): return os.path.join(sys._MEIPASS, "rc") return os.path.join(os.path.dirname(__file__), "..", "..", "rc")
[docs]class ColorSwatch(QWidget): """ A color swatch widget for displaying and selecting colors. """ def __init__(self, color, parent=None): """ Construct a ColorSwatch class color: A QColor specifying the starting color for the swatch. """ super(ColorSwatch, self).__init__(parent=parent) self._color = color
[docs] def setColor(self, new_color): """ Set the color of the swatch. new_color: A QColor containing the new color. """ self._color = new_color
[docs] def getColor(self): """ Returns the current color as a QColor """ return self._color
[docs] def getHexColor(self): """ Returns the current color as a hex string. """ red = "%02x" % self.getColor().red() green = "%02x" % self.getColor().green() blue = "%02x" % self.getColor().blue() return "#%s%s%s" % (red, green, blue)
[docs] def paintEvent(self, e): """ Paint event handler """ qp = QPainter() qp.begin(self) qp.setBrush(QBrush(self._color)) qp.drawRect(0, 0, self.width(), self.height()) qp.end()
[docs] def mousePressEvent(self, e): """ Mouse press event handler (opens a dialog to select a new color for the swatch). """ color_choice = QColorDialog.getColor(self.getColor()) if color_choice.isValid(): self.setColor(color_choice)
[docs] def enterEvent(self, e): """ Enter event handler (sets the cursor to a pointing hand). """ self.setCursor(Qt.PointingHandCursor)
[docs] def leaveEvent(self, e): """ Leave event handler (sets the cursor to whatever it was before). """ self.unsetCursor()
[docs]class ColorPreview(QWidget): _color_imgs = { 'standard': 'sample_std.png', 'inverted': 'sample_inv.png', 'protanopia': 'sample_pro.png', } def __init__(self, styles, default='standard', **kwargs): super(ColorPreview, self).__init__(**kwargs) self._img_path = resource_path() #os.path.join(os.path.dirname(__file__), "..", "..", "rc") self._styles = [ s.lower() for s in styles ] self.changeImage(self._styles.index(default)) self._base_x, self._base_y = 118, 80 self._aspect = float(self._base_x) / self._base_y self.setMinimumSize(self._base_x, self._base_y) self.show()
[docs] @Slot(str) def changeImage(self, img_index): self._current = self._styles[img_index] self._img = QPixmap(os.path.join(self._img_path, ColorPreview._color_imgs[self._current])) self.update()
[docs] def paintEvent(self, e): qp = QPainter() qp.begin(self) qp.setBrush(QBrush(QColor("#000000"))) qp.drawPixmap(0, 0, self.width(), self.height(), self._img, 0, 0, self._img.width(), self._img.height()) qp.end()
[docs]class PrefDialog(QDialog): """ The preferences dialog box for SHARPpy. """ _styles = { 'standard': { 'bg_color': '#000000', 'fg_color': '#ffffff', 'temp_color': '#ff0000', 'dewp_color': '#00ff00', 'wetb_color': '#00ffff', 'skew_dgz_color':'#f5d800', 'skew_itherm_color':'#555555', 'skew_itherm_hgz_color':'#0000ff', 'skew_adiab_color':'#333333', 'skew_mixr_color':'#006600', 'skew_hgt_color':'#ff0000', 'skew_lcl_mkr_color':'#00ff00', 'skew_lfc_mkr_color':'#ffff00', 'skew_el_mkr_color':'#ff00ff', 'hodo_itach_color':'#555555', 'hodo_crit_color':'#00ffff', 'eff_inflow_color':'#04dbd8', '0_3_color': '#ff0000', '3_6_color': '#00ff00', '6_9_color': '#ffff00', '9_12_color': '#00ffff', '12_15_color': '#00ffff', 'pwat_m3_color':'#ff7f00', 'pwat_m2_color':'#ee9a00', 'pwat_m1_color':'#ffdab9', 'pwat_p1_color':'#98fb98', 'pwat_p2_color':'#66cd00', 'pwat_p3_color':'#00ff00', 'alert_l1_color':'#775000', 'alert_l2_color':'#996600', 'alert_l3_color':'#ffffff', 'alert_l4_color':'#ffff00', 'alert_l5_color':'#ff0000', 'alert_l6_color':'#e700df', 'alert_lscp_color':'#00ffff', 'stp_box_color':'#00ff00', 'stp_line_color':'#0080ff', 'pcl_sel_color':'#00ffff', 'pcl_cin_hi_color':'#993333', 'pcl_cin_md_color':'#996600', 'pcl_cin_lo_color':'#00ff00', 'spd_itach_color':'#9d5736', 'srw_clsc_color':'#b1019a', 'srw_trace_color':'#ff0000', 'srw_0_2_color':'#8b0000', 'srw_4_6_color':'#6495ed', 'srw_9_11_color':'#9400d3', 'winter_dgz_color':'#ffff00', 'watch_pdstor_color':'#ff00ff', 'watch_tor_color':'#ff0000', 'watch_svr_color':'#ffff00', 'watch_mrglsvr_color':'#0099cc', 'watch_flood_color':'#5ffb17', 'watch_blizzard_color':'#3366ff', 'watch_fire_color':'#ff9900', 'watch_heat_color':'#c85a17', 'watch_none_color':'#ffcc33', }, 'inverted': { 'bg_color': '#ffffff', 'fg_color': '#000000', 'temp_color': '#dd0000', 'dewp_color': '#00dd00', 'wetb_color': '#00cccc', 'skew_dgz_color':'#f5d800', 'skew_itherm_color':'#bbbbbb', 'skew_itherm_hgz_color':'#6666ff', 'skew_adiab_color':'#dddddd', 'skew_mixr_color':'#adebad', 'skew_hgt_color':'#dd0000', 'skew_lcl_mkr_color':'#00bb00', 'skew_lfc_mkr_color':'#bbbb00', 'skew_el_mkr_color':'#bb00bb', 'hodo_itach_color':'#bbbbbb', 'hodo_crit_color':'#00cccc', 'eff_inflow_color': '#00cccc', '0_3_color': '#dd0000', '3_6_color': '#00dd00', '6_9_color': '#dddd00', '9_12_color': '#00dddd', '12_15_color': '#00dddd', 'pwat_m3_color':'#ff9900', 'pwat_m2_color':'#cc7a00', 'pwat_m1_color':'#804d00', 'pwat_p1_color':'#006600', 'pwat_p2_color':'#00b300', 'pwat_p3_color':'#00ff00', 'alert_l1_color':'#dfbb9f', 'alert_l2_color':'#cc9666', 'alert_l3_color':'#666666', 'alert_l4_color':'#999900', 'alert_l5_color':'#cc0000', 'alert_l6_color':'#e700df', 'alert_lscp_color':'#00cccc', 'stp_box_color':'#00aa00', 'stp_line_color':'#66b3ff', 'pcl_sel_color':'#00cccc', 'pcl_cin_hi_color':'#dfbb9f', 'pcl_cin_md_color':'#cc9666', 'pcl_cin_lo_color':'#00cc00', 'spd_itach_color':'#ebd2c6', 'srw_clsc_color':'#fe81ed', 'srw_trace_color':'#dd0000', 'srw_0_2_color':'#8b0000', 'srw_4_6_color':'#6495ed', 'srw_9_11_color':'#9400d3', 'winter_dgz_color':'#999900', 'watch_pdstor_color':'#dd00dd', 'watch_tor_color':'#dd0000', 'watch_svr_color':'#aaaa00', 'watch_mrglsvr_color':'#0099cc', 'watch_flood_color':'#5ffb17', 'watch_blizzard_color':'#3366ff', 'watch_fire_color':'#ff9900', 'watch_heat_color':'#c85a17', 'watch_none_color':'#cc9900', }, 'protanopia': { 'bg_color': '#000000', 'fg_color': '#ffffff', 'temp_color': '#ff0000', 'dewp_color': '#00ffff', 'wetb_color': '#6666ff', 'skew_dgz_color':'#f5d800', 'skew_itherm_color':'#555555', 'skew_itherm_hgz_color':'#0000ff', 'skew_adiab_color':'#333333', 'skew_mixr_color':'#006600', 'skew_hgt_color':'#ff0000', 'skew_lcl_mkr_color':'#00ff00', 'skew_lfc_mkr_color':'#ffff00', 'hodo_itach_color':'#555555', 'hodo_crit_color':'#00ffff', 'eff_inflow_color': '#00ffff', '0_3_color': '#ff0000', '3_6_color': '#0000ff', '6_9_color': '#ff9900', '9_12_color': '#00ffff', '12_15_color': '#00ffff', 'pwat_m3_color':'#ff7f00', 'pwat_m2_color':'#ee9a00', 'pwat_m1_color':'#ffdab9', 'pwat_p1_color':'#98fb98', 'pwat_p2_color':'#66cd00', 'pwat_p3_color':'#00ff00', 'alert_l1_color':'#775000', 'alert_l2_color':'#996600', 'alert_l3_color':'#00ff99', 'alert_l4_color':'#ffffff', 'alert_l5_color':'#00ffff', 'alert_l6_color':'#ff00ff', 'alert_lscp_color':'#ffff00', 'stp_box_color':'#00ff00', 'stp_line_color':'#0080ff', 'pcl_sel_color':'#00ffff', 'pcl_cin_hi_color':'#993333', 'pcl_cin_md_color':'#996600', 'pcl_cin_lo_color':'#00ff00', 'spd_itach_color':'#9d5736', 'srw_clsc_color':'#b1019a', 'srw_trace_color':'#ff0000', 'srw_0_2_color':'#8b0000', 'srw_4_6_color':'#6495ed', 'srw_9_11_color':'#9400d3', 'winter_dgz_color':'#ffff00', 'watch_pdstor_color':'#ff00ff', 'watch_tor_color':'#ff0000', 'watch_svr_color':'#ffff00', 'watch_mrglsvr_color':'#0099cc', 'watch_flood_color':'#5ffb17', 'watch_blizzard_color':'#3366ff', 'watch_fire_color':'#ff9900', 'watch_heat_color':'#c85a17', 'watch_none_color':'#ffcc33', } } def __init__(self, config, parent=None): """ Construct the preferences dialog box. config: A Config object containing the user's configuration. """ super(PrefDialog, self).__init__(parent=parent) self._config = config self.__initUI() def __initUI(self): """ Set up the user interface [private method]. """ self.setWindowTitle("SHARPpy Preferences") main_layout = QVBoxLayout() button_layout = QHBoxLayout() self.layout = QGridLayout() self.setLayout(main_layout) self.accept_button = QPushButton("Accept") self.accept_button.setDefault(True) self.accept_button.clicked.connect(self.applyChanges) self.cancel_button = QPushButton("Cancel") self.cancel_button.clicked.connect(self.rejectChanges) button_layout.addWidget(self.accept_button) button_layout.addWidget(self.cancel_button) main_layout.addLayout(self.layout) main_layout.addLayout(button_layout) tab_widget = QTabWidget() color_widget = self._createColorWidget() tab_widget.addTab(color_widget, "Colors") map_widget = self._createMapWidget() # tab_widget.addTab(map_widget, "Map") misc_widget = self._createMiscWidget() readout_widget = self._createReadoutWidget() tab_widget.addTab(misc_widget, "Units") tab_widget.addTab(readout_widget, "Readout") self.layout.addWidget(tab_widget, 0, 0, 1, 1) def _createReadoutWidget(self): layout = QVBoxLayout() box = QWidget() label = QLabel("Top Right Readout Variable:") box.setLayout(layout) layout.addWidget(label) self.combo1 = QComboBox() layout.addWidget(self.combo1) self.combo2 = QComboBox() layout.addWidget(QLabel("Bottom Right Readout Variable:")) layout.addWidget(self.combo2) self.variables = {"Temperature (C)": 'tmpc', 'Dewpoint (C)': 'dwpc',\ "Equiv. Potential Temp. (K)": 'thetae',\ "Wetbulb Temperature (C)": 'wetbulb',\ "Potential Temperature (K)": 'theta',\ "Water Vapor Mixing Ratio (g/kg)": 'wvmr',\ "Vertical Velocity (mb/hr)": 'omeg'} for k in self.variables.keys(): self.combo1.addItem(k) self.combo2.addItem(k) idx1 = np.where(np.asarray(list(self.variables.values())) == self._config['preferences', 'readout_tr'])[0] idx2 = np.where(np.asarray(list(self.variables.values())) == self._config['preferences', 'readout_br'])[0] self.combo1.setCurrentIndex(idx1) self.combo2.setCurrentIndex(idx2) return box def _createColorWidget(self): colors_box = QWidget() colors_layout = QVBoxLayout() colors_box.setLayout(colors_layout) color_styles = ['Standard', 'Inverted', 'Protanopia'] self._color_style = self._config['preferences', 'color_style'] def updateStyle(style_idx): self._color_style = color_styles[style_idx].lower() colors_list = QComboBox() colors_list.addItems(color_styles) colors_list.setCurrentIndex(color_styles.index(self._color_style.title())) colors_layout.addWidget(colors_list) colors_prvw = ColorPreview(color_styles, default=self._color_style, parent=self) colors_layout.addWidget(colors_prvw) colors_list.activated.connect(colors_prvw.changeImage) colors_list.activated.connect(updateStyle) return colors_box def _createMapWidget(self): return QWidget() def _createMiscWidget(self): misc_box = QWidget() layout = QVBoxLayout() misc_box.setLayout(layout) temp_units_box, self.temp_units = PrefDialog._createRadioSet("Surface Temperature Units", ["Fahrenheit", "Celsius"], default=self._config['preferences', 'temp_units']) layout.addWidget(temp_units_box) wind_units_box, self.wind_units = PrefDialog._createRadioSet("Wind Units", ["knots", "m/s"], default=self._config['preferences', 'wind_units']) layout.addWidget(wind_units_box) pw_units_box, self.pw_units = PrefDialog._createRadioSet("Precipitable Water Vapor Units", ["in", "cm"], default=self._config['preferences', 'pw_units']) layout.addWidget(pw_units_box) return misc_box @staticmethod def _createColorBox(name, default_color): """ Create a color swatch and label [private static method] name: The label on the color swatch. default_color: The starting color for the swatch as a hex string. Returns a QWidget and a ColorSwatch object. """ swatch = ColorSwatch(QColor(default_color)) swatch.setMaximumWidth(40) swatch.setMinimumWidth(40) label = QLabel(name) colorbox = QWidget() layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) colorbox.setLayout(layout) layout.addWidget(swatch) layout.addWidget(label) return colorbox, swatch @staticmethod def _createRadioSet(set_name, opt_names, default=None, orientation='horizontal'): """ Create a set of radio buttons [private static method] set_name: Name of the group of buttons opt_names: A list of names for the radio buttons. default: The name of the button to be selected initially. orientation: The direction to arrange the radio buttons. Accepted values are 'horizontal' and 'vertical'. Default is 'horizontal'. Returns a QGroupBox and a dictionary with names as keys of QRadioButton's as values. """ radios = {} radio_box = QGroupBox(set_name) if orientation == 'horizontal': radio_layout = QHBoxLayout() elif orientation == 'vertical': radio_layout = QVBoxLayout() radio_box.setLayout(radio_layout) for oname in opt_names: radios[oname] = QRadioButton(oname) if oname == default: radios[oname].setChecked(True) radio_layout.addWidget(radios[oname]) return radio_box, radios def _applyRadio(self, config_name, radio): """ Apply the radio button selection to the configuration [private method]. config_name: Field in the configuration file to set. radio: Dictionary with names of the radio buttons as keys and QRadioButtons as values. """ for radio_name, rad in radio.items(): if rad.isChecked(): self._config['preferences', config_name] = radio_name
[docs] def applyChanges(self): """ Apply the state of the preferences box to the configuration and close the box. """ self._applyRadio('temp_units', self.temp_units) self._applyRadio('wind_units', self.wind_units) self._applyRadio('pw_units', self.pw_units) self._config['preferences', 'color_style'] = self._color_style for item, color in PrefDialog._styles[self._color_style].items(): self._config['preferences', item] = color self._config['preferences', 'readout_tr'] = self.variables[self.combo1.currentText()] self._config['preferences', 'readout_br'] = self.variables[self.combo2.currentText()] self.accept()
[docs] def rejectChanges(self): """ Close the box without applying the changes to the configuration. """ self.reject()
[docs] @staticmethod def initConfig(config): """ Initialize the configuration with the user preferences [static method]. config: A Config object containing the configuration. """ pref_config = { ('preferences', 'temp_units'):'Fahrenheit', ('preferences', 'wind_units'):'knots', ('preferences', 'pw_units'):'in', ('preferences', 'color_style'):'standard', ('preferences', 'readout_br'): 'dwpc', ('preferences', 'readout_tr'): 'tmpc' } color_config = dict((('preferences', k), v) for k, v in PrefDialog._styles['standard'].items()) pref_config.update(color_config) config.initialize(pref_config) color_style = config['preferences', 'color_style'] for item, color in PrefDialog._styles[color_style].items(): config['preferences', item] = color