一.实现绘图
QT实现绘图需要QCustomPlot类这里提供QCustomPlot官网地址:Qt Plotting Widget QCustomPlot - Introduction
下载好类后将qcustomplot.cpp和qcustomplot.h两个文件加入到工程中
添加完成后可以在工程目录中看到这两个文件,并在widget.h中加入代码
#include "qcustomplot.h"
然后可以在ui编辑页面绘制一个Widget图框,右击选择提升为
然后在弹出的对话框,在提升为类名那里输入QCustomPlot,然后头文件那里会自动填充为qcustomplot.h,单击添加,最后单击提升。
可以回到ui界面,看到现在widget已经变成了QCustomPlot类
在对象列表里更改widget为 customPlot
如果Qt版本在5.0以上,需要在.pro文件中的QT变量加上printsupport
再加上两个Pushbutton,调整好customPlot的大小,简单的ui界面就设计完成了
在ui文件中右击绘制散点图按钮,选择转到槽,选择clicked(),加入以下代码,可以测试下功能
void Widget::on_pushButton_clicked()
{
//绘图前先清除
ui->customPlot->clearGraphs();//清除图像,函数接受一个int类型的返回值,返回删除的graphs数。
ui->customPlot->legend->setVisible(false);//设置图例为不可见
ui->customPlot->replot();//重新绘制
QCPAxis *xAxis = ui->customPlot->xAxis;//x轴
QCPAxis *yAxis = ui->customPlot->yAxis;//y轴
ui->customPlot->addGraph(xAxis,yAxis);//设置图像坐标轴
QVector<double> x(16), y(16); //初始化向量x和y
x = {119,116.5,114,111.5,109,106.5,104,101.5,99,96.5,94,91.5,89,86.5,84,81.5};//x,y的值可以随意更改,改为用户需要得到
y = {9.8,9.2,8.8,8.7,8.9,8.4,8.8,9.1,9.5,10,9.8,10.5,10.4,9.3,8.4,7.3};
ui->customPlot->graph(0)->setData(x, y);
ui->customPlot->graph(0)->setName("散点图");// 设置图例名称
ui->customPlot->legend->setBrush(QColor(255,255,255,0));//设置图例背景
// 为坐标轴添加标签
xAxis->setLabel("X轴");
yAxis->setLabel("Y轴");
// 设置坐标轴的范围,以看到所有数据
ui->customPlot->graph(0)->rescaleAxes();
ui->customPlot->legend->setVisible(true); // 显示图例
ui->customPlot->graph(0)->setLineStyle((QCPGraph::LineStyle)0); // 线段风格(QCPGraph::LineStyle)i
ui->customPlot->graph(0)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle,QColor(qBlue(200)),5));//设置散点形状
// 支持鼠标拖拽轴的范围、滚动缩放轴的范围,左键点选图层(每条曲线独占一个图层)
ui->customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);
// 重画图像
ui->customPlot->replot();
}
可以参考
wendy_ya文章 QCustomPlot基础教程学习绘图更多的操作。
二.实现拟合(最小二乘法)
1.Eigen矩阵运算库
- Eigen官网:http://eigen.tuxfamily.org
到Eigen官网下载Eigen类,解压后保存到QT安装目录,并修改文件夹名称为eigen_3_4_0
再到工程文件中的.pro文件中加入代码,路径为你自己eigen_3_4_0
的路径
INCLUDEPATH += D:\Qt\eigen_3_4_0
添加头文件
#include <Eigen/Dense>
#include <Eigen/Core>
#include <Eigen/Geometry>
#include <Eigen/Eigenvalues>
2.拟合函数
右击Pushbutton2,建立槽函数,在槽函数中加入以下代码
void Widget::on_pushButton_2_clicked()
{
const int N = 6;
//参考C++最小二乘拟合 (高阶最小二乘拟合)(附C++代码)作者:koko_TT
QVector<double> x(16), y(16); //初始化向量x和y
x = {119,116.5,114,111.5,109,106.5,104,101.5,99,96.5,94,91.5,89,86.5,84,81.5};//x,y的值可以随意更改,改为用户需要得到
y = {9.8,9.2,8.8,8.7,8.9,8.4,8.8,9.1,9.5,10,9.8,10.5,10.4,9.3,8.4,7.3};
Eigen::MatrixXd A(x.size(), N + 1);
for (unsigned int i = 0; i < x.size(); ++i) { // 遍历所有点
for (int n = N, dex = 0; n >= 1; --n, ++dex) { // 遍历N到1阶
A(i, dex) = pow(x[i], n);
}
A(i, N) = 1; //
}
// 创建B矩阵
Eigen::MatrixXd B(y.size(), 1);
for (unsigned int i = 0; i < y.size(); ++i) {
B(i, 0) = y[i];
}
Eigen::MatrixXd W;
W = (A.transpose() * A).inverse() * A.transpose() * B;
double w[N+1];
for(int i = 0;i <= 6;i++)
{
w[i] = W(i,0);
}
QVector<double> x_fit(16), y_fit(16); //初始化向量x_fit和y_fit
for (int i=0; i<16; ++i)
{
x_fit[i] = x[i];
for (int n = N; n >= 1; --n) // 遍历N到1阶
{
y_fit[i] = y_fit[i] + w[6-n]*pow(x[i], n);
}
y_fit[i] = y_fit[i]+w[6];
}
//绘图前先清除
ui->customPlot->clearGraphs();//清除图像,函数接受一个int类型的返回值,返回删除的graphs数。
ui->customPlot->legend->setVisible(false);//设置图例为不可见
ui->customPlot->replot();//重新绘制
QCPAxis *xAxis = ui->customPlot->xAxis;//x轴
QCPAxis *yAxis = ui->customPlot->yAxis;//y轴
// 为坐标轴添加标签
xAxis->setLabel("X轴");
yAxis->setLabel("Y轴");
ui->customPlot->addGraph(xAxis,yAxis);//设置图像坐标轴
ui->customPlot->graph(0)->setData(x, y);
ui->customPlot->graph(0)->setName("散点图");// 设置图例名称
ui->customPlot->legend->setBrush(QColor(255,255,255,0));//设置图例背景
// 设置坐标轴的范围,以看到所有数据
ui->customPlot->graph(0)->rescaleAxes();
ui->customPlot->legend->setVisible(true); // 显示图例
ui->customPlot->graph(0)->setLineStyle((QCPGraph::LineStyle)0); // 线段风格(QCPGraph::LineStyle)i
ui->customPlot->graph(0)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle,QColor(qBlue(200)),5));//设置散点形状
ui->customPlot->addGraph(xAxis,yAxis);
ui->customPlot->graph(1)->setData(x_fit, y_fit);
ui->customPlot->graph(1)->setName("曲线拟合后");// 设置图例名称
ui->customPlot->legend->setVisible(true); // 显示图例
// 设置坐标轴的范围,以看到所有数据
ui->customPlot->graph(1)->rescaleAxes(true);
ui->customPlot->graph(1)->setPen(QPen(QColor(255, 0, 0))); // 设置画笔
ui->customPlot->graph(1)->setLineStyle((QCPGraph::LineStyle)1); // 线段风格(QCPGraph::LineStyle)i
// 支持鼠标拖拽轴的范围、滚动缩放轴的范围,左键点选图层(每条曲线独占一个图层)
ui->customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);
// 重画图像
ui->customPlot->replot();
}
关于最小二乘法可以参考
koko_TT的
C++最小二乘拟合 (高阶最小二乘拟合)这篇文章,写的很详细