7

C++ Qt开发:Charts绘制各类图表详解 - lyshark

 8 months ago
source link: https://www.cnblogs.com/LyShark/p/17927046.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍TreeWidgetQCharts的常用方法及灵活运用。

在之前的文章中笔者介绍了如何使用QCharts模块来绘制简单的折线图并对通用API接口进行了概括,本章我们通过在TreeWidget组件中提取数据,并依次实现柱状图、饼状图、堆叠图、百分比图、散点图等。

1.1 创建柱状图

柱状图(Bar Chart)用于显示各类别之间的数量关系。它通过在一个坐标系中绘制垂直的矩形条(柱)来表示数据。每个柱的高度表示相应类别的数量或数值,柱的宽度一般是固定的,类别之间的间隔可以根据需要调整。

柱状图主要用于比较不同类别的数值或数量,帮助观察数据的分布趋势、对比不同类别的数据大小,以及发现数据之间的关系。柱状图通常在横轴上表示不同的类别,纵轴上表示数量或数值。

以下是柱状图的一些主要特点:

  1. 垂直柱状图(Vertical Bar Chart):柱状图的柱是垂直排列的,纵轴表示数值或数量。
  2. 水平柱状图(Horizontal Bar Chart):柱状图的柱是水平排列的,横轴表示数值或数量。
  3. 分组柱状图(Grouped Bar Chart):将柱按照类别分组,同一组内的柱一般在相同的位置。
  4. 堆叠柱状图(Stacked Bar Chart):将柱叠加在一起,柱的高度表示总和。
  5. 百分比柱状图(Percentage Bar Chart):每个柱的高度表示相对于总和的百分比。

柱状图是数据可视化中常用的工具之一,易于理解且能够直观地传达信息。在业务、科学研究、金融等领域,柱状图被广泛用于展示数据的分布和趋势。在Qt中柱状图的绘制离不开三个类的支持,其分别是QBarSetQBarSeriesQBarCategoryAxis这三个类提供了用于操作和管理条形图数据集的方法。

QBarSet类主要用于创建或表示一个柱状图的集合元素。以下是关于QBarSet的主要方法的说明和概述,以表格形式呈现:

方法 描述
QBarSet(const QString &label = QString()) 构造函数,创建一个空的 QBarSet 对象,可以通过提供标签进行初始化。
void append(qreal value) 将一个值添加到数据集的末尾。
void append(const QList<qreal> &values) 将一组值添加到数据集的末尾。
void replace(int index, qreal value) 替换数据集中指定索引位置的值。
void replace(const QList<qreal> &values) 用提供的一组值替换整个数据集。
void clear() 清除数据集中的所有值。
int count() const 返回数据集中值的数量。
bool isEmpty() const 检查数据集是否为空。
QString label() const 返回数据集的标签。
void setLabel(const QString &label) 设置数据集的标签。
qreal at(int index) const 返回数据集中指定索引位置的值。
QList<qreal> values() const 返回包含数据集所有值的列表。

QBarSeries 用于表示条形图数据系列。以下是 QBarSeries 类的一些主要方法和概述:

方法 描述
QBarSeries(QObject *parent = nullptr) 构造函数,创建一个空的 QBarSeries 对象。
void append(QBarSet *set) 将一个 QBarSet 对象添加到系列的末尾。
void append(const QList<QBarSet*> &sets) 将一组 QBarSet 对象添加到系列的末尾。
void replace(int index, QBarSet *set) 替换系列中指定索引位置的 QBarSet 对象。
void replace(const QList<QBarSet*> &sets) 用提供的一组 QBarSet 对象替换整个系列。
void remove(int index) 移除系列中指定索引位置的 QBarSet 对象。
void clear() 清除系列中的所有 QBarSet 对象。
int count() const 返回系列中 QBarSet 对象的数量。
bool isEmpty() const 检查系列是否为空。
QBarSet* at(int index) const 返回系列中指定索引位置的 QBarSet 对象。
QList<QBarSet*> barSets() const 返回包含系列所有 QBarSet 对象的列表。

QBarCategoryAxis 表示条形图横坐标,用于管理和显示条形图中的分类轴,其中每个条形图都属于特定的类别。以下是 QBarCategoryAxis 类的一些主要方法和概述:

方法 描述
QBarCategoryAxis(QObject *parent = nullptr) 构造函数,创建一个空的 QBarCategoryAxis 对象。
void append(const QStringList &categories) 将一组类别添加到轴的末尾。
void append(const QString &category) 将一个类别添加到轴的末尾。
void insert(int index, const QString &category) 在指定索引位置插入一个类别。
void insert(int index, const QStringList &categories) 在指定索引位置插入一组类别。
void remove(const QString &category) 移除指定的类别。
void remove(int index, int count = 1) 从指定索引位置开始移除指定数量的类别。
void clear() 清除轴中的所有类别。
int count() const 返回轴中类别的数量。
QString categoryAt(int index) const 返回轴中指定索引位置的类别。
QStringList categories() const 返回包含轴所有类别的列表。
void setCategories(const QStringList &categories) 设置轴的类别。
void setStartValue(qreal value) 设置轴的起始值。
qreal startValue() const 返回轴的起始值。
void setRange(qreal min, qreal max) 设置轴的范围。
void append(const QVector<QPointF> &points) 将一组点添加到轴的末尾,用于自动设置类别。
void replace(const QVector<QPointF> &points) 用提供的一组点替换整个轴,用于自动设置类别。

