def plotFilterRange(self, small, large, dates, **kwargs): self.form = MainWindow() self.histogram = HistogramWidget(self.form.btnHistogram) self.cluster = ClusterWidget(self.form.btnCluster) # self.form.move(300, 300) self.form.timeline.setScene(self.scene) self.form.timeline.setSceneRect(0, 0, 710, 10) dayIndices = list(map(lambda x: x[1], day)) dayIndex = -1 for d in dates: d = d[0:10] # b'2014-01-01 00:00:00' => b'2014-01-01' if dayIndex != dayIndices.index(d): dayIndex = dayIndices.index(d) rect = self.scene.addRect(2 * dayIndex, 1, 1, 10, self.pen) rect.setToolTip(bytes.decode(d)) self.scatterpoints = SelectableScatterPlotItem(small, large, dates, pen=None, symbol='o', **kwargs) self.form.graphicsView.addItem(self.scatterpoints) self.form.graphicsView.setLabel(axis = 'left', text = 'large') self.form.graphicsView.setLabel(axis = 'bottom', text = 'small') self.form.graphicsView.showGrid(True, True) self.form.show() self.tooltip = pg.TextItem(text = '', color = (176, 127, 255), anchor = (1, 1)) self.form.graphicsView.addItem(self.tooltip) self.tooltip.hide() self.scatterpoints.scene().sigMouseMoved.connect(self.onMove) self.form.btnFilter.clicked.connect(self.onfilterWindow) self.form.btnQuit.clicked.connect(self.onQuit) self.form.btnDelete.clicked.connect(self.onDelete) self.form.btnUndo.clicked.connect(self.undoFunction) self.form.btnHistogram.clicked.connect(self.onHistogram) self.form.btnCluster.clicked.connect(self.onCluster) self.form.actionFitLine.triggered.connect(self._update_regression_line) self.form.actionFitCubic.triggered.connect(self.fitCubic) self.form.action_Monatsverteilung.triggered.connect(functools.partial(self.setHistogramInterval, "month")) self.form.action_Jahresverteilung.triggered.connect(functools.partial(self.setHistogramInterval, "year")) self.form.action_Tagesverteilung.triggered.connect(functools.partial(self.setHistogramInterval, "day")) self.scatterpoints.selection.change_listeners += (self._update_regression_line, self.fitCubic, self.activateButtonHistogram) #Aktivieren des Undo-Buttons if self.stack.isEmpty(): self.form.btnUndo.setEnabled(False) else: self.form.btnUndo.setEnabled(True) insecurity_line_pen = QPen(QColor.fromRgbF(1, 1, 0, 0.5)) self._regression_lines = ( pg.InfiniteLine(), pg.InfiniteLine(pen=insecurity_line_pen), pg.InfiniteLine(pen=insecurity_line_pen)) for l in self._regression_lines: l.hide() self.form.graphicsView.addItem(l) print("len Filter: ", len(self.new_data))
class Plot: """ Plottet die Daten, welche in 'data' stehen. Filter-Button öffnet das Filter-Fenster Quit-Button schließt die Anwendung """ def __init__(self, data = None): self.data = data self.form = None self._regression_lines = () self.scatterpoints = None self.tooltip = None self.scene = QGraphicsScene() self.pen = QPen(QColor(0, 0, 255)) self.stack = Stack() self.original_data = data self.new_data = data if data is not None: self.plotFilterRange(data['small'], data['large'], data['date'], autoDownsample = True) self.histoInterval = None def onMove(self, scene_pos): pos = self.scatterpoints.mapFromScene(scene_pos) nearest_neighbor = self.scatterpoints.pointsAt(pos) nearest_neighbor = next(iter(nearest_neighbor), None) if nearest_neighbor is None: self.tooltip.hide() return s = self.data[nearest_neighbor] selection = self.scatterpoints.selection if nearest_neighbor in selection: tt = '{} selected items'.format(len(selection)) for m in ('sum', 'median', 'mean', 'var'): tt += '\n{}s=[{:.3}, {:.3}]'.format(m.upper(), *selection.get_stat(m)) else: tt = 'small={2:d}\nlarge={3:d}\ndate={0}'.format(s[0].decode(), *s) self.tooltip.setText(tt) # anchor des Tooltips anpassen, sodass Tooltip nicht aus dem Graph fällt self.tooltip.setPos(s[1], s[2]) self.tooltip.show() def onfilterWindow(self): """ Das Filter-Fenster: besteht aus tabWidget mit 2 Reitern Reiter Filter by Month/Day: treeWidget mit der Filterung von Monat und Tag. Ohne Tagangabe wird der komplette Monat gewählt Reiter Filter by Range: Über zwei Slider kann ein Startdatum und Enddatum ausgewählt werden OK-Button funktioniert nur, wenn ein Filter gewählt wurde Cancel-Button schließt das Filter-Fenster """ self.widForm = QWidget() self.widForm.move(1110, 300) self.wid = widgetwin_ui.Ui_Form() self.wid.setupUi(self.widForm) # Erzeuge Liste mit allen eingetragenen Monaten aus dem treeWidget topLevelItem = self.wid.treeWidget.topLevelItem(0) childs = tuple(map(topLevelItem.child, range(topLevelItem.childCount()))) # Sliders #self.wid.sliderTo.setValue(365) self.wid.sliderFrom.valueChanged.connect(self.setFrom) self.wid.sliderTo.valueChanged.connect(self.setTo) self.widForm.show() # TreeWidget self.wid.treeWidget.itemClicked.connect(functools.partial(self.onItemClick, childs)) # Buttons self.wid.btnCancel.clicked.connect(self.onCancel) self.wid.btnOk2.clicked.connect(self.onOkFilterSlider) self.wid.btnCancel2.clicked.connect(self.onCancel) self.wid.btnOk.clicked.connect(self.onOkMonth) def onItemClick(self, childs): getSelected = self.wid.treeWidget.selectedItems() if len(getSelected) > 0: baseNode = getSelected[0] # Prüft ob ein Monat bzw. Tag ausgewählt wurde childNodeText = baseNode.text(0) if baseNode in childs: print(len(self.wid.labMonth.text())) self.wid.labMonth.setText(childNodeText) print(len(self.wid.labMonth.text())) else: if len(childNodeText) == 1: childNodeText = "0" + childNodeText self.wid.labDay.setText(childNodeText) def onOkMonth(self): """ Sucht die Messdaten welche im Filter 'Filter by Month/Day' ausgewählt wurden 1. onOkMonth: Baue Suchstring, bestehend aus Monat und Tag, zusammen 2. filterMonth: Suche im Datensatz nach alle zutreffenden Messdaten 3. plot(self, filter): Plotten der Daten """ if len(self.wid.labMonth.text()) > 1: strMonth = self.wid.labMonth.text() if strMonth == 'January': print("January") self.filterMonth('2014-01' + '-' + self.wid.labDay.text()) elif strMonth == 'February': print("February") self.filterMonth('2014-02' + '-' + self.wid.labDay.text()) elif strMonth == 'March': print("March") self.filterMonth('2014-03' + '-' + self.wid.labDay.text()) elif strMonth == 'April': print("April") self.filterMonth('2014-04' + '-' + self.wid.labDay.text()) elif strMonth == 'May': print("May") self.filterMonth('2014-05' + '-' + self.wid.labDay.text()) elif strMonth == 'June': print("June") self.filterMonth('2014-06' + '-' + self.wid.labDay.text()) elif strMonth == 'July': print("July") self.filterMonth('2014-07' + '-' + self.wid.labDay.text()) elif strMonth == 'August': print("August") self.filterMonth('2014-08' + '-' + self.wid.labDay.text()) elif strMonth == 'September': print("September") self.filterMonth('2014-09' + '-' + self.wid.labDay.text()) elif strMonth == 'October': print("October") self.filterMonth('2014-10' + '-' + self.wid.labDay.text()) elif strMonth == 'November': print("November") self.filterMonth('2014-11' + '-' + self.wid.labDay.text()) elif strMonth == 'December': print("December") self.filterMonth('2014-12' + '-' + self.wid.labDay.text()) def filterMonth(self, timeInterval): # TODO: Use numpy.ndarray's range filter view instead of deleting tuples piece by piece self.stack.push(self.new_data) self.new_data = self.original_data index = 0 for s in self.new_data: decode_date = s[0].decode("utf-8") if timeInterval in decode_date: index += 1 else: self.new_data = np.delete(self.new_data, index) if len(self.new_data)>0: self.data = self.new_data if len(self.data) > 0: self.plotFilterRange(self.data['small'], self.data['large'], self.data['date'], autoDownsample = True) else: msgBox = QMessageBox() msgBox.setText("No data exists for the filter!") msgBox.exec_() def plot(self, filter): """ Kann verwendet werden, wenn ein kompletter Monat ausgewählt wurde Parameter 'filter' muss eine Datei sein """ new_data = np.genfromtxt(filter, dtype = [('date', '|S19'), ('small', 'i8'), ('large', 'i8')], delimiter = ';', names = ["date", "small", "large"]) self.plotFilterRange(new_data['small'], new_data['large']) def onDelete(self): if not self.scatterpoints.selection: return self.stack.push(self.new_data) self.data = self.new_data = np.delete(self.new_data, tuple(self.scatterpoints.selection)) self.scatterpoints.clear() self.plotFilterRange(self.data['small'], self.data['large'], self.data['date'], autoDownsample = True) def undoFunction(self): self.data = self.stack.pop() self.plotFilterRange(self.data['small'], self.data['large'], self.data['date'], autoDownsample = True) def onCancel(self): """ Jeder Cancel-Button blendet das Filter-Fenster aus """ self.widForm.close() def onQuit(self): """ Quit-Button schließt die Anwendung """ sys.exit(0) def onOkFilterSlider(self): """ Sucht alle Messdaten in gegeben Zeitraum (von 'fromValue' bis 'toValue') 1. onOkFilterSlider: Prüfe ob fromValue < toValue ist, ansonsten tausche die Werte und ändere Slider danach suche alle Messdaten im Zeitraum 2. plotFilterRange(self, small, large): Plotten der Daten. Small/Large = Liste allen kleinen/großen Partikel """ self.stack.push(self.new_data) fromValue = int(self.wid.sliderFrom.value()) toValue = int(self.wid.sliderTo.value()) if fromValue > toValue: fromValue = toValue toValue = self.wid.sliderFrom.value() self.wid.sliderFrom.setValue(fromValue) self.wid.sliderTo.setValue(toValue) fromDate = self.getDateFromDay(fromValue) toDate = self.getDateFromDay(toValue) self.wid.labFrom.setText(fromDate) self.wid.labTo.setText(toDate) isDeletePoint = True # Alle Punkte die nicht im Filterzeitraum liegen, werden aus der Datenmenge gelöscht self.new_data = self.original_data index = 0 for s in self.new_data: decode_date = s[0].decode("utf-8") if (fromDate in decode_date) and isDeletePoint: isDeletePoint = False if (toDate in decode_date) and not isDeletePoint: isDeletePoint = True if isDeletePoint: self.new_data = np.delete(self.new_data, index) # new_data wird kleiner, darum darf der Index nicht wachsen. else: index += 1 if len(self.new_data) > 0: self.data = self.new_data if len(self.data) > 0: self.plotFilterRange(self.data['small'], self.data['large'], self.data['date'], autoDownsample = True) else: msgBox = QMessageBox() msgBox.setText("No data exists for the filter!") msgBox.exec_() def _update_regression_line(self, *args): lines = self._regression_lines if not lines: return if self.form.actionFitLine.isChecked(): if self.scatterpoints.selection: xs, ys = self.scatterpoints.selection.values().transpose() else: xs = self.data['small'] ys = self.data['large'] if len(xs) > 2: a, b, q, r, sigma_a, sigma_b = math_utils.fitLine(xs, ys) lines[0].setValue(QPointF(0, a)) lines[1].setValue(QPointF(0, a - sigma_a)) lines[2].setValue(QPointF(0, a + sigma_a)) lines[0].setAngle(math.degrees(math.atan(b))) lines[1].setAngle(math.degrees(math.atan(b - sigma_b))) lines[2].setAngle(math.degrees(math.atan(b + sigma_b))) lines[0].setToolTip('a = %f\nb = %f\np = %f\nr = %f' % (a, b, q, r)) for l in lines: l.show() return for l in lines: l.hide() def fitCubic(self, *args): if self.form.actionFitCubic.isChecked(): pass # was ist Maximum-Likelihood # wie berechnet man das Polynom # wie stellt man es dar else: pass def activateButtonHistogram(self, *args): if (len(self.scatterpoints.selection) > 0) & (self.histoInterval != None): self.form.btnHistogram.setEnabled(True) self.form.btnDelete.setEnabled(True) elif (len(self.scatterpoints.selection) > 0): self.form.btnDelete.setEnabled(True) def setHistogramInterval(self, interval): isChecked = False if bool(self.form.action_Monatsverteilung.isChecked) & (interval == "month"): isChecked = True self.form.action_Jahresverteilung.setChecked(False) self.form.action_Tagesverteilung.setChecked(False) elif bool(self.form.action_Tagesverteilung.isChecked) & (interval == "year"): isChecked = True self.form.action_Monatsverteilung.setChecked(False) self.form.action_Tagesverteilung.setChecked(False) elif bool(self.form.action_Tagesverteilung.isChecked) & (interval == "day"): isChecked = True self.form.action_Jahresverteilung.setChecked(False) self.form.action_Monatsverteilung.setChecked(False) if isChecked: self.histoInterval = interval self.activateButtonHistogram(self.scatterpoints.selection) else: self.form.btnHistogram.setEnabled(False) def onHistogram(self,): self.histogram.onHistogram(self.histoInterval, self.scatterpoints.selection) def onCluster(self,): self.cluster.onCluster() def plotFilterRange(self, small, large, dates, **kwargs): self.form = MainWindow() self.histogram = HistogramWidget(self.form.btnHistogram) self.cluster = ClusterWidget(self.form.btnCluster) # self.form.move(300, 300) self.form.timeline.setScene(self.scene) self.form.timeline.setSceneRect(0, 0, 710, 10) dayIndices = list(map(lambda x: x[1], day)) dayIndex = -1 for d in dates: d = d[0:10] # b'2014-01-01 00:00:00' => b'2014-01-01' if dayIndex != dayIndices.index(d): dayIndex = dayIndices.index(d) rect = self.scene.addRect(2 * dayIndex, 1, 1, 10, self.pen) rect.setToolTip(bytes.decode(d)) self.scatterpoints = SelectableScatterPlotItem(small, large, dates, pen=None, symbol='o', **kwargs) self.form.graphicsView.addItem(self.scatterpoints) self.form.graphicsView.setLabel(axis = 'left', text = 'large') self.form.graphicsView.setLabel(axis = 'bottom', text = 'small') self.form.graphicsView.showGrid(True, True) self.form.show() self.tooltip = pg.TextItem(text = '', color = (176, 127, 255), anchor = (1, 1)) self.form.graphicsView.addItem(self.tooltip) self.tooltip.hide() self.scatterpoints.scene().sigMouseMoved.connect(self.onMove) self.form.btnFilter.clicked.connect(self.onfilterWindow) self.form.btnQuit.clicked.connect(self.onQuit) self.form.btnDelete.clicked.connect(self.onDelete) self.form.btnUndo.clicked.connect(self.undoFunction) self.form.btnHistogram.clicked.connect(self.onHistogram) self.form.btnCluster.clicked.connect(self.onCluster) self.form.actionFitLine.triggered.connect(self._update_regression_line) self.form.actionFitCubic.triggered.connect(self.fitCubic) self.form.action_Monatsverteilung.triggered.connect(functools.partial(self.setHistogramInterval, "month")) self.form.action_Jahresverteilung.triggered.connect(functools.partial(self.setHistogramInterval, "year")) self.form.action_Tagesverteilung.triggered.connect(functools.partial(self.setHistogramInterval, "day")) self.scatterpoints.selection.change_listeners += (self._update_regression_line, self.fitCubic, self.activateButtonHistogram) #Aktivieren des Undo-Buttons if self.stack.isEmpty(): self.form.btnUndo.setEnabled(False) else: self.form.btnUndo.setEnabled(True) insecurity_line_pen = QPen(QColor.fromRgbF(1, 1, 0, 0.5)) self._regression_lines = ( pg.InfiniteLine(), pg.InfiniteLine(pen=insecurity_line_pen), pg.InfiniteLine(pen=insecurity_line_pen)) for l in self._regression_lines: l.hide() self.form.graphicsView.addItem(l) print("len Filter: ", len(self.new_data)) def getDateFromDay(self, chooseDay): """ Wandelt die Byte-Daten in Strings um """ sliderDate = day['sliderDate'] chooseDateByte = sliderDate[chooseDay] chooseDate = chooseDateByte.decode("utf-8") return chooseDate def setFrom(self): """ Setzen des From-Sliders bei Änderung """ chooseDay = self.wid.sliderFrom.value() chooseDate = self.getDateFromDay(chooseDay) print(chooseDate) self.wid.labFrom.setText(chooseDate) def setTo(self): """ Setzen des To-Sliders bei Änderung """ chooseDay = self.wid.sliderTo.value() chooseDate = self.getDateFromDay(chooseDay) self.wid.labTo.setText(chooseDate)