QCustomPlot是一个用于绘图和数据可视化的Qt C++小部件。它没有进一步的依赖性,并且有很好的文档记录。该绘图库专注于制作美观、出版质量的2D绘图、图形和图表,并为实时可视化应用程序提供高性能。查看设置和基本绘图教程以开始。
QCustomPlot可以导出为各种格式,如矢量化PDF文件和光栅化图像,如PNG、JPG和BMP。QCustomPlot是在应用程序中显示实时数据以及为其他媒体生成高质量绘图的解决方案。

eg1:一个简单的带填充的衰减正弦函数及其红色指数包络

// add two new graphs and set their look:
customPlot->addGraph();
customPlot->graph(0)->setPen(QPen(Qt::blue)); // line color blue for first graph
customPlot->graph(0)->setBrush(QBrush(QColor(0, 0, 255, 20))); // first graph will be filled with translucent blue
customPlot->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(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); // 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);

eg2:具有数据点、相应误差条和2sigma置信带的sinc函数

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();
QPen pen;
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 legend
customPlot->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));
// add error bars:
QCPErrorBars *errorBars = new QCPErrorBars(customPlot->xAxis, customPlot->yAxis);
errorBars->removeFromLegend();
errorBars->setAntialiased(false);
errorBars->setDataPlottable(customPlot->graph(3));
errorBars->setPen(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 (int i=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 (int i=0; i<50; ++i)
{// generate a gaussian distributed random number:double tmp1 = rand()/(double)RAND_MAX;double tmp2 = rand()/(double)RAND_MAX;double r = 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)->setData(x1, y1);
errorBars->setData(y1err);
customPlot->graph(2)->rescaleAxes();
customPlot->graph(3)->rescaleAxes(true);
// setup look of bottom tick labels:
customPlot->xAxis->setTickLabelRotation(30);
customPlot->xAxis->ticker()->setTickCount(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();

eg3:几种散点样式的演示

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;QPen pen;
// add graphs with different scatter styles:
for (int i=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 (int k=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.indexOfEnumerator("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{QPainterPath customScatterPath;for (int i=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();

eg4:演示QCustomPlot在设置情节样式方面的多功能性

eg

// 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 (int i=0; i<x1.size(); ++i)
{x1[i] = i/(double)(x1.size()-1)*10;y1[i] = qCos(x1[i]*0.8+qSin(x1[i]*0.16+1.0))*qSin(x1[i]*0.54)+1.4;
}
for (int i=0; i<x2.size(); ++i)
{x2[i] = i/(double)(x2.size()-1)*10;y2[i] = qCos(x2[i]*0.85+qSin(x2[i]*0.165+1.1))*qSin(x2[i]*0.50)+1.7;
}
for (int i=0; i<x3.size(); ++i)
{x3[i] = i/(double)(x3.size()-1)*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 (int i=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 = new QCPBars(customPlot->xAxis, customPlot->yAxis);
bars1->setWidth(9/(double)x3.size());
bars1->setData(x3, y3);
bars1->setPen(Qt::NoPen);
bars1->setBrush(QColor(10, 140, 70, 160));QCPBars *bars2 = new QCPBars(customPlot->xAxis, customPlot->yAxis);
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);
QLinearGradient plotGradient;
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);
QLinearGradient axisRectGradient;
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);

eg5:一个带有色阶的二维彩色地图。色阶可以像轴一样拖动和缩放

// configure axis rect:
customPlot->setInteractions(QCP::iRangeDrag|QCP::iRangeZoom); // this will also allow rescaling the color scale by dragging/zooming
customPlot->axisRect()->setupFullAxesBox(true);
customPlot->xAxis->setLabel("x");
customPlot->yAxis->setLabel("y");// set up the QCPColorMap:
QCPColorMap *colorMap = new QCPColorMap(customPlot->xAxis, customPlot->yAxis);
int nx = 200;
int ny = 200;
colorMap->data()->setSize(nx, ny); // we want the color map to have nx * ny data points
colorMap->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:
double x, y, z;
for (int xIndex=0; xIndex<nx; ++xIndex)
{for (int yIndex=0; yIndex<ny; ++yIndex){colorMap->data()->cellToCoord(xIndex, yIndex, &x, &y);double r = 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 = new QCPColorScale(customPlot);
customPlot->plotLayout()->addElement(0, 1, colorScale); // add it to the right of the main axis rect
colorScale->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 scale
colorScale->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 = new QCPMarginGroup(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();

eg6:Pixmap散点和多行轴标签,以及顶部的绘图标题

customPlot->axisRect()->setBackground(QPixmap("./solarpanels.jpg"));
customPlot->addGraph();
customPlot->graph()->setLineStyle(QCPGraph::lsLine);
QPen pen;
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 << 2011;
value << 2.17 << 3.42 << 4.94 << 10.38 << 15.86 << 29.33 << 52.1;
customPlot->graph()->setData(year, value);// set title of plot:
customPlot->plotLayout()->insertRow(0);
customPlot->plotLayout()->addElement(0, 0, new QCPTextElement(customPlot, "Regenerative Energies", QFont("sans", 12, QFont::Bold)));
// 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->setSubTicks(false);
customPlot->yAxis2->setSubTicks(false);
customPlot->xAxis->setRange(2004.5, 2011.5);
customPlot->yAxis->setRange(0, 52);
// setup legend:
customPlot->legend->setFont(QFont(font().family(), 7));
customPlot->legend->setIconSize(50, 20);
customPlot->legend->setVisible(true);
customPlot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignLeft | Qt::AlignTop);

eg7:实时生成数据和时间底轴

Setup function:
customPlot->addGraph(); // blue line
customPlot->graph(0)->setPen(QPen(QColor(40, 110, 255)));
customPlot->addGraph(); // red line
customPlot->graph(1)->setPen(QPen(QColor(255, 110, 40)));QSharedPointer<QCPAxisTickerTime> timeTicker(new QCPAxisTickerTime);
timeTicker->setTimeFormat("%h:%m:%s");
customPlot->xAxis->setTicker(timeTicker);
customPlot->axisRect()->setupFullAxesBox();
customPlot->yAxis->setRange(-1.2, 1.2);// 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 possiblerealtimeDataSlot, called by timer:
static QTime time(QTime::currentTime());
// calculate two new data points:
double key = time.elapsed()/1000.0; // time elapsed since start of demo, in seconds
static double lastPointKey = 0;
if (key-lastPointKey > 0.002) // at most add point every 2 ms
{// add data to lines:ui->customPlot->graph(0)->addData(key, qSin(key)+qrand()/(double)RAND_MAX*1*qSin(key/0.3843));ui->customPlot->graph(1)->addData(key, qCos(key)+qrand()/(double)RAND_MAX*0.5*qSin(key/0.4364));// 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, 8, Qt::AlignRight);
ui->customPlot->replot();// calculate frames per second:
static double lastFpsKey;
static int frameCount;
++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()->size()+ui->customPlot->graph(1)->data()->size()), 0);lastFpsKey = key;frameCount = 0;
}

eg8:具有不同键/值轴和顶部轴圆周率刻度标记的多种绘图样式

customPlot->setLocale(QLocale(QLocale::English, QLocale::UnitedKingdom)); // period as decimal separator and comma as thousand separator
customPlot->legend->setVisible(true);
QFont legendFont = font();  // start out with MainWindow's font..
legendFont.setPointSize(9); // and make a bit smaller for legend
customPlot->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 function
customPlot->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 image
customPlot->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 function with error bars
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(customPlot->graph(1));// 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 2
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");// setup for graph 4: key axis right, value axis top
// will contain parabolically distributed data points with some random perturbance
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");// 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 (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;
}// pass data points to graphs:
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);
// 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:
customPlot->xAxis2->setTicker(QSharedPointer<QCPAxisTickerPi>(new QCPAxisTickerPi));
// add title layout element:
customPlot->plotLayout()->insertRow(0);
customPlot->plotLayout()->addElement(0, 0, new QCPTextElement(customPlot, "Way too many graphs in one plot", QFont("sans", 12, QFont::Bold)));
// 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);

eg9:对数轴缩放。正弦函数在负无穷远处过零点的正确显示注记

customPlot->setNoAntialiasingOnDrag(true); // more performance/responsiveness during dragging
customPlot->addGraph();
QPen pen;
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)->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!");const int dataCount = 200;
const int dataFactorialCount = 21;
QVector<QCPGraphData> dataLinear(dataCount), dataMinusSinExp(dataCount), dataPlusSinExp(dataCount), dataFactorial(dataFactorialCount);
for (int i=0; i<dataCount; ++i)
{dataLinear[i].key = i/10.0;dataLinear[i].value = dataLinear[i].key;dataMinusSinExp[i].key = i/10.0;dataMinusSinExp[i].value = -qSin(dataMinusSinExp[i].key)*qExp(dataMinusSinExp[i].key);dataPlusSinExp[i].key = i/10.0;dataPlusSinExp[i].value = qSin(dataPlusSinExp[i].key)*qExp(dataPlusSinExp[i].key);
}
for (int i=0; i<dataFactorialCount; ++i)
{dataFactorial[i].key = i;dataFactorial[i].value = 1.0;for (int k=1; k<=i; ++k) dataFactorial[i].value *= k; // factorial
}
customPlot->graph(0)->data()->set(dataLinear);
customPlot->graph(1)->data()->set(dataMinusSinExp);
customPlot->graph(2)->data()->set(dataPlusSinExp);
customPlot->graph(3)->data()->set(dataFactorial);customPlot->yAxis->grid()->setSubGridVisible(true);
customPlot->xAxis->grid()->setSubGridVisible(true);
customPlot->yAxis->setScaleType(QCPAxis::stLogarithmic);
customPlot->yAxis2->setScaleType(QCPAxis::stLogarithmic);
QSharedPointer<QCPAxisTickerLog> logTicker(new QCPAxisTickerLog);
customPlot->yAxis->setTicker(logTicker);
customPlot->yAxis2->setTicker(logTicker);
customPlot->yAxis->setNumberFormat("eb"); // e = exponential, b = beautiful decimal powers
customPlot->yAxis->setNumberPrecision(0); // makes sure "1*10^4" is displayed only as "10^4"
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

eg10:几种线条风格的演示

customPlot->legend->setVisible(true);
customPlot->legend->setFont(QFont("Helvetica", 9));
QPen pen;
QStringList lineNames;
lineNames << "lsNone" << "lsLine" << "lsStepLeft" << "lsStepRight" << "lsStepCenter" << "lsImpulse";
// add graphs with different line styles:
for (int i=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 (int j=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();

eg11:在底轴上使用填充和智能日期刻度的随机游动

// 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:
double now = QDateTime::currentDateTime().toTime_t();
srand(8); // set the random seed, so we always get the same random data
// create multiple graphs:
for (int gi=0; gi<5; ++gi)
{customPlot->addGraph();QColor color(20+200/4.0*gi,70*(1.6-gi/4.0), 150, 150);customPlot->graph()->setLineStyle(QCPGraph::lsLine);customPlot->graph()->setPen(QPen(color.lighter(200)));customPlot->graph()->setBrush(QBrush(color));// generate random walk data: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);elsetimeData[i].value = qFabs(timeData[i-1].value)*(1+0.02/4.0*(4-gi)) + (i/50.0+1)*(rand()/(double)RAND_MAX-0.5);}customPlot->graph()->data()->set(timeData);
}
// configure bottom axis to show date instead of number:
QSharedPointer<QCPAxisTickerDateTime> dateTicker(new QCPAxisTickerDateTime);
dateTicker->setDateTimeFormat("d. MMMM\nyyyy");
customPlot->xAxis->setTicker(dateTicker);
// configure left axis text labels:
QSharedPointer<QCPAxisTickerText> textTicker(new QCPAxisTickerText);
textTicker->addTick(10, "a bit\nlow");
textTicker->addTick(50, "quite\nhigh");
customPlot->yAxis->setTicker(textTicker);
// 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 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 with slightly transparent background brush:
customPlot->legend->setVisible(true);
customPlot->legend->setBrush(QColor(255, 255, 255, 150));

eg12:半透明梯度填充参数曲线

// create empty curve objects:
QCPCurve *fermatSpiral1 = new QCPCurve(customPlot->xAxis, customPlot->yAxis);
QCPCurve *fermatSpiral2 = new QCPCurve(customPlot->xAxis, customPlot->yAxis);
QCPCurve *deltoidRadial = new QCPCurve(customPlot->xAxis, customPlot->yAxis);
// generate the curve data points:
const int pointCount = 500;
QVector<QCPCurveData> dataSpiral1(pointCount), dataSpiral2(pointCount), dataDeltoid(pointCount);
for (int i=0; i<pointCount; ++i)
{double phi = i/(double)(pointCount-1)*8*M_PI;double theta = i/(double)(pointCount-1)*2*M_PI;dataSpiral1[i] = QCPCurveData(i, qSqrt(phi)*qCos(phi), qSqrt(phi)*qSin(phi));dataSpiral2[i] = QCPCurveData(i, -dataSpiral1[i].key, -dataSpiral1[i].value);dataDeltoid[i] = QCPCurveData(i, 2*qCos(2*theta)+qCos(1*theta)+2*qSin(theta), 2*qSin(2*theta)-qSin(1*theta));
}
// pass the data to the curves; we know t (i in loop above) is ascending, so set alreadySorted=true (saves an extra internal sort):
fermatSpiral1->data()->set(dataSpiral1, true);
fermatSpiral2->data()->set(dataSpiral2, true);
deltoidRadial->data()->set(dataDeltoid, true);
// 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)));
QRadialGradient radialGrad(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();

eg13:带手动x轴刻度标签的三个堆叠条形图

// set dark background gradient:
QLinearGradient gradient(0, 0, 0, 400);
gradient.setColorAt(0, QColor(90, 90, 90));
gradient.setColorAt(0.38, QColor(105, 105, 105));
gradient.setColorAt(1, QColor(70, 70, 70));
customPlot->setBackground(QBrush(gradient));// create empty bar chart objects:
QCPBars *regen = new QCPBars(customPlot->xAxis, customPlot->yAxis);
QCPBars *nuclear = new QCPBars(customPlot->xAxis, customPlot->yAxis);
QCPBars *fossil = new QCPBars(customPlot->xAxis, customPlot->yAxis);
regen->setAntialiased(false); // gives more crisp, pixel aligned bar borders
nuclear->setAntialiased(false);
fossil->setAntialiased(false);
regen->setStackingGap(1);
nuclear->setStackingGap(1);
fossil->setStackingGap(1);
// set names and colors:
fossil->setName("Fossil fuels");
fossil->setPen(QPen(QColor(111, 9, 176).lighter(170)));
fossil->setBrush(QColor(111, 9, 176));
nuclear->setName("Nuclear");
nuclear->setPen(QPen(QColor(250, 170, 20).lighter(150)));
nuclear->setBrush(QColor(250, 170, 20));
regen->setName("Regenerative");
regen->setPen(QPen(QColor(0, 168, 140).lighter(130)));
regen->setBrush(QColor(0, 168, 140));
// stack bars on top 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";
QSharedPointer<QCPAxisTickerText> textTicker(new QCPAxisTickerText);
textTicker->addTicks(ticks, labels);
customPlot->xAxis->setTicker(textTicker);
customPlot->xAxis->setTickLabelRotation(60);
customPlot->xAxis->setSubTicks(false);
customPlot->xAxis->setTickLength(0, 4);
customPlot->xAxis->setRange(0, 8);
customPlot->xAxis->setBasePen(QPen(Qt::white));
customPlot->xAxis->setTickPen(QPen(Qt::white));
customPlot->xAxis->grid()->setVisible(true);
customPlot->xAxis->grid()->setPen(QPen(QColor(130, 130, 130), 0, Qt::DotLine));
customPlot->xAxis->setTickLabelColor(Qt::white);
customPlot->xAxis->setLabelColor(Qt::white);// prepare y axis:
customPlot->yAxis->setRange(0, 12.1);
customPlot->yAxis->setPadding(5); // a bit more space to the left border
customPlot->yAxis->setLabel("Power Consumption in\nKilowatts per Capita (2007)");
customPlot->yAxis->setBasePen(QPen(Qt::white));
customPlot->yAxis->setTickPen(QPen(Qt::white));
customPlot->yAxis->setSubTickPen(QPen(Qt::white));
customPlot->yAxis->grid()->setSubGridVisible(true);
customPlot->yAxis->setTickLabelColor(Qt::white);
customPlot->yAxis->setLabelColor(Qt::white);
customPlot->yAxis->grid()->setPen(QPen(QColor(130, 130, 130), 0, Qt::SolidLine));
customPlot->yAxis->grid()->setSubGridPen(QPen(QColor(130, 130, 130), 0, Qt::DotLine));// 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, 100));
customPlot->legend->setBorderPen(Qt::NoPen);
QFont legendFont = font();
legendFont.setPointSize(10);
customPlot->legend->setFont(legendFont);
customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);

eg14:带离群点的统计5参数盒图

QCPStatisticalBox *statistical = new QCPStatisticalBox(customPlot->xAxis, customPlot->yAxis);
QBrush boxBrush(QColor(60, 60, 255, 100));
boxBrush.setStyle(Qt::Dense6Pattern); // make it look oldschool
statistical->setBrush(boxBrush);// specify data:
statistical->addData(1, 1.1, 1.9, 2.25, 2.7, 4.2);
statistical->addData(2, 0.8, 1.6, 2.2, 3.2, 4.9, QVector<double>() << 0.7 << 0.34 << 0.45 << 6.2 << 5.84); // provide some outliers as QVector
statistical->addData(3, 0.2, 0.7, 1.1, 1.6, 2.9);// prepare manual x axis labels:
customPlot->xAxis->setSubTicks(false);
customPlot->xAxis->setTickLength(0, 4);
customPlot->xAxis->setTickLabelRotation(20);
QSharedPointer<QCPAxisTickerText> textTicker(new QCPAxisTickerText);
textTicker->addTick(1, "Sample 1");
textTicker->addTick(2, "Sample 2");
textTicker->addTick(3, "Control Group");
customPlot->xAxis->setTicker(textTicker);// 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);

eg15:

#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::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);QCPTextElement *title = new QCPTextElement(ui->customPlot, "Interaction Example", QFont("sans", 17, QFont::Bold));ui->customPlot->plotLayout()->addElement(0, 0, title);ui->customPlot->xAxis->setLabel("x Axis");ui->customPlot->yAxis->setLabel("y Axis");ui->customPlot->legend->setVisible(true);QFont legendFont = 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 itemsaddRandomGraph();addRandomGraph();addRandomGraph();addRandomGraph();ui->customPlot->rescaleAxes();// 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(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(title, SIGNAL(doubleClicked(QMouseEvent*)), this, SLOT(titleDoubleClick(QMouseEvent*)));// connect slot that shows a message in the status bar when a graph is clicked:connect(ui->customPlot, SIGNAL(plottableClick(QCPAbstractPlottable*,int,QMouseEvent*)), this, SLOT(graphClicked(QCPAbstractPlottable*,int)));// 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()
{delete ui;
}void MainWindow::titleDoubleClick(QMouseEvent* event)
{Q_UNUSED(event)if (QCPTextElement *title = qobject_cast<QCPTextElement*>(sender())){// Set the plot title by double clicking on itbool ok;QString newTitle = QInputDialog::getText(this, "QCustomPlot example", "New plot title:", QLineEdit::Normal, title->text(), &ok);if (ok){title->setText(newTitle);ui->customPlot->replot();}}
}void MainWindow::axisLabelDoubleClick(QCPAxis *axis, QCPAxis::SelectablePart part)
{// 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{bool ok;QString newLabel = QInputDialog::getText(this, "QCustomPlot example", "New axis label:", QLineEdit::Normal, axis->label(), &ok);if (ok){axis->setLabel(newLabel);ui->customPlot->replot();}}
}void MainWindow::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);bool ok;QString newName = QInputDialog::getText(this, "QCustomPlot example", "New graph name:", QLineEdit::Normal, plItem->plottable()->name(), &ok);if (ok){plItem->plottable()->setName(newName);ui->customPlot->replot();}}
}void MainWindow::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 (int i=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->setSelection(QCPDataSelection(graph->data()->dataRange()));}}
}void MainWindow::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 draggedif (ui->customPlot->xAxis->selectedParts().testFlag(QCPAxis::spAxis))ui->customPlot->axisRect()->setRangeDrag(ui->customPlot->xAxis->orientation());else if (ui->customPlot->yAxis->selectedParts().testFlag(QCPAxis::spAxis))ui->customPlot->axisRect()->setRangeDrag(ui->customPlot->yAxis->orientation());elseui->customPlot->axisRect()->setRangeDrag(Qt::Horizontal|Qt::Vertical);
}void MainWindow::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 zoomedif (ui->customPlot->xAxis->selectedParts().testFlag(QCPAxis::spAxis))ui->customPlot->axisRect()->setRangeZoom(ui->customPlot->xAxis->orientation());else if (ui->customPlot->yAxis->selectedParts().testFlag(QCPAxis::spAxis))ui->customPlot->axisRect()->setRangeZoom(ui->customPlot->yAxis->orientation());elseui->customPlot->axisRect()->setRangeZoom(Qt::Horizontal|Qt::Vertical);
}void MainWindow::addRandomGraph()
{int n = 50; // number of points in graphdouble xScale = (rand()/(double)RAND_MAX + 0.5)*2;double yScale = (rand()/(double)RAND_MAX + 0.5)*2;double xOffset = (rand()/(double)RAND_MAX - 0.5)*4;double yOffset = (rand()/(double)RAND_MAX - 0.5)*10;double r1 = (rand()/(double)RAND_MAX - 0.5)*2;double r2 = (rand()/(double)RAND_MAX - 0.5)*2;double r3 = (rand()/(double)RAND_MAX - 0.5)*2;double r4 = (rand()/(double)RAND_MAX - 0.5)*2;QVector<double> x(n), y(n);for (int i=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 > 50)ui->customPlot->graph()->setScatterStyle(QCPScatterStyle((QCPScatterStyle::ScatterShape)(rand()%14+1)));QPen graphPen;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();
}void MainWindow::removeSelectedGraph()
{if (ui->customPlot->selectedGraphs().size() > 0){ui->customPlot->removeGraph(ui->customPlot->selectedGraphs().first());ui->customPlot->replot();}
}void MainWindow::removeAllGraphs()
{ui->customPlot->clearGraphs();ui->customPlot->replot();
}void MainWindow::contextMenuRequest(QPoint pos)
{QMenu *menu = new QMenu(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));
}void MainWindow::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{bool ok;int dataInt = contextAction->data().toInt(&ok);if (ok){ui->customPlot->axisRect()->insetLayout()->setInsetAlignment(0, (Qt::Alignment)dataInt);ui->customPlot->replot();}}
}void MainWindow::graphClicked(QCPAbstractPlottable *plottable, int dataIndex)
{// since we know we only have QCPGraphs in the plot, we can immediately access interface1D()// usually it's better to first check whether interface1D() returns non-zero, and only then use it.double dataValue = plottable->interface1D()->dataMainValue(dataIndex);QString message = QString("Clicked on graph '%1' at data point #%2 with value %3.").arg(plottable->name()).arg(dataIndex).arg(dataValue);ui->statusBar->showMessage(message, 2500);
}

