目录
效果:
代码:
import sys
from PyQt5 import QtCore,QtGui,QtWidgets
from PyQt5.QtCore import Qt
from typing import Any,Dict
import pyqtgraph as pg
pg.setConfigOption('background', 'w')
pg.setConfigOption('foreground', 'k')
自定义横坐标控件
class RotateAxisItem(pg.AxisItem):
def drawPicture(self, p, axisSpec, tickSpecs, textSpecs):
p.setRenderHint(p.Antialiasing,False)
p.setRenderHint(p.TextAntialiasing,True)
## draw long line along axis
pen,p1,p2 = axisSpec
p.setPen(pen)
p.drawLine(p1,p2)
p.translate(0.5,0) ## resolves some damn pixel ambiguity
## draw ticks
for pen,p1,p2 in tickSpecs:
p.setPen(pen)
p.drawLine(p1,p2)
## draw all text
# if self.tickFont is not None:
# p.setFont(self.tickFont)
p.setPen(self.pen())
for rect,flags,text in textSpecs:
# this is the important part
p.save()
p.translate(rect.x(),rect.y())
p.rotate(-30)
p.drawText(-rect.width(),rect.height(),rect.width(),rect.height(),flags,text)
# restoring the painter is *required*!!!
p.restore()
绘制蜡烛控件
## Create a subclass of GraphicsObject.
## The only required methods are paint() and boundingRect()
## (see QGraphicsItem documentation)
class CandlestickItem(pg.GraphicsObject):
def __init__(self, data):
pg.GraphicsObject.__init__(self)
self.data = data ## data must have fields: time, open, close, min, max
self.generatePicture()
def generatePicture(self):
## pre-computing a QPicture object allows paint() to run much more quickly,
## rather than re-drawing the shapes every time.
self.picture = QtGui.QPicture()
p = QtGui.QPainter(self.picture)
p.setPen(pg.mkPen('d'))
w = (self.data[1][0] - self.data[0][0]) / 3.
for (t, open, close, min, max) in self.data:
p.drawLine(QtCore.QPointF(t, min), QtCore.QPointF(t, max))
if open > close:
p.setBrush(pg.mkBrush('r'))
else:
p.setBrush(pg.mkBrush('g'))
p.drawRect(QtCore.QRectF(t - w, open, w * 2, close - open))
p.end()
def paint(self, p, *args):
p.drawPicture(0, 0, self.picture)
def boundingRect(self):
## boundingRect _must_ indicate the entire area that will be drawn on
## or else we will get artifacts and possibly crashing.
## (in this case, QPicture does all the work of computing the bouning rect for us)
return QtCore.QRectF(self.picture.boundingRect())
绘制蜡烛图控件
class PyQtGraphWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.init_data()
self.init_ui()
def init_data(self):
pass
def init_ui(self):
self.title_label = QtWidgets.QLabel('折线图')
self.title_label.setAlignment(Qt.AlignCenter)
xax = RotateAxisItem(orientation='bottom')
xax.setHeight(h=50)
self.pw = pg.PlotWidget(axisItems={'bottom': xax})
self.pw.setMouseEnabled(x=True, y=False)
# self.pw.enableAutoRange(x=False,y=True)
self.pw.setAutoVisible(x=False, y=True)
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.title_label)
layout.addWidget(self.pw)
self.setLayout(layout)
pass
def set_k_data(self,data:Dict[str,Any]):
'''k线图'''
self.pw.clear()
title_str = data['title_str']
xTick_show = [data['xTick_show']]
xTick = data['xTick']
x = data['x']
candle_data = data['candle_data']
self.y_data = candle_data
self.xTick = xTick
self.title_label.setText(title_str)
xax = self.pw.getAxis('bottom')
xax.setTicks(xTick_show)
candle_item_list = CandlestickItem(candle_data)
self.pw.addItem(candle_item_list)
self.vLine = pg.InfiniteLine(angle=90, movable=False)
self.hLine = pg.InfiniteLine(angle=0, movable=False)
self.label = pg.TextItem()
self.pw.addItem(self.vLine, ignoreBounds=True)
self.pw.addItem(self.hLine, ignoreBounds=True)
self.pw.addItem(self.label, ignoreBounds=True)
self.vb = self.pw.getViewBox()
self.proxy = pg.SignalProxy(self.pw.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved)
# 显示整条折线图
self.pw.enableAutoRange()
pass
def mouseMoved(self,evt):
pos = evt[0]
if self.pw.sceneBoundingRect().contains(pos):
mousePoint = self.vb.mapSceneToView(pos)
index = int(mousePoint.x())
if index >= 0 and index < len(self.y_data):
x_str = self.xTick[index][1]
y_str_html = ''
# time, open, close, min, max
y_str_html += '<br/> 开盘:'+str(self.y_data[index][1])
y_str_html += '<br/> 收盘:'+str(self.y_data[index][2])
y_str_html += '<br/> 最低:'+str(self.y_data[index][3])
y_str_html += '<br/> 最高:'+str(self.y_data[index][4])
html_str = '<p style="color:black;font-size:18px;font-weight:bold;"> ' + x_str +' '+y_str_html+ '</p>'
self.label.setHtml(html_str)
self.label.setPos(mousePoint.x(), mousePoint.y())
self.vLine.setPos(mousePoint.x())
self.hLine.setPos(mousePoint.y())
pass
pass
使用:
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
xTick = [(0,'2022-01-01'),(1,'2022-01-02'),(2,'2022-01-03'),(3,'2022-01-04'),(4,'2022-01-05')]
xTick_show = xTick
x = [0,1,2,3,4]
candle_data = [
(0, 9, 15, 8, 16),
(1, 10, 13, 5, 15),
(2, 13, 17, 9, 20),
(3, 17, 14, 11, 23),
(4, 14, 15, 5, 19)
]
pre_data = {}
pre_data['title_str'] = 'K线图'
pre_data['xTick_show'] = xTick_show
pre_data['xTick'] = xTick
pre_data['x'] = x
pre_data['candle_data'] = candle_data
temp_w = PyQtGraphWidget()
temp_w.show()
temp_w.set_k_data(pre_data)
sys.exit(app.exec_())
pass