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
class ChartView(QChartView): def __init__(self, file, parent=None): super(ChartView, self).__init__(parent) self._chart = QChart() self._chart.setAcceptHoverEvents(True) self.setChart(self._chart) self.initUi(file) def initUi(self, file): if isinstance(file, dict): return self.__analysis(file) if isinstance(file, str): if not os.path.isfile(file): return self.__analysis(json.loads(file)) with open(file, "rb") as fp: data = fp.read() encoding = chardet.detect(data) or {} data = data.decode(encoding.get("encoding") or "utf-8") self.__analysis(json.loads(data)) # def onSeriesHoverd(self, point, state): # print(point, state) def mouseMoveEvent(self, event): super(ChartView, self).mouseMoveEvent(event) # 获取x和y轴的最小最大值 axisX, axisY = self._chart.axisX(), self._chart.axisY() min_x, max_x = axisX.min(), axisX.max() min_y, max_y = axisY.min(), axisY.max() # 把鼠标位置所在点转换为对应的xy值 x = self._chart.mapToValue(event.pos()).x() y = self._chart.mapToValue(event.pos()).y() index = round(x) # 四舍五入 print(x, y, index) # 得到在坐标系中的所有series的类型和点 points = [(s.type(), s.at(index)) for s in self._chart.series() if min_x <= x <= max_x and min_y <= y <= max_y] print(points) def __getColor(self, color=None, default=Qt.white): ''' :param color: int|str|[r,g,b]|[r,g,b,a] ''' if not color: return QColor(default) if isinstance(color, QBrush): return color # 比如[r,g,b]或[r,g,b,a] if isinstance(color, list) and 3 <= len(color) <= 4: return QColor(*color) else: return QColor(color) def __getPen(self, pen=None, default=QPen(Qt.white, 1, Qt.SolidLine, Qt.SquareCap, Qt.BevelJoin)): ''' :param pen: pen json ''' if not pen or not isinstance(pen, dict): return default return QPen(self.__getColor(pen.get("color", None) or default.color()), pen.get("width", 1) or 1, pen.get("style", 0) or 0, pen.get("capStyle", 16) or 16, pen.get("joinStyle", 64) or 64) def __getAlignment(self, alignment): ''' :param alignment: left|top|right|bottom ''' try: return getattr(Qt, "Align" + alignment.capitalize()) except: return Qt.AlignTop # if alignment == "left": # return Qt.AlignLeft # if alignment == "right": # return Qt.AlignRight # if alignment == "bottom": # return Qt.AlignBottom # return Qt.AlignTop def __setTitle(self, title=None): ''' :param title: title json ''' if not title or not isinstance(title, dict): return # 设置标题 self._chart.setTitle(title.get("text", "") or "") # 设置标题颜色 self._chart.setTitleBrush( self.__getColor( title.get("color", self._chart.titleBrush()) or self._chart.titleBrush())) # 设置标题字体 font = QFont(title.get("font", "") or self._chart.titleFont()) pointSize = title.get("pointSize", -1) or -1 if pointSize > 0: font.setPointSize(pointSize) font.setWeight(title.get("weight", -1) or -1) font.setItalic(title.get("italic", False) or False) self._chart.setTitleFont(font) def __setAnimation(self, animation=None): ''' :param value: animation json ''' if not animation or not isinstance(animation, dict): return # 动画持续时间 self._chart.setAnimationDuration( animation.get("duration", 1000) or 1000) # 设置动画曲线 self._chart.setAnimationEasingCurve( EasingCurve.get(animation.get("curve", 10) or 10, None) or QEasingCurve.OutQuart) # 设置开启何种动画 self._chart.setAnimationOptions( AnimationOptions.get(animation.get("options", 0) or 0, None) or QChart.NoAnimation) def __setBackground(self, background=None): ''' :param background:background json ''' if not background or not isinstance(background, dict): return # 设置是否背景可用 self._chart.setBackgroundVisible( background.get("visible", True) or True) # 设置背景矩形的圆角 self._chart.setBackgroundRoundness(background.get("radius", 0) or 0) # 设置下拉阴影 self._chart.setDropShadowEnabled( background.get("dropShadow", True) or True) # 设置pen self._chart.setBackgroundPen( self.__getPen(background.get("pen", None), self._chart.backgroundPen())) # 设置背景 image = background.get("image", None) color = background.get("color", None) if image: self._chart.setBackgroundBrush(QBrush(QPixmap(image))) elif color: self._chart.setBackgroundBrush( self.__getColor(color, self._chart.backgroundBrush())) def __setMargins(self, margins=None): ''' :param margins: margins json ''' if not margins or not isinstance(margins, dict): return left = margins.get("left", 20) or 20 top = margins.get("top", 20) or 20 right = margins.get("right", 20) or 20 bottom = margins.get("bottom", 20) or 20 self._chart.setMargins(QMargins(left, top, right, bottom)) def __setLegend(self, legend=None): ''' :param legend: legend json ''' if not legend or not isinstance(legend, dict): return _legend = self._chart.legend() _legend.setAlignment(self.__getAlignment(legend.get("alignment", None))) _legend.setShowToolTips(legend.get("showToolTips", True) or True) def __getSerie(self, serie=None): if not serie or not isinstance(serie, dict): return None types = serie.get("type", "") or "" data = serie.get("data", []) or [] if not data or not isinstance(data, list): return None if types == "line": _series = QLineSeries(self._chart) else: return None # 设置series名字 _series.setName(serie.get("name", "") or "") # 添加数据到series中 for index, value in enumerate(data): # 保证vlaue必须是数字 _series.append(index, value if type(value) in (int, float) else 0) return _series def __setSeries(self, series=None): if not series or not isinstance(series, list): return for serie in series: _serie = self.__getSerie(serie) if _serie: # _serie.hovered.connect(self.onSeriesHoverd) self._chart.addSeries(_serie) # 创建默认的xy轴 self._chart.createDefaultAxes() def __setAxisX(self, axisx=None): if not axisx or not isinstance(axisx, dict): return series = self._chart.series() if not series: return types = axisx.get("type", None) data = axisx.get("data", []) or [] if not data or not isinstance(data, list): return None minx = self._chart.axisX().min() maxx = self._chart.axisX().max() if types == "category": xaxis = QCategoryAxis( self._chart, labelsPosition=QCategoryAxis.AxisLabelsPositionOnValue) # 隐藏网格 xaxis.setGridLineVisible(False) # 刻度条数 tickc_d = len(data) tickc = tickc_d if tickc_d > 1 else self._chart.axisX().tickCount() xaxis.setTickCount(tickc) # 强制x轴刻度与新刻度条数一致 self._chart.axisX().setTickCount(tickc) step = (maxx - minx) / (tickc - 1) for i in range(min(tickc_d, tickc)): xaxis.append(data[i], minx + i * step) self._chart.setAxisX(xaxis, series[-1]) def __analysis(self, datas): ''' analysis json data :param datas: json data ''' # 标题 self.__setTitle(datas.get("title", None)) # 抗锯齿 if (datas.get("antialiasing", False) or False): self.setRenderHint(QPainter.Antialiasing) # 主题 self._chart.setTheme(datas.get("theme", 0) or 0) # 动画 self.__setAnimation(datas.get("animation", None)) # 背景设置 self.__setBackground(datas.get("background", None)) # 边距设置 self.__setMargins(datas.get("margins", None)) # 设置图例 self.__setLegend(datas.get("legend", None)) # 设置series self.__setSeries(datas.get("series", None)) # 自定义的x轴 self.__setAxisX(datas.get("axisx", None))
class LeftBarBarChart(QTabWidget): chart = None tabs = [] bar_sets = [] inputs = [] main_tab = None def __init__(self, parent): super(LeftBarBarChart, self).__init__() self.setParent(parent) self.setStyleSheet(""" color: white; border-radius: 4px; background:rgb(37,43,52,220); """) self.init_ui() def init_ui(self): # Tab Bar self.tab_bar = TabBarPlus(self) self.setTabBar(self.tab_bar) # Properties # self.setMovable(True) # Signals self.tab_bar.plusClicked.connect(self.add_tab) self.tab_bar.tabMoved.connect(self.tab_bar.movePlusButton) self.tabCloseRequested.connect(self.removeTab) ####### self.chart = QChart() self.serie = QBarSeries() self.chart.addSeries(self.serie) self.chart.setTitle("Bar Chart") self.main_tab = MainTab(self) self.addTab(self.main_tab, self.main_tab.name) self.chart.createDefaultAxes() self.chart.setAnimationDuration(2000) self.chart.setAnimationOptions(QChart.AllAnimations) def add_tab(self): if self.count() >= 0: self.setTabsClosable(True) else: self.setTabsClosable(False) tab = Tab(self, "New Tab", len(self.main_tab.all_inputs)) self.tabs.append(tab) self.addTab(tab, tab.name) def removeTab(self, p_int): if self.count() > 1: super(LeftBarBarChart, self).removeTab(p_int) del self.tabs[p_int - 1] if self.count() >= 2: self.setTabsClosable(True) else: self.setTabsClosable(False) def update_all_tabs(self, amount): for tab in self.tabs: tab.update_tab(amount) def update_axes(self): self.chart.removeSeries(self.serie) self.chart.addSeries(self.serie) self.chart.createDefaultAxes()
class GraphicsScene(QGraphicsScene): def __init__(self): super(GraphicsScene, self).__init__() self.line_series = QLineSeries() self.chart = QChart() self.chart_view = QChartView(self.chart) self.chart_view.setMinimumSize(640, 480) self.model = ItemModel() self.model.signal_update_models.connect(self.update_axes) self.table_view = TableView() self.table_view.setModel(self.model) self.table_view.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self.table_view.verticalHeader().setSectionResizeMode( QHeaderView.Stretch) self.chart.setAnimationOptions(QChart.AllAnimations) self.chart.setAnimationDuration(2000) self.line_series.setName("Line 1") self.mapper = QVXYModelMapper(self) self.mapper.setXColumn(0) self.mapper.setYColumn(1) self.mapper.setSeries(self.line_series) self.mapper.setModel(self.model) self.chart.addSeries(self.line_series) seriesColorHex = self.line_series.pen().color().name() self.model.add_mapping(seriesColorHex, QRect(0, 0, 2, self.model.rowCount())) self.line_series2 = QLineSeries() self.line_series2.setName("Line 2") self.mapper2 = QVXYModelMapper(self) self.mapper2.setXColumn(2) self.mapper2.setYColumn(3) self.mapper2.setSeries(self.line_series2) self.mapper2.setModel(self.model) self.chart.addSeries(self.line_series2) seriesColorHex = self.line_series2.pen().color().name() self.model.add_mapping(seriesColorHex, QRect(2, 0, 2, self.model.rowCount())) self.chart.createDefaultAxes() self.chart_view.setRenderHint(QPainter.Antialiasing) self.chart.resize(500, 400) self.chart.setFlag(QGraphicsItem.ItemIsMovable) self.chart.setFlag(QGraphicsItem.ItemIsSelectable) self.addItem(self.chart) @pyqtSlot() def update_axes(self): self.chart.removeSeries(self.line_series) self.chart.removeSeries(self.line_series2) self.chart.addSeries(self.line_series) self.chart.addSeries(self.line_series2) self.chart.createDefaultAxes()
class LeftBarPieChart(QWidget): def __init__(self, parent): super(LeftBarPieChart, self).__init__() self.parent = parent self.setParent(parent) self.chart = None self.inputs = [] self.layout = None self.layout_inp = None self.btn_add = None self.w_inp = None self.header = None self.init_ui() def init_ui(self): self.chart = QChart() self.chart.setTheme(QChart.ChartThemeBlueIcy) self.chart.setAnimationDuration(1000) self.chart.setAnimationOptions(QChart.AllAnimations) self.serie = QPieSeries() self.layout = QVBoxLayout() self.layout_inp = QVBoxLayout() self.w_inp = QWidget() self.w_inp.setStyleSheet(""" .QWidget{ background-color: transparent; } """) self.w_inp.setLayout(self.layout_inp) self.setLayout(self.layout) self.inputs.append(InputPieChart(self)) self.btn_add = QPushButton("+") self.btn_remove = QPushButton("-") self.btn_add.clicked.connect(self.add_input) self.btn_remove.clicked.connect(self.remove_input) self.btn_add.setStyleSheet(""" border: 0px; background: green; color: white; """) self.btn_remove.setStyleSheet(""" border: 0px; background: red; color: white; """) self.header = HeaderPieChartInput() self.layout.addWidget(self.header) self.layout.addWidget(self.w_inp) self.layout.addStretch(-1) self.layout.addWidget(self.btn_remove) self.layout.addWidget(self.btn_add) self.layout_inp.addWidget(self.inputs[0]) self.serie.append(self.inputs[0].name.text(), 2) # self.slice.setExploded() # self.slice.setLabelVisible() # self.slice.setPen(QPen(Qt.darkGreen,2)) # self.slice.setBrush(Qt.green) self.chart.addSeries(self.serie) self.chart.setTitle("Pie Chart") def add_input(self): if len(self.inputs) < 10: self.inputs.append(InputPieChart(self)) self.layout_inp.addWidget(self.inputs[-1]) self.serie.append(self.inputs[-1].name.text(), int(self.inputs[-1].value.text())) # for slice in self.serie.slices(): # slice.setBrush(Qt.green) def remove_input(self): if len(self.inputs) >= 1: self.layout_inp.removeWidget(self.inputs[-1]) self.inputs[-1].hide() self.inputs.remove(self.inputs[-1]) self.slc = self.serie.slices()[-1] self.serie.remove(self.slc) # for slice in self.serie.slices(): # slice.setBrush(Qt.green) def input_changed(self, txt): if self.serie in self.chart.series(): self.chart.removeSeries(self.serie) self.serie = QPieSeries() for inp in self.inputs: self.serie.append(inp.name.text(), int(inp.value.text())) self.chart.addSeries(self.serie)
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.init_ui() def init_ui(self): self.line_series = QLineSeries() self.chart = QChart() self.chart_view = QChartView(self.chart) self.chart_view.setMinimumSize(640,480) self.model = ItemModel() self.model.signal_update_models.connect(self.update_axes) self.table_view = TableView() self.table_view.setModel(self.model) self.table_view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) self.table_view.verticalHeader().setSectionResizeMode(QHeaderView.Stretch) self.chart.setAnimationOptions(QChart.AllAnimations) self.chart.setAnimationDuration(2000) self.line_series.setName("Line 1") self.mapper = QVXYModelMapper(self) self.mapper.setXColumn(0) self.mapper.setYColumn(1) self.mapper.setSeries(self.line_series) self.mapper.setModel(self.model) self.chart.addSeries(self.line_series) seriesColorHex = self.line_series.pen().color().name() self.model.add_mapping(seriesColorHex, QRect(0,0,2, self.model.rowCount())) self.line_series2 = QLineSeries() self.line_series2.setName("Line 2") self.mapper2 = QVXYModelMapper(self) self.mapper2.setXColumn(2) self.mapper2.setYColumn(3) self.mapper2.setSeries(self.line_series2) self.mapper2.setModel(self.model) self.chart.addSeries(self.line_series2) seriesColorHex = self.line_series2.pen().color().name() self.model.add_mapping(seriesColorHex, QRect(2, 0, 2, self.model.rowCount())) self.chart.createDefaultAxes() self.grid = QGridLayout() self.grid.addWidget(self.table_view,0,0) self.grid.addWidget(self.chart_view,0,1) self.chart_view.setRenderHint(QPainter.Antialiasing) self.cw = QWidget() self.cw.setLayout(self.grid) self.setCentralWidget(self.cw) self.resize(400,300) @pyqtSlot() def update_axes(self): self.chart.removeSeries(self.line_series) self.chart.removeSeries(self.line_series2) self.chart.addSeries(self.line_series) self.chart.addSeries(self.line_series2) self.chart.createDefaultAxes()