eg16:

Setup function:
customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
QCPGraph *graph = customPlot->addGraph();
int n = 500;
double phase = 0;
double k = 3;
QVector<double> x(n), y(n);
for (int i=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 = new QCPItemBracket(customPlot);
bracket->left->setCoords(-8, 1.1);
bracket->right->setCoords(8, 1.1);
bracket->setLength(13);// add the text label at the top:
QCPItemText *wavePacketText = new QCPItemText(customPlot);
wavePacketText->position->setParentAnchor(bracket->center);
wavePacketText->position->setCoords(0, -10); // move 10 pixels to the top from bracket center anchor
wavePacketText->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 = new QCPItemTracer(customPlot);
itemDemoPhaseTracer = phaseTracer; // so we can access it later in the bracketDataSlot for animation
phaseTracer->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 = new QCPItemText(customPlot);
phaseTracerText->position->setType(QCPItemPosition::ptAxisRectRatio);
phaseTracerText->setPositionAlignment(Qt::AlignRight|Qt::AlignBottom);
phaseTracerText->position->setCoords(1.0, 0.95); // lower right corner of axis rect
phaseTracerText->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 = new QCPItemCurve(customPlot);
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->pixelPosition().y()-phaseTracerText->top->pixelPosition().y())*0.85));// add the group velocity tracer (green circle):
QCPItemTracer *groupTracer = new QCPItemTracer(customPlot);
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 = new QCPItemText(customPlot);
groupTracerText->position->setType(QCPItemPosition::ptAxisRectRatio);
groupTracerText->setPositionAlignment(Qt::AlignRight|Qt::AlignTop);
groupTracerText->position->setCoords(1.0, 0.20); // lower right corner of axis rect
groupTracerText->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 = new QCPItemCurve(customPlot);
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->pixelPosition().y()-groupTracerText->top->pixelPosition().y())*0.85));// add dispersion arrow:
QCPItemCurve *arrow = new QCPItemCurve(customPlot);
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 = new QCPItemText(customPlot);
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:double secs = QCPAxisTickerDateTime::dateTimeToKey(QDateTime::currentDateTime());// update data to make phase move:
int n = 500;
double phase = secs*5;
double k = 3;
QVector<double> x(n), y(n);
for (int i=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:
double key = secs;
static double lastFpsKey;
static int frameCount;
++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()->size()), 0);lastFpsKey = key;frameCount = 0;
}

