QCustomPlot绘图类详解(大白话)

本文假定你会使用Qt开发,但未接触过QCustomPlot绘图类或者是刚接触。

如何往Qt中引入QCustomPlot

  1. 首先,去官网下载最新版本的源码,注意是QCustomPlot.tar.gz这个文件,里面包含源码和示例。实际上,我们只需要qcustomplot.hqcustomplot.h这两个源文件。
    官网下载
  2. 将代码文件拷贝到本地工程,并引入。
    引入源文件
    QCustomPlot需要依赖printsupport模块,如果你是使用QT+VS开发,配置如下:
    Qt+Vs
    如果是Qt Create开发,在.pro文件中添加:QT += QWidget printsupport
  3. 在Qt中新建ui文件,拖拽一个QWidget控件,将其提升为QCustomPlot
    在这里插入图片描述

QCustomPlot常用函数

// 设置背景色
ui.plotWidget->setBackground(QBrush(QColor("#404040")));

// 设置X/Y轴的标签
ui.plotWidget->xAxis->setLabel(QStringLiteral("次数"));

// 设置X/Y轴标签字体
ui.plotWidget->xAxis->setLabelFont(plotFont);

// 设置X/Y轴标签颜色
ui.plotWidget->xAxis->setLabelColor(QColor(Qt::red));

// 设置x=0或y=0所在直线的画笔
ui.plotWidget->xAxis->grid()->setZeroLinePen(QPen(QColor(Qt::yellow)));

// 设置X/Y轴刻度范围
ui.plotWidget->xAxis->setRange(1, PT_CNT);

// 设置X/Y轴刻度数,也就是分为几段
ui.plotWidget->xAxis->ticker()->setTickCount(8);

// 设置X/Y轴刻度值文本的颜色
ui.plotWidget->xAxis->setTickLabelColor(QColor(Qt::green));

// 设置X/Y轴轴线的画笔
ui.plotWidget->xAxis->setBasePen(QPen(QColor(Qt::white), 2, Qt::SolidLine));

// 设置X/Y轴大刻度的画笔,被分段的位置
ui.plotWidget->xAxis->setTickPen(QPen(QColor("#ff00ff")));

// 设置X/Y轴小刻度的画笔
ui.plotWidget->xAxis->setSubTickPen(QPen(QColor("#00ffff")));

// 设置内部网格线的画笔
ui.plotWidget->xAxis->grid()->setPen(QPen(QColor(Qt::darkRed), 1, Qt::DotLine));

// 添加一个图层
ui.plotWidget->addGraph();

// 为对应图层添加数据
ui.plotWidget->graph(0)->addData(keys, values);

// 为图层设置画笔
ui.plotWidget->graph(0)->setPen(QColor(Qt::blue));

// 设置是/否抗锯齿
ui.plotWidget->graph(0)->setAntialiasedFill(true);

// 刷新绘图,更改数据后需手动刷新(缩放会自动刷新)
ui.plotWidget->replot();

// 支持拖拽和缩放
ui.plotWidget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);

绘制直方图

更改QCustomPlot相关属性,这里以颜色修改为主(稍有点乱哈),创建距离-测距次数的直方图。
在这里插入图片描述
相关代码如下:

