0、說明
本節(jié)翻譯總結(jié)自:Qt Plotting Widget QCustomPlot - Basic Plotting
本節(jié)內(nèi)容是使用QCustomPlot進行基本繪圖。
本節(jié)教程都使用customPlot這個變量,它是一個指向QCustomPlot實例的指針,當然,在我們的項目中,我們更可能是通過ui->customPlot來訪問這些QCustomPlot實例。
1、基本用法
1.1、創(chuàng)建新畫布
customPlot -> addGraph();
每個Graph及其上的線構(gòu)成一幅圖。
1.2、給畫布分配數(shù)據(jù)點
customPlot->graph(0)->setData(x,y)
x、y是大小相等的一組數(shù)據(jù),其中x中存儲的是橫坐標,y中存儲的是縱坐標。
1.3、軸
假設(shè)我們有兩個QVector<double>,分別存放了一組點的x和y坐標(Key與Value)。不過QCustomPlot更傾向于使用Key與Value而非x與y,這樣可以更靈活地區(qū)分哪個軸具有什么樣的功能。所以當我們定義左邊軸為Key軸而底部軸為Value軸時,我們就可以沿著左邊的軸繪制一幅直立的圖。
QCustomPlot有4個軸customPlot->xAxis, yAxis, xAxis2, 和 yAxis2,它們都是QCPAxis類型的,分別對應(yīng)下、左、上、右。
如果要設(shè)置軸的范圍為(-1,1),可以用:
customPlot->xAxis->setRange(-1,1);
1.4、重繪
如果對畫布做了任何修改,可以用
customPlot->replot();
進行重繪。
不過每當Widget被拉伸或者觸發(fā)了內(nèi)置用戶交互時,都會自動進行重繪;這里的交互是指通過鼠標拖動坐標軸的范圍、用鼠標滾輪縮放等。
1.5、例子
繪制一個y=x2的曲線:
QVector<double> x(101),y(101);
for(int i=0;i<101;i++){
x[i]=i/50.0-1;//設(shè)置x的范圍為-1~1
y[i]=x[i]*x[i];
}
//創(chuàng)建畫布,設(shè)置畫布上的點數(shù)據(jù)
ui->customPlot->addGraph();
ui->customPlot->graph(0)->setData(x,y);
//設(shè)置坐標軸標簽
ui->customPlot->xAxis->setLabel("x");
ui->customPlot->yAxis->setLabel("y");
//設(shè)置坐標軸范圍,以便我們可以看到全部數(shù)據(jù)
ui->customPlot->xAxis->setRange(-1,1);
ui->customPlot->yAxis->setRange(0,1);
ui->customPlot->replot();
?坐標軸刻度、間隔和顯示的數(shù)字是由axis ticker決定的,它是QCPAxisTicker類型的變量,通過xAxis->ticker()訪問。
可以通過xAxis->ticker()->setTickCount(6)來調(diào)整坐標軸上顯示的刻度數(shù)值的個數(shù)。默認情況下,這個個數(shù)是自適應(yīng)的最少的個數(shù)。不過,也有一些特殊的情況,比如坐標軸是時間、日期、分類、對數(shù)坐標系的情況。具體可以看QCPAxisTicker。
2、改變樣式
2.1、畫布
2.1.1、線的樣式
graph->setLineStyle(..)
有哪些線的樣式,可以看QCPGraph::LineStyle。
2.1.2、畫筆
graph->setPen(..)
2.1.3、點的樣式
graph->setScatterStyle(..)
有哪些點的樣式,可以看QCPScatterStyle
2.1.4、填充色
graph->setBrush(..):填充該線和0刻度線圍成的區(qū)域。
graph->setChannelFillGraph(otherGraph):填充兩條線之間的區(qū)域;如果要移除線間填充,只需要把參數(shù)設(shè)置為0即可,這時填充的區(qū)域為該線與0刻度線圍成的區(qū)域。
如果要完全移除區(qū)域填充,用graph->setBrush(Qt::NoBrush)
2.2、坐標軸
坐標軸多是通過改變畫筆和字體進行修改的。可以看QCPAxis。
這里給出一些比較重要的特性:
setBasePen
,?setTickPen
,?setTickLength
,?setSubTickLength
,?setSubTickPen
,?setTickLabelFont
,?setLabelFont
,?setTickLabelPadding
,?setLabelPadding
.
我們可以用setRangeReversed來顛倒一個坐標軸(例如按照從高到低的順序繪制)。
如果想修飾坐標軸的尾部(例如添加箭頭),可以用setLowerEnding或setUpperEnding。
2.3、網(wǎng)格線
網(wǎng)格線是QCPGrid對象。
網(wǎng)格線是和坐標軸綁定的,水平網(wǎng)格線是與左坐標軸綁定的,通過customPlot->yAxis->grid()訪問。網(wǎng)格線的外觀由繪制它的畫筆決定,通過yAxis->grid()->setPen()進行設(shè)置。
位于0刻度處的網(wǎng)格線可以用不同的畫筆繪制,該畫筆樣式通過setZeroLinePen進行配置。如果我們不想用特殊的畫筆繪制零刻度線,只需要把它設(shè)置為Qt::NoPen即可,這樣0刻度線就和普通刻度線的繪制方法一樣了。
子網(wǎng)格線默認是隱藏的,可以用grid()->setSubGridVisible(true)激活。
2.4、例1:兩幅圖疊加繪制
下邊的代碼是繪制一幅衰減的余弦曲線和它的指數(shù)包裹曲線,每條曲線即是一條Graph
//添加兩幅圖并填充內(nèi)容
//第一幅圖
ui->customPlot->addGraph();
//線的顏色
ui->customPlot->graph(0)->setPen(QPen(Qt::blue));
//用半透明的藍色填充
ui->customPlot->graph(0)->setBrush(QBrush(QColor(0,0,255,20)));
//第二幅圖
ui->customPlot->addGraph();
ui->customPlot->graph(1)->setPen(QPen(Qt::red));
//生成數(shù)據(jù)點
QVector<double> x(251),y0(251),y1(251);
for(int i=0;i<251;i++){
x[i]=i;
y0[i]=qExp(-i/150.0)*qCos(i/10.0);//指數(shù)衰減的余弦曲線
y1[i]=qExp(-i/150.0);//指數(shù)包裹曲線
}
//配置上和右坐標軸來顯式刻度,但是不顯示數(shù)字
ui->customPlot->xAxis2->setVisible(true);
ui->customPlot->xAxis2->setTickLabels(false);
ui->customPlot->yAxis2->setVisible(true);
ui->customPlot->yAxis->setTickLabels(false);
//修改左和底坐標軸,使之與右和上坐標軸始終匹配
connect(ui->customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), ui->customPlot->xAxis2, SLOT(setRange(QCPRange)));
connect(ui->customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), ui->customPlot->yAxis2, SLOT(setRange(QCPRange)));
//為每幅圖設(shè)置點
ui->customPlot->graph(0)->setData(x,y0);
ui->customPlot->graph(1)->setData(x,y1);
//使圖0自適應(yīng)范圍
ui->customPlot->graph(0)->rescaleAxes();
//圖1頁一樣,但是只允許放大,以免比圖0小
ui->customPlot->graph(1)->rescaleAxes(true);
//注意,以上兩步也可以用ui->customPlot->rescaleAxes();來代替
//允許用戶用鼠標拖拉、縮放、選擇任一幅圖
ui->customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);
結(jié)果:
正如上文所寫,為Graph進行色彩填充,只需要用setBrush()就可以實現(xiàn)。
2.5、例2:多軸、多樣式繪圖
接下來,我們來看一個更復(fù)雜的例子,這個例子中包含了4個坐標軸上的4個Graph,紋理填充,垂直誤差、圖例、分割點等內(nèi)容
QCustomPlot * cp = ui->customPlot;
QCustomPlot * customPlot = cp;
//設(shè)置區(qū)域,點號作為小數(shù)分隔符、逗號作為千位分隔符
cp->setLocale(QLocale(QLocale::English,QLocale::UnitedKingdom));
cp->legend->setVisible(true);
//用MainWindow字體,減小字體大小
QFont legendFont=font();
legendFont.setPointSize(9);
cp->legend->setFont(legendFont);
cp->legend->setBrush(QBrush(QColor(255,255,255,230)));
//默認情況下,圖例是嵌入主框架之中,接下來演示如何修改它的布局
cp->axisRect()->insetLayout()->setInsetAlignment(0,Qt::AlignBottom | Qt::AlignRight);
//配置第一幅圖,Key軸是左,Value軸是底
cp->addGraph(cp->yAxis,cp->xAxis);
cp->graph(0)->setPen(QPen(QColor(255,100,0)));
cp->graph(0)->setBrush(QBrush(QPixmap("./balboa.jpg")));
cp->graph(0)->setLineStyle(QCPGraph::lsLine);
cp->graph(0)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDisc,5));
cp->graph(0)->setName("Left maxwell function");
//配置第二幅圖,Key是底,Value是左
customPlot->addGraph();
customPlot->graph(1)->setPen(QPen(Qt::red));
customPlot->graph(1)->setBrush(QBrush(QPixmap("./balboa.jpg"))); // same fill as we used for graph 0
customPlot->graph(1)->setLineStyle(QCPGraph::lsStepCenter);
customPlot->graph(1)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, Qt::red, Qt::white, 7));
customPlot->graph(1)->setName("Bottom maxwell function");
QCPErrorBars * errorBars = new QCPErrorBars(customPlot->xAxis,customPlot->yAxis);
errorBars->removeFromLegend();
errorBars->setDataPlottable(cp->graph(1));
//配置第三幅圖,Key是頂,Value是右
customPlot->addGraph(customPlot->xAxis2, customPlot->yAxis2);
customPlot->graph(2)->setPen(QPen(Qt::blue));
customPlot->graph(2)->setName("High frequency sine");
//配置第四幅圖,軸與第三幅圖相同
customPlot->addGraph(customPlot->xAxis2, customPlot->yAxis2);
QPen blueDotPen;
blueDotPen.setColor(QColor(30, 40, 255, 150));
blueDotPen.setStyle(Qt::DotLine);
blueDotPen.setWidthF(4);
customPlot->graph(3)->setPen(blueDotPen);
customPlot->graph(3)->setName("Sine envelope");
//配置第五幅圖,右為Key軸,頂為Value軸
//第五幅圖中包含一些隨機擾動的點
customPlot->addGraph(customPlot->yAxis2, customPlot->xAxis2);
customPlot->graph(4)->setPen(QColor(50, 50, 50, 255));
customPlot->graph(4)->setLineStyle(QCPGraph::lsNone);
customPlot->graph(4)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, 4));
customPlot->graph(4)->setName("Some random data around\na quadratic function");
//生成數(shù)據(jù)
QVector<double> x0(25), y0(25);
QVector<double> x1(15), y1(15), y1err(15);
QVector<double> x2(250), y2(250);
QVector<double> x3(250), y3(250);
QVector<double> x4(250), y4(250);
for (int i=0; i<25; ++i) // data for graph 0
{
x0[i] = 3*i/25.0;
y0[i] = qExp(-x0[i]*x0[i]*0.8)*(x0[i]*x0[i]+x0[i]);
}
for (int i=0; i<15; ++i) // data for graph 1
{
x1[i] = 3*i/15.0;;
y1[i] = qExp(-x1[i]*x1[i])*(x1[i]*x1[i])*2.6;
y1err[i] = y1[i]*0.25;
}
for (int i=0; i<250; ++i) // data for graphs 2, 3 and 4
{
x2[i] = i/250.0*3*M_PI;
x3[i] = x2[i];
x4[i] = i/250.0*100-50;
y2[i] = qSin(x2[i]*12)*qCos(x2[i])*10;
y3[i] = qCos(x3[i])*10;
y4[i] = 0.01*x4[i]*x4[i] + 1.5*(rand()/(double)RAND_MAX-0.5) + 1.5*M_PI;
}
//為每幅圖設(shè)置數(shù)據(jù)
customPlot->graph(0)->setData(x0, y0);
customPlot->graph(1)->setData(x1, y1);
errorBars->setData(y1err);
customPlot->graph(2)->setData(x2, y2);
customPlot->graph(3)->setData(x3, y3);
customPlot->graph(4)->setData(x4, y4);
//激活頂和右坐標軸
customPlot->xAxis2->setVisible(true);
customPlot->yAxis2->setVisible(true);
//設(shè)置顯示數(shù)據(jù)的合適的范圍
customPlot->xAxis->setRange(0, 2.7);
customPlot->yAxis->setRange(0, 2.6);
customPlot->xAxis2->setRange(0, 3.0*M_PI);
customPlot->yAxis2->setRange(-70, 35);
//為頂軸設(shè)置刻度為pi相關(guān)刻度
customPlot->xAxis2->setTicker(QSharedPointer<QCPAxisTickerPi>(new QCPAxisTickerPi));
//添加標題布局
customPlot->plotLayout()->insertRow(0);
customPlot->plotLayout()->addElement(0, 0, new QCPTextElement(customPlot, "Way too many graphs in one plot", QFont("sans", 12, QFont::Bold)));
//設(shè)置各個軸的標簽
customPlot->xAxis->setLabel("Bottom axis with outward ticks");
customPlot->yAxis->setLabel("Left axis label");
customPlot->xAxis2->setLabel("Top axis label");
customPlot->yAxis2->setLabel("Right axis label");
//使底軸刻度向外延伸
customPlot->xAxis->setTickLength(0, 5);
customPlot->xAxis->setSubTickLength(0, 3);
//使右軸刻度向內(nèi)和向外延伸
customPlot->yAxis2->setTickLength(3, 3);
customPlot->yAxis2->setSubTickLength(1, 1);
結(jié)果:
?正如結(jié)果所示,我們可以自由定義哪個軸占主導(dǎo)地位。
為了展示圖2的誤差線,我們構(gòu)造了QCPErrorBars實例用以繪制其他Graph的誤差線。
2.6、例3:繪制日期、時間數(shù)據(jù)
本例介紹如何繪制時間、日期相關(guān)的數(shù)。要實現(xiàn)這一目的,需要在每個軸上使用QCPAxisTickerDateTime作為軸刻度。
QCustomPlot * cp = ui->customPlot;
QCustomPlot * customPlot = ui->customPlot;
cp->setLocale(QLocale(QLocale::English,QLocale::UnitedKingdom));
//當前時間戳,用它作為起始點
double now = QDateTime::currentDateTime().toSecsSinceEpoch();
//設(shè)置隨機數(shù)種子
srand(8);
//生成多幅graph
for(int gi=0;gi<5;gi++){
cp->addGraph();
QColor color(20+200/4.0*gi,70*(1.6-gi/4.0),150,150);
cp->graph()->setLineStyle(QCPGraph::lsLine);
cp->graph()->setPen(QPen(color.lighter(200)));
cp->graph()->setBrush(QBrush(color));
//產(chǎn)生隨機數(shù)據(jù)
QVector<QCPGraphData> timeData(250);
for (int i=0;i<250;i++){
timeData[i].key=now+24*3600*i;
if(i==0)
timeData[i].value =(i/50.0+1)*(rand()/(double)RAND_MAX-0.5);
else
timeData[i].value=qFabs(timeData[i-1].value)*(1+0.02/4.0*(4-gi))+(i/50.0+1)*(rand()/(double)RAND_MAX-0.5);
cp->graph()->data()->set(timeData);
}
//配置底軸以顯示日期而非數(shù)字
QSharedPointer<QCPAxisTickerDateTime>dateTicker(new QCPAxisTickerDateTime);
dateTicker->setDateTimeFormat("d._MMMM\nyyyy");
cp->xAxis->setTicker(dateTicker);
//配置左軸
QSharedPointer<QCPAxisTickerText> textTicker(new QCPAxisTickerText);
textTicker->addTick(10,"a bit\nlow");
textTicker->addTick(50,"quite/nhigh");
cp->yAxis->setTicker(textTicker);
//為左軸和底軸的刻度設(shè)置合適的字體
cp->xAxis->setTickLabelFont(QFont(QFont().family(),8));
cp->yAxis->setTickLabelFont(QFont(QFont().family(),8));
//設(shè)置軸標簽
cp->xAxis->setLabel("Date");
cp->yAxis->setLabel("Random wobbly lines value");
//使頂軸和右軸可見,但是并不顯示刻度值和標簽
customPlot->xAxis2->setVisible(true);
customPlot->yAxis2->setVisible(true);
customPlot->xAxis2->setTicks(false);
customPlot->yAxis2->setTicks(false);
customPlot->xAxis2->setTickLabels(false);
customPlot->yAxis2->setTickLabels(false);
//設(shè)置軸范圍以顯示所有數(shù)據(jù)
cp->xAxis->setRange(now,now+24*3600*249);
cp->yAxis->setRange(0,60);
//顯示圖例,圖例背景輕微透明
cp->legend->setVisible(true);
cp->legend->setBrush(QColor(255,255,255,150));
結(jié)果:
?我們傳入dateTicker->setDateTimeFormat()中的字符串,需要符合ISO8601時間格式,除了時間格式之外的其他字符都會原封不動的保留,而時間格式的字符會被正確填充。
需要注意的是,QCustomPlot處理的時間/日期坐標系,都是以時間戳0起始坐標點的,,單位是s。所以當我們構(gòu)造時,也要以時間戳為橫坐標,只是在顯示的時候通過時間/日期占位符轉(zhuǎn)化為指定的時間/日期。
如果精度是比秒更小的單元,那么可以用浮點數(shù)。我們可以用QCPAxisTickerDateTime::dateTimeToKey和keyToDateTime用于浮點Unix Time和QDateTime間的轉(zhuǎn)換。
而對于QDateTime::toMSecsSinceEpoch,則是以毫秒為單位,也可以使用這種方式構(gòu)建更微小的時間精度。
3、圖形之外:曲線、圖標、統(tǒng)計圖
目前為止,我們只應(yīng)用了Graph,因為Graph是我們使用QCustomPlot的主要內(nèi)容,QCustomPlot為我們使用Graph提供了專門的接口,我們也一直在使用它們,比如QCustomPlot::addGraph、QCustomPlot::graph等等。但是這些并不是全部。
QCustomPlot也有許多更通用的繪圖接口,稱為Plottable,這個接口是圍繞抽象類QCPAbstractPlottable構(gòu)建的。所有的Plottables都是從這個類繼承而來,當然也包括了最熟悉的QCPGraph類?,F(xiàn)在介紹一些QCustomPlot提供的Plottable類:
- QCPGraph:這是我們本節(jié)經(jīng)常用的一個Plottable類。用于點、線、填充的方式展示一系列的數(shù)據(jù);
- QCPCurve:與QCPgraph類似,不同之處在于它用于展示參數(shù)曲線。不同于函數(shù)Graph,使用這個類時可能有循環(huán);
- QCPBars:柱狀圖;
- QCPStatisticalBox::箱型圖;
- QCPColorMap:通過使用顏色梯度將第三個維度可視化的2D圖;
- QCPFinancial: 用于可視化股價的Plottable;
- QCPErrorBars: 一個特殊的Plottable,附加在另一個Plottable上用于顯示數(shù)據(jù)點的誤差情況。
不同于Graph,其他的Plottable需要用new進行構(gòu)造,而不是用addCurve、addBars等函數(shù)創(chuàng)建。已經(jīng)存在的Plottable可以通過QCustomPlot::plottable(int index)訪問,plottable的數(shù)量可以用QCustomPlot::plottableCount訪問。文章來源:http://www.zghlxwxcb.cn/news/detail-461256.html
下文是構(gòu)造柱狀圖的例子:文章來源地址http://www.zghlxwxcb.cn/news/detail-461256.html
QCPBars *myBars = new QCPBars(customPlot->xAxis, customPlot->yAxis);
// now we can modify properties of myBars:
myBars->setName("Bars Series 1");
QVector<double> keyData;
QVector<double> valueData;
keyData << 1 << 2 << 3;
valueData << 2 << 4 << 8;
myBars->setData(keyData, valueData);
customPlot->rescaleAxes();
customPlot->replot();
到了這里,關(guān)于qcustomplot使用教程--基本繪圖的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!