eg17:

// configure axis rect:
customPlot->plotLayout()->clear(); // clear default axis rect so we can start from scratch
QCPAxisRect *wideAxisRect = new QCPAxisRect(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 numbers
QCPLayoutGrid *subLayout = new QCPLayoutGrid;
customPlot->plotLayout()->addElement(0, 0, wideAxisRect); // insert axis rect in first row
customPlot->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 = new QCPAxisRect(customPlot, false); // false means to not setup default axes
QCPAxisRect *subRectRight = new QCPAxisRect(customPlot, false);
subLayout->addElement(0, 0, subRectLeft);
subLayout->addElement(0, 1, subRectRight);
subRectRight->setMaximumSize(150, 150); // make bottom right axis rect size fixed 150x150
subRectRight->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)->ticker()->setTickCount(2);
subRectRight->axis(QCPAxis::atRight)->ticker()->setTickCount(2);
subRectRight->axis(QCPAxis::atBottom)->ticker()->setTickCount(2);
subRectLeft->axis(QCPAxis::atBottom)->grid()->setVisible(true);
// synchronize the left and right margins of the top and bottom axis rects:
QCPMarginGroup *marginGroup = new QCPMarginGroup(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<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;// create and configure plottables:
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();
// setup a ticker for subBars key axis that only gives integer ticks:
QSharedPointer<QCPAxisTickerFixed> intTicker(new QCPAxisTickerFixed);
intTicker->setTickStep(1.0);
intTicker->setScaleStrategy(QCPAxisTickerFixed::ssMultiples);
subBars->keyAxis()->setTicker(intTicker);

eg18:

customPlot->legend->setVisible(true);// generate two sets of random walk data (one for candlestick and one for ohlc chart):
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; // bin data in 1 day intervals
time[0] = startTime;
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;
}// create candlestick chart:
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)));// create ohlc chart:
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)); // divide binSize by 3 just to make the ohlc bars a bit denser
ohlc->setWidth(binSize*0.2);
ohlc->setTwoColored(true);// create bottom axis rect for volume bar chart:
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)); // add data to either volumeNeg or volumePos, depending on sign of 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); // only want vertical grid in main axis rect, so hide xAxis backbone, ticks, and labels
customPlot->xAxis->setTicker(dateTimeTicker);
customPlot->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 = new QCPMarginGroup(customPlot);
customPlot->axisRect()->setMarginGroup(QCP::msLeft|QCP::msRight, group);
volumeAxisRect->setMarginGroup(QCP::msLeft|QCP::msRight, group);

