From 04b35ae263518005e5f5382310a204166ea9c708 Mon Sep 17 00:00:00 2001 From: Lars Bittrich Date: Mon, 29 Apr 2019 22:45:20 +0200 Subject: [PATCH] new type histogram view in particle analysis --- analysis/analysisview.py | 99 +++++++++---------------------------- analysis/analysiswidgets.py | 74 ++++++++++++++++++++++++++- 2 files changed, 94 insertions(+), 79 deletions(-) diff --git a/analysis/analysisview.py b/analysis/analysisview.py index d04ba07..01cf255 100644 --- a/analysis/analysisview.py +++ b/analysis/analysisview.py @@ -30,7 +30,7 @@ from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar -from .analysiswidgets import ExpExcelDialog, AdditiveViewer +from .analysiswidgets import ExpExcelDialog, AdditiveViewer, ParticleTypeView from .loadresults import LoadWITecResults from .particleeditor import ParticleEditor from .database import DataBaseWindow @@ -67,11 +67,10 @@ class ParticleAnalysis(QtWidgets.QMainWindow): self.currentSpectrumIndex = 0 self.lastSpectrumInFocus = None - self.typeHistogramCanvas = FigureCanvas(Figure()) + self.typeHistogram = ParticleTypeView(self) + self.typeHistogram.indexClicked.connect(self.getAdditivePlot) self.sizeHistogramCanvas = FigureCanvas(Figure()) - self.typeHist_ax = self.typeHistogramCanvas.figure.subplots() - self.typeHist_ax.axis('off') sizeHistGroup = QtWidgets.QGroupBox() sizeHistLayout = QtWidgets.QHBoxLayout() self.sizeHist_ax = self.sizeHistogramCanvas.figure.subplots() @@ -107,7 +106,7 @@ class ParticleAnalysis(QtWidgets.QMainWindow): splitter1.addWidget(sizeHistGroup) splitter2 = QtWidgets.QSplitter(QtCore.Qt.Horizontal) splitter2.addWidget(splitter1) - splitter2.addWidget(self.typeHistogramCanvas) + splitter2.addWidget(self.typeHistogram) splitter2.setSizes([300, 150]) self.navigationGroup = QtWidgets.QGroupBox('Navigate through polymers') @@ -343,11 +342,12 @@ class ParticleAnalysis(QtWidgets.QMainWindow): self.importWindow = LoadWITecResults(self.datastats, self) self.importWindow.exec() - def getAdditivePlot(self, event): - clickedindex = int(np.round(event.xdata)) + @QtCore.pyqtSlot(int) + def getAdditivePlot(self, clickedindex): polymer = self.datastats.typehistogram[clickedindex][0] #get the polymer name, that was clicked on - if len(self.datastats.sorted_additives[clickedindex]) > 0: + if self.datastats.sorted_additives is not None and \ + len(self.datastats.sorted_additives[clickedindex]) > 0: self.additivePlot = AdditiveViewer(polymer, self.datastats.sorted_additives[clickedindex]) self.additivePlot.show() @@ -419,10 +419,6 @@ class ParticleAnalysis(QtWidgets.QMainWindow): self.menuLayout.addWidget(self.resultScrollarea) - if self.datastats.currentAdditives is not None: - self.typeHistogramCanvas.setCursor(QtGui.QCursor(QtCore.Qt.WhatsThisCursor)) - self.typeHistogramCanvas.mpl_connect('button_press_event', self.getAdditivePlot) - self.expExcelAct.setDisabled(False) if sqlEnabled: self.expSQLAct.setDisabled(False) @@ -567,38 +563,16 @@ class ParticleAnalysis(QtWidgets.QMainWindow): self.currentSpectrumIndex = self.datastats.particles2spectra[self.currentParticleIndex][self.spectrumSelector.value()-1] self.updateSpecPlot() - def updateHistogram(self): - self.sizeHist_ax.clear() - self.typeHist_ax.clear() - - self.typeHist_ax.axis('on') - self.sizeHist_ax.axis('on') - + def updateHistogram(self): #draw the general histogram colorList = [] - if self.selOverlayAct.isChecked(): - abundancyList = [] - for index, checkbox in enumerate(self.polymerCheckBoxes): - if checkbox.isChecked(): - abundancyList.append(self.datastats.typehistogram[index][1]) - curColor = self.getColorFromName(self.datastats.typehistogram[index][0], base255 = False) - colorList.append(curColor) - - else: - abundancyList = [i[1] for i in self.datastats.typehistogram] - for polymer in self.datastats.typehistogram: - curColor = self.getColorFromName(polymer[0], base255 = False) - colorList.append(curColor) - - self.typeHist_ax.barh(range(len(abundancyList)), abundancyList, color=colorList) - itemsInPlot = (len(abundancyList) if len(abundancyList) < self.dispResultSpinBox.value() else self.dispResultSpinBox.value()) - self.typeHist_ax.set_ylim([itemsInPlot, -1]) #plot in inverse order (have index 0 (highest abundancy) at top) - - ###add text labels - self.histPlotTextLabels = [] - y_label_position = 0 + abundancyList = [] + labelList = [] for index, i in enumerate(self.datastats.typehistogram): if not self.selOverlayAct.isChecked() or self.polymerCheckBoxes[index].isChecked(): + abundancyList.append(self.datastats.typehistogram[index][1]) + curColor = self.getColorFromName(self.datastats.typehistogram[index][0]) + colorList.append(QtGui.QColor(*curColor)) if self.datastats.sorted_additives is None: numads = '' else: @@ -609,46 +583,17 @@ class ParticleAnalysis(QtWidgets.QMainWindow): numads = '(' + str(numads) + ')' numpolymers = i[1] label = ('{} x ' + self.datastats.typehistogram[index][0] + ' {}').format(numpolymers, numads) - x_label_position = self.typeHist_ax.get_xlim()[1]*0.05 - self.histPlotTextLabels.append(self.typeHist_ax.text(x_label_position, y_label_position, label, fontsize = 15, rotation = 0, verticalalignment = 'bottom')) - y_label_position += 1 - - for label in self.histPlotTextLabels: - pos = label.get_position() - curLimits = self.typeHist_ax.get_ylim() - if curLimits[1] < pos[1] < curLimits[0]: - label.set_alpha(1) - else: - label.set_alpha(0) - - self.typeHist_ax.set_title('Polymer Type Distribution', fontsize = 15) - self.typeHist_ax.tick_params(axis='y', which='both', left=False, labelleft=False) - self.typeHist_ax.tick_params(axis='both', which='both', labelsize=15) - self.typeHist_ax.set_ylabel('Polymer Type', fontsize = 15) - self.typeHist_ax.set_xlabel('Number', fontsize = 15) - - if len(self.datastats.typehistogram) > self.dispResultSpinBox.value(): - - def wheelScroll(event): - step = -0.05*event.step*self.dispResultSpinBox.value() - ymin, ymax = self.typeHist_ax.get_ylim() - if ymin > ymax: - ymin, ymax = ymax, ymin - self.typeHist_ax.set_ylim([ymax+step, ymin+step]) - - for label in self.histPlotTextLabels: - pos = label.get_position() - if ymin+step < pos[1] < ymax+step: - label.set_alpha(1) - else: - label.set_alpha(0) - self.typeHist_ax.figure.canvas.draw() + labelList.append(label) - self.typeHistogramCanvas.mpl_connect('scroll_event', wheelScroll) - - self.typeHist_ax.figure.canvas.draw() + print("abundancyList:", abundancyList) + print("labelList:", labelList) + print("colorList:", colorList) + self.typeHistogram.updateTypes(list(zip(abundancyList, labelList, colorList))) #general size histogram + self.sizeHist_ax.clear() + self.sizeHist_ax.axis('on') + self.bins = np.logspace(0.1, 3, 20) self.sizes = [i[0] if np.isnan(i[2]) else i[2] for i in self.datastats.getParticleStats()] #extract long size (if ellipse fit is nan -> box fit) sizehist = np.histogram(self.sizes, self.bins) diff --git a/analysis/analysiswidgets.py b/analysis/analysiswidgets.py index 2108e96..05ae32d 100644 --- a/analysis/analysiswidgets.py +++ b/analysis/analysiswidgets.py @@ -19,7 +19,7 @@ along with this program, see COPYING. If not, see . """ -from PyQt5 import QtWidgets +from PyQt5 import QtWidgets, QtGui, QtCore import numpy as np import pandas as pd import os @@ -201,4 +201,74 @@ class AdditiveViewer(QtWidgets.QWidget): self.ax.hist(sortedAdditives) self.ax.set_ylabel('Number', fontsize = 15) - self.ax.tick_params(axis='both', which='both', labelsize=15) \ No newline at end of file + self.ax.tick_params(axis='both', which='both', labelsize=15) + + +class ParticleIndicator(QtWidgets.QPushButton): + def __init__(self, number, numtotal, color, text, parent=None): + super().__init__(parent) + self.number = number + self.numtotal = numtotal + self.color = color + self.text = text + self.setFixedHeight(30) + + def paintEvent(self, event): + r = self.number/self.numtotal + width = self.width() + height = self.height() + + qp = QtGui.QPainter() + qp.begin(self) + qp.fillRect(self.rect(), QtCore.Qt.white) + qp.setPen(self.color) + qp.setBrush(self.color) + qp.drawRoundedRect(0, 0, int(width*r), height, 5. ,5.) + qp.setPen(QtCore.Qt.black) + qp.setBrush(QtCore.Qt.NoBrush) + qp.drawRoundedRect(0, 0, width, height, 5. ,5.) + qp.drawText(self.rect(), QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter, + self.text) + + qp.end() + + +class ParticleTypeView(QtWidgets.QScrollArea): + indexClicked = QtCore.pyqtSignal(int) + def __init__(self, parent=None): + super().__init__(parent) + self.view = QtWidgets.QWidget(self) + self.view.setCursor(QtGui.QCursor(QtCore.Qt.WhatsThisCursor)) + self.view.setMinimumWidth(250) + + group = QtWidgets.QGroupBox('Polymer Type Distribution', self.view) + self.indicatorbox = QtWidgets.QVBoxLayout() + self.indicatorbox.setContentsMargins(5,5,5,5) + group.setLayout(self.indicatorbox) + + hbox = QtWidgets.QHBoxLayout() + hbox.addWidget(group) + self.view.setLayout(hbox) + self.setWidgetResizable(True) + self.setWidget(self.view) + self.setAlignment(QtCore.Qt.AlignHCenter) + + def updateTypes(self, types): + print("Updating polymer type view", flush=True) + for i in range(self.indicatorbox.count()): + self.indicatorbox.takeAt(0) + + numtotal = sum([num for num, text, color in types]) + + def getIndexFunction(index): + return lambda : self.indexClicked.emit(index) + + for index, entry in enumerate(types): + num, text, color = entry + print("num, text, color:", num, text, color, flush=True) + pi = ParticleIndicator(num, numtotal, color, text) + self.indicatorbox.addWidget(pi) + pi.clicked.connect(getIndexFunction(index)) + self.indicatorbox.addStretch() + self.view.update() + \ No newline at end of file -- GitLab