QCustomPlot开源库使用

打印 上一主题 下一主题

主题 550|帖子 550|积分 1650

1.简介

QCustomPlot是用于绘图和数据可视化的Qt C ++小部件。它没有进一步的依靠关系,而且有据可查。该绘图库专注于制作雅观,出书质量的2D绘图,图形和图表,以及为及时可视化应用程序提供高性能。看一下“ 设置”和“ 基本绘图”教程以开始使用。QCustomPlot可以导出为各种格式,比方矢量化的PDF文件和光栅化的图像(如PNG,JPG和BMP)。QCustomPlot是用于在应用程序内部显示及时数据以及为其他媒体生成高质量图的办理方案。
2.QCustomPlot下载与安装

参考:Qt Plotting Widget QCustomPlot - Setting Up
QCustomPlot 2.1.1官方文档:QCustomPlot 2.1.1 Documentation
QCustomPlot官网地点:Qt Plotting Widget QCustomPlot - Introduction
(1)下载下来的qcustomplot.h和qcustomplot.cpp参加工程中
(2)如果Qt版本在5.0以上,需要在.pro文件中的QT变量加上printsupport
(3)添加帮助文档
在下载的documentation文件夹下有个qcustomplot.qch文件,将它拷贝Qt的文档目录下(一般为C:\Users\用户名\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Qt\6.1.0\MinGW 8.1.0 (64-bit),会根据你的Qt版本号而做相应变更),然后在QtCreator——>工具——>选项——>帮助——>文档——>添加,选择qcustomplot.qch文件,确定,以后按F1就能跳转到QCustomPlot的帮助文档了。
3.QCustomPlot图层先容

图层先容:
QCustomPlot类管理着所有的图层,它默认自带了六个图层,分别是:

  • 配景层background
  • 网格层grid
  • 绘图层main
  • 坐标轴层axes
  • 图例层legend
  • overlay层overlay
依据层的顺序的不同,绘制的顺序也不同,越在底下的层越早绘制,当前层默以为绘图层main。下图中就是QCPAxisRect。

层有两种刷新模式:


  • lmLogical:只用于渲染的顺序,而且与相邻的lmLogical层共享绘图缓存(注意这里的相邻,如果前一个层是lmBuffered模式,则会新建一个绘图缓存用于绘图)
  • lmBuffered:拥有本身的绘图缓存,而且可以单独的刷新(调用QCPLayer::replot函数)
默认只有overlay层启用了lmBuffered单独绘制机制,其它层都共享一个绘图缓存,由于overlay层重要是用于存放悬浮与图表上的item项,需要频繁的刷新,启用了lmBuffered的层会多占用内存。
布局方式:
在QCustomPlot中,布局方式只有两种:


  • QCPLayoutGrid:网格布局
  • QCPLayoutInset:内嵌式布局, 这种布局的作用是把子元素与布局的界限对齐或者将其放置在布局内的任意位置(图例QCPLegend就被放置在此布局内),严酷来说这个并不算布局
继续关系图如下所示:

这两种布局都继续自QCPLayout,而QCPLayout继续自QCPLayoutElement布局元素,所以一个布局可以包罗另一个布局,布局内的元素都要继续自QCPLayoutElement。
4.QCustomPlot坐标轴的相关属性和方法

(1)QCustomPlot中的轴先容:
QCustomPlot中由QCPAxis类管理QCustomPlot内的单个轴。通常不需要外部实例化。通过QCustomPlot::xAxis(底部)、QCustomPlot::yAxis(左侧)、QCustomPlot::xAxis2(顶部)和QCustomPlot::yAxis2(右侧)访问QCustomPlot的默认四个轴。其位置如下图所示:

(2)设置轴标签与清空轴标签:
设置轴标签利用setLabel函数:
   void QCPAxis::setLabel const QString &str)
  (3)设置轴范围:
设置轴的范围利用setRange函数:
   void QCPAxis::setRange (double lower, double upper)
  lower表示最小值,upper表示最大值
(4)设置使坐标轴自行缩放可以或许完全显示:
   customPlot->graph(0)->rescaleAxes();
  customPlot->graph(1)->rescaleAxes(true);
  【注意】:
   调用 customPlot->graph(0)->rescaleAxes();后范围被缩小了,曲线正好占满整个区域,但是调用customPlot->graph(0)->rescaleAxes(true)就不会有变化,由于区域不会缩小。
  (5)设置轴与暗号标签的显示与隐蔽:
设置是否显示轴利用setVisible()函数:
   void QCPLayer::setVisible(bool visible)
  轴默认显示,如果不显示可以将bool设置为false
