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

【Qwt 7.0 系列】多坐标轴与多绘图布局 —— 寄生绘图与 QwtFigure 容器

【Qwt 7.0 系列】多坐标轴与多绘图布局 —— 寄生绘图与 QwtFigure 容器

本文是 Qwt 7.0 系列介绍和教程,如果你正在寻找一个高性能、协议友好、同时支持 2D 和 3D 绘图的 Qt 数据可视化库,那么这篇文章就是为你准备的。

系列总述文章:Qwt 7.0 —— 基于 Qt 的高性能 2D/3D 绘图库

概述 | 高性能曲线绘制 | 常用图表类型 | 高级科学图表 | 多坐标轴与布局 | 交互功能 | 3D 数据可视化 | 坐标轴与刻度 | 控件与辅助元素 | 总体架构解析 | matplotlib 风格绘图

项目地址:GitHub | Gitee | 在线文档

引言

如果你用过原版 Qwt 6.x,一定遇到过这样的痛点:一个QwtPlot只能拥有上下左右四个坐标轴。当你需要在同一张图上绘制温度(℃)、压力(kPa)、流量(L/s)三种不同量级的数据时,两个 Y 轴根本不够用。

在 matplotlib 中,这个问题通过twinx()/twiny()轻松解决;但在 Qt 的绘图世界里,长期以来没有优雅的方案。Qwt 7.0 带来了全新的寄生绘图(Parasite Axes)机制和QwtFigure 容器,彻底打破了这一限制。这两个特性是 Qwt 7.0 最重要的架构创新之一,原版 Qwt 6.x 完全不支持。

本文将带你深入理解这两个全新功能,从原理到实战,一步步掌握多坐标轴叠加和多绘图布局的技巧。


一、寄生绘图(Parasite Axes)—— 多坐标轴系统

1.1 工作原理

寄生绘图的核心思想很简单:在宿主绘图的画布上方,叠加一个透明的子绘图。这个子绘图拥有独立的坐标系统,但和宿主绘图共享同一块绘图区域。

它有三个关键特征:

特征说明
画布区域一致寄生绘图的画布与宿主绘图保持相同尺寸
独立坐标系统可以拥有自己的刻度范围、标签、单位
透明背景只显示坐标轴和曲线,不遮挡宿主绘图

你可以把寄生绘图想象成一层"透明薄膜",贴在宿主绘图上面,每层薄膜各自携带一套独立的坐标轴。

1.2 创建寄生绘图:createParasitePlot()

通过QwtPlot::createParasitePlot()方法创建寄生绘图,签名如下:

QwtPlot*createParasitePlot(QwtAxis::Position enableAxis);

参数enableAxis指定寄生绘图初始显示的坐标轴位置,其他坐标轴默认隐藏。下面是一个完整的示例:

// 创建宿主绘图QwtPlot*hostPlot=newQwtPlot();// ... 设置宿主绘图的参数(曲线、标题等)////////////////////////////////////////////////////////// 添加寄生坐标系////////////////////////////////////////////////////////QwtPlot*parasitePlot=hostPlot->createParasitePlot(QwtAxis::YLeft);// 额外启用寄生绘图的其他坐标轴parasitePlot->enableAxis(QwtAxis::YRight,true);parasitePlot->enableAxis(QwtAxis::XTop,true);// 设置寄生绘图与宿主共享 X 轴parasitePlot->setParasiteShareAxis(QwtAxis::XBottom);// 设置寄生轴标题parasitePlot->setAxisTitle(QwtAxis::YLeft,"Y2 Left Axis");parasitePlot->setAxisTitle(QwtAxis::YRight,"Y2 Right Axis");parasitePlot->setAxisTitle(QwtAxis::XTop,"X2 Top Axis");// 在寄生绘图上添加曲线QColorcurColor(255,127,14);// 橙色,与宿主曲线区分QwtPlotCurve*parasiteCurve=newQwtPlotCurve("parasite sine Wave 1");parasiteCurve->setSamples(generateSampleData(100,2000,2.3));parasiteCurve->attach(parasitePlot);parasiteCurve->setPen(curColor,1.5);parasiteCurve->setRenderHint(QwtPlotItem::RenderAntialiased,true);// 给寄生轴的刻度上色,方便区分parasitePlot->axisWidget(QwtAxis::YLeft)->setScaleColor(curColor);parasitePlot->axisWidget(QwtAxis::YRight)->setScaleColor(curColor);parasitePlot->axisWidget(QwtAxis::XTop)->setScaleColor(curColor);

