Qt QCustomPlot 绘制子轴

抄大神杰作:QCustomplot(五)QCPAxisRect进行子绘图-CSDN博客

需求来源:试验数据需要多轴对比。

实现多Y轴、单X轴、X轴是时间轴、X轴range联动、rect之间的间距是0,每个图上有legend(这里有个疑问,每添加个rect在这个rect上添加graph,再添加legend,第一个rect上就有多个legend,其他rect上就只有一个。);

实现多Y轴、多X轴,x轴不联动。

频谱图,多Y轴,单X轴

关键代码如下,请大佬们多多指正:

//时域图
void MultiAxisWidget::recvRawData(int iRow, QString oStrLabel, QVector<double> adX, QVector<double> adY)
{
    QCPAxisRect* poAxisRect = new QCPAxisRect(ui->plot);
    poAxisRect->setAutoMargins(QCP::msNone);
    poAxisRect->setMargins(QMargins(100, 0, 0, 0));

    ui->plot->plotLayout()->addElement(iCntIndex, 0, poAxisRect);

    QCPAxis* poAxisX = poAxisRect->axis(QCPAxis::atBottom);
    QCPAxis* poAxisY = poAxisRect->axis(QCPAxis::atLeft);

    poAxisX->setVisible(false);

    poAxisY->grid()->setZeroLinePen(QPen(Qt::red));

    poAxisX->grid()->setSubGridVisible(true);
    poAxisY->grid()->setSubGridVisible(true);

    QList<QCPAxis*> aaxisField;
    aaxisField << poAxisX;
    poAxisRect->setRangeZoomAxes(aaxisField);

    poAxisY->setVisible(true);
    poAxisY->setLabel("振幅(mV)");

    auto poGraph = ui->plot->addGraph(poAxisX, poAxisY);

    poGraph->setName(oStrLabel);
    poGraph->setData(adX, adY);
    poGraph->setLineStyle(QCPGraph::lsLine);
    poGraph->setPen(QPen(Qt::blue, 2));

    poGraph->rescaleKeyAxis(true);
    poGraph->rescaleValueAxis(true, true);
    poGraph->rescaleAxes();

    auto poThread = new QThread;
    poGraph->setParent(nullptr);
    poGraph->moveToThread(poThread);
    poGraph->setVisible(true);

    QPair<QCPAxisRect*, QCPGraph*> pairContent(poAxisRect, poGraph) ;

    aopContent.append(pairContent);

    ++iCntIndex;

    QSharedPointer<QCPAxisTickerDateTime> dateTicker(new QCPAxisTickerDateTime);//日期做X轴
    dateTicker->setDateTimeFormat("HH:mm:ss");//日期格式(可参考QDateTime::fromString()函数)
    dateTicker->setTickCount(12);

    switch(eAxisType)
    {
        case AXIS_X_M:
            poAxisRect->setAutoMargins(QCP::msBottom);
            poAxisX->setVisible(true);
            poAxisX->setTicker(dateTicker);//设置X轴为时间轴

            break;

        case AXIS_X_S:

            if(iCntIndex == iCnt)
            {
                poAxisRect->setAutoMargins(QCP::msBottom);
                poAxisX->setVisible(true);
                poAxisX->setTicker(dateTicker);//设置X轴为时间轴

                QTimer::singleShot(1000, this, [ = ]()
                {
                    this->linkage();
                });
            }
            break;
    }

    if(iCntIndex == iCnt)
    {
        for(QPair<QCPAxisRect*, QCPGraph*> pairContent : aopContent)
        {
            QCPLegend* poLegend = new QCPLegend;
            pairContent.first->insetLayout()->addElement(poLegend, Qt::AlignTop | Qt::AlignRight);
            poLegend->setLayer("legend");
            poLegend->addItem(new QCPPlottableLegendItem(poLegend, pairContent.second));
        }
    }

    ui->plot->replot();
}

//频谱图
void MultiAxisWidget::recvSpectrum(QString oStrLabel, QVector<double> x, QVector<double> y, QList<double> adTargetF)
{
    QCPAxisRect* poAxisRect = new QCPAxisRect(ui->plot);
    poAxisRect->setAutoMargins(QCP::msNone);
    poAxisRect->setMargins(QMargins(100, 0, 0, 0));

    ui->plot->plotLayout()->addElement(iCntIndex, 0, poAxisRect);

    QCPAxis* poAxisX = poAxisRect->axis(QCPAxis::atBottom);
    QCPAxis* poAxisY = poAxisRect->axis(QCPAxis::atLeft);

    poAxisX->setVisible(false);

    QList<QCPAxis*> aaxisField;
    aaxisField << poAxisX;
    poAxisRect->setRangeZoomAxes(aaxisField);

    poAxisX->setLabel("频率(Hz)");          //X轴文字显示
    poAxisY->setLabel("振幅(mV)");          //Y轴文字显示

    poAxisY->grid()->setZeroLinePen(QPen(Qt::red));

    poAxisX->setRangeReversed(true);
    poAxisX->setScaleType(QCPAxis::stLogarithmic);
    poAxisY->setScaleType(QCPAxis::stLogarithmic);

    ui->plot->xAxis->grid()->setSubGridVisible(true);
    poAxisY->grid()->setSubGridVisible(true);

    auto poGraph = ui->plot->addGraph(poAxisX, poAxisY);

    poGraph->setName(oStrLabel);
    poGraph->setData(x, y);
    poGraph->setLineStyle(QCPGraph::lsLine);
    poGraph->setPen(QPen(Qt::blue, 2));

    poGraph->rescaleKeyAxis(true);
    poGraph->rescaleValueAxis(true, true);
    poGraph->rescaleAxes();

    auto poThread = new QThread;
    poGraph->setParent(nullptr);
    poGraph->moveToThread(poThread);
    poGraph->setVisible(true);

    for(int i = 0; i < adTargetF.count(); i++)
    {
        QCPItemTracer* poTracer = new QCPItemTracer(ui->plot);

        poTracer->setGraphKey(adTargetF.at(i));
        poTracer->setInterpolating(false);
        poTracer->setStyle(QCPItemTracer::tsCircle);
        poTracer->setPen(QPen(Qt::yellow));
        poTracer->setBrush(Qt::red);
        poTracer->position->setType(QCPItemPosition::ptPlotCoords);
        poTracer->setSize(8);

        poTracer->setClipAxisRect(poAxisRect);//设置裁剪的坐标轴
        poTracer->setGraph(poGraph);

        QCPItemStraightLine* poLine = new QCPItemStraightLine(ui->plot);

        poLine->setPen(QPen(Qt::red, 0.5, Qt::DotLine));
        //垂直参考线,就是两点一线
        //m_pHorReffer_DG->setClipToAxisRect(false);//裁剪,让外部也要看到
        poLine->setClipAxisRect(poAxisRect);//设置裁剪的坐标轴
        poLine->point1->setAxes(poAxisRect->axis(QCPAxis::atBottom), poAxisRect->axis(QCPAxis::atLeft)); //绑定坐标
        poLine->point2->setAxes(poAxisRect->axis(QCPAxis::atBottom), poAxisRect->axis(QCPAxis::atLeft));

        poLine->point1->setCoords(adTargetF.at(i), 1);
        poLine->point2->setCoords(adTargetF.at(i), 2);
    }

    QPair<QCPAxisRect*, QCPGraph*> pairContent(poAxisRect, poGraph) ;

    aopContent.append(pairContent);

    ++iCntIndex;

    if(iCntIndex == iCnt)
    {
        poAxisRect->setAutoMargins(QCP::msBottom);

        QSharedPointer<QCPAxisTickerText> textTicker = QSharedPointer<QCPAxisTickerText>(new QCPAxisTickerText);
        textTicker.data()->clear();

        foreach(double dF, adTargetF)
        {
            textTicker->addTick(dF, QString("%1").arg(dF));
        }

        poAxisX->setTicker(textTicker);

        poAxisX->setTickLabelRotation(34.38);

        poAxisX->setVisible(true);

        QTimer::singleShot(1000, this, [ = ]()
        {
            this->linkage();
        });

        for(QPair<QCPAxisRect*, QCPGraph*> pairContent : aopContent)
        {
            QCPLegend* poLegend = new QCPLegend;
            pairContent.first->insetLayout()->addElement(poLegend, Qt::AlignTop | Qt::AlignRight);
            poLegend->setLayer("legend");
            poLegend->addItem(new QCPPlottableLegendItem(poLegend, pairContent.second));
        }
    }

    ui->plot->replot();
}

//多  x轴联动
void MultiAxisWidget::linkage()
{
    for(QPair<QCPAxisRect*, QCPGraph*> pairContent : aopContent)
    {
        for(QPair<QCPAxisRect*, QCPGraph*> pairContentOther : aopContent)
        {
            if(pairContentOther.first == pairContent.first)
            {
                continue;
            }
            connect(pairContent.first->axis(QCPAxis::atBottom), QOverload<const QCPRange&>::of(&QCPAxis::rangeChanged),
                    pairContentOther.first->axis(QCPAxis::atBottom), QOverload<const QCPRange&>::of(&QCPAxis::setRange));
        }
    }

    //鼠标双击曲线,在颜色对话框中给被点击的曲线设置颜色
    connect(ui->plot, &QCustomPlot::plottableDoubleClick, this, [ = ](QCPAbstractPlottable * plottable, int dataIndex, QMouseEvent * event)
    {
        QColorDialog colorDialog;
        colorDialog.setCurrentColor(Qt::red);

        // 显示对话框
        int result = colorDialog.exec();

        // 检查用户是否选择了颜色
        if (result == QDialog::Accepted)
        {
            // 获取选择的颜色
            QColor selectedColor = colorDialog.selectedColor();

            plottable->setPen(QPen(selectedColor, 2));

            ui->plot->replot();
        }
    });

    ui->plot->replot();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/336611.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【⭐AI工具⭐】实用工具推荐

目录 壹 实用工具工具合集TinyWowHiPDF 公式处理SimpleTex公式中常用的希腊字母符号公式在论文中的格式 图像处理BgRemoverPix Fix像素蒸发Photopea 音频处理啦啦爱 笔记整理飞书妙记 素材整理Eagle 其它一次性临时电子邮件近邻词汇检索据意查句诗三百能不能好好说话&#xff1…

2023 年值得一读的技术文章 | NebulaGraph 技术社区

在之前的产品篇&#xff0c;我们了解到了 NebulaGraph 内核及周边工具在 2023 年经历了什么样的变化。伴随着这些特性的变更和上线&#xff0c;在【文章】博客分类中&#xff0c;一篇篇的博文记录下了这些功能背后的设计思考和研发实践。当中&#xff0c;既有对内存管理 Memory…

Python爬虫IP池

目录 一、介绍 1.1 为什么需要IP池&#xff1f; 1.2 IP池与代理池的区别 二、构建一个简单的IP池 三、注意事项 一、介绍 在网络爬虫的世界中&#xff0c;IP池是一个关键的概念。它允许爬虫程序在请求网页时使用多个IP地址&#xff0c;从而降低被封禁的风险&#xff0c;提高…

【大坑】MyBatisPlus使用updateById莫名将数据四舍五入了

问题描述 我目前在为本地的一所高中开发一个成绩分析的网站&#xff0c;后端使用的是SpringBootMyBatisPlus&#xff0c;业务逻辑是用户在前端上传EXCEL文件&#xff0c;后端从文件中读取成绩存到数据库用于分析。但是奇怪的是&#xff1a;在后端&#xff0c;进入数据库之前的…

DBA技术栈MongoDB: 索引和查询优化

2.1 批量插入数据 单条数据插入db.collection.insertOne()多条数据插入db.collection.insertMany() db.inventory.insertMany( [{ item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },{ item: "notebook"…

【MATLAB源码-第119期】基于matlab的GMSK系统1bit差分解调误码率曲线仿真,输出各个节点的波形以及功率谱。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 GMSK&#xff08;高斯最小频移键控&#xff09;是一种数字调制技术&#xff0c;广泛应用于移动通信&#xff0c;例如GSM网络。它是一种连续相位调频制式&#xff0c;通过改变载波的相位来传输数据。GMSK的关键特点是其频谱的…

vue3通过ref调用子组件方法,第一次点击报找不到该方法,ref和v-if冲突

通过ref实现父子组件通信&#xff0c;但在第一次点击按钮的时候报找不到子组件的方法 原因&#xff1a;ref和v-if冲突,ref只有在组件渲染完成才注册引用信息&#xff0c;v-if首次为false没有把元素或子组件渲染&#xff0c;所以没有注册引用信息。 父组件 <uni-popup ref…

GO 中高效 int 转换 string 的方法与高性能源码剖析

文章目录 使用 strconv.Itoa使用 fmt.Sprintf使用 strconv.FormatIntFormatInt 深入剖析1. 快速路径处理小整数2. formatBits 函数的高效实现 结论 Go 语言 中&#xff0c;将整数&#xff08;int&#xff09;转换为字符串&#xff08;string&#xff09;是一项常见的操作。 本文…

Peter算法小课堂—拓扑排序与最小生成树

拓扑排序 讲拓扑排序前&#xff0c;我们要先了解什么是DAG树。所谓DAG树&#xff0c;就是指“有向无环图”。请判断下列图是否是DAG图 第一幅图&#xff0c;它不是DAG图&#xff0c;因为它形成了一个环。第二幅图&#xff0c;它也不是DAG图&#xff0c;因为它没有方向。第三幅…

汽车加油问题(贪心)

问题描述&#xff1a; 一辆汽车加满油后可行驶n 公里。旅途中有若干个加油站。设计一个有效算法&#xff0c;指出应在哪些加油站停靠加油&#xff0c;使沿途加油次数最少。并证明算法能产生一个最优解。 编程任务&#xff1a; 对于给定的n 和k 个加油站位置&#xff0c;编程计算…

Harmony Ble蓝牙App(四)描述符

Harmony Ble蓝牙App&#xff08;四&#xff09;描述符 前言正文一、优化二、描述① 概念② 描述提供者③ 显示描述符 三、源码 前言 上一篇中了解了特性和属性&#xff0c;同时显示设备蓝牙服务下的特性和属性&#xff0c;本文中就需要来使用这些特性和属性来完成一些功能。 正…

设计模式--组合模式

缘起 某日&#xff0c;小明公司最近接到一个办公管理系统的项目&#xff0c;并且在每个城市都有分部。这属于是很常见的OA系统&#xff0c;只要前期将需求分析完善好&#xff0c;中后期开发维护是不难的。 然而&#xff0c;总部公司使用后觉得很OK&#xff0c;想要其他城市的…

softmax回实战

1.数据集 MNIST数据集 (LeCun et al., 1998) 是图像分类中广泛使用的数据集之一&#xff0c;但作为基准数据集过于简单。 我们将使用类似但更复杂的Fashion-MNIST数据集 (Xiao et al., 2017)。 import torch import torchvision from torch.utils import data from torchvisi…

STM32标准库开发—软件I2C读取MPU6050

软件模拟I2C时序 初始化I2C引脚以及时钟 void MyI2C_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_ModeGPIO_Mode_Out_OD;GPIO_InitStruct.GPIO_PinGPIO_Pin_10|GPIO_Pin_11;GPIO_InitStruct.G…

pearcmd文件包含漏洞

1.什么是pearcmd.php pecl是PHP中用于管理扩展而使用的命令行工具&#xff0c;而pear是pecl依赖的类库。在7.3及以前&#xff0c;pecl/pear是默认安装的&#xff1b;在7.4及以后&#xff0c;需要我们在编译PHP的时候指定--with-pear才会安装 不过&#xff0c;在Docker任意版本…

(菜鸟自学)Metasploit漏洞利用——ms08-067

&#xff08;菜鸟自学&#xff09;漏洞利用——ms08-067 漏洞简介利用nmapMSF软件对XP sp3系统进行渗透攻击设置exploit模块参数RHOSTRPORTSMBPIPEExploit Target 设置有效载荷查找可兼容的有效载荷 渗透测试VNC 漏洞简介 MS08-067 是指微软于2008年发布的一个安全漏洞&#x…

重学Java 10 面向对象

正是风雨欲来的时候&#xff0c;火却越烧越旺了 ——24.1.20 重点 1.为何使用面向对象思想编程 2.如何使用面向对象思想编程 3.何时使用面向对象思想编程 4.利用代码去描述世间万物的分类 5.在一个类中访问另外一个类中的成员 -> new对象 6.成员变量和局部变量的区别 一…

利用HTML+CSS+JS打造炫酷时钟网页的完整指南

引言 在现代Web开发中&#xff0c;制作一个引人注目的时钟网页是一种常见而令人愉悦的体验。本文将介绍如何使用HTML、CSS和JavaScript来创建一个炫酷的时钟网页&#xff0c;通过这个项目&#xff0c;你将学到如何结合这三种前端技术&#xff0c;制作一个动态且美观的时钟效果…

接口测试 02 -- JMeter入门到实战

前言 JM eter毕竟是做压测的工具&#xff0c;自动化这块还是有缺陷。 如果公司做一些简单的接口自动化&#xff0c;可以考虑使用JMeter快速完成&#xff0c;如果想做完善的接口自动化体系&#xff0c;建议还是基于Python来做。 为什么学习接口测试要先从JMeter开始&#xff1f;…

C语言数据结构——顺序表

&#xff08;图片由AI生成&#xff09; 0.前言 在程序设计的世界里&#xff0c;数据结构是非常重要的基础概念。本文将专注于C语言中的一种基本数据结构——顺序表。我们将从数据结构的基本概念讲起&#xff0c;逐步深入到顺序表的内部结构、分类&#xff0c;最后通过一个实…