由于公司的Execl版本(v2010)偏低,没有画箱线图的功能,故我用python写了一小段程序,可以用来画箱线图。绘图库使用的还是matplotlib。
通过点击图形元素,可以很方便的修改总标题和轴标题,可以改变箱体的样式和颜色。还可以添加水平参考线。
源码如下主要由4个部分组成。
1. 实现绘图功能的myCanvas.py
from PyQt5.QtWidgets import *from matplotlib import pyplot as pltfrom matplotlib.backends.backend_qt5agg import FigureCanvasQTAggfrom matplotlib.figure import Figureimport matplotlibmatplotlib.rcParams["font.sans-serif"] = ["SimHei"]matplotlib.rcParams["axes.unicode_minus"] = Falseclass Canvas(FigureCanvasQTAgg): def __init__(self, parent=None, width=5, height=4, dpi=100): self.fig = Figure(figsize=(width, height), dpi=dpi) #创建画布,设置宽高,每英寸像素点数 self.axes = self.fig.add_subplot(111)# self.axes.tick_params(axis='x',rotation =90,direction="in")#日期旋转90度显示 FigureCanvasQTAgg.__init__(self, self.fig)#调用基类的初始化函数 self.setParent(parent) FigureCanvasQTAgg.updateGeometry(self) def LinePlot(self, title, x_axis_labels, allData,legend_labels): self.axes.cla()#清除已绘的图形 for i in range(len(allData)): line, = self.axes.plot(allData[i],marker='o',markersize=5)#可以省略x轴labels self.axes.legend(labels= legend_labels, loc ="best") self.title = self.axes.set_title(title) self.title.set_picker(5) self.axes.grid(lw=0.5,ls="--",alpha=0.5) self.draw()#重新绘制 #handles, labels = self.axes.get_legend_handles_labels() #print(handles) #print(labels) def BoxPlot(self, title, labels, allData,settings,xticklabelAngle): self.axes.cla()#清除已绘的图形 bplot = self.axes.boxplot(allData,labels=labels,meanline=settings["showmeans"], showmeans=settings["showmeans"], patch_artist=True,showfliers=settings["outliers"],sym=settings["sym"],notch=settings["notch"]) colors = ['green','navy', 'lightblue', 'magenta','lightgreen','blue','lime','indigo','pink','brown','cyan','yellow','olive', 'darkblue','maroon','lavender','chartreuse','ivory','crimson','beige','fuchsia','azure','goldenrod','khaki', 'darkgreen','chocolate','coral','gold','aquamarine'] for box, color in zip(bplot['boxes'], colors): box.set(color=color,linewidth=2) box.set_picker(5) self.title = self.axes.set_title(title,fontsize=14) self.title.set_picker(5) self.xlabel = self.axes.set_xlabel("x label",fontsize = 12) self.xlabel.set_picker(4) self.ylabel = self.axes.set_ylabel("y label",fontsize = 12) self.ylabel.set_picker(4) self.grid = self.axes.grid(lw=0.5,ls="--",alpha=0.5) for ticklabel in self.axes.xaxis.get_ticklabels(): ticklabel.set_rotation(xticklabelAngle)#0度表示水平从左向右 #ticklabel.set_fontsize(14) self.draw()#重新绘制 if __name__ == "__main__": canvas = Canvas() #canvas.BoxPlot()
2. 存储数据的myTable.py
#import sysfrom PyQt5.QtWidgets import *from PyQt5.QtGui import QColor, QFont, QIcon, QKeySequence,QPixmap,QImage,QPainter,QPen,QBrushfrom PyQt5.QtCore import Qt, QDate, QTime, QDateTime, QTimer, QSettings,pyqtSignal,QPoint,QMetaObject#import osclass TableWidgetItem(QTableWidgetItem): def __init__(self,text,type = QTableWidgetItem.Type): super(myTableWidgetItem,self).__init__() self.setText(text) self.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter)class TableWidget(QTableWidget): colNameChanged = pyqtSignal(int,str) def __init__(self,parent=None): super().__init__(parent) self.setup() self.createActions() self.eventHandle() self.setContextMenuPolicy(Qt.CustomContextMenu)#允许右键产生子菜单 self.customContextMenuRequested.connect(self.custom_right_menu)#右键菜单 self.clipboard = QApplication.clipboard() self.mimeData = self.clipboard.mimeData() self.currentColumns = None self.resize(1000, 618) def setup(self): self.setEditTriggers(QAbstractItemView.DoubleClicked)#NoEditTriggers,CurrentChanged,SelectedClicked,AnyKeyPressed,DoubleClicked,AllEditTriggers self.setSelectionBehavior(QAbstractItemView.SelectItems) #,QAbstractItemView.SelectRows,QAbstractItemView.SelectColumns self.setSelectionMode(QAbstractItemView.ExtendedSelection) #SingleSelection #ContiguousSelection #ExtendedSelection #MultiSelection #NoSelection #self.resizeColumnsToContents()#.resizeColumnToContents (self, int column) #self.setStyleSheet("QTableCornerButton::section{background-color:green;}")#左上角 Ncolumns = 1000 Nrows = 10001 self.setColumnCount(Ncolumns) self.setRowCount(Nrows) self.setVerticalHeaderLabels((str(x) for x in range(Nrows)))#垂向header labels self.setColumnCount(Ncolumns) #self.horizontalHeader().setStyleSheet("QHeaderView::section{background-color:rgb(180,180,250);}") #self.horizontalHeader().setDefaultAlignment(Qt.AlignHCenter| Qt.AlignVCenter) #self.horizontalHeader().sectionMoved[int,int,int].connect(self.on_columnSelectionsChanged) #self.horizontalHeader().sectionCountChanged[int,int].connect(self.on_columnSelectionsChanged) for i in range(self.rowCount()): self.setRowHeight(i, 20) #setSpan (self, int row, int column, int rowSpan, int columnSpan)#"合并单元格" # .clearSpans() #.setRowHeight (self, int row, int height) #.setColumnWidth (self, int column, int width) #self.setSortingEnabled(True)## #.sortByColumn (self, int column, Qt.SortOrder order) #.setWordWrap (self, bool on) #.setGridStyle (self, Qt.PenStyle style) #hideColumn (self, int column) #hideRow (self, int row)
/*
* 提示:该行代码过长,系统自动注释不进行高亮。一键复制会移除系统注释
* def createActions(self): self.copyAct = QAction(QIcon('/editcopy.png'),"&Copy...", self, shortcut=QKeySequence.Copy,statusTip="Copy", triggered=self.clipboard_copy)# self.pasteAct = QAction(QIcon('/editpaste.png'),"&Paste...", self, shortcut=QKeySequence.Paste,statusTip="Copy", triggered=self.clipboard_paste)# self.delAct = QAction(QIcon('/editcut.png'),"&Delete content", self, shortcut=QKeySequence.Delete,statusTip="Delete", triggered=self.delete_)# pix = QPixmap(16, 16) pix.fill(Qt.red) self.bgcolorAct = QAction(QIcon(pix),"背景颜色", self, statusTip="background color", triggered=self.setBGColor)# self.delallAct = QAction(QIcon('/editcut.png'),"&clear all", self,statusTip="clear all", triggered=self.clear_all)# self.delrowAct = QAction(QIcon('/editcut.png'),"删除此行", self,statusTip="delete current row", triggered=self.delete_row)# self.delcolumnAct = QAction(QIcon('/editcut.png'),"删除此列", self,statusTip="delete current column", triggered=self.delete_column)# def eventHandle(self): self.cellActivated[int,int].connect(self.on_cellActivated) #self.cellEntered[int,int].connect(self.on_cellEntered) self.cellChanged[int,int].connect(self.on_cellChanged) # can triggered by code self.cellClicked[int,int].connect(self.on_cellClicked) self.cellDoubleClicked[int,int].connect(self.on_cellDoubleClicked) #self.currentCellChanged[int,int,int,int].connect(self.on_currentCellChanged) self.itemSelectionChanged.connect(self.on_itemSelectionChanged) self.addAction(self.copyAct) self.addAction(self.pasteAct) self.addAction(self.delAct) def setBGColor(self): color = QColorDialog.getColor() if color.isValid(): #tuple(map( lambda x: x/255.0, color.getRgb()[0:-1])) for item in self.selectedItems(): item.setBackground(color) def delete_row(self): self.removeRow (self.currentRow()) def delete_column(self): self.removeColumn (self.currentColumn()) def custom_right_menu(self, pos): menu = QMenu() act1 = menu.addAction(self.copyAct) act2 = menu.addAction(self.pasteAct) act3 = menu.addAction(self.delAct) act4 = menu.addAction(self.bgcolorAct) act5 = menu.addAction(self.delallAct) act6 = menu.addAction(self.delrowAct) act7 = menu.addAction(self.delcolumnAct) action = menu.exec_(self.mapToGlobal(pos)) if action == act1: pass elif action == act2: pass else: return def delete_(self): for item in self.selectedItems(): item.setText("") def clear_all(self): for item in self.selectedItems(): item.setText('') item.setBackground(QColor(255,255,255)) item.setToolTip('') def clipboard_copy(self): if not self.selectedItems() : self.clipboard.clear() # not equal to .setText('') return selected_rows = [item.row() for item in self.selectedItems()] row_max ,row_min = max(selected_rows), min(selected_rows) rows = row_max - row_min +1 selected_columns= [item.column() for item in self.selectedItems()] column_max ,column_min = max(selected_columns), min(selected_columns) columns = column_max - column_min +1 content = [['']*columns for row in range(rows)] # [['']*columns]*rows # wrong!!!! for item in self.selectedItems(): content[item.row() - row_min][item.column() - column_min] = item.text() text_output = '' for i in range(rows): text_output += "\t".join(content[i])+"\n" self.clipboard.setText(text_output[:-1]) def clipboard_paste(self): #print self.currentItem(),self.currentRow(),self.currentColumn() row,col = self.currentRow(),self.currentColumn() if self.mimeData.hasText(): # .hasImage(),.hasHtml() text = self.mimeData.text() lines = text.split("\n") for i in range(len(lines)): records = lines[i].split("\t") for j in range(len(records)): s = records[j] if self.item(row+i,col+j): self.item(row+i,col+j).setText(s) else: item = QTableWidgetItem(s) self.setItem(row+i,col+j,item) def on_cellActivated(self,row,col):# "Enter" key pressed self.setCurrentCell(self.currentRow()+1,self.currentColumn()) def on_cellChanged(self,row,col): if row == 0: if col > 0: for j in range(col): if self.item(0,j) is None or self.item(0,j).text() == '': QMessageBox.critical(self, "错误", "左边不能有空的列!") return self.colNameChanged.emit(col,self.item(row,col).text()) #def on_cellEntered(self,row,col): #print ("cellEntered") def on_cellClicked(self,row,col): if self.item(row,col): info = "row: %s, col: %s, value: %s" %(row+1, col+1, self.item(row,col).text()) else: info = "row: %s, col: %s, value: %s" %(row+1, col+1, None) #self.topLevelWidget().statusBar().showMessage(info) def on_cellDoubleClicked(self,row,col): pass #self.setBGColor() #print "row,col:",row+1,col+1 def on_cellPressed(self,row,col): print ("cellPressed") #print "row,col:",row+1,col+1 #def on_currentCellChanged(self, currentRow, currentCol, previousRow, previousCol): #print "currentCellChanged" #print "current row,current col,previous row,previous col:",currentRow+1,currentCol+1,previousRow+1, previousCol+1 #print "selectedIndexes:", self.selectedIndexes() #print "selectedItems:", self.selectedItems() #for item in self.selectedItems(): #print (item.row(),item.column(),item.text()) def on_itemSelectionChanged(self): self.currentColumns = set() for item in self.selectedItems(): self.currentColumns.add(item.column()) def keyPressEvent(self,event): key = event.key() if key == 16777235: # Ctrl+up 滑动条位置回到顶部 if event.modifiers() & Qt.ControlModifier:#Ctrl 键被按下 self.verticalScrollBar().setValue(0) elif key == 16777234: # # Ctrl+ left 滑动条位置回到左端 if event.modifiers() & Qt.ControlModifier:#Ctrl 键被按下 self.horizontalScrollBar().setValue(0) else: QWidget.keyPressEvent(self, event) def randomData(self): from random import random for i in range(0,100): for j in range(0,8): item = QTableWidgetItem(str((i*random())*(j+1)))#.setText(str(i*j)) self.setItem(i,j,item) for j in range(8): self.setColumnWidth(j, 60) self.item(0,j).setBackground(QColor(180,180,225)) self.item(0,j).setText(chr(ord('A')+j))if __name__ =="__main__": import sys APP=QApplication(sys.argv) myqt=TableWidget() myqt.randomData() myqt.show() sys.exit(APP.exec_())
*/
3. 实现对话框交互的myDialogs.py
import sysfrom PyQt5.QtWidgets import *from PyQt5.QtGui import QColor, QFont, QIcon,QPixmapfrom PyQt5.QtCore import Qt, pyqtSignal,QSize,QDate
class TitleDlg(QDialog): applySignal = pyqtSignal(str,int,tuple)#自定义信号 def __init__(self, title, parent = None): super().__init__(parent) self.setWindowTitle(title) okButton = QPushButton("OK") applyButton = QPushButton("Apply") cancelButton = QPushButton("Cancel") okButton.clicked.connect(self.ok) applyButton.clicked.connect(self.apply) cancelButton.clicked.connect(self.reject) buttonLayout = QHBoxLayout() buttonLayout.addStretch() buttonLayout.addWidget(okButton) buttonLayout.addWidget(applyButton) buttonLayout.addWidget(cancelButton) layout = QGridLayout() label0 = QLabel("字体大小:") self.fontsizeSpinBox = QSpinBox() self.fontsizeSpinBox.setValue(12) self.fontsizeSpinBox.setRange(10,30) self.colorButton = QPushButton("文字颜色") self.colorButton.clicked.connect(self.setTextColor) self.colorLabel = QLabel() self.colorLabel.setFrameShadow(QFrame.Sunken) self.colorLabel.setStyleSheet("QLabel{background:rgb(0,0,0);}") self.textEdit = QTextEdit() self.textEdit.setText("??") self.textEdit.selectAll() self.textEdit.setFocus(True) #self.textEdit.setSizePolicy(QSizePolicy.Minimum,QSizePolicy.Minimum) self.textEdit.setFixedHeight(50)
/*
* 提示:该行代码过长,系统自动注释不进行高亮。一键复制会移除系统注释
* layout.addWidget(label0,0,0) layout.addWidget(self.fontsizeSpinBox,0,1) layout.addWidget(self.colorButton,0,2) layout.addWidget(self.colorLabel,0,3) layout.addWidget(self.textEdit,1,0,1,4) layout.addLayout(buttonLayout,2,0,1,4) self.setLayout(layout) self.rgb = (0,0,0) def setTextColor(self): color = QColorDialog.getColor(Qt.black, None,"选择颜色") if color.isValid(): self.rgb = color.getRgb()[0:3]#getRgb()返回四个值!!! self.colorLabel.setStyleSheet("QLabel{background:rgb(%d,%d,%d);}"% self.rgb) #有多重花括号,不好用f字符串 def apply(self):#重新实现accept方法 self.applySignal.emit(self.textEdit.toPlainText(),self.fontsizeSpinBox.value(),self.rgb) def ok(self):#不能重载 done(), 否则self.reject()异常 self.apply() self.hide()class BoxDlg(QDialog): applySignal = pyqtSignal(tuple)#自定义信号 def __init__(self, title, parent = None): super().__init__(parent) self.setWindowTitle(title) okButton = QPushButton("OK") applyButton = QPushButton("Apply") cancelButton = QPushButton("Cancel") okButton.clicked.connect(self.ok) applyButton.clicked.connect(self.apply) cancelButton.clicked.connect(self.reject) buttonLayout = QHBoxLayout() buttonLayout.addStretch() buttonLayout.addWidget(okButton) buttonLayout.addWidget(applyButton) buttonLayout.addWidget(cancelButton) layout = QGridLayout() self.colorButton = QPushButton("填充颜色") self.colorButton.clicked.connect(self.setPatchColor) layout.addWidget(self.colorButton,0,0) layout.addLayout(buttonLayout,1,0,1,4) self.setLayout(layout) self.rgb = (0,0,255) def setPatchColor(self): color = QColorDialog.getColor(Qt.black, None,"选择颜色") if color.isValid(): self.rgb = color.getRgb()[0:3]#getRgb()返回四个值!!! self.colorButton.setStyleSheet("QPushButton{background:rgb(%d,%d,%d);}"% self.rgb) def apply(self):#重新实现accept方法 self.applySignal.emit(self.rgb) def ok(self):#不能重载 done(), 否则self.reject()异常 self.apply() self.hide() class RefHLineDlg(QDialog): applySignal = pyqtSignal(dict)#自定义信号 def __init__(self, title, parent = None): super().__init__(parent) self.setWindowTitle(title) okButton = QPushButton("OK") applyButton = QPushButton("Apply") cancelButton = QPushButton("Cancel") okButton.clicked.connect(self.ok) applyButton.clicked.connect(self.apply) cancelButton.clicked.connect(self.reject) buttonLayout = QHBoxLayout() buttonLayout.addStretch() buttonLayout.addWidget(okButton) buttonLayout.addWidget(applyButton) buttonLayout.addWidget(cancelButton) layout = QGridLayout() self.yLineEdit = QLineEdit() self.labelEdit = QLineEdit() self.x1LineEdit = QLineEdit('0') self.x1LineEdit.setToolTip("决定了水平参考线左端点的x坐标") self.x2LineEdit = QLineEdit() self.x2LineEdit.setToolTip("决定了水平参考线右端点的x坐标") self.lsComboBox = QComboBox() self.lsComboBox.addItems(['-','--','-.',':']) self.lwSpinBox = QDoubleSpinBox() self.lwSpinBox.setValue(1.0) self.lwSpinBox.setRange(0.5,3.0) self.lwSpinBox.setSingleStep(0.25) self.colorButton = QPushButton() self.colorButton.setStyleSheet("QPushButton{background:rgb(255,0,0);}") self.alphaSpinBox = QDoubleSpinBox() self.alphaSpinBox.setValue(1.0) self.alphaSpinBox.setRange(0.2,1.0) self.alphaSpinBox.setSingleStep(0.1) layout.addWidget(QLabel("y ="),0,0) layout.addWidget(self.yLineEdit,0,1) layout.addWidget(QLabel("标签名:"),0,2) layout.addWidget(self.labelEdit,0,3) layout.addWidget(QLabel("x1="),1,0) layout.addWidget(self.x1LineEdit,1,1) layout.addWidget(QLabel("x2="),1,2) layout.addWidget(self.x2LineEdit,1,3) layout.addWidget(QLabel("线型:"),2,0) layout.addWidget(self.lsComboBox,2,1) layout.addWidget(QLabel("线宽:"),2,2) layout.addWidget(self.lwSpinBox,2,3) layout.addWidget(QLabel("颜色:"),3,0) layout.addWidget(self.colorButton,3,1) layout.addWidget(QLabel("不透明度:"),3,2) layout.addWidget(self.alphaSpinBox,3,3) layout.addLayout(buttonLayout,4,0,1,4) self.setLayout(layout) self.setWindowTitle("水平参考线设置") self.setting = dict() self.setting["rgb"] = (255,0,0) self.colorButton.clicked.connect(self.setColor) def setColor(self): color = QColorDialog.getColor(Qt.black, None,"选择颜色") if color.isValid(): self.setting["rgb"] = color.getRgb()[0:3]#getRgb()返回四个值(0`255)!!! self.colorButton.setStyleSheet("QPushButton{background:rgb(%d,%d,%d);}"% self.setting["rgb"]) def apply(self):#重新实现accept方法 try: self.setting["y"] = float(self.yLineEdit.text()) except ValueError: QMessageBox.critical(self, "错误", "y的值不合法!") return labelText = self.labelEdit.text() if labelText == '': QMessageBox.critical(self, "错误", "标签名不能为空!") return else:self.setting["label"] = labelText try: self.setting["x1"] = float(self.x1LineEdit.text()) except ValueError: QMessageBox.critical(self, "错误", "x1的值不合法!") return try: self.setting["x2"] = float(self.x2LineEdit.text()) except ValueError: QMessageBox.critical(self, "错误", "x2的值不合法!") return if self.setting["x1"] >= self.setting["x2"]: QMessageBox.critical(self, "错误", "x2 须大于 x1!") return self.setting["linestyle"] = self.lsComboBox.currentText() self.setting["linewidth"] = self.lwSpinBox.value() self.setting["alpha"] = self.alphaSpinBox.value() self.applySignal.emit(self.setting) def ok(self):#不能重载 done(), 否则self.reject()异常 try: self.setting["y"] = float(self.yLineEdit.text()) except ValueError: QMessageBox.critical(self, "错误", "y的值不合法!") return labelText = self.labelEdit.text() if labelText == '': QMessageBox.critical(self, "错误", "标签名不能为空!") return else:self.setting["label"] = labelText try: self.setting["x1"] = float(self.x1LineEdit.text()) except ValueError: QMessageBox.critical(self, "错误", "x1的值不合法!") return try: self.setting["x2"] = float(self.x2LineEdit.text()) except ValueError: QMessageBox.critical(self, "错误", "x2的值不合法!") return if self.setting["x1"] >= self.setting["x2"]: QMessageBox.critical(self, "错误", "x2 须大于 x1!") return self.setting["linestyle"] = self.lsComboBox.currentText() self.setting["linewidth"] = self.lwSpinBox.value() self.setting["alpha"] = self.alphaSpinBox.value() self.applySignal.emit(self.setting) self.close()
*/
if __name__ == '__main__': app = QApplication(sys.argv) dlg = RefHLineDlg("title",None) dlg.show() sys.exit(app.exec_())
4. 主程序
# -*- coding: utf-8 -*-import sysfrom PyQt5.QtWidgets import *from PyQt5.QtGui import QColor, QFont, QIconfrom PyQt5.QtCore import Qt, pyqtSignal,QSizeimport random#import resourcefrom matplotlib.backends.backend_qt5agg import NavigationToolbar2QTimport matplotlibfrom myTable import TableWidget,TableWidgetItemfrom myCanvas import Canvasfrom filteredList import FilteredListfrom myDialogs import TitleDlg, BoxDlg, RefHLineDlg class MainWindow(QMainWindow): def __init__(self, parent = None): super().__init__(parent) self.setWindowTitle("数据可视化") self.create_table() self.create_canvas() self.setup_centralWidget() self.setWindowIcon(QIcon("boxplot.PNG")) self.createActions() self.setup_toolBar() self.setup_menuBar() self.setup_dockWidget() self.statusBar().showMessage("ready") #self.resize(800,500) def create_table(self): self.table = TableWidget() def update_table(self): self.table.clearContents()#清除内容 def create_canvas(self): self.canvas = Canvas(self) self.canvas.mpl_connect('pick_event', self.onpick) self.titleDlg = None self.xlabelDlg = None self.ylabelDlg = None self.boxPlotSetting = dict() self.boxPlotSetting["outliers"] = True self.boxPlotSetting["notch"] = False self.boxPlotSetting["sym"] = "+" self.boxPlotSetting["showmeans"] = True self.xticklabelAngle = 0 def setup_centralWidget(self): self.tabWidget = QTabWidget() self.tabWidget.addTab(self.table,"数据") vlayout = QVBoxLayout() Navigation_toolbar = NavigationToolbar2QT(self.canvas, self) vlayout.addWidget(self.canvas) vlayout.addWidget(Navigation_toolbar) plotWidget = QWidget() plotWidget.setLayout(vlayout) self.tabWidget.addTab(plotWidget,"绘图") self.setCentralWidget(self.tabWidget)#指定主窗口中心部件 def createActions(self): #self.newAction = QAction("New record", self) #self.newAction.setIcon(QIcon(":new.png")) #self.newAction.triggered.connect(self.newRecord) #self.newAction.setStatusTip("###") self.exitAction = QAction("E&xit",self) self.exitAction.triggered.connect(self.close) self.showLogAction = QAction("Show log window",self) self.showLogAction.setShortcut("Ctrl+L") self.showLogAction.setCheckable(True) self.showLogAction.setChecked(True) self.showLogAction.toggled[bool].connect(self.showDockWidget) self.helpAboutAction = QAction("About",self) self.helpAboutAction.setShortcut("Ctrl+H") self.helpAboutAction.triggered.connect(self.showAboutDialog) self.xticklabelAngleAction = QAction("xticklabel rotation angle") self.xticklabelAngleAction.triggered.connect(self.setXticklabelAngle) def setXticklabelAngle(self): angle, okPressed = QInputDialog.getInt(self, "xtick 标签旋转角度","请输入xtick 标签旋转角度:", self.xticklabelAngle, -360, 360, 10) if okPressed: self.xticklabelAngle = angle def showAboutDialog(self): #不能重载showAboutDlg,否则报错 QMessageBox.about(self, "about 对话框 标题", "版本: V0.1\n作者: wsp") def setup_menuBar(self): menuBar = self.menuBar() fileMenu = menuBar.addMenu("&File") fileMenu.addAction(self.exitAction) optionMenu = menuBar.addMenu("&Option") linePlotMenu = optionMenu.addMenu("&Line Plot setting") boxPlotMenu = optionMenu.addMenu("&Box Plot setting") boxPlotMenu.addAction(self.xticklabelAngleAction)
ViewMenu = menuBar.addMenu("&View") ViewMenu.addAction(self.showLogAction) helpMenu = menuBar.addMenu("&Help") helpMenu.addAction(self.helpAboutAction) def showDockWidget(self, b): self.logDockWidget.setVisible(b)
def on_plotTypeListItemClicked(self, item):
if item.text() == "Line Plot": legend_labels = [] x_axis_labels = [] AllData= [] for j in range(len(self.dataSourceList.dict)): ch = self.dataSourceList.dict[j] if ch.checkState() == 2: legend_labels.append(ch.text()) data = [] for i in range(1,self.table.rowCount()): if self.table.item(i,j): try: data.append(float(self.table.item(i,j).text())) except ValueError as e: continue else: break AllData.append(data) if legend_labels: title ="折线图 Line PLOT" n = max([len(x) for x in AllData]) x_axis_labels = [str(x) for x in range(1,n+1)] #default, 用数字表示label self.canvas.LinePlot(title,x_axis_labels, AllData,legend_labels) else: QMessageBox.warning(self, "警告", "请至少选择一列数据!") elif item.text() == "Box Plot": labels = [] AllData= [] for j in range(len(self.dataSourceList.dict)): ch = self.dataSourceList.dict[j] if ch.checkState() == 2: #labels.append(self.table.item(0,j).text()) labels.append(ch.text()) data = [] for i in range(1,self.table.rowCount()): if self.table.item(i,j): try: data.append(float(self.table.item(i,j).text())) except ValueError as e: continue else: break AllData.append(data) if labels: title ="箱线图 Box Plot" self.canvas.BoxPlot(title,labels, AllData,self.boxPlotSetting,self.xticklabelAngle) self.boxDlg = None else: QMessageBox.critical(self, "错误", "请至少选择一列数据!") self.tabWidget.setCurrentIndex(1) def showOutliers(self,b): self.boxPlotSetting["outliers"] = b self.cbb0.setDisabled(not b) def notch(self,b): self.boxPlotSetting["notch"] = b def outlierSymbol(self,sym): self.boxPlotSetting["sym"] = sym def showMeanline(self,b): self.boxPlotSetting["showmeans"] = b def setup_toolBar(self): toolbar0 = self.addToolBar("BoxPlot settings")#添加工具条 toolbar0.setToolTip("重新绘图后才生效!") label0 = QLabel("Box Plot:") cb0 = QCheckBox("显示异常点") cb0.setChecked(True) cb0.toggled[bool].connect(self.showOutliers) self.cbb0 = QComboBox() self.cbb0.addItems(["+","*","o",".","v","^","s","x"]) self.cbb0.currentTextChanged[str].connect(self.outlierSymbol) cb1 = QCheckBox("收腰") cb1.toggled[bool].connect(self.notch) cb2 = QCheckBox("显示mean线") cb2.setChecked(True) cb2.toggled[bool].connect(self.showMeanline) toolbar0.addWidget(label0) toolbar0.addWidget(cb0) toolbar0.addWidget(self.cbb0) toolbar0.addSeparator() toolbar0.addWidget(cb1) toolbar0.addWidget(cb2) #添加参考线工具条 toolbar1 = self.addToolBar("add ref lines")#添加工具条 toolbar1.setToolTip("添加横向或竖向参考线") label10 = QLabel("+ ref lines:") bt10 = QPushButton("y = ? --") bt10.clicked.connect(self.showHlineDlg) bt11 = QPushButton("x = ? |") toolbar1.addWidget(label10) toolbar1.addWidget(bt10) toolbar1.addWidget(bt11) toolbar2 = self.addToolBar("add random data")#添加工具条 toolbar1.setToolTip("生成一点随机数据用于演示") randButton = QPushButton("生成随机数据") randButton.clicked.connect(self.table.randomData) toolbar2.addWidget(randButton)
def showHlineDlg(self): refHLineDlg = RefHLineDlg(title="水平参考线设置",parent=self) refHLineDlg.applySignal.connect(self.addHline) refHLineDlg.show() def addHline(self, sett): rgb = [x/255.0 for x in sett["rgb"]] #handles, labels = self.canvas.axes.get_legend_handles_labels() self.canvas.axes.hlines(sett["y"],sett["x1"],sett["x2"],label=sett["label"],linestyles=sett["linestyle"], color=rgb,linewidth=sett["linewidth"],alpha=sett["alpha"]) #self.canvas.axes.legend(handles=handles,labels=labels,loc="best") self.canvas.axes.legend(loc="best") self.canvas.draw() def setup_dockWidget(self): self.logDockWidget = QDockWidget("plot",self) self.logDockWidget.setAllowedAreas(Qt.LeftDockWidgetArea) widget_dock = QWidget() layout = QVBoxLayout() self.plotTypeList = QListWidget() self.plotTypeList.addItem(QListWidgetItem(QIcon("plot.PNG"),"Line Plot")) self.plotTypeList.addItem("Scatter Plot") self.plotTypeList.addItem("Pie Plot") self.plotTypeList.addItem(QListWidgetItem(QIcon("boxplot.PNG"),"Box Plot")) self.plotTypeList.itemClicked[QListWidgetItem].connect(self.on_plotTypeListItemClicked) self.plotTypeList.setIconSize(QSize(80,40)) textList = [] #for j in range(8): #textList.append(self.table.item(0,j).text()) self.dataSourceSelectStacked= QStackedWidget() self.dataSourceList = FilteredList(textList=textList) self.table.colNameChanged[int,str].connect(self.dataSourceList.updateItemName) self.dataSourceSelectStacked.addWidget(QWidget()) self.dataSourceSelectStacked.addWidget(QWidget()) self.dataSourceSelectStacked.addWidget(QWidget()) self.dataSourceSelectStacked.addWidget(self.dataSourceList) self.dataSourceSelectStacked.setCurrentIndex(3)# layout.addWidget(self.plotTypeList) layout.addWidget(QLabel("请选择数据列:")) layout.addWidget(self.dataSourceSelectStacked) widget_dock.setLayout(layout) self.logDockWidget.setWidget(widget_dock) #self.logDockWidget.setFixedWidth(215) self.logDockWidget.visibilityChanged.connect(self.showLogAction.setChecked) self.addDockWidget(Qt.LeftDockWidgetArea, self.logDockWidget)#添加停靠窗口 def onpick(self, event): self.obj = event.artist print(self.obj) print(type(self.obj)) if self.obj == self.canvas.title: if self.titleDlg is None: self.titleDlg = TitleDlg(title="标题设置", parent=self) self.titleDlg.applySignal.connect(self.updateTitle) self.titleDlg.show()#非模态地显示对话框 elif isinstance(self.obj, matplotlib.patches.PathPatch): if self.boxDlg is None: self.boxDlg = BoxDlg(title="箱线设置", parent=self) self.boxDlg.applySignal.connect(self.updateBox) #facecolor = self.obj.get_facecolor()[0:3] self.boxDlg.show()#非模态地显示对话框 elif self.obj == self.canvas.ylabel: if self.ylabelDlg is None: self.ylabelDlg = TitleDlg(title="y轴标签设置", parent=self) self.ylabelDlg.applySignal.connect(self.updateYlabel) self.ylabelDlg.show()#非模态地显示对话框 elif self.obj == self.canvas.xlabel: if self.xlabelDlg is None: self.xlabelDlg = TitleDlg(title="x轴标签设置", parent=self) self.xlabelDlg.applySignal.connect(self.updateXlabel) self.xlabelDlg.show()#非模态地显示对话框 self.canvas.draw() def updateTitle(self,text,fontsize,color):#For modaless dialog color = [x/255.0 for x in color] self.canvas.axes.set_title(text,fontsize=fontsize,color=color) self.canvas.draw() def updateBox(self,color): self.obj.set_color([x/255.0 for x in color]) self.canvas.draw() def updateYlabel(self,text,fontsize,color): color = [x/255.0 for x in color] self.canvas.axes.set_ylabel(text,fontsize=fontsize,color=color) self.canvas.draw() def updateXlabel(self,text,fontsize,color): color = [x/255.0 for x in color] self.canvas.axes.set_xlabel(text,fontsize=fontsize,color=color) self.canvas.draw()
if __name__ == '__main__': app = QApplication(sys.argv) mw = MainWindow() mw.show() sys.exit(app.exec_())
本文分享自 Python可视化编程机器学习OpenCV 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!