如下代码是使用 Qt 的图表模块创建一个包含柱状图和折线图的图表,并显示在 QGraphicsView 控件中,在MainWindow::MainWindow构造函数中我们可以使用如下代码实现柱状图的创建。

图表初始化:创建一个 QChart 对象,并设置图表的标题和动画效果。然后将图表设置给 ui->graphicsView 控件,同时启用抗锯齿渲染。

QChart *chart = new QChart();
chart->setTitle("柱状图统计");
chart->setAnimationOptions(QChart::SeriesAnimations);

// 为graphicsView设置chart
ui->graphicsView->setChart(chart);
ui->graphicsView->setRenderHint(QPainter::Antialiasing);

// 构造柱状图
chart =ui->graphicsView->chart();
chart->removeAllSeries();            // 删除所有序列
chart->removeAxis(chart->axisX());   // 删除坐标轴
chart->removeAxis(chart->axisY());   // 删除坐标轴

创建数据集:构造三个 QBarSet 对象,分别表示数学、语文、英语的数据集。同时创建一个 QLineSeries 对象,表示平均分数据集,并设置线条的颜色和宽度。

QBarSet *setMath = new QBarSet(theModel->horizontalHeaderItem(1)->text());      // 数学字段
QBarSet *setChinese = new QBarSet(theModel->horizontalHeaderItem(2)->text());   // 语文字段
QBarSet *setEnglish= new QBarSet(theModel->horizontalHeaderItem(3)->text());    // 英语字段

// 创建折线线条
QLineSeries *Line = new QLineSeries();
Line->setName(theModel->horizontalHeaderItem(4)->text());  // 表示平均分
QPen pen;
pen.setColor(Qt::red);  // 使用红色
pen.setWidth(2);        // 设置宽度
Line->setPen(pen);      // 绘制

添加数据:遍历前10个数据行,将数学、语文、英语的成绩和平均分添加到相应的数据集中。

for(int i=0;i< 10;i++)
{
    // 从数据模型获取数据
    setMath->append(theModel->item(i,1)->text().toInt());            // 数学
    setChinese->append(theModel->item(i,2)->text().toInt());         // 语文
    setEnglish->append(theModel->item(i,3)->text().toInt());         // 英语
    Line->append(QPointF(i,theModel->item(i,4)->text().toFloat()));  // 平均分
}

创建柱状图序列:使用 QBarSeries 创建一个柱状图序列,并将三个数据集添加到序列中。同时,将折线图序列也添加到图表中。

cppCopy codeQBarSeries *series = new QBarSeries();
series->append(setMath);
series->append(setChinese);
series->append(setEnglish);

chart->addSeries(series);
chart->addSeries(Line);

设置坐标轴:创建横坐标轴 axisX 和纵坐标轴 axisY,设置它们的范围、标签等信息,然后将它们与相应的序列关联。

// 创建柱状图序列 QBarSeries 并添加三个数据集
QBarSeries *series = new QBarSeries();
series->append(setMath);
series->append(setChinese);
series->append(setEnglish);

chart->addSeries(series); // 添加柱状图序列
chart->addSeries(Line);   // 添加折线图序列

// 用于横坐标在字符串列表 即UID
QStringList categories;
for (int i=0;i<10;i++)
{
    categories <<theModel->item(i,0)->text();
}

// 柱状图的坐标轴
QBarCategoryAxis *axisX = new QBarCategoryAxis();
axisX->append(categories);            // 添加横坐标文字列表
chart->setAxisX(axisX, series);       // 设置横坐标
chart->setAxisX(axisX, Line);         // 设置横坐标

// 设置坐标范围
axisX->setRange(categories.at(0), categories.at(categories.count()-1));

// 数值型坐标作为纵轴
QValueAxis *axisY = new QValueAxis;
axisY->setRange(0, 100);
axisY->setTitleText("分数");
axisY->setTickCount(6);
axisY->setLabelFormat("%.0f");

图例显示设置:显示图例,并设置图例在底部对齐。

chart->setAxisY(axisY, series);
chart->setAxisY(axisY, Line);
chart->legend()->setVisible(true);
chart->legend()->setAlignment(Qt::AlignBottom);

这样,你就创建了一个包含柱状图和折线图的图表,并将其显示在 QGraphicsView 控件中,运行后则可以得到如下图所示的图例;

1.2 创建饼状图