运行效果如下(单寄生绘图):

1.3 多寄生绘图叠加:任意数量的坐标轴

Qwt 7.0 的强大之处在于——寄生绘图的数量没有限制。只需在宿主绘图上多次调用createParasitePlot(),即可创建任意多的坐标轴层。下面是创建第二个寄生绘图的代码:

////////////////////////////////////////////////////////// 添加第二个寄生坐标系////////////////////////////////////////////////////////QwtPlot*parasitePlot2=hostPlot->createParasitePlot(QwtAxis::YLeft);// 启用额外坐标轴并设置共享parasitePlot2->enableAxis(QwtAxis::YRight,true);parasitePlot2->enableAxis(QwtAxis::XBottom,true);parasitePlot2->setParasiteShareAxis(QwtAxis::XTop);// 设置轴标题parasitePlot2->setAxisTitle(QwtAxis::YLeft,"Y3 Left Axis");parasitePlot2->setAxisTitle(QwtAxis::YRight,"Y3 Right Axis");parasitePlot2->setAxisTitle(QwtAxis::XBottom,"X3 Bottom Axis");// 在第二个寄生绘图上添加曲线QColorcurColor2(192,43,149);// 紫色QwtPlotCurve*parasiteCurve2=newQwtPlotCurve("parasite sine Wave 2");parasiteCurve2->setSamples(generateSampleData(200,1000,4.3));parasiteCurve2->attach(parasitePlot2);parasiteCurve2->setPen(curColor2,1);parasiteCurve2->setRenderHint(QwtPlotItem::RenderAntialiased,true);// 刻度上色parasitePlot2->axisWidget(QwtAxis::YLeft)->setScaleColor(curColor2);parasitePlot2->axisWidget(QwtAxis::YRight)->setScaleColor(curColor2);parasitePlot2->axisWidget(QwtAxis::XBottom)->setScaleColor(curColor2);

两个寄生绘图叠加后的效果:

可以看到,图上有三套不同颜色的坐标轴,分别对应宿主绘图和两个寄生绘图。这在原版 Qwt 6.x 中是根本做不到的。

1.4 寄生绘图的层级关系

寄生绘图有明确的层级关系,决定了坐标轴的布局顺序:

  • 先添加的寄生绘图处于低层级,其坐标轴靠近宿主绘图
  • 后添加的寄生绘图处于高层级,其坐标轴远离宿主绘图

布局时,宿主绘图先完成自身布局,然后从低层级到高层级依次布局寄生绘图的坐标轴。

1.5 坐标轴共享配置

通过setParasiteShareAxis()方法,可以让寄生绘图与宿主绘图共享某个坐标轴。共享后,该轴的刻度范围会自动同步:

// 寄生绘图的 X 轴与宿主共享parasitePlot->setParasiteShareAxis(QwtAxis::XBottom);

这在 X 轴代表时间等公共维度时非常有用——多个 Y 轴各自独立,但共享同一条 X 轴。

1.6 生命周期管理与遍历

生命周期:寄生绘图的生命周期与宿主绘图绑定。宿主绘图销毁时,所有寄生绘图自动销毁,无需手动管理。

判断与遍历:通过以下方法可以区分和获取绘图对象:

// 判断是否为宿主/寄生绘图boolisHost=plot->isHostPlot();boolisParasite=plot->isParasitePlot();// 获取宿主绘图(在寄生绘图上调用)QwtPlot*host=parasitePlot->hostPlot();// 获取所有寄生绘图(在宿主绘图上调用)QList<QwtPlot*>parasites=hostPlot->parasitePlots();// 获取所有绘图列表(宿主 + 寄生,在任何绘图上调用均可)constQList<QwtPlot*>plotList=plot->plotList();// plotList[0] 是宿主绘图本身for(QwtPlot*p:plotList){constQwtPlotItemList&items=p->itemList();for(QwtPlotItem*item:items){// 遍历所有绘图项}}

注意:一个绘图不会既是寄生绘图又是宿主绘图。在寄生绘图上调用createParasitePlot()将返回nullptr


二、QwtFigure —— 多绘图布局容器

2.1 类似 matplotlib Figure 的概念

如果说寄生绘图解决的是"一个画布上多套坐标轴"的问题,那么QwtFigure解决的就是"一个窗口里多个子图"的问题。

QwtFigure是一个类似 matplotlibFigure的容器窗口,用于组织和管理多个QwtPlot组件。它提供了两种布局方式:归一化坐标布局和网格布局。

2.2 归一化坐标布局

归一化坐标就是以[0, 1]范围的百分比来定位子图,遵循 Qt 标准的左上角坐标系:

QwtFigure*figure=newQwtFigure();figure->setSizeInches(8,6);// 设置图形尺寸为 8x6 英寸figure->setFaceColor(Qt::white);// 设置背景色QwtPlot*plot1=newQwtPlot();// 添加到左上角四分之一区域figure->addAxes(plot1,QRectF(0.0,0.0,0.5,0.5));// 或者使用分离参数形式QwtPlot*plot2=newQwtPlot();figure->addAxes(plot2,0.5,0.0,0.5,0.5);// 右上角

四个参数依次是:x, y, width, height,均为占整个 Figure 窗口的百分比。

2.3 网格布局(类似 subplot)

如果你熟悉 matplotlib 的subplot,那么 QwtFigure 的网格布局会让你感到亲切:

// 3x2 网格,第1行第0列(0-based)QwtPlot*plot3=newQwtPlot();figure->addGridAxes(plot3,3,2,1,0);// 3x2 网格,第1行第1列QwtPlot*plot4=newQwtPlot();figure->addGridAxes(plot4,3,2,1,1);// 3x2 网格,第2行,跨2列QwtPlot*hostPlot=newQwtPlot();figure->addGridAxes(hostPlot,3,2,2,0,1,2);

addGridAxes的参数含义:(plot, totalRows, totalCols, row, col, rowSpan, colSpan),其中rowSpancolSpan可选,用于跨行跨列。

下面是一个综合使用归一化坐标和网格布局的完整示例效果:

2.4 坐标轴对齐功能

当多个子图的 Y 轴刻度范围差异较大时,画布的水平边界可能不对齐,视觉上不够整齐:

QwtFigure 提供了addAxisAlignment()方法来解决这个问题:

// plot1、plot3、hostPlot 的左坐标轴对齐figure->addAxisAlignment({plot1,plot3,hostPlot},QwtAxis::YLeft);// plot2、plot4 的左坐标轴对齐figure->addAxisAlignment({plot2,plot4},QwtAxis::YLeft);

对齐后,相关子图的画布边界会自动调整到同一水平线:

注意:只有可见的坐标轴才能对齐。如果某个子图的对应坐标轴未显示,则无法参与对齐。

2.5 交互式操作蒙版:QwtFigureWidgetOverlay

QwtFigure 还提供了一个交互式操作蒙版QwtFigureWidgetOverlay,允许用户在运行时通过鼠标拖拽来调整子绘图的位置和大小,类似于可视化设计器中的操作体验。

QwtFigure*figure=newQwtFigure();// ... 添加子绘图 ...// 创建并显示操作蒙版QwtFigureWidgetOverlay*overlay=newQwtFigureWidgetOverlay(figure);overlay->show();

运行效果如下:

蒙版提供两项核心功能,可通过枚举控制:

enumBuiltInFunctionsFlag{FunSelectCurrentPlot=1,// 选择当前绘图FunResizePlot=2// 调整绘图大小};

启用/禁用特定功能:

// 只保留选择功能,禁用尺寸调整overlay->setBuiltInFunctionsEnable(QwtFigureWidgetOverlay::FunResizePlot,false);

自定义蒙版外观:

overlay->setBorderPen(QPen(Qt::red,2,Qt::DashLine));overlay->setControlPointBrush(QBrush(Qt::green));overlay->setControlPointSize(QSize(10,10));overlay->showPercentText(false);// 隐藏百分比文本

蒙版还提供两个有用的信号:widgetNormGeometryChanged()(子图几何尺寸变化)和activeWidgetChanged()(当前激活子图变化),方便你响应用户操作。


三、绘图布局调整

无论是单绘图还是多绘图场景,QwtPlotLayout都是控制绘图内部空间分配的核心引擎。它负责组织标题、图例、坐标轴和画布区域的位置与大小。

3.1 画布边距

画布边距控制画布与坐标轴之间的空白:

QwtPlotLayout*layout=plot->plotLayout();// 设置所有坐标轴的画布边距为 10 像素layout->setCanvasMargin(10);// 仅设置左侧 Y 轴的画布边距layout->setCanvasMargin(15,QwtAxis::YLeft);

3.2 组件间距与画布对齐

// 组件(标题、画布、图例、页脚)之间的间距layout->setSpacing(8);// 画布与坐标轴刻度对齐(默认开启)layout->setAlignCanvasToScales(true);// 也可以按轴单独控制layout->setAlignCanvasToScale(QwtAxis::XBottom,true);layout->setAlignCanvasToScale(QwtAxis::YLeft,false);

对齐模式下,画布边界与刻度线精确对齐;不对齐模式下,画布保持固定大小,刻度标签完整显示。

3.3 图例位置

// 图例放在右侧,占 20% 宽度layout->setLegendPosition(QwtPlot::RightLegend,0.2);// 图例放在底部layout->setLegendPosition(QwtPlot::BottomLegend);
位置枚举说明
QwtPlot::LeftLegend图例在 YLeft 轴左侧
QwtPlot::RightLegend图例在 YRight 轴右侧
QwtPlot::BottomLegend图例在页脚下方
QwtPlot::TopLegend图例在标题上方

3.4 寄生绘图的轴边距

对于寄生绘图,坐标轴之间的间距通过QwtScaleWidget的两个属性控制:

  • margin:坐标轴靠近画布一侧到画布的距离,默认 0(紧贴画布)
  • edgeMargin:坐标轴靠近绘图边界一侧到边界的距离,默认 0(紧贴边框)

添加寄生轴后,在显示前应手动调用updateAllAxisEdgeMargin()自动计算各层轴的间距,避免重叠:

hostPlot->updateAllAxisEdgeMargin();

该函数会遍历宿主及所有寄生轴,逐层计算 margin 和 edgeMargin,使各层坐标轴均匀分布。


四、与原版 Qwt 6.x 的区别

这是很多读者关心的问题,下面做一个对比总结:

特性原版 Qwt 6.xQwt 7.0
坐标轴数量固定 4 个(上下左右)任意多个(寄生绘图叠加)
多绘图布局容器无(需手动用 QLayout 管理)QwtFigure 容器,支持归一化坐标和网格布局
坐标轴对齐addAxisAlignment() 自动对齐
交互式布局调整QwtFigureWidgetOverlay 蒙版
多 Y 轴场景需要复杂的 hack原生支持,API 简洁

寄生绘图和 QwtFigure 都是 Qwt 7.0 全新引入的功能,原版 Qwt 6.x 完全不支持。这是 7.0 最重要的架构创新之一,借鉴了 matplotlib 的设计理念,但完全基于 Qt 原生组件实现,性能和集成度更好。


五、总结

本文介绍了 Qwt 7.0 的两大布局利器:

  1. 寄生绘图:通过createParasitePlot()在同一画布上叠加任意多套独立坐标轴,完美解决多 Y 轴、多量级数据的可视化需求。寄生绘图与宿主绘图共享画布、独立坐标系、生命周期自动管理。

  2. QwtFigure 容器:类似 matplotlib Figure 的多绘图布局容器,支持归一化坐标定位和网格布局,还能通过addAxisAlignment()实现子图坐标轴对齐,配合QwtFigureWidgetOverlay蒙版实现交互式布局调整。

这两个功能让 Qwt 7.0 在多轴、多图场景下的能力大幅跃升,从"够用"走向"好用"。

系列文章

系列总述:Qwt 7.0 —— 基于 Qt 的高性能 2D/3D 绘图库

  • 第 1 篇:快速入门与核心新特性概览
  • 第 2 篇:曲线绘图详解 —— 从基础到百万级数据性能优化
  • 第 3 篇:常用图表类型实战 —— 柱状图、散点图、箱线图与直方图
  • 第 4 篇:高级科学图表 —— 光谱图、向量场、K线图与极坐标绘图
  • 第 5 篇:多坐标轴与多绘图布局 —— 寄生绘图与 QwtFigure 容器
  • 第 6 篇:交互功能详解 —— 平移、缩放、坐标轴交互与数据拾取
  • 第 7 篇:3D 数据可视化 —— OpenGL 高性能三维绘图
  • 第 8 篇:坐标轴与刻度系统 —— 刻度引擎、网格、图例与刻度朝内
  • 第 9 篇:控件与辅助元素 —— 滑块旋钮、标记与装饰
  • 第 10 篇:总体架构解析 —— 从单体到三库模块化的演进
  • 第 11 篇:matplotlib 风格绘图 —— QwtPyPlot 接口详解

相关链接

  • 项目地址:https://github.com/czyt1988/QWT
  • Gitee 镜像:https://gitee.com/czyt1988/QWT
  • 在线文档:https://czyt1988.github.io/QWT/zh/
  • 系列总述:https://blog.csdn.net/czyt1988/article/details/160193393
http://www.jsqmd.com/news/1125704/

相关文章:

  • 入门级降噪耳机怎么选:从通勤、会议和续航看 5 款值得关注的产品
  • 嵌入式八股文 第一期
  • Perplexity vs 秘塔AI vs Google SGE:三大AI搜索引擎横评
  • 四类芯片对比(一)
  • UNY Finance生态航母再扩容,UNY Bet(UNY预测)即将上线!
  • 通产美伦MB8010能量平台运维质控实操方案分享
  • 【极简监控·番外篇】被逼无奈的“降维打击”:Java Remote Debug 救火指南
  • MongoDB 大数据备份,新手教程
  • Git脏树(Dirty Tree)介绍(指工作目录中存在未提交修改的状态)已修改、未跟踪、git status、线上线下不一致问题
  • Gateway API:Ingress 的下一代替代方案
  • UE4 SceneCaptureComponent2D 实战:3步实现UI内3D模型360°预览(附蓝图)
  • 教育学论文降AI工具免费推荐:2026年教育学毕业论文AIGC超标4.8元亲测99.26%知网完整方案
  • CodaYun 一站式浏览器工作台:开发者 设计师专属效率解决方案
  • C++中的String的常用函数用法
  • 【算法从零到千】【32-41】位运算(详细讲解+题目运用)
  • Allegro 生产文件导出:Gerber 274X 与钻孔文件 5 步标准化检查清单
  • 羽球联盟 HarmonyOS NEXT 实战系列 (03/20):四Tab首页容器与资讯首屏搭建
  • Agentic AI:换个角度,从问题拆解到交付验证
  • 史上最简单!sirpdboy固件一键搞定软路由刷机、调试、扩容,彻底告别麻烦!
  • 多模态大模型架构的收敛与分化:从Transformer到模态定制
  • 全局光照/阴影的几个常见问题
  • Linux指令实战学习之内存泄漏
  • 堪萨斯大学新研究:揭示读唇出错原因,有望提升读唇训练与AI转录能力
  • 小模型回到电脑本地,数据安全就自动解决了吗?
  • 1D-CNN 轴承故障诊断实战:CWRU 数据集 6 类识别准确率达 99.2%
  • 小米寥寥几家车企设计汽车顶棚
  • 数智驱动 全域增长:劲捷KINGJOY的跨界突围与全域增长之路
  • 一颗Codec芯片的生存法则:为什么AI语音产品需要TP9311?
  • Agent 需要拦截模型调用?用 Middleware 给它加个“拦截器“!
  • 图像哈希算法(aHash/dHash/pHash)Python实战:3种方法对比与汉明距离阈值调优指南