void PlotTest::InitForm()
{
    ui.plotWidget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);

    ui.plotWidget->setBackground(QBrush(QColor("#404040")));
    ui.plotWidget->xAxis->setLabel(QStringLiteral("次数"));
    ui.plotWidget->yAxis->setLabel(QStringLiteral("距离(cm)"));

    QFont plotFont = font();
    plotFont.setPointSizeF(10.0);

	//设置轴标签字体和颜色
    ui.plotWidget->xAxis->setLabelFont(plotFont);
    ui.plotWidget->yAxis->setLabelFont(plotFont);
    ui.plotWidget->xAxis->setLabelColor(QColor(Qt::red));
    ui.plotWidget->yAxis->setLabelColor(QColor(Qt::red));

	//设置网格线的零线颜色
    ui.plotWidget->xAxis->grid()->setZeroLinePen(QPen(QColor(Qt::yellow)));
    ui.plotWidget->yAxis->grid()->setZeroLinePen(QPen(QColor(Qt::yellow)));
	
	//设置轴的范围和刻度数量
    ui.plotWidget->xAxis->setRange(1, PT_CNT);
    ui.plotWidget->yAxis->setRange(-10, 90);
    ui.plotWidget->xAxis->ticker()->setTickCount(8);
    ui.plotWidget->yAxis->ticker()->setTickCount(8);
    
	//设置刻度标签颜色和基线颜色及样式
    ui.plotWidget->xAxis->setTickLabelColor(QColor(Qt::green));
    ui.plotWidget->yAxis->setTickLabelColor(QColor(Qt::green));
    ui.plotWidget->xAxis->setBasePen(QPen(QColor(Qt::white), 2, Qt::SolidLine));
    ui.plotWidget->yAxis->setBasePen(QPen(QColor(Qt::white), 2, Qt::SolidLine));
    ui.plotWidget->xAxis->setTickPen(QPen(QColor("#ff00ff")));
    ui.plotWidget->yAxis->setTickPen(QPen(QColor("#ff00ff")));
    ui.plotWidget->xAxis->setSubTickPen(QPen(QColor("#00ffff")));
    ui.plotWidget->yAxis->setSubTickPen(QPen(QColor("#00ffff")));
    ui.plotWidget->xAxis->grid()->setPen(QPen(QColor(Qt::darkRed), 1, Qt::DotLine));
    ui.plotWidget->yAxis->grid()->setPen(QPen(QColor(Qt::darkGreen), 1, Qt::DotLine));

    QVector<double> keys, values;
    for (int i = 1; i <= PT_CNT; i++)
    {
        keys.push_back(i);
        values.push_back(rand() % 100 - 10);
    }
    ui.plotWidget->addGraph();
    ui.plotWidget->graph(0)->addData(keys, values);
    ui.plotWidget->graph(0)->setPen(QColor(Qt::blue));
    ui.plotWidget->graph(0)->setAntialiasedFill(true);
    ui.plotWidget->replot();
}

刷新直方图

刷新直方图比较简单,刷新指定图层的数据即可。有2种方式:

  • 更换数据
ui.plotWidget->graph(0)->data()->clear(); // 清楚图层对应的数据
ui.plotWidget->graph(0)->addData(keys, values); // 添加新的数据
  • 更换图层
ui.plotWidget->clearGraphs(); // 删除图层(单个或所有)
ui.plotWidget->addGraph(); // 新建图层
ui.plotWidget->graph(0)->addData(keys, values); // 添加新数据

注:两种方式会适用于不同的场景下。
请添加图片描述

绘制连续的直方图

连续直方图可以理解为:不断往图层里添加数据。需要注意的是,每次添加数据都需要更新刻度范围。代码如下:

void PlotTest::DrawContinueGraph()
{
    QVector<double> keys, values;

    for (int i = 1; i <= PT_CNT; i++)
    {
        keys.push_back(mRefreshCnt * PT_CNT + i);
        values.push_back(rand() % 100 + 1);
    }

    ui.plotWidget->graph(0)->addData(keys, values);
    ui.plotWidget->xAxis->setRange(1, PT_CNT * (mRefreshCnt + 1));
    ui.plotWidget->graph(0)->setAntialiasedFill(true);
    ui.plotWidget->replot();

    mRefreshCnt++;
}

请添加图片描述

完整代码

// PlotTest.h文件
#pragma once

#include <QtWidgets/QWidget>
#include "ui_PlotTest.h"

class PlotTest : public QWidget
{
    Q_OBJECT

public:
    PlotTest(QWidget *parent = nullptr);
    ~PlotTest();

public:
    void InitForm();            // 初始化控件
    void DrawStaticGraph();     // 绘制静态图
    void DrawDynamicGraph();    // 绘制动态图(单图刷新)
    void DrawContinueGraph();   // 绘制连续图(多图刷新)
    
public slots:
    void on_btnDynamicDraw_clicked();
    void on_btnContinueDraw_clicked();

private:
    Ui::PlotTestClass ui;
    int mRefreshCnt; // 连续刷新次数
};
// PlotTest.cpp文件
#include "PlotTest.h"
#include "CustomPlot\qcustomplot.h"