饼状图(Pie Chart)用于展示各部分占整体的比例关系。它通过在一个圆形区域内绘制扇形来表示数据的相对大小。整个圆表示总体,而每个扇形的弧长(或面积)表示相应类别的数量或比例。

饼状图的主要特点包括:

  1. 占比表示:每个扇形的大小表示相应类别在总体中所占的比例,从而直观地展示各类别之间的相对关系。
  2. 圆形布局:饼状图的数据以圆形的方式呈现,使得用户能够轻松比较各部分的大小。
  3. 清晰易懂:饼状图通常用于表示数据的相对比例,特别适用于展示类别之间的占比关系,非常直观。
  4. 单一变量:饼状图适合展示单一变量的占比关系,不适用于多个变量或时间序列的比较。
  5. 限制数据量:由于饼状图是基于整个圆的,适合表示少量类别的占比关系。当类别过多时,可能导致图形复杂,难以解读。

饼状图常见的应用场景包括市场份额分析、调查结果的占比展示、资源分配比例等。然而,有时候,为了更好地表达数据,也会使用改进版的饼状图,如环形图(Donut Chart)等。

QPieSeries 是 Qt Charts 模块中用于绘制饼状图的数据序列类。它派生自 QAbstractSeries 类,用于管理和展示饼状图中的数据。以下是 QPieSeries 类的一些常用方法和属性,以表格形式概述:

方法 描述
QPieSeries(QObject *parent = nullptr) 构造函数,创建一个 QPieSeries 对象。
~QPieSeries() 析构函数,释放 QPieSeries 对象。
append(QPieSlice *slice) 向饼状图序列中追加一个饼块。
insert(int index, QPieSlice *slice) 在指定位置插入一个饼块。
remove(QPieSlice *slice) 从饼状图序列中移除指定的饼块。
clear() 清除饼状图序列中的所有饼块。
slices() 返回饼状图序列中的所有饼块。
count() 返回饼状图序列中的饼块数量。
at(int index) 返回饼状图序列中指定索引位置的饼块。
setVisible(bool visible) 设置饼状图序列的可见性。
isVisible() 返回饼状图序列的可见性。
setHoleSize(double size) 设置饼状图中间空心的大小,范围为 [0.0, 1.0],0.0 表示没有空心,1.0 表示整个饼状图都是空心。
holeSize() 返回饼状图中间空心的大小。
setPieSize(double size) 设置饼状图的大小,范围为 [0.0, 1.0],默认为 1.0。
pieSize() 返回饼状图的大小。
setLabelsVisible(bool visible) 设置饼块的标签是否可见。
labelsVisible() 返回饼块的标签是否可见。
setLabelsPosition(QPieSlice::LabelPosition position) 设置饼块标签的位置。
labelsPosition() 返回饼块标签的位置。
setLabelsPrecision(int precision) 设置饼块标签显示的小数位数。
labelsPrecision() 返回饼块标签显示的小数位数。
clicked(QPieSlice *slice) 点击饼块时发出的信号,参数为被点击的饼块。
hovered(QPieSlice *slice, bool state) 鼠标悬停在饼块上时发出的信号,参数为被悬停的饼块和悬停状态。
pressed(QPieSlice *slice) 鼠标按下饼块时发出的信号,参数为被按下的饼块。
released(QPieSlice *slice) 鼠标释放饼块时发出的信号,参数为被释放的饼块。

QPieSlice 是 Qt Charts 模块中用于表示饼状图中的单个饼块的类。每个 QPieSlice 对象都代表饼状图中的一个数据分块。

以下是关于 QPieSlice 的一些方法以及说明:

方法 描述
QPieSlice(qreal value, QString label) 构造函数,创建一个带有给定值和标签的 QPieSlice 对象。
~QPieSlice() 析构函数,释放 QPieSlice 对象。
setLabel(QString label) 设置饼块的标签文字。
label() 返回饼块的标签文字。
setValue(qreal value) 设置饼块的值。
value() 返回饼块的值。
setExploded(bool exploded) 设置饼块是否为爆炸状态,即是否与饼图分离。
isExploded() 返回饼块是否为爆炸状态。
setPieSeries(QPieSeries *series) 设置饼块所属的 QPieSeries 对象。
pieSeries() 返回饼块所属的 QPieSeries 对象。
setBrush(const QBrush &brush) 设置饼块的画刷,即填充颜色。
brush() 返回饼块的画刷。
setLabelBrush(const QBrush &brush) 设置饼块标签的画刷,即标签的颜色。
labelBrush() 返回饼块标签的画刷。
setPen(const QPen &pen) 设置饼块的画笔,即边框颜色和样式。
pen() 返回饼块的画笔。
setLabelVisible(bool visible) 设置饼块标签是否可见。
isLabelVisible() 返回饼块标签是否可见。
setExplodeDistanceFactor(qreal factor) 设置饼块爆炸时的距离因子,即与饼图分离的距离。
explodeDistanceFactor() 返回饼块爆炸时的距离因子。
setPercentage(qreal percentage) 设置饼块的百分比值。
percentage() 返回饼块的百分比值。
clicked(bool state) 鼠标点击饼块时发出的信号,参数为鼠标点击的状态(按下或释放)。
hovered(bool state) 鼠标悬停在饼块上时发出的信号,参数为悬停状态。
pressed() 鼠标按下饼块时发出的信号。
released() 鼠标释放饼块时发出的信号。