(6)设置是否显示暗号标签:
利用setTickLabels()函数:
   void QCPAxis::setTickLabels(bool show)
  暗号标签是在暗号旁边绘制的数字。暗号标签默认显示,如果不显示可以将bool设置为false
左轴和下轴默认显示轴和暗号标签,右轴和上轴默认不显示轴和暗号标签,如果想为右轴和上轴显示刻度但不显示标签,可以进行如下设置
设置后,还需要设置使左轴和下轴始终将其范围转移到上轴和右轴上,代码如下:
  1. connect(customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->xAxis2, SLOT(setRange(QCPRange)));
  2. connect(customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->yAxis2, SLOT(setRange(QCPRange)));
复制代码
(7)设置轴的颜色
设置轴的颜色利用setBasePen函数:
   void QCPAxis::setBasePen(const QPen & pen)
  (8)设置配景颜色:
设置配景颜色利用setBackground函数:
   void QPainter::setBackground(const QBrush &brush)
  (9)设置配景图片:
设置配景图片同样利用setBackground()函数:
   void QCPAxisRect::setBackground (const QPixmap & pm)
  设置配景缩放使用setBackgroundScaled()函数:
   void QCPAxisRect::setBackgroundScaled (bool scaled)
  设置缩放图形的横纵比利用setBackgroundScaledMode函数:
   void QCPAxisRect::setBackgroundScaledMode(Qt::AspectRatioMode mode)
  该函数常与setBackgroundScaled函数集合使用,代表缩放图形时的横纵比。常用参数如下:

参数
形貌
Qt::IgnoreAspectRatio
巨细可自由缩放。不保留纵横比
Qt::KeepAspectRatio
在给定的矩形内,巨细被缩放为一个尽可能大的矩形,保留纵横比
Qt::KeepAspectRatioByExpanding
将巨细缩放为给定矩形外尽可能小的矩形,保留纵横比
(10)图例统一放在下方
代码示例:
  1. // 设置图例行优先排列
  2. customPlot->legend->setFillOrder(QCPLayoutGrid::foColumnsFirst);
  3. // 设置六个图例自动换行
  4. customPlot->legend->setWrap(6);
  5. // 设置图例可见
  6. customPlot->legend->setVisible(true);
  7. // 设置图例位置,这里选择显示在QCPAxisRect下方,同理可设置显示在QCustomPlot中任意位置
  8. customPlot->plotLayout()->addElement(1 , 0, customPlot->legend);
  9. // 设置显示比例
  10. customPlot->plotLayout()->setRowStretchFactor(1, 0.001);
  11. // 设置边框隐藏
  12. customPlot->legend->setBorderPen(Qt::NoPen);
复制代码
运行结果如下所示: 

(11)设置图例与曲线同步选中
起首,需要设置Qcustomplot的属性:
  1. //设置基本坐标轴(左侧Y轴和下方X轴)可拖动、可缩放、曲线可选、legend可选、设置伸缩比例,使所有图例可见
  2. CustomPlot->setInteractions(QCP::iRangeDrag|QCP::iRangeZoom| QCP::iSelectAxes | QCP::iSelectLegend | QCP::iSelectPlottables);
  3. //设置legend只能选择图例
  4. CustomPlot->legend->setSelectableParts(QCPLegend::spItems);
复制代码
然后需要编写槽函数:
  1. void MainWindow::selectionChanged()
  2. {
  3.   // make top and bottom axes be selected synchronously, and handle axis and tick labels as one selectable object:
  4.   if (ui->customPlot->xAxis->selectedParts().testFlag(QCPAxis::spAxis) || ui->customPlot->xAxis->selectedParts().testFlag(QCPAxis::spTickLabels) ||
  5.       ui->customPlot->xAxis2->selectedParts().testFlag(QCPAxis::spAxis) || ui->customPlot->xAxis2->selectedParts().testFlag(QCPAxis::spTickLabels))
  6.   {
  7.     ui->customPlot->xAxis2->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels);
  8.     ui->customPlot->xAxis->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels);
  9.   }
  10.   // make left and right axes be selected synchronously, and handle axis and tick labels as one selectable object:
  11.   if (ui->customPlot->yAxis->selectedParts().testFlag(QCPAxis::spAxis) || ui->customPlot->yAxis->selectedParts().testFlag(QCPAxis::spTickLabels) ||
  12.       ui->customPlot->yAxis2->selectedParts().testFlag(QCPAxis::spAxis) || ui->customPlot->yAxis2->selectedParts().testFlag(QCPAxis::spTickLabels))
  13.   {
  14.     ui->customPlot->yAxis2->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels);
  15.     ui->customPlot->yAxis->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels);
  16.   }
  17.   // 将图形的选择与相应图例项的选择同步
  18.   for (int i=0; i<ui->customPlot->graphCount(); ++i)
  19.   {
  20.     QCPGraph *graph = ui->customPlot->graph(i);
  21.     QCPPlottableLegendItem *item = ui->customPlot->legend->itemWithPlottable(graph);
  22.     if (item->selected() || graph->selected())
  23.     {
  24.       item->setSelected(true);
  25.       //注意:这句需要Qcustomplot2.0系列版本
  26.       graph->setSelection(QCPDataSelection(graph->data()->dataRange()));
  27.       //这句1.0系列版本即可
  28.       //graph->setSelected(true);
  29.     }
  30.   }
  31. }
