最近b站上有不少数据可视化的视频,
据说基本上都是由 Jannchie见齐 大佬的框架制作的,听说这个框架用起来很方便(虽然我暂时还没用过),不过这么多人用那就表示做的相当好,但是我的毕设是自己搞一个数据可视化系统,毕设总不能拿别人的吧,所以我就干脆搞一个类似的做毕设得了,
话说我舍友也是b站up主,一直吐槽自己辛苦做的mad没人看,别人导几个数据进去就有几十万播放(做mad死路一条.jpg)
用qt就可以了,昨天开始做的,现在还是个半成品,界面很简陋,这几天会完善好,喜欢的可以去github上给个star
先给大家眼睛道个歉
用法还是很简单的,传一个字典进去,字典中每一个key对应一个list,list中储存值的变化,可以设置最大显示数量,和动画时间,和左侧的标签属性,不设置默认为text,以后还可以设置更多花样,这几天会搞定
演示效果
()
写一下制作过程(只是个半成品正在完善),先说最基本的
先说一下QPropertyAnimation,可以自定义控件的变化与时间
@pyqtSlot()
def on_pushButton_clicked(self):
self.label = QtWidgets.QLabel(self)
self.label.setGeometry(QtCore.QRect(150, 142, 141, 141))
self.label.setStyleSheet("background-color: rgb(119, 78, 255);")
self.label.show()
self.anim = QPropertyAnimation(self.label, b"geometry")#操作self.label
self.anim.setDuration(1000)#动画时间10s
self.anim.setStartValue(QtCore.QRect(150, 142, 141, 141))#起始位置
self.anim.setKeyValueAt(0.5, QtCore.QRect(150, 80, 141, 141))#50%时的位置
self.anim.setEndValue(QtCore.QRect(60, 80, 141, 141))#结束位置
self.anim.start()
1首先写一个界面,为了方便观察背景设为白色,加一个按钮用来开始
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(1000, 890)
Dialog.setSizeGripEnabled(True)
self.setStyleSheet("background-color: rgb(255, 255, 255)")
self.pushButton = QtWidgets.QPushButton(Dialog)
self.pushButton.setGeometry(QtCore.QRect(50, 800, 100, 50))
self.pushButton.setObjectName("pushButton")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.pushButton.setText(_translate("Dialog", "开始吧"))
2写一个随参数变化位置与长度的条
就是见齐大佬视频里的这个啦,这个条可以通过Qlabel实现,设置其底色为红即可
负责计算每个条的xywl(x,y,width,lenght即位置与大小)等参数的函数以后再说,先默认其是计算好的,
xywl_list表示在移动过程中依次要去的位置,
time为动画时间,未定义默认为每次变化一秒
color为背景颜色,为了方便演示默认为黑色了
text为显示文本,先不管了默认为‘’
show_num为只显示前show_num名
继承Qlabel
class bar_label(QLabel):
def __init__(self, xywl, xywl_list,ui, show_num, time=None, text='',color=None ):
super(bar_label, self).__init__(ui)
self.x, self.y, self.w, self.l=xywl
self.xywl_list=xywl_list
self.show_num=show_num
if time==None:time=1000*len(xywl_list)#没有设置时间就一秒设置一次
self.time=time
self.color=color
self.setGeometry(QtCore.QRect(0, self.y, self.l, self.l))
self.setStyleSheet("background-color: rgb"+str((0, 0, 0))+";font-size:"+str(300//show_num)+"px")#这里以后会改的
self.setText(text)
self.show()
移动函数
def move_it(self):
n=len(self.xywl_list)
self.anim = QPropertyAnimation(self, b"geometry")
self.anim.setStartValue(QRect(self.x,self.y, self.w, self.l));
self.anim.setDuration(self.time)
for i in range(n):
x, y, w, l=self.xywl_list[i]
self.anim.setKeyValueAt((i+1)/len(self.xywl_list), QRect(x,y, w, l))
self.anim.start()
随参数变化效果如下
代码
w= [(100, 0, 775, 90), (100, 560, 300, 90), (100, 0, 515, 90), (100, 420, 380, 90), (100, 140, 660, 90), (100, 140, 560, 90), (100, 280, 350, 90), (100, 280, 515, 90), (100, 140, 445, 90), (100, 560, 355, 90)]
s=bar_label(w[0], w[1:], self, 5, 10000)#self是窗口
s.move_it()
3写一个随参数变化位置与数字的标签
就是见齐大佬视频里的这个啦,还是继承qlabel
class num_label(QLabel):
def __init__(self, xywl, xywl_list,ui, show_num, num_list, time=None,color=None ):
super(num_label, self).__init__(ui)
self.x, self.y, self.w, self.l=xywl
self.x=self.x+self.w+50#跟在条的后面
self.time=time
self.color=color
self.w=200
self.xywl_list=xywl_list
self.show_num=show_num
self.num_list=num_list#记录参数
self.setGeometry(QtCore.QRect(self.x, self.y, self.l, self.l))
self.setStyleSheet("background-color: rgb"+str((255, 255, 255))+";font-size:15px")
self.setText(str(num_list[0]))#开始值
self.show()
为了支持数字动态变化
def get_num(self):
return 0
def set_num(self, s):
self.setText(str(s))
text = pyqtProperty(int, fget=get_num, fset=set_num)
这样
self.anim = QPropertyAnimation(self, b"text")会调用set_num
变化函数
def move_it(self):
n=len(self.xywl_list)
self.anim = QPropertyAnimation(self, b"geometry")
self.anim2 = QPropertyAnimation(self, b"text")
self.anim.setStartValue(QRect(self.x,self.y, self.w, self.l));
self.anim.setDuration(self.time)
self.anim2.setDuration(self.time)
for i in range(n):
x, y, w, l=self.xywl_list[i]
x=x+w+50#跟在条后面
w=200
self.anim.setKeyValueAt((i+1)/len(self.xywl_list), QRect(x,y, w, l))
for i in range(1, n-1):
self.anim2.setKeyValueAt((i)/len(self.xywl_list), self.num_list[i])
self.anim2.setEndValue(self.num_list[-1])
self.anim.start()
self.anim2.start()
4写一个随参数变化位置且可以设定文本或图片的标签
还是继承qlabel
label_type默认为’text‘,为’pic‘时,会将text识别为图片路径
class labels_label(QLabel):
def __init__(self, xywl, xywl_list,ui, show_num, time=None, label_type='text' ,text='example',color=None ):
super(labels_label, self).__init__(ui)
self.x, self.y, self.w, self.l=xywl
self.x=0#在最左侧
self.time=time
self.text=text
self.color=color
self.label_type=label_type
self.w=100
self.xywl_list=xywl_list
self.show_num=show_num
self.setGeometry(QtCore.QRect(0, self.y, self.l, self.l))
self.setStyleSheet("background-color: rgb"+str((255, 255, 255))+";font-size:15px")
self.setObjectName(text)
if self.label_type=='text':self.setText(text)
else:
img=QPixmap(text)
self.setScaledContents(True)
self.setPixmap(img)
self.show()
移动函数
def move_it(self):
n=len(self.xywl_list)
self.anim = QPropertyAnimation(self, b"geometry")
self.anim.setStartValue(QRect(self.x,self.y, self.w, self.l));
self.anim.setDuration(self.time)
for i in range(n):
x, y, w, l=self.xywl_list[i]
x=0
w=100
self.anim.setKeyValueAt((i+1)/len(self.xywl_list), QRect(x,y, w, l))
self.anim.start()
效果如下
计算每个条的移动轨迹的函数下次说
这一部分完整代码
import sys, random
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QApplication, QLabel,QDialog
from PyQt5.QtGui import *
from PyQt5.QtCore import *
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(1000, 890)
Dialog.setSizeGripEnabled(True)
self.setStyleSheet("background-color: rgb(255, 255, 255)")
self.pushButton = QtWidgets.QPushButton(Dialog)
self.pushButton.setGeometry(QtCore.QRect(50, 800, 100, 50))
self.pushButton.setObjectName("pushButton")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.pushButton.setText(_translate("Dialog", "开始吧"))
class Dialog(QDialog, Ui_Dialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.setupUi(self)
@pyqtSlot()
def on_pushButton_clicked(self):
q={'A': [(100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0)], 'B': [(100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0)], 'C': [(100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0)], 'D': [(100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 420, 260, 90), (100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0)], 'E': [(100, 800, 0, 0), (100, 800, 0, 0), (100, 800, 0, 0), (100, 560, 300, 90), (100, 800, 0, 0), (100, 800, 0, 0), (100, 560, 195, 90), (100, 800, 0, 0), (100, 420, 240, 90), (100, 280, 385, 90)], 'F': [(100, 560, 300, 90), (100, 420, 480, 90), (100, 140, 440, 90), (100, 140, 460, 90), (100, 560, 395, 90), (100, 280, 495, 90), (100, 800, 0, 0), (100, 560, 380, 90), (100, 280, 275, 90), (100, 420, 360, 90)], 'G': [(100, 140, 590, 90), (100, 280, 505, 90), (100, 280, 420, 90), (100, 280, 455, 90), (100, 420, 565, 90), (100, 560, 345, 90), (100, 800, 0, 0), (100, 420, 425, 90), (100, 800, 0, 0), (100, 800, 0, 0)], 'H': [(100, 420, 365, 90), (100, 0, 580, 90), (100, 560, 365, 90), (100, 800, 0, 0), (100, 280, 630, 90), (100, 420, 455, 90), (100, 0, 620, 90), (100, 0, 645, 90), (100, 0, 515, 90), (100, 140, 520, 90)], 'I': [(100, 0, 775, 90), (100, 560, 300, 90), (100, 0, 515, 90), (100, 420, 380, 90), (100, 140, 660, 90), (100, 140, 560, 90), (100, 280, 350, 90), (100, 280, 515, 90), (100, 140, 445, 90), (100, 560, 355, 90)], 'J': [(100, 280, 505, 90), (100, 140, 580, 90), (100, 420, 380, 90), (100, 0, 850, 90), (100, 0, 890, 90), (100, 0, 730, 90), (100, 140, 450, 90), (100, 140, 645, 90), (100, 560, 240, 90), (100, 0, 775, 90)]}
q2={'A': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'B': [14, 13, 17, 8, 19, 11, 17, 13, 19, 6], 'C': [33, 40, 33, 23, 31, 30, 35, 15, 14, 17], 'D': [21, 51, 53, 39, 58, 45, 21, 59, 60, 23], 'E': [72, 37, 24, 32, 42, 46, 46, 64, 66, 60], 'F': [32, 35, 86, 84, 52, 38, 55, 39, 53, 94], 'G': [39, 111, 112, 45, 58, 92, 95, 78, 50, 90], 'H': [85, 93, 43, 61, 117, 57, 51, 120, 84, 93], 'I': [67, 97, 152, 146, 76, 54, 81, 95, 108, 71], 'J': [126, 51, 135, 170, 64, 152, 123, 120, 114, 173]}
labels=['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']
l1=[]
l2=[]
l3=[]
for i in range(len(labels)):
l1.append(labels_label(q[labels[i]][0], q[labels[i]][1:], self, 5, 10000, 'text',text= labels[i]))
l2.append(bar_label(q[labels[i]][0], q[labels[i]][1:], self, 5, 10000))
l3.append(num_label(q[labels[i]][0], q[labels[i]][1:], self, 5,q2[labels[i]], 10000))
for i in range(len(labels)):
l1[i].move_it()
l2[i].move_it()
l3[i].move_it()
class bar_label(QLabel):
def __init__(self, xywl, xywl_list,ui, show_num, time=None, text='',color=None ):
super(bar_label, self).__init__(ui)
self.x, self.y, self.w, self.l=xywl
self.xywl_list=xywl_list
self.show_num=show_num
if time==None:time=1000*len(xywl_list)
self.time=time
self.text=text
self.color=color
self.setGeometry(QtCore.QRect(0, self.y, self.l, self.l))
self.setStyleSheet("background-color: rgb"+str((random.randint(0, 255), random.randint(0, 255), random.randint(0, 255) ))+";font-size:"+str(300//show_num)+"px")
self.setObjectName(text)
self.setText(text)
self.show()
def move_it(self):
n=len(self.xywl_list)
self.anim = QPropertyAnimation(self, b"geometry")
self.anim.setStartValue(QRect(self.x,self.y, self.w, self.l));
self.anim.setDuration(self.time)
for i in range(n):
x, y, w, l=self.xywl_list[i]
self.anim.setKeyValueAt((i+1)/len(self.xywl_list), QRect(x,y, w, l))
self.anim.start()
class labels_label(QLabel):
def __init__(self, xywl, xywl_list,ui, show_num, time=None, label_type='text' ,text='example',color=None ):
super(labels_label, self).__init__(ui)
self.x, self.y, self.w, self.l=xywl
self.x=0
self.time=time
self.text=text
self.color=color
self.label_type=label_type
self.w=min(self.l+300//show_num*len(text), 100)
self.xywl_list=xywl_list
self.show_num=show_num
self.setGeometry(QtCore.QRect(self.x, self.y, self.l, self.l))
self.setStyleSheet("background-color: rgb"+str((255, 255, 255))+";font-size:15px")
self.setObjectName(text)
if self.label_type=='text':self.setText(text)
else:
img=QPixmap(text)
self.setScaledContents(True)
self.setPixmap(img)
self.show()
def move_it(self):
n=len(self.xywl_list)
self.anim = QPropertyAnimation(self, b"geometry")
self.anim.setStartValue(QRect(self.x,self.y, self.w, self.l));
self.anim.setDuration(self.time)
for i in range(n):
x, y, w, l=self.xywl_list[i]
x=0
w=min(l+300//self.show_num*len(self.text), 100)
self.anim.setKeyValueAt((i+1)/len(self.xywl_list), QRect(x,y, w, l))
self.anim.start()
class num_label(QLabel):
def __init__(self, xywl, xywl_list,ui, show_num, num_list, time=None,color=None ):
super(num_label, self).__init__(ui)
self.x, self.y, self.w, self.l=xywl
self.x=self.x+self.w+50
self.time=time
self.color=color
self.w=200
self.xywl_list=xywl_list
self.show_num=show_num
self.num_list=num_list
self.setGeometry(QtCore.QRect(self.x, self.y, self.l, self.l))
self.setStyleSheet("background-color: rgb"+str((255, 255, 255))+";font-size:15px")
self.setText(str(num_list[0]))
self.show()
def get_num(self):
return 0
def set_num(self, s):
self.setText(str(s))
text = pyqtProperty(int, fget=get_num, fset=set_num)
def move_it(self):
n=len(self.xywl_list)
self.anim = QPropertyAnimation(self, b"geometry")
self.anim2 = QPropertyAnimation(self, b"text")
self.anim.setStartValue(QRect(self.x,self.y, self.w, self.l));
self.anim.setDuration(self.time)
self.anim2.setDuration(self.time)
for i in range(n):
x, y, w, l=self.xywl_list[i]
x=x+w+50
w=200
self.anim.setKeyValueAt((i+1)/len(self.xywl_list), QRect(x,y, w, l))
for i in range(1, n-1):
self.anim2.setKeyValueAt((i)/len(self.xywl_list), self.num_list[i])
self.anim2.setEndValue(self.num_list[-1])
self.anim.start()
self.anim2.start()
if __name__ == '__main__':
app = QApplication(sys.argv)
dlg = Dialog()
dlg.show()
sys.exit(app.exec_())