当前位置: 首页 > news >正文

QCustomPlot 特定图表类型实战

QCustomPlot 特定图表类型实战

QCustomPlot 不仅擅长绘制基础折线图,还支持多种专业图表类型,包括柱状图、散点图、饼图甚至热力图。虽然其原生 API 主要围绕 QCPGraph 设计,但通过灵活组合图层、图元(QCPItem)与数据映射,我们完全可以实现丰富的可视化效果。

本文将带你实战五类常见图表:多曲线折线图、柱状图家族、散点/气泡图、饼图/环形图、热力图,每类均提供可运行的核心代码与实现思路。


1. 折线图进阶:多曲线对比、曲线平滑处理与异常值标记

多曲线对比

只需多次调用 addGraph() 并设置不同样式:

// 曲线1:温度
plot->addGraph();
plot->graph(0)->setName("温度");
plot->graph(0)->setData(x, temp);
plot->graph(0)->setPen(QPen(Qt::red, 2));// 曲线2:湿度
plot->addGraph();
plot->graph(1)->setName("湿度");
plot->graph(1)->setData(x, humidity);
plot->graph(1)->setPen(QPen(Qt::blue, 2));
plot->graph(1)->setLineStyle(QCPGraph::lsLine);
plot->graph(1)->setScatterStyle(QCPScatterStyle::ssCircle);plot->legend->setVisible(true);

曲线平滑处理(简易移动平均)

QCustomPlot 本身不提供平滑算法,但可在数据层面预处理:

QVector<double> smooth(const QVector<double>& data, int window = 5) {QVector<double> smoothed;for (int i = 0; i < data.size(); ++i) {double sum = 0;int count = 0;for (int j = qMax(0, i - window/2); j <= qMin(data.size()-1, i + window/2); ++j) {sum += data[j];count++;}smoothed.append(sum / count);}return smoothed;
}auto smoothedY = smooth(yRaw);
plot->addGraph();
plot->graph(0)->setData(x, smoothedY);
plot->graph(0)->setPen(QPen(Qt::green, 1.5, Qt::DashLine));

异常值标记

使用 QCPItemTracerQCPItemEllipse 在特定点添加标记:

for (int i = 0; i < y.size(); ++i) {if (qAbs(y[i] - mean) > 3 * stddev) { // 假设已计算均值与标准差QCPItemEllipse *ellipse = new QCPItemEllipse(plot);ellipse->topLeft->setType(QCPItemPosition::ptPlotCoords);ellipse->bottomRight->setType(QCPItemPosition::ptPlotCoords);ellipse->topLeft->setCoords(x[i] - 0.1, y[i] - 0.5);ellipse->bottomRight->setCoords(x[i] + 0.1, y[i] + 0.5);ellipse->setPen(QPen(Qt::red, 2));ellipse->setBrush(Qt::transparent);}
}

2. 柱状图实战:单组、分组与堆叠柱状图实现

QCustomPlot 没有原生柱状图类,但可通过 QCPBars 实现。

单组柱状图

QCPBars *bars = new QCPBars(plot->xAxis, plot->yAxis);
plot->addPlottable(bars);QVector<double> keys = {1, 2, 3, 4};
QVector<double> values = {2.1, 3.4, 2.8, 4.0};bars->setData(keys, values);
bars->setWidth(0.6);
bars->setPen(QPen(Qt::black));
bars->setBrush(QColor(50, 150, 250));

分组柱状图(多组并列)

为每组创建一个 QCPBars,并通过偏移 keys 实现并列:

double width = 0.2;
int groupCount = 3;
QVector<QCPBars*> barGroups;for (int i = 0; i < groupCount; ++i) {QCPBars *bar = new QCPBars(plot->xAxis, plot->yAxis);plot->addPlottable(bar);QVector<double> keysOffset;for (double key : baseKeys) {keysOffset << key + (i - groupCount/2.0) * width;}bar->setData(keysOffset, values[i]);bar->setWidth(width * 0.9);bar->setBrush(QColor(100 + i*50, 150, 200));barGroups << bar;
}// 设置 X 轴标签
plot->xAxis->setAutoTicks(false);
plot->xAxis->setAutoTickLabels(false);
plot->xAxis->setTickVector(baseKeys);
plot->xAxis->setTickVectorLabels({"A", "B", "C", "D"});

堆叠柱状图

使用 moveAbove() 方法将柱子堆叠:

QCPBars *bar1 = new QCPBars(plot->xAxis, plot->yAxis);
QCPBars *bar2 = new QCPBars(plot->xAxis, plot->yAxis);bar1->setData(keys, values1);
bar2->setData(keys, values2);bar2->moveAbove(bar1); // bar2 堆叠在 bar1 之上plot->addPlottable(bar1);
plot->addPlottable(bar2);

3. 散点图与气泡图:根据数据维度定制散点大小、颜色映射

基础散点图

plot->addGraph();
plot->graph(0)->setLineStyle(QCPGraph::lsNone); // 无线条
plot->graph(0)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, 6));
plot->graph(0)->setData(x, y);

