箱形图(英文:Box plot),又称为盒须图、盒式图、盒状图或箱线图,也称箱须图(Box-whisker Plot)。是一种用作显示一组数据分散情况资料的统计图,经常被使用于各种领域,因形状如箱子而得名。它主要用于反映原始数据分布的特征,还可以进行多组数据分布特征的比较。箱形图的绘制方法是:先找出一组数据的上边缘、下边缘、中位数和两个四分位数;然后, 连接两个四分位数画出箱体;再将上边缘和下边缘与箱体相连接,中位数在箱体中间。
QChart提供QBoxPlotSeries, QBoxSet类来实现箱形图的绘制。
QBoxPlotSeries类在箱形图中显示数据。QBoxPlotSeries充当箱形数据集的容器。在QBoxPlotSeries可添加多个箱形数据集QBoxPlotSet。
QBoxPlotSeries 常用函数:
QBoxPlotSeries常用信号:
QBoxSet类代表箱形图中的一个条目。箱形条目是范围和由五个不同值构成的三个中值的图形表示。有两种指定值的方法。第一个是通过使用构造函数或流运算符(<<)。必须按以下顺序指定值:下极值,下四分位数,中位数,上四分位数和上限。第二种方法是创建一个空的QBoxSet实例,并使用setValue()方法指定值。
QBoxSet常用函数:
QBoxSet常用信号:
在QChart C++演示代码为基础上改写,示例代码显示了如何创建一个箱形图,同时也显示了如何从文件中读取数据,并对其进行排列然后查找出箱形图的中位数。最终图形显示了两个公司一年中月度股票数据偏差。
两公司月度股票数据如下图所示:
acme_data.txt
boxwhisk_data.txt
资源文件boxplotdata.qrc文件:
- <RCC>
- <qresource prefix="/">
- <file alias="acme">acme_data.txt</file>
- <file alias="boxwhisk">boxwhisk_data.txt</file>
- </qresource>
- </RCC>
完整代码如下:
- import sys
- from PyQt5.QtCore import Qt, QIODevice, QTextStream, QFile, QDateTime
- from PyQt5.QtGui import QPainter
- from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox
- from PyQt5.QtChart import QChart, QChartView, QBoxPlotSeries, QBoxSet, QValueAxis
-
- import boxplotdata_rc
-
- #读取文本文件并从数据中查找极值和中值
- class BoxDataReader(QTextStream):
- def __init__(self, device, parent = None):
- super(BoxDataReader, self).__init__(parent)
- self.setDevice(device)
- self.sortedList = []
-
- def readFile(self, device):
- self.setDevice(device)
-
- def readBox(self):
- line = self.readLine()
- if line.startswith('#'):
- return None
-
- strList = line.split(' ')
- self.sortedList.clear()
- for i in range(1,len(strList)):
- self.sortedList.append(float(strList[i]))
- self.sortedList.sort() #从小到大排序
-
- count = len(self.sortedList)
-
- box = QBoxSet(strList[0])
- box.setValue(QBoxSet.LowerExtreme, self.sortedList[0]) #下边沿
- box.setValue(QBoxSet.UpperExtreme, self.sortedList[-1]) #上边沿
- box.setValue(QBoxSet.Median, self.findMedian(0, count)) # 中位数
- box.setValue(QBoxSet.LowerQuartile, self.findMedian(0, count//2)) #下四分位数
- box.setValue(QBoxSet.UpperQuartile, self.findMedian(count//2 + count%2, count)) #上四分位数
-
- return box
-
- #获得中值
- def findMedian(self, begin, end):
- count = begin - end
- if count % 2:
- return self.sortedList[count//2 + begin]
- else:
- right = self.sortedList[count//2 + begin]
- left = self.sortedList[count//2 - 1 + begin]
- return (right + left) / 2.0
-
- class DemoChartBoxWhisk(QMainWindow):
- def __init__(self, parent=None):
- super(DemoChartBoxWhisk, self).__init__(parent)
-
- # 设置窗口标题
- self.setWindowTitle('实战 Qt for Python: QChart箱须图演示')
- # 设置窗口大小
- self.resize(640, 480)
-
- self.createChart()
-
- def createChart(self):
- #创建box-whisk
- acmeSeries = QBoxPlotSeries()
- acmeSeries.setName('Acme Ltd')
-
- boxWhiskSeries = QBoxPlotSeries()
- boxWhiskSeries.setName('BoxWhisk Inc')
-
- #从文件中读取数据
- acmeData = QFile(':acme')
- if not acmeData.open(QIODevice.ReadOnly | QIODevice.Text):
- QMessageBox.information(self, '读数据', '不合法的数据文件')
- return
-
- dataReader = BoxDataReader(acmeData)
- while not dataReader.atEnd():
- boxSet = dataReader.readBox()
- if not boxSet is None:
- acmeSeries.append(boxSet)
-
- boxwhiskData = QFile(':boxwhisk')
- if not boxwhiskData.open(QIODevice.ReadOnly | QIODevice.Text):
- QMessageBox.information(self, '读数据', '不合法的数据文件')
- return
-
- dataReader.readFile(boxwhiskData)
- while not dataReader.atEnd():
- boxSet = dataReader.readBox()
- if not boxSet is None:
- boxWhiskSeries.append(boxSet)
-
- #创建图表
- chart = QChart()
- chart.addSeries(acmeSeries)
- chart.addSeries(boxWhiskSeries)
- chart.setTitle('Acme Ltd and BoxWhisk Inc share deviation in 2012')
- chart.setAnimationOptions(QChart.SeriesAnimations)
-
- #坐标轴设置
- chart.createDefaultAxes()
- axisY = chart.axes(Qt.Vertical)[0]
- axisY.setMin(15.0)
- axisY.setMax(34.0)
-
- #图例
- chart.legend().setVisible(True)
- chart.legend().setAlignment(Qt.AlignBottom)
-
- #图表视图
- chartView = QChartView(chart)
- chartView.setRenderHint(QPainter.Antialiasing)
-
- self.setCentralWidget(chartView)
-
-
- if __name__ == '__main__':
- app = QApplication(sys.argv)
- window = DemoChartBoxWhisk()
- window.show()
- sys.exit(app.exec())
运行结果如下图:
QChart箱形图示例