复制代码
最后,在主函数中将信号与槽进行毗连:
  1. connect(ui->customPlot, SIGNAL(selectionChangedByUser()), this, SLOT(selectionChanged()));
复制代码
selectionChangedByUser()信号在用户更改QCustomPlot中的选择后发出,比方通过单击。

5.QCustomPlot图例的相关设置

(1)显示图例:图例默认不显示,显示图例使用setVisible()函数
(2)设置图例位置:设置图例位置利用setInsetAlignment函数
位置
形貌
Qt::AlignLeft
居左
Qt::AlignHCenter
程度居中
Qt::AlighRight
居右
Qt::AlignTop
居上
Qt::AlignVCenter
垂直居中
Qt::AlignBottom
居下
(3)设置边框隐蔽:设置图例的边框利用setBorderPen()函数:
   void QCPLegend::setBorderPen(const QPen & pen)
  设置边框隐蔽代码如下:
   customPlot->legend->setBorderPen(Qt::NoPen);
  (4)设置图例字体代码为:
   customPlot->legend->setFont(QFont("Helvetica", 9));
  (5)设置图例间隔代码为:
   customPlot->legend->setRowSpacing(-3);
  (6)设置图例文字颜色代码为:
customPlot->legend->setTextColor(TextColor);//设置图例文字颜色
(7)设置图例中图形与文字间隔图例边框的间隔代码为:
customPlot->legend->setMargins(QMargins(0,0,0,0));
(8)设置图例配景
设置图例配景为空缺利用如下语句实现:
   customPlot->legend->setBrush(QColor(255,255,255,0));//设置图例配景
  (9)设置图例名称
设置第i条直线的名称:
   customPlot->graph(i)->setName(names);//设置名称
  6.QCustomPlot线条样式设置

通过画笔QPen设置线的线宽、样式和颜色,以及线的样式,代码示例:
  1. QPen pen;
  2. pen.setWidth(3);//设置线宽
  3. // 添加Graph,一条曲线使用一个Graph
  4. customPlot->addGraph();
  5. pen.setStyle(Qt::PenStyle::DashLine);//设置为虚线
  6. pen.setColor(Qt::blue);//设置线条蓝色
  7. customPlot->graph(0)->setPen(pen);
复制代码
常见的线条样式如下:

设置线条样式添补,设置曲线和x轴围成区域的添补颜色利用画刷QBrush:
   customPlot->graph(0)->setBrush(QBrush(QColor(0,0,255,50))); //蓝色,透明度50
  7.QCustomPlot绘制曲线

  1.     // 生成数据,画出的是抛物线
  2.     QVector<double> x(101), y(101); //初始化向量x和y
  3.     for (int i=0; i<101; ++i)
  4.     {
  5.       x[i] = i/50.0 - 1; // x范围[-1,1]
  6.       y[i] = x[i]*x[i]; // y=x*x
  7.     }
  8.     ui->customPlot->addGraph();//添加数据曲线(一个图像可以有多个数据曲线)
  9.     // graph(0);可以获取某个数据曲线(按添加先后排序)
  10.     // setData();为数据曲线关联数据
  11.     ui->customPlot->graph(0)->setData(x, y);
  12.     ui->customPlot->graph(0)->setName("第一个示例");// 设置图例名称
  13.     // 为坐标轴添加标签
  14.     ui->customPlot->xAxis->setLabel("x");
  15.     ui->customPlot->yAxis->setLabel("y");
  16.     // 设置坐标轴的范围,以看到所有数据
  17.     ui->customPlot->xAxis->setRange(-1, 1);
  18.     ui->customPlot->yAxis->setRange(0, 1);
  19.     ui->customPlot->legend->setVisible(true); // 显示图例
  20.     // 重画图像
  21.     ui->customPlot->replot();
