def __init__(self, spec): super().__init__(None) self.spec = spec self.chart = QChart() # self.chart.setTitle(str(self.spec.variables)) # self.chart.legend().hide() for i in range(len(self.spec.variables)): series = QLineSeries() series.setColor( QColor( self.spec.colors[i][0], self.spec.colors[i][1], self.spec.colors[i][2], )) series.setName(self.spec.variables[i]) self.chart.addSeries(series) self.setMinimumWidth(400) self.setMinimumHeight(230) self.setChart(self.chart) self.setRenderHint(QPainter.Antialiasing) self.chart.createDefaultAxes() self.autoscale_y_axis = True if self.spec.min_y and self.spec.max_y: self.autoscale_y_axis = False self.chart.axes()[1].setRange(self.spec.min_y, self.spec.max_y) self._updates_per_second = 60 self._data = [] self._min = 0 self._max = 0
def _get_processor_chart(self): # type: (Display) -> QChartView # Create pen pen = QLineSeries().pen() pen.setColor(Qt.red) pen.setWidthF(1) # Series self._processor_series = QLineSeries() self._processor_series.setPen(pen) self._processor_series.useOpenGL() # Chart self._processor_chart = QChart() self._processor_chart.legend().hide() self._processor_chart.addSeries(self._processor_series) self._processor_chart.createDefaultAxes() self._processor_chart.axisX().setMax(100) self._processor_chart.axisX().setMin(0) self._processor_chart.axisY().setMax(5000) self._processor_chart.axisY().setMin(0) self._processor_x_axis = QValueAxis() self._processor_x_axis.setLabelFormat('%i') self._processor_chart.setAxisX(self._processor_x_axis, self._processor_series) self._processor_y_axis = QLogValueAxis() self._processor_y_axis.setLabelFormat('%g') self._processor_y_axis.setBase(8) # Chart View view = QChartView(self._processor_chart) view.setRenderHint(QPainter.Antialiasing) view.setStyleSheet('margin: 0px; height: 250%; width: 400%;') return view
def _get_connector_chart(self): # type: (Display) -> QChartView # Create pen pen = QLineSeries().pen() pen.setColor(Qt.blue) pen.setWidthF(1) # Series self._connector_series = QLineSeries() self._connector_series.setPen(pen) self._connector_series.useOpenGL() # Chart self._connector_chart = QChart() self._connector_chart.legend().hide() self._connector_chart.addSeries(self._connector_series) self._connector_chart.createDefaultAxes() self._connector_chart.axisX().setMax(100) self._connector_chart.axisX().setMin(0) self._connector_chart.axisY().setMax(500) self._connector_chart.axisY().setMin(-500) # Chart View view = QChartView(self._connector_chart) view.setRenderHint(QPainter.Antialiasing) view.setStyleSheet('margin: 0px; height: 250%; width: 400%;') return view
def add_new_data(self, data: dict): self.x += self.time.msec() self.time.start() if self.x > 10000: self.ax.setRange(self.x - 10000, self.x) for key in data: try: value = float(data[key]) except ValueError: continue if value > self.ymax: self.ymax = value self.ay.setRange(self.ymin, self.ymax) elif value < self.ymin: self.ymin = value self.ay.setRange(self.ymin, self.ymax) if key in self.lines: if self.lines[key].__len__() >= 32: # self.lines[key].replace(0,self.x, value) self.lines[key].remove(0) # else: self.lines[key].append(self.x, value) else: # ls = QSplineSeries(self) ls = QLineSeries(self) ls.append(self.x, value) ls.setColor( QColor(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))) ls.setName(key) self.chart().addSeries(ls) self.chart().setAxisX(self.ax, ls) self.chart().setAxisY(self.ay, ls) self.lines[key] = ls
def createSeries(self, dataArray): series = QLineSeries() for i in range(len(dataArray)): value = QPointF(i, dataArray[i][0]) series.append(value) series.setColor(QColor(0, 255, 0)) self.removeSeries() series.setName("灰度图") self.qchart.addSeries(series) self.lastSeries = series
def addSeries( self, _x2idx: typing.Dict, _idx2x: list, _chart: QChart, _axis_x: QValueAxis, _axis_y: QValueAxis ): series = QLineSeries() series.setName(self.name) for x, y in zip(self.x_list, self.y_list): series.append(_x2idx[x], y) if self.color is not None: series.setColor(self.color) _chart.addSeries(series) _chart.setAxisX(_axis_x, series) _chart.setAxisY(_axis_y, series) if self.show_value: self.createShow()
def InitGui(self): self.setWindowTitle("Line Chart") self.setGeometry(100,200,800,600) series = QLineSeries() series.setColor(QColor('red')) seriesA = QLineSeries() seriesA.setColor(QColor('green')) for i in range(1,20): series.append(10*i,20+i*i*8-3*i) seriesA.append(10*i, 6-i*i*2+5*i) chart = QChart() chart.addSeries(series) chart.addSeries(seriesA) chart.setAnimationOptions(chart.SeriesAnimations) chart.setAnimationDuration(1000) chart.setTitle("Line Chart") chart.legend().setVisible(True) chart.legend().setAlignment(Qt.AlignBottom) view = QChartView(chart) view.setRenderHint(QPainter.Antialiasing) vbox = QVBoxLayout() vbox.addWidget(view) root = QWidget() root.setLayout(vbox) self.setCentralWidget(root) pass
def create_rgb_Series(self, dataArray): series = [] colors = [QColor(255, 0, 0), QColor(0, 255, 0), QColor(0, 0, 255)] names = ['红', '绿', '蓝'] for i in range(len(dataArray)): serie = QLineSeries() for j in range(len(dataArray[i])): value = QPointF(j, dataArray[i][j][0]) serie.append(value) serie.setColor(colors[i]) serie.setName(names[i]) series.append(serie) for ser in series: self.qchart.addSeries(ser) # 先将旧的rgb线移除 self.removeSeries() self.lastSeries = series
def setupChart(self): """Set up the GUI's graph series type, chart instance, chart axes, and chart view widget.""" random.seed(50) # Create seed for random numbers # Create the model instance and set the headers self.model = QStandardItemModel() self.model.setColumnCount(3) self.model.setHorizontalHeaderLabels(["Year", "Social Exp. %GDP", "Country"]) # Collect x and y data values and labels from the CSV file xy_data_and_labels = self.loadCSVFile() # Create the individual lists for x, y and labels values x_values, y_values, labels = [], [], [] # Append items to the corresponding lists for item in range(len(xy_data_and_labels)): x_values.append(xy_data_and_labels[item][0]) y_values.append(xy_data_and_labels[item][1]) labels.append(xy_data_and_labels[item][2]) # Remove all duplicates from the labels list using list comprehension. # This list will be used to create the labels in the chart's legend. set_of_labels = [] [set_of_labels.append(x) for x in labels if x not in set_of_labels] # Create chart object self.chart = QChart() self.chart.setTitle("Public Social Spending as a Share of GDP, 1880 to 2016") self.chart.legend().hide() # Hide legend at the start # Specify parameters for the x and y axes self.axis_x = QValueAxis() self.axis_x.setLabelFormat("%i") self.axis_x.setTickCount(10) self.axis_x.setRange(1880, 2016) self.chart.addAxis(self.axis_x, Qt.AlignBottom) self.axis_y = QValueAxis() self.axis_y.setLabelFormat("%i" + "%") self.axis_y.setRange(0, 40) self.chart.addAxis(self.axis_y, Qt.AlignLeft) # Create a Python dict to associate the labels with the individual line series series_dict = {} for label in set_of_labels: # Create labels from data and add them to a Python dictionary series_label = 'series_{}'.format(label) series_dict[series_label] = label # Create label value for each line series # For each of the keys in the dict, create a line series for keys in series_dict.keys(): # Use get() to access the corresponding value for a key label = series_dict.get(keys) # Create line series instance and set its name and color values line_series = QLineSeries() line_series.setName(label) line_series.setColor(QColor(random.randint(10, 254), random.randint(10, 254), random.randint(10, 254))) # Append x and y coordinates to the series for value in range(len(xy_data_and_labels)): if line_series.name() == xy_data_and_labels[value][2]: line_series.append(x_values[value], y_values[value]) # Create and add items to the model (for displaying the table) items = [QStandardItem(str(item)) for item in xy_data_and_labels[value]] color = line_series.pen().color() for item in items: item.setBackground(color) self.model.insertRow(value, items) self.chart.addSeries(line_series) line_series.attachAxis(self.axis_x) line_series.attachAxis(self.axis_y) # Create QChartView object for displaying the chart self.chart_view = ChartView(self.chart) self.setCentralWidget(self.chart_view)
def __init__(self, parent=None): super(Widget, self).__init__(parent) self.setWindowTitle('Financieële grafieken externe werken') self.setWindowIcon(QIcon('./images/logos/logo.jpg')) self.setWindowFlags(self.windowFlags() | Qt.WindowSystemMenuHint | Qt.WindowMinMaxButtonsHint) grid = QGridLayout() grid.setSpacing(20) metadata = MetaData() resultaten = Table('resultaten', metadata, Column('resID', Integer(), primary_key=True), Column('statusweek', String), Column('btotaal', Float), Column('wtotaal', Float), Column('betaald_bedrag', Float), Column('meerminderwerk', Float), Column('onderhandenwerk', Float), Column('aanneemsom', Float), Column('blonen', Float), Column('wlonen', Float), Column('bmaterialen', Float), Column('wmaterialen', Float), Column('bmaterieel', Float), Column('wmaterieel', Float), Column('bprojectkosten', Float), Column('wprojectkosten', Float), Column('binhuur', Float), Column('winhuur', Float), Column('bdiensten', Float), Column('wdiensten', Float), Column('bruto_winst', Float), Column('boekweek', String)) params = Table('params', metadata, Column('paramID', Integer(), primary_key=True), Column('tarief', String)) engine = create_engine( 'postgresql+psycopg2://postgres@localhost/bisystem') con = engine.connect() selpar1 = select([params]).where(params.c.paramID == 97) rppar1 = con.execute(selpar1).first() bo_incr = rppar1[1] / 52 #begrote omzet per week selpar2 = select([params]).where(params.c.paramID == 98) rppar2 = con.execute(selpar2).first() bw_incr = rppar2[1] / 52 #begrote winst per week jaar = jrwk[0:4] engine = create_engine( 'postgresql+psycopg2://postgres@localhost/bisystem') con = engine.connect() selres = select([resultaten]).where(and_(resultaten.c.boekweek == jrwk,\ resultaten.c.statusweek.like(jaar+'%'))).order_by(resultaten.c.statusweek) rpres = con.execute(selres) if keuze == '1': s1 = 2 s2 = 3 t1 = 'Kosten totaal begroot' t2 = 'Kosten totaal werkelijk' t3 = 'Kosten totaal ' c1 = Qt.red c2 = Qt.blue ysch = 160000000 elif keuze == '2': s1 = 8 s2 = 9 t1 = 'Lonen begroot' t2 = 'Lonen werkelijk' t3 = 'Lonen ' c1 = Qt.green c2 = Qt.darkBlue ysch = 100000000 elif keuze == '3': s1 = 10 s2 = 11 t1 = 'Materialen begroot' t2 = 'Materialen werkelijk' t3 = 'Materialen' c1 = Qt.cyan c2 = Qt.magenta ysch = 60000000 elif keuze == '4': s1 = 12 s2 = 13 t1 = 'Materiëel begroot' t2 = 'Materiëel werkelijk' t3 = 'Materiëel ' c1 = Qt.darkYellow c2 = Qt.darkGreen ysch = 20000000 elif keuze == '5': s1 = 16 s2 = 17 t1 = 'Inhuur begroot' t2 = 'Inhuur werkelijk' t3 = 'Inhuur ' c1 = Qt.darkBlue c2 = Qt.darkRed ysch = 30000000 elif keuze == '6': s1 = 18 s2 = 19 t1 = 'Diensten begroot' t2 = 'Diensten werkelijk' t3 = 'Diensten ' c1 = Qt.red c2 = Qt.blue ysch = 30000000 elif keuze == '7': s1 = 14 s2 = 15 t1 = 'Projektkosten begroot' t2 = 'Projektkosten werkelijk' t3 = 'Projektkosten ' c1 = Qt.darkYellow c2 = Qt.darkCyan ysch = 10000000 elif keuze == '8': y3 = [ 0, ] y3val = 0 x1 = [ 0, ] xval1 = 0 # prognose winst for teller in range(0, 53): y3val = y3val + bw_incr y3 = y3 + [(y3val)] xval1 = xval1 + 1 x1 = x1 + [(xval1)] s1 = 20 s2 = 20 t1 = 'Bruto winst prognose' t2 = 'Bruto winst actueel' t3 = 'Bruto winst - prognose / aktueel ' c1 = Qt.darkCyan c2 = Qt.darkMagenta ysch = 20000000 elif keuze == '9': s1 = 6 s2 = 4 t1 = 'Onderhandenwerk' t2 = 'Betaald bedrag' t3 = 'Onderhandenwerk - Betaald bedrag ' c1 = Qt.yellow c2 = Qt.green ysch = 160000000 elif keuze == 'A': y4 = [ 0, ] y4val = 0 x2 = [ 0, ] xval2 = 0 #prognose omzet for teller in range(0, 53): y4val = y4val + bo_incr y4 = y4 + [(y4val)] xval2 = xval2 + 1 x2 = x2 + [(xval2)] s1 = 7 s2 = 7 t1 = 'Omzet prognose' t2 = 'Omzet aktueel' t3 = 'Omzet ' c1 = Qt.red c2 = Qt.blue ysch = 160000000 elif keuze == 'B': s1 = 20 s2 = 5 t1 = 'Bruto winst werkelijk' t2 = 'Meerminderwerk' t3 = 'Bruto winst werkelijk / Meerminderwerk ' c1 = Qt.darkRed c2 = Qt.darkBlue ysch = 30000000 x = [ 0, ] y1 = [ 0, ] y2 = [ 0, ] idx = 0 yval1 = 0 yval2 = 0 for row in rpres: yval1 = y1[idx] + row[s1] y1 = y1 + [(yval1)] yval2 = y2[idx] + row[s2] y2 = y2 + [(yval2)] x = x + [(int(row[1][4:]))] idx += 1 series1 = QLineSeries() if keuze == '8': for t, val in zip(x1, y3): series1.append(int(t), val) elif keuze == 'A': for t, val in zip(x2, y4): series1.append(int(t), val) else: for t, val in zip(x, y1): series1.append(int(t), val) series2 = QLineSeries() for t, val in zip(x, y2): series2.append(int(t), val) chart = QChart() chart.addSeries(series1) chart.addSeries(series2) series1.setColor(QColor(c1)) series2.setColor(QColor(c2)) series1.setName(t1) series2.setName(t2) chart.legend().setVisible(True) font = QFont() font.setPixelSize(22) chart.setTitleFont(font) chart.setTitle(t3 + jaar) chart.setTitleBrush(QBrush(Qt.black)) chart.legend().setLabelBrush(QColor(Qt.black)) axisX = QCategoryAxis() axisY = QCategoryAxis() axisX.setTitleText('Jaar ' + jaar + ' - Weeknummers') axisX.setTitleBrush(QBrush(Qt.black)) font = QFont("Sans Serif") axisX.setTitleFont(font) axisPen = QPen(QColor(100, 100, 100)) # 100,100,100 axisPen.setWidth(3) axisX.setLinePen(axisPen) axisY.setLinePen(axisPen) axisBrush = QBrush(Qt.black) axisX.setLabelsBrush(axisBrush) axisY.setLabelsBrush(axisBrush) axisX.setGridLineVisible(False) axisY.setGridLineVisible(True) axisX.setShadesBrush(QBrush(QColor(245, 245, 245))) axisX.setShadesVisible(True) for x in range(1, 54): axisX.append(jaar + "-" + ("0" + str(x))[-2:], x) axisX.setRange(0, 53) axisX.setLabelsAngle(-90) axisY = QValueAxis() axisY.setTickCount(33) axisY.setTitleText("Bedragen in Euro") axisY.setTitleFont(font) axisY.setLabelFormat('%d') axisY.setTitleBrush(QBrush(Qt.black)) axisY.setRange(0, ysch) #disable for automatic Y scale #axisY.applyNiceNumbers() #enable by automatic Y scale Lfont = QFont("Sans Serif") Dfont = QFont("Sans Serif") Lfont.setPixelSize(10) Dfont.setPixelSize(10) axisX.setLabelsFont(Dfont) axisY.setLabelsFont(Lfont) axisPen = QPen(QColor('black')) axisPen = QPen() axisPen.setWidth(2) axisX.setLinePen(axisPen) axisX.setLabelsColor(QColor('black')) axisY.setLinePen(axisPen) axisY.setLabelsColor(QColor('black')) chart.addAxis(axisX, Qt.AlignBottom) series1.attachAxis(axisX) axisX.setLabelsAngle(-90) chart.addAxis(axisY, Qt.AlignLeft) series1.attachAxis(axisY) series2.attachAxis(axisY) self.chartView = QChartView(chart) self.chartView.setRenderHint(QPainter.Antialiasing) buttonPreview = QPushButton('Afdrukvoorbeeld') buttonPreview.clicked.connect(self.handle_preview) buttonPreview.setStyleSheet( "color: black; background-color: gainsboro") buttonPrint = QPushButton('Printen') buttonPrint.clicked.connect(self.handle_print) buttonPrint.setStyleSheet( "color: black; background-color: gainsboro") buttonSluit = QPushButton('Sluiten') buttonSluit.clicked.connect(lambda: sluit(self, m_email)) buttonSluit.setStyleSheet( "color: black; background-color: gainsboro") grid.addWidget(self.chartView, 0, 0, 0, 3) grid.addWidget(buttonSluit, 1, 0) grid.addWidget(buttonPrint, 1, 1) grid.addWidget(buttonPreview, 1, 2) self.setLayout(grid) self.setGeometry(200, 40, 1395, 930)
class RectZoomMoveView(QChartView): """ Filter data to be displayed in rectangular body """ rangeSig = pyqtSignal(list) def __init__(self, parent=None): super(RectZoomMoveView, self).__init__(parent) self.setChart(QChart()) self.chart().setMargins(QMargins(5, 5, 5, 5)) self.chart().setContentsMargins(-10, -10, -10, -10) self.chart().setTitle(" ") self.relationState = True # Define two rectangles for background and drawing respectively self.parentRect = QGraphicsRectItem(self.chart()) self.parentRect.setFlag(QGraphicsItem.ItemClipsChildrenToShape, True) self.parentRect.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True) self.RangeItem = RectRangeItem(parent=self.parentRect) self.RangeItem.setZValue(998) pen = QPen(Qt.gray) pen.setWidth(1) self.parentRect.setPen(pen) self.parentRect.setZValue(997) self.scene().addItem(self.parentRect) self.scene().addItem(self.RangeItem) self.RangeItem.hide() self.m_chartRectF = QRectF() self.m_rubberBandOrigin = QPointF(0, 0) self.dataLength = 0 self.RangeItem.selectedChange.connect(self.changeFromRectItem) self.BtnsWidget = ViewButtonsWidget(self) self.BtnsWidget.refreshBtn.clicked.connect(self.updateView) self.BtnsWidget.RelationSig.connect(self.setRelationState) self.BtnsWidget.dateRangeEdit.dateRangeSig.connect(self.changDateRect) def changDateRect(self, daterange): if self.chartTypes == "Bar": v = 3 else: v = 2 l = len(self.RangeItem.rangePoints) if l > 2: try: num = self.mintimeData.date().daysTo(daterange[0]) left = self.RangeItem.rangePoints[num] num = self.mintimeData.date().daysTo(daterange[1]) right = self.RangeItem.rangePoints[num] rect = self.chart().plotArea() rect.setLeft(left) rect.setRight(right) except: rect = self.chart().plotArea() self.RangeItem.setRect(rect) self.RangeItem.updateHandlesPos() else: try: num = self.mintimeData.date().daysTo(daterange[0]) left = self.RangeItem.rangePoints[num] num = self.mintimeData.date().daysTo(daterange[0]) right = self.RangeItem.rangePoints[num] rect = self.chart().plotArea() rect.setLeft(left) rect.setRight(right) except: rect = self.chart().plotArea() self.RangeItem.setRect(rect) self.RangeItem.updateHandlesPos() def lineSpace(self, start, end, num): res = [] if self.chartTypes == "Bar": step = (end - start) / (num) for i in range(num + 2): res.append(start + i * step) else: step = (end - start) / (num - 1) for i in range(num + 1): res.append(start + i * step) return res def getRangePoints(self): count = self.zoomSeries.count() rect = self.chart().plotArea() left = rect.left() right = rect.right() if count == 0: self.RangeItem.rangePoints = [left, right] else: # Get coordinate position for each node self.RangeItem.rangePoints = self.lineSpace(left, right, count) def setRangeColor(self, color): self.RangeItem.setRangeColor(color) def setRelationState(self, state): self.relationState = state def initSeries(self, chartTypes="Bar"): self.chartTypes = chartTypes axisX = QDateTimeAxis() axisX.setFormat("yyyy-MM-dd") self.zoomSeries = QLineSeries(self.chart()) self.chart().addSeries(self.zoomSeries) self.chart().setAxisY(QValueAxis(), self.zoomSeries) self.chart().setAxisX(axisX, self.zoomSeries) self.initView() def clearAll(self): # Clear all series and axes self.chart().removeAllSeries() axess = self.chart().axes() for axes in axess: self.chart().removeAxis(axes) def setData(self, timeData, valueData, chartTypes="Bar"): axisX = QDateTimeAxis() axisX.setFormat("yyyy-MM-dd") if self.chartTypes == "Bar": # Clear all series self.clearAll() self.zoomSeries = QLineSeries(self.chart()) barSeries = QBarSeries(self.chart()) barset = QBarSet("data") barSeries.setBarWidth(0.8) barSeries.append(barset) for td, vd in zip(timeData, valueData): self.zoomSeries.append(td.toMSecsSinceEpoch(), vd) barset.append(valueData) self.zoomSeries.hide() self.chart().addSeries(self.zoomSeries) self.chart().addSeries(barSeries) self.chart().setAxisY(QValueAxis(), self.zoomSeries) axisX.setRange(min(timeData), max(timeData)) self.chart().setAxisX(axisX, self.zoomSeries) elif self.chartTypes == "Scatter": # Clear all series self.clearAll() self.zoomSeries = QLineSeries(self.chart()) scattSeries = QScatterSeries(self.chart()) scattSeries.setMarkerSize(8) for td, vd in zip(timeData, valueData): self.zoomSeries.append(td.toMSecsSinceEpoch(), vd) scattSeries.append(td.toMSecsSinceEpoch(), vd) self.zoomSeries.hide() self.chart().addSeries(self.zoomSeries) self.chart().addSeries(scattSeries) self.chart().setAxisY(QValueAxis(), self.zoomSeries) axisX.setRange(min(timeData), max(timeData)) self.chart().setAxisX(axisX, self.zoomSeries) elif self.chartTypes in ["Line", "PLine"]: self.clearAll() if self.chartTypes == "Line": self.zoomSeries = QLineSeries(self.chart()) else: self.zoomSeries = QSplineSeries(self.chart()) for td, vd in zip(timeData, valueData): self.zoomSeries.append(td.toMSecsSinceEpoch(), vd) self.chart().addSeries(self.zoomSeries) self.chart().setAxisY(QValueAxis(), self.zoomSeries) axisX.setRange(min(timeData), max(timeData)) self.chart().setAxisX(axisX, self.zoomSeries) elif self.chartTypes == "Area": self.clearAll() self.zoomSeries = QLineSeries() self.zoomSeries.setColor(QColor("#666666")) for td, vd in zip(timeData, valueData): self.zoomSeries.append(td.toMSecsSinceEpoch(), vd) areaSeries = QAreaSeries(self.zoomSeries, None) self.chart().addSeries(self.zoomSeries) self.chart().addSeries(areaSeries) self.chart().setAxisY(QValueAxis(), areaSeries) axisX.setRange(min(timeData), max(timeData)) self.chart().setAxisX(axisX, areaSeries) self.zoomSeries.hide() self.mintimeData = min(timeData) self.maxtimeData = max(timeData) self.BtnsWidget.dateRangeEdit.setDateRange([ self.mintimeData.toString("yyyy-MM-dd"), self.maxtimeData.toString("yyyy-MM-dd"), ]) self.updateView() def resetView(self): rect = self.chart().plotArea() self.parentRect.setRect(rect) topRight = self.chart().plotArea().topRight() x = int(topRight.x()) y = int(topRight.y()) self.BtnsWidget.setGeometry(QRect(x - 420, 0, 420, 23)) self.RangeItem.setRect(rect) self.RangeItem.show() self.save_current_rubber_band() self.RangeItem.updateHandlesPos() self.apply_nice_numbers() self.getRangePoints() self.sendRang() def initView(self): self.RangeItem.hide() # Hide y-axis if self.chart().axisY(): self.chart().axisY().setVisible(False) if self.chart().axisX(): self.chart().axisX().setGridLineVisible(False) self.m_chartRectF = QRectF() self.m_rubberBandOrigin = QPointF(0, 0) self.getRangePoints() def updateView(self): self.RangeItem.hide() # Hide y-axis if self.chart().axisY(): self.chart().axisY().setVisible(False) if self.chart().axisX(): self.chart().axisX().setGridLineVisible(False) self.m_chartRectF = QRectF() self.m_rubberBandOrigin = QPointF(0, 0) self.resetView() # Map points to chart def point_to_chart(self, pnt): scene_point = self.mapToScene(pnt) chart_point = self.chart().mapToValue(scene_point) return chart_point # Map chart to points def chart_to_view_point(self, char_coord): scene_point = self.chart().mapToPosition(char_coord) view_point = self.mapFromScene(scene_point) return view_point # Save positions of rectangles def save_current_rubber_band(self): rect = self.RangeItem.rect() chart_top_left = self.point_to_chart(rect.topLeft().toPoint()) self.m_chartRectF.setTopLeft(chart_top_left) chart_bottom_right = self.point_to_chart(rect.bottomRight().toPoint()) self.m_chartRectF.setBottomRight(chart_bottom_right) # Respond to change in positions of rectangles def changeFromRectItem(self, rectIndex): self.save_current_rubber_band() self.sendRang(rectIndex) def sendRang(self, rectIndex=[]): if self.RangeItem.rect() != self.parentRect.rect(): self.BtnsWidget.setPalActive() else: self.BtnsWidget.setPalDisActive() if self.chartTypes == "Bar": v = 3 else: v = 2 if rectIndex == []: maxData = QDateTime.fromMSecsSinceEpoch( self.zoomSeries.at(len(self.RangeItem.rangePoints) - v).x()) minData = QDateTime.fromMSecsSinceEpoch(self.zoomSeries.at(0).x()) else: minData = max(rectIndex[0], 0) maxData = min(rectIndex[1], len(self.RangeItem.rangePoints) - v) minData = QDateTime.fromMSecsSinceEpoch( self.zoomSeries.at(minData).x()) maxData = QDateTime.fromMSecsSinceEpoch( self.zoomSeries.at(maxData).x()) if minData > maxData: if self.RangeItem.handleSelected is None: self.resetView() else: self.BtnsWidget.dateRangeEdit.setDate([ minData.toString("yyyy-MM-dd"), maxData.toString("yyyy-MM-dd") ]) if self.relationState: self.rangeSig.emit([ minData.toString("yyyy-MM-dd HH:mm:ss"), maxData.toString("yyyy-MM-dd HH:mm:ss"), ]) # Change positions of rectangles in scaling def resizeEvent(self, event): super().resizeEvent(event) rect = self.chart().plotArea() self.parentRect.setRect(rect) self.getRangePoints() topRight = self.chart().plotArea().topRight() x = int(topRight.x()) y = int(topRight.y()) self.BtnsWidget.setGeometry(QRect(x - 420, 0, 420, 23)) if self.RangeItem.isVisible(): self.restore_rubber_band() self.save_current_rubber_band() self.RangeItem.updateHandlesPos() else: self.RangeItem.setRect(self.parentRect.rect()) self.RangeItem.show() self.RangeItem.setRect(self.parentRect.rect()) self.save_current_rubber_band() self.RangeItem.updateHandlesPos() self.apply_nice_numbers() # Restore to original positions of rectangles def restore_rubber_band(self): view_top_left = self.chart_to_view_point(self.m_chartRectF.topLeft()) view_bottom_right = self.chart_to_view_point( self.m_chartRectF.bottomRight()) self.m_rubberBandOrigin = view_top_left height = self.chart().plotArea().height() rect = QRectF() rect.setTopLeft(view_top_left) rect.setBottomRight(view_bottom_right) rect.setHeight(height) self.RangeItem.setRect(rect) # Adjust display coordinates of axes automatically def apply_nice_numbers(self): axes_list = self.chart().axes() for value_axis in axes_list: if value_axis: pass
class Widget(QWidget): def __init__(self): super().__init__() self.setMinimumSize(800, 600) self.setWindowTitle("Rectifier") self.chartView = QChartView() self.chart = self.chartView.chart() self.series = QLineSeries() self.series2 = QLineSeries() self.series2.setColor(QColor('red')) # for i in range(-90, 90): # rectifier # x = i * pi / 50 # print('x', x) # y = sin(x) # print('y', abs(y)) # self.series.append(x, abs(y)) x = [None] * 400 for n in range(-200, 200): t = n / 100 if t >= -2 and t <= -1: x[n] = 0 elif t >= -1 and t <= 1: x[n] = 1 elif t >= 1 and t <= 2: x[n] = 0 self.series2.append(t, x[n]) self.chart.addSeries(self.series) self.chart.addSeries(self.series2) self.chart.legend().hide() def format_axis(axis, min_value, max_value, step): for s in axis.categoriesLabels(): axis.remove(s) axis.setStartValue(min_value) for i in range(ceil(min_value / step), floor(max_value / step) + 1): v = i * step axis.append('%s' % v, v) axis.setRange(min_value, max_value) grid_pen = QPen(QColor('silver')) grid_pen.setDashPattern([1, 1, 1, 1, 0, 0, 0, 0]) #grid_pen.setDashPattern([1, 1, 0, 0]) axis.setGridLinePen(grid_pen) self.chart.createDefaultAxes() self.chart.axisX().setRange(-5, 5) self.chart.axisX().setGridLineVisible(False) self.chartAxisX = QCategoryAxis( labelsPosition=QCategoryAxis.AxisLabelsPositionOnValue, startValue=0.0) self.chart.setAxisX(self.chartAxisX) format_axis(self.chartAxisX, -5, 5, 1) self.chart.axisY().setRange(-0.1, 1.3) self.chartAxisY = QCategoryAxis( labelsPosition=QCategoryAxis.AxisLabelsPositionOnValue, startValue=0.0) self.chart.setAxisY(self.chartAxisY) format_axis(self.chartAxisY, -0.1, 1.3, 1) self.layout = QGridLayout(self) self.layout.addWidget(self.chartView, 1, 1) self.chartView.show() self.setLayout(self.layout)
class AmzHistoryChart(QWidget): """A chart that graphs the history of an AmazonListing's sales rank, price, and number of offers.""" def __init__(self, parent=None): super(AmzHistoryChart, self).__init__(parent=parent) self.dbsession = Session() self.context_menu_actions = [] self._avg_pointspan = 0 self._max_points = 100 self.source = None self.history = None layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) # Set up the chart self.chart_view = QChartView(self) self.chart_view.setRenderHint(QPainter.Antialiasing) self.chart_view.setContextMenuPolicy(Qt.CustomContextMenu) self.chart_view.customContextMenuRequested.connect(self.context_menu) self.chart = QChart() self.chart.legend().hide() self.chart.setFlags(QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsSelectable) self.chart.installEventFilter(self) self.chart_view.setChart(self.chart) self.layout().addWidget(self.chart_view) # Create the axes rcolor = QColor(50, 130, 220) pcolor = QColor(0, 200, 0) ocolor = QColor(255, 175, 0) self.timeAxis = QDateTimeAxis() self.timeAxis.setFormat('M/dd hh:mm') self.timeAxis.setTitleText('Date/Time') self.chart.addAxis(self.timeAxis, Qt.AlignBottom) self.timeAxis.minChanged.connect(self.on_timeaxis_min_changed) self.rankAxis = QValueAxis() self.rankAxis.setLabelFormat('%\'i') self.rankAxis.setTitleText('Sales Rank') self.rankAxis.setLinePenColor(rcolor) self.rankAxis.setLabelsColor(rcolor) self.chart.addAxis(self.rankAxis, Qt.AlignLeft) self.priceAxis = QValueAxis() self.priceAxis.setLabelFormat('$%.2f') self.priceAxis.setTitleText('Price') self.priceAxis.setLinePenColor(pcolor) self.priceAxis.setLabelsColor(pcolor) self.chart.addAxis(self.priceAxis, Qt.AlignRight) # Create the series self.rankLine = QLineSeries() self.chart.addSeries(self.rankLine) self.rankLine.attachAxis(self.timeAxis) self.rankLine.attachAxis(self.rankAxis) self.rankLine.setColor(rcolor) self.priceLine = QLineSeries() self.chart.addSeries(self.priceLine) self.priceLine.attachAxis(self.timeAxis) self.priceLine.attachAxis(self.priceAxis) self.priceLine.setColor(pcolor) self.salesPoints = QScatterSeries() self.chart.addSeries(self.salesPoints) self.salesPoints.attachAxis(self.timeAxis) self.salesPoints.attachAxis(self.rankAxis) self.salesPoints.setColor(ocolor) def add_context_action(self, action): """Add an action to the chart's context menu.""" self.context_menu_actions.append(action) def add_context_actions(self, actions): """Adds all action in an iterable.""" self.context_menu_actions.extend(actions) def remove_context_action(self, action): """Removes an action from the chart's context menu.""" self.context_menu_actions.remove(action) def context_menu(self, point): """Show a context menu on the chart.""" menu = QMenu(self) menu.addActions(self.context_menu_actions) point = self.chart_view.viewport().mapToGlobal(point) menu.popup(point) def set_source(self, source): """Set the source listing for the graph.""" self.source = source # Update the chart self.rankLine.clear() self.priceLine.clear() self.salesPoints.clear() self.history = None start_date = datetime.utcnow() - timedelta(days=5) self.load_history_from(start_date) self.reset_axes() def load_history_from(self, start_date=datetime.utcfromtimestamp(0)): """Load history data from start-present.""" if not self.source: self._avg_pointspan = 0 return # Get the earliest point already in the chart points = self.rankLine.pointsVector() if points: # The chart is drawn right-to-left, so the last point is the earliest point earliest_msecs = points[-1].x() earliest = datetime.fromtimestamp(earliest_msecs / 1000, timezone.utc) if earliest <= start_date: return else: earliest = datetime.now(timezone.utc) # Get the product history stats if we don't already have them if self.history is None: self.history = dbhelpers.ProductHistoryStats(self.dbsession, self.source.id) # Start adding points to the chart last_row = None for row in self.dbsession.query(AmzProductHistory).\ filter(AmzProductHistory.amz_listing_id == self.source.id, AmzProductHistory.timestamp > start_date.replace(tzinfo=None), AmzProductHistory.timestamp < earliest.replace(tzinfo=None)).\ order_by(AmzProductHistory.timestamp.desc()): # SqlAlchemy returns naive timestamps time = row.timestamp.replace(tzinfo=timezone.utc).timestamp() * 1000 self.rankLine.append(time, row.salesrank or 0) self.priceLine.append(time, row.price or 0) if last_row: # It's possible for salesrank to be None try: slope = (last_row.salesrank - row.salesrank) / (last_row.timestamp.timestamp() - row.timestamp.timestamp()) if slope < -0.3: self.salesPoints.append(last_row.timestamp.replace(tzinfo=timezone.utc).timestamp() * 1000, last_row.salesrank) except (TypeError, AttributeError): pass last_row = row # Calculate the average span between points spans = 0 for p1, p2 in itertools.zip_longest(itertools.islice(points, 0, None, 2), itertools.islice(points, 1, None, 2)): if p1 and p2: spans += abs(p1.x() - p2.x()) self._avg_pointspan = spans // 2 def on_timeaxis_min_changed(self, min): """Respond to a change in the time axis' minimum value.""" # toTime_t() converts to UTC automatically utc_min = datetime.fromtimestamp(min.toTime_t(), timezone.utc) self.load_history_from(start_date=utc_min - timedelta(days=1)) def reset_axes(self): """Resets the chart axes.""" r = self.rankLine.pointsVector() p = self.priceLine.pointsVector() # If there is only one data point, set the min and max to the day before and the day after if len(r) == 1: tmin = QDateTime.fromMSecsSinceEpoch(r[0].x(), Qt.LocalTime).addDays(-1) tmax = QDateTime.fromMSecsSinceEpoch(r[0].x(), Qt.LocalTime).addDays(+1) else: tmin = min(r, key=lambda pt: pt.x(), default=QPointF(QDateTime.currentDateTime().addDays(-1).toMSecsSinceEpoch(), 0)).x() tmax = max(r, key=lambda pt: pt.x(), default=QPointF(QDateTime.currentDateTime().addDays(+1).toMSecsSinceEpoch(), 0)).x() tmin = QDateTime.fromMSecsSinceEpoch(tmin, Qt.LocalTime) tmax = QDateTime.fromMSecsSinceEpoch(tmax, Qt.LocalTime) self.timeAxis.setMin(tmin) self.timeAxis.setMax(tmax) # Find the min and max values of the series min_point = lambda pts: min(pts, key=lambda pt: pt.y(), default=QPointF(0, 0)) max_point = lambda pts: max(pts, key=lambda pt: pt.y(), default=QPointF(0, 0)) rmin = min_point(r) rmax = max_point(r) pmin = min_point(p) pmax = max_point(p) # Scale the mins and maxes to 'friendly' values scalemin = lambda v, step: ((v - step / 2) // step) * step scalemax = lambda v, step: ((v + step / 2) // step + 1) * step # The the axis bounds rmin = max(scalemin(rmin.y(), 1000), 0) rmax = scalemax(rmax.y(), 1000) pmin = max(scalemin(pmin.y(), 5), 0) pmax = scalemax(pmax.y(), 5) self.rankAxis.setMin(rmin) self.rankAxis.setMax(rmax) self.priceAxis.setMin(pmin) self.priceAxis.setMax(pmax) def eventFilter(self, watched, event): """Intercept and handle mouse events.""" if event.type() == QEvent.GraphicsSceneWheel and event.orientation() == Qt.Vertical: factor = 0.95 if event.delta() < 0 else 1.05 self.chart.zoom(factor) return True if event.type() == QEvent.GraphicsSceneMouseDoubleClick: self.chart.zoomReset() self.reset_axes() return True if event.type() == QEvent.GraphicsSceneMouseMove: delta = event.pos() - event.lastPos() self.chart.scroll(-delta.x(), delta.y()) return True return False