#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()