气泡图(第三维:大小)

QCustomPlot 不直接支持变大小散点,但可通过循环添加 QCPItemEllipse 实现:

for (int i = 0; i < x.size(); ++i) {double radius = z[i] * 5; // z 为第三维数据QCPItemEllipse *bubble = new QCPItemEllipse(plot);bubble->topLeft->setCoords(x[i] - radius, y[i] - radius);bubble->bottomRight->setCoords(x[i] + radius, y[i] + radius);bubble->setPen(Qt::NoPen);bubble->setBrush(QColor(255, 100, 100, 150)); // 半透明
}

颜色映射(第四维)

结合 QCPColorGradientQCPColorMap 更适合热力图,但对散点可手动映射:

QCPColorGradient gradient;
gradient.setColorStops({{0.0, Qt::blue}, {0.5, Qt::yellow}, {1.0, Qt::red}});for (int i = 0; i < x.size(); ++i) {double normValue = (z[i] - zMin) / (zMax - zMin); // 归一化QColor color = gradient.color(normValue);QCPItemEllipse *point = new QCPItemEllipse(plot);point->topLeft->setCoords(x[i] - 3, y[i] - 3);point->bottomRight->setCoords(x[i] + 3, y[i] + 3);point->setBrush(color);point->setPen(Qt::NoPen);
}

⚠️ 注意:大量散点时性能较低,建议数据量 < 1000。


4. 饼图与环形图:QCustomPlot 实现饼图及扇区交互效果

QCustomPlot 无原生饼图支持,但可通过 QCPItemEllipse + QPainterPath 手绘,或使用 QCPCurve 模拟。

简易饼图实现(使用 QCPItem)

