QCustomPlot之轴矩形和轴(五)

轴矩形QCPAxisRect

轴矩形的作用主要有以下几种:

  • 背景绘制,所以轴矩形默认存在于background
  • 管理多个轴,并不仅限于上下左右四个轴
  • 图表的拖拽和缩放

先来看下轴矩形的构造函数,可以看到,轴矩形管理着上下左右四个方向的轴,同时当setupDefaultAxes为true时(默认为true)时,将会添加上下左右四个轴,并且设置下轴(x轴)和左轴(y轴)为拖拽和缩放时影响的轴

QCPAxisRect::QCPAxisRect(QCustomPlot *parentPlot, bool setupDefaultAxes)
    : QCPLayoutElement(parentPlot),
      mBackgroundBrush(Qt::NoBrush),
      mBackgroundScaled(true),
      mBackgroundScaledMode(Qt::KeepAspectRatioByExpanding),
      mInsetLayout(new QCPLayoutInset),
      mRangeDrag(Qt::Horizontal | Qt::Vertical),           // 水平和竖直方向都可以拖拽
      mRangeZoom(Qt::Horizontal | Qt::Vertical),           // 水平和竖直方向都可以缩放
      mRangeZoomFactorHorz(0.85),                          // 水平缩放比例
      mRangeZoomFactorVert(0.85),                          // 竖直缩放比例
      mDragging(false)
{
    // 其余无关代码

    mAxes.insert(QCPAxis::atLeft, QList<QCPAxis*>());
    mAxes.insert(QCPAxis::atRight, QList<QCPAxis*>());
    mAxes.insert(QCPAxis::atTop, QList<QCPAxis*>());
    mAxes.insert(QCPAxis::atBottom, QList<QCPAxis*>());

    if (setupDefaultAxes) {
        QCPAxis *xAxis = addAxis(QCPAxis::atBottom);
        QCPAxis *yAxis = addAxis(QCPAxis::atLeft);
        QCPAxis *xAxis2 = addAxis(QCPAxis::atTop);
        QCPAxis *yAxis2 = addAxis(QCPAxis::atRight);
        setRangeDragAxes(xAxis, yAxis);                        // 设置拖拽时影响的轴
        setRangeZoomAxes(xAxis, yAxis);                        // 设置缩放时影响的轴
        
        // 其余无关代码
    }
}

于是我们可以知道,轴矩形是怎么影响图表的拖拽和缩放的:

  1. mRangeDrag、mRangeZoom作用的方向,由setRangeDrag和setRangeZoom函数设置
  2. setRangeDragAxes和setRangeZoomAxes函数设置的拖拽和缩放时影响的轴(可以是多个轴)

同时轴矩形还提供了函数zoom函数,可以很方便的实现矩形框选缩放的功能

轴QCPAxis

轴的作用主要是:决定图表的范围

轴主要由四部分组成:

  • 轴线及刻度线
  • 轴刻度文字
  • 轴标签
  • 网格线

QCPAxis可以为多个图表所共有,同时它提供了非常丰富的接口用于设置上述组成部分的风格,QCustomPlot之个性化外观(二)的内容

QCustomPlot还为我们提供了几种默认的轴(ticker, 其实是用于产生刻度和刻度文字的):

  • QCPAxisTickerFixed // 固定步进的轴
  • QCPAxisTickerLog // log轴
  • QCPAxisTickerPi // Pi轴
  • QCPAxisTickerText // 文字轴
  • QCPAxisTickerDateTime // 日期轴
  • QCPAxisTickerTime // 时间轴

使用setTicker函数设置相应的ticker就可以了

多种轴类型

setNumberFormat函数的介绍:用于轴标签文字的显示格式,可以由以下三个字符组成

  • 第一个字符可以为:'e'/'E'、'g'/'G'、'f',这里使用了Qt的显示风格
  • 第二个字符必须为:'b',当且仅当第一个字符为'e'(科学计数法)或者'g'(精度为最大有效位数)时才有效,b即beautiful,可以让轴刻度文字看起来更好看
  • 第三个字符可以为:'c'(cross)、'd'(dot),即表现为乘号或者点

总结

  • 轴矩形可以拥有多个轴
  • 多个图表可以共用一个轴
  • QCustomPlot可以存在多个轴矩形,因为轴矩形继承自QCPLayoutElement
void MainWindow::setupAdvancedAxesDemo(QCustomPlot *customPlot)
{
    demoName = "Advanced Axes Demo";

    customPlot->plotLayout()->clear();   // 首先清空默认的轴矩形,让我们从头开始
    QCPAxisRect *wideAxisRect = new QCPAxisRect(customPlot, true);   // 还记得setupDefaultAxes为true时的作用吗,忘了的话翻上去看吧
    wideAxisRect->setupFullAxesBox(true);    // 让四个轴关联,并全部显示出来
    wideAxisRect->addAxis(QCPAxis::atLeft)->setTickLabelColor(QColor("#6050F8"));  // 在左边多添加一个轴并且设置它的颜色

    QCPLayoutGrid *subLayout = new QCPLayoutGrid;
    customPlot->plotLayout()->addElement(0, 0, wideAxisRect);     // 在第一行添加轴矩形
    customPlot->plotLayout()->addElement(1, 0, subLayout);        // 在第二行添加一个子布局,后面会添加两个轴矩形在里面

    QCPAxisRect *subRectLeft = new QCPAxisRect(customPlot, false);   // 不配置轴
    QCPAxisRect *subRectRight = new QCPAxisRect(customPlot, false);

    // 让右边的轴矩形固定大小
    subRectRight->setMaximumSize(100, 100);
    subRectRight->setMinimumSize(100, 100);

    subLayout->addElement(0, 0, subRectLeft);                      // 在第一列添加轴矩形
    subLayout->addElement(0, 1, subRectRight);                     // 在第二列添加轴矩形

    subRectLeft->addAxes(QCPAxis::atBottom | QCPAxis::atLeft);     // 添加下轴和左轴
    subRectRight->addAxes(QCPAxis::atBottom | QCPAxis::atRight);   // 添加下轴和右轴
    subRectLeft->axis(QCPAxis::atLeft)->ticker()->setTickCount(2); // 设置轴的刻度为一个固定的步进值
    subRectRight->axis(QCPAxis::atRight)->ticker()->setTickCount(2);
    subRectLeft->axis(QCPAxis::atBottom)->grid()->setVisible(true);

    // 保持一个好的习惯,将它们放置在相应的层
    foreach (auto *rect, customPlot->axisRects()) {
        foreach (auto *axis, rect->axes()) {
            axis->setLayer("axes");
            axis->grid()->setLayer("grid");
        }
    }

    // 准备数据
    QVector<QCPGraphData> dataCos(21), dataGauss(50), dataRandom(100);
    QVector<double> x3, y3;
    qsrand(3);
    for (int i=0; i<dataCos.size(); ++i) {
        dataCos[i].key = i/(double)(dataCos.size()-1)*10-5.0;
        dataCos[i].value = qCos(dataCos[i].key);
    }
    for (int i=0; i<dataGauss.size(); ++i) {
        dataGauss[i].key = i/(double)dataGauss.size()*10-5.0;
        dataGauss[i].value = qExp(-dataGauss[i].key*dataGauss[i].key*0.2)*1000;
    }
    for (int i=0; i<dataRandom.size(); ++i) {
        dataRandom[i].key = i/(double)dataRandom.size()*10;
        dataRandom[i].value = qrand()/(double)RAND_MAX-0.5+dataRandom[qMax(0, i-1)].value;
    }
    x3 << 1 << 2 << 3 << 4;
    y3 << 2 << 2.5 << 4 << 1.5;

    // mainGraphCos和 mainGraphGauss 共享下轴,但是它们的左轴不同
    QCPGraph *mainGraphCos = customPlot->addGraph(wideAxisRect->axis(QCPAxis::atBottom), wideAxisRect->axis(QCPAxis::atLeft));
    mainGraphCos->data()->set(dataCos);
    mainGraphCos->valueAxis()->setRange(-1, 1);
    mainGraphCos->rescaleKeyAxis();
    mainGraphCos->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, QPen(Qt::black), QBrush(Qt::white), 6));
    mainGraphCos->setPen(QPen(QColor(120, 120, 120), 2));

    QCPGraph *mainGraphGauss = customPlot->addGraph(wideAxisRect->axis(QCPAxis::atBottom), wideAxisRect->axis(QCPAxis::atLeft, 1));
    mainGraphGauss->data()->set(dataGauss);
    mainGraphGauss->setPen(QPen(QColor("#8070B8"), 2));
    mainGraphGauss->setBrush(QColor(110, 170, 110, 30));
    mainGraphCos->setChannelFillGraph(mainGraphGauss);
    mainGraphCos->setBrush(QColor(255, 161, 0, 50));
    mainGraphGauss->valueAxis()->setRange(0, 1000);
    mainGraphGauss->rescaleKeyAxis();

    QCPGraph *subGraphRandom = customPlot->addGraph(subRectLeft->axis(QCPAxis::atBottom), subRectLeft->axis(QCPAxis::atLeft));
    subGraphRandom->data()->set(dataRandom);
    subGraphRandom->setLineStyle(QCPGraph::lsImpulse);
    subGraphRandom->setPen(QPen(QColor("#FFA100"), 1.5));
    subGraphRandom->rescaleAxes();

    QCPBars *subBars = new QCPBars(subRectRight->axis(QCPAxis::atBottom), subRectRight->axis(QCPAxis::atRight));
    subBars->setWidth(3/(double)x3.size());
    subBars->setData(x3, y3);
    subBars->setPen(QPen(Qt::black));
    subBars->setAntialiased(false);
    subBars->setAntialiasedFill(false);
    subBars->setBrush(QColor("#705BE8"));
    subBars->keyAxis()->setSubTicks(false);
    subBars->rescaleAxes();

    // 给柱状图一个固定步进轴
    QSharedPointer<QCPAxisTickerFixed> intTicker(new QCPAxisTickerFixed);
    intTicker->setTickStep(1.0);
    intTicker->setScaleStrategy(QCPAxisTickerFixed::ssMultiples);
    subBars->keyAxis()->setTicker(intTicker);
}
多个轴与多个轴矩形的效果图
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351

推荐阅读更多精彩内容

  • 文章转载自:https://github.com/tuteng/MPAndroidCharthttps://git...
    no白菜阅读 5,132评论 0 8
  • d3 (核心部分)选择集d3.select - 从当前文档中选择一系列元素。d3.selectAll - 从当前文...
    谢大见阅读 3,439评论 1 4
  • 参考资料:Plotly_express官方API教程、Plotly_express官方画图教程 一、概述 Plot...
    惑也阅读 50,587评论 4 57
  • 构建一个学习算法的推荐方法为: 从一个简单的能快速实现的算法开始,实现该算法并用交叉验证集数据测试这个算法 绘制学...
    dreampai阅读 176评论 0 1
  • 今天在楼下遛弯儿的时候看见一条狗,然后和狗主人聊了会儿,他说狗狗是领养的,但是程序非常正规,狗狗该做的一些疫苗都做...
    CAT_BROOKLYN阅读 133评论 0 0