Esempio n. 1
0
class PyWeramiWindow(QtGui.QMainWindow, Ui_MainWindow):

    def __init__(self, filename=None, parent=None):
        super(PyWeramiWindow,self).__init__(parent)
        self.settings = QtCore.QSettings("LX", "pywerami")
        self.setupUi(self)
        self._fig = plt.figure(facecolor="white")
        self._ax = self._fig.add_subplot(111)

        self._canvas = FigureCanvas(self._fig)
        self._canvas.setParent(self.widget)
        self._canvas.setFocusPolicy(QtCore.Qt.StrongFocus)
        self.matplot.addWidget(self._canvas)
        self.mpl_toolbar = NavigationToolbar(self._canvas,self.widget)
        self.mpl_toolbar.hide()
        self.matplot.addWidget(self.mpl_toolbar)

        #set combos
        self.cmaps = [m for m in plt.cm.datad if not m.endswith("_r")]
        self.mapstyle.addItems(self.cmaps)

        # set validators
        self.levelmin.setValidator(QtGui.QDoubleValidator(self.levelmin))
        self.levelmax.setValidator(QtGui.QDoubleValidator(self.levelmax))
        self.levelnum.setValidator(QtGui.QIntValidator(self.levelmin))
        self.levelstep.setValidator(QtGui.QDoubleValidator(self.levelstep))
        self.clipmin.setValidator(QtGui.QDoubleValidator(self.clipmin))
        self.clipmax.setValidator(QtGui.QDoubleValidator(self.clipmax))
        
        # Set icons in toolbar
        self.actionOpen.setIcon(QtGui.QIcon.fromTheme('document-open'))
        self.actionSave.setIcon(QtGui.QIcon.fromTheme('document-save'))
        self.actionSaveas.setIcon(QtGui.QIcon.fromTheme('document-save-as'))
        self.actionImport.setIcon(QtGui.QIcon.fromTheme('x-office-spreadsheet'))
        self.actionHome.setIcon(self.mpl_toolbar._icon('home.png'))
        self.actionPan.setIcon(self.mpl_toolbar._icon('move.png'))
        self.actionZoom.setIcon(self.mpl_toolbar._icon('zoom_to_rect.png'))
        self.actionGrid.setIcon(QtGui.QIcon.fromTheme('format-justify-fill'))
        self.actionAxes.setIcon(self.mpl_toolbar._icon('qt4_editor_options.png'))
        self.actionSavefig.setIcon(self.mpl_toolbar._icon('filesave.png'))
        #self.action3D.setIcon(QtGui.QIcon.fromTheme(''))
        self.actionProperties.setIcon(QtGui.QIcon.fromTheme('preferences-other'))
        self.actionQuit.setIcon(QtGui.QIcon.fromTheme('application-exit'))
        self.actionAbout.setIcon(QtGui.QIcon.fromTheme('help-about'))
        
        self.actionImport.triggered.connect(self.import_data)
        self.actionHome.triggered.connect(self.mpl_toolbar.home)
        self.actionPan.triggered.connect(self.plotpan)
        self.actionZoom.triggered.connect(self.plotzoom)
        self.actionGrid.triggered.connect(self.plotgrid)
        self.actionAxes.triggered.connect(self.mpl_toolbar.edit_parameters)
        self.actionSavefig.triggered.connect(self.mpl_toolbar.save_figure)
        self.actionProperties.triggered.connect(self.edit_options)
        self.actionQuit.triggered.connect(self.close)
        if filename:
            self.import_data(filename)
        
        # ready
        self.statusbar.showMessage("Ready", 5000)

    def closeEvent(self,event):
        reply=QtGui.QMessageBox.question(self,'Message',"Are you sure to quit?",QtGui.QMessageBox.Yes,QtGui.QMessageBox.No)
        if reply==QtGui.QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

    def import_data(self, filename=None):
        if not filename:
            filename = QtGui.QFileDialog.getOpenFileName(self, "Import tab file", ".", "TAB (*.tab);;All files (*.*)")
        if filename:
            self.data = WeramiData.from_tab(filename)

            # populate listview and setup properties
            self.props = {}
            self._model = QtGui.QStandardItemModel(self.listView)
            for var in self.data.dep:
                item = QtGui.QStandardItem(var)
                item.setCheckable(True)
                self._model.appendRow(item)
                self.default_var_props(var)

            self.listView.setModel(self._model)
            self.listView.show()
            # connect listview signals
            self.varSel = self.listView.selectionModel()
            self.varSel.selectionChanged.connect(self.on_var_changed)
            self._model.itemChanged.connect(self.plot)
            # buttons signals
            self.buttonBox.button(QtGui.QDialogButtonBox.Apply).clicked.connect(self.apply_props)
            self.buttonBox.button(QtGui.QDialogButtonBox.RestoreDefaults).clicked.connect(self.restore_props)
            self.contcolor.clicked.connect(self.contours_color)
            self.action3D.triggered.connect(self.switch3d)
            # signals to calculate step size
            self.levelmin.editingFinished.connect(self.step_from_levels)
            self.levelmax.editingFinished.connect(self.step_from_levels)
            self.levelnum.editingFinished.connect(self.step_from_levels)
            self.setlevels.toggled.connect(self.step_from_levels)
            
            # all done focus
            self.action3D.setChecked(False) # no 3d on import
            self.varSel.setCurrentIndex(self._model.index(0, 0), QtGui.QItemSelectionModel.ClearAndSelect | QtGui.QItemSelectionModel.Rows)
            self.listView.setFocus()
            self.plot()
            self.statusbar.showMessage("Data from {} imported".format(self.data.label), 5000)

    def contours_color(self):
    	col = QtGui.QColorDialog.getColor()
    	if col.isValid():
            self.contcolor.setStyleSheet("background-color: {}".format(col.name()))

    def step_from_levels(self):
        if self.setlevels.isChecked():
            step = (float(self.levelmax.text()) - float(self.levelmin.text())) / (int(self.levelnum.text()) - 1)
            self.levelstep.setText(repr(step))
            self.props[self.var]['step'] = step

    def default_var_props(self, var):
        data = self.data.get_var(var)
        prop = {}
        #levels
        prop['min'] = data.min()
        prop['max'] = data.max()
        prop['num'] = 10
        prop['step'] = (prop['max'] - prop['min']) / (prop['num'] - 1)
        prop['levels'] = 'num'
        prop['type'] = 'linear'
        #style
        prop['fill'] = False
        prop['opacity'] = 100
        prop['cmap'] = 'jet'
        prop['contours'] = 'color'
        prop['color'] = '#000000'
        prop['label'] = False
        #processing
        prop['resample'] = 1
        prop['median'] = 1
        prop['gauss'] = 0
        prop['clipmin'] = data.min()
        prop['clipmax'] = data.max()

        self.props[var] = prop

    def set_var_props(self, var):
        #levels
        self.levelmin.setText(repr(self.props[var]['min']))
        self.levelmax.setText(repr(self.props[var]['max']))
        self.levelnum.setText(repr(self.props[var]['num']))
        self.levelstep.setText(repr(self.props[var]['step']))
        if self.props[var]['levels'] == 'num':
            self.setlevels.setChecked(True)
        else:
            self.setstep.setChecked(True)
        if self.props[var]['type'] == 'linear':
            self.linlevel.setChecked(True)
        else:
            self.cdflevel.setChecked(True)
        #style
        if self.props[var]['fill']:
            self.fillstyle.setChecked(True)
        else:
            self.fillstyle.setChecked(False)
        self.opacity.setValue(self.props[var]['opacity'])
        self.mapstyle.setCurrentIndex(self.cmaps.index(self.props[var]['cmap']))
        self.contcolor.setStyleSheet("background-color: {}".format(self.props[var]['color']))
        if self.props[var]['contours'] == 'map':
            self.contcheckmap.setChecked(True)
        elif self.props[var]['contours'] == 'color':
            self.contcheckcolor.setChecked(True)
        else:
            self.contchecknone.setChecked(True)
        if self.props[var]['label']:
            self.contlabel.setChecked(True)
        else:
            self.contlabel.setChecked(False)
        #processing
        self.resample.setValue(self.props[var]['resample'])
        self.filtersize.setValue(self.props[var]['median'])
        self.filtersigma.setValue(self.props[var]['gauss'])
        self.clipmin.setText(repr(self.props[var]['clipmin']))
        self.clipmax.setText(repr(self.props[var]['clipmax']))

    def on_var_changed(self, selected):
        self.var = self.data.dep[selected.indexes()[0].row()]
        self.set_var_props(self.var)
        if self.action3D.isChecked():
            self.plot()

    def apply_props(self):
        #levels
        self.props[self.var]['min'] = float(self.levelmin.text())
        self.props[self.var]['max'] = float(self.levelmax.text())
        self.props[self.var]['num'] = int(self.levelnum.text())
        self.props[self.var]['step'] = float(self.levelstep.text())
        if self.setlevels.isChecked():
            self.props[self.var]['levels'] = 'num'
        else:
            self.props[self.var]['levels'] = 'step'
        if self.linlevel.isChecked():
            self.props[self.var]['type'] = 'linear'
        else:
            self.props[self.var]['type'] = 'cdf'
        #style
        if self.fillstyle.isChecked():
            self.props[self.var]['fill'] = True
        else:
            self.props[self.var]['fill'] = False
        self.props[self.var]['opacity'] = self.opacity.value()
        self.props[self.var]['cmap'] = str(self.mapstyle.currentText())
        self.props[self.var]['color'] = str(self.contcolor.palette().color(1).name())
        if self.contcheckmap.isChecked():
            self.props[self.var]['contours'] = 'map'
        elif self.contcheckcolor.isChecked():
            self.props[self.var]['contours'] = 'color'
        else:
            self.props[self.var]['contours'] = ''
        if self.contlabel.isChecked():
            self.props[self.var]['label'] = True
        else:
            self.props[self.var]['label'] = False
        #processing
        self.props[self.var]['resample'] = self.resample.value()
        self.props[self.var]['median'] = self.filtersize.value()
        self.props[self.var]['gauss'] = self.filtersigma.value()
        self.props[self.var]['clipmin'] = float(self.clipmin.text())
        self.props[self.var]['clipmax'] = float(self.clipmax.text())
        self.plot()

    def restore_props(self):
        self.default_var_props(self.var)
        self.set_var_props(self.var)
        self.plot()

    def edit_options(self):
        dlg = OptionsForm(self)
        dlg.exec_()

    def plotpan(self):
        self.actionZoom.setChecked(False)
        self.mpl_toolbar.pan()

    def plotzoom(self):
        self.actionPan.setChecked(False)
        self.mpl_toolbar.zoom()

    def plotgrid(self):
        plt.grid()
        self._canvas.draw()

    def switch3d(self):
        if not self.action3D.isChecked():
            self._fig.clear()
            self._ax = self._fig.add_subplot(111)
        else:
            self._fig.clear()
            self._ax = self._fig.add_subplot(111, projection='3d')
        self.plot()

    def plot(self):
        self._ax.cla()
        if not self.action3D.isChecked():
            extent = self.data.get_extent()
            i = 0
            while self._model.item(i):
                if self._model.item(i).checkState():
                    CS = None
                    var = str(self._model.item(i).text())
                    # get data, smooth and clip
                    data = self.data.get_var(var,nan=np.float(self.settings.value("nan", "NaN", type=str)))
                    if self.props[var]['resample'] > 1:
                        data = np.ma.array(ndimage.zoom(data.filled(0), self.props[var]['resample']), mask=ndimage.zoom(data.mask, self.props[var]['resample'], order=0))
                    if self.props[var]['median'] > 1:
                        data = np.ma.array(ndimage.median_filter(data, size=self.props[var]['median']*self.props[var]['resample']), mask=data.mask)
                    if self.props[var]['gauss'] > 0:
                        data = np.ma.array(ndimage.gaussian_filter(data, sigma=self.props[var]['gauss']*self.props[var]['resample']), mask=data.mask)
                    data = np.ma.masked_outside(data, self.props[var]['clipmin'], self.props[var]['clipmax'])
                    if self.props[var]['fill']:
                        self._ax.imshow(data, interpolation='none', origin='lower', extent=extent, aspect='auto', cmap=plt.get_cmap(self.props[var]['cmap']), alpha=self.props[var]['opacity']/100.0)
                    if self.props[var]['type'] == 'linear':
                        if self.props[var]['levels'] == 'num':
                            clevels = np.linspace(self.props[var]['min'], self.props[var]['max'], self.props[var]['num'])
                        else:
                            # trick to include max in levels
                            clevels = np.arange(self.props[var]['min'], self.props[var]['max'] + 10**np.ceil(np.log10(np.abs(self.props[var]['max']))), self.props[var]['step'])
                    else:
                        # cdf based on histogram binned acording to the Freedman-Diaconis rule
                        v = np.sort(data.compressed())
                        IQR = v[int(round((v.size-1) * float(0.75)))] - v[int(round((v.size-1) * float(0.25)))]
                        bin_size = 2 * IQR * v.size**(-1.0/3)
                        nbins = int(round(max(self.props[var]['num'], (v[-1]-v[0]) / (bin_size+0.001))))
                        hist, bin_edges = np.histogram(v, bins=nbins)
                        cdf = np.cumsum(hist)
                        cdfx = np.cumsum(np.diff(bin_edges)) + bin_edges[:2].sum()/2
                        clevels = np.interp(np.linspace(cdf[0],cdf[-1],self.props[var]['num'] + 2)[1:-1], cdf, cdfx)
                    if self.props[var]['contours'] == 'map':
                        CS = self._ax.contour(self.data.get_xrange(self.props[var]['resample']), self.data.get_yrange(self.props[var]['resample']), data, clevels, cmap=plt.get_cmap(self.props[var]['cmap']))
                    elif self.props[var]['contours'] == 'color':
                        CS = self._ax.contour(self.data.get_xrange(self.props[var]['resample']), self.data.get_yrange(self.props[var]['resample']), data, clevels, colors=self.props[var]['color'])
                    if self.props[var]['label'] and CS:
                        self._ax.clabel(CS, fontsize=8, inline=1)
                i += 1

            self._ax.axis(extent)
            plt.title(self.data.label)
        else:
            # get data, smooth and clip
            data = self.data.get_var(self.var)
            if self.props[self.var]['resample'] > 1:
                data = np.ma.array(ndimage.zoom(data.filled(0), self.props[self.var]['resample']), mask=ndimage.zoom(data.mask, self.props[self.var]['resample'], order=0))
            if self.props[self.var]['median'] > 1:
                data = np.ma.array(ndimage.median_filter(data, size=self.props[self.var]['median']*self.props[self.var]['resample']), mask=data.mask)
            if self.props[self.var]['gauss'] > 0:
                data = np.ma.array(ndimage.gaussian_filter(data, sigma=self.props[self.var]['gauss']*self.props[self.var]['resample']), mask=data.mask)
            data = np.ma.masked_outside(data, self.props[self.var]['clipmin'], self.props[self.var]['clipmax'])
            x,y = np.meshgrid(self.data.get_xrange(self.props[self.var]['resample']), self.data.get_yrange(self.props[self.var]['resample']))
            self._ax.plot_surface(x, y, data.filled(np.NaN), vmin=data.min(), vmax=data.max(), cmap=plt.get_cmap(self.props[self.var]['cmap']), linewidth=0.5, alpha=self.props[self.var]['opacity']/100.0)
            self._ax.view_init(azim=235, elev=30)

        plt.xlabel(self.data.ind[self.data.xvar]['name'])
        plt.ylabel(self.data.ind[self.data.yvar]['name'])
        plt.tight_layout()
        self._canvas.draw()
Esempio n. 2
0
 def _icon(self, name):
     if name.startswith(os.path.sep):
         return QtGui.QIcon(name)
     return NavigationToolbar._icon(self, name)