全球滚动:【QCustomPlot】绘制 x-y 曲线图
使用 QCustomPlot 绘图库辅助开发时整理的学习笔记。同系列文章目录可见 《绘图库 QCustomPlot 学习笔记》目录。本篇介绍如何使用 QCustomPlot 绘制 x-y 曲线图,需要 x 轴数据与 y 轴数据都已知,示例中使用的 QCustomPlot 版本为 Version 2.1.1
,QT 版本为 5.9.2
。
通过包含源码的方式来使用 QCustomPlot 绘图库,方法详见本人同系列文章 使用方法(源码方式)。此外,库官网有提供绘图的示例代码,详见 QCustomPlot - Introduction,下载压缩包 QCustomPlot.tar.gz 中也有示例的工程代码,详见同系列文章 下载。下面示例中所用的工程文件(demoQCP.pro
)内容为:
(资料图片)
QT += core guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupportgreaterThan(QT_MAJOR_VERSION, 4): CONFIG += c++11lessThan(QT_MAJOR_VERSION, 5): QMAKE_CXXFLAGS += -std=c++11TARGET = demoQCPTEMPLATE = appSOURCES += main.cpp\ qcustomplot.cppHEADERS += qcustomplot.h
实际使用 QCustomPlot 进行绘图时,通常是将 UI 界面中的某个 QWidget
控件提升为 QCustomPlot
,然后以指针的方式调用 QCustomPlot
的类方法绘制图像。这一方式用在示例中有点繁琐(需要 .ui
文件),为了突出示例重点,减少文件依赖,示例代码直接在 main.cpp
中声明了一个 QCustomPlot
对象,示例工程所需的文件如下,只需四个文件,demoQCP.pro
的文件内容已在上面给出,main.cpp
的文件内容会在后面给出,qcustomplot.h
与 qcustomplot.cpp
两个文件下载自官网。
main.cpp
文件的框架如下,demoPlot()
里面用来写绘图的示例代码。
#include #include #include "qcustomplot.h"void demoPlot(QCustomPlot *customPlot){ // 绘图示例代码}int main(int argc, char *argv[]){ QApplication a(argc, argv); QMainWindow window; // 将QCustomPlot窗口作为QMainWindow中心窗口 QCustomPlot customPlot; window.setCentralWidget(&customPlot); // 绘图 demoPlot(&customPlot); // 显示 window.setWindowTitle(QStringLiteral("x-y 曲线图示例 @木三百川")); window.setGeometry(100, 100, 800, 600); window.show(); return a.exec();}
关于绘图颜色、线型、字体、网格线等外观上的美化,会在本人同系列文章 《绘图库 QCustomPlot 学习笔记》目录 中再做介绍,想学习的不妨关注一下。本文章只介绍绘制 x-y 曲线图的基础方法。
2. 常用 API 介绍绘制 x-y 曲线图所使用的类为 QCPGraph
,它提供的类方法可在 Documentation - QCPGraph 中找到。常用的接口有以下几个:
// 重置/添加绘图数据的接口void setData(const QVector &keys, const QVector &values, bool alreadySorted=false)void addData(const QVector &keys, const QVector &values, bool alreadySorted=false)void addData(double key, double value) // 设置线型void setLineStyle(LineStyle ls) // 设置点型void setScatterStyle(const QCPScatterStyle &style)
3. 绘制一条 x-y 曲线demoPlot()
函数如下:
void demoPlot(QCustomPlot *customPlot){ // 显示上方横轴(xAxis2)与右方纵轴(yAxis2),并与xAxis/yAxis保持同步 customPlot->axisRect()->setupFullAxesBox(true); // 生成x-y数据, y=x^2, 定义域[-1,1] QVector x(101), y(101); for (int i = 0; i < 101; ++i) { x[i] = i/50.0 - 1; y[i] = x[i]*x[i]; } // 新建QCPGraph对象,并设置绘图数据 customPlot->addGraph(); customPlot->graph(0)->setData(x, y); // 设置标题 customPlot->plotLayout()->insertRow(0); customPlot->plotLayout()->addElement(0, 0, new QCPTextElement(customPlot, "Test-Title", QFont("sans", 17, QFont::Bold))); // 设置坐标轴标签 customPlot->xAxis->setLabel("x"); customPlot->yAxis->setLabel("y"); // 设置坐标轴范围 customPlot->xAxis->setRange(-1, 1); customPlot->yAxis->setRange(0, 1); // 刷新显示 customPlot->replot();}
绘制效果:
4. 绘制多条 x-y 曲线demoPlot()
函数如下:
void demoPlot(QCustomPlot *customPlot){ // 显示上方横轴(xAxis2)与右方纵轴(yAxis2),并与xAxis/yAxis保持同步 customPlot->axisRect()->setupFullAxesBox(true); // 生成x-y数据,y1=x^2,y2=x^3,定义域[-1,1] QVector x(101), y1(101), y2(101); for (int i = 0; i < 101; ++i) { x[i] = i/50.0 - 1; y1[i] = x[i]*x[i]; y2[i] = x[i]*x[i]*x[i]; } // 新建QCPGraph对象,并设置绘图数据x-y1 customPlot->addGraph(); customPlot->graph(0)->setPen(QPen(Qt::blue)); customPlot->graph(0)->setData(x, y1); customPlot->graph(0)->setName(QStringLiteral("二次曲线图例")); // 新建QCPGraph对象,并设置绘图数据x-y2 customPlot->addGraph(); customPlot->graph(1)->setPen(QPen(Qt::red)); customPlot->graph(1)->setData(x, y2); customPlot->graph(1)->setName(QStringLiteral("三次曲线图例")); // 显示图例 customPlot->legend->setVisible(true); // 设置标题 customPlot->plotLayout()->insertRow(0); customPlot->plotLayout()->addElement(0, 0, new QCPTextElement(customPlot, "Test-Title", QFont("sans", 17, QFont::Bold))); // 设置坐标轴标签 customPlot->xAxis->setLabel("x"); customPlot->yAxis->setLabel("y"); // 设置坐标轴范围 customPlot->xAxis->setRange(-1, 1); customPlot->yAxis->setRange(-1, 1); // 刷新显示 customPlot->replot();}
绘制效果:
5. 绘制往回走的 x-y 曲线举个例子,若需要绘制 \(x=(y+0.8)\times y\times (y-0.8),y\in [-1,1]\) 曲线,有三种方法:
方法一:新建QCPGraph
对象时,指定 yAxis
为 keyAxis
,指定 xAxis
为 valueAxis
,即互换一下坐标轴的角色,这是最靠谱也最常用的方法。方法二:仍以 xAxis
为 keyAxis
、yAxis
为 valueAxis
(默认情况),但在调用 setData()
时,需传入第三个参数 true
。这是一种偷懒的做法,并且绘图的横轴数据(keyAxis)需满足一定的条件:keyData
必须先递增再减小、且减小时不得离 keyData[0]
太近,否则绘图会出错。方法三:导出绘图数据的内存地址,直接将数据写入内存中,这种做法常被用来提升 QCustomPlot 性能,缩短数据更新时间,但用此来绘制往回走的 x-y 曲线时,绘图的横轴数据也需要满足上面的条件,否则绘图会出错。当曲线形成的环路很复杂时,一般采用绘制参数曲线的方法来表现,详见 Documentation - QCPCurve 或本人同系列文章。
5.1 靠谱方法:互换 x-y 轴demoPlot()
函数如下:
void demoPlot(QCustomPlot *customPlot){ // 显示上方横轴(xAxis2)与右方纵轴(yAxis2),并与xAxis/yAxis保持同步 customPlot->axisRect()->setupFullAxesBox(true); // 生成y-x数据, x=(y+0.8)*y*(y-0.8), 定义域[-1,1] QVector x(101), y(101); for (int i = 0; i < 101; ++i) { y[i] = i/50.0 - 1; x[i] = (y[i]+0.8)*y[i]*(y[i]-0.8); } // 新建QCPGraph对象(互换xAxis/yAxis),并设置绘图数据 customPlot->addGraph(customPlot->yAxis, customPlot->xAxis); customPlot->graph(0)->setData(y, x); // 设置标题 customPlot->plotLayout()->insertRow(0); customPlot->plotLayout()->addElement(0, 0, new QCPTextElement(customPlot, "Test-Title", QFont("sans", 17, QFont::Bold))); // 设置坐标轴标签 customPlot->xAxis->setLabel("x"); customPlot->yAxis->setLabel("y"); // 设置坐标轴范围 customPlot->xAxis->setRange(-0.5, 0.5); customPlot->yAxis->setRange(-1, 1); // 刷新显示 customPlot->replot();}
绘制效果:
5.2 偷懒方法:设置 alreadySorted = truedemoPlot()
函数如下:
void demoPlot(QCustomPlot *customPlot){ // 显示上方横轴(xAxis2)与右方纵轴(yAxis2),并与xAxis/yAxis保持同步 customPlot->axisRect()->setupFullAxesBox(true); // 生成y-x数据, x=(y+0.8)*y*(y-0.8), 定义域[-1,1] QVector x(101), y(101); for (int i = 0; i < 101; ++i) { y[i] = i/50.0 - 1; x[i] = (y[i]+0.8)*y[i]*(y[i]-0.8); } // 新建QCPGraph对象,并设置绘图数据以及 alreadySorted = true customPlot->addGraph(); customPlot->graph(0)->setData(x, y, true); // 设置标题 customPlot->plotLayout()->insertRow(0); customPlot->plotLayout()->addElement(0, 0, new QCPTextElement(customPlot, "Test-Title", QFont("sans", 17, QFont::Bold))); // 设置坐标轴标签 customPlot->xAxis->setLabel("x"); customPlot->yAxis->setLabel("y"); // 设置坐标轴范围 customPlot->xAxis->setRange(-0.5, 0.5); customPlot->yAxis->setRange(-1, 1); // 刷新显示 customPlot->replot();}
绘制效果:
注意这张图中,keyData
(横轴)满足先递增再减小、且减小时的最小值(约为 -0.197
)大于 keyData[0]
(约为 -0.360
),所以绘制没有出错。有兴趣的可以尝试一下,当横轴数据减小且比较接近 keyData[0]
时,绘制的效果。
关于如何导出一维绘图数据的内存地址,详见本人另一篇文章 【QCustomPlot】性能提升之修改源码(版本 V2.x.x)。demoPlot()
函数如下:
void demoPlot(QCustomPlot *customPlot){ // 显示上方横轴(xAxis2)与右方纵轴(yAxis2),并与xAxis/yAxis保持同步 customPlot->axisRect()->setupFullAxesBox(true); // 新建QCPGraph对象,获得绘图数据的内存地址,并设置绘图数据 customPlot->addGraph(); QVector *mData = customPlot->graph(0)->data()->coreData(); mData->reserve(101); mData->resize(101); for (int i = 0; i < 101; ++i) { double y = i/50.0 - 1; (*mData)[i].key = (y+0.8)*y*(y-0.8); (*mData)[i].value = y; } // 设置标题 customPlot->plotLayout()->insertRow(0); customPlot->plotLayout()->addElement(0, 0, new QCPTextElement(customPlot, "Test-Title", QFont("sans", 17, QFont::Bold))); // 设置坐标轴标签 customPlot->xAxis->setLabel("x"); customPlot->yAxis->setLabel("y"); // 设置坐标轴范围 customPlot->xAxis->setRange(-0.5, 0.5); customPlot->yAxis->setRange(-1, 1); // 刷新显示 customPlot->replot();}
绘制效果:
6. 绘制间隙中断的 x-y 曲线当 keyAxis
数据中存在 NaN
时,绘制曲线会出现间隙中断的效果,demoPlot()
函数如下:
void demoPlot(QCustomPlot *customPlot){ // 显示上方横轴(xAxis2)与右方纵轴(yAxis2),并与xAxis/yAxis保持同步 customPlot->axisRect()->setupFullAxesBox(true); // 生成x-y数据, y=x^2, 定义域[-1,1] QVector x(101), y(101); for (int i = 0; i < 101; ++i) { x[i] = i/50.0 - 1; y[i] = x[i]*x[i]; } y[30] = qQNaN(); y[60] = std::numeric_limits::quiet_NaN(); // 新建QCPGraph对象,并设置绘图数据 customPlot->addGraph(); customPlot->graph(0)->setData(x, y); // 设置标题 customPlot->plotLayout()->insertRow(0); customPlot->plotLayout()->addElement(0, 0, new QCPTextElement(customPlot, "Test-Title", QFont("sans", 17, QFont::Bold))); // 设置坐标轴标签 customPlot->xAxis->setLabel("x"); customPlot->yAxis->setLabel("y"); // 设置坐标轴范围 customPlot->xAxis->setRange(-1, 1); customPlot->yAxis->setRange(0, 1); // 刷新显示 customPlot->replot();}
绘制效果:
关键词:
您可能也感兴趣:
为您推荐
机票里面包含保险吗?飞机保险有必要买吗?
辽宁扩大缓缴社保费政策实施范围 补缴期间免收滞纳金
近十年财险业务快速发展 财产保险业风险保障水平不提升
排行
最近更新
- 全球滚动:【QCustomPlot】绘制 x-y 曲线图
- 焦点精选!中考提示:正常饮食!别让吃饭成为考生“负担”
- 3D打印无金属柔性胶状电极问世_全球新视野
- 环球简讯:春雨潇潇雨未歇(春雨潇潇)
- 嵌入式冰箱销售保持高增长_全球信息
- 工行济宁分行全力发展普惠金融业务助力小微企业获得信贷
- 农行湖北安陆支行开展“金融知识普及月”系列活动
- 西乡农商银行峡口支行“贷”动产业发展新活力-精彩看点
- 平顶山卫东农商银行举办2023年贵金属纪念币产品展销暨客户答谢会
- 山西清徐农商银行服务三农“落点精准”|每日快看
- pu发泡和聚氨酯发泡有什么区别_pu发泡
- 常吃咸菜对人的身体有害处吗?_焦点要闻
- 盐跟味精,哪个对高血压危害大? 全球消息
- 热点!菜花炒瘦肉是怎么做的?
- 五花肉炒花菜怎么做?-环球时快讯
- 五花肉炒花菜的做法?
- 促消费加力、“小而美”破圈……“618”购物节盘点 世界信息
- 【报资讯】新产业(300832):6月19日北向资金减持14.65万股
- 世界热点!王者2023端午节有什么活动 王者荣耀端午节活动介绍
- 罗莱生活(002293):6月19日北向资金增持14.94万股-当前观点
- 涡阳县气象台发布大雾橙色预警【II级/严重】【2023-06-20】 快播报
- 【当前热闻】官坊街道(关于官坊街道介绍)
- 夏令跟冬令的时间怎么分的(夏令时与冬令时区别)
- 最新消息:20万左右的suv车哪个好点 20万左右的suv车哪个好
- 上海大学怎么样是211吗 上海大学怎么样知乎
- 曝大S吸毒!黄子佼供出7人,具俊晔天价电费成关键,疑是3胎生...
- 灾难末世日常(末世预见)
- 今头条!江油市人民法院地址_江油市人民法院
- 百事通!雪花牛排和菲力牛排的区别?
- 超级兔子联机版 超级兔子优化王|当前速讯