def __init__(self, data, title, flags="chroma", parent=None, **k): QWidget.__init__(self, parent) MSDialogController.__init__(self, 0, parent) self.model = self.qApp.model self.view = self.qApp.view self.data = data self.title = title self.flags = flags if self.flags == 'peak': if self.acTree not in (self.view.treeView_2, self.view.treeView_3): print "Unknown Error" return idx = self.acTree.selectedIndexes()[0] s = qApp.instance().dockControl.currentSample[ 1 if self.acTree is self.view.treeView_2 else 2] if s is None: print "unknow error" return values = map(float, idx.data().toString().split('/')[:2]) self.currentPeak = s.peakAt(*values) #connection to update the selected Peak object self.connect(self.acTree, SIGNAL("changedLine"), self.updateCurrentPeak) self.minX, self.maxX, self.maxY = [0] * 3 #if flags != 'peak': # self.minX, self.maxX, self.maxY = self.getMax() self.pw = PlotWidget(self.minX, self.maxX, self.maxY, parent=self, **k) #parent=self, #self.pw.setAttribute(Qt.WA_DeleteOnClose)#plotItem.setAttribute(Qt.WA_PaintOnScreen & Qt.WA_PaintUnclipped) if k.get('antialiased', False): self.pw.setRenderHint(0x01) #antialiasing i suppose self.pw.setTitle(title) self.pw.updateGrid() self._setupUi() self.connect(self, SIGNAL('linePlotted'), self.updateContextMenu) self.connect(self.view.sampleTableView, SIGNAL("disHighlightRequested(QModelIndex)"), self.disHighlightOne) self.connect(self.view.sampleTableView, SIGNAL("highlightRequested(QModelIndex)"), self.highlight) self.connect(self.view.sampleTableView, SIGNAL("noHighlightRequested()"), self.disHighlight) self.connect(self.view.ppmEditer, SIGNAL('valueChanged(double)'), self.redrawAll) self.drawnItems = {} self.trashItems = [] #why unecessary? nope to collect annotation stuff self.textLabels = [] self.pixmaps = [] self.dataPoints = None self._plotting(self.data) #initial plotting
def __init__(self, data, title, flags="chroma", parent=None, **k): QWidget.__init__(self, parent) MSDialogController.__init__(self, 0, parent) self.model = self.qApp.model self.view = self.qApp.view self.data=data self.title=title self.flags=flags if self.flags == 'peak': if self.acTree not in (self.view.treeView_2, self.view.treeView_3): print "Unknown Error" return idx=self.acTree.selectedIndexes()[0] s = qApp.instance().dockControl.currentSample[1 if self.acTree is self.view.treeView_2 else 2] if s is None: print "unknow error" return values = map(float, idx.data().toString().split('/')[:2]) self.currentPeak = s.peakAt(*values) #connection to update the selected Peak object self.connect(self.acTree, SIGNAL("changedLine"), self.updateCurrentPeak) self.minX, self.maxX, self.maxY = [0] * 3 #if flags != 'peak': # self.minX, self.maxX, self.maxY = self.getMax() self.pw = PlotWidget(self.minX, self.maxX, self.maxY, parent=self, **k)#parent=self, #self.pw.setAttribute(Qt.WA_DeleteOnClose)#plotItem.setAttribute(Qt.WA_PaintOnScreen & Qt.WA_PaintUnclipped) if k.get('antialiased', False): self.pw.setRenderHint(0x01)#antialiasing i suppose self.pw.setTitle(title) self.pw.updateGrid() self._setupUi() self.connect(self, SIGNAL('linePlotted'), self.updateContextMenu) self.connect(self.view.sampleTableView, SIGNAL("disHighlightRequested(QModelIndex)"), self.disHighlightOne) self.connect(self.view.sampleTableView, SIGNAL("highlightRequested(QModelIndex)"), self.highlight) self.connect(self.view.sampleTableView, SIGNAL("noHighlightRequested()"), self.disHighlight) self.connect(self.view.ppmEditer, SIGNAL('valueChanged(double)'), self.redrawAll) self.drawnItems = {} self.trashItems=[]#why unecessary? nope to collect annotation stuff self.textLabels = [] self.pixmaps = [] self.dataPoints = None self._plotting(self.data)#initial plotting
class MSQtCanvas(QWidget, MSDialogController): """ DONE:the current peak is not updated while the user press up and down key on the treeView TODO: think about a mjor redesign of those classes """ #linePlotted = pyqtSignal(object, str) #lineRemoved = pyqtSignal(object) def __init__(self, data, title, flags="chroma", parent=None, **k): QWidget.__init__(self, parent) MSDialogController.__init__(self, 0, parent) self.model = self.qApp.model self.view = self.qApp.view self.data = data self.title = title self.flags = flags if self.flags == 'peak': if self.acTree not in (self.view.treeView_2, self.view.treeView_3): print "Unknown Error" return idx = self.acTree.selectedIndexes()[0] s = qApp.instance().dockControl.currentSample[ 1 if self.acTree is self.view.treeView_2 else 2] if s is None: print "unknow error" return values = map(float, idx.data().toString().split('/')[:2]) self.currentPeak = s.peakAt(*values) #connection to update the selected Peak object self.connect(self.acTree, SIGNAL("changedLine"), self.updateCurrentPeak) self.minX, self.maxX, self.maxY = [0] * 3 #if flags != 'peak': # self.minX, self.maxX, self.maxY = self.getMax() self.pw = PlotWidget(self.minX, self.maxX, self.maxY, parent=self, **k) #parent=self, #self.pw.setAttribute(Qt.WA_DeleteOnClose)#plotItem.setAttribute(Qt.WA_PaintOnScreen & Qt.WA_PaintUnclipped) if k.get('antialiased', False): self.pw.setRenderHint(0x01) #antialiasing i suppose self.pw.setTitle(title) self.pw.updateGrid() self._setupUi() self.connect(self, SIGNAL('linePlotted'), self.updateContextMenu) self.connect(self.view.sampleTableView, SIGNAL("disHighlightRequested(QModelIndex)"), self.disHighlightOne) self.connect(self.view.sampleTableView, SIGNAL("highlightRequested(QModelIndex)"), self.highlight) self.connect(self.view.sampleTableView, SIGNAL("noHighlightRequested()"), self.disHighlight) self.connect(self.view.ppmEditer, SIGNAL('valueChanged(double)'), self.redrawAll) self.drawnItems = {} self.trashItems = [] #why unecessary? nope to collect annotation stuff self.textLabels = [] self.pixmaps = [] self.dataPoints = None self._plotting(self.data) #initial plotting def getMax(self): localXmin = [] localXmax = [] localYmax = [] for el in self.data: if el is None: continue localXmin.append(min_f(el.x_data)) localXmax.append(max_f(el.x_data)) localYmax.append(max_l(el.y_data)) return min_f(np.array(localXmin)), max_f(np.array(localXmax)), max_l( np.array(localYmax)) def _plotting(self, data): """ refactor this shit c = Line(chrom.x_data, chrom.y_data, QColor.fromRgbF(*(self.ref.sample.color+(.7,))), parent=self.pw.plotItem.vb, scene=self.pw.scene()) #test scatter plot self.scatter = ScatterPlotItem(x=chrom.x_data, y=chrom.y_data) self.pw.addDataItem(self.scatter) self.scatter.sigClicked.connect(self.requestSpectra) """ if self.flags == 'peak': self.connect(self.pw.plotItem.vb, SIGNAL('showDiffOrSpectra(PyQt_PyObject)'), self.drawSpectra) self.ref = sorted([e for e in data if e is not None], key=lambda x: x.height)[-1] ppm = self.view.ppmEditer.value() if self.view.usePpm.isChecked( ) else self.ref.sample.ppm chrom = self.ref.sample.massExtraction(self.ref.mass(), ppm, asChromatogram=True) #show labels self.textLabels += self.showTextLabel(chrom.x_data, chrom.y_data) #drawing color = QColor.fromRgbF(*self.ref.sample.color + (.5, )) c = self.pw.plotItem.plot(chrom.x_data, chrom.y_data, pen=color) self.drawnItems[self.ref.sample] = c # peak's pixmap on the ref peak pix = PeakArrowItem(self.ref, pen=color, brush=color, pos=(self.ref.rt, self.ref.height + (self.ref.height * 6) / 100.), angle=-90, parent=self.pw.plotItem.vb) pix.setZValue(1000) self.pw.addItem(pix) #both these connections are emitted #in peak Indicator by effictivamente qApp self.connect(qApp.instance(), SIGNAL("highlightRequested"), c.setHighlighted) self.connect(qApp.instance(), SIGNAL('updateBarPlot'), self.barPlot.setPeakGroup) # self.emit(SIGNAL('linePlotted'), self.ref.sample.shortName()) #if qApp.instance().lowMemory: # chromatograms=[el.sample.loadAndExtract(el.mass(), el.sample.ppm, asChromatogram=True) \ # for el in data if el != ref and el is not None] #else: ppm = self.view.ppmEditer.value() if self.view.usePpm.isChecked( ) else self.ref.sample.ppm chromatograms=[el.sample.massExtraction(el.mass(), ppm, asChromatogram=True) \ for el in data if el is not None and el != self.ref] self.drawEics(chromatograms) #initialisation zoom on the peak self.pw.setYRange(0., self.ref.height + (self.ref.height * 12) / 100.) self.pw.setXRange(self.ref.rtmin - 20, self.ref.rtmax + 20) elif self.flags == 'chroma': ref = [d for d in data if d is not None] if not ref: print "Error, empty data to plot" return self.ref = ref[0] self.textLabels += self.showTextLabel(self.ref.x_data, self.ref.y_data) self.drawEics(data) else: #spectrum if not data: #print "NOTHING TO PLOT" return self.ref = data[0] for el in data: c = SpectrumItem(el, centroid=True, scene=self.pw.scene()) self.pw.addItem(c) self.drawnItems[el.sample] = c self.pw.plotItem.curves.append(c) self.emit(SIGNAL('linePlotted'), el.sample.shortName()) #just put time information if data: i = 0 while data[i] is None and i < len(data): i += 1 self.textLabels += self.showTextLabel(data[i].x_data, data[i].y_data) #setting the range #warning: autoRange pw function does not work well #on spectrum item maxY = max([el.y_data.max() for el in data]) minX, maxX = min([el.x_data.min() for el in data ]), max([el.x_data.max() for el in data]) self.pw.setXRange(minX, maxX, padding=0) self.pw.setYRange(0., maxY, padding=0) def drawEics(self, data): for chrom in data: color = QColor.fromRgbF(*(chrom.sample.color + (.5, ))) c = self.pw.plotItem.plot(x=chrom.x_data, y=chrom.y_data, pen=color) #c = Line(chrom.x_data, chrom.y_data, # color, # parent=self.pw.plotItem.vb, # scene=self.pw.scene()) self.drawnItems[chrom.sample] = c #self.pw.addItem(c) #self.pw.plotItem.curves.append(c) self.emit(SIGNAL('linePlotted'), chrom.sample.shortName()) if self.flags != 'peaks': self.pw.autoRange() #=========================================================================== # UI stuffs #=========================================================================== def _setupUi(self): # self.stop = QToolButton() # self.stop.setIcon(QIcon('gui/icons/tools_wizard.png')) # self.stop.setToolTip('Enable or disable the appearance of the contextMenu') layout = QVBoxLayout(self) self.smoothButton = QToolButton() #self.smoothButton.setToolButtonStyle(2) self.smoothButton.setPopupMode(2) self.smoothButton.setToolTip("Smooth the visualized data") #self.smoothButton.setText("Smooth...") self.smoothButton.setIcon( QIcon(os.path.normcase('gui/icons/smooth.png'))) self.smoothMenu = QMenu() self.connect(self.smoothMenu, SIGNAL('triggered(QAction*)'), self.smooth) self.smoothButton.setMenu(self.smoothMenu) self.pw.plotItem.toolBar.addWidget(self.smoothButton) self.flipButton = QToolButton() #self.flipButton.setToolButtonStyle(2) self.flipButton.setIcon(QIcon(os.path.normcase('gui/icons/flip.png'))) self.flipButton.setToolTip("Flip the visualized data") #self.flipButton.setText("Flip...") self.flipButton.setPopupMode(2) self.flipMenu = QMenu() self.connect(self.flipMenu, SIGNAL('triggered(QAction*)'), self.flip) self.flipButton.setMenu(self.flipMenu) self.pw.plotItem.toolBar.addWidget(self.flipButton) self.annotButton = QToolButton() #self.annotButton.setToolButtonStyle(2) self.annotButton.setPopupMode(2) #self.annotButton.setText("&Annotate...") self.annotButton.setIcon( QIcon(os.path.normcase('gui/icons/attach.png'))) self.annotMenu = QMenu() self.annotMenu.addAction("&Add Annotation") self.annotMenu.addAction("&Remove last Annotation") self.annotMenu.addAction("&Remove All Annotation") self.annotButton.setMenu(self.annotMenu) self.connect(self.annotMenu.actions()[0], SIGNAL("triggered()"), self.annotate) self.connect(self.annotMenu.actions()[1], SIGNAL("triggered()"), self.removeLastAnnot) self.connect(self.annotMenu.actions()[2], SIGNAL("triggered()"), self.removeAllAnnot) self.pw.plotItem.toolBar.addWidget(self.annotButton) self.addPlotButton = QToolButton() #self.addPlotButton.setToolButtonStyle(2) self.addPlotButton.setText("Add...") self.addPlotButton.setIcon( QIcon(os.path.normcase('gui/icons/list_add.png'))) self.addPlotButton.setToolTip("Add a new plot to the current figure") #self.addPlotButton.setText('&Add Plot') self.pw.plotItem.toolBar.addWidget(self.addPlotButton) self.showSpectra = QToolButton() self.showSpectra.setPopupMode(2) #instant popup #self.showSpectra.setToolButtonStyle(2) self.showSpectra.setIcon( QIcon(os.path.normcase('gui/icons/file_export.png'))) #self.showSpectra.setText('&Show /hide...') self.showSpectra.setToolTip('Show/hide ...') self.showMenu = QMenu() self.showTextLabels = QAction("&Show Labels", self.showMenu) self.showTextLabels.setCheckable(True) self.showTextLabels.setChecked(True) self.showMenu.addAction(self.showTextLabels) self.connect(self.showMenu.actions()[0], SIGNAL('toggled(bool)'), self.setTextLabelsVisibility) showSpectrum = QAction("&Merged Spectrum", self.showMenu) showSpectrum.setCheckable(True) if self.flags == 'chroma' or self.flags == 'spectra': showSpectrum.setEnabled(False) self.showMenu.addAction(showSpectrum) self.connect(self.showMenu.actions()[1], SIGNAL('toggled(bool)'), self.drawSpectraRequested) showNonXCMSPeak = QAction("&Show Non XCMS Peak", self.showMenu) showNonXCMSPeak.setCheckable(True) if self.flags == 'spectra': showNonXCMSPeak.setEnabled(False) self.showMenu.addAction(showNonXCMSPeak) self.connect(self.showMenu.actions()[2], SIGNAL('toggled(bool)'), self.setPixmapVisibility) showDataPoints = QAction("&Show DataPoints", self.showMenu) showDataPoints.setCheckable(True) showDataPoints.setChecked(False) self.showMenu.addAction(showDataPoints) self.connect(self.showMenu.actions()[3], SIGNAL('toggled(bool)'), self.setDataPointsVisibility) self.showSpectra.setMenu(self.showMenu) self.pw.plotItem.toolBar.addWidget(self.showSpectra) self.saveToPng = QToolButton() self.saveToPng.setIcon( QIcon(os.path.normcase('gui/icons/thumbnail.png'))) #self.saveToPng.setToolButtonStyle(2) #self.saveToPng.setText("Save to Png...") self.pw.plotItem.toolBar.addWidget(self.saveToPng) self.connect(self.saveToPng, SIGNAL('clicked()'), self.pw.writeImage) #add bar plot even if we are plotting chroma #cause we can find non xcms peaks self.barPlot = BarPlot(scene=self.pw.sceneObj) #self.barPlot.rotate(-90.) if self.flags == 'peak': self.barPlot.setPeakGroup(self.data) #TODO modify to get this close to us #on the left part xpos = self.barPlot.scene().width() * 3.5 #-bwidth; ypos = self.barPlot.scene().height() * 1.1 self.barPlot.setPos(xpos, ypos) self.barPlot.setZValue(1000) layout.addWidget(self.pw) layout.addWidget(self.pw.plotItem.toolBar) def showTextLabel(self, x, y, secure=25): """ add labels of principle peaks of spectrum or chroma on the plot, return the labels, that we can show hide """ maxis = [] #will contain tuple(rt, intens) indexes = [] #from core.MetObjects import MSAbstractTypes from scipy.ndimage import gaussian_filter1d as gauss z = gauss(y, 1) #z = MSAbstractTypes.computeBaseLine(z, 92., 0.8) i = 0 while i < len(z) - 1: while z[i + 1] >= z[i] and i < len(y) - 2: i += 1 maxis.append((x[i], y[i])) indexes.append(i) while z[i + 1] <= z[i] and i < len(z) - 2: i += 1 i += 1 labels = [] for t in sorted(maxis, key=lambda x: x[1])[-5:]: g = QGraphicsTextItem(str(t[0])) g.setFlag(QGraphicsItem.ItemIgnoresTransformations) font = QApplication.font() font.setPointSizeF(6.5) g.setFont(font) g.setDefaultTextColor(Qt.black) g.setPos(t[0], t[1]) labels.append(g) self.pw.addItem(g) return labels #=============================================================================== #SLOTS #=============================================================================== def redrawAll(self, value): self.pw.clear() self._plotting(self.data) def disHighlightOne(self, idx): if not idx.isValid(): return sample = self.model.sample(idx.data().toString(), fullNameEntry=False) if sample is None: return try: self.drawnItems[sample].setHighlighted(False) except KeyError: pass def highlight(self, idx): if not idx.isValid(): return sample = self.model.sample(idx.data().toString(), fullNameEntry=False) if sample is None: return try: self.drawnItems[sample].setHighlighted(True) except KeyError: pass #print "sample not found" self.pw.plotItem.update() #works def disHighlight(self): for key in self.drawnItems.iterkeys(): self.drawnItems[key].setHighlighted(False) self.pw.plotItem.update() def setTextLabelsVisibility(self, bool_): for t in self.textLabels: t.setVisible(bool_) def setDataPointsVisibility(self, b): if self.dataPoints is None: if self.flags == 'peak': chrom = self.ref.sample.massExtraction(self.ref.mass(), self.ref.sample.ppm, asChromatogram=True) self.dataPoints = ScatterPlotItem(x=chrom.x_data, y=chrom.y_data) else: self.dataPoints = ScatterPlotItem(x=self.ref.x_data, y=self.ref.y_data) if self.flags != 'spectra': self.dataPoints.sigClicked.connect(self.requestSpectra) self.pw.addDataItem(self.dataPoints) self.dataPoints.setVisible(b) def setPixmapVisibility(self, bool_): """ draw other peaks than the xcms peak """ if not self.pixmaps and bool_: ppm = 1. if self.ref.sample.kind == 'MRM' else self.ref.sample.ppm chrom = self.ref.sample.massExtraction(self.ref.mass(), ppm, asChromatogram=True) \ if self.flags == 'peak' else self.ref chrom.findNonXCMSPeaks() for p in chrom.peaks.ipeaks(): if self.flags == 'peak': diff = (p.height * 10) / 100 if abs(p.height - self.ref.height) < diff: continue #we assume that they are the same peaks pix = PeakIndicator(p, icon='flags') #self.connect(pix, SIGNAL("highlightRequested"), c.setHighlighted) self.connect(pix, SIGNAL('updateBarPlot'), self.barPlot.setPeakGroup) pix.setPos(p.rt, p.height + (p.height * 10) / 100.) pix.setZValue(1000) self.pixmaps.append(pix) self.pw.addItem(pix) if self.pixmaps: for t in self.pixmaps: t.setVisible(bool_) @pyqtSlot() def updateCurrentPeak(self): idx = self.acTree.selectedIndexes()[0] s = self.model.sample(idx.parent().data().toString(), fullNameEntry=False) if s is not None: self.currentPeak = s.peakAt(*map(float, idx.data().toString().split('/'))) def requestSpectra(self, scatter, l): """ idea plot all spectra between a time range and not only with only one spectra """ if not l: return ref = l[0] self.emit(SIGNAL("drawSpectrumByTime"), ref.pos(), self.ref.sample) @pyqtSlot() def drawSpectraRequested(self, bool_): """ i think this is for plotting merged spectrum """ if bool_: self.emit(SIGNAL('drawSpectraRequested'), self.currentPeak) else: self.hideRequested() def drawSpectra(self, l): self.emit( SIGNAL('drawSpectra(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'), l[0], l[1], self.ref.sample) @pyqtSlot() def hideRequested(self): self.emit(SIGNAL('hideRequested')) self.showMenu.actions()[1].setChecked(False) @pyqtSlot() def redraw(self): """ this is for updating the view port when hiding or not samples """ chromas = [] for spl in self.model: if spl.checked: if spl in self.drawnItems.keys(): self.drawnItems[spl].setVisible(True) else: chromas.append(spl.chroma[0]) else: self.drawnItems[spl].setVisible(False) self._plotting(chromas) self.pw.plotItem.update() #works def cleanScene(self): """ remove all items in the trash """ for element in self.trashItems: self.pw.sceneObj.removeItem(element) @pyqtSlot() def updateContextMenu(self, line): self.flipMenu.addAction(line) self.smoothMenu.addAction(line) #=============================================================================== # CONTEXT MENU SLOTS #=============================================================================== @pyqtSlot(str) def flip(self, action): spl = self.model.sample(self.fullXmlPath(action.text())) if spl is None: print "can not flip, can not recognize the selected sample" return try: self.drawnItems[spl].updateData(-self.drawnItems[spl].getData()[1], self.drawnItems[spl].getData()[0]) except KeyError: pass if len(self.data) == 1: #we are flipping the text labels only #if only one dataset is flipped for item in self.textLabels: item.setPos(item.pos().x(), -item.pos().y()) @pyqtSlot(str) def smooth(self, action): """ TODO: would be good to reuse the widget in the menuControl """ from core.MetObjects import MSAbstractTypes class Dial(QDialog): choices = ['flat', 'hanning', 'hamming', 'bartlett', 'blackman'] def __init__(self, parent): QDialog.__init__(self, parent) f = QFormLayout(self) self.a = QSpinBox(self) self.a.setValue(30) self.b = QComboBox(self) self.b.addItems(self.choices) self.c = QDialogButtonBox(self) self.c.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) f.addRow("window:", self.a) f.addRow("method:", self.b) f.addRow("", self.c) self.connect(self.c, SIGNAL("accepted()"), self.sendData) self.connect(self.c, SIGNAL("rejected()"), self.reinitialize) def sendData(self): self.parent().window = self.a.value() self.parent().method = self.b.currentText() self.close() def reinitialize(self): self.parent().window = None self.parent().method = None self.close() Dial(self).exec_() if self.window and self.method: for spl in self.drawnItems.keys(): if action.text() == spl.shortName(): self.drawnItems[spl].updateData( MSAbstractTypes.averageSmoothing( self.drawnItems[spl].getData()[1], self.window, self.method), self.drawnItems[spl].getData()[0]) @pyqtSlot() def plotEIC(self): if self.flags == 'spectra': #show double combobox #select the good spectra then draw pass else: mass, ok = QInputDialog.getText(self.view, "EIC query", "mass:") if not (mass and ok): return xmlfile = self.fullXmlPath(self.selection[0].data().toString()) if not xmlfile: xmlfile = self.fullXmlPath( self.selection[0].parent().data().toString()) if not xmlfile: print "item clicked not recognized..." return sample = self.model.sample(xmlfile) if sample.kind == 'HighRes': error = (sample.ppm / 1e6) * float(mass) x, y = massExtraction(sample, float(mass), error) from core.MetObjects import MSChromatogram chrom = MSChromatogram(x_data=x, y_data=y, sample=sample) else: chrom = sample.getChromWithTrans(math.ceil(float(mass))) self.view.addMdiSubWindow( MSQtCanvas([chrom], "EIC %s" % str(mass), labels={ 'bottom': 'RT(s)', 'left': 'INTENSITY' })) #=========================================================================== # annotate stuff #=========================================================================== @pyqtSlot() def annotate(self): text, bool_ = QInputDialog.getText(self.view, "Annotation dialog", "Annotation:") g = QGraphicsTextItem(str(text)) g.setFlag(QGraphicsItem.ItemIgnoresTransformations) g.setFlag(QGraphicsItem.ItemIsMovable) g.setTextInteractionFlags(Qt.TextEditorInteraction) font = qApp.instance().font() font.setPointSizeF(10.) g.setFont(font) g.setDefaultTextColor(Qt.blue) g.setPos(500, 1e4) self.trashItems.append(g) self.pw.addItem(g) def removeAllAnnot(self): if not self.trashItems: self.view.showErrorMessage("Error", "No annotation detected") return for i in self.trashItems: self.pw.removeItem(i) def removeLastAnnot(self): if not self.trashItems: self.view.showErrorMessage("Error", "No annotation detected") self.pw.removeItem(self.trashItems[-1])
def __init__(self, R, parent=None): super(ToolsFrame, self).__init__(parent) # r engine # self.R = R # tabs # self.toolTabs = QTabWidget() # log tab # self.rLogGroup = QGroupBox() self.rlogLayout = QGridLayout() self.logStats = QLabel() self.logList = QListWidget() self.logClear = QToolButton() self.logSearh = QLineEdit() self.rlogLayout.addWidget(self.logStats, 0, 0, 1, 2) self.rlogLayout.addWidget(self.logList, 1, 0, 1, 2) self.rlogLayout.addWidget(self.logSearh, 2, 0) self.rlogLayout.addWidget(self.logClear, 2, 1) self.rLogGroup.setLayout(self.rlogLayout) self.toolTabs.addTab(self.rLogGroup, "Lo&g") # r console tab # self.rConsoleGroup = QGroupBox() self.rConsoleLayout = QGridLayout() self.rEnable = QLabel("R console is for testing purposes only, and by default is disabled.") self.rConsole = QTextEdit() self.rInput = QLineEdit() self.enterButton = QToolButton() self.clearButton = QToolButton() self.namespaceButton = QToolButton() self.namesList = QListWidget() self.rConsoleLayout.addWidget(self.rConsole, 0, 0, 1, 5) self.rConsoleLayout.addWidget(self.rInput, 1, 0, 1, 2) self.rConsoleLayout.addWidget(self.enterButton, 1, 2, 1, 1) self.rConsoleLayout.addWidget(self.clearButton, 1, 3, 1, 1) self.rConsoleLayout.addWidget(self.namespaceButton, 1, 4, 1, 1) self.rConsoleLayout.addWidget(self.namesList, 2, 0, 1, 5) self.rConsoleLayout.addWidget(self.rEnable, 3, 0, 1, 5) self.rConsoleGroup.setLayout(self.rConsoleLayout) self.toolTabs.addTab(self.rConsoleGroup, "&R") # graphs tab # self.plotWidget = PlotWidget() self.data = None geometry = self.saveGeometry() self.toolTabs.addTab(self.plotWidget, "Grap&h") self.restoreGeometry(geometry) # table tab # self.tableWidget = QTableWidget() self.toolTabs.addTab(self.tableWidget, "Ta&ble") # export tab # self.exportGroup = QGroupBox() self.exportLayout = QGridLayout() self.exportForecast = QCheckBox("Export resulting forecast") self.exportStepByStep = QCheckBox("Export modelling steps") self.exportGraph = QCheckBox("Export graphics") self.exportData = QCheckBox("Export data") self.exportAll = QPushButton("Export all") self.exportButton = QPushButton("Export as") self.picLbl = QLabel() self.exportLayout.addWidget(self.picLbl, 0, 0, 1, 2) self.exportLayout.addWidget(self.exportForecast, 1, 0) self.exportLayout.addWidget(self.exportStepByStep, 1, 1) self.exportLayout.addWidget(self.exportData, 2, 0) self.exportLayout.addWidget(self.exportGraph, 2, 1) self.exportLayout.addWidget(self.exportAll, 3, 0) self.exportLayout.addWidget(self.exportButton, 3, 1) self.exportGroup.setLayout(self.exportLayout) self.toolTabs.addTab(self.exportGroup, "&Export") # global layout # self.mainLayout = QVBoxLayout() # hover area # self.hoverLayout = QHBoxLayout() self.upScale = QToolButton() self.fixSize = QToolButton() self.toolDetached = QToolButton() self.hoverArea = QLabel() self.hoverLayout.addWidget(self.upScale) self.hoverLayout.addWidget(self.fixSize) self.hoverLayout.addWidget(self.toolDetached) self.mainLayout.addWidget(self.hoverArea) self.mainLayout.addLayout(self.hoverLayout) self.mainLayout.addWidget(self.toolTabs) self.setLayout(self.mainLayout) # flags # self.flash = False self.shownHoverInfo = False # initialization # self.initComposition() self.initComponents() self.initActions() # post init # self.rInput.setFocus() self.inStack = {"stack": [], "index": -1} self.toggleLogControls() self.rNewline = "\n"
class ToolsFrame(QWidget): def __init__(self, R, parent=None): super(ToolsFrame, self).__init__(parent) # r engine # self.R = R # tabs # self.toolTabs = QTabWidget() # log tab # self.rLogGroup = QGroupBox() self.rlogLayout = QGridLayout() self.logStats = QLabel() self.logList = QListWidget() self.logClear = QToolButton() self.logSearh = QLineEdit() self.rlogLayout.addWidget(self.logStats, 0, 0, 1, 2) self.rlogLayout.addWidget(self.logList, 1, 0, 1, 2) self.rlogLayout.addWidget(self.logSearh, 2, 0) self.rlogLayout.addWidget(self.logClear, 2, 1) self.rLogGroup.setLayout(self.rlogLayout) self.toolTabs.addTab(self.rLogGroup, "Lo&g") # r console tab # self.rConsoleGroup = QGroupBox() self.rConsoleLayout = QGridLayout() self.rEnable = QLabel("R console is for testing purposes only, and by default is disabled.") self.rConsole = QTextEdit() self.rInput = QLineEdit() self.enterButton = QToolButton() self.clearButton = QToolButton() self.namespaceButton = QToolButton() self.namesList = QListWidget() self.rConsoleLayout.addWidget(self.rConsole, 0, 0, 1, 5) self.rConsoleLayout.addWidget(self.rInput, 1, 0, 1, 2) self.rConsoleLayout.addWidget(self.enterButton, 1, 2, 1, 1) self.rConsoleLayout.addWidget(self.clearButton, 1, 3, 1, 1) self.rConsoleLayout.addWidget(self.namespaceButton, 1, 4, 1, 1) self.rConsoleLayout.addWidget(self.namesList, 2, 0, 1, 5) self.rConsoleLayout.addWidget(self.rEnable, 3, 0, 1, 5) self.rConsoleGroup.setLayout(self.rConsoleLayout) self.toolTabs.addTab(self.rConsoleGroup, "&R") # graphs tab # self.plotWidget = PlotWidget() self.data = None geometry = self.saveGeometry() self.toolTabs.addTab(self.plotWidget, "Grap&h") self.restoreGeometry(geometry) # table tab # self.tableWidget = QTableWidget() self.toolTabs.addTab(self.tableWidget, "Ta&ble") # export tab # self.exportGroup = QGroupBox() self.exportLayout = QGridLayout() self.exportForecast = QCheckBox("Export resulting forecast") self.exportStepByStep = QCheckBox("Export modelling steps") self.exportGraph = QCheckBox("Export graphics") self.exportData = QCheckBox("Export data") self.exportAll = QPushButton("Export all") self.exportButton = QPushButton("Export as") self.picLbl = QLabel() self.exportLayout.addWidget(self.picLbl, 0, 0, 1, 2) self.exportLayout.addWidget(self.exportForecast, 1, 0) self.exportLayout.addWidget(self.exportStepByStep, 1, 1) self.exportLayout.addWidget(self.exportData, 2, 0) self.exportLayout.addWidget(self.exportGraph, 2, 1) self.exportLayout.addWidget(self.exportAll, 3, 0) self.exportLayout.addWidget(self.exportButton, 3, 1) self.exportGroup.setLayout(self.exportLayout) self.toolTabs.addTab(self.exportGroup, "&Export") # global layout # self.mainLayout = QVBoxLayout() # hover area # self.hoverLayout = QHBoxLayout() self.upScale = QToolButton() self.fixSize = QToolButton() self.toolDetached = QToolButton() self.hoverArea = QLabel() self.hoverLayout.addWidget(self.upScale) self.hoverLayout.addWidget(self.fixSize) self.hoverLayout.addWidget(self.toolDetached) self.mainLayout.addWidget(self.hoverArea) self.mainLayout.addLayout(self.hoverLayout) self.mainLayout.addWidget(self.toolTabs) self.setLayout(self.mainLayout) # flags # self.flash = False self.shownHoverInfo = False # initialization # self.initComposition() self.initComponents() self.initActions() # post init # self.rInput.setFocus() self.inStack = {"stack": [], "index": -1} self.toggleLogControls() self.rNewline = "\n" # self.rNewline = self.R.newline # glitches starting with R 2.13 def initComposition(self): self.setWindowTitle("Tools") self.setWindowFlags(Qt.Tool) self.setMinimumSize(T_WIDTH, T_HEIGHT) self.setFocusPolicy(Qt.StrongFocus) def initComponents(self): self.setStyleSheet( """QGroupBox {""" + GRADIENT + """} QPushButton { color: #333; border: 1px solid #555; border-radius: 11px; padding: 2px; background: qradialgradient(cx: 0.3, cy: -0.4, fx: 0.3, fy: -0.4, radius: 1.35, stop: 0 #fff, stop: 1 #888); min-width: 80px; } QPushButton:hover { color: #fff; background: qradialgradient(cx: 0.3, cy: -0.4, fx: 0.3, fy: -0.4, radius: 1.35, stop: 0 #fff, stop: 1 #bbb);} QPushButton:pressed { background: qradialgradient(cx: 0.4, cy: -0.1, fx: 0.4, fy: -0.1, radius: 1.35, stop: 0 #fff, stop: 1 #ddd);} QPushButton:checked { background: qradialgradient(cx: 0.4, cy: -0.1, fx: 0.4, fy: -0.1, radius: 1.35, stop: 0 #fff, stop: 1 #ddd);} QToolButton { color: #333; border: 1px solid #555; border-radius: 11px; padding: 2px; background: qradialgradient(cx: 0.3, cy: -0.4, fx: 0.3, fy: -0.4, radius: 1.35, stop: 0 #fff, stop: 1 #888); min-width: 20px; } QToolButton:hover { color: #fff; background: qradialgradient(cx: 0.3, cy: -0.4, fx: 0.3, fy: -0.4, radius: 1.35, stop: 0 #fff, stop: 1 #bbb); } QToolButton:pressed { background: qradialgradient(cx: 0.4, cy: -0.1, fx: 0.4, fy: -0.1, radius: 1.35, stop: 0 #fff, stop: 1 #ddd); } QToolButton:checked { background: qradialgradient(cx: 0.4, cy: -0.1, fx: 0.4, fy: -0.1, radius: 1.35, stop: 0 #fff, stop: 1 #ddd); } QTabWidget::tab-bar { alignment: center; } QTabBar::tab {""" + GRADIENT + """border: 1px solid #C4C4C3; border-bottom-color: #C2C7CB; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; min-width: 16ex; padding: 2px; } QTabBar::tab:selected, QTabBar::tab:hover { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #fafafa, stop: 0.4 #f4f4f4, stop: 0.5 #e7e7e7, stop: 1.0 #fafafa); } QTabBar::tab:selected { border-color: #9B9B9B; border-bottom-color: #C2C7CB; } QTabBar::tab:!selected { margin-bottom: 2px; } QTabBar::tab:selected { margin-left: -4px; margin-right: -4px; } QTabBar::tab:first:selected { margin-left: 0; } QTabBar::tab:last:selected { margin-right: 0; } QTabBar::tab:only-one { margin: 0; } QLineEdit { border: 2px solid gray; border-radius: 6px; } QLineEdit:focus { selection-color: white; selection-background-color: gray; border: 2px solid black; border-radius: 6px; } QScrollBar:vertical { width: 20px; border: 1px solid grey; border-radius: 6px; background-color: transparent; margin: 28px 0 28px 0; } QScrollBar::add-line:vertical { background: transparent; height: 32px; subcontrol-position: bottom; subcontrol-origin: margin; } QScrollBar::sub-line:vertical { background: transparent; height: 32px; subcontrol-position: top; subcontrol-origin: margin; } QScrollBar::up-arrow:vertical { width: 20px; height: 32px; background: transparent; image: url(../res/icons/arrow_up.png); } QScrollBar::up-arrow:hover { bottom: 2px; } QScrollBar::down-arrow:vertical { width: 20px; height: 32px; background: transparent; image: url(../res/icons/arrow_down.png); } QScrollBar::down-arrow:hover { top: 2px; } QScrollBar::handle:vertical { border-radius: 6px; background: url(../res/icons/handle.png) 0% center no-repeat; background-color: white; min-height: 32px; } QScrollBar::handle:hover { background: url(../res/icons/handle_hover.png) 0% center no-repeat; background-color: white; border: 1px solid gray; } QScrollBar:horizontal { height: 20px; border: 1px solid grey; border-radius: 6px; background-color: transparent; margin: 0 28px 0 28px; } QScrollBar::add-line:horizontal { background: transparent; width: 32px; subcontrol-position: right; subcontrol-origin: margin; } QScrollBar::sub-line:horizontal { background: transparent; width: 32px; subcontrol-position: left; subcontrol-origin: margin; } QScrollBar::left-arrow:horizontal { width: 32px; height: 20px; background: transparent; image: url(../res/icons/arrow_left.png); } QScrollBar::left-arrow:hover { right: 2px; } QScrollBar::right-arrow:horizontal { width: 32px; height: 20px; background: transparent; image: url(../res/icons/arrow_right.png); } QScrollBar::right-arrow:hover { left: 2px; } QScrollBar::handle:horizontal { border-radius: 6px; background: url(../res/icons/handle_horizontal.png) 0% center no-repeat; background-color: white; min-width: 32px; } QCheckBox::indicator { width: 16px; height: 16px; } QCheckBox::indicator:unchecked { image: url(../res/icons/checkbox_no.png); } QCheckBox::indicator:checked { image: url(../res/icons/checkbox_yes.png); } QCheckBox::indicator:unchecked:pressed { image: url(../res/icons/checkbox_pressed.png); } QCheckBox::indicator:unchecked:hover { background: gray; border-radius: 4px; } QCheckBox::indicator:checked:pressed { image: url(../res/icons/checkbox_pressed.png); } QCheckBox::indicator:checked:hover { background: gray; border-radius: 4px; }""" ) # layout and tabs self.toolTabs.setTabPosition(QTabWidget.South) self.upScale.setText("&Upscale") self.upScale.setMaximumHeight(18) self.upScale.setCheckable(True) self.upScale.setHidden(True) self.fixSize.setText("&Lock vertical resize") self.fixSize.setMaximumHeight(18) self.fixSize.setCheckable(True) self.fixSize.setHidden(True) self.toolDetached.setText("&Detach") self.toolDetached.setMaximumHeight(18) self.toolDetached.setCheckable(True) self.toolDetached.setHidden(True) self.hoverArea.setMaximumHeight(2) self.hoverArea.setAlignment(Qt.AlignCenter) self.hoverLayout.setAlignment(Qt.AlignCenter) self.mainLayout.setAlignment(Qt.AlignCenter) # r console # self.enterButton.setText("enter") self.enterButton.setCheckable(True) self.clearButton.setText("clear") self.namespaceButton.setText("..") self.namespaceButton.setCheckable(True) self.rEnable.setAlignment(Qt.AlignCenter) self.rEnable.setWordWrap(True) self.rEnable.setFont(QFont(FONTS_DICT["warn"][0], FONTS_DICT["warn"][2])) self.rEnable.setStyleSheet("QLabel { border: none; color: gray; }") self.rConsole.setReadOnly(True) self.rConsole.setStyleSheet( """QTextEdit::focus { border: 2px solid black; border-radius: 6px; }""" ) self.namesList.setHidden(True) self.namesList.setContextMenuPolicy(Qt.ActionsContextMenu) self.namesList.setAlternatingRowColors(True) self.namesList.setStyleSheet( """QListView::item:selected:active { background: qlineargradient(x1: 1, y1: 0, x2: 0, y2: 3, stop: 0 #cbdaf1, stop: 1 #bfcde4); } QListView::item { border: 1px solid #d9d9d9; border-top-color: transparent; border-bottom-color: transparent; } QListView::item:hover { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #e7effd, stop: 1 #cbdaf1); border: 1px solid #bfcde4; } QListView::focus { border: 2px solid black; border-radius: 6px; }""" ) # hide r components self.enterButton.hide() self.clearButton.hide() self.namespaceButton.hide() self.namesList.hide() self.rInput.hide() self.rConsole.hide() # table # self.tableWidget.setContextMenuPolicy(Qt.ActionsContextMenu) self.tableWidget.setAlternatingRowColors(True) # graph # self.plotWidget.plot() # log # self.logList.setSelectionMode(QAbstractItemView.ExtendedSelection) self.logList.setAlternatingRowColors(True) self.logList.setContextMenuPolicy(Qt.ActionsContextMenu) self.logList.setWordWrap(True) self.logList.setToolTip("Doubleclick to copy") self.logClear.setText("Clear") self.logStats.setAlignment(Qt.AlignCenter) self.logStats.hide() self.logList.setStyleSheet( """QListView { alternate-background-color: whitesmoke; } QListView::item { border: 1px solid #d9d9d9; border-top-color: transparent; border-bottom-color: transparent; } QListView::item:selected { border: 1px solid dimgray; border-radius: 4px; } QListView::item:selected:active { background: qlineargradient(x1: 1, y1: 0, x2: 0, y2: 3, stop: 0 #cbdaf1, stop: 1 #bfcde4); } QListView::item:hover { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #e7effd, stop: 1 #cbdaf1); border: 1px solid #bfcde4; } QListView::focus { border: 2px solid black; border-radius: 6px; }""" ) # table # self.tableWidget.setStyleSheet( """QTableView::item:selected:active { background: qlineargradient(x1: 1, y1: 0, x2: 0, y2: 3, stop: 0 #cbdaf1, stop: 1 #bfcde4); } QTableView::item { border: 1px solid #d9d9d9; border-top-color: transparent; border-bottom-color: transparent; } QTableView::item:hover { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #e7effd, stop: 1 #cbdaf1); border: 1px solid #bfcde4; } QTableView::focus { border: 2px solid black; border-radius: 6px; }""" ) # fonts # self.logList.setFont(QFont(FONTS_DICT["log"][0], FONTS_DICT["log"][2])) self.tableWidget.setFont(QFont(FONTS_DICT["table"][0], FONTS_DICT["table"][2])) # export # self.exportLayout.setAlignment(Qt.AlignCenter) self.exportData.hide() self.exportGraph.hide() self.picLbl.setPixmap(QPixmap(RES + ICONS + GRAPH)) self.picLbl.setAlignment(Qt.AlignCenter) self.picLbl.hide() # hotkeys # # ... def initActions(self): # R self.rInput.returnPressed.connect(self.rCommand) self.clearButton.clicked.connect(self.clearRConsole) self.namespaceButton.clicked.connect(self.viewNamespace) self.namesList.itemDoubleClicked.connect(self.appendItemInline) self.rFilter = RFilter() self.rEnable.setAttribute(Qt.WA_Hover, True) self.rEnable.installEventFilter(self.rFilter) self.namesList.addAction( QAction(QIcon(RES + ICONS + GRAPH), "Plot selected object", self, triggered=self.plotFromR) ) # dialog self.upScale.clicked.connect(self.changeScale) self.filter = StatusFilter() self.hoverArea.setAttribute(Qt.WA_Hover, True) self.hoverArea.installEventFilter(self.filter) # log self.logClear.clicked.connect(self.clearEntries) self.logSearh.textChanged.connect(self.highlightSearch) self.logSearh.returnPressed.connect(self.logSearh.clear) self.logList.itemDoubleClicked.connect(self.copyToClipboard) self.logList.addAction( QAction(QIcon(RES + ICONS + CONTROLS), "Toggle controls", self, triggered=self.toggleLogControls) ) # table self.tableWidget.addAction(QAction(QIcon(RES + ICONS + CLEAR), "Clear all", self, triggered=self.clearTable)) self.tableWidget.addAction( QAction(QIcon(RES + ICONS + COPY), "Copy selected column(s)", self, triggered=self.copyColumns) ) self.tableWidget.addAction( QAction(QIcon(RES + ICONS + ELEMENTS), "Copy selected item(s)", self, triggered=self.copyItems) ) self.tableWidget.addAction( QAction(QIcon(RES + ICONS + CUT), "Remove selected column(s)", self, triggered=self.removeColumns) ) self.tableWidget.addAction( QAction(QIcon(RES + ICONS + GRAPH), "Plot selected items", self, triggered=self.plotItems) ) self.tableWidget.addAction( QAction(QIcon(RES + ICONS + SCALE), "Resize to contents", self, triggered=self.resizeTableToFit) ) # export exportMenu = QMenu() exportMenu.addAction(QAction("Microsoft Excel Spreadsheet (XLS)", self, triggered=self.exportToXls)) toPDF = QAction("Portable Document Format (PDF)", self, triggered=self.exportToPdf) toTXT = QAction("Plain text (TXT) && PNG", self, triggered=self.exportToVarious) toPrint = QAction("Send to print", self, triggered=self.sendToPrint) exportMenu.addAction(toPrint) exportMenu.addAction(toTXT) exportMenu.addAction(toPDF) toTXT.setDisabled(True) toPDF.setDisabled(True) toPrint.setDisabled(True) self.exportButton.setMenu(exportMenu) self.exportForecast.stateChanged.connect(self.toggleExportOptions) self.exportStepByStep.stateChanged.connect(self.toggleExportOptions) self.exportGraph.stateChanged.connect(self.updatePix) self.exportAll.clicked.connect(self.exportAllXls) # --------- actions ---------# # -------- export ----------# def exportAllXls(self): self.exportForecast.setChecked(True) self.exportStepByStep.setChecked(True) self.exportData.setChecked(True) self.exportGraph.setChecked(True) self.toggleExportOptions() self.exportToXls() def toggleExportOptions(self): if self.exportForecast.isChecked() or self.exportStepByStep.isChecked(): self.exportData.show() self.exportGraph.show() self.updatePix() else: self.exportData.hide() self.exportGraph.hide() self.picLbl.hide() def updatePix(self): if self.exportForecast.isChecked() and self.exportStepByStep.isChecked() and self.exportGraph.isChecked(): self.picLbl.setPixmap(QPixmap(RES + ICONS + SERIES[2])) elif self.exportForecast.isChecked() and self.exportStepByStep.isChecked(): self.picLbl.setPixmap(QPixmap(RES + ICONS + SERIES[1])) self.picLbl.show() elif self.exportForecast.isChecked(): self.picLbl.setPixmap(QPixmap(RES + ICONS + SERIES[0])) self.picLbl.show() elif self.exportStepByStep.isChecked(): self.picLbl.setPixmap(QPixmap(RES + ICONS + SERIES[3])) self.picLbl.show() else: self.picLbl.hide() def exportToPdf(self): # QPrinter # http://goo.gl/AgX3l # http://goo.gl/K5zg4 pass def exportToXls(self): # opening file dialog fileName = QFileDialog.getSaveFileName(self, "Save as", RES, "Microsoft Excel Spreadsheet (*.xls)") if fileName.count() > 0: try: COLUMN_WIDTH = 3000 alignment = Alignment() alignment.horizontal = Alignment.HORZ_CENTER alignment.vertical = Alignment.VERT_CENTER borders = Borders() borders.left = Borders.THIN borders.right = Borders.THIN borders.top = Borders.THIN borders.bottom = Borders.THIN style = XFStyle() style.alignment = alignment style.borders = borders font = Font() font.bold = True headerStyle = XFStyle() headerStyle.font = font separate = Borders() separate.left = Borders.THIN separate.right = Borders.DOUBLE separate.top = Borders.THIN separate.bottom = Borders.THIN separateStyle = XFStyle() separateStyle.borders = separate book = Workbook(encoding="utf-8") # modelling data if self.exportStepByStep.isChecked(): dec_sheet = book.add_sheet("Data decomposition") # decomposition data if self.exportData.isChecked(): # initial data column = 0 row = 0 dec_sheet.write(row, column, "Time series", headerStyle) dec_sheet.col(column).width = COLUMN_WIDTH row += 1 for item in self.parentWidget().currentDataSet[0]: dec_sheet.write(row, column, item, separateStyle) row += 1 # decomposition for lvl in self.parentWidget().wCoefficients: row = 0 column += 1 dec_sheet.write(row, column, "Level" + str(column - 1), headerStyle) dec_sheet.col(column).width = COLUMN_WIDTH row += 1 for item in lvl: dec_sheet.write(row, column, item, style) row += 1 # decomposition graphs if self.exportGraph.isChecked(): pass levels_sheet = book.add_sheet("Multiscale forecast") # levels data if self.exportData.isChecked(): column = 0 for lvl in self.parentWidget().processedWCoeffs: row = 0 levels_sheet.write(row, column, "Level" + str(column), headerStyle) levels_sheet.col(column).width = COLUMN_WIDTH row += 1 for item in lvl: levels_sheet.write(row, column, float(item), style) row += 1 column += 1 if self.exportForecast.isChecked(): result_sheet = book.add_sheet("Results") if self.exportData.isChecked(): # initial column = 0 row = 0 result_sheet.write(row, column, "Initial data", headerStyle) result_sheet.col(column).width = COLUMN_WIDTH row += 1 for item in self.parentWidget().currentDataSet[0]: result_sheet.write(row, column, item, separateStyle) row += 1 # forecast row = 0 column += 1 result_sheet.write(row, column, "Forecast", headerStyle) result_sheet.col(column).width = COLUMN_WIDTH row += 1 for item in self.parentWidget().resultingForecast: result_sheet.write(row, column, item, style) row += 1 if self.exportGraph.isChecked(): row = 0 column = 2 self.parentWidget().resultingGraph.saveFigure("forecast", format="bmp") result_sheet.insert_bitmap(RES + TEMP + "forecast.bmp", row, column) # saving xls try: book.save(unicode(fileName)) self.parentWidget().messageInfo.showInfo("Saved as " + unicode(fileName)) except Exception: self.parentWidget().messageInfo.showInfo("Could not save as " + unicode(fileName), True) except Exception, e: self.parentWidget().messageInfo.showInfo("Not enough data.", True)
class MSQtCanvas(QWidget, MSDialogController): """ DONE:the current peak is not updated while the user press up and down key on the treeView TODO: think about a mjor redesign of those classes """ #linePlotted = pyqtSignal(object, str) #lineRemoved = pyqtSignal(object) def __init__(self, data, title, flags="chroma", parent=None, **k): QWidget.__init__(self, parent) MSDialogController.__init__(self, 0, parent) self.model = self.qApp.model self.view = self.qApp.view self.data=data self.title=title self.flags=flags if self.flags == 'peak': if self.acTree not in (self.view.treeView_2, self.view.treeView_3): print "Unknown Error" return idx=self.acTree.selectedIndexes()[0] s = qApp.instance().dockControl.currentSample[1 if self.acTree is self.view.treeView_2 else 2] if s is None: print "unknow error" return values = map(float, idx.data().toString().split('/')[:2]) self.currentPeak = s.peakAt(*values) #connection to update the selected Peak object self.connect(self.acTree, SIGNAL("changedLine"), self.updateCurrentPeak) self.minX, self.maxX, self.maxY = [0] * 3 #if flags != 'peak': # self.minX, self.maxX, self.maxY = self.getMax() self.pw = PlotWidget(self.minX, self.maxX, self.maxY, parent=self, **k)#parent=self, #self.pw.setAttribute(Qt.WA_DeleteOnClose)#plotItem.setAttribute(Qt.WA_PaintOnScreen & Qt.WA_PaintUnclipped) if k.get('antialiased', False): self.pw.setRenderHint(0x01)#antialiasing i suppose self.pw.setTitle(title) self.pw.updateGrid() self._setupUi() self.connect(self, SIGNAL('linePlotted'), self.updateContextMenu) self.connect(self.view.sampleTableView, SIGNAL("disHighlightRequested(QModelIndex)"), self.disHighlightOne) self.connect(self.view.sampleTableView, SIGNAL("highlightRequested(QModelIndex)"), self.highlight) self.connect(self.view.sampleTableView, SIGNAL("noHighlightRequested()"), self.disHighlight) self.connect(self.view.ppmEditer, SIGNAL('valueChanged(double)'), self.redrawAll) self.drawnItems = {} self.trashItems=[]#why unecessary? nope to collect annotation stuff self.textLabels = [] self.pixmaps = [] self.dataPoints = None self._plotting(self.data)#initial plotting def getMax(self): localXmin =[] localXmax = [] localYmax = [] for el in self.data: if el is None: continue localXmin.append(min_f(el.x_data)) localXmax.append(max_f(el.x_data)) localYmax.append(max_l(el.y_data)) return min_f(np.array(localXmin)), max_f(np.array(localXmax)), max_l(np.array(localYmax)) def _plotting(self, data): """ refactor this shit c = Line(chrom.x_data, chrom.y_data, QColor.fromRgbF(*(self.ref.sample.color+(.7,))), parent=self.pw.plotItem.vb, scene=self.pw.scene()) #test scatter plot self.scatter = ScatterPlotItem(x=chrom.x_data, y=chrom.y_data) self.pw.addDataItem(self.scatter) self.scatter.sigClicked.connect(self.requestSpectra) """ if self.flags == 'peak': self.connect(self.pw.plotItem.vb, SIGNAL('showDiffOrSpectra(PyQt_PyObject)'), self.drawSpectra) self.ref = sorted([e for e in data if e is not None], key=lambda x:x.height)[-1] ppm = self.view.ppmEditer.value() if self.view.usePpm.isChecked() else self.ref.sample.ppm chrom = self.ref.sample.massExtraction(self.ref.mass(), ppm, asChromatogram=True) #show labels self.textLabels += self.showTextLabel(chrom.x_data, chrom.y_data) #drawing color = QColor.fromRgbF(*self.ref.sample.color +(.5, )) c = self.pw.plotItem.plot(chrom.x_data, chrom.y_data, pen=color) self.drawnItems[self.ref.sample] = c # peak's pixmap on the ref peak pix= PeakArrowItem(self.ref, pen=color, brush=color, pos=(self.ref.rt, self.ref.height + (self.ref.height * 6) / 100.), angle=-90, parent=self.pw.plotItem.vb) pix.setZValue(1000) self.pw.addItem(pix) #both these connections are emitted #in peak Indicator by effictivamente qApp self.connect(qApp.instance(), SIGNAL("highlightRequested"), c.setHighlighted) self.connect(qApp.instance(), SIGNAL('updateBarPlot'), self.barPlot.setPeakGroup) # self.emit(SIGNAL('linePlotted'), self.ref.sample.shortName()) #if qApp.instance().lowMemory: # chromatograms=[el.sample.loadAndExtract(el.mass(), el.sample.ppm, asChromatogram=True) \ # for el in data if el != ref and el is not None] #else: ppm = self.view.ppmEditer.value() if self.view.usePpm.isChecked() else self.ref.sample.ppm chromatograms=[el.sample.massExtraction(el.mass(), ppm, asChromatogram=True) \ for el in data if el is not None and el != self.ref] self.drawEics(chromatograms) #initialisation zoom on the peak self.pw.setYRange(0., self.ref.height + (self.ref.height * 12) / 100.) self.pw.setXRange(self.ref.rtmin - 20, self.ref.rtmax + 20) elif self.flags == 'chroma': ref = [d for d in data if d is not None] if not ref: print "Error, empty data to plot" return self.ref = ref[0] self.textLabels+=self.showTextLabel(self.ref.x_data, self.ref.y_data) self.drawEics(data) else:#spectrum if not data: #print "NOTHING TO PLOT" return self.ref = data[0] for el in data: c=SpectrumItem(el, centroid=True, scene=self.pw.scene()) self.pw.addItem(c) self.drawnItems[el.sample] = c self.pw.plotItem.curves.append(c) self.emit(SIGNAL('linePlotted'), el.sample.shortName()) #just put time information if data: i=0 while data[i] is None and i < len(data): i+=1 self.textLabels+=self.showTextLabel(data[i].x_data, data[i].y_data) #setting the range #warning: autoRange pw function does not work well #on spectrum item maxY = max([el.y_data.max() for el in data]) minX, maxX = min([el.x_data.min() for el in data]), max([el.x_data.max() for el in data]) self.pw.setXRange(minX, maxX, padding=0) self.pw.setYRange(0., maxY, padding=0) def drawEics(self, data): for chrom in data: color = QColor.fromRgbF(*(chrom.sample.color+(.5,))) c=self.pw.plotItem.plot(x=chrom.x_data, y=chrom.y_data, pen=color) #c = Line(chrom.x_data, chrom.y_data, # color, # parent=self.pw.plotItem.vb, # scene=self.pw.scene()) self.drawnItems[chrom.sample] = c #self.pw.addItem(c) #self.pw.plotItem.curves.append(c) self.emit(SIGNAL('linePlotted'), chrom.sample.shortName()) if self.flags != 'peaks': self.pw.autoRange() #=========================================================================== # UI stuffs #=========================================================================== def _setupUi (self): # self.stop = QToolButton() # self.stop.setIcon(QIcon('gui/icons/tools_wizard.png')) # self.stop.setToolTip('Enable or disable the appearance of the contextMenu') layout=QVBoxLayout(self) self.smoothButton=QToolButton() #self.smoothButton.setToolButtonStyle(2) self.smoothButton.setPopupMode(2) self.smoothButton.setToolTip("Smooth the visualized data") #self.smoothButton.setText("Smooth...") self.smoothButton.setIcon(QIcon(os.path.normcase('gui/icons/smooth.png'))) self.smoothMenu = QMenu() self.connect(self.smoothMenu, SIGNAL('triggered(QAction*)'), self.smooth) self.smoothButton.setMenu(self.smoothMenu) self.pw.plotItem.toolBar.addWidget(self.smoothButton) self.flipButton=QToolButton() #self.flipButton.setToolButtonStyle(2) self.flipButton.setIcon(QIcon(os.path.normcase('gui/icons/flip.png'))) self.flipButton.setToolTip("Flip the visualized data") #self.flipButton.setText("Flip...") self.flipButton.setPopupMode(2) self.flipMenu = QMenu() self.connect(self.flipMenu, SIGNAL('triggered(QAction*)'), self.flip) self.flipButton.setMenu(self.flipMenu) self.pw.plotItem.toolBar.addWidget(self.flipButton) self.annotButton=QToolButton() #self.annotButton.setToolButtonStyle(2) self.annotButton.setPopupMode(2) #self.annotButton.setText("&Annotate...") self.annotButton.setIcon(QIcon(os.path.normcase('gui/icons/attach.png'))) self.annotMenu = QMenu() self.annotMenu.addAction("&Add Annotation") self.annotMenu.addAction("&Remove last Annotation") self.annotMenu.addAction("&Remove All Annotation") self.annotButton.setMenu(self.annotMenu) self.connect(self.annotMenu.actions()[0], SIGNAL("triggered()"), self.annotate) self.connect(self.annotMenu.actions()[1], SIGNAL("triggered()"), self.removeLastAnnot) self.connect(self.annotMenu.actions()[2], SIGNAL("triggered()"), self.removeAllAnnot) self.pw.plotItem.toolBar.addWidget(self.annotButton) self.addPlotButton=QToolButton() #self.addPlotButton.setToolButtonStyle(2) self.addPlotButton.setText("Add...") self.addPlotButton.setIcon(QIcon(os.path.normcase('gui/icons/list_add.png'))) self.addPlotButton.setToolTip("Add a new plot to the current figure") #self.addPlotButton.setText('&Add Plot') self.pw.plotItem.toolBar.addWidget(self.addPlotButton) self.showSpectra=QToolButton() self.showSpectra.setPopupMode(2) #instant popup #self.showSpectra.setToolButtonStyle(2) self.showSpectra.setIcon(QIcon(os.path.normcase('gui/icons/file_export.png'))) #self.showSpectra.setText('&Show /hide...') self.showSpectra.setToolTip('Show/hide ...') self.showMenu=QMenu() self.showTextLabels=QAction("&Show Labels", self.showMenu) self.showTextLabels.setCheckable(True) self.showTextLabels.setChecked(True) self.showMenu.addAction(self.showTextLabels) self.connect(self.showMenu.actions()[0], SIGNAL('toggled(bool)'), self.setTextLabelsVisibility) showSpectrum=QAction("&Merged Spectrum", self.showMenu) showSpectrum.setCheckable(True) if self.flags == 'chroma' or self.flags == 'spectra': showSpectrum.setEnabled(False) self.showMenu.addAction(showSpectrum) self.connect(self.showMenu.actions()[1], SIGNAL('toggled(bool)'), self.drawSpectraRequested) showNonXCMSPeak=QAction("&Show Non XCMS Peak", self.showMenu) showNonXCMSPeak.setCheckable(True) if self.flags == 'spectra': showNonXCMSPeak.setEnabled(False) self.showMenu.addAction(showNonXCMSPeak) self.connect(self.showMenu.actions()[2], SIGNAL('toggled(bool)'), self.setPixmapVisibility) showDataPoints = QAction("&Show DataPoints", self.showMenu) showDataPoints.setCheckable(True) showDataPoints.setChecked(False) self.showMenu.addAction(showDataPoints) self.connect(self.showMenu.actions()[3], SIGNAL('toggled(bool)'), self.setDataPointsVisibility) self.showSpectra.setMenu(self.showMenu) self.pw.plotItem.toolBar.addWidget(self.showSpectra) self.saveToPng = QToolButton() self.saveToPng.setIcon(QIcon(os.path.normcase('gui/icons/thumbnail.png'))) #self.saveToPng.setToolButtonStyle(2) #self.saveToPng.setText("Save to Png...") self.pw.plotItem.toolBar.addWidget(self.saveToPng) self.connect(self.saveToPng, SIGNAL('clicked()'), self.pw.writeImage) #add bar plot even if we are plotting chroma #cause we can find non xcms peaks self.barPlot = BarPlot(scene=self.pw.sceneObj) #self.barPlot.rotate(-90.) if self.flags == 'peak': self.barPlot.setPeakGroup(self.data) #TODO modify to get this close to us #on the left part xpos = self.barPlot.scene().width()*3.5#-bwidth; ypos = self.barPlot.scene().height()*1.1 self.barPlot.setPos(xpos,ypos) self.barPlot.setZValue(1000) layout.addWidget(self.pw) layout.addWidget(self.pw.plotItem.toolBar) def showTextLabel(self, x, y, secure=25): """ add labels of principle peaks of spectrum or chroma on the plot, return the labels, that we can show hide """ maxis=[]#will contain tuple(rt, intens) indexes=[] #from core.MetObjects import MSAbstractTypes from scipy.ndimage import gaussian_filter1d as gauss z=gauss(y, 1) #z = MSAbstractTypes.computeBaseLine(z, 92., 0.8) i=0 while i <len(z)-1: while z[i+1] >= z[i] and i < len(y)-2: i+=1 maxis.append((x[i], y[i])) indexes.append(i) while z[i+1] <= z[i] and i<len(z)-2: i+=1 i+=1 labels=[] for t in sorted(maxis, key=lambda x:x[1])[-5:]: g=QGraphicsTextItem(str(t[0])) g.setFlag(QGraphicsItem.ItemIgnoresTransformations) font=QApplication.font() font.setPointSizeF(6.5) g.setFont(font) g.setDefaultTextColor(Qt.black) g.setPos(t[0], t[1]) labels.append(g) self.pw.addItem(g) return labels #=============================================================================== #SLOTS #=============================================================================== def redrawAll(self, value): self.pw.clear() self._plotting(self.data) def disHighlightOne(self, idx): if not idx.isValid(): return sample = self.model.sample(idx.data().toString(), fullNameEntry=False) if sample is None: return try: self.drawnItems[sample].setHighlighted(False) except KeyError: pass def highlight(self, idx): if not idx.isValid(): return sample = self.model.sample(idx.data().toString(), fullNameEntry=False) if sample is None: return try: self.drawnItems[sample].setHighlighted(True) except KeyError: pass #print "sample not found" self.pw.plotItem.update()#works def disHighlight(self): for key in self.drawnItems.iterkeys(): self.drawnItems[key].setHighlighted(False) self.pw.plotItem.update() def setTextLabelsVisibility(self, bool_): for t in self.textLabels: t.setVisible(bool_) def setDataPointsVisibility(self, b): if self.dataPoints is None: if self.flags == 'peak': chrom = self.ref.sample.massExtraction(self.ref.mass(), self.ref.sample.ppm, asChromatogram=True) self.dataPoints = ScatterPlotItem(x=chrom.x_data, y=chrom.y_data) else: self.dataPoints = ScatterPlotItem(x=self.ref.x_data, y=self.ref.y_data) if self.flags != 'spectra': self.dataPoints.sigClicked.connect(self.requestSpectra) self.pw.addDataItem(self.dataPoints) self.dataPoints.setVisible(b) def setPixmapVisibility(self, bool_): """ draw other peaks than the xcms peak """ if not self.pixmaps and bool_: ppm = 1. if self.ref.sample.kind=='MRM' else self.ref.sample.ppm chrom = self.ref.sample.massExtraction(self.ref.mass(), ppm, asChromatogram=True) \ if self.flags == 'peak' else self.ref chrom.findNonXCMSPeaks() for p in chrom.peaks.ipeaks(): if self.flags == 'peak': diff=(p.height*10)/100 if abs(p.height-self.ref.height) < diff: continue #we assume that they are the same peaks pix=PeakIndicator(p, icon='flags') #self.connect(pix, SIGNAL("highlightRequested"), c.setHighlighted) self.connect(pix, SIGNAL('updateBarPlot'), self.barPlot.setPeakGroup) pix.setPos(p.rt, p.height + (p.height * 10) / 100.) pix.setZValue(1000) self.pixmaps.append(pix) self.pw.addItem(pix) if self.pixmaps: for t in self.pixmaps: t.setVisible(bool_) @pyqtSlot() def updateCurrentPeak(self): idx=self.acTree.selectedIndexes()[0] s=self.model.sample(idx.parent().data().toString(), fullNameEntry=False) if s is not None: self.currentPeak=s.peakAt(*map(float, idx.data().toString().split('/'))) def requestSpectra(self, scatter, l): """ idea plot all spectra between a time range and not only with only one spectra """ if not l: return ref = l[0] self.emit(SIGNAL("drawSpectrumByTime"), ref.pos(), self.ref.sample) @pyqtSlot() def drawSpectraRequested(self, bool_): """ i think this is for plotting merged spectrum """ if bool_: self.emit(SIGNAL('drawSpectraRequested'), self.currentPeak) else: self.hideRequested() def drawSpectra(self, l): self.emit(SIGNAL('drawSpectra(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'), l[0], l[1], self.ref.sample) @pyqtSlot() def hideRequested(self): self.emit(SIGNAL('hideRequested')) self.showMenu.actions()[1].setChecked(False) @pyqtSlot() def redraw(self): """ this is for updating the view port when hiding or not samples """ chromas =[] for spl in self.model: if spl.checked: if spl in self.drawnItems.keys(): self.drawnItems[spl].setVisible(True) else: chromas.append(spl.chroma[0]) else: self.drawnItems[spl].setVisible(False) self._plotting(chromas) self.pw.plotItem.update()#works def cleanScene(self): """ remove all items in the trash """ for element in self.trashItems: self.pw.sceneObj.removeItem(element) @pyqtSlot() def updateContextMenu(self, line): self.flipMenu.addAction(line) self.smoothMenu.addAction(line) #=============================================================================== # CONTEXT MENU SLOTS #=============================================================================== @pyqtSlot(str) def flip(self, action): spl=self.model.sample(self.fullXmlPath(action.text())) if spl is None: print "can not flip, can not recognize the selected sample" return try: self.drawnItems[spl].updateData(-self.drawnItems[spl].getData()[1], self.drawnItems[spl].getData()[0]) except KeyError: pass if len(self.data) == 1: #we are flipping the text labels only #if only one dataset is flipped for item in self.textLabels: item.setPos(item.pos().x(), -item.pos().y()) @pyqtSlot(str) def smooth(self, action): """ TODO: would be good to reuse the widget in the menuControl """ from core.MetObjects import MSAbstractTypes class Dial(QDialog): choices =['flat', 'hanning', 'hamming', 'bartlett', 'blackman'] def __init__(self, parent): QDialog.__init__(self, parent) f =QFormLayout(self) self.a =QSpinBox(self) self.a.setValue(30) self.b = QComboBox(self) self.b.addItems(self.choices) self.c= QDialogButtonBox(self) self.c.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok) f.addRow("window:" ,self.a) f.addRow("method:", self.b) f.addRow("", self.c) self.connect(self.c, SIGNAL("accepted()"), self.sendData) self.connect(self.c, SIGNAL("rejected()"), self.reinitialize) def sendData(self): self.parent().window = self.a.value() self.parent().method = self.b.currentText() self.close() def reinitialize(self): self.parent().window = None self.parent().method = None self.close() Dial(self).exec_() if self.window and self.method: for spl in self.drawnItems.keys(): if action.text() == spl.shortName(): self.drawnItems[spl].updateData( MSAbstractTypes.averageSmoothing(self.drawnItems[spl].getData()[1],self.window , self.method), self.drawnItems[spl].getData()[0]) @pyqtSlot() def plotEIC(self): if self.flags == 'spectra': #show double combobox #select the good spectra then draw pass else: mass, ok = QInputDialog.getText(self.view, "EIC query", "mass:") if not (mass and ok): return xmlfile = self.fullXmlPath(self.selection[0].data().toString()) if not xmlfile: xmlfile = self.fullXmlPath(self.selection[0].parent().data().toString()) if not xmlfile: print "item clicked not recognized..." return sample = self.model.sample(xmlfile) if sample.kind =='HighRes': error=(sample.ppm/1e6)*float(mass) x, y = massExtraction(sample, float(mass), error) from core.MetObjects import MSChromatogram chrom = MSChromatogram(x_data=x, y_data=y, sample=sample) else: chrom = sample.getChromWithTrans(math.ceil(float(mass))) self.view.addMdiSubWindow(MSQtCanvas([chrom], "EIC %s"%str(mass), labels={'bottom':'RT(s)', 'left':'INTENSITY'})) #=========================================================================== # annotate stuff #=========================================================================== @pyqtSlot() def annotate(self): text, bool_ = QInputDialog.getText(self.view, "Annotation dialog", "Annotation:") g=QGraphicsTextItem(str(text)) g.setFlag(QGraphicsItem.ItemIgnoresTransformations) g.setFlag(QGraphicsItem.ItemIsMovable) g.setTextInteractionFlags(Qt.TextEditorInteraction) font=qApp.instance().font() font.setPointSizeF(10.) g.setFont(font) g.setDefaultTextColor(Qt.blue) g.setPos(500,1e4) self.trashItems.append(g) self.pw.addItem(g) def removeAllAnnot(self): if not self.trashItems: self.view.showErrorMessage("Error", "No annotation detected") return for i in self.trashItems: self.pw.removeItem(i) def removeLastAnnot(self): if not self.trashItems: self.view.showErrorMessage("Error", "No annotation detected") self.pw.removeItem(self.trashItems[-1])