QPieSlice 主要用于配置和管理饼状图中的单个数据分块,包括设置饼块的标签、值、颜色、样式等属性。

饼状图的绘制流程与柱状图一样,主要以下几个步骤:

饼图初始化: 创建一个QChart对象,并设置其动画选项。然后将该图表对象设置为QGraphicsView的图表,并启用反锯齿渲染。

// 饼图初始化
QChart *chart = new QChart();
chart->setAnimationOptions(QChart::SeriesAnimations);
ui->graphicsView->setChart(chart);
ui->graphicsView->setRenderHint(QPainter::Antialiasing);

// 绘制饼图
chart->removeAllSeries();

创建饼图序列:为图表创建一个新的饼图序列(QPieSeries),并通过循环的方式向序列中添加成绩。

// 创建饼图序列
QPieSeries *series = new QPieSeries();

// 饼图中间空心的大小
series->setHoleSize(0.30);

// 添加分块数据
for (int i=0;i<=4;i++)
{
    // 获得QTreeWidgetItem的item
    QTreeWidgetItem* item=ui->treeWidget->topLevelItem(i);

    // 获取分析对象,数学、英语、语文或平均分,添加一个饼图分块数据,标签,数值
    series->append(item->text(0),item->text(1).toFloat());
}

添加分块数据到饼图:QTreeWidget中获取每个分析对象(数学、英语、语文或平均分),并将其添加到饼图序列中。

// 饼图分块
QPieSlice *slice;

// 设置每个分块的标签文字
for(int i=0;i<=4;i++)
{
    // 获取分块
    slice =series->slices().at(i);

    // 设置分块的标签
    slice->setLabel(slice->label()+QString::asprintf(": %.0f人, %.1f%%", slice->value(),slice->percentage()*100));

    // 信号与槽函数关联,鼠标落在某个分块上时,此分块弹出
    connect(slice, SIGNAL(hovered(bool)),this, SLOT(on_PieSliceHighlight(bool)));
}

slice->setExploded(true);           // 最后一个设置为exploded
series->setLabelsVisible(true);     // 只影响当前的slices,必须添加完slice之后再设置
chart->addSeries(series);           // 添加饼图序列

chart->legend()->setVisible(true);  // 图例
chart->legend()->setAlignment(Qt::AlignRight);

设置饼图分块的标签和槽函数关联: 对于每个分块,设置其标签文字,包括数值和百分比,并关联鼠标悬停事件的槽函数。

// 鼠标移入移出时触发hovered信号
void MainWindow::on_PieSliceHighlight(bool show)
{
    QPieSlice *slice;
    slice=(QPieSlice *)sender();

    // 动态设置setExploded效果
    // slice->setLabelVisible(show);
    slice->setExploded(show);
}

上述代码流程实现了在Qt中使用QPieSeriesQPieSlice绘制饼状图的功能,包括图表的初始化、数据的设置、分块标签的添加、饼图分块的突出显示等。在图表中,每个分块代表一种分析对象,标签包含人数和百分比信息,运行后输出如下效果;

1.3 创建堆叠图

堆叠图(Stacked Chart)用于展示多个数据系列的累积效果,即将不同系列的数据在同一数值点上进行堆叠显示。这种图表形式旨在突出整体的趋势以及各组成部分的相对贡献。

堆叠图有多种形式,其中两种常见的类型包括:

  1. 堆叠柱状图(Stacked Bar Chart):在同一类别或数值点上,将不同系列的柱状图堆叠在一起。每个柱状图的高度表示该系列在该点上的数值,而整个柱状图的高度表示各个系列在该点上的累积总和。
  2. 堆叠面积图(Stacked Area Chart):在同一类别或数值点上,将不同系列的面积图堆叠在一起。每个面积图的面积表示该系列在该点上的数值,而整个堆叠面积图的高度表示各个系列在该点上的累积总和。

堆叠图的优势在于能够直观地显示各部分在整体中的相对比例,并清晰地展示随时间或其他维度的变化。这种图表类型通常用于比较多个系列的总体趋势,并强调各个系列之间的相对贡献。在堆叠图中,每个系列的数值贡献会在相同的数值点上叠加显示,使得读者能够更容易比较各系列的相对大小。

堆叠图的创建需要用到QStackedBarSeriesQBarCategoryAxis类,QStackedBarSeries 是 Qt Charts 模块中用于创建堆叠柱状图的类。堆叠柱状图显示多个柱状系列的堆叠效果,每个柱状系列由一个或多个柱状条组成,这些柱状条按照数据堆叠在一起,形成整体的柱状图。