复制代码
8.QCustomlot绘制多条曲线

  1. QCustomPlot *customPlot = ui->customPlot;//创建customPlot//每条曲线都会独占一个graph()customPlot->addGraph();customPlot->graph(0)->setPen(QPen(Qt::blue)); // 曲线的颜色customPlot->graph(0)->setBrush(QBrush(QColor(0, 0, 255, 20))); // 曲线与X轴包围区的颜色customPlot->addGraph();//添加graph等价于添加一条新曲线customPlot->graph(1)->setPen(QPen(Qt::red)); // 曲线的颜色// 生成模拟数据点 (x-y0 第一条曲线, x-y1为第2条曲线):QVector<double> x(251), y0(251), y1(251);for (int i=0; i<251; ++i){   x[i] = i;   y0[i] = qExp(-i/150.0)*qCos(i/10.0); // 第一条曲线:y0衰减cos   y1[i] = qExp(-i/150.0);              // 第二条曲线:y1衰减指数}// 边框右侧和上侧均显示刻度线,但不显示刻度值:customPlot->xAxis2->setVisible(true);customPlot->xAxis2->setTickLabels(false);customPlot->yAxis2->setVisible(true);customPlot->yAxis2->setTickLabels(false);// 使上下两个X轴的范围总是相等,使左右两个Y轴的范围总是相等connect(customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->xAxis2, SLOT(setRange(QCPRange)));
  2. connect(customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->yAxis2, SLOT(setRange(QCPRange)));
  3. // 把已存在的数据添补进graph的数据区customPlot->graph(0)->setData(x, y0);customPlot->graph(1)->setData(x, y1);//自动调整XY轴的范围,以便显示出graph(0)中所有的点(下面会单独讲到这个函数)customPlot->graph(0)->rescaleAxes();//自动调整XY轴的范围,以便显示出graph(1)中所有的点customPlot->graph(1)->rescaleAxes(true);// 支持鼠标拖拽轴的范围、滚动缩放轴的范围,左键点选图层(每条曲线独占一个图层)customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);// 立刻刷新图像ui->customPlot->replot();
复制代码
9.QCustomPlot绘制散点图

可参考案例:Plot Screenshots: Line Style Demo和Screenshots: Scatter Style Demo。
  1.     QCustomPlot *customPlot = ui->customPlot;//创建customPlot
  2.     QPen pen;
  3.     QStringList lineNames;
  4.     lineNames << "lsNone" << "lsLine" << "lsStepLeft" << "lsStepRight" << "lsStepCenter" << "lsImpulse";
  5.     for (int i = QCPGraph::lsNone; i <= QCPGraph::lsImpulse; ++i)
  6.     {
  7.         customPlot->addGraph();
  8.         pen.setColor(QColor(qSin(i*1+1.2)*80+80, qSin(i*0.3+0)*80+80, qSin(i*0.3+1.5)*80+80));
  9.         customPlot->graph()->setPen(pen);       // 设置画笔
  10.         customPlot->graph()->setName(lineNames.at(i-QCPGraph::lsNone));//图例名称
  11.         customPlot->graph()->setLineStyle((QCPGraph::LineStyle)i);  // 线段风格
  12.         customPlot->graph()->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, 5));//设置散点形状
  13.         customPlot->legend->setVisible(true); // 显示图例
  14.         QVector<double> x(15), y(15);
  15.         for (int j=0; j<15; ++j)
  16.         {
  17.             x[j] = j/15.0 * 5*3.14 + 0.01;
  18.             y[j] = 7*qSin(x[j])/x[j] - (i-QCPGraph::lsNone)*5 + (QCPGraph::lsImpulse)*5 + 2;
  19.         }
  20.         customPlot->graph()->setData(x, y);//x和y
  21.         customPlot->graph()->rescaleAxes(true);//自动调整XY轴的范围
  22.     }
复制代码
这里重要解释一下LineStyle和ScatterShape这两个函数。
(1)enum QCPGraph:ineStyle:定义图形线在绘图中的视觉表示方式。
参数
形貌
lsNone
数据点不与任何线毗连
lsLine
数据点由一条直线毗连
lsStepLeft
将线绘制为阶跃,此中阶跃高度为左侧数据点的值
lsStepRight
将线绘制为阶跃,此中阶跃高度为右侧数据点的值
lsStepCenter
当阶跃位于两个数据点之间时,将线绘制为阶跃
lsImpulse
每个数据点由一条平行于值轴的线表示(脉冲线)
(2)enum QCPScatterStyle::ScatterShape:设置散点外形
名称
外形
形貌
ssNone
不绘制散点符号
ssDot
.
单点
ssCross
x
交叉
ssPlus
+