QCustomplot相关推荐

  1. QCustomPlot使用手冊(三)

    一.改变范围 QCustomPlot *customplot; customplot->setInteraction(QCP::iRangeDrag,true); 使控件能够拖拉. custom ...

  2. Ubuntu使用QCustomPlot简介

    参考网址 https://blog.csdn.net/zyc_csdn/article/details/78840376 显示实时数据 https://blog.csdn.net/qq_2887712 ...

  3. QCustomPlot的简单用法总结

    QCustomPlot的简单用法总结 第一部分:QCustomPlot的下载与安装 第二部分:QCustomPlot在VS2013+QT下的使用 QCustomPlot的简单用法总结    写在前面, ...

  4. qt跟随鼠标动态绘制_采用Qt快速绘制多条曲线(折线),跟随鼠标动态显示线上点的值(基于Qt的开源绘图控件QCustomPlot进行二次开发)...

    #include "MyTracer.h"XxwTracer::XxwTracer(QCustomPlot*_plot, TracerType _type, QObject *pa ...

  5. QCustomplot控件设备背景图片(Qt图片自适应控件大小),并且设置绘图区域颜色透明

    核心代码如下 其中customplot是传入的QCustomplot指针 customPlot->setBackground(QPixmap(":/img/line1.png" ...

  6. QCustomplot设置背景为透明色

    ui->widget_2->setBackground(QColor(255,255,255,0)); ui->widget_2为QCustomplot的指针

  7. QT利用QCustomplot绘制折线图海底声速梯度图,解决一条曲线中一个X值对应两个Y值

    一.问题描述 我想要绘制如下的图 最近遇到一个问题就是绘制海底声速梯度图,当我绘制深海情况下的声速梯度,有一个折回来的曲线,如果我仅仅用普通的曲线绘制会出现来回折线的情况如下图所示: 里面细节如上图所 ...

  8. QCustomplot怎么实现对大数据量的自适应采样显示不卡顿

    我在之前使用QCustomplot时候,当时需要特别大的数据量的显示,结果图像显示的特别卡顿,CPU占用率也特别高,然后当时在解决时候是自己写了采样抽取数据的函数,最后解决的. 然后这回在阅读手册时候 ...

  9. QCustomPlot实现实时动态曲线(包含手动设置XY轴显示的方法)

    Qt4中,可以使用QCustompPlot来绘制曲线,QCustompPlot是一个第三方工具,可以到官网下载:http://www.qcustomplot.com/index.php/downloa ...

  10. Qt第三方库QCustomPlot——认识图表的各个部分

    QCustomPlot类的命名规则是QCP加xxx.类的组织有很强的区分性,就像Qt中分了模块一样 下面了解图表的各组成部分. 观察下面这个图表: 对应名称及相应类如下:各组成 where class ...

最新文章

  1. 圣路易斯华盛顿大学计算机科学,圣路易斯华盛顿大学计算机科学专业入学要求是什么?...
  2. 使用 Boost.MPI 的 all_reduce() 计算最小值的示例
  3. javascript设置和获取cookie的方法
  4. c++11 lambda
  5. 自己写cache server之网络框架处理——Oracle、Mysql都不靠谱儿(中)
  6. 蒙特利尔问题(三门问题)的解释
  7. LoadRunner压力测试案列
  8. 珍爱网App竞品分析报告
  9. 拼多多商品详情查询V1新版接口
  10. 【网站】八大极品桌面壁纸网站,惊艳
  11. 湖南人,霸占互联网的三分天下
  12. 【离散数学】最大元素、最小元素、极大元素、极小元素、上界、下界、最小上界(上确界)、最大下界(下确界)
  13. sqldblink建好不能查询_眉山这个停车场显示有车位却不能停?原来是……
  14. 企业邮箱怎么开通?手机微信怎么绑定公司邮箱?
  15. Postman couldn‘t upload file
  16. 微博签到数据——北京、上海、昆明、深圳(2018-2022已更新完毕)
  17. 数据分析师有发展前景吗?
  18. Jquery.city-picker 实现省市区三级联动
  19. php直播系统app吗,ThinkPHP完美运营版安卓苹果双端直播系统APP源码 带主播连麦PK功能源码...
  20. 【软件安装故障排除】安装完PyCharm,启动时弹出“Failed to load JVM DLL\bin\server\jvm.dll“解决方案

热门文章

  1. 理解ASM(六)ASM文件管理
  2. 流量卡之家:为推广5G 4G网络降速?三大运营商回应:不存在的!
  3. Java与Kotlin的单例模式(霸气.jpg)
  4. 200个经典C语言程序
  5. 区块链技术是关键?元宇宙热潮背后的三股驱动力
  6. Java线程池ThreadPoolExecutor参数讲解、实例助记 保证你过目不忘
  7. 【天光学术】思想政治教育论文:我国古代思想政治教育的文化历史演进及启示
  8. js中字符串和int类型相互转化
  9. 腾讯微博宣布关闭!下一个会是微视吗?
  10. 养成番:0基础入门学习Python---Day05(元组、二维元组、字典、set集合以及操作方法)