前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >箱线图(BoxPlot) App

箱线图(BoxPlot) App

作者头像
用户6021899
发布2020-04-13 18:54:14
1.1K0
发布2020-04-13 18:54:14
举报

由于公司的Execl版本(v2010)偏低,没有画箱线图的功能,故我用python写了一小段程序,可以用来画箱线图。绘图库使用的还是matplotlib。

通过点击图形元素,可以很方便的修改总标题和轴标题,可以改变箱体的样式和颜色。还可以添加水平参考线。

源码如下主要由4个部分组成。

1. 实现绘图功能的myCanvas.py

代码语言:javascript
复制
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

代码语言:javascript
复制
#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

代码语言:javascript
复制
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. 主程序

代码语言:javascript
复制
# -*- 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_())
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-04-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python可视化编程机器学习OpenCV 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档