目录
一、盒须图效果
实现效果如下:
QBoxPlotSeries类以方框和胡须图表的形式显示数据。
“长方体绘图”系列充当长方体和胡须项目的容器。多个系列中的项目根据其索引值分组。
QBarCategoryAxis类用于将类别添加到图表的轴。类别标签必须是唯一的。如果为多个长方体和胡须项目定义了相同的类别标签,则只绘制第一个类别标签。
盒须图最主要设置为QBarSet的设置,详细信息如下表:
QBoxSet::LowerExtreme | 0 | 盒须图最小值 |
QBoxSet::LowerQuartile | 1 | 盒须图中间部分的最小值 |
QBoxSet::Median | 2 | 盒须图中间值 |
QBoxSet::UpperQuartile | 3 | 盒须图中间部分的最大值 |
QBoxSet::UpperExtreme | 4 | 盒须图最大值 |
如下图:
二、创建盒须图类
通过new创建两个盒须图类,可以通过setname设置其名字.
m_ptrBoxPlotSeries(new QBoxPlotSeries)
m_ptrBoxPlotSeries2(new QBoxPlotSeries)
m_ptrBoxPlotSeries->setName("统信");
m_ptrBoxPlotSeries2->setName("麒麟");
三、设置盒须图数据
数据设置使用QBarSet进行设置.
因为QBarSet的设置有大小之分,所以我们可以使用qSort对数据进行排序.
那么最小值为listData.first().最大值为listData.last().
中间值为listData的中间值.
QList<qreal> listData;
listData << 25.74 << 25.28 << 25.86 << 26.05 << 26.64 << 28.47 << 28.30
<< 29.22 << 29.72 << 27.50 << 25.62 << 25.50 << 25.15 << 26.47
<< 27.41 << 25.78 << 24.82 << 24.89 << 24.88 << 24.60 << 23.85;
qSort(listData.begin(), listData.end());
QBoxSet *box = new QBoxSet("统信");
int count = listData.count();
box->setValue(QBoxSet::LowerExtreme, listData.first());
box->setValue(QBoxSet::UpperExtreme, listData.last());
box->setValue(QBoxSet::Median, findMedian(listData, 0, count));
box->setValue(QBoxSet::LowerQuartile, findMedian(listData, 0, count / 2));
box->setValue(QBoxSet::UpperQuartile,
findMedian(listData, count / 2 + (count % 2), count));
m_ptrBoxPlotSeries->append(box);
四、计算中间值
传入列表数据,将计算,起点和终点之间的中间值.如果%2 为1那么说明起为单数,可以使用二分之一总数+起始位置.
如果是双数,计算左右值的和除以2.
qreal Widget::findMedian(QList<qreal> sortedList, int begin, int end)
{
//! [5]
int count = end - begin;
if (count % 2) {
return sortedList.at(count / 2 + begin);
} else {
qreal right = sortedList.at(count / 2 + begin);
qreal left = sortedList.at(count / 2 - 1 + begin);
return (right + left) / 2.0;
}
//! [5]
}
五、源代码
https://gitcode.com/arv002/qt/tree/master/QtChartDemo/QBoxPlotSeries/BoxPlotSeries
源代码
widget.cpp
#include "widget.h"
#include <QtDebug>
#include <QLegendMarker>
#include <QBarLegendMarker>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, m_ptrChart(new QChart)
, m_ptrChartview(new QChartView(m_ptrChart, this))
, m_ptrBoxPlotSeries(new QBoxPlotSeries)
, m_ptrBoxPlotSeries2(new QBoxPlotSeries)
{
initUI();
initConnect();
}
void Widget::initUI()
{
setWindowTitle(tr("盒须图样例"));
m_ptrChart->setMinimumSize(500, 500);
m_ptrChart->setTitle("盒须图样例");
initData();
m_ptrChart->createDefaultAxes();
m_ptrChart->axes(Qt::Vertical).first()->setMin(15.0);
m_ptrChart->axes(Qt::Vertical).first()->setMax(40.0);
m_ptrChart->setAnimationOptions(QChart::AllAnimations);
m_ptrChartview->setFixedSize(600, 600);
m_ptrChartview->setRenderHint(QPainter::Antialiasing);
}
void Widget::initConnect()
{
foreach (auto marker, m_ptrChart->legend()->markers()) {
QObject::disconnect(marker, &QLegendMarker::clicked, this,
&Widget::handleMarkerClicked);
QObject::connect(marker, &QLegendMarker::clicked, this,
&Widget::handleMarkerClicked);
}
}
void Widget::handleMarkerClicked()
{
QLegendMarker *marker = qobject_cast<QLegendMarker *>(sender());
//断言
Q_ASSERT(marker);
switch (marker->type()) {
case QLegendMarker::LegendMarkerTypeBoxPlot: {
//控序列隐藏/显示
// Toggle visibility of series
marker->series()->setVisible(!marker->series()->isVisible());
// Turn legend marker back to visible, since hiding series also
// hides the marker and we don't want it to happen now.
marker->setVisible(true);
//修改图例
// Dim the marker, if series is not visible
qreal alpha = 1.0;
if (!marker->series()->isVisible()) alpha = 0.5;
QColor color;
QBrush brush = marker->labelBrush();
color = brush.color();
color.setAlphaF(alpha);
brush.setColor(color);
marker->setLabelBrush(brush);
brush = marker->brush();
color = brush.color();
color.setAlphaF(alpha);
brush.setColor(color);
marker->setBrush(brush);
QPen pen = marker->pen();
color = pen.color();
color.setAlphaF(alpha);
pen.setColor(color);
marker->setPen(pen);
break;
}
default: {
qInfo() << "Unknown marker type";
break;
}
}
}
void Widget::initData()
{
QList<qreal> listData;
listData << 25.74 << 25.28 << 25.86 << 26.05 << 26.64 << 28.47 << 28.30
<< 29.22 << 29.72 << 27.50 << 25.62 << 25.50 << 25.15 << 26.47
<< 27.41 << 25.78 << 24.82 << 24.89 << 24.88 << 24.60 << 23.85;
qSort(listData.begin(), listData.end());
QBoxSet *box = new QBoxSet("统信");
int count = listData.count();
box->setValue(QBoxSet::LowerExtreme, listData.first());
box->setValue(QBoxSet::UpperExtreme, listData.last());
box->setValue(QBoxSet::Median, findMedian(listData, 0, count));
box->setValue(QBoxSet::LowerQuartile, findMedian(listData, 0, count / 2));
box->setValue(QBoxSet::UpperQuartile,
findMedian(listData, count / 2 + (count % 2), count));
m_ptrBoxPlotSeries->append(box);
listData.clear();
qInfo() << listData;
listData << 30.79 << 29.62 << 29.67 << 30.37 << 30.16 << 30.22 << 31.02
<< 33.70 << 32.60 << 32.24 << 31.98 << 31.79 << 31.10 << 30.79
<< 31.53 << 30.92 << 29.00 << 29.58 << 30.37 << 29.40 << 28.60;
qSort(listData.begin(), listData.end());
QBoxSet *box2 = new QBoxSet("麒麟");
count = listData.count();
qInfo() << findMedian(listData, 0, count);
qInfo() << findMedian(listData, 0, count / 2);
qInfo() << findMedian(listData, count / 2 + (count % 2), count);
box2->setValue(QBoxSet::LowerExtreme, listData.first());
box2->setValue(QBoxSet::UpperExtreme, listData.last());
box2->setValue(QBoxSet::Median, findMedian(listData, 0, count));
box2->setValue(QBoxSet::LowerQuartile, findMedian(listData, 0, count / 2));
box2->setValue(QBoxSet::UpperQuartile,
findMedian(listData, count / 2 + (count % 2), count));
m_ptrBoxPlotSeries2->append(box2);
m_ptrBoxPlotSeries->setName("统信");
m_ptrBoxPlotSeries2->setName("麒麟");
m_ptrChart->addSeries(m_ptrBoxPlotSeries);
m_ptrChart->addSeries(m_ptrBoxPlotSeries2);
}
qreal Widget::findMedian(QList<qreal> sortedList, int begin, int end)
{
//! [5]
int count = end - begin;
if (count % 2) {
return sortedList.at(count / 2 + begin);
} else {
qreal right = sortedList.at(count / 2 + begin);
qreal left = sortedList.at(count / 2 - 1 + begin);
return (right + left) / 2.0;
}
//! [5]
}
Widget::~Widget() {}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QChart>
#include <QChartView>
#include <QBoxPlotSeries>
#include <QBoxSet>
QT_CHARTS_USE_NAMESPACE
class Widget : public QWidget {
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
void initUI();
void initConnect();
void initData();
qreal findMedian(QList<qreal> sortedList, int begin, int end);
public slots:
void handleMarkerClicked();
private:
QChart *m_ptrChart;
QChartView *m_ptrChartview;
QBoxPlotSeries *m_ptrBoxPlotSeries;
QBoxPlotSeries *m_ptrBoxPlotSeries2;
};
#endif // WIDGET_H
六、其他文章
Qt散点图、折线图、柱状图、盒须图、饼状图、雷达图开发实例。
在开发过程中我们会使用多各种各样的图,讲数据进行可视化。我们可以使用以上几种图来表达我们的数据。Qt提供了一些可视化图的库Qchart,我们可以利用他开发自己想要图表。
6.1 散点图
散点图,顾名思义就是由一些散乱的点组成的图表,这些点在哪个位置,是由其X值和Y值确定的。所以也叫做XY散点图。
作用一:可以展示数据的分布和聚合情况。
作用二:得到趋势线公式。
文章地址:点击地址
源代码地址:gitcode地址
6.2 折线图
折线图是排列在工作表的列或行中的数据可以绘制到折线图中。折线图可以显示随时间(根据常用比例设置)而变化的连续数据,因此非常适用于显示在相等时间间隔下数据的趋势。
文章地址:点击进入
代码地址: gitcode地址
6.3 柱状图
柱形图,又称长条图、柱状统计图(德文: Säulendiagramm、英文:bar chart、西班牙文: diagrama de barras)亦称条图(德文: Stabdiagramm、英文:bar graph、西班牙文: diagrama de columnas)、条状图、棒形图,是一种以长方形的长度为变量的统计图表。长条图用来比较两个或以上的价值(不同时间或者不同条件),只有一个变量,通常利用于较小的数据集分析。长条图亦可横向排列,或用多维方式表达。
文章地址:点击进入
代码地址:gitcode地址
水平柱状图
文章地址:点击进入
代码地址:gitcode地址
水平堆叠图
文章地址:点击进入
代码地址:gitcode地址
水平百分比柱状图
文章地址:点击进入
代码地址:gitcode地址
6.4 盒须图
箱形图(Box-plot)又称为盒须图、盒式图或箱线图,是一种用作显示一组数据分散情况资料的统计图。因形状如箱子而得名。在各种领域也经常被使用,常见于品质管理。它主要用于反映原始数据分布的特征,还可以进行多组数据分布特征的比 较。箱线图的绘制方法是:先找出一组数据的上边缘、下边缘、中位数和两个四分位数;然后, 连接两个四分位数画出箱体;再将上边缘和下边缘与箱体相连接,中位数在箱体中间。
文章地址:点击进入
代码地址:gitcode地址
6.5 饼状图
饼状图常用于统计学模型。有2D与3D饼状图,2D饼状图为圆形,手画时,常用圆规作图。饼状图显示一个数据系列(数据系列:在图表中绘制的相关数据点,这些数据源自数据表的行或列。图表中的每个数据系列具有唯一的颜色或图案并且在图表的图例中表示。可以在图表中绘制一个或多个数据系列。饼状图只有一个数据系列。)中各项的大小与各项总和的比例。饼状图中的数据点(数据点:在图表中绘制的单个值,这些值由条形、柱形、折线、饼状图或圆环图的扇面、圆点和其他被称为数据标记的图形表示。相同颜色的数据标记组成一个数据系列。)显示为整个饼状图
文章地址:点击进入
代码地址:gitcode地址
6.6 雷达图
雷达图是以从同一点开始的轴上表示的三个或更多个定量变量的二维图表的形式显示多变量数据的图形方法。轴的相对位置和角度通常是无信息的。 雷达图也称为网络图,蜘蛛图,星图,蜘蛛网图,不规则多边形,极坐标图或Kiviat图。它相当于平行坐标图,轴径向排列。
文章地址:点击进入
代码地址:gitcode地址