QCustomPlot介紹及例項
阿新 • • 發佈:2019-02-06
QCustomPlot 是一個小巧好用的 QT 圖表外掛。用來畫曲線圖、趨勢圖、座標圖、柱狀圖等類似二維圖的庫。實現大部分的2維圖形繪製。使用時,我們在程式中寫完相關呼叫的程式碼後,只需將 QCunstomPlot.cpp 和 QCustomPlot.h 兩個檔案加入工程,正常編譯即可,有GPL的授權,支援跨平臺的C/C++語言 。
QCustomPlot給我們提供了非常方便的載入資料的介面:setData() 和 addData()。
QCustomPlot採用了大量的技術比如自適應取樣和文字物件快取為了減少replot的時間。然而一些特性比如半透明的填充,反鋸齒和粗線條都可能導致低效率。如果你在你的程式中注意到了這些。這有一些提示關於如何跳高Replot的效能。
下面給出常用的統計圖和K線圖的示例:
統計圖效果如圖1-1所示:customPlot->plotLayout()->clear(); QCPAxisRect *wideAxisRect = new QCPAxisRect(customPlot); wideAxisRect->setupFullAxesBox(true); wideAxisRect->axis(QCPAxis::atRight, 0)->setTickLabels(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); subLayout->addElement(0, 0, subRectLeft); subLayout->addElement(0, 1, subRectRight); subRectRight->setMaximumSize(150, 150); subRectRight->setMinimumSize(150, 150); 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); subRectRight->axis(QCPAxis::atBottom)->ticker()->setTickCount(2); subRectLeft->axis(QCPAxis::atBottom)->grid()->setVisible(true); QCPMarginGroup *marginGroup = new QCPMarginGroup(customPlot); subRectLeft->setMarginGroup(QCP::msLeft, marginGroup); subRectRight->setMarginGroup(QCP::msRight, marginGroup); wideAxisRect->setMarginGroup(QCP::msLeft | QCP::msRight, marginGroup); foreach (QCPAxisRect *rect, customPlot->axisRects()) { foreach (QCPAxis *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; 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);
圖1-1 統計圖
K線圖程式碼:
customPlot->legend->setVisible(true); int n = 500; QVector<double> time(n), value1(n), value2(n); QDateTime start = QDateTime(QDate(2014, 6, 11)); start.setTimeSpec(Qt::UTC); double startTime = start.toTime_t(); double binSize = 3600*24; value1[0] = 60; value2[0] = 20; qsrand(9); for (int i=1; i<n; ++i) { time[i] = startTime + 3600*i; value1[i] = value1[i-1] + (qrand()/(double)RAND_MAX-0.5)*10; value2[i] = value2[i-1] + (qrand()/(double)RAND_MAX-0.5)*3; } QCPFinancial *candlesticks = new QCPFinancial(customPlot->xAxis, customPlot->yAxis); candlesticks->setName("Candlestick"); candlesticks->setChartStyle(QCPFinancial::csCandlestick); candlesticks->data()->set(QCPFinancial::timeSeriesToOhlc(time, value1, binSize, startTime)); candlesticks->setWidth(binSize*0.9); candlesticks->setTwoColored(true); candlesticks->setBrushPositive(QColor(245, 245, 245)); candlesticks->setBrushNegative(QColor(40, 40, 40)); candlesticks->setPenPositive(QPen(QColor(0, 0, 0))); candlesticks->setPenNegative(QPen(QColor(0, 0, 0))); QCPFinancial *ohlc = new QCPFinancial(customPlot->xAxis, customPlot->yAxis); ohlc->setName("OHLC"); ohlc->setChartStyle(QCPFinancial::csOhlc); ohlc->data()->set(QCPFinancial::timeSeriesToOhlc(time, value2, binSize/3.0, startTime)); ohlc->setWidth(binSize*0.2); ohlc->setTwoColored(true); QCPAxisRect *volumeAxisRect = new QCPAxisRect(customPlot); customPlot->plotLayout()->addElement(1, 0, volumeAxisRect); volumeAxisRect->setMaximumSize(QSize(QWIDGETSIZE_MAX, 100)); volumeAxisRect->axis(QCPAxis::atBottom)->setLayer("axes"); volumeAxisRect->axis(QCPAxis::atBottom)->grid()->setLayer("grid"); // bring bottom and main axis rect closer together: customPlot->plotLayout()->setRowSpacing(0); volumeAxisRect->setAutoMargins(QCP::msLeft|QCP::msRight|QCP::msBottom); volumeAxisRect->setMargins(QMargins(0, 0, 0, 0)); // create two bar plottables, for positive (green) and negative (red) volume bars: customPlot->setAutoAddPlottableToLegend(false); QCPBars *volumePos = new QCPBars(volumeAxisRect->axis(QCPAxis::atBottom), volumeAxisRect->axis(QCPAxis::atLeft)); QCPBars *volumeNeg = new QCPBars(volumeAxisRect->axis(QCPAxis::atBottom), volumeAxisRect->axis(QCPAxis::atLeft)); for (int i=0; i<n/5; ++i) { int v = qrand()%20000+qrand()%20000+qrand()%20000-10000*3; (v < 0 ? volumeNeg : volumePos)->addData(startTime+3600*5.0*i, qAbs(v)); volumePos->setWidth(3600*4); volumePos->setPen(Qt::NoPen); volumePos->setBrush(QColor(100, 180, 110)); volumeNeg->setWidth(3600*4); volumeNeg->setPen(Qt::NoPen); volumeNeg->setBrush(QColor(180, 90, 90)); // interconnect x axis ranges of main and bottom axis rects: connect(customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), volumeAxisRect->axis(QCPAxis::atBottom), SLOT(setRange(QCPRange))); connect(volumeAxisRect->axis(QCPAxis::atBottom), SIGNAL(rangeChanged(QCPRange)), customPlot->xAxis, SLOT(setRange(QCPRange))); // configure axes of both main and bottom axis rect: QSharedPointer<QCPAxisTickerDateTime> dateTimeTicker(new QCPAxisTickerDateTime); dateTimeTicker->setDateTimeSpec(Qt::UTC); dateTimeTicker->setDateTimeFormat("dd. MMMM"); volumeAxisRect->axis(QCPAxis::atBottom)->setTicker(dateTimeTicker); volumeAxisRect->axis(QCPAxis::atBottom)->setTickLabelRotation(15); customPlot->xAxis->setBasePen(Qt::NoPen); customPlot->xAxis->setTickLabels(false); customPlot->xAxis->setTicks(false); customPlot->xAxis->setTicker(dateTimeTicker); customPlot->rescaleAxes(); customPlot->xAxis->scaleRange(1.025, customPlot->xAxis->range().center()); customPlot->yAxis->scaleRange(1.1, customPlot->yAxis->range().center()); QCPMarginGroup *group = new QCPMarginGroup(customPlot); customPlot->axisRect()->setMarginGroup(QCP::msLeft|QCP::msRight, group); volumeAxisRect->setMarginGroup(QCP::msLeft|QCP::msRight, group);
K線圖如圖1-2所示:
圖1-2 K線圖其它繪圖效果如下所示: