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();
}
相关推荐
爱上电路设计3 小时前
有趣的算法
开发语言·c++·算法
studyForMokey3 小时前
kotlin 函数类型接口lambda写法
android·开发语言·kotlin
2401_858120263 小时前
探索sklearn文本向量化:从词袋到深度学习的转变
开发语言·python·机器学习
与墨学长4 小时前
Rust破界:前端革新与Vite重构的深度透视(中)
开发语言·前端·rust·前端框架·wasm
虫小宝4 小时前
Java中的软件架构重构与升级策略
java·开发语言·重构
CTGU_daffodil5 小时前
matlab 绘制高等数学中的二维函数示例
开发语言·matlab
立秋67895 小时前
使用Python绘制堆积柱形图
开发语言·python
逸群不凡5 小时前
C++|哈希应用->布隆过滤器
开发语言·数据结构·c++·算法·哈希算法
敲代码的小白帆5 小时前
跟着峰哥学java 第四天 商品分类 前后端显示
java·开发语言
friklogff6 小时前
【JavaScript脚本宇宙】美化网格布局:Isotope和Masonry让你的网页焕然一新
开发语言·前端·javascript