Qt之基于QCustomPlot绘制直方图(Histogram),叠加正态分布曲线

文章目录

任务目标


封装一个图表库(PlotViewCtrl),基于QCustomPlot。

理论知识

1. 什么是统计直方图? 什么是正态分布曲线?两者有何关系与区别?

参考案例:

浅谈正态分布的起源与应用
【小结】常见血细胞分析仪的检测原理与直方图/散点图

调用代码

cpp 复制代码
	// .h文件
	WidHistogram*			m_pWidHistogram = nullptr;
	
	// .cpp文件
	m_pWidHistogram = new WidHistogram(this);
	QHBoxLayout* pMainLayout = new QHBoxLayout(this);
	pMainLayout->addWidget(m_pWidHistogram);
	m_pWidHistogram->InitPlot_Histogram();

关键实现代码

cpp 复制代码
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

cpp 复制代码
// 引用头文件
#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();
}
相关推荐
IT笔记3 小时前
【Rust】Rust Match 模式匹配详解
java·开发语言·rust
逝水无殇4 小时前
C# 运算符重载详解
开发语言·后端·c#
TPBoreas4 小时前
配置信息防泄露方案:.env 环境隔离详解(dotenv-java)
java·开发语言
敲代码的嘎仔4 小时前
实习日志day6--实习日志day6--title命名规范化&businessType纠正&补充缺失的@Log注解&报警与通信模块补充&产出阶段总结文档
java·开发语言·人工智能·git·python·实习·大二
江华森5 小时前
Python 实现高德地图找房(一):环境搭建与数据爬虫
开发语言·爬虫·python
杜子不疼.5 小时前
【Qt初识】信号槽(三):机制意义、断开连接与 Lambda 表达式
开发语言·数据库·qt
老迟到的茉莉6 小时前
Hermes 是谁?跟 Claude Code 差在哪
开发语言·python
学逆向的6 小时前
汇编——内存
开发语言·汇编·算法·网络安全
lbb 小魔仙6 小时前
MuMu 模拟器 6.0 硬核测评:这次升级确实不一样
java·开发语言·模拟器·mumu·硬核测评
r_oo_ki_e_7 小时前
Java 线程池
java·开发语言