simple BarStack
This commit is contained in:
parent
8add13065d
commit
ece4019bc0
4 changed files with 78 additions and 72 deletions
|
@ -11,3 +11,4 @@ like [百度 echarts](http://echarts.baidu.com/demo.htmlhttp://echarts.baidu.com
|
|||
|
||||
### [2.charts](charts/)
|
||||
- [2.1 折线图](charts/line)
|
||||
- [2.2 柱状图](charts/bar)
|
|
@ -6,3 +6,6 @@
|
|||
|
||||
### [1.折线图](line/)
|
||||
- [1.1 折线图堆叠](line/LineStack.py)
|
||||
|
||||
### [2.柱状图](bar/)
|
||||
- [2.1 柱状图堆叠](bar/BarStack.py)
|
|
@ -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 = ["邮件营销","联盟广告","视频广告","直接访问","搜索引擎"]
|
||||
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 |
Loading…
Reference in a new issue