简介
QCustomPlot是一个基于Qt C++的图形库,用于绘制和数据可视化 - 制作漂亮的2D图 - 曲线图、趋势图、坐标图、柱状图等,并为实时可视化应用程序提供高性能服务。它没有进一步的依赖关系,并有着良好的文档记录。
QCustomPlot可以导出为各种格式,比如:PDF文件和位图(如:PNG、JPG、BMP)。
可在自己的项目中直接使用两个源文件(qcustomplot.h与qcustomplot.cpp)或预先编译成库。
QCustomPlot是一个小型的qt画图标类,效果可以,易用,只需要在项目中加入头文件qcustomplot.h和qcustomplot.cpp文件,然后使一个widget提升为QCustomPlot类,即可使用。
QCustomPlot 可以导出为各种格式,如矢量化 PDF 文件和光栅化图像,如 PNG、JPG 和 BMP。QCustomPlot 是在应用程序内显示实时数据以及为其他媒体生成高质量绘图的解决方案。
QCustomPlot、QtCharts,Qwt
QCustomPlot是目前使用最为广泛的Qt图表类;
Qt的QWidget代码方向图表类只有QtCharts,Qwt,QCustomPlot
绘制实时数据波形图,我们一般使用到的库有qwt、qcustomplot以及官方的QtCharts模块。
- qwt这个库安装比较麻烦,界面老旧,不过功能比较全。
- qcustomplot很精简小巧,就一个.h .cpp文件,大量数据绘制时,性能突出。
- QtCharts这个模块以前是收费使用的,现在已经免费了,官方出品。
美观:Qcustomplot≈Qchart > Qwt
性能:Qcustomplot >Qchart> Qwt
绘制1000个数据点时,qcustomplot平均耗时 13.6毫秒,Qwt平均耗时40毫秒,QChart平均耗时12.5毫秒;
绘制10000个数据点时,qcustomplot平均耗时 21.6毫秒,Qwt平均耗时78毫秒,QChart平均耗时13.5毫秒;
绘制100000个数据点时,qcustomplot平均耗时22.5毫秒,Qwt平均耗时524毫秒,QChart平均耗时20.7毫秒;
绘制500000个数据点时,qcustomplot平均耗时43.3毫秒,QChart平均耗时194.25毫秒。
从性能角度
QCustomPlot是一个比较完善的框架,其框架和缓存化的处理使其处理性能大幅度提升(设置笔宽为1,可撑起几百万点),而QtCharts只是一个半成品,不论是否有bug,QtCharts在两千个点以内是可以使用的,超过两千个点就存在刷新卡顿的问题(很大可能)。
从定制化角度
QCustomPlot修改源码因为其是一步一步继承过来的,修改起来是比较麻烦的,还需要反复调试以防止修改了代码出现了其他问题,入添加一个少则半天一天,多则几天,所以如果需要定制修改QCustomoPlot源码的需求,是需要进一步仔细评估是否值得这么做。
最新版本:2.1.0,于2021年3月29日发布:
它建立了高达Qt 6.0的兼容性(保持兼容性一直到4.6),并包括许多功能添加,错误修复和较小的改进,增加了极坐标波形绘制控件等,需要C++11支持。具体见详细变更列表日志。
官方提供的demo提供了4个例程,这里初入手的特别注意范例plot-examples,其包含了多种效果,修改代码的数字实现不同的demo,如果修改 setupDemo(1);如下图:是Realtime Data Demo。这个就是绘制实时数据的demo。
QCustomPlot官网下载
官网下载地址:Qt Plotting Widget QCustomPlot - Download
不用纠结具体哪个版本,根据提示选择自己Qt版本对应的就可以。推荐下载完整包,包括源码、文档和例程。
进入QCustomPlot下载页,下载最新的完整包(包含:源码、文档、示例)!
将下载好的安装包进行解压缩,里面包含文档、示例、更改日志、GPL授权、以及最重要的两个文件qcustomplot.h与qcustomplot.cp
QCustomPlot 调用一
1、下载的QCustomPlot压缩包解压后,把qcustomplot.h和qcustomplot.cpp文件拷贝到工程文件夹,在左侧工程名称上右键点击弹出对话框,选择“添加现有文件”,选中qcustomplot.h和qcustomplot.cpp文件,添加到工程目录,如下图:
2、在工程的.pro文件中可以看到添加记录,同时在Qt5以上版本中,需要添加 printsupport。如下图所示:
3、接下来我们在界面中拖拽一个Widget控件,选中并右键选中“提升为”,如下图所示:
4、在弹出的对话框中输入 QCustomPlot ,自动匹配 qcustomplot.h,再点击“添加”,选中后点击“提升”,则原来的Widget控件已成为一个带坐标的 CustomPlot 控件,如下图:
如果是代码方式添加就不需要对控件提升的这布操作,直接使用QCustomPlot 类声明对象即可。如
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QCustomPlot *pCustomPlot = new QCustomPlot(this);
pCustomPlot->resize(300, 300);
}
5、添加printsupport
如果Qt版本在5.0以上,需要在.pro文件中的QT变量加上printsupport:
QT += widgets printsupport
6、添加帮助文档
在下载的documentation文件夹下有个qcustomplot.qch文件,将它拷贝Qt的安装文档目录下(一般为qt5.9\Docs\Qt-5.9,会根据你的Qt版本号而做相应变动),然后在QtCreator ——>工具——>选项——>帮助——>文档——>添加,选择qcustomplot.qch文件,确定,以后按F1就能跳转到QCustomPlot的帮助
至此,我们已经完成了对QCustomPlot的调用。接下来就可以在QCustomPlot控件进行绘图操作了~
QCustomPlot画曲线
1、添加QCustomPlot控件
我们先把拖拽并提升为QCustomPlot的widget控件改名为customplot,以示区分。
2、添加曲线
我们添加的QCustomPlot控件,是一个画布,我们可以在同一个画布上画很多曲线。那么首先我们需要添加曲线,函数是
ui->customplot->addGraph();
3、设置曲线的具体数据
设置曲线的具体数据的函数是
void QCPGraph::setData(const QVector<double> &keys,
const QVector<double> &values,
bool alreadySorted)
这里的keys是x坐标,values是y坐标,均为QVector类型。因此我们需要先用QVector赋值一对点集,作为x和y坐标。代码如下:
// generate some data: 一个二次函数 y = x^2
QVector<double> x(101), y(101); // initialize with entries 0..100
for (int i=0; i<101; ++i)
{
x[i] = i-50; // x goes from -50 to 50
y[i] = x[i]*x[i]; // let's plot a quadratic function
}
再把数据作为x和y坐标集进行绘图,代码如下:
ui->customplot->graph(0)->setData(x,y);
把以上代码组合在一起,先定义坐标集,完整代码如下:
// generate some data: 一个二次函数 y = x^2
QVector<double> x(101), y(101); // initialize with entries 0..100
for (int i=0; i<101; ++i)
{
x[i] = i; // x goes from 1 to 100
y[i] = x[i]*x[i]; // let's plot a quadratic function
}
ui->customplot->addGraph();
ui->customplot->graph(0)->setData(x,y);
ui->customplot->replot(); //按钮执行时需要添加刷新函数
把完成代码放在MainWindow初始化函数或某个控件点击函数,执行动作后可显示如下曲线:
当然,这个曲线的很单调,还是个折线图,显示也不完全,还需要做很多修饰。按照感觉舒适度,有几个点是要做的,主要有:
- 坐标范围要显示全,比如代码设置的x轴(-50,50)范围
- 坐标轴的名称,至少有个x和y轴名称,最好加个单位
- 不要显示折线,当然也和x轴没显示全有关
- 有个标题
4、 设置曲线元素和修饰
我们先按照上面列举的舒适度顺序来优化先曲线
4.1 设置曲线显示范围
我们可以手动设置坐标轴范围,也可以自动设置。
根据x轴范围(-50,50),则y轴范围是(1,2500),我们先手动设置下:
ui->customplot->xAxis->setRange(1,100);
ui->customplot->yAxis->setRange(1,2500);
自动设置,即自适应坐标范围代码如下:
ui->customplot->rescaleAxes(true);
两种方式得到相同的曲线,如下图:
4.2 设置坐标轴名称
我们给坐标轴加个名称和单位,代码如下:
ui->customplot->xAxis->setLabel("电压(V)");
ui->customplot->yAxis->setLabel("电流(A)");
4.3 设置曲线标题
我们再给曲线加个标题,代码如下:
QCPTextElement *plotTitle = new QCPTextElement(ui->customplot);
plotTitle->setText("伏安曲线");
plotTitle->setFont(QFont("宋体", 16, QFont::Bold));
ui->customplot->plotLayout()->insertRow(0);
ui->customplot->plotLayout()->addElement(0, 0, plotTitle);
这里涉及到QCustomPlot的布局系统,用于管理标题、图例、网格、坐标轴矩形等元素,可参见其他博主译文:QCustomPlot之布局系统
在设置坐标轴名称和添加标题后,曲线显示如下:
到这里,一个基本完整的曲线就完成了,我们再把代码总结下:
// generate some data: 一个二次函数 y = x^2
QVector<double> x(101), y(101); // initialize with entries 0..100
for (int i=0; i<101; ++i)
{
x[i] = i-50; // x goes from -50 to 50
y[i] = x[i]*x[i]; // let's plot a quadratic function
}
ui->customplot->addGraph();
ui->customplot->graph(0)->setData(x,y);
// ui->customplot->xAxis->setRange(-50,50);
// ui->customplot->yAxis->setRange(1,2500);
ui->customplot->rescaleAxes(true);
ui->customplot->xAxis->setLabel("电压(V)");
ui->customplot->yAxis->setLabel("电流(A)");
QCPTextElement *plotTitle = new QCPTextElement(ui->customplot);
plotTitle->setText("伏安曲线");
plotTitle->setFont(QFont("宋体", 16, QFont::Bold));
ui->customplot->plotLayout()->insertRow(0);
ui->customplot->plotLayout()->addElement(0, 0, plotTitle);
QCustomPlot 调用二
方法二:直接定义QCustomPlot 控件指针,不提升类
QCustomPlot *pCustomPlot = new QCustomPlot(this);
pCustomPlot->resize(300, 300);
效果如图:
详细代码如图:
#include "qcustomplot.h"
MainWindow::MainWindow(QWidget *parent)
: CustomWindow(parent)
{
...
QCustomPlot *pCustomPlot = new QCustomPlot(this);
pCustomPlot->resize(300, 300);
// 可变数组存放绘图的坐标的数据,分别存放x和y坐标的数据,101为数据长度
QVector<double> x(101), y(101);
// 添加数据,这里演示y = x^3,为了正负对称,x从-10到+10
for (int i = 0; i < 101; ++i)
{
x[i] = i/5 - 10;
y[i] = qPow(x[i], 3); // x的y次方;
}
// 向绘图区域QCustomPlot添加一条曲线
QCPGraph *pGraph = pCustomPlot->addGraph();
// 添加数据
pCustomPlot->graph(0)->setData(x, y);
// 设置坐标轴名称
pCustomPlot->xAxis->setLabel("x");
pCustomPlot->yAxis->setLabel("y");
// 设置背景色
pCustomPlot->setBackground(QColor(50, 50, 50));
pGraph->setPen(QPen(QColor(32, 178, 170)));
// 设置x/y轴文本色、轴线色、字体等
pCustomPlot->xAxis->setTickLabelColor(Qt::white);
pCustomPlot->xAxis->setLabelColor(QColor(0, 160, 230));
pCustomPlot->xAxis->setBasePen(QPen(QColor(32, 178, 170)));
pCustomPlot->xAxis->setTickPen(QPen(QColor(128, 0, 255)));
pCustomPlot->xAxis->setSubTickPen(QColor(255, 165, 0));
QFont xFont = pCustomPlot->xAxis->labelFont();
xFont.setPixelSize(20);
pCustomPlot->xAxis->setLabelFont(xFont);
pCustomPlot->yAxis->setTickLabelColor(Qt::white);
pCustomPlot->yAxis->setLabelColor(QColor(0, 160, 230));
pCustomPlot->yAxis->setBasePen(QPen(QColor(32, 178, 170)));
pCustomPlot->yAxis->setTickPen(QPen(QColor(128, 0, 255)));
pCustomPlot->yAxis->setSubTickPen(QColor(255, 165, 0));
QFont yFont = pCustomPlot->yAxis->labelFont();
yFont.setPixelSize(20);
pCustomPlot->yAxis->setLabelFont(yFont);
// 设置坐标轴显示范围,否则只能看到默认范围
pCustomPlot->xAxis->setRange(-11, 11);
pCustomPlot->yAxis->setRange(-1100, 1100);
...
}
曲线的元素、属性和操作总结
在构建曲线图之前,我们先理一理曲线包括哪些元素和功能,然后再看如何用代码实现。打开Excel表,我们画一个曲线,如下图所示:
曲线元素
对于曲线的组成元素,可以做个简单总结。曲线元素主要包括:
1)曲线标题
2)坐标轴标题
3)坐标轴刻度
4)坐标点集合,即(x,y),构成曲线
5)图例
6)网格
曲线属性
对于曲线的元素,我们又可以赋予一定的属性,主要包括:
1)文字颜色和大小
2)曲线颜色和粗细
曲线操作
我们除了观看曲线,还需要对曲线做一些常规操作,主要包括:
1)坐标轴范围设置,可以用代码实现自适应坐标范围功能
2)曲线放大与缩小,如正向(左上角画到右下角)画矩形进行放大,反向(右下角画到左上角)画矩形恢复满刻度
3)修改曲线颜色和粗细
4)显示或隐藏单条或多条曲线
5)显示或隐藏网格,设置网格风格
曲线算法
曲线本身常有自己的特征,为了找出这些特征或进行优化处理,会涉及到一些算法操作。常用的算法可以包括:
1)寻峰
2)去噪
3)微分/求导
4)消锯齿
5)归一化
QCustomPlot框架梳理
前文我们总结了曲线的基本元素、属性和操作,接下来就使用QCustomPlot去实现他们。学习一个类之前,我们也根据对表格的认知过程,再梳理一下要学习哪些内容。
1、如何获取QCustomPlot,如何调用,显示一条简单的曲线。
1)下载、安装和调用
2)最基本的曲线显示
2、如何设置QCustomPlot的元素和属性。
1)坐标轴、网格
2)文字大小和颜色
3)曲线粗细
3、如何对QCustomPlot曲线进行操作。
1)元素的显示和隐藏
2)放大、缩小和平移
3)自适应坐标范围
4、如何对曲线进行算法处理。
1)平滑、拟合、插值、消除锯齿
2)微分、寻峰
3)归一化、误差分析
注:
本节和前文表曲线总结有些重复,之所以列出来,就是为了再次明确我们要用QCustomPlot干什么,梳理曲线认知。
许多教程上来就直接讲解QCustomPlot,把官方例程贴出来一顿解说,这样很容易忽略掉我们自身对曲线的认知,把原本服务于我们表达和操作曲线的QCustomPlot,硬生生的变成了我们要去学习和适应它了。学习过程中,我们必须把握好一条主线,就是我们对曲线本身有很好的认知,只需要研究QCustomPlot如何帮我们实现。