class PieChart : public QObject {
public:static void drawPie(QCustomPlot *plot, const QVector<double> &values, const QStringList &labels) {double total = std::accumulate(values.begin(), values.end(), 0.0);double startAngle = 90; // 从顶部开始for (int i = 0; i < values.size(); ++i) {double spanAngle = 360.0 * values[i] / total;QCPItemPieSlice *slice = new QCPItemPieSlice(plot);slice->setStartAngle(startAngle);slice->setSpanAngle(spanAngle);slice->setRadius(80);slice->setBrush(QColor(QRandomGenerator::global()->bounded(256),QRandomGenerator::global()->bounded(256),QRandomGenerator::global()->bounded(256)));plot->addItem(slice);startAngle += spanAngle;}}
};

📌 实际项目中,更推荐使用 QPainter 自定义 widget 绘制饼图,或集成第三方库。QCustomPlot 并非为此类图表设计。

扇区交互(高亮)

监听鼠标点击,动态调整被点击扇区的 setRadius()setOffset() 实现“弹出”效果。


5. 热力图入门:基于 QCustomPlot 的二维数据热力图绘制技巧

热力图是 QCustomPlot 的强项,通过 QCPColorMap 实现。

基础热力图

QCPColorMap *colorMap = new QCPColorMap(plot->xAxis, plot->yAxis);
plot->addPlottable(colorMap);// 设置数据维度
int nx = 50, ny = 50;
colorMap->data()->setSize(nx, ny);
colorMap->data()->setRange(QCPRange(0, 10), QCPRange(0, 10));// 填充数据
for (int xIndex = 0; xIndex < nx; ++xIndex) {for (int yIndex = 0; yIndex < ny; ++yIndex) {double x = colorMap->data()->key(xIndex);double y = colorMap->data()->value(yIndex);double z = qSin(x) * qCos(y); // 示例函数colorMap->data()->setCell(xIndex, yIndex, z);}
}// 设置颜色梯度
QCPColorGradient gradient;
gradient.setColorStops({{0.0, Qt::blue}, {0.5, Qt::white}, {1.0, Qt::red}});
colorMap->setGradient(gradient);// 显示颜色条
QCPColorScale *colorScale = new QCPColorScale(plot);
plot->plotLayout()->addElement(0, 1, colorScale);
colorScale->setType(QCPAxis::atRight);
colorMap->setColorScale(colorScale);
colorScale->axis()->setLabel("强度");plot->rescaleAxes();
plot->replot();

优化技巧

  • 使用 setInterpolate(true) 平滑过渡;
  • 调用 setTightBoundary(true) 避免边缘空白;
  • 对于离散数据,可关闭插值并设置 setFillAlpha(1.0)

结语

尽管 QCustomPlot 以折线图起家,但通过 QCPBarsQCPColorMapQCPItem 等组件,我们能实现柱状图、热力图、气泡图等丰富图表。对于饼图等非笛卡尔坐标系图表,虽可模拟,但建议评估是否更适合用其他可视化方案。

最佳实践建议

  • 折线/散点/热力图 → 优先使用 QCustomPlot;
  • 柱状图 → 使用 QCPBars
  • 饼图/雷达图 → 考虑自定义 QWidget + QPainter

附:关键类速查

图表类型核心类
折线图QCPGraph
柱状图QCPBars
热力图QCPColorMap
自定义图形QCPItemXXX
图例/标题QCPLegend, QCPTextElement
http://www.dtcms.com/a/428672.html

相关文章:

  • python 将关键数据标注在png图片里
  • python加速方法 对比 numba numb.cuda triton pycuda cupy
  • 常州天狼网站建设二手物品交换网站建设
  • 关于Java的几个小问题
  • 青岛手机网站建设手工制作月饼
  • 国外的哪个网站可以做跳转青岛网站推广途径
  • 湖北省和住房建设厅官方网站山东泰山新闻
  • 营销网站定制公司台州网站设计哪家好
  • C++——基础
  • 回顾首尔 KBW 2025,Sui 的创新与联结周
  • 2025CCPC郑州邀请赛暨河南省赛 B. 随机栈 II 题解
  • 珠海网站建设公商城二次开发
  • 合肥市蜀山区做个网站多少钱电子商务网页制作是什么
  • 做网站推广需要多少费用one dirve做网站
  • 京东网站的建设与发展前景上海闵行中心医院
  • 无锡网站建设要求手机设计软件app推荐
  • 网站开发e r图无极网页游戏
  • 网站建设与功能模块wordpress appkey 插件
  • 鸿鹄网站建设网站的建设费用
  • 硅胶东莞网站建设公司注册后怎么做网站
  • 高端大气网站设计欣赏企业网站建设费用怎么做账
  • 全国U系列射击锦标赛
  • 房地产建设网站长春火车站需要核酸检测报告吗
  • 深入网站开发和运维京东企业咨询属于什么行业
  • 网站如何做视频点播深圳网站做的好的公司名称
  • 网站建设的需要是什么wordpress创建主题面板
  • C语言基础之指针1
  • 深圳好的网站建设公安徽网站开发哪家好
  • 昆明公司网站建设做资料分享网站
  • Product Hunt 9月热门 AI 应用解读