以下是 QStackedBarSeries 的一些重要方法和属性:

方法 描述
QStackedBarSeries(QObject *parent = nullptr) 构造函数,创建一个 QStackedBarSeries 对象。
void append(QBarSet *set) 将一个 QBarSet 添加到序列中。
void append(QList<QBarSet *> sets) 将一组 QBarSet 添加到序列中。
QList<QBarSet *> barSets() const 返回序列中的所有 QBarSet
void setLabelsVisible(bool visible) 设置是否显示柱状图的标签。
bool labelsVisible() const 返回柱状图的标签可见性。
void setLabelsFormat(const QString &format) 设置标签的显示格式。
QString labelsFormat() const 返回标签的显示格式。
void setLabelsPosition(QAbstractBarSeries::LabelsPosition position) 设置标签的位置。
QAbstractBarSeries::LabelsPosition labelsPosition() const 返回标签的位置。

QStackedBarSeries 通过添加不同的 QBarSet 对象来创建堆叠效果。每个 QBarSet 对象代表一个柱状系列,它包含了一组柱状条的数据。标签、颜色和其他样式属性可以通过 QBarSet 进行定制。使用这些方法和属性,可以方便地控制堆叠柱状图的外观和行为,如下代码则是堆叠图创建的实现;

// 初始化叠加柱状图绘制窗口
QChart *chart = new QChart();
chart->setAnimationOptions(QChart::SeriesAnimations);
ui->graphicsView->setChart(chart);
ui->graphicsView->setRenderHint(QPainter::Antialiasing);

// 绘制叠加柱状图
chart->removeAllSeries();
chart->removeAxis(chart->axisX());
chart->removeAxis(chart->axisY());

// 创建三门课程的数据集
QBarSet *setMath = new QBarSet(theModel->horizontalHeaderItem(1)->text());
QBarSet *setChinese = new QBarSet(theModel->horizontalHeaderItem(2)->text());
QBarSet *setEnglish= new QBarSet(theModel->horizontalHeaderItem(3)->text());

// 添加前十个分数数据到数据集
for(int i=0;i<20;i++)
{
    setMath->append(theModel->item(i,1)->text().toInt());
    setChinese->append(theModel->item(i,2)->text().toInt());
    setEnglish->append(theModel->item(i,3)->text().toInt());
}

// 创建QStackedBarSeries对象并添加数据集
QStackedBarSeries *series = new QStackedBarSeries();
series->append(setMath);
series->append(setChinese);
series->append(setEnglish);
series->setLabelsVisible(true);

// 添加序列到图表
chart->addSeries(series);

QStringList categories;

// 绘制前十个数据
for (int i=0;i<10;i++)
{
    categories <<theModel->item(i,0)->text();
}

// 类别坐标轴 作为横轴
QBarCategoryAxis *axisX = new QBarCategoryAxis();
axisX->append(categories);
chart->setAxisX(axisX, series);
axisX->setRange(categories.at(0), categories.at(categories.count()-1));

// 数值坐标轴 作为纵轴
QValueAxis *axisY = new QValueAxis;
axisY->setRange(0, 300);
axisY->setTitleText("总分");
axisY->setTickCount(6);
axisY->setLabelFormat("%.0f");
chart->setAxisY(axisY, series);

// 设置图表属性
chart->legend()->setVisible(true);
chart->legend()->setAlignment(Qt::AlignBottom);

运行后,通过QBarSet保存课程数据集,最后增加横轴纵轴区间,当数据被加载后,图表则会输出如下所示的数据集;

1.4 创建百分比图

百分比图(Percentage Chart)用于显示各部分占整体的百分比关系的图表。这种图表通过以百分比形式展示每个部分在总体中所占比例,提供了一种直观的方式来比较不同部分的相对大小。

百分比图有多种形式,其中一些常见的类型包括:

  1. 百分比柱状图(Percentage Bar Chart):类似于常规柱状图,但每个柱的高度表示相对于整体的百分比。
  2. 百分比堆叠柱状图(Percentage Stacked Bar Chart):将柱叠加在一起,每个部分的高度表示相对于总体的百分比。
  3. 百分比饼状图(Percentage Pie Chart):类似于饼状图,但每个扇形的角度或面积表示相对于整体的百分比。
  4. 百分比面积图(Percentage Area Chart):面积图的每个区域表示相对于整体的百分比。
  5. 百分比堆叠面积图(Percentage Stacked Area Chart):将面积叠加在一起,每个区域的面积表示相对于总体的百分比。

这些图表形式在不同情境下用于展示数据的占比关系,特别适用于需要强调相对比例的场景。百分比图通常能够帮助观众更容易地理解各部分在整体中的贡献,是一种有力的数据可视化工具。

使用百分比图时,注意确保数据的总和为100%。百分比图在市场份额分析、调查结果的占比展示、资源分配比例等方面得到广泛应用。

QPercentBarSeries 是 Qt Charts 模块中用于绘制百分比柱状图的类。它派生自 QAbstractBarSeries 类,表示一个二维坐标系中的数据系列,其中的数据以百分比柱状图的形式呈现。

以下是关于 QPercentBarSeries 的一些方法以及说明:

方法 描述
QPercentBarSeries() 构造函数,创建一个 QPercentBarSeries 对象。
~QPercentBarSeries() 析构函数,释放 QPercentBarSeries 对象。
setLabelsVisible(bool) 设置百分比柱状图上的数据标签是否可见。
labelsVisible() 返回百分比柱状图上的数据标签是否可见的状态。
setLabelsPosition(Position) 设置百分比柱状图上的数据标签位置,Position 是一个枚举类型,表示标签的位置,如上方、下方、内部等。
labelsPosition() 返回百分比柱状图上的数据标签位置。
setLabelsFormat(QString) 设置百分比柱状图上的数据标签的格式,使用字符串指定标签的显示格式。
labelsFormat() 返回百分比柱状图上的数据标签的显示格式。
setPercentageVisible(bool) 设置百分比柱状图上的百分比标签是否可见。
percentageVisible() 返回百分比柱状图上的百分比标签是否可见的状态。
setStackingGap(qreal) 设置百分比柱状图中堆叠的百分比柱之间的间隙。
stackingGap() 返回百分比柱状图中堆叠的百分比柱之间的间隙。
append(QBarSet*) 在百分比柱状图中追加一个数据集。
insert(int, QBarSet*) 在百分比柱状图中插入一个数据集,参数为位置索引和 QBarSet 对象。
remove(QBarSet*) 从百分比柱状图中移除指定的数据集。
take(int) 从百分比柱状图中移除并返回指定位置的数据集。
take(QBarSet*) 从百分比柱状图中移除指定的数据集并返回。
count() 返回百分比柱状图中数据集的数量。
barSets() 返回百分比柱状图中所有数据集的列表。
barWidth() 返回百分比柱状图中百分比柱的宽度。
barWidthChanged(qreal) 当百分比柱状图中百分比柱的宽度发生变化时发出的信号,参数为新的宽度值。

QPercentBarSeries 类主要用于在图表中绘制百分比柱状图,其中的数据集可以包含多个柱子,每个柱子表示一个百分比。

// 百分比柱状图初始化
QChart *chart = new QChart();
chart->setAnimationOptions(QChart::SeriesAnimations);
ui->graphicsView->setChart(chart);
ui->graphicsView->setRenderHint(QPainter::Antialiasing);

// 绘制百分比柱状图
chart->removeAllSeries();
chart->removeAxis(chart->axisX());
chart->removeAxis(chart->axisY());

// 创建数据集
QBarSet *setMath = new QBarSet(theModel->horizontalHeaderItem(1)->text());
QBarSet *setChinese = new QBarSet(theModel->horizontalHeaderItem(2)->text());
QBarSet *setEnglish= new QBarSet(theModel->horizontalHeaderItem(3)->text());

QTreeWidgetItem *item;
QStringList categories;

for (int i=0;i<=4;i++)
{
    // 从分数段统计数据表里获取数据添加到数据集
    item=ui->treeWidget->topLevelItem(i);

    // 横坐标的标签
    categories<<item->text(0);

    // 添加数据到QBarSet中
    setMath->append(item->text(1).toFloat());
    setChinese->append(item->text(2).toFloat());
    setEnglish->append(item->text(3).toFloat());
}

// 添加序列
QPercentBarSeries *series = new QPercentBarSeries();
series->append(setMath);
series->append(setChinese);
series->append(setEnglish);
series->setLabelsVisible(true);
series->setLabelsFormat("@value人");
chart->addSeries(series);

// 添加横坐标
QBarCategoryAxis *axisX = new QBarCategoryAxis();
axisX->append(categories);
chart->setAxisX(axisX, series);
axisX->setRange(categories.at(0), categories.at(categories.count()-1));

// 添加纵坐标
QValueAxis *axisY = new QValueAxis;
axisY->setRange(0, 100);
axisY->setTitleText("百分比");
axisY->setTickCount(6);
axisY->setLabelFormat("%.1f");
chart->setAxisY(axisY, series);

// 设置属性
chart->legend()->setVisible(true);
chart->legend()->setAlignment(Qt::AlignRight);

运行后则可输出不同分数段每一门成绩的百分比分布情况,如下图所示;

1.5 创建散点图

散点图(Scatter Plot)是一种二维图表,用于显示两个变量之间的关系。散点图的每个数据点由两个数值组成,分别对应于图表的横轴和纵轴。通过在图表中绘制这些点,可以观察和分析变量之间的关联性、趋势、聚集程度等。

散点图的特点包括:

  1. 数据点表示:每个数据点在图表上表示为一个独立的点,其中横轴对应一个变量,纵轴对应另一个变量。
  2. 关系展示:散点图主要用于展示两个变量之间的关系,例如相关性、分布情况、趋势等。
  3. 离散数据:适用于离散型数据,每个点表示一个具体的观测值。
  4. 聚类发现:通过观察数据点的分布,可以发现数据是否呈现出某种聚类模式。
  5. 异常值检测:可以用于检测异常值,即图表中偏离正常分布的离群点。

散点图的应用场景非常广泛,常见的用途包括:

  • 相关性分析:通过观察散点图,可以初步了解两个变量之间的相关性,是进行相关性分析的一种可视化手段。
  • 趋势分析:散点图可以用于观察两个变量之间是否存在趋势,是进行趋势分析的有力工具。
  • 异常值检测:通过识别离群点,可以发现数据中的异常值,有助于数据清理和分析的准确性。
  • 聚类分析:观察数据点的分布,可以发现是否存在某种聚类模式,对于数据的分组有一定帮助。

总体而言,散点图是一种简单而强大的工具,可用于初步探索和理解两个变量之间的关系。

QSplineSeries 是 Qt Charts 模块中用于绘制光滑曲线的类。它表示图表中的一条曲线,通过一系列的数据点来定义曲线的形状。

以下是关于 QSplineSeries 的一些方法以及说明:

方法 描述
QSplineSeries(QObject *parent = nullptr) 构造函数,创建一个 QSplineSeries 对象。
~QSplineSeries() 析构函数,释放 QSplineSeries 对象。
append(QPointF point) 向曲线中追加一个数据点。
append(QList<QPointF> points) 向曲线中追加一组数据点。
replace(int index, QPointF point) 替换指定索引处的数据点。
replace(QList<QPointF> points) 替换曲线中的所有数据点。
remove(int index) 移除指定索引处的数据点。
remove(int index, int count) 移除从指定索引开始的指定数量的数据点。
clear() 清空曲线中的所有数据点。
pointsVector() 返回曲线的数据点。
setUseOpenGL(bool enable) 设置是否使用 OpenGL 进行绘制。
useOpenGL() 返回是否使用 OpenGL 进行绘制。
setPen(const QPen &pen) 设置曲线的画笔,即曲线的颜色和样式。
pen() 返回曲线的画笔。
setBrush(const QBrush &brush) 设置曲线的画刷,即填充颜色。
brush() 返回曲线的画刷。
setPointLabelsVisible(bool visible) 设置是否显示数据点的标签。
isPointLabelsVisible() 返回数据点的标签是否可见。
setPointLabelsFormat(const QString &format) 设置数据点标签的显示格式,支持使用占位符。
pointLabelsFormat() 返回数据点标签的显示格式。
setPointLabelsColor(const QColor &color) 设置数据点标签的颜色。
pointLabelsColor() 返回数据点标签的颜色。
setPointLabelsFont(const QFont &font) 设置数据点标签的字体。
pointLabelsFont() 返回数据点标签的字体。
setPointsVisible(bool visible) 设置是否显示数据点。
arePointsVisible() 返回数据点是否可见。
setPointLabelsClipping(bool clipping) 设置是否裁剪超出绘图区域的数据点标签。
isPointLabelsClipping() 返回数据点标签是否裁剪超出绘图区域。
clicked(QPointF point) 鼠标点击曲线时发出的信号,参数为鼠标点击的数据点坐标。
hovered(QPointF point, bool state) 鼠标悬停在曲线上时发出的信号,参数为悬停状态以及悬停位置的数据点坐标。
pressed(QPointF point) 鼠标按下曲线时发出的信号,参数为鼠标按下的数据点坐标。
released(QPointF point) 鼠标释放曲线时发出的信号,参数为鼠标释放的数据点坐标。
doubleClicked(QPointF point) 鼠标双击曲线时发出的信号,参数为鼠标双击的数据点坐标。

QSplineSeries 主要用于绘制光滑曲线,通过添加一系列的数据点,可以在图表中呈现出相应的曲线形状。

QScatterSeries 是 Qt Charts 模块中用于绘制散点图的类。它派生自 QXYSeries 类,用于表示图表中的一组散点数据,通过一系列的坐标点来显示离散的数据分布。

以下是关于 QScatterSeries 的一些方法以及说明:

方法 说明
QScatterSeries(QObject *parent = nullptr) 构造函数,创建一个 QScatterSeries 对象。
~QScatterSeries() 析构函数,释放 QScatterSeries 对象。
append(QPointF point) 向散点图中追加一个数据点。
append(QList<QPointF> points) 向散点图中追加一组数据点。
replace(int index, QPointF point) 替换指定索引处的数据点。
replace(QList<QPointF> points) 替换散点图中的所有数据点。
remove(int index) 移除指定索引处的数据点。
remove(int index, int count) 移除从指定索引开始的指定数量的数据点。
clear() 清空散点图中的所有数据点。
pointsVector() 返回散点图的数据点。
setMarkerShape(QScatterSeries::MarkerShape shape) 设置散点的形状,可以是圆形、方形等。
markerShape() 返回散点的形状。
setMarkerSize(qreal size) 设置散点的大小。
markerSize() 返回散点的大小。
setPen(const QPen &pen) 设置散点图的画笔,即散点的边框颜色和样式。
pen() 返回散点图的画笔。
setBrush(const QBrush &brush) 设置散点图的画刷,即散点的填充颜色。
brush() 返回散点图的画刷。
setBorderColor(const QColor &color) 设置散点的边框颜色。
borderColor() 返回散点的边框颜色。
setBackgroundColor(const QColor &color) 设置散点的背景颜色。
backgroundColor() 返回散点的背景颜色。
setBorderColor(const QColor &color) 设置散点的边框颜色。
borderColor() 返回散点的边框颜色。
setBrush(const QBrush &brush) 设置散点的画刷,即填充颜色。
brush() 返回散点的画刷。
setPen(const QPen &pen) 设置散点的画笔,即边框颜色和样式。
pen() 返回散点的画笔。
setUseOpenGL(bool enable) 设置是否使用 OpenGL 进行绘制。
useOpenGL() 返回是否使用 OpenGL 进行绘制。
setMarkerShape(QScatterSeries::MarkerShape shape) 设置散点的形状,可以是圆形、方形等。
markerShape() 返回散点的形状。
setMarkerSize(qreal size) 设置散点的大小。
markerSize() 返回散点的大小。
setMarkerColor(const QColor &color) 设置散点的颜色。
markerColor() 返回散点的颜色。
clicked(QPointF point) 鼠标点击散点时发出的信号,参数为鼠标点击的数据点坐标。
hovered(QPointF point, bool state) 鼠标悬停在散点上时发出的信

绘制散点图实现代码如下所示;

// 散点图初始化
QChart *chart = new QChart();
chart->setAnimationOptions(QChart::SeriesAnimations);
ui->graphicsView->setChart(chart);
ui->graphicsView->setRenderHint(QPainter::Antialiasing);

// 清空绘图区
chart->removeAllSeries();
chart->removeAxis(chart->axisX());
chart->removeAxis(chart->axisY());

// 光滑曲线序列
QSplineSeries *seriesLine = new QSplineSeries();
seriesLine->setName("曲线");
QPen pen;
pen.setColor(Qt::blue);
pen.setWidth(2);
seriesLine->setColor(Qt::blue);
seriesLine->setPen(pen);

// 散点序列
QScatterSeries *series0 = new QScatterSeries();
series0->setName("散点");
series0->setMarkerShape(QScatterSeries::MarkerShapeCircle);
series0->setBorderColor(Qt::black);
series0->setBrush(QBrush(Qt::red));
series0->setMarkerSize(12);

// 随机数种子
qsrand(QTime::currentTime().second());

// 设置曲线随机数
for (int i=0;i<10;i++)
{
    int x=(qrand() % 20);    // 0到20之间的随机数
    int y=(qrand() % 20);
    series0->append(x,y);    // 散点序列
    seriesLine->append(x,y); // 光滑曲线序列
}

chart->addSeries(series0);
chart->addSeries(seriesLine);

// 增加Y坐标轴(可注释)
QValueAxis *axisY = new QValueAxis;
axisY->setRange(0, 20);
axisY->setTitleText("Y坐标");
axisY->setTickCount(11);
axisY->setLabelFormat("%.0f");
axisY->setGridLineVisible(true);
chart->setAxisY(axisY, series0);
chart->setAxisY(axisY, seriesLine);

// 增加X坐标轴(可注释)
QValueAxis *axisX = new QValueAxis;
axisX->setRange(0, 20);
axisX->setTitleText("X");
axisX->setTickCount(11);
axisX->setLabelFormat("%.0f");
axisX->setGridLineVisible(true);
chart->setAxisX(axisX, series0);
chart->setAxisX(axisX, seriesLine);

// 创建缺省的坐标轴(默认缺省值)
chart->createDefaultAxes();
chart->axisX()->setTitleText("X 轴");
chart->axisX()->setRange(-2,22);

chart->axisY()->setTitleText("Y 轴");
chart->axisY()->setRange(-2,22);

chart->legend()->setVisible(true);
chart->legend()->setAlignment(Qt::AlignRight);

// 绑定槽函数,用于点击图例显示与隐藏数据
foreach (QLegendMarker* marker, chart->legend()->markers())
{
    QObject::disconnect(marker, SIGNAL(clicked()), this, SLOT(on_chartBarLegendMarkerClicked()));
    QObject::connect(marker, SIGNAL(clicked()), this, SLOT(on_chartBarLegendMarkerClicked()));
}

运行上述代码则可实现输出随机散点图,其中右侧散点与曲线可以进行自定义隐藏与显示,如下图所示;

1379525-20231225214036220-983354487.png

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK