QCPColorMap实现瀑布图

发布于:2023-01-04 ⋅ 阅读:(952) ⋅ 点赞:(0)

因为项目需要用qt实现瀑布图效果,参考过很多博主的经验,效果图下图

 来源

QCustomPlot之瀑布图(十五)_梁如风的博客-CSDN博客_qcustomplot 瀑布图

第一种类型的瀑布图实现了,大小固定,只是每个cell上的数据不一样,所以思路如该博主所述,每次更新cell数据即可。

第二种类型的瀑布图更符合我的项目需求,但是一直没有找到合适的实现方式。

来源利用QCustomePlot绘制热力图,瀑布图,频谱色图等_尘埃飞舞的博客-CSDN博客_qcustomplot频谱图

深入研究博主的思路发现,这种也不是我想要的瀑布图,因为显示范围依旧是固定的,只是不断新增数据,看起来像是瀑布效果

而实际我需要的是下面的效果,随着新数据到来,不断的对原图进行填充,超出一定显示范围后进行滚动

 下面来说一下实现思路

  1. 创建QCPColorMap对象,绑定到对应的QCustomplot对象上
  2. 设置QCustomplot对象的显示显示范围和显示长度
  3. 给QCPColorMap对象新增数据,设置自适应坐标
  4. 重绘QCustomplot对象
  5. 重复2-4步骤

实现代码如下

void MainWindow::updateMapData(QCustomPlot *plot,QVector<QVector<double>>z,QString xlabel,QString ylabel,QString name,double showLen)
{
    plot->setInteractions(QCP::iRangeZoom | QCP::iSelectPlottables);
    int tlen = z.size();
    int flen = z[0].size();

    plot->xAxis->setLabel(xlabel);//x轴显示文字
    plot->yAxis->setLabel(ylabel);//y轴显示文字

    plot->xAxis->setRange(z.last().at(0),z.last().at(1));
    plot->yAxis->setRange(z.last().at(4)<showLen?0:z.last().at(4)-showLen,showLen,Qt::AlignLeft);

    if(plot->plottableCount() < 2){
        //通过传递的轴的QCustomPlot进行注册,简洁理解QCPColorMap的数据为(x轴,y轴;颜色,值value)
        QCPColorMap *m_pColorMap = new QCPColorMap(plot->xAxis,plot->yAxis);
        m_pColorMap->data()->setSize(flen,tlen-1);//设置整个图(x,y)点数
        m_pColorMap->data()->setRange(QCPRange(z.last().at(0),z.last().at(1)),QCPRange(0,z.last().at(5)));//setRange是设置X轴以及Y轴的范围
        for(int x=0;x<tlen-1;x++)
        {
            for(int y=0;y<flen;y++)
            {
                m_pColorMap->data()->setCell(y,x,z[x][y]);
            }
        }
        m_pColorMap->rescaleDataRange(true);
    }else{
        auto *colorMap = static_cast<QCPColorMap *>(plot->plottable(plot->plottableCount()-1));
        int valueSize = colorMap->data()->valueSize();

        colorMap->data()->setSize2(flen,valueSize+tlen-1);//设置整个图(x,y)点数
        colorMap->data()->setRange(QCPRange(z.last().at(0),z.last().at(1)),QCPRange(0,z.last().at(5)));//setRange是设置X轴以及Y轴的范围
        for(int x=0;x<tlen-1;x++)
        {
            for(int y=0;y<flen;y++)
            {
                colorMap->data()->setCell(y,valueSize+x,z[x][y]);
            }
        }
        colorMap->rescaleDataRange(true);
    }
    plot->replot(QCustomPlot::rpQueuedReplot);
}

/*旧版本,通过新增QCPColorMap 对象实现*/
void MainWindow::updateMapData(QCustomPlot *plot,QVector<QVector<double>>z,QString xlabel,QString ylabel,QString name,bool zoom)
{
    plot->setInteractions(QCP::iRangeZoom | QCP::iSelectPlottables);
    int tlen = z.size();
    int flen = z[0].size();

    double showLen = ui->doubleSpinBox_showLen->value();
    plot->xAxis->setLabel(xlabel);//x轴显示文字
    plot->yAxis->setLabel(ylabel);//y轴显示文字
    if(zoom){
        double last_upper = plot->xAxis->range().upper;
        plot->xAxis->setRange(z.last().at(0),qMin(z.last().at(1),last_upper));
    }else{
        plot->xAxis->setRange(z.last().at(0),z.last().at(1));
    }
    plot->yAxis->setRange(z.last().at(4)<showLen?0:z.last().at(4)-showLen,showLen,Qt::AlignLeft);

    //通过传递的轴的QCustomPlot进行注册,简洁理解QCPColorMap的数据为(x轴,y轴;颜色,值value)
    QCPColorMap *m_pColorMap = new QCPColorMap(plot->xAxis,plot->yAxis);
    m_pColorMap->data()->setSize(flen,tlen-1);//设置整个图(x,y)点数
    m_pColorMap->data()->setRange(QCPRange(z.last().at(0),z.last().at(1)),QCPRange(z.last().at(4),z.last().at(5)));//setRange是设置X轴以及Y轴的范围

    for(int x=0;x<tlen-1;x++)
    {
        for(int y=0;y<flen;y++)
        {
            m_pColorMap->data()->setCell(y,x,z[x][y]);
        }
    }
    m_pColorMap->rescaleDataRange(true);
    plot->replot(QCustomPlot::rpQueuedReplot);
}

关键部分:通过判断QCustomplot对象的plottable个数,plottable(0)为graph本身

  • 小于2,创建QCPColorMap对象
  • 否则,找到已经存在的QCPColorMap,对其进行操作
    • 也就是进行之前所述的2-4步骤

需要注意的一点是QCPColorMap的reSize()函数调用后,会将原有的data进行初始化,也就是丢失掉原有数据,所以无法使用。

Qt——绘制瀑布图/热度图_kiwen_su的博客-CSDN博客_qchart瀑布图

if (sec_xAddTime >= sec_xAxisEndTime)//平;移;图
{
    int nx = sec_xAxisEndTime - sec_xAxisStartTime;//x轴上;的点;数

    sec_xAxisEndTime += nx;//向右;平移;nx秒
    sec_xAxisStartTime += nx;

    clearAllDatas();//清;空之;前的数;据
    ui.heatMap->xAxis->setRange(sec_xAxisStartTime, sec_xAxisEndTime);//x轴;范围
    m_pColorMap->data()->setSize(nx, len_maxHeight);//重;新;设;置;范围
    m_pColorMap->data()->setRange(QCPRange(sec_xAxisStartTime, sec_xAxisEndTime), QCPRange(0, len_maxHeight)); //(x,y)点对应;取值;范;围
    //QCPColorMapData *existData = m_pColorMap->data();
    //m_pColorMap->setData(existData, true);
    //m_pColorMap->data()->recalculateDataBounds();
    //m_pColorMap->rescaleDataRange(true);
}
uint x = sec_xAddTime - sec_xAxisStartTime;

for (int i = 0; i < (data.vec_Height.size()-1); i++)
{
    for (int y = data.vec_Height.at(i); y <= data.vec_Height.at(i+1); y++)
    {
        m_pColorMap->data()->setCell(x, y, data.vec_Value.at(i));//设;置;数据
    }
}

这位博主注释掉的4行代码就是想实现这个思路,但是由于resize之后,data已经为空,所以导致数据丢失,导致只有最后一行数据

在这里插入图片描述

官方注释如下:
Resizes the data array to have keySize cells in the key dimension and valueSize cells in the value dimension.
The current data is discarded and the map cells are set to 0, unless the map had already the requested size.

我的实现思路是重写resize函数,结果还是比较令人满意的,提供我的代码,仅供参考

重写QCustomplot库的reSize函数-C++文档类资源-CSDN下载


网站公告

今日签到

点亮在社区的每一天
去签到