QCustomPlot曲线绘制和管理(第一章)
本教程共分三章,按照认知过程,以简单直白的语言详解曲线的绘制和管理。
1)第一章(本章)从曲线的构成、属性和操作入手,先让读者对曲线有个整体的直观认识,接着介绍QCustomPlot的下载、调用,再逐步添加元素,最后呈现一个简单且基本完整的曲线,并给出完整的代码。
2)第二章详解图例、网格、坐标等元素和相关属性设置。
3)第三章讲解对曲线的放大、缩小、平移、修改元素属性等操作。
一、曲线的元素、属性和操作总结
在构建曲线图之前,我们先理一理曲线包括哪些元素和功能,然后再看如何用代码实现。打开Excel表,我们画一个曲线,如下图所示:
1.1 曲线元素
对于曲线的组成元素,可以做个简单总结。曲线元素主要包括:
1)曲线标题
2)坐标轴标题
3)坐标轴刻度
4)坐标点集合,即(x,y),构成曲线
5)图例
6)网格
1.2 曲线属性
对于曲线的元素,我们又可以赋予一定的属性,主要包括:
1)文字颜色和大小
2)曲线颜色和粗细
1.3 曲线操作
我们除了观看曲线,还需要对曲线做一些常规操作,主要包括:
1)坐标轴范围设置,可以用代码实现自适应坐标范围功能
2)曲线放大与缩小,如正向(左上角画到右下角)画矩形进行放大,反向(右下角画到左上角)画矩形恢复满刻度
3)修改曲线颜色和粗细
4)显示或隐藏单条或多条曲线
5)显示或隐藏网格,设置网格风格
1.4 曲线算法
曲线本身常有自己的特征,为了找出这些特征或进行优化处理,会涉及到一些算法操作。常用的算法可以包括:
1)寻峰
2)去噪
3)微分/求导
4)消锯齿
5)归一化
二、QCustomPlot框架梳理
前文我们总结了曲线的基本元素、属性和操作,接下来就使用QCustomPlot去实现他们。学习一个类之前,我们也根据对表格的认知过程,再梳理一下要学习哪些内容。
如何获取QCustomPlot,如何调用,显示一条简单的曲线。
1)下载、安装和调用
2)最基本的曲线显示
如何设置QCustomPlot的元素和属性。
1)坐标轴、网格
2)文字大小和颜色
3)曲线粗细
如何对QCustomPlot曲线进行操作。
1)元素的显示和隐藏
2)放大、缩小和平移
3)自适应坐标范围
如何对曲线进行算法处理。
1)平滑、拟合、插值、消除锯齿
2)微分、寻峰
3)归一化、误差分析
本节和前文表曲线总结有些重复,之所以列出来,就是为了再次明确我们要用QCustomPlot干什么,梳理曲线认知。
许多教程上来就直接讲解QCustomPlot,把官方例程贴出来一顿解说,这样很容易忽略掉我们自身对曲线的认知,把原本服务于我们表达和操作曲线的QCustomPlot,硬生生的变成了我们要去学习和适应它了。学习过程中,我们必须把握好一条主线,就是我们对曲线本身有很好的认知,只需要研究QCustomPlot如何帮我们实现。
三、QCustomPlot详解
3.1 QCustomPlot下载和调用
3.1.1 QCustomPlot官网下载
官网下载地址:https://www.qcustomplot.com/index.php/download
不用纠结具体哪个版本,根据提示选择自己Qt版本对应的就可以。推荐下载完整包,包括源码、文档和例程。
接下来我们按照官网引导教程来调出一个带坐标的QCustomplot界面,如下图
3.1.2 QCustomPlot调用
本节按照官网引导教程说明如何调用QCustomPlot。
英文好的朋友可以直接到官网阅读:https://www.qcustomplot.com/index.php/tutorials/settingup
- 下载的QCustomPlot压缩包解压后,把qcustomplot.h和qcustomplot.cpp文件拷贝到工程文件夹,在左侧工程名称上右键点击弹出对话框,选择“添加现有文件”,选中qcustomplot.h和qcustomplot.cpp文件,添加到工程目录,如下图:
- 在工程的.pro文件中可以看到添加记录,同时在Qt5以上版本中,需要添加 printsupport。如下图所示:
- 接下来我们在界面中拖拽一个Widget控件,选中并右键选中“提升为”,如下图所示:
- 在弹出的对话框中输入 QCustomPlot ,自动匹配 qcustomplot.h,再点击“添加”,选中后点击“提升”,则原来的Widget控件已成为一个带坐标的 CustomPlot 控件,如下图:
至此,我们已经完成了对QCustomPlot的调用。接下来就可以在QCustomPlot控件进行绘图操作了~
3.2 QCustomPlot画曲线
英文好的朋友可以参照官网画曲线教程:https://www.qcustomplot.com/index.php/tutorials/basicplotting
我们先把拖拽并提升为QCustomPlot的widget控件改名为customplot,以示区分。
我们添加的QCustomPlot控件,是一个画布,我们可以在同一个画布上画很多曲线。那么首先我们需要添加曲线,函数是
customPlot->addGraph();
设置曲线的具体数据的函数是
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轴没显示全有关
- 有个标题
3.3 设置曲线元素和修饰
我们先按照上面列举的舒适度顺序来优化先曲线
3.3.1 设置曲线显示范围
我们可以手动设置坐标轴范围,也可以自动设置。
根据x轴范围(-50,50),则y轴范围是(1,2500),我们先手动设置下:
ui->customplot->xAxis->setRange(1,100);
ui->customplot->yAxis->setRange(1,2500);
自动设置,即自适应坐标范围代码如下:
ui->customplot->rescaleAxes(true);
两种方式得到相同的曲线,如下图:
3.3.2 设置坐标轴名称
我们给坐标轴加个名称和单位,代码如下:
ui->customplot->xAxis->setLabel("电压(V)");
ui->customplot->yAxis->setLabel("电流(A)");
3.3.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);