Upload
others
View
8
Download
0
Embed Size (px)
Citation preview
Plot Screenshots: Simple Demo
// add two new graphs and set their look:customPlot->addGraph();customPlot->graph(0)->setPen(QPen(Qt::blue)); // line color blue for first graphcustomPlot->graph(0)->setBrush(QBrush(QColor(0, 0, 255, 20))); // first graph will be filled with translucent bluecustomPlot->addGraph();
customPlot->graph(1)->setPen(QPen(Qt::red)); // line color red for second graph// generate some points of data (y0 for first, y1 for second graph):QVector<double> x(250), y0(250), y1(250);for(inti=0; i<250; ++i){
x[i] = i;y0[i] = qExp(-i/150.0)*qCos(i/10.0); // exponentially decaying cosiney1[i] = qExp(-i/150.0); // exponential envelope
}// configure right and top axis to show ticks but no labels:// (see QCPAxisRect::setupFullAxesBox for a quicker method to do this)customPlot->xAxis2->setVisible(true);customPlot->xAxis2->setTickLabels(false);customPlot->yAxis2->setVisible(true);customPlot->yAxis2->setTickLabels(false);// make left and bottom axes always transfer their ranges to right and top axes:connect(customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->xAxis2, SLOT(setRange(QCPRange)));connect(customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->yAxis2, SLOT(setRange(QCPRange)));// pass data points to graphs:customPlot->graph(0)->setData(x, y0);customPlot->graph(1)->setData(x, y1);// let the ranges scale themselves so graph 0 fits perfectly in the visible area:customPlot->graph(0)->rescaleAxes();// same thing for graph 1, but only enlarge ranges (in case graph 1 is smaller than graph 0):customPlot->graph(1)->rescaleAxes(true);// Note: we could have also just called customPlot->rescaleAxes(); instead
// Allow user to drag axis ranges with mouse, zoom with mouse wheel and select graphs by clicking:customPlot->setInteractions(QCP::iRangeDrag| QCP::iRangeZoom| QCP::iSelectPlottables);
Plot Screenshots: Sinc Scatter Demo
customPlot->legend->setVisible(true);customPlot->legend->setFont(QFont("Helvetica",9));// set locale to english, so we get english decimal separator:customPlot->setLocale(QLocale(QLocale::English, QLocale::UnitedKingdom));// add confidence band graphs:customPlot->addGraph();QPenpen;pen.setStyle(Qt::DotLine);pen.setWidth(1);pen.setColor(QColor(180,180,180));customPlot->graph(0)->setName("Confidence Band 68%");customPlot->graph(0)->setPen(pen);customPlot->graph(0)->setBrush(QBrush(QColor(255,50,30,20)));customPlot->addGraph();customPlot->legend->removeItem(customPlot->legend->itemCount()-1); // don't show two confidence band graphs in legendcustomPlot->graph(1)->setPen(pen);customPlot->graph(0)->setChannelFillGraph(customPlot->graph(1));// add theory curve graph:customPlot->addGraph();pen.setStyle(Qt::DashLine);pen.setWidth(2);pen.setColor(Qt::red);customPlot->graph(2)->setPen(pen);customPlot->graph(2)->setName("Theory Curve");// add data point graph:customPlot->addGraph();
customPlot->graph(3)->setPen(QPen(Qt::blue));customPlot->graph(3)->setLineStyle(QCPGraph::lsNone);customPlot->graph(3)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCross, 4));customPlot->graph(3)->setErrorType(QCPGraph::etValue);customPlot->graph(3)->setErrorPen(QPen(QColor(180,180,180)));customPlot->graph(3)->setName("Measurement");
// generate ideal sinc curve data and some randomly perturbed data for scatter plot:QVector<double> x0(250), y0(250);QVector<double> yConfUpper(250), yConfLower(250);for(inti=0; i<250; ++i){
x0[i] = (i/249.0-0.5)*30+0.01; // by adding a small offset we make sure not do divide by zero in next code liney0[i] = qSin(x0[i])/x0[i]; // sinc functionyConfUpper[i] = y0[i]+0.15;yConfLower[i] = y0[i]-0.15;x0[i] *= 1000;
}QVector<double> x1(50), y1(50), y1err(50);for(inti=0; i<50; ++i){
// generate a gaussian distributed random number:doubletmp1 = rand()/(double)RAND_MAX;doubletmp2 = rand()/(double)RAND_MAX;doubler = qSqrt(-2*qLn(tmp1))*qCos(2*M_PI*tmp2); // box-muller transform for gaussian distribution// set y1 to value of y0 plus a random gaussian pertubation:
x1[i] = (i/50.0-0.5)*30+0.25;y1[i] = qSin(x1[i])/x1[i]+r*0.15;x1[i] *= 1000;y1err[i] = 0.15;
}// pass data to graphs and let QCustomPlot determine the axes ranges so the whole thing is visible:customPlot->graph(0)->setData(x0, yConfUpper);customPlot->graph(1)->setData(x0, yConfLower);customPlot->graph(2)->setData(x0, y0);customPlot->graph(3)->setDataValueError(x1, y1, y1err);customPlot->graph(2)->rescaleAxes();customPlot->graph(3)->rescaleAxes(true);// setup look of bottom tick labels:customPlot->xAxis->setTickLabelRotation(30);customPlot->xAxis->setAutoTickCount(9);customPlot->xAxis->setNumberFormat("ebc");customPlot->xAxis->setNumberPrecision(1);customPlot->xAxis->moveRange(-10);// make top right axes clones of bottom left axes. Looks prettier:customPlot->axisRect()->setupFullAxesBox();
Plot Screenshots: Scatter Style Demo
customPlot->legend->setVisible(true);customPlot->legend->setFont(QFont("Helvetica", 9));customPlot->legend->setRowSpacing(-3);QVector<QCPScatterStyle::ScatterShape> shapes;shapes << QCPScatterStyle::ssCross;shapes << QCPScatterStyle::ssPlus;shapes << QCPScatterStyle::ssCircle;shapes << QCPScatterStyle::ssDisc;shapes << QCPScatterStyle::ssSquare;shapes << QCPScatterStyle::ssDiamond;shapes << QCPScatterStyle::ssStar;shapes << QCPScatterStyle::ssTriangle;shapes << QCPScatterStyle::ssTriangleInverted;shapes << QCPScatterStyle::ssCrossSquare;shapes << QCPScatterStyle::ssPlusSquare;shapes << QCPScatterStyle::ssCrossCircle;shapes << QCPScatterStyle::ssPlusCircle;shapes << QCPScatterStyle::ssPeace;shapes << QCPScatterStyle::ssCustom;
QPenpen;// add graphs with different scatter styles:for(inti=0; i<shapes.size(); ++i){
customPlot->addGraph();
pen.setColor(QColor(qSin(i*0.3)*100+100, qSin(i*0.6+0.7)*100+100, qSin(i*0.4+0.6)*100+100));// generate data:QVector<double> x(10), y(10);for(intk=0; k<10; ++k){
x[k] = k/10.0* 4*3.14+ 0.01;y[k] = 7*qSin(x[k])/x[k] + (shapes.size()-i)*5;
}customPlot->graph()->setData(x, y);customPlot->graph()->rescaleAxes(true);customPlot->graph()->setPen(pen);customPlot->graph()->setName(QCPScatterStyle::staticMetaObject.enumerator(QCPScatterStyle::staticMetaObject.inde
xOfEnumerator("ScatterShape")).valueToKey(shapes.at(i)));customPlot->graph()->setLineStyle(QCPGraph::lsLine);// set scatter style:if(shapes.at(i) != QCPScatterStyle::ssCustom){
customPlot->graph()->setScatterStyle(QCPScatterStyle(shapes.at(i), 10));}else{
QPainterPathcustomScatterPath;for(inti=0; i<3; ++i)
customScatterPath.cubicTo(qCos(2*M_PI*i/3.0)*9, qSin(2*M_PI*i/3.0)*9, qCos(2*M_PI*(i+0.9)/3.0)*9, qSin(2*M_PI*(i+0.9)/3.0)*9, 0, 0);
customPlot->graph()->setScatterStyle(QCPScatterStyle(customScatterPath, QPen(Qt::black, 0), QColor(40, 70, 255, 50), 10));
}}// set blank axis lines:customPlot->rescaleAxes();customPlot->xAxis->setTicks(false);customPlot->yAxis->setTicks(false);customPlot->xAxis->setTickLabels(false);customPlot->yAxis->setTickLabels(false);// make top right axes clones of bottom left axes:customPlot->axisRect()->setupFullAxesBox();
Plot Screenshots: Styled Plot Demo
// prepare data:QVector<double> x1(20), y1(20);QVector<double> x2(100), y2(100);QVector<double> x3(20), y3(20);QVector<double> x4(20), y4(20);for(inti=0; i<x1.size(); ++i){
x1[i] = i/(double)x1.size()*10;y1[i] = qCos(x1[i]*0.8+qSin(x1[i]*0.16+1.0))*qSin(x1[i]*0.54)+1.4;
}for(inti=0; i<x2.size(); ++i){
x2[i] = i/(double)x2.size()*10;y2[i] = qCos(x2[i]*0.85+qSin(x2[i]*0.165+1.1))*qSin(x2[i]*0.50)+1.7;
}for(inti=0; i<x3.size(); ++i){
x3[i] = i/(double)x3.size()*10;y3[i] = 0.05+3*(0.5+qCos(x3[i]*x3[i]*0.2+2)*0.5)/(double)(x3[i]+0.7)+qrand()/(double)RAND_MAX*0.01;
}for(inti=0; i<x4.size(); ++i){
x4[i] = x3[i];y4[i] = (0.5-y3[i])+((x4[i]-2)*(x4[i]-2)*0.02);
}
// create and configure plottables:QCPGraph*graph1 = customPlot->addGraph();graph1->setData(x1, y1);graph1->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, QPen(Qt::black, 1.5), QBrush(Qt::white), 9));graph1->setPen(QPen(QColor(120, 120, 120), 2));
QCPGraph*graph2 = customPlot->addGraph();graph2->setData(x2, y2);graph2->setPen(Qt::NoPen);graph2->setBrush(QColor(200, 200, 200, 20));graph2->setChannelFillGraph(graph1);
QCPBars*bars1 = newQCPBars(customPlot->xAxis, customPlot->yAxis);customPlot->addPlottable(bars1);bars1->setWidth(9/(double)x3.size());bars1->setData(x3, y3);bars1->setPen(Qt::NoPen);bars1->setBrush(QColor(10, 140, 70, 160));
QCPBars*bars2 = newQCPBars(customPlot->xAxis, customPlot->yAxis);customPlot->addPlottable(bars2);bars2->setWidth(9/(double)x4.size());bars2->setData(x4, y4);bars2->setPen(Qt::NoPen);bars2->setBrush(QColor(10, 100, 50, 70));bars2->moveAbove(bars1);
// move bars above graphs and grid below bars:customPlot->addLayer("abovemain", customPlot->layer("main"), QCustomPlot::limAbove);customPlot->addLayer("belowmain", customPlot->layer("main"), QCustomPlot::limBelow);graph1->setLayer("abovemain");customPlot->xAxis->grid()->setLayer("belowmain");customPlot->yAxis->grid()->setLayer("belowmain");
// set some pens, brushes and backgrounds:customPlot->xAxis->setBasePen(QPen(Qt::white, 1));customPlot->yAxis->setBasePen(QPen(Qt::white, 1));customPlot->xAxis->setTickPen(QPen(Qt::white, 1));customPlot->yAxis->setTickPen(QPen(Qt::white, 1));customPlot->xAxis->setSubTickPen(QPen(Qt::white, 1));customPlot->yAxis->setSubTickPen(QPen(Qt::white, 1));customPlot->xAxis->setTickLabelColor(Qt::white);customPlot->yAxis->setTickLabelColor(Qt::white);customPlot->xAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine));customPlot->yAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine));customPlot->xAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine));customPlot->yAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine));customPlot->xAxis->grid()->setSubGridVisible(true);customPlot->yAxis->grid()->setSubGridVisible(true);customPlot->xAxis->grid()->setZeroLinePen(Qt::NoPen);customPlot->yAxis->grid()->setZeroLinePen(Qt::NoPen);customPlot->xAxis->setUpperEnding(QCPLineEnding::esSpikeArrow);
customPlot->yAxis->setUpperEnding(QCPLineEnding::esSpikeArrow);QLinearGradientplotGradient;plotGradient.setStart(0, 0);plotGradient.setFinalStop(0, 350);plotGradient.setColorAt(0, QColor(80, 80, 80));plotGradient.setColorAt(1, QColor(50, 50, 50));customPlot->setBackground(plotGradient);QLinearGradientaxisRectGradient;axisRectGradient.setStart(0, 0);axisRectGradient.setFinalStop(0, 350);axisRectGradient.setColorAt(0, QColor(80, 80, 80));axisRectGradient.setColorAt(1, QColor(30, 30, 30));customPlot->axisRect()->setBackground(axisRectGradient);
customPlot->rescaleAxes();customPlot->yAxis->setRange(0, 2);
Plot Screenshots: Color Map Demo
// configure axis rect:customPlot->setInteractions(QCP::iRangeDrag|QCP::iRangeZoom); // this will also allow rescaling the color scale by dragging/zoomingcustomPlot->axisRect()->setupFullAxesBox(true);customPlot->xAxis->setLabel("x");customPlot->yAxis->setLabel("y");
// set up the QCPColorMap:QCPColorMap*colorMap = newQCPColorMap(customPlot->xAxis, customPlot->yAxis);customPlot->addPlottable(colorMap);intnx = 200;intny = 200;colorMap->data()->setSize(nx, ny); // we want the color map to have nx * ny data pointscolorMap->data()->setRange(QCPRange(-4, 4), QCPRange(-4, 4)); // and span the coordinate range -4..4 in both key (x) and value (y) dimensions// now we assign some data, by accessing the QCPColorMapData instance of the color map:doublex, y, z;for(intxIndex=0; xIndex<nx; ++xIndex){
for(intyIndex=0; yIndex<ny; ++yIndex){
colorMap->data()->cellToCoord(xIndex, yIndex, &x, &y);doubler = 3*qSqrt(x*x+y*y)+1e-2;z = 2*x*(qCos(r+2)/r-qSin(r+2)/r); // the B field strength of dipole radiation (modulo physical constants)colorMap->data()->setCell(xIndex, yIndex, z);
}
}
// add a color scale:QCPColorScale*colorScale = newQCPColorScale(customPlot);customPlot->plotLayout()->addElement(0, 1, colorScale); // add it to the right of the main axis rectcolorScale->setType(QCPAxis::atRight); // scale shall be vertical bar with tick/axis labels right (actually atRight is already the default)colorMap->setColorScale(colorScale); // associate the color map with the color scalecolorScale->axis()->setLabel("Magnetic Field Strength");
// set the color gradient of the color map to one of the presets:colorMap->setGradient(QCPColorGradient::gpPolar);// we could have also created a QCPColorGradient instance and added own colors to// the gradient, see the documentation of QCPColorGradient for what's possible.
// rescale the data dimension (color) such that all data points lie in the span visualized by the color gradient:colorMap->rescaleDataRange();
// make sure the axis rect and color scale synchronize their bottom and top margins (so they line up):QCPMarginGroup*marginGroup = newQCPMarginGroup(customPlot);customPlot->axisRect()->setMarginGroup(QCP::msBottom|QCP::msTop, marginGroup);colorScale->setMarginGroup(QCP::msBottom|QCP::msTop, marginGroup);
// rescale the key (x) and value (y) axes so the whole color map is visible:customPlot->rescaleAxes();
Plot Screenshots: Scatter Pixmap Demo
customPlot->axisRect()->setBackground(QPixmap("./solarpanels.jpg"));customPlot->addGraph();customPlot->graph()->setLineStyle(QCPGraph::lsLine);QPenpen;pen.setColor(QColor(255, 200, 20, 200));pen.setStyle(Qt::DashLine);pen.setWidthF(2.5);customPlot->graph()->setPen(pen);customPlot->graph()->setBrush(QBrush(QColor(255,200,20,70)));customPlot->graph()->setScatterStyle(QCPScatterStyle(QPixmap("./sun.png")));// set graph name, will show up in legend next to icon:customPlot->graph()->setName("Data from Photovoltaic\nenergy barometer 2011");// set data:QVector<double> year, value;year << 2005<< 2006<< 2007<< 2008 << 2009 << 2010;value << 2.17<< 3.42<< 4.94<< 10.38<< 15.86<< 29.33;customPlot->graph()->setData(year, value);
// set title of plot:customPlot->plotLayout()->insertRow(0);customPlot->plotLayout()->addElement(0, 0, newQCPPlotTitle(customPlot, "Regenerative Energies"));// set a fixed tick-step to one tick per year value:customPlot->xAxis->setAutoTickStep(false);customPlot->xAxis->setTickStep(1);customPlot->xAxis->setSubTickCount(3);// other axis configurations:
customPlot->xAxis->setLabel("Year");customPlot->yAxis->setLabel("Installed Gigawatts of\nphotovoltaic in the European Union");customPlot->xAxis2->setVisible(true);customPlot->yAxis2->setVisible(true);customPlot->xAxis2->setTickLabels(false);customPlot->yAxis2->setTickLabels(false);customPlot->xAxis2->setTicks(false);customPlot->yAxis2->setTicks(false);customPlot->xAxis2->setSubTickCount(0);customPlot->yAxis2->setSubTickCount(0);customPlot->xAxis->setRange(2004.5, 2010.5);customPlot->yAxis->setRange(0, 30);// setup legend:customPlot->legend->setFont(QFont(font().family(), 7));customPlot->legend->setIconSize(50, 20);customPlot->legend->setVisible(true);
Plot Screenshots: Realtime Data Demo
Setup function: customPlot->addGraph(); // blue linecustomPlot->graph(0)->setPen(QPen(Qt::blue));customPlot->graph(0)->setBrush(QBrush(QColor(240, 255, 200)));customPlot->graph(0)->setAntialiasedFill(false);customPlot->addGraph(); // red linecustomPlot->graph(1)->setPen(QPen(Qt::red));customPlot->graph(0)->setChannelFillGraph(customPlot->graph(1));
customPlot->addGraph(); // blue dotcustomPlot->graph(2)->setPen(QPen(Qt::blue));customPlot->graph(2)->setLineStyle(QCPGraph::lsNone);customPlot->graph(2)->setScatterStyle(QCPScatterStyle::ssDisc);customPlot->addGraph(); // red dotcustomPlot->graph(3)->setPen(QPen(Qt::red));customPlot->graph(3)->setLineStyle(QCPGraph::lsNone);customPlot->graph(3)->setScatterStyle(QCPScatterStyle::ssDisc);
customPlot->xAxis->setTickLabelType(QCPAxis::ltDateTime);customPlot->xAxis->setDateTimeFormat("hh:mm:ss");customPlot->xAxis->setAutoTickStep(false);customPlot->xAxis->setTickStep(2);customPlot->axisRect()->setupFullAxesBox();
// make left and bottom axes transfer their ranges to right and top axes:
connect(customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->xAxis2, SLOT(setRange(QCPRange)));connect(customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->yAxis2, SLOT(setRange(QCPRange)));
// setup a timer that repeatedly calls MainWindow::realtimeDataSlot:connect(&dataTimer, SIGNAL(timeout()), this, SLOT(realtimeDataSlot()));dataTimer.start(0); // Interval 0 means to refresh as fast as possible
realtimeDataSlot , called by timer: // calculate two new data points:doublekey = QDateTime::currentDateTime().toMSecsSinceEpoch()/1000.0;staticdoublelastPointKey = 0;if(key-lastPointKey > 0.01) // at most add point every 10 ms{
doublevalue0 = qSin(key); //qSin(key*1.6+qCos(key*1.7)*2)*10 + qSin(key*1.2+0.56)*20 + 26;doublevalue1 = qCos(key); //qSin(key*1.3+qCos(key*1.2)*1.2)*7 + qSin(key*0.9+0.26)*24 + 26;// add data to lines:ui->customPlot->graph(0)->addData(key, value0);ui->customPlot->graph(1)->addData(key, value1);// set data of dots:ui->customPlot->graph(2)->clearData();ui->customPlot->graph(2)->addData(key, value0);
ui->customPlot->graph(3)->clearData();ui->customPlot->graph(3)->addData(key, value1);// remove data of lines that's outside visible range:ui->customPlot->graph(0)->removeDataBefore(key-8);ui->customPlot->graph(1)->removeDataBefore(key-8);// rescale value (vertical) axis to fit the current data:ui->customPlot->graph(0)->rescaleValueAxis();ui->customPlot->graph(1)->rescaleValueAxis(true);lastPointKey = key;
}// make key axis range scroll with the data (at a constant range size of 8):ui->customPlot->xAxis->setRange(key+0.25, 8, Qt::AlignRight);ui->customPlot->replot();
// calculate frames per second:staticdoublelastFpsKey;staticintframeCount;++frameCount;if(key-lastFpsKey > 2) // average fps over 2 seconds{
ui->statusBar->showMessage(QString("%1 FPS, Total Data points: %2").arg(frameCount/(key-lastFpsKey), 0, 'f', 0).arg(ui->customPlot->graph(0)->data()->count()+ui->customPlot->graph(1)->data()->count()), 0);
lastFpsKey = key;
frameCount = 0;}
Plot Screenshots: Multiple Axes Demo
customPlot->setLocale(QLocale(QLocale::English, QLocale::UnitedKingdom)); // period as decimal separator and comma as thousand separatorcustomPlot->legend->setVisible(true);QFontlegendFont = font(); // start out with MainWindow's font..legendFont.setPointSize(9); // and make a bit smaller for legendcustomPlot->legend->setFont(legendFont);customPlot->legend->setBrush(QBrush(QColor(255,255,255,230)));// by default, the legend is in the inset layout of the main axis rect. So this is how we access it to change legend placement:customPlot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignBottom|Qt::AlignRight);
// setup for graph 0: key axis left, value axis bottom// will contain left maxwell-like functioncustomPlot->addGraph(customPlot->yAxis, customPlot->xAxis);customPlot->graph(0)->setPen(QPen(QColor(255, 100, 0)));customPlot->graph(0)->setBrush(QBrush(QPixmap("./balboa.jpg"))); // fill with texture of specified imagecustomPlot->graph(0)->setLineStyle(QCPGraph::lsLine);customPlot->graph(0)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDisc, 5));customPlot->graph(0)->setName("Left maxwell function");
// setup for graph 1: key axis bottom, value axis left (those are the default axes)// will contain bottom maxwell-like functioncustomPlot->addGraph();customPlot->graph(1)->setPen(QPen(Qt::red));customPlot->graph(1)->setBrush(QBrush(QPixmap("./balboa.jpg"))); // same fill as we used for graph 0customPlot->graph(1)->setLineStyle(QCPGraph::lsStepCenter);customPlot->graph(1)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, Qt::red, Qt::white, 7));
customPlot->graph(1)->setErrorType(QCPGraph::etValue);customPlot->graph(1)->setName("Bottom maxwell function");
// setup for graph 2: key axis top, value axis right// will contain high frequency sine with low frequency beating:customPlot->addGraph(customPlot->xAxis2, customPlot->yAxis2);customPlot->graph(2)->setPen(QPen(Qt::blue));customPlot->graph(2)->setName("High frequency sine");
// setup for graph 3: same axes as graph 2// will contain low frequency beating envelope of graph 2customPlot->addGraph(customPlot->xAxis2, customPlot->yAxis2);QPenblueDotPen;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");
// setup for graph 4: key axis right, value axis top// will contain parabolically distributed data points with some random perturbancecustomPlot->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");
// generate data, just playing with numbers, not much to learn here: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(inti=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(inti=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(inti=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;
}
// pass data points to graphs:customPlot->graph(0)->setData(x0, y0);customPlot->graph(1)->setDataValueError(x1, y1, y1err);customPlot->graph(2)->setData(x2, y2);customPlot->graph(3)->setData(x3, y3);customPlot->graph(4)->setData(x4, y4);// activate top and right axes, which are invisible by default:customPlot->xAxis2->setVisible(true);customPlot->yAxis2->setVisible(true);// set ranges appropriate to show data: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);// set pi ticks on top axis:QVector<double> piTicks;QVector<QString> piLabels;piTicks << 0 << 0.5*M_PI << M_PI << 1.5*M_PI << 2*M_PI << 2.5*M_PI << 3*M_PI;piLabels << "0"<< QString::fromUtf8("? π ") << QString::fromUtf8(" π") < < QString::fromUtf8("1? π") << QString::fromUtf8("2 π ") << QString::fromUtf8("2? π ") << QString::fromUtf8("3 π");customPlot->xAxis2->setAutoTicks(false);customPlot->xAxis2->setAutoTickLabels(false);customPlot->xAxis2->setTickVector(piTicks);customPlot->xAxis2->setTickVectorLabels(piLabels);
// add title layout element:customPlot->plotLayout()->insertRow(0);customPlot->plotLayout()->addElement(0, 0, newQCPPlotTitle(customPlot, "Way too many graphs in one plot"));// set labels: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");// make ticks on bottom axis go outward:customPlot->xAxis->setTickLength(0, 5);customPlot->xAxis->setSubTickLength(0, 3);// make ticks on right axis go inward and outward:customPlot->yAxis2->setTickLength(3, 3);customPlot->yAxis2->setSubTickLength(1, 1);
Plot Screenshots: Logarithmic Axis Demo
customPlot->setNoAntialiasingOnDrag(true); // more performance/responsiveness during dragging
customPlot->addGraph();QPenpen;pen.setColor(QColor(255,170,100));pen.setWidth(2);pen.setStyle(Qt::DotLine);customPlot->graph(0)->setPen(pen);customPlot->graph(0)->setName("x");
customPlot->addGraph();customPlot->graph(1)->setPen(QPen(Qt::red));customPlot->graph(1)->setBrush(QBrush(QColor(255, 0, 0, 20)));customPlot->graph(1)->setErrorType(QCPGraph::etBoth);customPlot->graph(1)->setName("-sin(x)exp(x)");
customPlot->addGraph();customPlot->graph(2)->setPen(QPen(Qt::blue));customPlot->graph(2)->setBrush(QBrush(QColor(0, 0, 255, 20)));customPlot->graph(2)->setName(" sin(x)exp(x)");
customPlot->addGraph();pen.setColor(QColor(0,0,0));pen.setWidth(1);pen.setStyle(Qt::DashLine);customPlot->graph(3)->setPen(pen);customPlot->graph(3)->setBrush(QBrush(QColor(0,0,0,15)));customPlot->graph(3)->setLineStyle(QCPGraph::lsStepCenter);
customPlot->graph(3)->setName("x!");
QVector<double> x0(200), y0(200);QVector<double> x1(200), y1(200);QVector<double> x2(200), y2(200);QVector<double> x3(21), y3(21);for(inti=0; i<200; ++i){
x0[i] = i/10.0;y0[i] = x0[i];x1[i] = i/10.0;y1[i] = -qSin(x1[i])*qExp(x1[i]);x2[i] = i/10.0;y2[i] = qSin(x2[i])*qExp(x2[i]);
}for(inti=0; i<21; ++i){
x3[i] = i;y3[i] = 1;for(intk=1; k<=i; ++k) y3[i] *= k; // factorial
}customPlot->graph(0)->setData(x0, y0);customPlot->graph(1)->setData(x1, y1);customPlot->graph(2)->setData(x2, y2);customPlot->graph(3)->setData(x3, y3);
customPlot->yAxis->grid()->setSubGridVisible(true);customPlot->xAxis->grid()->setSubGridVisible(true);customPlot->yAxis->setScaleType(QCPAxis::stLogarithmic);customPlot->yAxis->setScaleLogBase(100);customPlot->yAxis->setNumberFormat("eb"); // e = exponential, b = beautiful decimal powerscustomPlot->yAxis->setNumberPrecision(0); // makes sure "1*10^4" is displayed only as "10^4"customPlot->yAxis->setSubTickCount(10);customPlot->xAxis->setRange(0, 19.9);customPlot->yAxis->setRange(1e-2, 1e10);// make range draggable and zoomable:customPlot->setInteractions(QCP::iRangeDrag| QCP::iRangeZoom);
// make top right axes clones of bottom left axes:customPlot->axisRect()->setupFullAxesBox();// connect signals so top and right axes move in sync with bottom and left axes:connect(customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->xAxis2, SLOT(setRange(QCPRange)));connect(customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->yAxis2, SLOT(setRange(QCPRange)));
customPlot->legend->setVisible(true);customPlot->legend->setBrush(QBrush(QColor(255,255,255,150)));customPlot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignLeft|Qt::AlignTop); // make legend align in top left corner or axis rect
Plot Screenshots: Line Style Demo
customPlot->legend->setVisible(true);customPlot->legend->setFont(QFont("Helvetica", 9));QPenpen;QStringListlineNames;lineNames << "lsNone"<< "lsLine"<< "lsStepLeft"<< "lsStepRight"<< "lsStepCenter"<< "lsImpulse";// add graphs with different line styles:for(inti=QCPGraph::lsNone; i<=QCPGraph::lsImpulse; ++i){
customPlot->addGraph();pen.setColor(QColor(qSin(i*1+1.2)*80+80, qSin(i*0.3+0)*80+80, qSin(i*0.3+1.5)*80+80));customPlot->graph()->setPen(pen);customPlot->graph()->setName(lineNames.at(i-QCPGraph::lsNone));customPlot->graph()->setLineStyle((QCPGraph::LineStyle)i);customPlot->graph()->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, 5));// generate data:QVector<double> x(15), y(15);for(intj=0; j<15; ++j){
x[j] = j/15.0* 5*3.14+ 0.01;y[j] = 7*qSin(x[j])/x[j] - (i-QCPGraph::lsNone)*5+ (QCPGraph::lsImpulse)*5+ 2;
}customPlot->graph()->setData(x, y);customPlot->graph()->rescaleAxes(true);
}// zoom out a bit:customPlot->yAxis->scaleRange(1.1, customPlot->yAxis->range().center());
customPlot->xAxis->scaleRange(1.1, customPlot->xAxis->range().center());// set blank axis lines:customPlot->xAxis->setTicks(false);customPlot->yAxis->setTicks(true);customPlot->xAxis->setTickLabels(false);customPlot->yAxis->setTickLabels(true);// make top right axes clones of bottom left axes:customPlot->axisRect()->setupFullAxesBox();
Plot Screenshots: Date Axis Demo
// set locale to english, so we get english month names:customPlot->setLocale(QLocale(QLocale::English, QLocale::UnitedKingdom));// seconds of current time, we'll use it as starting point in time for data:doublenow = QDateTime::currentDateTime().toTime_t();srand (8); // set the random seed, so we always get the same random data// create multiple graphs:for(intgi=0; gi<5; ++gi){
customPlot->addGraph();QPenpen;pen.setColor(QColor(0, 0, 255, 200));customPlot->graph()->setLineStyle(QCPGraph::lsLine);customPlot->graph()->setPen(pen);customPlot->graph()->setBrush(QBrush(QColor(255/4.0*gi,160,50,150)));// generate random walk data:QVector<double> time (250), value(250);for(inti=0; i<250; ++i){
time [i] = now + 24*3600*i;if(i == 0)
value[i] = (i/50.0+1)*( rand ()/(double)RAND_MAX-0.5);else
value[i] = qFabs(value[i-1])*(1+0.02/4.0*(4-gi)) + (i/50.0+1)*( rand()/(double)RAND_MAX-0.5);}customPlot->graph()->setData( time , value);
}
// configure bottom axis to show date and time instead of number:customPlot->xAxis->setTickLabelType(QCPAxis::ltDateTime);customPlot->xAxis->setDateTimeFormat("MMMM\nyyyy");// set a more compact font size for bottom and left axis tick labels:customPlot->xAxis->setTickLabelFont(QFont(QFont().family(), 8));customPlot->yAxis->setTickLabelFont(QFont(QFont().family(), 8));// set a fixed tick-step to one tick per month:customPlot->xAxis->setAutoTickStep(false);customPlot->xAxis->setTickStep(2628000); // one month in secondscustomPlot->xAxis->setSubTickCount(3);// apply manual tick and tick label for left axis:customPlot->yAxis->setAutoTicks(false);customPlot->yAxis->setAutoTickLabels(false);customPlot->yAxis->setTickVector(QVector<double>() << 5<< 55);customPlot->yAxis->setTickVectorLabels(QVector<QString>() << "Not so\nhigh"<< "Very\nhigh");// set axis labels:customPlot->xAxis->setLabel("Date");customPlot->yAxis->setLabel("Random wobbly lines value");// make top and right axes visible but without ticks and labels:customPlot->xAxis2->setVisible(true);customPlot->yAxis2->setVisible(true);customPlot->xAxis2->setTicks(false);customPlot->yAxis2->setTicks(false);customPlot->xAxis2->setTickLabels(false);customPlot->yAxis2->setTickLabels(false);// set axis ranges to show all data:
customPlot->xAxis->setRange(now, now+24*3600*249);customPlot->yAxis->setRange(0, 60);// show legend:customPlot->legend->setVisible(true);
Plot Screenshots: Parametric Curves Demo
// create empty curve objects and add them to customPlot:QCPCurve*fermatSpiral1 = newQCPCurve(customPlot->xAxis, customPlot->yAxis);QCPCurve*fermatSpiral2 = newQCPCurve(customPlot->xAxis, customPlot->yAxis);QCPCurve*deltoidRadial = newQCPCurve(customPlot->xAxis, customPlot->yAxis);customPlot->addPlottable(fermatSpiral1);customPlot->addPlottable(fermatSpiral2);customPlot->addPlottable(deltoidRadial);// generate the curve data points:intpointCount = 500;QVector<double> x1(pointCount), y1(pointCount);QVector<double> x2(pointCount), y2(pointCount);QVector<double> x3(pointCount), y3(pointCount);for(inti=0; i<pointCount; ++i){
doublephi = (i/(double)(pointCount-1))*8*M_PI;x1[i] = qSqrt(phi)*qCos(phi);y1[i] = qSqrt(phi)*qSin(phi);x2[i] = -x1[i];y2[i] = -y1[i];doublet = i/(double)(pointCount-1)*2*M_PI;x3[i] = 2*qCos(2*t)+qCos(1*t)+2*qSin(t);y3[i] = 2*qSin(2*t)-qSin(1*t);
}// pass the data to the curves:fermatSpiral1->setData(x1, y1);fermatSpiral2->setData(x2, y2);
deltoidRadial->setData(x3, y3);// color the curves:fermatSpiral1->setPen(QPen(Qt::blue));fermatSpiral1->setBrush(QBrush(QColor(0, 0, 255, 20)));fermatSpiral2->setPen(QPen(QColor(255, 120, 0)));fermatSpiral2->setBrush(QBrush(QColor(255, 120, 0, 30)));QRadialGradientradialGrad(QPointF(310, 180), 200);radialGrad.setColorAt(0, QColor(170, 20, 240, 100));radialGrad.setColorAt(0.5, QColor(20, 10, 255, 40));radialGrad.setColorAt(1,QColor(120, 20, 240, 10));deltoidRadial->setPen(QPen(QColor(170, 20, 240)));deltoidRadial->setBrush(QBrush(radialGrad));// set some basic customPlot config:customPlot->setInteractions(QCP::iRangeDrag| QCP::iRangeZoom| QCP::iSelectPlottables);customPlot->axisRect()->setupFullAxesBox();customPlot->rescaleAxes();
Plot Screenshots: Bar Chart Demo
// create empty bar chart objects:QCPBars*regen = newQCPBars(customPlot->xAxis, customPlot->yAxis);QCPBars*nuclear = newQCPBars(customPlot->xAxis, customPlot->yAxis);QCPBars*fossil = newQCPBars(customPlot->xAxis, customPlot->yAxis);customPlot->addPlottable(regen);customPlot->addPlottable(nuclear);customPlot->addPlottable(fossil);// set names and colors:QPenpen;pen.setWidthF(1.2);fossil->setName("Fossil fuels");pen.setColor(QColor(255, 131, 0));fossil->setPen(pen);fossil->setBrush(QColor(255, 131, 0, 50));nuclear->setName("Nuclear");pen.setColor(QColor(1, 92, 191));nuclear->setPen(pen);nuclear->setBrush(QColor(1, 92, 191, 50));regen->setName("Regenerative");pen.setColor(QColor(150, 222, 0));regen->setPen(pen);regen->setBrush(QColor(150, 222, 0, 70));// stack bars ontop of each other:nuclear->moveAbove(fossil);regen->moveAbove(nuclear);
// prepare x axis with country labels:QVector<double> ticks;QVector<QString> labels;ticks << 1<< 2<< 3<< 4<< 5<< 6<< 7;labels << "USA"<< "Japan"<< "Germany"<< "France"<< "UK"<< "Italy"<< "Canada";customPlot->xAxis->setAutoTicks(false);customPlot->xAxis->setAutoTickLabels(false);customPlot->xAxis->setTickVector(ticks);customPlot->xAxis->setTickVectorLabels(labels);customPlot->xAxis->setTickLabelRotation(60);customPlot->xAxis->setSubTickCount(0);customPlot->xAxis->setTickLength(0, 4);customPlot->xAxis->grid()->setVisible(true);customPlot->xAxis->setRange(0, 8);
// prepare y axis:customPlot->yAxis->setRange(0, 12.1);customPlot->yAxis->setPadding(5); // a bit more space to the left bordercustomPlot->yAxis->setLabel("Power Consumption in\nKilowatts per Capita (2007)");customPlot->yAxis->grid()->setSubGridVisible(true);QPengridPen;gridPen.setStyle(Qt::SolidLine);gridPen.setColor(QColor(0, 0, 0, 25));customPlot->yAxis->grid()->setPen(gridPen);gridPen.setStyle(Qt::DotLine);customPlot->yAxis->grid()->setSubGridPen(gridPen);
// Add data:QVector<double> fossilData, nuclearData, regenData;fossilData << 0.86*10.5<< 0.83*5.5<< 0.84*5.5<< 0.52*5.8<< 0.89*5.2<< 0.90*4.2<< 0.67*11.2;nuclearData << 0.08*10.5<< 0.12*5.5<< 0.12*5.5<< 0.40*5.8<< 0.09*5.2<< 0.00*4.2<< 0.07*11.2;regenData << 0.06*10.5<< 0.05*5.5<< 0.04*5.5<< 0.06*5.8<< 0.02*5.2<< 0.07*4.2<< 0.25*11.2;fossil->setData(ticks, fossilData);nuclear->setData(ticks, nuclearData);regen->setData(ticks, regenData);
// setup legend:customPlot->legend->setVisible(true);customPlot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignTop|Qt::AlignHCenter);customPlot->legend->setBrush(QColor(255, 255, 255, 200));QPenlegendPen;legendPen.setColor(QColor(130, 130, 130, 200));customPlot->legend->setBorderPen(legendPen);QFontlegendFont = font();legendFont.setPointSize(10);customPlot->legend->setFont(legendFont);customPlot->setInteractions(QCP::iRangeDrag| QCP::iRangeZoom);
Plot Screenshots: Statistical Box Demo
// create empty statistical box plottables:QCPStatisticalBox*sample1 = newQCPStatisticalBox(customPlot->xAxis, customPlot->yAxis);QCPStatisticalBox*sample2 = newQCPStatisticalBox(customPlot->xAxis, customPlot->yAxis);QCPStatisticalBox*sample3 = newQCPStatisticalBox(customPlot->xAxis, customPlot->yAxis);customPlot->addPlottable(sample1);customPlot->addPlottable(sample2);customPlot->addPlottable(sample3);QBrushboxBrush(QColor(60, 60, 255, 100));boxBrush.setStyle(Qt::Dense6Pattern); // make it look oldschoolsample1->setBrush(boxBrush);sample2->setBrush(boxBrush);sample3->setBrush(boxBrush);
// set data:sample1->setKey(1);sample1->setMinimum(1.1);sample1->setLowerQuartile(1.9);sample1->setMedian(2.25);sample1->setUpperQuartile(2.7);sample1->setMaximum(4.2);
sample2->setKey(2);sample2->setMinimum(0.8);sample2->setLowerQuartile(1.6);sample2->setMedian(2.2);sample2->setUpperQuartile(3.2);
sample2->setMaximum(4.9);sample2->setOutliers(QVector<double>() << 0.7<< 0.39<< 0.45<< 6.2<< 5.84);
sample3->setKey(3);sample3->setMinimum(0.2);sample3->setLowerQuartile(0.7);sample3->setMedian(1.1);sample3->setUpperQuartile(1.6);sample3->setMaximum(2.9);
// prepare manual x axis labels:customPlot->xAxis->setSubTickCount(0);customPlot->xAxis->setTickLength(0, 4);customPlot->xAxis->setTickLabelRotation(20);customPlot->xAxis->setAutoTicks(false);customPlot->xAxis->setAutoTickLabels(false);customPlot->xAxis->setTickVector(QVector<double>() << 1<< 2<< 3);customPlot->xAxis->setTickVectorLabels(QVector<QString>() << "Sample 1"<< "Sample 2"<< "Control Group");
// prepare axes:customPlot->yAxis->setLabel(QString::fromUtf8("O ? Absorption [mg]"));customPlot->rescaleAxes();customPlot->xAxis->scaleRange(1.7, customPlot->xAxis->range().center());customPlot->yAxis->setRange(0, 7);customPlot->setInteractions(QCP::iRangeDrag| QCP::iRangeZoom);
Interaction Example
#include "mainwindow.h"#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget*parent) :QMainWindow(parent),ui(newUi::MainWindow)
{srand (QDateTime::currentDateTime().toTime_t());ui->setupUi(this);
ui->customPlot->setInteractions(QCP::iRangeDrag| QCP::iRangeZoom| QCP::iSelectAxes|QCP::iSelectLegend| QCP::iSelectPlottables);
ui->customPlot->xAxis->setRange(-8, 8);ui->customPlot->yAxis->setRange(-5, 5);ui->customPlot->axisRect()->setupFullAxesBox();
ui->customPlot->plotLayout()->insertRow(0);ui->customPlot->plotLayout()->addElement(0, 0, newQCPPlotTitle(ui->customPlot, "Interaction Example"));
ui->customPlot->xAxis->setLabel("x Axis");ui->customPlot->yAxis->setLabel("y Axis");ui->customPlot->legend->setVisible(true);QFontlegendFont = font();legendFont.setPointSize(10);ui->customPlot->legend->setFont(legendFont);ui->customPlot->legend->setSelectedFont(legendFont);
ui->customPlot->legend->setSelectableParts(QCPLegend::spItems); // legend box shall not be selectable, only legend items
addRandomGraph();addRandomGraph();addRandomGraph();addRandomGraph();
// connect slot that ties some axis selections together (especially opposite axes):connect(ui->customPlot, SIGNAL(selectionChangedByUser()), this, SLOT(selectionChanged()));// connect slots that takes care that when an axis is selected, only that direction can be dragged and zoomed:connect(ui->customPlot, SIGNAL(mousePress(QMouseEvent*)), this, SLOT(mousePress()));connect(ui->customPlot, SIGNAL(mouseWheel(QWheelEvent*)), this, SLOT(mouseWheel()));
// make bottom and left axes transfer their ranges to top and right axes: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)));
// connect some interaction slots:connect(ui->customPlot, SIGNAL(titleDoubleClick(QMouseEvent*,QCPPlotTitle*)), this,
SLOT(titleDoubleClick(QMouseEvent*,QCPPlotTitle*)));connect(ui->customPlot, SIGNAL(axisDoubleClick(QCPAxis*,QCPAxis::SelectablePart,QMouseEvent*)), this,
SLOT(axisLabelDoubleClick(QCPAxis*,QCPAxis::SelectablePart)));connect(ui->customPlot, SIGNAL(legendDoubleClick(QCPLegend*,QCPAbstractLegendItem*,QMouseEvent*)), this,
SLOT(legendDoubleClick(QCPLegend*,QCPAbstractLegendItem*)));
// connect slot that shows a message in the status bar when a graph is clicked:connect(ui->customPlot, SIGNAL(plottableClick(QCPAbstractPlottable*,QMouseEvent*)), this,
SLOT(graphClicked(QCPAbstractPlottable*)));
// setup policy and connect slot for context menu popup:ui->customPlot->setContextMenuPolicy(Qt::CustomContextMenu);connect(ui->customPlot, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuRequest(QPoint)));
}
MainWindow::~MainWindow(){
deleteui;}
voidMainWindow::titleDoubleClick(QMouseEvent* event, QCPPlotTitle* title){
Q_UNUSED(event)// Set the plot title by double clicking on itboolok;QStringnewTitle = QInputDialog::getText(this, "QCustomPlot example", "New plot title:", QLineEdit::Normal,
title->text(), &ok);if(ok){
title->setText(newTitle);ui->customPlot->replot();
}
}
voidMainWindow::axisLabelDoubleClick(QCPAxis*axis, QCPAxis::SelectablePartpart){
// Set an axis label by double clicking on itif(part == QCPAxis::spAxisLabel) // only react when the actual axis label is clicked, not tick label or axis backbone{
boolok;QStringnewLabel = QInputDialog::getText(this, "QCustomPlot example", "New axis label:", QLineEdit::Normal,
axis->label(), &ok);if(ok){
axis->setLabel(newLabel);ui->customPlot->replot();
}}
}
voidMainWindow::legendDoubleClick(QCPLegend*legend, QCPAbstractLegendItem*item){
// Rename a graph by double clicking on its legend itemQ_UNUSED(legend)if(item) // only react if item was clicked (user could have clicked on border padding of legend where there is no
item, then item is 0){
QCPPlottableLegendItem*plItem = qobject_cast<QCPPlottableLegendItem*>(item);
boolok;QStringnewName = QInputDialog::getText(this, "QCustomPlot example", "New graph name:", QLineEdit::Normal,
plItem->plottable()->name(), &ok);if(ok){
plItem->plottable()->setName(newName);ui->customPlot->replot();
}}
}
voidMainWindow::selectionChanged(){
/*normally, axis base line, axis tick labels and axis labels are selectable separately, but we wantthe user only to be able to select the axis as a whole, so we tie the selected states of the tick labelsand the axis base line together. However, the axis label shall be selectable individually.
The selection state of the left and right axes shall be synchronized as well as the state of thebottom and top axes.
Further, we want to synchronize the selection of the graphs with the selection state of the respectivelegend item belonging to that graph. So the user can select a graph by either clicking on the graph itselfor on its legend item.
*/
// make top and bottom axes be selected synchronously, and handle axis and tick labels as one selectable object:if(ui->customPlot->xAxis->selectedParts().testFlag(QCPAxis::spAxis) ||
ui->customPlot->xAxis->selectedParts().testFlag(QCPAxis::spTickLabels) ||ui->customPlot->xAxis2->selectedParts().testFlag(QCPAxis::spAxis) ||
ui->customPlot->xAxis2->selectedParts().testFlag(QCPAxis::spTickLabels)){
ui->customPlot->xAxis2->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels);ui->customPlot->xAxis->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels);
}// make left and right axes be selected synchronously, and handle axis and tick labels as one selectable object:if(ui->customPlot->yAxis->selectedParts().testFlag(QCPAxis::spAxis) ||
ui->customPlot->yAxis->selectedParts().testFlag(QCPAxis::spTickLabels) ||ui->customPlot->yAxis2->selectedParts().testFlag(QCPAxis::spAxis) ||
ui->customPlot->yAxis2->selectedParts().testFlag(QCPAxis::spTickLabels)){
ui->customPlot->yAxis2->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels);ui->customPlot->yAxis->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels);
}
// synchronize selection of graphs with selection of corresponding legend items:for(inti=0; i<ui->customPlot->graphCount(); ++i){
QCPGraph*graph = ui->customPlot->graph(i);QCPPlottableLegendItem*item = ui->customPlot->legend->itemWithPlottable(graph);if(item->selected() || graph->selected()){
item->setSelected(true);graph->setSelected(true);
}}
}
voidMainWindow::mousePress(){
// if an axis is selected, only allow the direction of that axis to be dragged// if no axis is selected, both directions may be dragged
if(ui->customPlot->xAxis->selectedParts().testFlag(QCPAxis::spAxis))ui->customPlot->axisRect()->setRangeDrag(ui->customPlot->xAxis->orientation());
elseif(ui->customPlot->yAxis->selectedParts().testFlag(QCPAxis::spAxis))ui->customPlot->axisRect()->setRangeDrag(ui->customPlot->yAxis->orientation());
elseui->customPlot->axisRect()->setRangeDrag(Qt::Horizontal|Qt::Vertical);
}
voidMainWindow::mouseWheel(){
// if an axis is selected, only allow the direction of that axis to be zoomed// if no axis is selected, both directions may be zoomed
if(ui->customPlot->xAxis->selectedParts().testFlag(QCPAxis::spAxis))ui->customPlot->axisRect()->setRangeZoom(ui->customPlot->xAxis->orientation());
elseif(ui->customPlot->yAxis->selectedParts().testFlag(QCPAxis::spAxis))ui->customPlot->axisRect()->setRangeZoom(ui->customPlot->yAxis->orientation());
elseui->customPlot->axisRect()->setRangeZoom(Qt::Horizontal|Qt::Vertical);
}
voidMainWindow::addRandomGraph(){
intn = 50; // number of points in graphdoublexScale = ( rand ()/(double)RAND_MAX + 0.5)*2;doubleyScale = ( rand ()/(double)RAND_MAX + 0.5)*2;doublexOffset = ( rand ()/(double)RAND_MAX - 0.5)*4;doubleyOffset = ( rand ()/(double)RAND_MAX - 0.5)*5;doubler1 = ( rand()/(double)RAND_MAX - 0.5)*2;doubler2 = ( rand()/(double)RAND_MAX - 0.5)*2;doubler3 = ( rand()/(double)RAND_MAX - 0.5)*2;doubler4 = ( rand()/(double)RAND_MAX - 0.5)*2;QVector<double> x(n), y(n);for(inti=0; i<n; i++){
x[i] = (i/(double)n-0.5)*10.0*xScale + xOffset;y[i] = (qSin(x[i]*r1*5)*qSin(qCos(x[i]*r2)*r4*3)+r3*qCos(qSin(x[i])*r4*2))*yScale + yOffset;
}
ui->customPlot->addGraph();ui->customPlot->graph()->setName(QString("New graph %1").arg(ui->customPlot->graphCount()-1));
ui->customPlot->graph()->setData(x, y);ui->customPlot->graph()->setLineStyle((QCPGraph::LineStyle)( rand ()%5+1));if( rand ()%100> 75)
ui->customPlot->graph()->setScatterStyle(QCPScatterStyle((QCPScatterStyle::ScatterShape)( rand ()%9+1)));QPengraphPen;graphPen.setColor(QColor( rand ()%245+10, rand ()%245+10, rand ()%245+10));graphPen.setWidthF( rand ()/(double)RAND_MAX*2+1);ui->customPlot->graph()->setPen(graphPen);ui->customPlot->replot();
}
voidMainWindow::removeSelectedGraph(){
if(ui->customPlot->selectedGraphs().size() > 0){
ui->customPlot->removeGraph(ui->customPlot->selectedGraphs().first());ui->customPlot->replot();
}}
voidMainWindow::removeAllGraphs(){
ui->customPlot->clearGraphs();ui->customPlot->replot();
}
voidMainWindow::contextMenuRequest(QPointpos){
QMenu*menu = newQMenu(this);menu->setAttribute(Qt::WA_DeleteOnClose);
if(ui->customPlot->legend->selectTest(pos, false) >= 0) // context menu on legend requested{
menu->addAction("Move to top left", this, SLOT(moveLegend()))->setData((int)(Qt::AlignTop|Qt::AlignLeft));menu->addAction("Move to top center", this,
SLOT(moveLegend()))->setData((int)(Qt::AlignTop|Qt::AlignHCenter));menu->addAction("Move to top right", this, SLOT(moveLegend()))->setData((int)(Qt::AlignTop|Qt::AlignRight));menu->addAction("Move to bottom right", this,
SLOT(moveLegend()))->setData((int)(Qt::AlignBottom|Qt::AlignRight));menu->addAction("Move to bottom left", this,
SLOT(moveLegend()))->setData((int)(Qt::AlignBottom|Qt::AlignLeft));} else // general context menu on graphs requested{
menu->addAction("Add random graph", this, SLOT(addRandomGraph()));if(ui->customPlot->selectedGraphs().size() > 0)
menu->addAction("Remove selected graph", this, SLOT(removeSelectedGraph()));if(ui->customPlot->graphCount() > 0)
menu->addAction("Remove all graphs", this, SLOT(removeAllGraphs()));}
menu->popup(ui->customPlot->mapToGlobal(pos));}
voidMainWindow::moveLegend(){
if(QAction* contextAction = qobject_cast<QAction*>(sender())) // make sure this slot is really called by a context menu action, so it carries the data we need
{boolok;intdataInt = contextAction->data().toInt(&ok);if(ok){
ui->customPlot->axisRect()->insetLayout()->setInsetAlignment(0, (Qt::Alignment)dataInt);ui->customPlot->replot();
}}
}
voidMainWindow::graphClicked(QCPAbstractPlottable*plottable){
ui->statusBar->showMessage(QString("Clicked on graph '%1'.").arg(plottable->name()), 1000);}
Plot Screenshots: Item Demo
Setup function: customPlot->setInteractions(QCP::iRangeDrag| QCP::iRangeZoom);QCPGraph*graph = customPlot->addGraph();intn = 500;doublephase = 0;doublek = 3;QVector<double> x(n), y(n);for(inti=0; i<n; ++i){
x[i] = i/(double)(n-1)*34- 17;y[i] = qExp(-x[i]*x[i]/20.0)*qSin(k*x[i]+phase);
}graph->setData(x, y);graph->setPen(QPen(Qt::blue));graph->rescaleKeyAxis();customPlot->yAxis->setRange(-1.45, 1.65);customPlot->xAxis->grid()->setZeroLinePen(Qt::NoPen);
// add the bracket at the top:QCPItemBracket*bracket = newQCPItemBracket(customPlot);customPlot->addItem(bracket);bracket->left->setCoords(-8, 1.1);bracket->right->setCoords(8, 1.1);bracket->setLength(13);
// add the text label at the top:QCPItemText*wavePacketText = newQCPItemText(customPlot);customPlot->addItem(wavePacketText);wavePacketText->position->setParentAnchor(bracket->center);wavePacketText->position->setCoords(0, -10); // move 10 pixels to the top from bracket center anchorwavePacketText->setPositionAlignment(Qt::AlignBottom|Qt::AlignHCenter);wavePacketText->setText("Wavepacket");wavePacketText->setFont(QFont(font().family(), 10));
// add the phase tracer (red circle) which sticks to the graph data (and gets updated in bracketDataSlot by timer event):QCPItemTracer*phaseTracer = newQCPItemTracer(customPlot);customPlot->addItem(phaseTracer);itemDemoPhaseTracer = phaseTracer; // so we can access it later in the bracketDataSlot for animationphaseTracer->setGraph(graph);phaseTracer->setGraphKey((M_PI*1.5-phase)/k);phaseTracer->setInterpolating(true);phaseTracer->setStyle(QCPItemTracer::tsCircle);phaseTracer->setPen(QPen(Qt::red));phaseTracer->setBrush(Qt::red);phaseTracer->setSize(7);
// add label for phase tracer:QCPItemText*phaseTracerText = newQCPItemText(customPlot);customPlot->addItem(phaseTracerText);phaseTracerText->position->setType(QCPItemPosition::ptAxisRectRatio);phaseTracerText->setPositionAlignment(Qt::AlignRight|Qt::AlignBottom);
phaseTracerText->position->setCoords(1.0, 0.95); // lower right corner of axis rectphaseTracerText->setText("Points of fixed\nphase define\nphase velocity vp");phaseTracerText->setTextAlignment(Qt::AlignLeft);phaseTracerText->setFont(QFont(font().family(), 9));phaseTracerText->setPadding(QMargins(8, 0, 0, 0));
// add arrow pointing at phase tracer, coming from label:QCPItemCurve*phaseTracerArrow = newQCPItemCurve(customPlot);customPlot->addItem(phaseTracerArrow);phaseTracerArrow->start->setParentAnchor(phaseTracerText->left);phaseTracerArrow->startDir->setParentAnchor(phaseTracerArrow->start);phaseTracerArrow->startDir->setCoords(-40, 0); // direction 30 pixels to the left of parent anchor (tracerArrow->start)phaseTracerArrow->end->setParentAnchor(phaseTracer->position);phaseTracerArrow->end->setCoords(10, 10);phaseTracerArrow->endDir->setParentAnchor(phaseTracerArrow->end);phaseTracerArrow->endDir->setCoords(30, 30);phaseTracerArrow->setHead(QCPLineEnding::esSpikeArrow);phaseTracerArrow->setTail(QCPLineEnding(QCPLineEnding::esBar, (phaseTracerText->bottom->pixelPoint().y()-phaseTracerText->top->pixelPoint().y())*0.85));
// add the group velocity tracer (green circle):QCPItemTracer*groupTracer = newQCPItemTracer(customPlot);customPlot->addItem(groupTracer);groupTracer->setGraph(graph);groupTracer->setGraphKey(5.5);groupTracer->setInterpolating(true);
groupTracer->setStyle(QCPItemTracer::tsCircle);groupTracer->setPen(QPen(Qt::green));groupTracer->setBrush(Qt::green);groupTracer->setSize(7);
// add label for group tracer:QCPItemText*groupTracerText = newQCPItemText(customPlot);customPlot->addItem(groupTracerText);groupTracerText->position->setType(QCPItemPosition::ptAxisRectRatio);groupTracerText->setPositionAlignment(Qt::AlignRight|Qt::AlignTop);groupTracerText->position->setCoords(1.0, 0.20); // lower right corner of axis rectgroupTracerText->setText("Fixed positions in\nwave packet define\ngroup velocity vg");groupTracerText->setTextAlignment(Qt::AlignLeft);groupTracerText->setFont(QFont(font().family(), 9));groupTracerText->setPadding(QMargins(8, 0, 0, 0));
// add arrow pointing at group tracer, coming from label:QCPItemCurve*groupTracerArrow = newQCPItemCurve(customPlot);customPlot->addItem(groupTracerArrow);groupTracerArrow->start->setParentAnchor(groupTracerText->left);groupTracerArrow->startDir->setParentAnchor(groupTracerArrow->start);groupTracerArrow->startDir->setCoords(-40, 0); // direction 30 pixels to the left of parent anchor (tracerArrow->start)groupTracerArrow->end->setCoords(5.5, 0.4);groupTracerArrow->endDir->setParentAnchor(groupTracerArrow->end);groupTracerArrow->endDir->setCoords(0, -40);groupTracerArrow->setHead(QCPLineEnding::esSpikeArrow);
groupTracerArrow->setTail(QCPLineEnding(QCPLineEnding::esBar, (groupTracerText->bottom->pixelPoint().y()-groupTracerText->top->pixelPoint().y())*0.85));
// add dispersion arrow:QCPItemCurve*arrow = newQCPItemCurve(customPlot);customPlot->addItem(arrow);arrow->start->setCoords(1, -1.1);arrow->startDir->setCoords(-1, -1.3);arrow->endDir->setCoords(-5, -0.3);arrow->end->setCoords(-10, -0.2);arrow->setHead(QCPLineEnding::esSpikeArrow);
// add the dispersion arrow label:QCPItemText*dispersionText = newQCPItemText(customPlot);customPlot->addItem(dispersionText);dispersionText->position->setCoords(-6, -0.9);dispersionText->setRotation(40);dispersionText->setText("Dispersion with\nvp < vg");dispersionText->setFont(QFont(font().family(), 10));
// setup a timer that repeatedly calls MainWindow::bracketDataSlot:connect(&dataTimer, SIGNAL(timeout()), this, SLOT(bracketDataSlot()));dataTimer.start(0); // Interval 0 means to refresh as fast as possible
bracketDataSlot , called by timer: doublesecs = QDateTime::currentDateTime().toMSecsSinceEpoch()/1000.0;// update data to make phase move:intn = 500;doublephase = secs*5;doublek = 3;QVector<double> x(n), y(n);for(inti=0; i<n; ++i){
x[i] = i/(double)(n-1)*34- 17;y[i] = qExp(-x[i]*x[i]/20.0)*qSin(k*x[i]+phase);
}ui->customPlot->graph()->setData(x, y);
itemDemoPhaseTracer->setGraphKey((8*M_PI+ fmod(M_PI*1.5-phase, 6*M_PI))/k);
ui->customPlot->replot();
// calculate frames per second:doublekey = secs;staticdoublelastFpsKey;staticintframeCount;++frameCount;if(key-lastFpsKey > 2) // average fps over 2 seconds{
ui->statusBar->showMessage(QString("%1 FPS, Total Data points: %2").arg(frameCount/(key-lastFpsKey), 0, 'f', 0).arg(ui->customPlot->graph(0)->data()->count()), 0);
lastFpsKey = key;frameCount = 0;
}
Plot Screenshots: Advanced Axes Demo
// configure axis rect:customPlot->plotLayout()->clear(); // clear default axis rect so we can start from scratchQCPAxisRect*wideAxisRect = newQCPAxisRect(customPlot);wideAxisRect->setupFullAxesBox(true);wideAxisRect->axis(QCPAxis::atRight, 0)->setTickLabels(true);wideAxisRect->addAxis(QCPAxis::atLeft)->setTickLabelColor(QColor("#6050F8")); // add an extra axis on the left and color its numbersQCPLayoutGrid*subLayout = newQCPLayoutGrid;customPlot->plotLayout()->addElement(0, 0, wideAxisRect); // insert axis rect in first rowcustomPlot->plotLayout()->addElement(1, 0, subLayout); // sub layout in second row (grid layout will grow accordingly)//customPlot->plotLayout()->setRowStretchFactor(1, 2);// prepare axis rects that will be placed in the sublayout:QCPAxisRect*subRectLeft = newQCPAxisRect(customPlot, false); // false means to not setup default axesQCPAxisRect*subRectRight = newQCPAxisRect(customPlot, false);subLayout->addElement(0, 0, subRectLeft);subLayout->addElement(0, 1, subRectRight);subRectRight->setMaximumSize(150, 150); // make bottom right axis rect size fixed 150x150subRectRight->setMinimumSize(150, 150); // make bottom right axis rect size fixed 150x150// setup axes in sub layout axis rects:subRectLeft->addAxes(QCPAxis::atBottom| QCPAxis::atLeft);subRectRight->addAxes(QCPAxis::atBottom| QCPAxis::atRight);subRectLeft->axis(QCPAxis::atLeft)->setAutoTickCount(2);subRectRight->axis(QCPAxis::atRight)->setAutoTickCount(2);subRectRight->axis(QCPAxis::atBottom)->setAutoTickCount(2);subRectLeft->axis(QCPAxis::atBottom)->grid()->setVisible(true);// synchronize the left and right margins of the top and bottom axis rects:
QCPMarginGroup*marginGroup = newQCPMarginGroup(customPlot);subRectLeft->setMarginGroup(QCP::msLeft, marginGroup);subRectRight->setMarginGroup(QCP::msRight, marginGroup);wideAxisRect->setMarginGroup(QCP::msLeft| QCP::msRight, marginGroup);// move newly created axes on "axes" layer and grids on "grid" layer:foreach(QCPAxisRect*rect, customPlot->axisRects()){
foreach(QCPAxis*axis, rect->axes()){
axis->setLayer("axes");axis->grid()->setLayer("grid");
}}
// prepare data:QVector<double> x1a(20), y1a(20);QVector<double> x1b(50), y1b(50);QVector<double> x2(100), y2(100);QVector<double> x3, y3;qsrand(3);for(inti=0; i<x1a.size(); ++i){
x1a[i] = i/(double)(x1a.size()-1)*10-5.0;y1a[i] = qCos(x1a[i]);
}for(inti=0; i<x1b.size(); ++i)
{x1b[i] = i/(double)x1b.size()*10-5.0;y1b[i] = qExp(-x1b[i]*x1b[i]*0.2)*1000;
}for(inti=0; i<x2.size(); ++i){
x2[i] = i/(double)x2.size()*10;y2[i] = qrand()/(double)RAND_MAX-0.5+y2[qAbs(i-1)];
}x3 << 1<< 2<< 3<< 4;y3 << 2<< 2.5<< 4<< 1.5;
// create and configure plottables:QCPGraph*mainGraph1 = customPlot->addGraph(wideAxisRect->axis(QCPAxis::atBottom), wideAxisRect->axis(QCPAxis::atLeft));mainGraph1->setData(x1a, y1a);mainGraph1->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, QPen(Qt::black), QBrush(Qt::white), 6));mainGraph1->setPen(QPen(QColor(120, 120, 120), 2));QCPGraph*mainGraph2 = customPlot->addGraph(wideAxisRect->axis(QCPAxis::atBottom), wideAxisRect->axis(QCPAxis::atLeft, 1));mainGraph2->setData(x1b, y1b);mainGraph2->setPen(QPen(QColor("#8070B8"), 2));mainGraph2->setBrush(QColor(110, 170, 110, 30));mainGraph1->setChannelFillGraph(mainGraph2);mainGraph1->setBrush(QColor(255, 161, 0, 50));
QCPGraph*graph2 = customPlot->addGraph(subRectLeft->axis(QCPAxis::atBottom), subRectLeft->axis(QCPAxis::atLeft));graph2->setData(x2, y2);graph2->setLineStyle(QCPGraph::lsImpulse);graph2->setPen(QPen(QColor("#FFA100"), 1.5));
QCPBars*bars1 = newQCPBars(subRectRight->axis(QCPAxis::atBottom), subRectRight->axis(QCPAxis::atRight));customPlot->addPlottable(bars1);bars1->setWidth(3/(double)x3.size());bars1->setData(x3, y3);bars1->setPen(QPen(Qt::black));bars1->setAntialiased(false);bars1->setAntialiasedFill(false);bars1->setBrush(QColor("#705BE8"));bars1->keyAxis()->setAutoTicks(false);bars1->keyAxis()->setTickVector(x3);bars1->keyAxis()->setSubTickCount(0);
// rescale axes according to graph's data:mainGraph1->rescaleAxes();mainGraph2->rescaleAxes();graph2->rescaleAxes();bars1->rescaleAxes();wideAxisRect->axis(QCPAxis::atLeft, 1)->setRangeLower(0);
Plot Screenshots: Financial Chart Demo
customPlot->legend->setVisible(true);
// generate two sets of random walk data (one for candlestick and one for ohlc chart):intn = 500;QVector<double> time (n), value1(n), value2(n);QDateTimestart = QDateTime(QDate(2014, 6, 11));start.setTimeSpec(Qt::UTC);doublestartTime = start.toTime_t();doublebinSize = 3600*24; // bin data in 1 day intervalstime [0] = startTime;value1[0] = 60;value2[0] = 20;qsrand(9);for(inti=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;
}
// create candlestick chart:QCPFinancial*candlesticks = newQCPFinancial(customPlot->xAxis, customPlot->yAxis);
customPlot->addPlottable(candlesticks);QCPFinancialDataMapdata1 = QCPFinancial::timeSeriesToOhlc( time , value1, binSize, startTime);candlesticks->setName("Candlestick");candlesticks->setChartStyle(QCPFinancial::csCandlestick);candlesticks->setData(&data1, true);candlesticks->setWidth(binSize*0.9);candlesticks->setTwoColored(true);candlesticks->setBrushPositive(QColor(245, 245, 245));candlesticks->setBrushNegative(QColor(0, 0, 0));candlesticks->setPenPositive(QPen(QColor(0, 0, 0)));candlesticks->setPenNegative(QPen(QColor(0, 0, 0)));
// create ohlc chart:QCPFinancial*ohlc = newQCPFinancial(customPlot->xAxis, customPlot->yAxis);customPlot->addPlottable(ohlc);QCPFinancialDataMapdata2 = QCPFinancial::timeSeriesToOhlc( time , value2, binSize/3.0, startTime); // divide binSize by 3 just to make the ohlc bars a bit denserohlc->setName("OHLC");ohlc->setChartStyle(QCPFinancial::csOhlc);ohlc->setData(&data2, true);ohlc->setWidth(binSize*0.2);ohlc->setTwoColored(true);
// create bottom axis rect for volume bar chart:QCPAxisRect*volumeAxisRect = newQCPAxisRect(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:QCPBars*volumePos = newQCPBars(volumeAxisRect->axis(QCPAxis::atBottom), volumeAxisRect->axis(QCPAxis::atLeft));QCPBars*volumeNeg = newQCPBars(volumeAxisRect->axis(QCPAxis::atBottom), volumeAxisRect->axis(QCPAxis::atLeft));for(inti=0; i<n/5; ++i){
intv = qrand()%20000+qrand()%20000+qrand()%20000-10000*3;(v < 0? volumeNeg : volumePos)->addData(startTime+3600*5.0*i, qAbs(v)); // add data to either volumeNeg or volumePos,
depending on sign of v}customPlot->setAutoAddPlottableToLegend(false);customPlot->addPlottable(volumePos);customPlot->addPlottable(volumeNeg);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:volumeAxisRect->axis(QCPAxis::atBottom)->setAutoTickStep(false);volumeAxisRect->axis(QCPAxis::atBottom)->setTickStep(3600*24*4); // 4 day tickstepvolumeAxisRect->axis(QCPAxis::atBottom)->setTickLabelType(QCPAxis::ltDateTime);volumeAxisRect->axis(QCPAxis::atBottom)->setDateTimeSpec(Qt::UTC);volumeAxisRect->axis(QCPAxis::atBottom)->setDateTimeFormat("dd. MMM");volumeAxisRect->axis(QCPAxis::atBottom)->setTickLabelRotation(15);volumeAxisRect->axis(QCPAxis::atLeft)->setAutoTickCount(3);customPlot->xAxis->setBasePen(Qt::NoPen);customPlot->xAxis->setTickLabels(false);customPlot->xAxis->setTicks(false); // only want vertical grid in main axis rect, so hide xAxis backbone, ticks, and labelscustomPlot->xAxis->setAutoTickStep(false);customPlot->xAxis->setTickStep(3600*24*4); // 4 day tickstepcustomPlot->rescaleAxes();customPlot->xAxis->scaleRange(1.025, customPlot->xAxis->range().center());customPlot->yAxis->scaleRange(1.1, customPlot->yAxis->range().center());
// make axis rects' left side line up:QCPMarginGroup*group = newQCPMarginGroup(customPlot);customPlot->axisRect()->setMarginGroup(QCP::msLeft|QCP::msRight, group);volumeAxisRect->setMarginGroup(QCP::msLeft|QCP::msRight, group);