#define PT_CNT       200    // 点数
#define GRAPH_CNT    5      // 图数

PlotTest::PlotTest(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);

    InitForm();
    mRefreshCnt = 1;
}

PlotTest::~PlotTest()
{

}

void PlotTest::on_btnDynamicDraw_clicked()
{
    ui.btnDynamicDraw->setEnabled(false);
    ui.btnContinueDraw->setEnabled(false);
    mRefreshCnt = 1;

    for (int i = 0; i < 10; i++)
    {
        DrawDynamicGraph();
        Sleep(500);
    }

    ui.btnDynamicDraw->setEnabled(true);
    ui.btnContinueDraw->setEnabled(true);
}

void PlotTest::on_btnContinueDraw_clicked()
{
    ui.btnDynamicDraw->setEnabled(false);
    ui.btnContinueDraw->setEnabled(false);
    mRefreshCnt = 0;
    ui.plotWidget->graph(0)->data()->clear();
    ui.plotWidget->xAxis->setRange(1, PT_CNT);

    for (int i = 0; i < 10; i++)
    {
        DrawContinueGraph();
        Sleep(500);
    }

    ui.btnDynamicDraw->setEnabled(true);
    ui.btnContinueDraw->setEnabled(true);
}

void PlotTest::InitForm()
{
    ui.plotWidget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);

#if 0
    ui.plotWidget->setBackground(QBrush(QColor("#404040")));
    ui.plotWidget->xAxis->setLabel(QStringLiteral("次数"));
    ui.plotWidget->yAxis->setLabel(QStringLiteral("距离(cm)"));

    QFont plotFont = font();
    plotFont.setPointSizeF(10.0);

    ui.plotWidget->xAxis->setLabelFont(plotFont);
    ui.plotWidget->yAxis->setLabelFont(plotFont);
    ui.plotWidget->xAxis->setLabelColor(QColor(Qt::red));
    ui.plotWidget->yAxis->setLabelColor(QColor(Qt::red));
    ui.plotWidget->xAxis->grid()->setZeroLinePen(QPen(QColor(Qt::yellow)));
    ui.plotWidget->yAxis->grid()->setZeroLinePen(QPen(QColor(Qt::yellow)));
    ui.plotWidget->xAxis->setRange(1, PT_CNT);
    ui.plotWidget->yAxis->setRange(-10, 90);
    ui.plotWidget->xAxis->ticker()->setTickCount(8);
    ui.plotWidget->yAxis->ticker()->setTickCount(8);
    ui.plotWidget->xAxis->setTickLabelColor(QColor(Qt::green));
    ui.plotWidget->yAxis->setTickLabelColor(QColor(Qt::green));
    ui.plotWidget->xAxis->setBasePen(QPen(QColor(Qt::white), 2, Qt::SolidLine));
    ui.plotWidget->yAxis->setBasePen(QPen(QColor(Qt::white), 2, Qt::SolidLine));
    ui.plotWidget->xAxis->setTickPen(QPen(QColor("#ff00ff")));
    ui.plotWidget->yAxis->setTickPen(QPen(QColor("#ff00ff")));
    ui.plotWidget->xAxis->setSubTickPen(QPen(QColor("#00ffff")));
    ui.plotWidget->yAxis->setSubTickPen(QPen(QColor("#00ffff")));
    ui.plotWidget->xAxis->grid()->setPen(QPen(QColor(Qt::darkRed), 1, Qt::DotLine));
    ui.plotWidget->yAxis->grid()->setPen(QPen(QColor(Qt::darkGreen), 1, Qt::DotLine));

    QVector<double> keys, values;
    for (int i = 1; i <= PT_CNT; i++)
    {
        keys.push_back(i);
        values.push_back(rand() % 100 - 10);
    }
    ui.plotWidget->addGraph();
    ui.plotWidget->graph(0)->addData(keys, values);
    ui.plotWidget->graph(0)->setPen(QColor(Qt::blue));
    ui.plotWidget->graph(0)->setAntialiasedFill(true);
    ui.plotWidget->replot();
#else
    ui.plotWidget->xAxis->setLabel(QStringLiteral("次数"));
    ui.plotWidget->yAxis->setLabel(QStringLiteral("距离(cm)"));
    ui.plotWidget->xAxis->setRange(1, PT_CNT);
    ui.plotWidget->yAxis->setRange(1, 100);
    ui.plotWidget->xAxis->ticker()->setTickCount(8);
    ui.plotWidget->yAxis->ticker()->setTickCount(8);

    DrawStaticGraph();

#endif
}

void PlotTest::DrawStaticGraph()
{
    QVector<double> keys, values;
    for (int i = 1; i <= PT_CNT; i++)
    {
        keys.push_back(i);
        values.push_back(rand() % 100 + 1);
    }

    ui.plotWidget->addGraph();
    ui.plotWidget->graph(0)->addData(keys, values);
    ui.plotWidget->graph(0)->setPen(QColor(Qt::blue));
    ui.plotWidget->graph(0)->setAntialiasedFill(true);
    ui.plotWidget->replot();
}

void PlotTest::DrawDynamicGraph()
{
    ui.plotWidget->clearGraphs();
    QVector<double> keys, values;
    for (int i = 1; i <= PT_CNT; i++)
    {
        keys.push_back(i);
        values.push_back(rand() % 100 + 1);
    }

    ui.plotWidget->addGraph();
    ui.plotWidget->graph(0)->addData(keys, values);
    ui.plotWidget->xAxis->setRange(1, PT_CNT);
    ui.plotWidget->graph(0)->setAntialiasedFill(true);
    ui.plotWidget->replot();
}

void PlotTest::DrawContinueGraph()
{
    QVector<double> keys, values;

    for (int i = 1; i <= PT_CNT; i++)
    {
        keys.push_back(mRefreshCnt * PT_CNT + i);
        values.push_back(rand() % 100 + 1);
    }

    ui.plotWidget->graph(0)->addData(keys, values);
    ui.plotWidget->xAxis->setRange(1, PT_CNT * (mRefreshCnt + 1));
    ui.plotWidget->graph(0)->setAntialiasedFill(true);
    ui.plotWidget->replot();

    mRefreshCnt++;
}
  • 11
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
XGBoost(eXtreme Gradient Boosting)是一种非常流行的机器学习算法,它是一种梯度提升树模型。它的设计目标是提高其前身GBDT(Gradient Boosting Decision Tree)算法的性能和鲁棒性。 XGBoost使用的是一种特殊的决策树模型,称为CART(Classification and Regression Trees)。与传统的决策树不同,CART决策树在每个节点上进行分裂时,会使用一种称为泰勒展开的方法,来近似地找到最优分裂点。通过这种方法,XGBoost能够更精确地构建决策树模型,并提高预测的准确性。 XGBoost还通过引入正则化技术,如L1和L2正则化,来避免模型过拟合。正则化可以限制模型的复杂性,提高模型的泛化能力,并使得模型对噪音数据不敏感。 在训练过程中,XGBoost使用梯度提升算法,该算法通过迭代地训练多个决策树,并使用梯度下降法来优化模型的损失函数。在每一轮迭代中,XGBoost会根据之前模型的预测结果和真实标签之间的误差,调整每个样本的权重,并生成一个新的决策树。通过这种迭代优化的方式,XGBoost能够逐步提升模型的准确性。 此外,XGBoost还具备优化性能的功能。它使用一种称为并行化的技术,通过同时在多个处理器上训练多个决策树,来加快训练速度。另外,XGBoost还支持特征重要性评估,可以通过计算每个特征对模型的贡献度来帮助我们理解数据的特征重要性。 总之,XGBoost是一种非常强大的机器学习算法,它通过使用特殊的决策树模型、正则化技术、梯度提升算法和优化性能等方法,提高了模型的预测准确性和鲁棒性。它在很多数据竞赛和实际应用中都取得了出色的结果。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值