ssCircle
o
圆圈
ssDisc

实心圆圈(圈内为pen颜色)



10.绘制柱状图

  1. //绘制柱状图
  2. QCPAxis *xAxis = ui->customPlot->xAxis;//x轴
  3. QCPAxis *yAxis = ui->customPlot->yAxis;//y轴
  4. QCPBars *bars = new QCPBars(xAxis, yAxis);  // 使用xAxis作为柱状图的x轴,yAxis作为y轴
  5. bars->setAntialiased(false); // 为了更好的边框效果,关闭抗齿锯
  6. bars->setName("Bars"); // 设置图例
  7. bars->setPen(QPen(QColor(0, 160, 140).lighter(130))); // 设置柱状图的边框颜色
  8. bars->setBrush(QColor(20,68,106));  // 设置柱状图的画刷颜色
  9. QVector<double> ticks;
  10. QVector<QString> labels;
  11. ticks << 1 << 2 << 3 << 4 << 5 << 6 << 7;//轴的范围
  12. labels << "A" << "B" << "C" << "D" << "E" << "F" << "G";//轴的刻度文字显示
  13. QSharedPointer<QCPAxisTickerText> textTicker(new QCPAxisTickerText);
  14. textTicker->addTicks(ticks, labels);
  15. xAxis->setTicker(textTicker);        // 设置为文字轴
  16. xAxis->setTickLabelRotation(60);     // 轴刻度文字旋转60度
  17. xAxis->setSubTicks(false);           // 不显示子刻度
  18. xAxis->setTickLength(0, 4);          // 轴内外刻度的长度分别是0,4,也就是轴内的刻度线不显示
  19. xAxis->setRange(0, 8);               // 设置x轴范围
  20. xAxis->setLabel("x");
  21. xAxis->setUpperEnding(QCPLineEnding::esSpikeArrow);
  22. yAxis->setRange(0, 12.1);          //设置y轴范围
  23. yAxis->setPadding(35);             // 轴的内边距
  24. yAxis->setLabel("y");
  25. yAxis->setUpperEnding(QCPLineEnding::esSpikeArrow);
  26. QVector<double> fossilData;
  27. fossilData  << 10 << 9 << 2 << 5 << 7 << 4 << 1;//y轴坐标值
  28. bars->setData(ticks, fossilData);
复制代码
11.QCustomPlot将绘制的图形保存导出

QCustomPlot提供了四种常用的save接口,其格式如下:
  1. saveBmp(const QString &fileName, int width, int height, double scale, int resolution, QCP::ResolutionUnit resolutionUnit);
  2. saveJpg(const QString &fileName, int width, int height, double scale, int quality, int resolution, QCP::ResolutionUnit resolutionUnit);
  3. savePng(const QString &fileName, int width, int height, double scale, int quality, int resolution, QCP::ResolutionUnit resolutionUnit);
  4. savePdf(const QString &fileName, int width, int height, QCP::ExportPen exportPen, const QString &pdfCreator, const QString &pdfTitle);
复制代码
代码示例:
  1.     QString filename = QFileDialog::getSaveFileName();
  2.     if( filename == "" ){
  3.         QMessageBox::information(this,"fail","保存失败");
  4.          return false;
  5.      }
  6.      else if( filename.endsWith(".png") ){
  7.          QMessageBox::information(this,"success","成功保存为png文件");
  8.          return ui->customPlot->savePng( filename, ui->customPlot->width(), ui->customPlot->height() );
  9.      }
  10.      else if( filename.endsWith(".jpg")||filename.endsWith(".jpeg") ){
  11.          QMessageBox::information(this,"success","成功保存为jpg文件");
  12.          return ui->customPlot->saveJpg( filename, ui->customPlot->width(), ui->customPlot->height() );
  13.      }
  14.      else if( filename.endsWith(".bmp") ){
  15.          QMessageBox::information(this,"success","成功保存为bmp文件");
  16.          return ui->customPlot->saveBmp( filename, ui->customPlot->width(), ui->customPlot->height() );
  17.      }
  18.      else if( filename.endsWith(".pdf") ){
  19.          QMessageBox::information(this,"success","成功保存为pdf文件");
  20.          return ui->customPlot->savePdf( filename, ui->customPlot->width(), ui->customPlot->height() );
  21.      }
  22.     else{
  23.      //否则追加后缀名为.png保存文件
  24.          QMessageBox::information(this,"success","保存成功,已默认保存为png文件");
  25.          return ui->customPlot->savePng(filename.append(".png"), ui->customPlot->width(), ui->customPlot->height() );
  26.     }
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

守听

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表