Qt之基于QCustomPlot绘制直方图(Histogram),叠加正态分布曲线
文章目录
- 任务目标
- 理论知识
- 1. 什么是统计直方图? 什么是正态分布曲线?两者有何关系与区别?
- 参考案例:
- 调用代码
- 关键实现代码
- 例程2
任务目标
封装一个图表库(PlotViewCtrl),基于QCustomPlot。
理论知识
1. 什么是统计直方图? 什么是正态分布曲线?两者有何关系与区别?
参考案例:
浅谈正态分布的起源与应用
【小结】常见血细胞分析仪的检测原理与直方图/散点图
调用代码
// .h文件
WidHistogram* m_pWidHistogram = nullptr;
// .cpp文件
m_pWidHistogram = new WidHistogram(this);
QHBoxLayout* pMainLayout = new QHBoxLayout(this);
pMainLayout->addWidget(m_pWidHistogram);
m_pWidHistogram->InitPlot_Histogram();
关键实现代码
void CstmPlot::InitPlot_Histogram()
{
clearPlottables();
legend->clearItems();
setInteraction(QCP::iSelectPlottables, false);
QVector<double> x(101), y(101);
double mean = 0.0, stddev = 1.0;
for (int i = 0; i < 101; ++i)
{
x[i] = -3 + i * 0.06;
y[i] = exp(-0.5 * pow((x[i] - mean) / stddev, 2)) / (stddev * sqrt(2 * M_PI));
}
QCPBars* pBars = new QCPBars(xAxis, yAxis);
pBars->setWidth(0.06);
pBars->setData(x, y);
pBars->setName("直方图");
// 设置笔的颜色为蓝色
pBars->setPen(QPen(QColor("#33A5FF"))); // Qt::gray
// 设置画刷的颜色为蓝色,即实心
pBars->setBrush(QBrush(Qt::blue));
#if 0
// 使用 QCPCurve
QCPCurve* pCurve = new QCPCurve(xAxis, yAxis);
pCurve->setData(x, y);
pCurve->setPen(QPen(Qt::red));
pCurve->setName("正态曲线");
#else
// 使用 QCPGraph
QCPGraph* pGraph = addGraph(xAxis, yAxis);
pGraph->setData(x, y);
pGraph->setPen(QPen(QColor("#FF3333"), 1, Qt::SolidLine));
pGraph->setName("正态曲线");
#endif
rescaleAxes();
replot();
}
例程2
// 引用头文件
#include <QApplication>
#include <QMainWindow>
#include <QChartView>
#include <QLineSeries>
#include <QValueAxis>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QVector>
#include <QRandomGenerator>
#include <cmath>
#include "qcustomplot/qcustomplot.h"
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
// 创建主窗口
QMainWindow* mainWindow = new QMainWindow();
QWidget* centralWidget = new QWidget(mainWindow);
mainWindow->setCentralWidget(centralWidget);
// 创建QCustomPlot对象
//QCustomPlot* customPlot = new QCustomPlot(centralWidget);
//customPlot->setMinimumSize(600, 400);
// 创建折线图
//QLineSeries* lineSeries = new QLineSeries();
QVector<QPointF> points;
for (int i = 0; i < 100; i++) {
double x = i;
double y = QRandomGenerator::global()->bounded(0, 100);
points.append(QPointF(x, y));
}
//lineSeries->append(points);
// 设置坐标轴
//QValueAxis* axisX = new QValueAxis();
//axisX->setLabelFormat("%d");
//axisX->setTitleText("时间");
//axisX->setRange(0, 100);
//QValueAxis* axisY = new QValueAxis();
//axisY->setLabelFormat("%d");
//axisY->setTitleText("电压");
//axisY->setRange(0, 100);
// 添加折线图到QCustomPlot中
//customPlot->addGraph();
//customPlot->graph(0)->setData(points);
//customPlot->graph(0)->setPen(QPen(Qt::blue));
//customPlot->xAxis->setRange(0, 100);
//customPlot->yAxis->setRange(0, 100);
// 统计电压区间
bool bFirstPt = true;
QVector<double> count(10, 0);
double maxVoltage = 0;
double minVoltage = 100;
for (int i = 0; i < points.size(); i++) {
double voltage = points[i].y();
if (voltage > maxVoltage) {
maxVoltage = voltage;
}
if (voltage < minVoltage) {
minVoltage = voltage;
}
if (bFirstPt)
{
bFirstPt = false;
}
else
{
int index = (voltage - minVoltage) / (maxVoltage - minVoltage) * 10;
if (index == 10) {
index--;
}
count[index]++;
}
}
// 绘制直方图
QCustomPlot* histogram = new QCustomPlot(centralWidget);
histogram->setMinimumSize(600, 400);
QCPBars* bars = new QCPBars(histogram->xAxis, histogram->yAxis);
QVector<double> ticks(10);
QVector<QString> labels(10);
for (int i = 0; i < 10; i++) {
ticks[i] = i + 0.5;
labels[i] = QString::number(minVoltage + (maxVoltage - minVoltage) / 10 * i, 'f', 2);
}
QSharedPointer<QCPAxisTicker> ticker(new QCPAxisTicker);
histogram->xAxis->setTicker(ticker);
histogram->xAxis->ticker()->setTickCount(10);
//histogram->xAxis->setAutoTicks(false);
//histogram->xAxis->setAutoTickLabels(false);
//histogram->xAxis->setTickVector(ticks);
//histogram->xAxis->setTickVectorLabels(labels);
histogram->xAxis->setTickLabelRotation(60);
bars->setData(ticks, count);
histogram->rescaleAxes();
histogram->xAxis->setRange(QCPRange(-0.1, 10.1));
histogram->replot();
// 绘制正态曲线图
QCustomPlot* normalCurve = new QCustomPlot(centralWidget);
normalCurve->setMinimumSize(600, 400);
QVector<double> x(1000), y(1000);
double mean = (maxVoltage + minVoltage) / 2;
double stdDev = (maxVoltage - minVoltage) / 6;
for (int i = 0; i < 1000; i++) {
x[i] = minVoltage + (maxVoltage - minVoltage) / 1000 * i;
y[i] = exp(-(x[i] - mean) * (x[i] - mean) / (2 * stdDev * stdDev)) / (stdDev * sqrt(2 * M_PI));
}
QCPGraph* graph = normalCurve->addGraph();
graph->setData(x, y);
normalCurve->rescaleAxes();
normalCurve->replot();
// 将QCustomPlot添加到主窗口中
QHBoxLayout* layout = new QHBoxLayout();
//layout->addWidget(customPlot);
layout->addWidget(histogram);
layout->addWidget(normalCurve);
centralWidget->setLayout(layout);
// 显示主窗口
mainWindow->show();
return a.exec();
}