Files
python_tools/analysis/analysis.py
2023-11-21 20:30:26 +08:00

293 lines
11 KiB
Python

#coding:utf-8
# 导入matplotlib模块并使用Qt5Agg
import typing
from PyQt5.QtCore import QObject
import matplotlib
matplotlib.use('Qt5Agg')
# 使用 matplotlib中的FigureCanvas (在使用 Qt5 Backends中 FigureCanvas继承自QtWidgets.QWidget)
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import matplotlib.pyplot as plt
import sys
import scheme_data
import numpy as np
import threading
import os
import build_html
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
plt.rcParams['figure.max_open_warning'] = False
# 定义一个可以嵌入到qt的figure
class QFigure(QObject):
def __init__(self,title:str) -> None:
QObject.__init__(self)
self._figure = plt.figure(figsize=(14,7))
self._canvas = FigureCanvas(self._figure)
self._ax = self._figure.add_axes([0.1,0.1,0.8,0.8])
self._ax.set_title(title)
self._title=title
self._line_min=None
self._line_max=None
self._max=0
self._min=0
def set_lines(self,x,y,lable:str=None,limit_max:int=None,limit_min:int=None):
line,=self._ax.plot(x,y,)
if(lable!=None):
line.set_label(lable)
self._ax.legend()
self.set_max(limit_max)
self.set_min(limit_min)
self._ax.grid(visible=True,which="major",axis="y")
def draw(self):
# start, end = self._ax.get_ylim()
start=self._min
end=self._max
step=(end-start)//20
bond=(end-start)//100+1
self._ax.set_ylim(start-bond,end+bond)
if(step>0):
ticks=np.arange(start, end,step)
self._ax.yaxis.set_ticks(ticks,minor=True)
# ticks=self._ax.yaxis.get_ticklocs()
# self._ax.yaxis.set_ticks(minor=True)
# self._ax.yaxis.set_ticks(ticks)
# self._ax.autoscale(enable=True, axis='both', tight=None)
self._canvas.draw()
def set_max(self,limit_max:int=None):
if(limit_max is not None):
if(self._line_max is not None):
self._line_max.remove()
self._line_max=None
print("remove max line")
self._line_max=self._ax.axhline(y=limit_max,color='g',linestyle='--')
self._max=limit_max
def set_min(self,limit_min:int=None):
if(limit_min is not None):
if(self._line_min is not None):
print("remove min line")
self._line_min.remove()
self._line_min=None
self._line_min=self._ax.axhline(y=limit_min,color='r',linestyle='--')
self._min=limit_min
def save(self,path:str,perfix:str):
path=os.path.join(path,"pic")
if not os.path.exists(path):
os.makedirs(path)
name=os.path.join(path,perfix+self._title)
self._figure.savefig(name+'.png')
def lable(self,lablex,labley):
self._ax.set_ylabel(labley)
self._ax.set_xlabel(lablex)
def canvas(self):
return self._canvas
# 定义一个任务需要的参数布局
class TParamLayout(QObject):
item_change_signal =pyqtSignal([int,str,str])
def __init__(self,index) -> None:
QObject.__init__(self)
self._layout=QFormLayout()
self._items=[]
self._index=index
def change_slot(self,text:str):
edit=self.sender()
# name=self.find_label(edit)
# print(edit.text()) 不用转换类型,直接就可以用 QLineEdit 的方法
name=edit.objectName()
# print(name,"text changed",text)
self.item_change_signal.emit(self._index,name,text)
def find_label(self,edit):
for i in self._items:
if(i[1]==edit):
return i[0].text()
return "none"
def add_item(self,name:str,value:str="",tooltip:str=None):
line_edit = QLineEdit()
line_edit.setObjectName(name)
line_edit.setText(value)
line_edit.textChanged.connect(self.change_slot)
line_edit_label = QLabel()
line_edit_label.setObjectName(name)
line_edit_label.setText(name)
line_edit_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
if(tooltip!=None):
line_edit_label.setToolTip(tooltip)
line_edit.setToolTip(tooltip)
self._layout.addRow(line_edit_label,line_edit)
self._items.append((line_edit_label,line_edit))
def item_value(self,name:str):
for i in self._items:
if(i[0].text()==name):
return i[1].text()
return None
def values(self):
vals=[]
for i in self._items:
vals.append((i[0].text(),i[1].text()))
return vals
def layout(self):
return self._layout
class Analysis(QWidget):
data_recv_end_signal =pyqtSignal([list,list])
calc_item_end_signal =pyqtSignal([list])
def __init__(self,parent=None):
super(Analysis,self).__init__(parent)
self.setWindowTitle("检测数据分析")
self.calc_item_end_signal.connect(self.calc_item_end_slot)
self.data_recv_end_signal.connect(self.data_recv_end_slot)
self._import_but = QPushButton("导入方案",self)
self._import_but.clicked.connect(self.import_but_clicked)
self._import_but.setGeometry(QRect(0,0,100,27))
self._export_but = QPushButton("导出数据")
self._export_but.clicked.connect(self.export_but_clicked)
self._scroll=QScrollArea(self)
self._scroll.setGeometry(0,30,1230,700)
# 设置布局
self._layout = QFormLayout()
self._layout.addRow(' ',self._export_but)
self._items=[]
def item_changed_slot(self,index:int,name:str,value:str):
print(index,name,value)
if(len(value)==0):
return
figure=self._items[index][0]
if(name.find("LimitMax")>=0):
figure.set_max(int(value))
if(name.find("LimitMin")>=0):
figure.set_min(int(value))
figure.draw()
def add_item(self,data_dict:dict):
data=data_dict["data"]
x=data_dict["x"]
name=data_dict["name"]
max=data_dict["max"]
min=data_dict["min"]
avg=data_dict["avg"]
mid=data_dict["mid"]
std=data_dict["std"]
limit_max=data_dict["limit_max"]
limit_min=data_dict["limit_min"]
dat_count=data_dict["dat_count"]
y=data_dict["y"]
figure = QFigure(name)
figure.lable("序号","数值")
tplayout=TParamLayout(self._item_index)
tplayout.add_item(name+":Max",str(max))
tplayout.add_item(name+":Min",str(min))
tplayout.add_item(name+":Avg",str(avg))
tplayout.add_item(name+":Mid",str(mid))
tplayout.add_item(name+":Std",str(std))
tplayout.add_item(name+":LimitMax",str(limit_max))
tplayout.add_item(name+":LimitMin",str(limit_min))
tplayout.item_change_signal.connect(self.item_changed_slot)
self._layout.addRow(figure.canvas(),tplayout.layout())
figure.set_lines(range(len(data)),data,lable="原始值",limit_max=limit_max,limit_min=limit_min)
figure.set_lines(dat_count,y,lable="权重")
figure.draw()
# figure.save(self._save_path,str(self._item_index)+".")
self._items.append((figure,tplayout,self._item_index))
self._item_index+=1
def calc_item_end_slot(self,data:list):
print("calc_item end.")
widget=QWidget()
widget.setGeometry(QRect(0,0,1200,20000))
for i in data:
self.add_item(i)
widget.setLayout(self._layout)
self._scroll.setWidget(widget)
def calc_item(self,data,name:str):
length=len(data)
# 排序,从小到大
sort_list=np.sort(data)
dat_count=np.bincount(data)
avg=round(np.average(data))
max=sort_list[-1]
min=sort_list[0]
mid=sort_list[len(sort_list)//2]
std=round(np.std(data))
# 把众数和原始值对齐
dat_count=dat_count[min:]
dat_count_max=np.max(dat_count)
dat_zoom=length//dat_count_max
dat_count=np.multiply(dat_count,dat_zoom)
# 去掉极大值,去掉极小值,使用99.8%的数据来统计区间
limit_max_t=sort_list[-(length//1000)]
limit_min_t=sort_list[(length//1000)]
limit_max=limit_max_t+(limit_max_t-limit_min_t)//5
limit_min=limit_min_t-(limit_max_t-limit_min_t)//5
# 使用3倍标准差来统计区间
# limit_max=avg+3*std
# limit_min=avg-3*std
if(limit_min<0):
limit_min=0
x=range(length)
y=np.add(range(len(dat_count)),min)
dat_struct={"name":name,"max":max,"min":min,"avg":avg,"mid":mid,"std":std,"limit_max":limit_max,
"limit_min":limit_min,"dat_count":dat_count,"y":y,"x":x,"data":data}
# self.add_item_signal.emit(dat_struct)
return dat_struct
# 连接的绘制的方法
def import_but_clicked(self):
self.sch_data=scheme_data.sch_data()
self._import_but.setEnabled(False)
ack=self.sch_data.select_scheme()
if(ack!=True):
return
self._save_path="file/"+self.sch_data.scheme_name.split('/')[-1].split('.')[0]
print(self._save_path)
self.recv_data()
def recv_data(self):
self._item_index=0
def recv_data_thread(sch_data:scheme_data.sch_data):
titles,data,num=sch_data.datas_sql()
print("recv data,len=",num)
self.data_recv_end_signal.emit(titles,data)
if(num<1000):
print("data len too less.")
return
items_data=[]
for i in range(len(titles)):
a=self.calc_item(data[i],titles[i])
items_data.append(a)
self.calc_item_end_signal.emit(items_data)
t = threading.Thread(target=recv_data_thread, args=(self.sch_data,))
t.start()
def data_recv_end_slot(self,titles:list,data:list):
self.titles=titles
self.sql_data=data
print("data recv end.")
def export_but_clicked(self):
ret_limit=[]
ret_values=[]
for i,t in zip(self._items,self.titles):
max=i[1].item_value(t+":LimitMax")
min=i[1].item_value(t+":LimitMin")
ret_limit.append((max,min))
ret_values.append(i[1].values())
i[0].save(self._save_path,str(i[2])+".")
self.sch_data.export_scheme(self._save_path,ret_limit)
self.sch_data.export_check_data(self._save_path)
build_html.html_build(self._save_path,self.titles,ret_values)
# 运行程序
if __name__ == '__main__':
QCoreApplication.setAttribute(Qt.ApplicationAttribute.AA_EnableHighDpiScaling)
app = QApplication(sys.argv)
main_window = Analysis()
main_window.show()
app.exec()