simple BarStack

This commit is contained in:
Irony 2018-01-24 23:43:22 +08:00
parent 8add13065d
commit ece4019bc0
4 changed files with 78 additions and 72 deletions

View file

@ -10,4 +10,5 @@ like [百度 echarts](http://echarts.baidu.com/demo.htmlhttp://echarts.baidu.com
- [1.3 ToolTip](test/ToolTip.py)
### [2.charts](charts/)
- [2.1 折线图](charts/line)
- [2.1 折线图](charts/line)
- [2.2 柱状图](charts/bar)

View file

@ -5,4 +5,7 @@
### [Python3.5 or latter][PyQt5 PyQtChart]
### [1.折线图](line/)
- [1.1 折线图堆叠](line/LineStack.py)
- [1.1 折线图堆叠](line/LineStack.py)
### [2.柱状图](bar/)
- [2.1 柱状图堆叠](bar/BarStack.py)

View file

@ -10,15 +10,14 @@ Created on 2017年12月28日
@description: like http://echarts.baidu.com/demo.html#bar-stack
'''
from random import randint
import sys
from PyQt5.QtChart import QChartView, QChart, QLineSeries, QLegend,\
QCategoryAxis, QBarSeries, QBarSet, QBarCategoryAxis
from PyQt5.QtChart import QChartView, QChart, QBarSeries, QBarSet, QBarCategoryAxis
from PyQt5.QtCore import Qt, QPointF, QRectF, QPoint
from PyQt5.QtGui import QPainter, QPen
from PyQt5.QtWidgets import QApplication, QGraphicsLineItem, QWidget, \
QHBoxLayout, QLabel, QVBoxLayout, QGraphicsProxyWidget
from random import randint
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
@ -58,18 +57,22 @@ class ToolTipWidget(QWidget):
self.titleLabel = QLabel(self, styleSheet="color:white;")
layout.addWidget(self.titleLabel)
def updateUi(self, title, points):
def updateUi(self, title, bars):
self.titleLabel.setText(title)
for serie, point in points:
if serie not in self.Cache:
for bar, value in bars:
if bar not in self.Cache:
item = ToolTipItem(
serie.color(),
(serie.name() or "-") + ":" + str(point.y()), self)
bar.color(),
(bar.label() or "-") + ":" + str(value), self)
self.layout().addWidget(item)
self.Cache[serie] = item
self.Cache[bar] = item
else:
self.Cache[serie].setText(
(serie.name() or "-") + ":" + str(point.y()))
self.Cache[bar].setText(
(bar.label() or "-") + ":" + str(value))
brush = bar.brush()
color = brush.color()
self.Cache[bar].setVisible(color.alphaF() == 1.0) # 隐藏那些不可用的项
self.adjustSize() # 调整大小
class GraphicsProxyWidget(QGraphicsProxyWidget):
@ -87,9 +90,9 @@ class GraphicsProxyWidget(QGraphicsProxyWidget):
def height(self):
return self.size().height()
def show(self, title, points, pos):
def show(self, title, bars, pos):
self.setGeometry(QRectF(pos, self.size()))
self.tipWidget.updateUi(title, points)
self.tipWidget.updateUi(title, bars)
super(GraphicsProxyWidget, self).show()
@ -104,26 +107,22 @@ class ChartView(QChartView):
# 提示widget
self.toolTipWidget = GraphicsProxyWidget(self._chart)
# line
# line 宽度需要调整
self.lineItem = QGraphicsLineItem(self._chart)
pen = QPen(Qt.gray)
pen.setWidth(1)
self.lineItem.setPen(pen)
self.lineItem.setZValue(998)
self.lineItem.hide()
'''
# 一些固定计算减少mouseMoveEvent中的计算量
# 获取x和y轴的最小最大值
axisX, axisY = self._chart.axisX(), self._chart.axisY()
self.min_x, self.max_x = axisX.min(), axisX.max()
self.category_len = len(axisX.categories())
self.min_x, self.max_x = -0.5, self.category_len - 0.5
self.min_y, self.max_y = axisY.min(), axisY.max()
# 坐标系中左上角顶点
self.point_top = self._chart.mapToPosition(
QPointF(self.min_x, self.max_y))
# 坐标原点坐标
self.point_bottom = self._chart.mapToPosition(
QPointF(self.min_x, self.min_y))
self.step_x = (self.max_x - self.min_x) / (axisX.tickCount() - 1)
def mouseMoveEvent(self, event):
super(ChartView, self).mouseMoveEvent(event)
@ -131,18 +130,24 @@ class ChartView(QChartView):
# 把鼠标位置所在点转换为对应的xy值
x = self._chart.mapToValue(pos).x()
y = self._chart.mapToValue(pos).y()
index = round((x - self.min_x) / self.step_x)
# 得到在坐标系中的所有series的类型和点
points = [(serie, serie.at(index))
for serie in self._chart.series() if self.min_x <= x <= self.max_x and self.min_y <= y <= self.max_y]
if points:
pos_x = self._chart.mapToPosition(
QPointF(index * self.step_x + self.min_x, self.min_y))
self.lineItem.setLine(pos_x.x(), self.point_top.y(),
pos_x.x(), self.point_bottom.y())
index = round(x)
# 得到在坐标系中的所有bar的类型和点
serie = self._chart.series()[0]
bars = [(bar, bar.at(index))
for bar in serie.barSets() if self.min_x <= x <= self.max_x and self.min_y <= y <= self.max_y]
# print(bars)
if bars:
right_top = self._chart.mapToPosition(
QPointF(self.max_x, self.max_y))
# 等分距离比例
step_x = round(
(right_top.x() - self.point_top.x()) / self.category_len)
posx = self._chart.mapToPosition(QPointF(x, self.min_y))
self.lineItem.setLine(posx.x(), self.point_top.y(),
posx.x(), posx.y())
self.lineItem.show()
try:
title = self.category[index]
title = self.categories[index]
except:
title = ""
t_width = self.toolTipWidget.width()
@ -154,25 +159,30 @@ class ChartView(QChartView):
y = pos.y() - t_height if self.height() - \
pos.y() - 20 < t_height else pos.y()
self.toolTipWidget.show(
title, points, QPoint(x, y))
title, bars, QPoint(x, y))
else:
self.toolTipWidget.hide()
self.lineItem.hide()
'''
def handleMarkerClicked(self):
marker = self.sender() # 信号发送者
if not marker:
return
visible = not marker.series().isVisible()
# # 隐藏或显示series
marker.series().setVisible(visible)
marker.setVisible(True) # 要保证marker一直显示
# 透明度
alpha = 1.0 if visible else 0.4
# 设置label的透明度
bar = marker.barset()
if not bar:
return
# bar透明度
brush = bar.brush()
color = brush.color()
alpha = 0.0 if color.alphaF() == 1.0 else 1.0
color.setAlphaF(alpha)
brush.setColor(color)
bar.setBrush(brush)
# marker
brush = marker.labelBrush()
color = brush.color()
alpha = 0.4 if color.alphaF() == 1.0 else 1.0
# 设置label的透明度
color.setAlphaF(alpha)
brush.setColor(color)
marker.setLabelBrush(brush)
@ -182,62 +192,54 @@ class ChartView(QChartView):
color.setAlphaF(alpha)
brush.setColor(color)
marker.setBrush(brush)
# 设置画笔透明度
pen = marker.pen()
color = pen.color()
color.setAlphaF(alpha)
pen.setColor(color)
marker.setPen(pen)
def handleMarkerHovered(self, status):
# 设置series的画笔宽度
# 设置bar的画笔宽度
marker = self.sender() # 信号发送者
if not marker:
return
series = marker.series()
if not series:
bar = marker.barset()
if not bar:
return
pen = series.pen()
pen = bar.pen()
if not pen:
return
pen.setWidth(pen.width() + (1 if status else -1))
series.setPen(pen)
bar.setPen(pen)
def handleSeriesHoverd(self, status,index,barset):
return print(status,index,barset)
# # 设置series的画笔宽度
# series = self.sender() # 信号发送者
# pen = series.pen()
# if not pen:
# return
# pen.setWidth(pen.width() + (1 if state else -1))
# series.setPen(pen)
def handleBarHoverd(self, status, index):
# 设置bar的画笔宽度
bar = self.sender() # 信号发送者
pen = bar.pen()
if not pen:
return
pen.setWidth(pen.width() + (1 if status else -1))
bar.setPen(pen)
def initChart(self):
self._chart = QChart(title="柱状图堆叠")
self._chart.setAcceptHoverEvents(True)
# Series动画
self._chart.setAnimationOptions(QChart.SeriesAnimations)
categories = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
names = ["邮件营销","联盟广告","视频广告","直接访问","搜索引擎"]
series = QBarSeries(self._chart)
self.categories = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
names = ["邮件营销", "联盟广告", "视频广告", "直接访问", "搜索引擎"]
series = QBarSeries(self._chart)
for name in names:
bar = QBarSet(name)
#随机数据
# 随机数据
for _ in range(7):
bar.append(randint(0,10))
bar.append(randint(0, 10))
series.append(bar)
# series.hovered.connect(self.handleSeriesHoverd) # 鼠标悬停
self._chart.addSeries(series)
bar.hovered.connect(self.handleBarHoverd) # 鼠标悬停
self._chart.addSeries(series)
self._chart.createDefaultAxes() # 创建默认的轴
# x轴
axis_x = QBarCategoryAxis(self._chart)
axis_x.append(categories)
axis_x.append(self.categories)
self._chart.setAxisX(axis_x, series)
# chart的图例
legend = self._chart.legend()
# 设置图例由Series来决定样式
legend.setMarkerShape(QLegend.MarkerShapeFromSeries)
legend.setVisible(True)
# 遍历图例上的标记并绑定信号
for marker in legend.markers():
# 点击事件

Binary file not shown.

Before

Width:  |  Height:  |  Size: 327 KiB

After

Width:  |  Height:  |  Size: 325 KiB