├── README.md ├── axistag.cpp ├── axistag.h ├── balboa.jpg ├── images.qrc ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── plot-examples.pro ├── qcpex.gif ├── qcustomplot.cpp ├── qcustomplot.h ├── solarpanels.jpg └── sun.png /README.md: -------------------------------------------------------------------------------- 1 | # QCPExamplesCollection 2 | QCustomPlot examples on one single app, with additionnal real time examples (waterfall...) 3 | 4 | ![](qcpex.gif) 5 | -------------------------------------------------------------------------------- /axistag.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | ** ** 3 | ** QCustomPlot, an easy to use, modern plotting widget for Qt ** 4 | ** Copyright (C) 2011-2018 Emanuel Eichhammer ** 5 | ** ** 6 | ** This program is free software: you can redistribute it and/or modify ** 7 | ** it under the terms of the GNU General Public License as published by ** 8 | ** the Free Software Foundation, either version 3 of the License, or ** 9 | ** (at your option) any later version. ** 10 | ** ** 11 | ** This program is distributed in the hope that it will be useful, ** 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** 14 | ** GNU General Public License for more details. ** 15 | ** ** 16 | ** You should have received a copy of the GNU General Public License ** 17 | ** along with this program. If not, see http://www.gnu.org/licenses/. ** 18 | ** ** 19 | **************************************************************************** 20 | ** Author: Emanuel Eichhammer ** 21 | ** Website/Contact: http://www.qcustomplot.com/ ** 22 | ** Date: 25.06.18 ** 23 | ** Version: 2.0.1 ** 24 | ****************************************************************************/ 25 | 26 | #include "axistag.h" 27 | 28 | AxisTag::AxisTag(QCPAxis *parentAxis) : 29 | QObject(parentAxis), 30 | mAxis(parentAxis) 31 | { 32 | // The dummy tracer serves here as an invisible anchor which always sticks to the right side of 33 | // the axis rect 34 | mDummyTracer = new QCPItemTracer(mAxis->parentPlot()); 35 | mDummyTracer->setVisible(false); 36 | mDummyTracer->position->setTypeX(QCPItemPosition::ptAxisRectRatio); 37 | mDummyTracer->position->setTypeY(QCPItemPosition::ptPlotCoords); 38 | mDummyTracer->position->setAxisRect(mAxis->axisRect()); 39 | mDummyTracer->position->setAxes(0, mAxis); 40 | mDummyTracer->position->setCoords(1, 0); 41 | 42 | // the arrow end (head) is set to move along with the dummy tracer by setting it as its parent 43 | // anchor. Its coordinate system (setCoords) is thus pixels, and this is how the needed horizontal 44 | // offset for the tag of the second y axis is achieved. This horizontal offset gets dynamically 45 | // updated in AxisTag::updatePosition. the arrow "start" is simply set to have the "end" as parent 46 | // anchor. It is given a horizontal offset to the right, which results in a 15 pixel long arrow. 47 | mArrow = new QCPItemLine(mAxis->parentPlot()); 48 | mArrow->setLayer("overlay"); 49 | mArrow->setClipToAxisRect(false); 50 | mArrow->setHead(QCPLineEnding::esSpikeArrow); 51 | mArrow->end->setParentAnchor(mDummyTracer->position); 52 | mArrow->start->setParentAnchor(mArrow->end); 53 | mArrow->start->setCoords(15, 0); 54 | 55 | // The text label is anchored at the arrow start (tail) and has its "position" aligned at the 56 | // left, and vertically centered to the text label box. 57 | mLabel = new QCPItemText(mAxis->parentPlot()); 58 | mLabel->setLayer("overlay"); 59 | mLabel->setClipToAxisRect(false); 60 | mLabel->setPadding(QMargins(3, 0, 3, 0)); 61 | mLabel->setBrush(QBrush(Qt::white)); 62 | mLabel->setPen(QPen(Qt::blue)); 63 | mLabel->setPositionAlignment(Qt::AlignLeft|Qt::AlignVCenter); 64 | mLabel->position->setParentAnchor(mArrow->start); 65 | } 66 | 67 | AxisTag::~AxisTag() 68 | { 69 | if (mDummyTracer) 70 | mDummyTracer->parentPlot()->removeItem(mDummyTracer); 71 | if (mArrow) 72 | mArrow->parentPlot()->removeItem(mArrow); 73 | if (mLabel) 74 | mLabel->parentPlot()->removeItem(mLabel); 75 | } 76 | 77 | void AxisTag::setPen(const QPen &pen) 78 | { 79 | mArrow->setPen(pen); 80 | mLabel->setPen(pen); 81 | } 82 | 83 | void AxisTag::setBrush(const QBrush &brush) 84 | { 85 | mLabel->setBrush(brush); 86 | } 87 | 88 | void AxisTag::setText(const QString &text) 89 | { 90 | mLabel->setText(text); 91 | } 92 | 93 | void AxisTag::updatePosition(double value) 94 | { 95 | // since both the arrow and the text label are chained to the dummy tracer (via anchor 96 | // parent-child relationships) it is sufficient to update the dummy tracer coordinates. The 97 | // Horizontal coordinate type was set to ptAxisRectRatio so to keep it aligned at the right side 98 | // of the axis rect, it is always kept at 1. The vertical coordinate type was set to 99 | // ptPlotCoordinates of the passed parent axis, so the vertical coordinate is set to the new 100 | // value. 101 | mDummyTracer->position->setCoords(1, value); 102 | 103 | // We want the arrow head to be at the same horizontal position as the axis backbone, even if 104 | // the axis has a certain offset from the axis rect border (like the added second y axis). Thus we 105 | // set the horizontal pixel position of the arrow end (head) to the axis offset (the pixel 106 | // distance to the axis rect border). This works because the parent anchor of the arrow end is 107 | // the dummy tracer, which, as described earlier, is tied to the right axis rect border. 108 | mArrow->end->setCoords(mAxis->offset(), 0); 109 | } 110 | -------------------------------------------------------------------------------- /axistag.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | ** ** 3 | ** QCustomPlot, an easy to use, modern plotting widget for Qt ** 4 | ** Copyright (C) 2011-2018 Emanuel Eichhammer ** 5 | ** ** 6 | ** This program is free software: you can redistribute it and/or modify ** 7 | ** it under the terms of the GNU General Public License as published by ** 8 | ** the Free Software Foundation, either version 3 of the License, or ** 9 | ** (at your option) any later version. ** 10 | ** ** 11 | ** This program is distributed in the hope that it will be useful, ** 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** 14 | ** GNU General Public License for more details. ** 15 | ** ** 16 | ** You should have received a copy of the GNU General Public License ** 17 | ** along with this program. If not, see http://www.gnu.org/licenses/. ** 18 | ** ** 19 | **************************************************************************** 20 | ** Author: Emanuel Eichhammer ** 21 | ** Website/Contact: http://www.qcustomplot.com/ ** 22 | ** Date: 25.06.18 ** 23 | ** Version: 2.0.1 ** 24 | ****************************************************************************/ 25 | 26 | #ifndef AXISTAG_H 27 | #define AXISTAG_H 28 | 29 | #include 30 | #include "qcustomplot.h" 31 | 32 | class AxisTag : public QObject 33 | { 34 | Q_OBJECT 35 | public: 36 | explicit AxisTag(QCPAxis *parentAxis); 37 | virtual ~AxisTag(); 38 | 39 | // setters: 40 | void setPen(const QPen &pen); 41 | void setBrush(const QBrush &brush); 42 | void setText(const QString &text); 43 | 44 | // getters: 45 | QPen pen() const { return mLabel->pen(); } 46 | QBrush brush() const { return mLabel->brush(); } 47 | QString text() const { return mLabel->text(); } 48 | 49 | // other methods: 50 | void updatePosition(double value); 51 | 52 | protected: 53 | QCPAxis *mAxis; 54 | QPointer mDummyTracer; 55 | QPointer mArrow; 56 | QPointer mLabel; 57 | }; 58 | 59 | 60 | #endif // AXISTAG_H 61 | -------------------------------------------------------------------------------- /balboa.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrnSlr/QCPExamplesCollection/e5c34a3ca27237b77088d7148b82e27e5844a5a2/balboa.jpg -------------------------------------------------------------------------------- /images.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | balboa.jpg 4 | solarpanels.jpg 5 | sun.png 6 | 7 | 8 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | ** ** 3 | ** QCustomPlot, an easy to use, modern plotting widget for Qt ** 4 | ** Copyright (C) 2011-2018 Emanuel Eichhammer ** 5 | ** ** 6 | ** This program is free software: you can redistribute it and/or modify ** 7 | ** it under the terms of the GNU General Public License as published by ** 8 | ** the Free Software Foundation, either version 3 of the License, or ** 9 | ** (at your option) any later version. ** 10 | ** ** 11 | ** This program is distributed in the hope that it will be useful, ** 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** 14 | ** GNU General Public License for more details. ** 15 | ** ** 16 | ** You should have received a copy of the GNU General Public License ** 17 | ** along with this program. If not, see http://www.gnu.org/licenses/. ** 18 | ** ** 19 | **************************************************************************** 20 | ** Author: Emanuel Eichhammer ** 21 | ** Website/Contact: http://www.qcustomplot.com/ ** 22 | ** Date: 25.06.18 ** 23 | ** Version: 2.0.1 ** 24 | ****************************************************************************/ 25 | 26 | #include 27 | #include "mainwindow.h" 28 | 29 | int main(int argc, char *argv[]) 30 | { 31 | #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) 32 | QApplication::setGraphicsSystem("raster"); 33 | #endif 34 | QApplication a(argc, argv); 35 | MainWindow w; 36 | w.show(); 37 | 38 | return a.exec(); 39 | } 40 | -------------------------------------------------------------------------------- /mainwindow.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | ** ** 3 | ** QCustomPlot, an easy to use, modern plotting widget for Qt ** 4 | ** Copyright (C) 2011-2018 Emanuel Eichhammer ** 5 | ** ** 6 | ** This program is free software: you can redistribute it and/or modify ** 7 | ** it under the terms of the GNU General Public License as published by ** 8 | ** the Free Software Foundation, either version 3 of the License, or ** 9 | ** (at your option) any later version. ** 10 | ** ** 11 | ** This program is distributed in the hope that it will be useful, ** 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** 14 | ** GNU General Public License for more details. ** 15 | ** ** 16 | ** You should have received a copy of the GNU General Public License ** 17 | ** along with this program. If not, see http://www.gnu.org/licenses/. ** 18 | ** ** 19 | **************************************************************************** 20 | ** Author: Emanuel Eichhammer ** 21 | ** Website/Contact: http://www.qcustomplot.com/ ** 22 | ** Date: 25.06.18 ** 23 | ** Version: 2.0.1 ** 24 | ****************************************************************************/ 25 | 26 | /************************************************************************************************************ 27 | ** ** 28 | ** This is the example code for QCustomPlot. ** 29 | ** ** 30 | ** It demonstrates basic and some advanced capabilities of the widget. The interesting code is inside ** 31 | ** the "setup(...)Demo" functions of MainWindow. ** 32 | ** ** 33 | ** In order to see a demo in action, call the respective "setup(...)Demo" function inside the ** 34 | ** MainWindow constructor. Alternatively you may call setupDemo(i) where i is the index of the demo ** 35 | ** you want (for those, see MainWindow constructor comments). All other functions here are merely a ** 36 | ** way to easily create screenshots of all demos for the website. I.e. a timer is set to successively ** 37 | ** setup all the demos and make a screenshot of the window area and save it in the ./screenshots ** 38 | ** directory. ** 39 | ** ** 40 | *************************************************************************************************************/ 41 | 42 | #include "mainwindow.h" 43 | #include "ui_mainwindow.h" 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | MainWindow::MainWindow(QWidget *parent) : 53 | QMainWindow(parent), 54 | ui(new Ui::MainWindow) 55 | { 56 | ui->setupUi(this); 57 | setGeometry(200, 200, 800, 600); 58 | 59 | _loGrid = new QGridLayout; 60 | 61 | ui->scrollArea->setWidgetResizable(true); 62 | ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); 63 | ui->scrollAreaWidgetContents->setLayout(_loGrid); 64 | 65 | setupDemo(false); 66 | } 67 | 68 | void MainWindow::setupDemo(bool openGl) 69 | { 70 | setupQuadraticDemo(0,0, openGl); 71 | setupSimpleDemo(0,1, openGl); 72 | setupSincScatterDemo(1,0, openGl); 73 | setupScatterStyleDemo(1,1, openGl); 74 | setupScatterPixmapDemo(2,0, openGl); 75 | setupLineStyleDemo(2,1, openGl); 76 | setupDateDemo(3,0, openGl); 77 | setupTextureBrushDemo(3,1, openGl); 78 | setupMultiAxisDemo(4,0, openGl); 79 | setupLogarithmicDemo(4,1, openGl); 80 | setupParametricCurveDemo(5,0, openGl); 81 | setupBarChartDemo(5,1, openGl); 82 | setupStatisticalDemo(6,0, openGl); 83 | setupSimpleItemDemo(6,1, openGl); 84 | setupStyledDemo(7,0, openGl); 85 | setupAdvancedAxesDemo(7,1, openGl); 86 | setupColorMapDemo(8,0, openGl); 87 | setupFinancialDemo(8,1, openGl); 88 | setupRealtimeDataDemo(9,0, openGl); 89 | setupRealtimeBrushDemo(9,1, openGl); 90 | setupRealtimeThresholdDemo(10,0, openGl); 91 | setupRealtimeEcgDemo(10,1, openGl); 92 | setupItemDemo(11,0, openGl); 93 | setupHistoryDemo(11,1, openGl); 94 | setupAxisTagDemo(12,0, openGl); 95 | setupBitFieldDemo(12,1, openGl); 96 | 97 | setWindowTitle("QCustomPlot Examples"); 98 | } 99 | 100 | void MainWindow::setupQuadraticDemo(int row, int col, bool openGl) 101 | { 102 | QWidget *widget = new QWidget(); 103 | widget->setWindowTitle("Quadratic Demo"); 104 | widget->setMinimumHeight(400); 105 | widget->setMaximumHeight(400); 106 | 107 | QCustomPlot *plot = new QCustomPlot(); 108 | plot->setOpenGl(openGl); 109 | QStatusBar *bar = new QStatusBar(); 110 | 111 | QVBoxLayout *layout = new QVBoxLayout(); 112 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 113 | layout->addWidget(plot, 1); 114 | layout->addWidget(bar, 0); 115 | widget->setLayout(layout); 116 | 117 | _loGrid->addWidget(widget,row,col,1,1); 118 | // generate some data: 119 | QVector x(101), y(101); // initialize with entries 0..100 120 | for (int i=0; i<101; ++i) 121 | { 122 | x[i] = i/50.0 - 1; // x goes from -1 to 1 123 | y[i] = x[i]*x[i]; // let's plot a quadratic function 124 | } 125 | // create graph and assign data to it: 126 | plot->addGraph(); 127 | plot->graph(0)->setData(x, y); 128 | // give the axes some labels: 129 | plot->xAxis->setLabel("x"); 130 | plot->yAxis->setLabel("y"); 131 | // set axes ranges, so we see all data: 132 | plot->xAxis->setRange(-1, 1); 133 | plot->yAxis->setRange(0, 1); 134 | 135 | plot->replot(); 136 | } 137 | 138 | void MainWindow::setupSimpleDemo(int row, int col, bool openGl) 139 | { 140 | QWidget *widget = new QWidget(); 141 | widget->setWindowTitle("Simple Demo"); 142 | widget->setMinimumHeight(400); 143 | widget->setMaximumHeight(400); 144 | 145 | QCustomPlot *plot = new QCustomPlot(); 146 | plot->setOpenGl(openGl); 147 | QStatusBar *bar = new QStatusBar(); 148 | 149 | QVBoxLayout *layout = new QVBoxLayout(); 150 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 151 | layout->addWidget(plot, 1); 152 | layout->addWidget(bar, 0); 153 | widget->setLayout(layout); 154 | 155 | _loGrid->addWidget(widget,row,col,1,1); 156 | 157 | // add two new graphs and set their look: 158 | plot->addGraph(); 159 | plot->graph(0)->setPen(QPen(Qt::blue)); // line color blue for first graph 160 | QLinearGradient gradient(1000, 0, 0, 0); 161 | gradient.setColorAt(0, QColor::fromRgbF(0, 1, 0, 1)); 162 | gradient.setColorAt(1, QColor::fromRgbF(0, 0, 0, 0)); 163 | 164 | QBrush brush(gradient); 165 | plot->graph(0)->setBrush(brush); // first graph will be filled with translucent blue 166 | plot->addGraph(); 167 | plot->graph(1)->setPen(QPen(Qt::red)); // line color red for second graph 168 | // generate some points of data (y0 for first, y1 for second graph): 169 | QVector x(251), y0(251), y1(251); 170 | for (int i=0; i<251; ++i) 171 | { 172 | x[i] = i; 173 | y0[i] = qExp(i/150.0)*qCos(i/10.0); // exponentially decaying cosine 174 | y1[i] = qExp(i/150.0); // exponential envelope 175 | } 176 | // configure right and top axis to show ticks but no labels: 177 | // (see QCPAxisRect::setupFullAxesBox for a quicker method to do this) 178 | plot->xAxis2->setVisible(true); 179 | plot->xAxis2->setTickLabels(false); 180 | plot->yAxis2->setVisible(true); 181 | plot->yAxis2->setTickLabels(false); 182 | // make left and bottom axes always transfer their ranges to right and top axes: 183 | connect(plot->xAxis, SIGNAL(rangeChanged(QCPRange)), plot->xAxis2, SLOT(setRange(QCPRange))); 184 | connect(plot->yAxis, SIGNAL(rangeChanged(QCPRange)), plot->yAxis2, SLOT(setRange(QCPRange))); 185 | // pass data points to graphs: 186 | plot->graph(0)->setData(x, y0); 187 | plot->graph(1)->setData(x, y1); 188 | // let the ranges scale themselves so graph 0 fits perfectly in the visible area: 189 | plot->graph(0)->rescaleAxes(); 190 | // same thing for graph 1, but only enlarge ranges (in case graph 1 is smaller than graph 0): 191 | plot->graph(1)->rescaleAxes(true); 192 | // Note: we could have also just called customPlot->rescaleAxes(); instead 193 | // Allow user to drag axis ranges with mouse, zoom with mouse wheel and select graphs by clicking: 194 | plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables); 195 | 196 | plot->replot(); 197 | } 198 | 199 | void MainWindow::setupSincScatterDemo(int row, int col, bool openGl) 200 | { 201 | QWidget *widget = new QWidget(); 202 | widget->setWindowTitle("Sinc Scatter Demo"); 203 | widget->setMinimumHeight(400); 204 | widget->setMaximumHeight(400); 205 | 206 | QCustomPlot *plot = new QCustomPlot(); 207 | plot->setOpenGl(openGl); 208 | QStatusBar *bar = new QStatusBar(); 209 | 210 | QVBoxLayout *layout = new QVBoxLayout(); 211 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 212 | layout->addWidget(plot, 1); 213 | layout->addWidget(bar, 0); 214 | widget->setLayout(layout); 215 | 216 | _loGrid->addWidget(widget,row,col,1,1); 217 | 218 | plot->legend->setVisible(true); 219 | plot->legend->setFont(QFont("Helvetica",9)); 220 | // set locale to english, so we get english decimal separator: 221 | plot->setLocale(QLocale(QLocale::English, QLocale::UnitedKingdom)); 222 | // add confidence band graphs: 223 | plot->addGraph(); 224 | QPen pen; 225 | pen.setStyle(Qt::DotLine); 226 | pen.setWidth(1); 227 | pen.setColor(QColor(180,180,180)); 228 | plot->graph(0)->setName("Confidence Band 68%"); 229 | plot->graph(0)->setPen(pen); 230 | plot->graph(0)->setBrush(QBrush(QColor(255,50,30,20))); 231 | plot->addGraph(); 232 | plot->legend->removeItem(plot->legend->itemCount()-1); // don't show two confidence band graphs in legend 233 | plot->graph(1)->setPen(pen); 234 | plot->graph(0)->setChannelFillGraph(plot->graph(1)); 235 | // add theory curve graph: 236 | plot->addGraph(); 237 | pen.setStyle(Qt::DashLine); 238 | pen.setWidth(2); 239 | pen.setColor(Qt::red); 240 | plot->graph(2)->setPen(pen); 241 | plot->graph(2)->setName("Theory Curve"); 242 | // add data point graph: 243 | plot->addGraph(); 244 | plot->graph(3)->setPen(QPen(Qt::blue)); 245 | plot->graph(3)->setLineStyle(QCPGraph::lsNone); 246 | plot->graph(3)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCross, 4)); 247 | // add error bars: 248 | QCPErrorBars *errorBars = new QCPErrorBars(plot->xAxis, plot->yAxis); 249 | errorBars->removeFromLegend(); 250 | errorBars->setAntialiased(false); 251 | errorBars->setDataPlottable(plot->graph(3)); 252 | errorBars->setPen(QPen(QColor(180,180,180))); 253 | plot->graph(3)->setName("Measurement"); 254 | 255 | // generate ideal sinc curve data and some randomly perturbed data for scatter plot: 256 | QVector x0(250), y0(250); 257 | QVector yConfUpper(250), yConfLower(250); 258 | for (int i=0; i<250; ++i) 259 | { 260 | 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 line 261 | y0[i] = qSin(x0[i])/x0[i]; // sinc function 262 | yConfUpper[i] = y0[i]+0.15; 263 | yConfLower[i] = y0[i]-0.15; 264 | x0[i] *= 1000; 265 | } 266 | QVector x1(50), y1(50), y1err(50); 267 | for (int i=0; i<50; ++i) 268 | { 269 | // generate a gaussian distributed random number: 270 | double tmp1 = rand()/(double)RAND_MAX; 271 | double tmp2 = rand()/(double)RAND_MAX; 272 | double r = qSqrt(-2*qLn(tmp1))*qCos(2*M_PI*tmp2); // box-muller transform for gaussian distribution 273 | // set y1 to value of y0 plus a random gaussian pertubation: 274 | x1[i] = (i/50.0-0.5)*30+0.25; 275 | y1[i] = qSin(x1[i])/x1[i]+r*0.15; 276 | x1[i] *= 1000; 277 | y1err[i] = 0.15; 278 | } 279 | // pass data to graphs and let QCustomPlot determine the axes ranges so the whole thing is visible: 280 | plot->graph(0)->setData(x0, yConfUpper); 281 | plot->graph(1)->setData(x0, yConfLower); 282 | plot->graph(2)->setData(x0, y0); 283 | plot->graph(3)->setData(x1, y1); 284 | errorBars->setData(y1err); 285 | plot->graph(2)->rescaleAxes(); 286 | plot->graph(3)->rescaleAxes(true); 287 | // setup look of bottom tick labels: 288 | plot->xAxis->setTickLabelRotation(30); 289 | plot->xAxis->ticker()->setTickCount(9); 290 | plot->xAxis->setNumberFormat("ebc"); 291 | plot->xAxis->setNumberPrecision(1); 292 | plot->xAxis->moveRange(-10); 293 | // make top right axes clones of bottom left axes. Looks prettier: 294 | plot->axisRect()->setupFullAxesBox(); 295 | 296 | plot->replot(); 297 | } 298 | 299 | void MainWindow::setupScatterStyleDemo(int row, int col, bool openGl) 300 | { 301 | QWidget *widget = new QWidget(); 302 | widget->setWindowTitle("Scatter Style Demo"); 303 | widget->setMinimumHeight(400); 304 | widget->setMaximumHeight(400); 305 | 306 | QCustomPlot *plot = new QCustomPlot(); 307 | plot->setOpenGl(openGl); 308 | QStatusBar *bar = new QStatusBar(); 309 | 310 | QVBoxLayout *layout = new QVBoxLayout(); 311 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 312 | layout->addWidget(plot, 1); 313 | layout->addWidget(bar, 0); 314 | widget->setLayout(layout); 315 | 316 | _loGrid->addWidget(widget,row,col,1,1); 317 | 318 | plot->legend->setVisible(true); 319 | plot->legend->setFont(QFont("Helvetica", 9)); 320 | plot->legend->setRowSpacing(-3); 321 | QVector shapes; 322 | shapes << QCPScatterStyle::ssCross; 323 | shapes << QCPScatterStyle::ssPlus; 324 | shapes << QCPScatterStyle::ssCircle; 325 | shapes << QCPScatterStyle::ssDisc; 326 | shapes << QCPScatterStyle::ssSquare; 327 | shapes << QCPScatterStyle::ssDiamond; 328 | shapes << QCPScatterStyle::ssStar; 329 | shapes << QCPScatterStyle::ssTriangle; 330 | shapes << QCPScatterStyle::ssTriangleInverted; 331 | shapes << QCPScatterStyle::ssCrossSquare; 332 | shapes << QCPScatterStyle::ssPlusSquare; 333 | shapes << QCPScatterStyle::ssCrossCircle; 334 | shapes << QCPScatterStyle::ssPlusCircle; 335 | shapes << QCPScatterStyle::ssPeace; 336 | shapes << QCPScatterStyle::ssCustom; 337 | 338 | QPen pen; 339 | // add graphs with different scatter styles: 340 | for (int i=0; iaddGraph(); 343 | 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)); 344 | // generate data: 345 | QVector x(10), y(10); 346 | for (int k=0; k<10; ++k) 347 | { 348 | x[k] = k/10.0 * 4*3.14 + 0.01; 349 | y[k] = 7*qSin(x[k])/x[k] + (shapes.size()-i)*5; 350 | } 351 | plot->graph()->setData(x, y); 352 | plot->graph()->rescaleAxes(true); 353 | plot->graph()->setPen(pen); 354 | plot->graph()->setName(QCPScatterStyle::staticMetaObject.enumerator(QCPScatterStyle::staticMetaObject.indexOfEnumerator("ScatterShape")).valueToKey(shapes.at(i))); 355 | plot->graph()->setLineStyle(QCPGraph::lsLine); 356 | // set scatter style: 357 | if (shapes.at(i) != QCPScatterStyle::ssCustom) 358 | { 359 | plot->graph()->setScatterStyle(QCPScatterStyle(shapes.at(i), 10)); 360 | } 361 | else 362 | { 363 | QPainterPath customScatterPath; 364 | for (int i=0; i<3; ++i) 365 | 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); 366 | plot->graph()->setScatterStyle(QCPScatterStyle(customScatterPath, QPen(Qt::black, 0), QColor(40, 70, 255, 50), 10)); 367 | } 368 | } 369 | // set blank axis lines: 370 | plot->rescaleAxes(); 371 | plot->xAxis->setTicks(false); 372 | plot->yAxis->setTicks(false); 373 | plot->xAxis->setTickLabels(false); 374 | plot->yAxis->setTickLabels(false); 375 | // make top right axes clones of bottom left axes: 376 | plot->axisRect()->setupFullAxesBox(); 377 | 378 | plot->replot(); 379 | } 380 | 381 | void MainWindow::setupLineStyleDemo(int row, int col, bool openGl) 382 | { 383 | QWidget *widget = new QWidget(); 384 | widget->setWindowTitle("Line Style Demo"); 385 | widget->setMinimumHeight(400); 386 | widget->setMaximumHeight(400); 387 | 388 | QCustomPlot *plot = new QCustomPlot(); 389 | plot->setOpenGl(openGl); 390 | QStatusBar *bar = new QStatusBar(); 391 | 392 | QVBoxLayout *layout = new QVBoxLayout(); 393 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 394 | layout->addWidget(plot, 1); 395 | layout->addWidget(bar, 0); 396 | widget->setLayout(layout); 397 | 398 | _loGrid->addWidget(widget,row,col,1,1); 399 | 400 | plot->legend->setVisible(true); 401 | plot->legend->setFont(QFont("Helvetica", 9)); 402 | QPen pen; 403 | QStringList lineNames; 404 | lineNames << "lsNone" << "lsLine" << "lsStepLeft" << "lsStepRight" << "lsStepCenter" << "lsImpulse"; 405 | // add graphs with different line styles: 406 | for (int i=QCPGraph::lsNone; i<=QCPGraph::lsImpulse; ++i) 407 | { 408 | plot->addGraph(); 409 | 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)); 410 | plot->graph()->setPen(pen); 411 | plot->graph()->setName(lineNames.at(i-QCPGraph::lsNone)); 412 | plot->graph()->setLineStyle((QCPGraph::LineStyle)i); 413 | plot->graph()->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, 5)); 414 | // generate data: 415 | QVector x(15), y(15); 416 | for (int j=0; j<15; ++j) 417 | { 418 | x[j] = j/15.0 * 5*3.14 + 0.01; 419 | y[j] = 7*qSin(x[j])/x[j] - (i-QCPGraph::lsNone)*5 + (QCPGraph::lsImpulse)*5 + 2; 420 | } 421 | plot->graph()->setData(x, y); 422 | plot->graph()->rescaleAxes(true); 423 | } 424 | // zoom out a bit: 425 | plot->yAxis->scaleRange(1.1, plot->yAxis->range().center()); 426 | plot->xAxis->scaleRange(1.1, plot->xAxis->range().center()); 427 | // set blank axis lines: 428 | plot->xAxis->setTicks(false); 429 | plot->yAxis->setTicks(true); 430 | plot->xAxis->setTickLabels(false); 431 | plot->yAxis->setTickLabels(true); 432 | // make top right axes clones of bottom left axes: 433 | plot->axisRect()->setupFullAxesBox(); 434 | 435 | plot->replot(); 436 | } 437 | 438 | void MainWindow::setupScatterPixmapDemo(int row, int col, bool openGl) 439 | { 440 | QWidget *widget = new QWidget(); 441 | widget->setWindowTitle("Scatter Pixmap Demo"); 442 | widget->setMinimumHeight(400); 443 | widget->setMaximumHeight(400); 444 | 445 | QCustomPlot *plot = new QCustomPlot(); 446 | plot->setOpenGl(openGl); 447 | QStatusBar *bar = new QStatusBar(); 448 | 449 | QVBoxLayout *layout = new QVBoxLayout(); 450 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 451 | layout->addWidget(plot, 1); 452 | layout->addWidget(bar, 0); 453 | widget->setLayout(layout); 454 | 455 | _loGrid->addWidget(widget,row,col,1,1); 456 | 457 | plot->axisRect()->setBackground(QPixmap(":/solarpanels.jpg")); 458 | plot->addGraph(); 459 | plot->graph()->setLineStyle(QCPGraph::lsLine); 460 | QPen pen; 461 | pen.setColor(QColor(255, 200, 20, 200)); 462 | pen.setStyle(Qt::DashLine); 463 | pen.setWidthF(2.5); 464 | plot->graph()->setPen(pen); 465 | plot->graph()->setBrush(QBrush(QColor(255,200,20,70))); 466 | plot->graph()->setScatterStyle(QCPScatterStyle(QPixmap(":/sun.png"))); 467 | // set graph name, will show up in legend next to icon: 468 | plot->graph()->setName("Data from Photovoltaic\nenergy barometer 2011"); 469 | // set data: 470 | QVector year, value; 471 | year << 2005 << 2006 << 2007 << 2008 << 2009 << 2010 << 2011; 472 | value << 2.17 << 3.42 << 4.94 << 10.38 << 15.86 << 29.33 << 52.1; 473 | plot->graph()->setData(year, value); 474 | 475 | // set title of plot: 476 | plot->plotLayout()->insertRow(0); 477 | plot->plotLayout()->addElement(0, 0, new QCPTextElement(plot, "Regenerative Energies", QFont("sans", 12, QFont::Bold))); 478 | // axis configurations: 479 | plot->xAxis->setLabel("Year"); 480 | plot->yAxis->setLabel("Installed Gigawatts of\nphotovoltaic in the European Union"); 481 | plot->xAxis2->setVisible(true); 482 | plot->yAxis2->setVisible(true); 483 | plot->xAxis2->setTickLabels(false); 484 | plot->yAxis2->setTickLabels(false); 485 | plot->xAxis2->setTicks(false); 486 | plot->yAxis2->setTicks(false); 487 | plot->xAxis2->setSubTicks(false); 488 | plot->yAxis2->setSubTicks(false); 489 | plot->xAxis->setRange(2004.5, 2011.5); 490 | plot->yAxis->setRange(0, 52); 491 | // setup legend: 492 | plot->legend->setFont(QFont(font().family(), 7)); 493 | plot->legend->setIconSize(50, 20); 494 | plot->legend->setVisible(true); 495 | plot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignLeft | Qt::AlignTop); 496 | plot->replot(); 497 | } 498 | 499 | void MainWindow::setupDateDemo(int row, int col, bool openGl) 500 | { 501 | QWidget *widget = new QWidget(); 502 | widget->setWindowTitle("Date Demo"); 503 | widget->setMinimumHeight(400); 504 | widget->setMaximumHeight(400); 505 | 506 | QCustomPlot *plot = new QCustomPlot(); 507 | plot->setOpenGl(openGl); 508 | QStatusBar *bar = new QStatusBar(); 509 | 510 | QVBoxLayout *layout = new QVBoxLayout(); 511 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 512 | layout->addWidget(plot, 1); 513 | layout->addWidget(bar, 0); 514 | widget->setLayout(layout); 515 | 516 | _loGrid->addWidget(widget,row,col,1,1); 517 | 518 | // set locale to english, so we get english month names: 519 | plot->setLocale(QLocale(QLocale::English, QLocale::UnitedKingdom)); 520 | // seconds of current time, we'll use it as starting point in time for data: 521 | double now = QDateTime::currentDateTime().toTime_t(); 522 | srand(8); // set the random seed, so we always get the same random data 523 | // create multiple graphs: 524 | for (int gi=0; gi<5; ++gi) 525 | { 526 | plot->addGraph(); 527 | QColor color(20+200/4.0*gi,70*(1.6-gi/4.0), 150, 150); 528 | plot->graph()->setLineStyle(QCPGraph::lsLine); 529 | plot->graph()->setPen(QPen(color.lighter(200))); 530 | plot->graph()->setBrush(QBrush(color)); 531 | // generate random walk data: 532 | QVector timeData(250); 533 | for (int i=0; i<250; ++i) 534 | { 535 | timeData[i].key = now + 24*3600*i; 536 | if (i == 0) 537 | timeData[i].value = (i/50.0+1)*(rand()/(double)RAND_MAX-0.5); 538 | else 539 | timeData[i].value = qFabs(timeData[i-1].value)*(1+0.02/4.0*(4-gi)) + (i/50.0+1)*(rand()/(double)RAND_MAX-0.5); 540 | } 541 | plot->graph()->data()->set(timeData); 542 | } 543 | // configure bottom axis to show date instead of number: 544 | QSharedPointer dateTicker(new QCPAxisTickerDateTime); 545 | dateTicker->setDateTimeFormat("d. MMMM\nyyyy"); 546 | plot->xAxis->setTicker(dateTicker); 547 | // configure left axis text labels: 548 | QSharedPointer textTicker(new QCPAxisTickerText); 549 | textTicker->addTick(10, "a bit\nlow"); 550 | textTicker->addTick(50, "quite\nhigh"); 551 | plot->yAxis->setTicker(textTicker); 552 | // set a more compact font size for bottom and left axis tick labels: 553 | plot->xAxis->setTickLabelFont(QFont(QFont().family(), 8)); 554 | plot->yAxis->setTickLabelFont(QFont(QFont().family(), 8)); 555 | // set axis labels: 556 | plot->xAxis->setLabel("Date"); 557 | plot->yAxis->setLabel("Random wobbly lines value"); 558 | // make top and right axes visible but without ticks and labels: 559 | plot->xAxis2->setVisible(true); 560 | plot->yAxis2->setVisible(true); 561 | plot->xAxis2->setTicks(false); 562 | plot->yAxis2->setTicks(false); 563 | plot->xAxis2->setTickLabels(false); 564 | plot->yAxis2->setTickLabels(false); 565 | // set axis ranges to show all data: 566 | plot->xAxis->setRange(now, now+24*3600*249); 567 | plot->yAxis->setRange(0, 60); 568 | // show legend with slightly transparent background brush: 569 | plot->legend->setVisible(true); 570 | plot->legend->setBrush(QColor(255, 255, 255, 150)); 571 | 572 | plot->replot(); 573 | } 574 | 575 | void MainWindow::setupTextureBrushDemo(int row, int col, bool openGl) 576 | { 577 | QWidget *widget = new QWidget(); 578 | widget->setWindowTitle("Texture Brush Demo"); 579 | widget->setMinimumHeight(400); 580 | widget->setMaximumHeight(400); 581 | 582 | QCustomPlot *plot = new QCustomPlot(); 583 | plot->setOpenGl(openGl); 584 | QStatusBar *bar = new QStatusBar(); 585 | 586 | QVBoxLayout *layout = new QVBoxLayout(); 587 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 588 | layout->addWidget(plot, 1); 589 | layout->addWidget(bar, 0); 590 | widget->setLayout(layout); 591 | 592 | _loGrid->addWidget(widget,row,col,1,1); 593 | 594 | // add two graphs with a textured fill: 595 | plot->addGraph(); 596 | QPen redDotPen; 597 | redDotPen.setStyle(Qt::DotLine); 598 | redDotPen.setColor(QColor(170, 100, 100, 180)); 599 | redDotPen.setWidthF(2); 600 | plot->graph(0)->setPen(redDotPen); 601 | plot->graph(0)->setBrush(QBrush(QPixmap(":/balboa.jpg"))); // fill with texture of specified image 602 | 603 | plot->addGraph(); 604 | plot->graph(1)->setPen(QPen(Qt::red)); 605 | 606 | // activate channel fill for graph 0 towards graph 1: 607 | plot->graph(0)->setChannelFillGraph(plot->graph(1)); 608 | 609 | // generate data: 610 | QVector x(250); 611 | QVector y0(250), y1(250); 612 | for (int i=0; i<250; ++i) 613 | { 614 | // just playing with numbers, not much to learn here 615 | x[i] = 3*i/250.0; 616 | y0[i] = 1+qExp(-x[i]*x[i]*0.8)*(x[i]*x[i]+x[i]); 617 | y1[i] = 1-qExp(-x[i]*x[i]*0.4)*(x[i]*x[i])*0.1; 618 | } 619 | 620 | // pass data points to graphs: 621 | plot->graph(0)->setData(x, y0); 622 | plot->graph(1)->setData(x, y1); 623 | // activate top and right axes, which are invisible by default: 624 | plot->xAxis2->setVisible(true); 625 | plot->yAxis2->setVisible(true); 626 | // make tick labels invisible on top and right axis: 627 | plot->xAxis2->setTickLabels(false); 628 | plot->yAxis2->setTickLabels(false); 629 | // set ranges: 630 | plot->xAxis->setRange(0, 2.5); 631 | plot->yAxis->setRange(0.9, 1.6); 632 | // assign top/right axes same properties as bottom/left: 633 | plot->axisRect()->setupFullAxesBox(); 634 | } 635 | 636 | void MainWindow::setupMultiAxisDemo(int row, int col, bool openGl) 637 | { 638 | QWidget *widget = new QWidget(); 639 | widget->setWindowTitle("Multi Axis Demo"); 640 | widget->setMinimumHeight(400); 641 | widget->setMaximumHeight(400); 642 | 643 | QCustomPlot *plot = new QCustomPlot(); 644 | plot->setOpenGl(openGl); 645 | QStatusBar *bar = new QStatusBar(); 646 | 647 | QVBoxLayout *layout = new QVBoxLayout(); 648 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 649 | layout->addWidget(plot, 1); 650 | layout->addWidget(bar, 0); 651 | widget->setLayout(layout); 652 | 653 | _loGrid->addWidget(widget,row,col,1,1); 654 | plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); 655 | 656 | plot->setLocale(QLocale(QLocale::English, QLocale::UnitedKingdom)); // period as decimal separator and comma as thousand separator 657 | plot->legend->setVisible(true); 658 | QFont legendFont = font(); // start out with MainWindow's font.. 659 | legendFont.setPointSize(9); // and make a bit smaller for legend 660 | plot->legend->setFont(legendFont); 661 | plot->legend->setBrush(QBrush(QColor(255,255,255,230))); 662 | // 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: 663 | plot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignBottom|Qt::AlignRight); 664 | 665 | // setup for graph 0: key axis left, value axis bottom 666 | // will contain left maxwell-like function 667 | plot->addGraph(plot->yAxis, plot->xAxis); 668 | plot->graph(0)->setPen(QPen(QColor(255, 100, 0))); 669 | plot->graph(0)->setBrush(QBrush(QPixmap(":/balboa.jpg"))); // fill with texture of specified image 670 | plot->graph(0)->setLineStyle(QCPGraph::lsLine); 671 | plot->graph(0)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDisc, 5)); 672 | plot->graph(0)->setName("Left maxwell function"); 673 | 674 | // setup for graph 1: key axis bottom, value axis left (those are the default axes) 675 | // will contain bottom maxwell-like function with error bars 676 | plot->addGraph(); 677 | plot->graph(1)->setPen(QPen(Qt::red)); 678 | plot->graph(1)->setBrush(QBrush(QPixmap("./balboa.jpg"))); // same fill as we used for graph 0 679 | plot->graph(1)->setLineStyle(QCPGraph::lsStepCenter); 680 | plot->graph(1)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, Qt::red, Qt::white, 7)); 681 | plot->graph(1)->setName("Bottom maxwell function"); 682 | QCPErrorBars *errorBars = new QCPErrorBars(plot->xAxis, plot->yAxis); 683 | errorBars->removeFromLegend(); 684 | errorBars->setDataPlottable(plot->graph(1)); 685 | 686 | // setup for graph 2: key axis top, value axis right 687 | // will contain high frequency sine with low frequency beating: 688 | plot->addGraph(plot->xAxis2, plot->yAxis2); 689 | plot->graph(2)->setPen(QPen(Qt::blue)); 690 | plot->graph(2)->setName("High frequency sine"); 691 | 692 | // setup for graph 3: same axes as graph 2 693 | // will contain low frequency beating envelope of graph 2 694 | plot->addGraph(plot->xAxis2, plot->yAxis2); 695 | QPen blueDotPen; 696 | blueDotPen.setColor(QColor(30, 40, 255, 150)); 697 | blueDotPen.setStyle(Qt::DotLine); 698 | blueDotPen.setWidthF(4); 699 | plot->graph(3)->setPen(blueDotPen); 700 | plot->graph(3)->setName("Sine envelope"); 701 | 702 | // setup for graph 4: key axis right, value axis top 703 | // will contain parabolically distributed data points with some random perturbance 704 | plot->addGraph(plot->yAxis2, plot->xAxis2); 705 | plot->graph(4)->setPen(QColor(50, 50, 50, 255)); 706 | plot->graph(4)->setLineStyle(QCPGraph::lsNone); 707 | plot->graph(4)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, 4)); 708 | plot->graph(4)->setName("Some random data around\na quadratic function"); 709 | 710 | // generate data, just playing with numbers, not much to learn here: 711 | QVector x0(25), y0(25); 712 | QVector x1(15), y1(15), y1err(15); 713 | QVector x2(250), y2(250); 714 | QVector x3(250), y3(250); 715 | QVector x4(250), y4(250); 716 | for (int i=0; i<25; ++i) // data for graph 0 717 | { 718 | x0[i] = 3*i/25.0; 719 | y0[i] = qExp(-x0[i]*x0[i]*0.8)*(x0[i]*x0[i]+x0[i]); 720 | } 721 | for (int i=0; i<15; ++i) // data for graph 1 722 | { 723 | x1[i] = 3*i/15.0;; 724 | y1[i] = qExp(-x1[i]*x1[i])*(x1[i]*x1[i])*2.6; 725 | y1err[i] = y1[i]*0.25; 726 | } 727 | for (int i=0; i<250; ++i) // data for graphs 2, 3 and 4 728 | { 729 | x2[i] = i/250.0*3*M_PI; 730 | x3[i] = x2[i]; 731 | x4[i] = i/250.0*100-50; 732 | y2[i] = qSin(x2[i]*12)*qCos(x2[i])*10; 733 | y3[i] = qCos(x3[i])*10; 734 | y4[i] = 0.01*x4[i]*x4[i] + 1.5*(rand()/(double)RAND_MAX-0.5) + 1.5*M_PI; 735 | } 736 | 737 | // pass data points to graphs: 738 | plot->graph(0)->setData(x0, y0); 739 | plot->graph(1)->setData(x1, y1); 740 | errorBars->setData(y1err); 741 | plot->graph(2)->setData(x2, y2); 742 | plot->graph(3)->setData(x3, y3); 743 | plot->graph(4)->setData(x4, y4); 744 | // activate top and right axes, which are invisible by default: 745 | plot->xAxis2->setVisible(true); 746 | plot->yAxis2->setVisible(true); 747 | // set ranges appropriate to show data: 748 | plot->xAxis->setRange(0, 2.7); 749 | plot->yAxis->setRange(0, 2.6); 750 | plot->xAxis2->setRange(0, 3.0*M_PI); 751 | plot->yAxis2->setRange(-70, 35); 752 | // set pi ticks on top axis: 753 | plot->xAxis2->setTicker(QSharedPointer(new QCPAxisTickerPi)); 754 | // add title layout element: 755 | // plot->plotLayout()->insertRow(0); 756 | // plot->plotLayout()->addElement(0, 0, new QCPTextElement(plot, "Way too many graphs in one plot", QFont("sans", 12, QFont::Bold))); 757 | 758 | // set labels: 759 | plot->xAxis->setLabel("Bottom axis with outward ticks"); 760 | plot->yAxis->setLabel("Left axis label"); 761 | plot->xAxis2->setLabel("Top axis label"); 762 | plot->yAxis2->setLabel("Right axis label"); 763 | // make ticks on bottom axis go outward: 764 | plot->xAxis->setTickLength(0, 5); 765 | plot->xAxis->setSubTickLength(0, 3); 766 | // make ticks on right axis go inward and outward: 767 | plot->yAxis2->setTickLength(3, 3); 768 | plot->yAxis2->setSubTickLength(1, 1); 769 | // plot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignLeft | Qt::AlignTop); 770 | 771 | plot->replot(); 772 | } 773 | 774 | void MainWindow::setupLogarithmicDemo(int row, int col, bool openGl) 775 | { 776 | QWidget *widget = new QWidget(); 777 | widget->setWindowTitle("Logarithmic Demo"); 778 | widget->setMinimumHeight(400); 779 | widget->setMaximumHeight(400); 780 | 781 | QCustomPlot *plot = new QCustomPlot(); 782 | plot->setOpenGl(openGl); 783 | QStatusBar *bar = new QStatusBar(); 784 | 785 | QVBoxLayout *layout = new QVBoxLayout(); 786 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 787 | layout->addWidget(plot, 1); 788 | layout->addWidget(bar, 0); 789 | widget->setLayout(layout); 790 | 791 | _loGrid->addWidget(widget,row,col,1,1); 792 | 793 | plot->setNoAntialiasingOnDrag(true); // more performance/responsiveness during dragging 794 | plot->addGraph(); 795 | QPen pen; 796 | pen.setColor(QColor(255,170,100)); 797 | pen.setWidth(2); 798 | pen.setStyle(Qt::DotLine); 799 | plot->graph(0)->setPen(pen); 800 | plot->graph(0)->setName("x"); 801 | 802 | plot->addGraph(); 803 | plot->graph(1)->setPen(QPen(Qt::red)); 804 | plot->graph(1)->setBrush(QBrush(QColor(255, 0, 0, 20))); 805 | plot->graph(1)->setName("-sin(x)exp(x)"); 806 | 807 | plot->addGraph(); 808 | plot->graph(2)->setPen(QPen(Qt::blue)); 809 | plot->graph(2)->setBrush(QBrush(QColor(0, 0, 255, 20))); 810 | plot->graph(2)->setName(" sin(x)exp(x)"); 811 | 812 | plot->addGraph(); 813 | pen.setColor(QColor(0,0,0)); 814 | pen.setWidth(1); 815 | pen.setStyle(Qt::DashLine); 816 | plot->graph(3)->setPen(pen); 817 | plot->graph(3)->setBrush(QBrush(QColor(0,0,0,15))); 818 | plot->graph(3)->setLineStyle(QCPGraph::lsStepCenter); 819 | plot->graph(3)->setName("x!"); 820 | 821 | const int dataCount = 200; 822 | const int dataFactorialCount = 21; 823 | QVector dataLinear(dataCount), dataMinusSinExp(dataCount), dataPlusSinExp(dataCount), dataFactorial(dataFactorialCount); 824 | for (int i=0; igraph(0)->data()->set(dataLinear); 840 | plot->graph(1)->data()->set(dataMinusSinExp); 841 | plot->graph(2)->data()->set(dataPlusSinExp); 842 | plot->graph(3)->data()->set(dataFactorial); 843 | 844 | plot->yAxis->grid()->setSubGridVisible(true); 845 | plot->xAxis->grid()->setSubGridVisible(true); 846 | plot->yAxis->setScaleType(QCPAxis::stLogarithmic); 847 | plot->yAxis2->setScaleType(QCPAxis::stLogarithmic); 848 | QSharedPointer logTicker(new QCPAxisTickerLog); 849 | plot->yAxis->setTicker(logTicker); 850 | plot->yAxis2->setTicker(logTicker); 851 | plot->yAxis->setNumberFormat("eb"); // e = exponential, b = beautiful decimal powers 852 | plot->yAxis->setNumberPrecision(0); // makes sure "1*10^4" is displayed only as "10^4" 853 | plot->xAxis->setRange(0, 19.9); 854 | plot->yAxis->setRange(1e-2, 1e10); 855 | // make range draggable and zoomable: 856 | plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); 857 | 858 | // make top right axes clones of bottom left axes: 859 | plot->axisRect()->setupFullAxesBox(); 860 | // connect signals so top and right axes move in sync with bottom and left axes: 861 | connect(plot->xAxis, SIGNAL(rangeChanged(QCPRange)), plot->xAxis2, SLOT(setRange(QCPRange))); 862 | connect(plot->yAxis, SIGNAL(rangeChanged(QCPRange)), plot->yAxis2, SLOT(setRange(QCPRange))); 863 | 864 | plot->legend->setVisible(true); 865 | plot->legend->setBrush(QBrush(QColor(255,255,255,150))); 866 | // make legend align in top left corner or axis rect 867 | plot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignLeft|Qt::AlignTop); 868 | 869 | plot->replot(); 870 | } 871 | 872 | void MainWindow::setupRealtimeDataDemo(int row, int col, bool openGl) 873 | { 874 | QTimer *timer = new QTimer(); 875 | QWidget *widget = new QWidget(); 876 | widget->setWindowTitle("Real Time Data Demo"); 877 | widget->setMinimumHeight(400); 878 | widget->setMaximumHeight(400); 879 | 880 | QCustomPlot *plot = new QCustomPlot(); 881 | plot->setOpenGl(openGl); 882 | QStatusBar *bar = new QStatusBar(); 883 | 884 | QVBoxLayout *layout = new QVBoxLayout(); 885 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 886 | layout->addWidget(plot, 1); 887 | layout->addWidget(bar, 0); 888 | widget->setLayout(layout); 889 | 890 | _loGrid->addWidget(widget,row,col,1,1); 891 | 892 | plot->addGraph(); // blue line 893 | plot->graph(0)->setPen(QPen(QColor(40, 110, 255))); 894 | plot->addGraph(); // red line 895 | plot->graph(1)->setPen(QPen(QColor(255, 110, 40))); 896 | 897 | QSharedPointer timeTicker(new QCPAxisTickerTime); 898 | timeTicker->setTimeFormat("%h:%m:%s"); 899 | plot->xAxis->setTicker(timeTicker); 900 | plot->axisRect()->setupFullAxesBox(); 901 | plot->yAxis->setRange(-1.2, 1.2); 902 | 903 | // make left and bottom axes transfer their ranges to right and top axes: 904 | connect(plot->xAxis, SIGNAL(rangeChanged(QCPRange)), plot->xAxis2, SLOT(setRange(QCPRange))); 905 | connect(plot->yAxis, SIGNAL(rangeChanged(QCPRange)), plot->yAxis2, SLOT(setRange(QCPRange))); 906 | 907 | connect(timer, &QTimer::timeout, 908 | [=]() { 909 | static QTime timeData(QTime::currentTime()); 910 | // calculate two new data points: 911 | double key = timeData.elapsed()/1000.0; // time elapsed since start of demo, in seconds 912 | static double lastPointKeyData = 0; 913 | if (key-lastPointKeyData > 0.002) // at most add point every 2 ms 914 | { 915 | // add data to lines: 916 | plot->graph(0)->addData(key, qSin(key)+qrand()/(double)RAND_MAX*1*qSin(key/0.3843)); 917 | plot->graph(1)->addData(key, qCos(key)+qrand()/(double)RAND_MAX*0.5*qSin(key/0.4364)); 918 | // rescale value (vertical) axis to fit the current data: 919 | //ui->customPlot->graph(0)->rescaleValueAxis(); 920 | //ui->customPlot->graph(1)->rescaleValueAxis(true); 921 | lastPointKeyData = key; 922 | } 923 | // make key axis range scroll with the data (at a constant range size of 8): 924 | plot->xAxis->setRange(key, 10, Qt::AlignRight); 925 | plot->replot(); 926 | 927 | 928 | plot->graph(0)->data()->removeBefore(key-11); 929 | plot->graph(1)->data()->removeBefore(key-11); 930 | 931 | // calculate frames per second: 932 | static double lastFpsKeyData; 933 | static int frameCountData; 934 | ++frameCountData; 935 | if (key-lastFpsKeyData > 2) // average fps over 2 seconds 936 | { 937 | bar->showMessage( 938 | QString("%1 FPS, Total Data points: %2") 939 | .arg(frameCountData/(key-lastFpsKeyData), 0, 'f', 0) 940 | .arg(plot->graph(0)->data()->size()+plot->graph(1)->data()->size()) 941 | , 0); 942 | lastFpsKeyData = key; 943 | frameCountData = 0; 944 | } 945 | } 946 | ); 947 | timer->start(0); // Interval 0 means to refresh as fast as possible 948 | 949 | } 950 | 951 | void MainWindow::setupRealtimeThresholdDemo(int row, int col, bool openGl) 952 | { 953 | 954 | QTimer *timer = new QTimer(); 955 | QWidget *widget = new QWidget(); 956 | widget->setWindowTitle("Real Time Threshold Demo"); 957 | widget->setMinimumHeight(400); 958 | widget->setMaximumHeight(400); 959 | 960 | QCustomPlot *plot = new QCustomPlot(); 961 | plot->setOpenGl(openGl); 962 | QStatusBar *bar = new QStatusBar(); 963 | 964 | QVBoxLayout *layout = new QVBoxLayout(); 965 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 966 | layout->addWidget(plot, 1); 967 | layout->addWidget(bar, 0); 968 | widget->setLayout(layout); 969 | 970 | _loGrid->addWidget(widget,row,col,1,1); 971 | 972 | plot->legend->setVisible(false); 973 | plot->addGraph(); // blue line 974 | plot->graph(0)->setPen(QPen(Qt::blue)); 975 | plot->addGraph(); // blue line 976 | plot->graph(1)->setPen(QPen(Qt::green)); 977 | plot->addGraph(); // blue line 978 | plot->graph(2)->setPen(QPen(Qt::red)); 979 | 980 | QSharedPointer timeTicker(new QCPAxisTickerTime); 981 | timeTicker->setTimeFormat("%h:%m:%s"); 982 | plot->xAxis->setTicker(timeTicker); 983 | plot->axisRect()->setupFullAxesBox(); 984 | plot->yAxis->setRange(-1.5, 1.5); 985 | 986 | QCPItemLine *lineBottom = new QCPItemLine(plot); 987 | lineBottom->setPen(QPen(Qt::green, 1, Qt::DashLine)); 988 | lineBottom->start->setTypeX(QCPItemPosition::ptAxisRectRatio); 989 | lineBottom->start->setTypeY(QCPItemPosition::ptPlotCoords); 990 | lineBottom->start->setAxisRect(plot->axisRect()); 991 | lineBottom->start->setAxes(0, plot->yAxis); 992 | lineBottom->start->setCoords(0, -1.0); 993 | lineBottom->end->setTypeX(QCPItemPosition::ptAxisRectRatio); 994 | lineBottom->end->setTypeY(QCPItemPosition::ptPlotCoords); 995 | lineBottom->end->setAxisRect(plot->axisRect()); 996 | lineBottom->end->setAxes(0, plot->yAxis); 997 | lineBottom->end->setCoords(1, -1.0); 998 | 999 | QCPItemLine *lineTop = new QCPItemLine(plot); 1000 | lineTop->setPen(QPen(Qt::red, 1, Qt::DashLine)); 1001 | lineTop->start->setTypeX(QCPItemPosition::ptAxisRectRatio); 1002 | lineTop->start->setTypeY(QCPItemPosition::ptPlotCoords); 1003 | lineTop->start->setAxisRect(plot->axisRect()); 1004 | lineTop->start->setAxes(0, plot->yAxis); 1005 | lineTop->start->setCoords(0, 1.0); 1006 | lineTop->end->setTypeX(QCPItemPosition::ptAxisRectRatio); 1007 | lineTop->end->setTypeY(QCPItemPosition::ptPlotCoords); 1008 | lineTop->end->setAxisRect(plot->axisRect()); 1009 | lineTop->end->setAxes(0, plot->yAxis); 1010 | lineTop->end->setCoords(1, 1.0); 1011 | 1012 | // make left and bottom axes transfer their ranges to right and top axes: 1013 | connect(plot->xAxis, SIGNAL(rangeChanged(QCPRange)), plot->xAxis2, SLOT(setRange(QCPRange))); 1014 | connect(plot->yAxis, SIGNAL(rangeChanged(QCPRange)), plot->yAxis2, SLOT(setRange(QCPRange))); 1015 | 1016 | // setup a timer that repeatedly calls MainWindow::realtimeDataSlot: 1017 | // connect(&dataTimer, SIGNAL(timeout()), this, SLOT(realtimeDataSlot())); 1018 | 1019 | connect(timer, &QTimer::timeout, 1020 | [=]() { 1021 | static QTime time(QTime::currentTime()); 1022 | // calculate two new data points: 1023 | double key = time.elapsed()/1000.0; // time elapsed since start of demo, in seconds 1024 | static double lastPointKey = 0; 1025 | static double lastPointValue = 0; 1026 | if (key-lastPointKey > 0.002) // at most add point every 2 ms 1027 | { 1028 | 1029 | // add data to lines: 1030 | double val = qSin(key)+qrand()/(double)RAND_MAX*1*qSin(key/0.3843); 1031 | if(val < -1.0) { 1032 | if(lastPointValue < -1.0) 1033 | plot->graph(1)->addData(key, val); 1034 | else if (lastPointValue > 1.0) { 1035 | double interv = (key - lastPointKey)/3; 1036 | plot->graph(2)->addData(lastPointKey + interv, 1.0); 1037 | plot->graph(0)->addData(lastPointKey + interv, 1.0); 1038 | plot->graph(0)->addData(lastPointKey + 2*interv, -1.0); 1039 | plot->graph(1)->addData(lastPointKey + 2*interv, -1.0); 1040 | plot->graph(1)->addData(key, val); 1041 | } else { 1042 | double interv = (key - lastPointKey)/2; 1043 | plot->graph(0)->addData(lastPointKey + interv, -1.0); 1044 | plot->graph(1)->addData(lastPointKey + interv, -1.0); 1045 | plot->graph(1)->addData(key, val); 1046 | } 1047 | plot->graph(0)->addData(key, qQNaN()); 1048 | plot->graph(2)->addData(key, qQNaN()); 1049 | } 1050 | else if( val > 1.0) { 1051 | if(lastPointValue < -1.0) { 1052 | double interv = (key - lastPointKey)/3; 1053 | plot->graph(0)->addData(lastPointKey + interv, -1.0); 1054 | plot->graph(0)->addData(lastPointKey + 2*interv, 1.0); 1055 | plot->graph(1)->addData(lastPointKey + interv, -1.0); 1056 | plot->graph(2)->addData(lastPointKey + 2*interv, 1.0); 1057 | plot->graph(2)->addData(key, val); 1058 | } 1059 | else if (lastPointValue > 1.0) { 1060 | plot->graph(2)->addData(key, val); 1061 | 1062 | } else 1063 | { 1064 | double interv = (key - lastPointKey)/2; 1065 | plot->graph(0)->addData(lastPointKey + interv, 1.0); 1066 | plot->graph(2)->addData(lastPointKey + interv, 1.0); 1067 | plot->graph(2)->addData(key, val); 1068 | } 1069 | 1070 | plot->graph(0)->addData(key, qQNaN()); 1071 | plot->graph(1)->addData(key, qQNaN()); 1072 | } else { 1073 | if(lastPointValue < -1.0) { 1074 | double interv = (key - lastPointKey)/2; 1075 | plot->graph(1)->addData(lastPointKey + interv, -1.0); 1076 | plot->graph(0)->addData(lastPointKey + interv, -1.0); 1077 | plot->graph(0)->addData(key, val); 1078 | }else if (lastPointValue > 1.0) { 1079 | double interv = (key - lastPointKey)/2; 1080 | plot->graph(2)->addData(lastPointKey + interv, 1.0); 1081 | plot->graph(0)->addData(lastPointKey + interv, 1.0); 1082 | plot->graph(0)->addData(key, val); 1083 | } else 1084 | { 1085 | plot->graph(0)->addData(key, val); 1086 | } 1087 | 1088 | plot->graph(1)->addData(key, qQNaN()); 1089 | plot->graph(2)->addData(key, qQNaN()); 1090 | 1091 | } 1092 | lastPointKey = key; 1093 | lastPointValue = val; 1094 | } 1095 | // make key axis range scroll with the data (at a constant range size of 8): 1096 | 1097 | // lineBottom->start->setCoords(0,-1.0); 1098 | // lineBottom->end->setCoords(1,-1.0); 1099 | plot->graph(0)->data()->removeBefore(key-10); 1100 | plot->graph(1)->data()->removeBefore(key-10); 1101 | plot->graph(2)->data()->removeBefore(key-10); 1102 | plot->xAxis->rescale(); 1103 | plot->yAxis->rescale(); 1104 | plot->replot(); 1105 | 1106 | // calculate frames per second: 1107 | static double lastFpsKey; 1108 | static int frameCount; 1109 | ++frameCount; 1110 | if (key-lastFpsKey > 2) // average fps over 2 seconds 1111 | { 1112 | bar->showMessage( 1113 | QString("%1 FPS, Total Data points: %2") 1114 | .arg(frameCount/(key-lastFpsKey), 0, 'f', 0) 1115 | .arg(plot->graph(0)->data()->size()+plot->graph(1)->data()->size()) 1116 | , 0); 1117 | lastFpsKey = key; 1118 | frameCount = 0; 1119 | } 1120 | } 1121 | ); 1122 | timer->start(0); // Interval 0 means to refresh as fast as possible 1123 | } 1124 | 1125 | void MainWindow::setupRealtimeBrushDemo(int row, int col, bool openGl) 1126 | { 1127 | QTimer *timer = new QTimer(); 1128 | QWidget *widget = new QWidget(); 1129 | widget->setWindowTitle("Real Time Brush Demo"); 1130 | widget->setMinimumHeight(400); 1131 | widget->setMaximumHeight(400); 1132 | 1133 | QCustomPlot *plot = new QCustomPlot(); 1134 | plot->setOpenGl(openGl); 1135 | QStatusBar *bar = new QStatusBar(); 1136 | 1137 | QVBoxLayout *layout = new QVBoxLayout(); 1138 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 1139 | layout->addWidget(plot, 1); 1140 | layout->addWidget(bar, 0); 1141 | widget->setLayout(layout); 1142 | 1143 | _loGrid->addWidget(widget,row,col,1,1); 1144 | // demoName = "Real Time Data Demo"; 1145 | 1146 | // include this section to fully disable antialiasing for higher performance: 1147 | /* 1148 | customPlot->setNotAntialiasedElements(QCP::aeAll); 1149 | QFont font; 1150 | font.setStyleStrategy(QFont::NoAntialias); 1151 | customPlot->xAxis->setTickLabelFont(font); 1152 | customPlot->yAxis->setTickLabelFont(font); 1153 | customPlot->legend->setFont(font); 1154 | */ 1155 | 1156 | plot->addGraph(); // red line 1157 | plot->graph(0)->setPen(Qt::NoPen); 1158 | QLinearGradient gradient0(0, 0, 0, 1); 1159 | gradient0.setCoordinateMode(QGradient::ObjectBoundingMode); 1160 | gradient0.setColorAt(1, QColor(40, 110, 255, 255)); 1161 | gradient0.setColorAt(0.95, QColor(40, 110, 255, 200)); 1162 | gradient0.setColorAt(0, QColor::fromRgbF(0, 0, 0, 0)); 1163 | QBrush brush0(gradient0); 1164 | plot->graph(0)->setBrush(brush0); 1165 | 1166 | plot->addGraph(); // red line 1167 | plot->graph(1)->setPen(Qt::NoPen); 1168 | 1169 | QLinearGradient gradient1(0, 0, 0, 1); 1170 | gradient1.setCoordinateMode(QGradient::ObjectBoundingMode); 1171 | gradient1.setColorAt(1, QColor(255, 110, 40, 255)); 1172 | gradient1.setColorAt(0.95, QColor(255, 110, 40, 200)); 1173 | gradient1.setColorAt(0, QColor::fromRgbF(0, 0, 0, 0)); 1174 | QBrush brush1(gradient1); 1175 | plot->graph(1)->setBrush(brush1); 1176 | 1177 | QSharedPointer timeTicker(new QCPAxisTickerTime); 1178 | timeTicker->setTimeFormat("%h:%m:%s"); 1179 | plot->xAxis->setTicker(timeTicker); 1180 | plot->axisRect()->setupFullAxesBox(); 1181 | plot->yAxis->setRange(-1.5, 1.5); 1182 | 1183 | // make left and bottom axes transfer their ranges to right and top axes: 1184 | connect(plot->xAxis, SIGNAL(rangeChanged(QCPRange)), plot->xAxis2, SLOT(setRange(QCPRange))); 1185 | connect(plot->yAxis, SIGNAL(rangeChanged(QCPRange)), plot->yAxis2, SLOT(setRange(QCPRange))); 1186 | 1187 | // setup a timer that repeatedly calls MainWindow::realtimeDataSlot: 1188 | // connect(&dataTimer, SIGNAL(timeout()), this, SLOT(realtimeDataSlot())); 1189 | 1190 | connect(timer, &QTimer::timeout, 1191 | [=]() { 1192 | static QTime timeBrush(QTime::currentTime()); 1193 | // calculate two new data points: 1194 | double key = timeBrush.elapsed()/1000.0; // time elapsed since start of demo, in seconds 1195 | static double lastPointKeyBrush = 0; 1196 | if (key-lastPointKeyBrush > 0.002) // at most add point every 2 ms 1197 | { 1198 | 1199 | // add data to lines: 1200 | plot->graph(0)->addData(key, qSin(key)+qrand()/(double)RAND_MAX*1*qSin(key/0.3843)); 1201 | plot->graph(1)->addData(key, qCos(key)+qrand()/(double)RAND_MAX*0.5*qSin(key/0.4364)); 1202 | // rescale value (vertical) axis to fit the current data: 1203 | //ui->customPlot->graph(0)->rescaleValueAxis(); 1204 | //ui->customPlot->graph(1)->rescaleValueAxis(true); 1205 | lastPointKeyBrush = key; 1206 | } 1207 | // make key axis range scroll with the data (at a constant range size of 8): 1208 | 1209 | plot->graph(0)->data()->removeBefore(key-10); 1210 | plot->graph(1)->data()->removeBefore(key-10); 1211 | plot->xAxis->rescale(); 1212 | plot->yAxis->rescale(); 1213 | plot->replot(); 1214 | 1215 | // calculate frames per second: 1216 | static double lastFpsKeyBrush; 1217 | static int frameCountBrush; 1218 | ++frameCountBrush; 1219 | if (key-lastFpsKeyBrush > 2) // average fps over 2 seconds 1220 | { 1221 | bar->showMessage( 1222 | QString("%1 FPS, Total Data points: %2") 1223 | .arg(frameCountBrush/(key-lastFpsKeyBrush), 0, 'f', 0) 1224 | .arg(plot->graph(0)->data()->size()+plot->graph(1)->data()->size()) 1225 | , 0); 1226 | lastFpsKeyBrush = key; 1227 | frameCountBrush = 0; 1228 | } 1229 | } 1230 | ); 1231 | timer->start(0); // Interval 0 means to refresh as fast as possible 1232 | } 1233 | 1234 | void MainWindow::setupRealtimeEcgDemo(int row, int col, bool openGl) 1235 | { 1236 | QWidget *widget = new QWidget(); 1237 | widget->setWindowTitle("Real Time ECG Demo"); 1238 | widget->setMinimumHeight(400); 1239 | widget->setMaximumHeight(400); 1240 | 1241 | QCustomPlot *plot = new QCustomPlot(); 1242 | plot->setOpenGl(openGl); 1243 | QStatusBar *bar = new QStatusBar(); 1244 | 1245 | QVBoxLayout *layout = new QVBoxLayout(); 1246 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 1247 | layout->addWidget(plot, 1); 1248 | layout->addWidget(bar, 0); 1249 | widget->setLayout(layout); 1250 | 1251 | _loGrid->addWidget(widget,row,col,1,1); 1252 | 1253 | plot->addGraph(plot->xAxis, plot->yAxis); // blue line 1254 | plot->graph(0)->setPen(QPen(Qt::blue)); 1255 | plot->addGraph(plot->xAxis2, plot->yAxis); // red line 1256 | plot->graph(1)->setPen(QPen(Qt::red)); 1257 | 1258 | plot->xAxis->setRange(0, 10); 1259 | plot->xAxis2->setRange(10, 20); 1260 | 1261 | QTimer *timer =new QTimer(); 1262 | connect(timer, &QTimer::timeout, 1263 | [=]() { 1264 | 1265 | static QTime timeEcg(QTime::currentTime()); 1266 | // calculate two new data points: 1267 | double keyTime = timeEcg.elapsed()/1000.0; // time elapsed since start of demo, in seconds 1268 | 1269 | double key = std::fmod(keyTime,20); 1270 | 1271 | static bool plottingBlue = true; 1272 | 1273 | // add data to lines: 1274 | double val = qSin(keyTime)+qrand()/(double)RAND_MAX*1*qSin(keyTime/0.3843); 1275 | plot->graph(0)->addData(key, val); 1276 | plot->graph(1)->addData(key, val); 1277 | 1278 | if(key <10.0) 1279 | { 1280 | if(!plottingBlue) 1281 | { 1282 | plottingBlue = true; 1283 | plot->graph(0)->data()->clear(); 1284 | } 1285 | plot->graph(1)->data()->removeBefore(10+key); 1286 | } 1287 | else 1288 | { 1289 | if(plottingBlue) 1290 | { 1291 | plottingBlue = false; 1292 | plot->graph(1)->data()->clear(); 1293 | } 1294 | plot->graph(0)->data()->removeBefore(key-10); 1295 | } 1296 | 1297 | // make key axis range scroll with the data (at a constant range size of 8): 1298 | plot->yAxis->rescale(); 1299 | plot->replot(); 1300 | } 1301 | ); 1302 | timer->start(0); 1303 | 1304 | } 1305 | 1306 | void MainWindow::setupParametricCurveDemo(int row, int col, bool openGl) 1307 | { 1308 | QWidget *widget = new QWidget(); 1309 | widget->setWindowTitle("Parametric Curves Demo"); 1310 | widget->setMinimumHeight(400); 1311 | widget->setMaximumHeight(400); 1312 | 1313 | QCustomPlot *plot = new QCustomPlot(); 1314 | plot->setOpenGl(openGl); 1315 | QStatusBar *bar = new QStatusBar(); 1316 | 1317 | QVBoxLayout *layout = new QVBoxLayout(); 1318 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 1319 | layout->addWidget(plot, 1); 1320 | layout->addWidget(bar, 0); 1321 | widget->setLayout(layout); 1322 | 1323 | _loGrid->addWidget(widget,row,col,1,1); 1324 | // demoName = "Parametric Curves Demo"; 1325 | 1326 | // create empty curve objects: 1327 | QCPCurve *fermatSpiral1 = new QCPCurve(plot->xAxis, plot->yAxis); 1328 | QCPCurve *fermatSpiral2 = new QCPCurve(plot->xAxis, plot->yAxis); 1329 | QCPCurve *deltoidRadial = new QCPCurve(plot->xAxis, plot->yAxis); 1330 | // generate the curve data points: 1331 | const int pointCount = 500; 1332 | QVector dataSpiral1(pointCount), dataSpiral2(pointCount), dataDeltoid(pointCount); 1333 | for (int i=0; idata()->set(dataSpiral1, true); 1343 | fermatSpiral2->data()->set(dataSpiral2, true); 1344 | deltoidRadial->data()->set(dataDeltoid, true); 1345 | // color the curves: 1346 | fermatSpiral1->setPen(QPen(Qt::blue)); 1347 | fermatSpiral1->setBrush(QBrush(QColor(0, 0, 255, 20))); 1348 | fermatSpiral2->setPen(QPen(QColor(255, 120, 0))); 1349 | fermatSpiral2->setBrush(QBrush(QColor(255, 120, 0, 30))); 1350 | QRadialGradient radialGrad(QPointF(310, 180), 200); 1351 | radialGrad.setColorAt(0, QColor(170, 20, 240, 100)); 1352 | radialGrad.setColorAt(0.5, QColor(20, 10, 255, 40)); 1353 | radialGrad.setColorAt(1,QColor(120, 20, 240, 10)); 1354 | deltoidRadial->setPen(QPen(QColor(170, 20, 240))); 1355 | deltoidRadial->setBrush(QBrush(radialGrad)); 1356 | // set some basic customPlot config: 1357 | plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables); 1358 | plot->axisRect()->setupFullAxesBox(); 1359 | plot->rescaleAxes(); 1360 | 1361 | plot->replot(); 1362 | } 1363 | 1364 | void MainWindow::setupBarChartDemo(int row, int col, bool openGl) 1365 | { 1366 | QWidget *widget = new QWidget(); 1367 | widget->setWindowTitle("Bar Chart Demo"); 1368 | widget->setMinimumHeight(400); 1369 | widget->setMaximumHeight(400); 1370 | 1371 | QCustomPlot *plot = new QCustomPlot(); 1372 | plot->setOpenGl(openGl); 1373 | QStatusBar *bar = new QStatusBar(); 1374 | 1375 | QVBoxLayout *layout = new QVBoxLayout(); 1376 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 1377 | layout->addWidget(plot, 1); 1378 | layout->addWidget(bar, 0); 1379 | widget->setLayout(layout); 1380 | 1381 | _loGrid->addWidget(widget,row,col,1,1); 1382 | // demoName = "Bar Chart Demo"; 1383 | // set dark background gradient: 1384 | QLinearGradient gradient(0, 0, 0, 400); 1385 | gradient.setColorAt(0, QColor(90, 90, 90)); 1386 | gradient.setColorAt(0.38, QColor(105, 105, 105)); 1387 | gradient.setColorAt(1, QColor(70, 70, 70)); 1388 | plot->setBackground(QBrush(gradient)); 1389 | 1390 | // create empty bar chart objects: 1391 | QCPBars *regen = new QCPBars(plot->xAxis, plot->yAxis); 1392 | QCPBars *nuclear = new QCPBars(plot->xAxis, plot->yAxis); 1393 | QCPBars *fossil = new QCPBars(plot->xAxis, plot->yAxis); 1394 | regen->setAntialiased(false); // gives more crisp, pixel aligned bar borders 1395 | nuclear->setAntialiased(false); 1396 | fossil->setAntialiased(false); 1397 | regen->setStackingGap(1); 1398 | nuclear->setStackingGap(1); 1399 | fossil->setStackingGap(1); 1400 | // set names and colors: 1401 | fossil->setName("Fossil fuels"); 1402 | fossil->setPen(QPen(QColor(111, 9, 176).lighter(170))); 1403 | fossil->setBrush(QColor(111, 9, 176)); 1404 | nuclear->setName("Nuclear"); 1405 | nuclear->setPen(QPen(QColor(250, 170, 20).lighter(150))); 1406 | nuclear->setBrush(QColor(250, 170, 20)); 1407 | regen->setName("Regenerative"); 1408 | regen->setPen(QPen(QColor(0, 168, 140).lighter(130))); 1409 | regen->setBrush(QColor(0, 168, 140)); 1410 | // stack bars on top of each other: 1411 | nuclear->moveAbove(fossil); 1412 | regen->moveAbove(nuclear); 1413 | 1414 | // prepare x axis with country labels: 1415 | QVector ticks; 1416 | QVector labels; 1417 | ticks << 1 << 2 << 3 << 4 << 5 << 6 << 7; 1418 | labels << "USA" << "Japan" << "Germany" << "France" << "UK" << "Italy" << "Canada"; 1419 | QSharedPointer textTicker(new QCPAxisTickerText); 1420 | textTicker->addTicks(ticks, labels); 1421 | plot->xAxis->setTicker(textTicker); 1422 | plot->xAxis->setTickLabelRotation(60); 1423 | plot->xAxis->setSubTicks(false); 1424 | plot->xAxis->setTickLength(0, 4); 1425 | plot->xAxis->setRange(0, 8); 1426 | plot->xAxis->setBasePen(QPen(Qt::white)); 1427 | plot->xAxis->setTickPen(QPen(Qt::white)); 1428 | plot->xAxis->grid()->setVisible(true); 1429 | plot->xAxis->grid()->setPen(QPen(QColor(130, 130, 130), 0, Qt::DotLine)); 1430 | plot->xAxis->setTickLabelColor(Qt::white); 1431 | plot->xAxis->setLabelColor(Qt::white); 1432 | 1433 | // prepare y axis: 1434 | plot->yAxis->setRange(0, 12.1); 1435 | plot->yAxis->setPadding(5); // a bit more space to the left border 1436 | plot->yAxis->setLabel("Power Consumption in\nKilowatts per Capita (2007)"); 1437 | plot->yAxis->setBasePen(QPen(Qt::white)); 1438 | plot->yAxis->setTickPen(QPen(Qt::white)); 1439 | plot->yAxis->setSubTickPen(QPen(Qt::white)); 1440 | plot->yAxis->grid()->setSubGridVisible(true); 1441 | plot->yAxis->setTickLabelColor(Qt::white); 1442 | plot->yAxis->setLabelColor(Qt::white); 1443 | plot->yAxis->grid()->setPen(QPen(QColor(130, 130, 130), 0, Qt::SolidLine)); 1444 | plot->yAxis->grid()->setSubGridPen(QPen(QColor(130, 130, 130), 0, Qt::DotLine)); 1445 | 1446 | // Add data: 1447 | QVector fossilData, nuclearData, regenData; 1448 | 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; 1449 | 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; 1450 | 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; 1451 | fossil->setData(ticks, fossilData); 1452 | nuclear->setData(ticks, nuclearData); 1453 | regen->setData(ticks, regenData); 1454 | 1455 | // setup legend: 1456 | plot->legend->setVisible(true); 1457 | plot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignTop|Qt::AlignHCenter); 1458 | plot->legend->setBrush(QColor(255, 255, 255, 100)); 1459 | plot->legend->setBorderPen(Qt::NoPen); 1460 | QFont legendFont = font(); 1461 | legendFont.setPointSize(10); 1462 | plot->legend->setFont(legendFont); 1463 | plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); 1464 | 1465 | plot->replot(); 1466 | } 1467 | 1468 | void MainWindow::setupStatisticalDemo(int row, int col, bool openGl) 1469 | { 1470 | QWidget *widget = new QWidget(); 1471 | widget->setWindowTitle("Statistical Demo"); 1472 | widget->setMinimumHeight(400); 1473 | widget->setMaximumHeight(400); 1474 | 1475 | QCustomPlot *plot = new QCustomPlot(); 1476 | plot->setOpenGl(openGl); 1477 | QStatusBar *bar = new QStatusBar(); 1478 | 1479 | QVBoxLayout *layout = new QVBoxLayout(); 1480 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 1481 | layout->addWidget(plot, 1); 1482 | layout->addWidget(bar, 0); 1483 | widget->setLayout(layout); 1484 | 1485 | _loGrid->addWidget(widget,row,col,1,1); 1486 | // demoName = "Statistical Demo"; 1487 | QCPStatisticalBox *statistical = new QCPStatisticalBox(plot->xAxis, plot->yAxis); 1488 | QBrush boxBrush(QColor(60, 60, 255, 100)); 1489 | boxBrush.setStyle(Qt::Dense6Pattern); // make it look oldschool 1490 | statistical->setBrush(boxBrush); 1491 | 1492 | // specify data: 1493 | statistical->addData(1, 1.1, 1.9, 2.25, 2.7, 4.2); 1494 | statistical->addData(2, 0.8, 1.6, 2.2, 3.2, 4.9, QVector() << 0.7 << 0.34 << 0.45 << 6.2 << 5.84); // provide some outliers as QVector 1495 | statistical->addData(3, 0.2, 0.7, 1.1, 1.6, 2.9); 1496 | 1497 | // prepare manual x axis labels: 1498 | plot->xAxis->setSubTicks(false); 1499 | plot->xAxis->setTickLength(0, 4); 1500 | plot->xAxis->setTickLabelRotation(20); 1501 | QSharedPointer textTicker(new QCPAxisTickerText); 1502 | textTicker->addTick(1, "Sample 1"); 1503 | textTicker->addTick(2, "Sample 2"); 1504 | textTicker->addTick(3, "Control Group"); 1505 | plot->xAxis->setTicker(textTicker); 1506 | 1507 | // prepare axes: 1508 | plot->yAxis->setLabel(QString::fromUtf8("O₂ Absorption [mg]")); 1509 | plot->rescaleAxes(); 1510 | plot->xAxis->scaleRange(1.7, plot->xAxis->range().center()); 1511 | plot->yAxis->setRange(0, 7); 1512 | plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); 1513 | 1514 | plot->replot(); 1515 | } 1516 | 1517 | void MainWindow::setupSimpleItemDemo(int row, int col, bool openGl) 1518 | { 1519 | QWidget *widget = new QWidget(); 1520 | widget->setWindowTitle("Simple Item Demo"); 1521 | widget->setMinimumHeight(400); 1522 | widget->setMaximumHeight(400); 1523 | 1524 | QCustomPlot *plot = new QCustomPlot(); 1525 | plot->setOpenGl(openGl); 1526 | QStatusBar *bar = new QStatusBar(); 1527 | 1528 | QVBoxLayout *layout = new QVBoxLayout(); 1529 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 1530 | layout->addWidget(plot, 1); 1531 | layout->addWidget(bar, 0); 1532 | widget->setLayout(layout); 1533 | 1534 | _loGrid->addWidget(widget,row,col,1,1); 1535 | // demoName = "Simple Item Demo"; 1536 | plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); 1537 | 1538 | // add the text label at the top: 1539 | QCPItemText *textLabel = new QCPItemText(plot); 1540 | textLabel->setPositionAlignment(Qt::AlignTop|Qt::AlignHCenter); 1541 | textLabel->position->setType(QCPItemPosition::ptAxisRectRatio); 1542 | textLabel->position->setCoords(0.5, 0); // place position at center/top of axis rect 1543 | textLabel->setText("Text Item Demo"); 1544 | textLabel->setFont(QFont(font().family(), 16)); // make font a bit larger 1545 | textLabel->setPen(QPen(Qt::black)); // show black border around text 1546 | 1547 | // add the arrow: 1548 | QCPItemLine *arrow = new QCPItemLine(plot); 1549 | arrow->start->setParentAnchor(textLabel->bottom); 1550 | arrow->end->setCoords(4, 1.6); // point to (4, 1.6) in x-y-plot coordinates 1551 | arrow->setHead(QCPLineEnding::esSpikeArrow); 1552 | 1553 | plot->replot(); 1554 | } 1555 | 1556 | void MainWindow::setupItemDemo(int row, int col, bool openGl) 1557 | { 1558 | QWidget *widget = new QWidget(); 1559 | widget->setWindowTitle("Item Demo"); 1560 | widget->setMinimumHeight(400); 1561 | widget->setMaximumHeight(400); 1562 | 1563 | QCustomPlot *plot = new QCustomPlot(); 1564 | plot->setOpenGl(openGl); 1565 | QStatusBar *bar = new QStatusBar(); 1566 | 1567 | QVBoxLayout *layout = new QVBoxLayout(); 1568 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 1569 | layout->addWidget(plot, 1); 1570 | layout->addWidget(bar, 0); 1571 | widget->setLayout(layout); 1572 | 1573 | _loGrid->addWidget(widget,row,col,1,1); 1574 | 1575 | plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); 1576 | QCPGraph *graph = plot->addGraph(); 1577 | int n = 500; 1578 | double phase = 0; 1579 | double k = 3; 1580 | QVector x(n), y(n); 1581 | for (int i=0; isetData(x, y); 1587 | graph->setPen(QPen(Qt::blue)); 1588 | graph->rescaleKeyAxis(); 1589 | plot->yAxis->setRange(-1.45, 1.65); 1590 | plot->xAxis->grid()->setZeroLinePen(Qt::NoPen); 1591 | 1592 | // add the bracket at the top: 1593 | QCPItemBracket *bracket = new QCPItemBracket(plot); 1594 | bracket->left->setCoords(-8, 1.1); 1595 | bracket->right->setCoords(8, 1.1); 1596 | bracket->setLength(13); 1597 | 1598 | // add the text label at the top: 1599 | QCPItemText *wavePacketText = new QCPItemText(plot); 1600 | wavePacketText->position->setParentAnchor(bracket->center); 1601 | wavePacketText->position->setCoords(0, -10); // move 10 pixels to the top from bracket center anchor 1602 | wavePacketText->setPositionAlignment(Qt::AlignBottom|Qt::AlignHCenter); 1603 | wavePacketText->setText("Wavepacket"); 1604 | wavePacketText->setFont(QFont(font().family(), 10)); 1605 | 1606 | // add the phase tracer (red circle) which sticks to the graph data (and gets updated in bracketDataSlot by timer event): 1607 | QCPItemTracer *phaseTracer = new QCPItemTracer(plot); 1608 | phaseTracer->setGraph(graph); 1609 | phaseTracer->setGraphKey((M_PI*1.5-phase)/k); 1610 | phaseTracer->setInterpolating(true); 1611 | phaseTracer->setStyle(QCPItemTracer::tsCircle); 1612 | phaseTracer->setPen(QPen(Qt::red)); 1613 | phaseTracer->setBrush(Qt::red); 1614 | phaseTracer->setSize(7); 1615 | 1616 | // add label for phase tracer: 1617 | QCPItemText *phaseTracerText = new QCPItemText(plot); 1618 | phaseTracerText->position->setType(QCPItemPosition::ptAxisRectRatio); 1619 | phaseTracerText->setPositionAlignment(Qt::AlignRight|Qt::AlignBottom); 1620 | phaseTracerText->position->setCoords(1.0, 0.95); // lower right corner of axis rect 1621 | phaseTracerText->setText("Points of fixed\nphase define\nphase velocity vp"); 1622 | phaseTracerText->setTextAlignment(Qt::AlignLeft); 1623 | phaseTracerText->setFont(QFont(font().family(), 9)); 1624 | phaseTracerText->setPadding(QMargins(8, 0, 0, 0)); 1625 | 1626 | // add arrow pointing at phase tracer, coming from label: 1627 | QCPItemCurve *phaseTracerArrow = new QCPItemCurve(plot); 1628 | phaseTracerArrow->start->setParentAnchor(phaseTracerText->left); 1629 | phaseTracerArrow->startDir->setParentAnchor(phaseTracerArrow->start); 1630 | phaseTracerArrow->startDir->setCoords(-40, 0); // direction 30 pixels to the left of parent anchor (tracerArrow->start) 1631 | phaseTracerArrow->end->setParentAnchor(phaseTracer->position); 1632 | phaseTracerArrow->end->setCoords(10, 10); 1633 | phaseTracerArrow->endDir->setParentAnchor(phaseTracerArrow->end); 1634 | phaseTracerArrow->endDir->setCoords(30, 30); 1635 | phaseTracerArrow->setHead(QCPLineEnding::esSpikeArrow); 1636 | phaseTracerArrow->setTail(QCPLineEnding(QCPLineEnding::esBar, (phaseTracerText->bottom->pixelPosition().y()-phaseTracerText->top->pixelPosition().y())*0.85)); 1637 | 1638 | // add the group velocity tracer (green circle): 1639 | QCPItemTracer *groupTracer = new QCPItemTracer(plot); 1640 | groupTracer->setGraph(graph); 1641 | groupTracer->setGraphKey(5.5); 1642 | groupTracer->setInterpolating(true); 1643 | groupTracer->setStyle(QCPItemTracer::tsCircle); 1644 | groupTracer->setPen(QPen(Qt::green)); 1645 | groupTracer->setBrush(Qt::green); 1646 | groupTracer->setSize(7); 1647 | 1648 | // add label for group tracer: 1649 | QCPItemText *groupTracerText = new QCPItemText(plot); 1650 | groupTracerText->position->setType(QCPItemPosition::ptAxisRectRatio); 1651 | groupTracerText->setPositionAlignment(Qt::AlignRight|Qt::AlignTop); 1652 | groupTracerText->position->setCoords(1.0, 0.20); // lower right corner of axis rect 1653 | groupTracerText->setText("Fixed positions in\nwave packet define\ngroup velocity vg"); 1654 | groupTracerText->setTextAlignment(Qt::AlignLeft); 1655 | groupTracerText->setFont(QFont(font().family(), 9)); 1656 | groupTracerText->setPadding(QMargins(8, 0, 0, 0)); 1657 | 1658 | // add arrow pointing at group tracer, coming from label: 1659 | QCPItemCurve *groupTracerArrow = new QCPItemCurve(plot); 1660 | groupTracerArrow->start->setParentAnchor(groupTracerText->left); 1661 | groupTracerArrow->startDir->setParentAnchor(groupTracerArrow->start); 1662 | groupTracerArrow->startDir->setCoords(-40, 0); // direction 30 pixels to the left of parent anchor (tracerArrow->start) 1663 | groupTracerArrow->end->setCoords(5.5, 0.4); 1664 | groupTracerArrow->endDir->setParentAnchor(groupTracerArrow->end); 1665 | groupTracerArrow->endDir->setCoords(0, -40); 1666 | groupTracerArrow->setHead(QCPLineEnding::esSpikeArrow); 1667 | groupTracerArrow->setTail(QCPLineEnding(QCPLineEnding::esBar, (groupTracerText->bottom->pixelPosition().y()-groupTracerText->top->pixelPosition().y())*0.85)); 1668 | 1669 | // add dispersion arrow: 1670 | QCPItemCurve *arrow = new QCPItemCurve(plot); 1671 | arrow->start->setCoords(1, -1.1); 1672 | arrow->startDir->setCoords(-1, -1.3); 1673 | arrow->endDir->setCoords(-5, -0.3); 1674 | arrow->end->setCoords(-10, -0.2); 1675 | arrow->setHead(QCPLineEnding::esSpikeArrow); 1676 | 1677 | // add the dispersion arrow label: 1678 | QCPItemText *dispersionText = new QCPItemText(plot); 1679 | dispersionText->position->setCoords(-6, -0.9); 1680 | dispersionText->setRotation(40); 1681 | dispersionText->setText("Dispersion with\nvp < vg"); 1682 | dispersionText->setFont(QFont(font().family(), 10)); 1683 | 1684 | // setup a timer that repeatedly calls MainWindow::bracketDataSlot: 1685 | // connect(&dataTimer, SIGNAL(timeout()), this, SLOT(bracketDataSlot())); 1686 | 1687 | QTimer *timer = new QTimer(); 1688 | connect(timer, &QTimer::timeout, 1689 | [=]() { 1690 | double secs = QCPAxisTickerDateTime::dateTimeToKey(QDateTime::currentDateTime()); 1691 | 1692 | // update data to make phase move: 1693 | int n = 500; 1694 | double phase = secs*5; 1695 | double k = 3; 1696 | QVector x(n), y(n); 1697 | for (int i=0; igraph()->setData(x, y); 1703 | 1704 | phaseTracer->setGraphKey((8*M_PI+fmod(M_PI*1.5-phase, 6*M_PI))/k); 1705 | 1706 | plot->replot(); 1707 | 1708 | // calculate frames per second: 1709 | double key = secs; 1710 | static double lastFpsKeyItem; 1711 | static int frameCountItem; 1712 | ++frameCountItem; 1713 | if (key-lastFpsKeyItem > 2) // average fps over 2 seconds 1714 | { 1715 | bar->showMessage( 1716 | QString("%1 FPS, Total Data points: %2") 1717 | .arg(frameCountItem/(key-lastFpsKeyItem), 0, 'f', 0) 1718 | .arg(plot->graph(0)->data()->size()) 1719 | , 0); 1720 | lastFpsKeyItem = key; 1721 | frameCountItem = 0; 1722 | } 1723 | } 1724 | ); 1725 | timer->start(0); // Interval 0 means to refresh as fast as possible 1726 | // dataTimer.start(0); // Interval 0 means to refresh as fast as possible 1727 | } 1728 | 1729 | void MainWindow::setupStyledDemo(int row, int col, bool openGl) 1730 | { 1731 | QWidget *widget = new QWidget(); 1732 | widget->setWindowTitle("Styled Demo"); 1733 | widget->setMinimumHeight(400); 1734 | widget->setMaximumHeight(400); 1735 | 1736 | QCustomPlot *plot = new QCustomPlot(); 1737 | plot->setOpenGl(openGl); 1738 | QStatusBar *bar = new QStatusBar(); 1739 | 1740 | QVBoxLayout *layout = new QVBoxLayout(); 1741 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 1742 | layout->addWidget(plot, 1); 1743 | layout->addWidget(bar, 0); 1744 | widget->setLayout(layout); 1745 | 1746 | _loGrid->addWidget(widget,row,col,1,1); 1747 | // demoName = "Styled Demo"; 1748 | 1749 | // prepare data: 1750 | QVector x1(20), y1(20); 1751 | QVector x2(100), y2(100); 1752 | QVector x3(20), y3(20); 1753 | QVector x4(20), y4(20); 1754 | for (int i=0; iaddGraph(); 1777 | graph1->setData(x1, y1); 1778 | graph1->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, QPen(Qt::black, 1.5), QBrush(Qt::white), 9)); 1779 | graph1->setPen(QPen(QColor(120, 120, 120), 2)); 1780 | 1781 | QCPGraph *graph2 = plot->addGraph(); 1782 | graph2->setData(x2, y2); 1783 | graph2->setPen(Qt::NoPen); 1784 | graph2->setBrush(QColor(200, 200, 200, 20)); 1785 | graph2->setChannelFillGraph(graph1); 1786 | 1787 | QCPBars *bars1 = new QCPBars(plot->xAxis, plot->yAxis); 1788 | bars1->setWidth(9/(double)x3.size()); 1789 | bars1->setData(x3, y3); 1790 | bars1->setPen(Qt::NoPen); 1791 | bars1->setBrush(QColor(10, 140, 70, 160)); 1792 | 1793 | QCPBars *bars2 = new QCPBars(plot->xAxis, plot->yAxis); 1794 | bars2->setWidth(9/(double)x4.size()); 1795 | bars2->setData(x4, y4); 1796 | bars2->setPen(Qt::NoPen); 1797 | bars2->setBrush(QColor(10, 100, 50, 70)); 1798 | bars2->moveAbove(bars1); 1799 | 1800 | // move bars above graphs and grid below bars: 1801 | plot->addLayer("abovemain", plot->layer("main"), QCustomPlot::limAbove); 1802 | plot->addLayer("belowmain", plot->layer("main"), QCustomPlot::limBelow); 1803 | graph1->setLayer("abovemain"); 1804 | plot->xAxis->grid()->setLayer("belowmain"); 1805 | plot->yAxis->grid()->setLayer("belowmain"); 1806 | 1807 | // set some pens, brushes and backgrounds: 1808 | plot->xAxis->setBasePen(QPen(Qt::white, 1)); 1809 | plot->yAxis->setBasePen(QPen(Qt::white, 1)); 1810 | plot->xAxis->setTickPen(QPen(Qt::white, 1)); 1811 | plot->yAxis->setTickPen(QPen(Qt::white, 1)); 1812 | plot->xAxis->setSubTickPen(QPen(Qt::white, 1)); 1813 | plot->yAxis->setSubTickPen(QPen(Qt::white, 1)); 1814 | plot->xAxis->setTickLabelColor(Qt::white); 1815 | plot->yAxis->setTickLabelColor(Qt::white); 1816 | plot->xAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine)); 1817 | plot->yAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine)); 1818 | plot->xAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine)); 1819 | plot->yAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine)); 1820 | plot->xAxis->grid()->setSubGridVisible(true); 1821 | plot->yAxis->grid()->setSubGridVisible(true); 1822 | plot->xAxis->grid()->setZeroLinePen(Qt::NoPen); 1823 | plot->yAxis->grid()->setZeroLinePen(Qt::NoPen); 1824 | plot->xAxis->setUpperEnding(QCPLineEnding::esSpikeArrow); 1825 | plot->yAxis->setUpperEnding(QCPLineEnding::esSpikeArrow); 1826 | QLinearGradient plotGradient; 1827 | plotGradient.setStart(0, 0); 1828 | plotGradient.setFinalStop(0, 350); 1829 | plotGradient.setColorAt(0, QColor(80, 80, 80)); 1830 | plotGradient.setColorAt(1, QColor(50, 50, 50)); 1831 | plot->setBackground(plotGradient); 1832 | QLinearGradient axisRectGradient; 1833 | axisRectGradient.setStart(0, 0); 1834 | axisRectGradient.setFinalStop(0, 350); 1835 | axisRectGradient.setColorAt(0, QColor(80, 80, 80)); 1836 | axisRectGradient.setColorAt(1, QColor(30, 30, 30)); 1837 | plot->axisRect()->setBackground(axisRectGradient); 1838 | 1839 | plot->rescaleAxes(); 1840 | plot->yAxis->setRange(0, 2); 1841 | 1842 | plot->replot(); 1843 | } 1844 | 1845 | void MainWindow::setupAdvancedAxesDemo(int row, int col, bool openGl) 1846 | { 1847 | QWidget *widget = new QWidget(); 1848 | widget->setWindowTitle("Advanced Axes Demo"); 1849 | widget->setMinimumHeight(400); 1850 | widget->setMaximumHeight(400); 1851 | 1852 | QCustomPlot *plot = new QCustomPlot(); 1853 | plot->setOpenGl(openGl); 1854 | QStatusBar *bar = new QStatusBar(); 1855 | 1856 | QVBoxLayout *layout = new QVBoxLayout(); 1857 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 1858 | layout->addWidget(plot, 1); 1859 | layout->addWidget(bar, 0); 1860 | widget->setLayout(layout); 1861 | 1862 | _loGrid->addWidget(widget,row,col,1,1); 1863 | // demoName = "Advanced Axes Demo"; 1864 | // configure axis rect: 1865 | plot->plotLayout()->clear(); // clear default axis rect so we can start from scratch 1866 | QCPAxisRect *wideAxisRect = new QCPAxisRect(plot); 1867 | wideAxisRect->setupFullAxesBox(true); 1868 | wideAxisRect->axis(QCPAxis::atRight, 0)->setTickLabels(true); 1869 | wideAxisRect->addAxis(QCPAxis::atLeft)->setTickLabelColor(QColor("#6050F8")); // add an extra axis on the left and color its numbers 1870 | QCPLayoutGrid *subLayout = new QCPLayoutGrid; 1871 | plot->plotLayout()->addElement(0, 0, wideAxisRect); // insert axis rect in first row 1872 | plot->plotLayout()->addElement(1, 0, subLayout); // sub layout in second row (grid layout will grow accordingly) 1873 | //customPlot->plotLayout()->setRowStretchFactor(1, 2); 1874 | // prepare axis rects that will be placed in the sublayout: 1875 | QCPAxisRect *subRectLeft = new QCPAxisRect(plot, false); // false means to not setup default axes 1876 | QCPAxisRect *subRectRight = new QCPAxisRect(plot, false); 1877 | subLayout->addElement(0, 0, subRectLeft); 1878 | subLayout->addElement(0, 1, subRectRight); 1879 | subRectRight->setMaximumSize(150, 150); // make bottom right axis rect size fixed 150x150 1880 | subRectRight->setMinimumSize(150, 150); // make bottom right axis rect size fixed 150x150 1881 | // setup axes in sub layout axis rects: 1882 | subRectLeft->addAxes(QCPAxis::atBottom | QCPAxis::atLeft); 1883 | subRectRight->addAxes(QCPAxis::atBottom | QCPAxis::atRight); 1884 | subRectLeft->axis(QCPAxis::atLeft)->ticker()->setTickCount(2); 1885 | subRectRight->axis(QCPAxis::atRight)->ticker()->setTickCount(2); 1886 | subRectRight->axis(QCPAxis::atBottom)->ticker()->setTickCount(2); 1887 | subRectLeft->axis(QCPAxis::atBottom)->grid()->setVisible(true); 1888 | // synchronize the left and right margins of the top and bottom axis rects: 1889 | QCPMarginGroup *marginGroup = new QCPMarginGroup(plot); 1890 | subRectLeft->setMarginGroup(QCP::msLeft, marginGroup); 1891 | subRectRight->setMarginGroup(QCP::msRight, marginGroup); 1892 | wideAxisRect->setMarginGroup(QCP::msLeft | QCP::msRight, marginGroup); 1893 | // move newly created axes on "axes" layer and grids on "grid" layer: 1894 | foreach (QCPAxisRect *rect, plot->axisRects()) 1895 | { 1896 | foreach (QCPAxis *axis, rect->axes()) 1897 | { 1898 | axis->setLayer("axes"); 1899 | axis->grid()->setLayer("grid"); 1900 | } 1901 | } 1902 | 1903 | // prepare data: 1904 | QVector dataCos(21), dataGauss(50), dataRandom(100); 1905 | QVector x3, y3; 1906 | qsrand(3); 1907 | for (int i=0; iaddGraph(wideAxisRect->axis(QCPAxis::atBottom), wideAxisRect->axis(QCPAxis::atLeft)); 1927 | mainGraphCos->data()->set(dataCos); 1928 | mainGraphCos->valueAxis()->setRange(-1, 1); 1929 | mainGraphCos->rescaleKeyAxis(); 1930 | mainGraphCos->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, QPen(Qt::black), QBrush(Qt::white), 6)); 1931 | mainGraphCos->setPen(QPen(QColor(120, 120, 120), 2)); 1932 | QCPGraph *mainGraphGauss = plot->addGraph(wideAxisRect->axis(QCPAxis::atBottom), wideAxisRect->axis(QCPAxis::atLeft, 1)); 1933 | mainGraphGauss->data()->set(dataGauss); 1934 | mainGraphGauss->setPen(QPen(QColor("#8070B8"), 2)); 1935 | mainGraphGauss->setBrush(QColor(110, 170, 110, 30)); 1936 | mainGraphCos->setChannelFillGraph(mainGraphGauss); 1937 | mainGraphCos->setBrush(QColor(255, 161, 0, 50)); 1938 | mainGraphGauss->valueAxis()->setRange(0, 1000); 1939 | mainGraphGauss->rescaleKeyAxis(); 1940 | 1941 | QCPGraph *subGraphRandom = plot->addGraph(subRectLeft->axis(QCPAxis::atBottom), subRectLeft->axis(QCPAxis::atLeft)); 1942 | subGraphRandom->data()->set(dataRandom); 1943 | subGraphRandom->setLineStyle(QCPGraph::lsImpulse); 1944 | subGraphRandom->setPen(QPen(QColor("#FFA100"), 1.5)); 1945 | subGraphRandom->rescaleAxes(); 1946 | 1947 | QCPBars *subBars = new QCPBars(subRectRight->axis(QCPAxis::atBottom), subRectRight->axis(QCPAxis::atRight)); 1948 | subBars->setWidth(3/(double)x3.size()); 1949 | subBars->setData(x3, y3); 1950 | subBars->setPen(QPen(Qt::black)); 1951 | subBars->setAntialiased(false); 1952 | subBars->setAntialiasedFill(false); 1953 | subBars->setBrush(QColor("#705BE8")); 1954 | subBars->keyAxis()->setSubTicks(false); 1955 | subBars->rescaleAxes(); 1956 | // setup a ticker for subBars key axis that only gives integer ticks: 1957 | QSharedPointer intTicker(new QCPAxisTickerFixed); 1958 | intTicker->setTickStep(1.0); 1959 | intTicker->setScaleStrategy(QCPAxisTickerFixed::ssMultiples); 1960 | subBars->keyAxis()->setTicker(intTicker); 1961 | 1962 | 1963 | plot->replot(); 1964 | } 1965 | 1966 | void MainWindow::setupColorMapDemo(int row, int col, bool openGl) 1967 | { 1968 | QWidget *widget = new QWidget(); 1969 | widget->setWindowTitle("Color Map Demo"); 1970 | widget->setMinimumHeight(400); 1971 | widget->setMaximumHeight(400); 1972 | 1973 | QCustomPlot *plot = new QCustomPlot(); 1974 | plot->setOpenGl(openGl); 1975 | QStatusBar *bar = new QStatusBar(); 1976 | 1977 | QVBoxLayout *layout = new QVBoxLayout(); 1978 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 1979 | layout->addWidget(plot, 1); 1980 | layout->addWidget(bar, 0); 1981 | widget->setLayout(layout); 1982 | 1983 | _loGrid->addWidget(widget,row,col,1,1); 1984 | // demoName = "Color Map Demo"; 1985 | 1986 | // configure axis rect: 1987 | plot->setInteractions(QCP::iRangeDrag|QCP::iRangeZoom); // this will also allow rescaling the color scale by dragging/zooming 1988 | plot->axisRect()->setupFullAxesBox(true); 1989 | plot->xAxis->setLabel("x"); 1990 | plot->yAxis->setLabel("y"); 1991 | 1992 | // set up the QCPColorMap: 1993 | QCPColorMap *colorMap = new QCPColorMap(plot->xAxis, plot->yAxis); 1994 | int nx = 200; 1995 | int ny = 200; 1996 | colorMap->data()->setSize(nx, ny); // we want the color map to have nx * ny data points 1997 | colorMap->data()->setRange(QCPRange(-4, 4), QCPRange(-4, 4)); // and span the coordinate range -4..4 in both key (x) and value (y) dimensions 1998 | // now we assign some data, by accessing the QCPColorMapData instance of the color map: 1999 | double x, y, z; 2000 | for (int xIndex=0; xIndexdata()->cellToCoord(xIndex, yIndex, &x, &y); 2005 | double r = 3*qSqrt(x*x+y*y)+1e-2; 2006 | z = 2*x*(qCos(r+2)/r-qSin(r+2)/r); // the B field strength of dipole radiation (modulo physical constants) 2007 | colorMap->data()->setCell(xIndex, yIndex, z); 2008 | } 2009 | } 2010 | 2011 | // add a color scale: 2012 | QCPColorScale *colorScale = new QCPColorScale(plot); 2013 | plot->plotLayout()->addElement(0, 1, colorScale); // add it to the right of the main axis rect 2014 | colorScale->setType(QCPAxis::atRight); // scale shall be vertical bar with tick/axis labels right (actually atRight is already the default) 2015 | colorMap->setColorScale(colorScale); // associate the color map with the color scale 2016 | colorScale->axis()->setLabel("Magnetic Field Strength"); 2017 | 2018 | // set the color gradient of the color map to one of the presets: 2019 | colorMap->setGradient(QCPColorGradient::gpPolar); 2020 | // we could have also created a QCPColorGradient instance and added own colors to 2021 | // the gradient, see the documentation of QCPColorGradient for what's possible. 2022 | 2023 | // rescale the data dimension (color) such that all data points lie in the span visualized by the color gradient: 2024 | colorMap->rescaleDataRange(); 2025 | 2026 | // make sure the axis rect and color scale synchronize their bottom and top margins (so they line up): 2027 | QCPMarginGroup *marginGroup = new QCPMarginGroup(plot); 2028 | plot->axisRect()->setMarginGroup(QCP::msBottom|QCP::msTop, marginGroup); 2029 | colorScale->setMarginGroup(QCP::msBottom|QCP::msTop, marginGroup); 2030 | 2031 | // rescale the key (x) and value (y) axes so the whole color map is visible: 2032 | plot->rescaleAxes(); 2033 | 2034 | plot->replot(); 2035 | } 2036 | 2037 | void MainWindow::setupFinancialDemo(int row, int col, bool openGl) 2038 | { 2039 | QWidget *widget = new QWidget(); 2040 | widget->setWindowTitle("Financial Charts Demo"); 2041 | widget->setMinimumHeight(400); 2042 | widget->setMaximumHeight(400); 2043 | 2044 | QCustomPlot *plot = new QCustomPlot(); 2045 | plot->setOpenGl(openGl); 2046 | QStatusBar *bar = new QStatusBar(); 2047 | 2048 | QVBoxLayout *layout = new QVBoxLayout(); 2049 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 2050 | layout->addWidget(plot, 1); 2051 | layout->addWidget(bar, 0); 2052 | widget->setLayout(layout); 2053 | 2054 | _loGrid->addWidget(widget,row,col,1,1); 2055 | plot->legend->setVisible(true); 2056 | 2057 | // generate two sets of random walk data (one for candlestick and one for ohlc chart): 2058 | int n = 500; 2059 | QVector time(n), value1(n), value2(n); 2060 | QDateTime start = QDateTime(QDate(2014, 6, 11)); 2061 | start.setTimeSpec(Qt::UTC); 2062 | double startTime = start.toTime_t(); 2063 | double binSize = 3600*24; // bin data in 1 day intervals 2064 | time[0] = startTime; 2065 | value1[0] = 60; 2066 | value2[0] = 20; 2067 | qsrand(9); 2068 | for (int i=1; ixAxis, plot->yAxis); 2077 | candlesticks->setName("Candlestick"); 2078 | candlesticks->setChartStyle(QCPFinancial::csCandlestick); 2079 | candlesticks->data()->set(QCPFinancial::timeSeriesToOhlc(time, value1, binSize, startTime)); 2080 | candlesticks->setWidth(binSize*0.9); 2081 | candlesticks->setTwoColored(true); 2082 | candlesticks->setBrushPositive(QColor(245, 245, 245)); 2083 | candlesticks->setBrushNegative(QColor(40, 40, 40)); 2084 | candlesticks->setPenPositive(QPen(QColor(0, 0, 0))); 2085 | candlesticks->setPenNegative(QPen(QColor(0, 0, 0))); 2086 | 2087 | // create ohlc chart: 2088 | QCPFinancial *ohlc = new QCPFinancial(plot->xAxis, plot->yAxis); 2089 | ohlc->setName("OHLC"); 2090 | ohlc->setChartStyle(QCPFinancial::csOhlc); 2091 | ohlc->data()->set(QCPFinancial::timeSeriesToOhlc(time, value2, binSize/3.0, startTime)); // divide binSize by 3 just to make the ohlc bars a bit denser 2092 | ohlc->setWidth(binSize*0.2); 2093 | ohlc->setTwoColored(true); 2094 | 2095 | // create bottom axis rect for volume bar chart: 2096 | QCPAxisRect *volumeAxisRect = new QCPAxisRect(plot); 2097 | plot->plotLayout()->addElement(1, 0, volumeAxisRect); 2098 | volumeAxisRect->setMaximumSize(QSize(QWIDGETSIZE_MAX, 100)); 2099 | volumeAxisRect->axis(QCPAxis::atBottom)->setLayer("axes"); 2100 | volumeAxisRect->axis(QCPAxis::atBottom)->grid()->setLayer("grid"); 2101 | // bring bottom and main axis rect closer together: 2102 | plot->plotLayout()->setRowSpacing(0); 2103 | volumeAxisRect->setAutoMargins(QCP::msLeft|QCP::msRight|QCP::msBottom); 2104 | volumeAxisRect->setMargins(QMargins(0, 0, 0, 0)); 2105 | // create two bar plottables, for positive (green) and negative (red) volume bars: 2106 | plot->setAutoAddPlottableToLegend(false); 2107 | QCPBars *volumePos = new QCPBars(volumeAxisRect->axis(QCPAxis::atBottom), volumeAxisRect->axis(QCPAxis::atLeft)); 2108 | QCPBars *volumeNeg = new QCPBars(volumeAxisRect->axis(QCPAxis::atBottom), volumeAxisRect->axis(QCPAxis::atLeft)); 2109 | for (int i=0; iaddData(startTime+3600*5.0*i, qAbs(v)); // add data to either volumeNeg or volumePos, depending on sign of v 2113 | } 2114 | volumePos->setWidth(3600*4); 2115 | volumePos->setPen(Qt::NoPen); 2116 | volumePos->setBrush(QColor(100, 180, 110)); 2117 | volumeNeg->setWidth(3600*4); 2118 | volumeNeg->setPen(Qt::NoPen); 2119 | volumeNeg->setBrush(QColor(180, 90, 90)); 2120 | 2121 | // interconnect x axis ranges of main and bottom axis rects: 2122 | connect(plot->xAxis, SIGNAL(rangeChanged(QCPRange)), volumeAxisRect->axis(QCPAxis::atBottom), SLOT(setRange(QCPRange))); 2123 | connect(volumeAxisRect->axis(QCPAxis::atBottom), SIGNAL(rangeChanged(QCPRange)), plot->xAxis, SLOT(setRange(QCPRange))); 2124 | // configure axes of both main and bottom axis rect: 2125 | QSharedPointer dateTimeTicker(new QCPAxisTickerDateTime); 2126 | dateTimeTicker->setDateTimeSpec(Qt::UTC); 2127 | dateTimeTicker->setDateTimeFormat("dd. MMMM"); 2128 | volumeAxisRect->axis(QCPAxis::atBottom)->setTicker(dateTimeTicker); 2129 | volumeAxisRect->axis(QCPAxis::atBottom)->setTickLabelRotation(15); 2130 | plot->xAxis->setBasePen(Qt::NoPen); 2131 | plot->xAxis->setTickLabels(false); 2132 | plot->xAxis->setTicks(false); // only want vertical grid in main axis rect, so hide xAxis backbone, ticks, and labels 2133 | plot->xAxis->setTicker(dateTimeTicker); 2134 | plot->rescaleAxes(); 2135 | plot->xAxis->scaleRange(1.025, plot->xAxis->range().center()); 2136 | plot->yAxis->scaleRange(1.1, plot->yAxis->range().center()); 2137 | 2138 | // make axis rects' left side line up: 2139 | QCPMarginGroup *group = new QCPMarginGroup(plot); 2140 | plot->axisRect()->setMarginGroup(QCP::msLeft|QCP::msRight, group); 2141 | volumeAxisRect->setMarginGroup(QCP::msLeft|QCP::msRight, group); 2142 | 2143 | plot->replot(); 2144 | } 2145 | 2146 | void MainWindow::setupAxisTagDemo(int row, int col, bool openGl) 2147 | { 2148 | QWidget *widget = new QWidget(); 2149 | widget->setWindowTitle("Axis Tag Demo"); 2150 | widget->setMinimumHeight(400); 2151 | widget->setMaximumHeight(400); 2152 | 2153 | QCustomPlot *plot = new QCustomPlot(); 2154 | plot->setOpenGl(openGl); 2155 | QStatusBar *bar = new QStatusBar(); 2156 | 2157 | QVBoxLayout *layout = new QVBoxLayout(); 2158 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 2159 | layout->addWidget(plot, 1); 2160 | layout->addWidget(bar, 0); 2161 | widget->setLayout(layout); 2162 | 2163 | _loGrid->addWidget(widget,row,col,1,1); 2164 | 2165 | // configure plot to have two right axes: 2166 | plot->yAxis->setTickLabels(false); 2167 | connect(plot->yAxis2, SIGNAL(rangeChanged(QCPRange)), plot->yAxis, SLOT(setRange(QCPRange))); // left axis only mirrors inner right axis 2168 | plot->yAxis2->setVisible(true); 2169 | plot->axisRect()->addAxis(QCPAxis::atRight); 2170 | plot->axisRect()->axis(QCPAxis::atRight, 0)->setPadding(30); // add some padding to have space for tags 2171 | plot->axisRect()->axis(QCPAxis::atRight, 1)->setPadding(30); // add some padding to have space for tags 2172 | 2173 | // create graphs: 2174 | QPointer mGraph1 = plot->addGraph(plot->xAxis, plot->axisRect()->axis(QCPAxis::atRight, 0)); 2175 | QPointer mGraph2 = plot->addGraph(plot->xAxis, plot->axisRect()->axis(QCPAxis::atRight, 1)); 2176 | mGraph1->setPen(QPen(QColor(250, 120, 0))); 2177 | mGraph2->setPen(QPen(QColor(0, 180, 60))); 2178 | 2179 | // create tags with newly introduced AxisTag class (see axistag.h/.cpp): 2180 | AxisTag *mTag1 = new AxisTag(mGraph1->valueAxis()); 2181 | mTag1->setPen(mGraph1->pen()); 2182 | AxisTag *mTag2 = new AxisTag(mGraph2->valueAxis()); 2183 | mTag2->setPen(mGraph2->pen()); 2184 | 2185 | // connect(&mDataTimer, SIGNAL(timeout()), this, SLOT(timerSlot())); 2186 | // mDataTimer.start(40); 2187 | 2188 | QTimer *timer = new QTimer(); 2189 | connect(timer, &QTimer::timeout, 2190 | [=]() { 2191 | 2192 | mGraph1->addData(mGraph1->dataCount(), qSin(mGraph1->dataCount()/50.0)+qSin(mGraph1->dataCount()/50.0/0.3843)*0.25); 2193 | mGraph2->addData(mGraph2->dataCount(), qCos(mGraph2->dataCount()/50.0)+qSin(mGraph2->dataCount()/50.0/0.4364)*0.15); 2194 | 2195 | // make key axis range scroll with the data: 2196 | plot->xAxis->rescale(); 2197 | mGraph1->rescaleValueAxis(false, true); 2198 | mGraph2->rescaleValueAxis(false, true); 2199 | plot->xAxis->setRange(plot->xAxis->range().upper, 100, Qt::AlignRight); 2200 | 2201 | // update the vertical axis tag positions and texts to match the rightmost data point of the graphs: 2202 | double graph1Value = mGraph1->dataMainValue(mGraph1->dataCount()-1); 2203 | double graph2Value = mGraph2->dataMainValue(mGraph2->dataCount()-1); 2204 | mTag1->updatePosition(graph1Value); 2205 | mTag2->updatePosition(graph2Value); 2206 | mTag1->setText(QString::number(graph1Value, 'f', 2)); 2207 | mTag2->setText(QString::number(graph2Value, 'f', 2)); 2208 | 2209 | plot->replot(); 2210 | } 2211 | ); 2212 | timer->start(40); 2213 | } 2214 | 2215 | void MainWindow::setupHistoryDemo(int row, int col, bool openGl) 2216 | { 2217 | QWidget *widget = new QWidget(); 2218 | widget->setWindowTitle("Waterfall Demo"); 2219 | widget->setMinimumHeight(400); 2220 | widget->setMaximumHeight(400); 2221 | 2222 | QCustomPlot *plot = new QCustomPlot(); 2223 | plot->setOpenGl(openGl); 2224 | QStatusBar *bar = new QStatusBar(); 2225 | 2226 | QVBoxLayout *layout = new QVBoxLayout(); 2227 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 2228 | layout->addWidget(plot, 1); 2229 | layout->addWidget(bar, 0); 2230 | widget->setLayout(layout); 2231 | 2232 | _loGrid->addWidget(widget,row,col,1,1); 2233 | 2234 | plot->axisRect()->insetLayout()->setMargins(QMargins(0,0,0,0)); 2235 | 2236 | int nbCurves = 40; 2237 | qreal axisRectWidth = 0.7; 2238 | qreal axisRectHeight = 0.5; 2239 | 2240 | qreal axisRectPosX = 1-axisRectWidth; 2241 | qreal axisRectPosY = 0.0; 2242 | 2243 | qreal dX = -1*(1-axisRectWidth) / (nbCurves -1); 2244 | qreal dY = (1-axisRectHeight) / (nbCurves -1); 2245 | 2246 | plot->yAxis->setVisible(false); 2247 | plot->xAxis->setVisible(false); 2248 | 2249 | 2250 | for(int i=nbCurves-1; i>=0; i--) { 2251 | 2252 | QCPAxisRect *axisRect = new QCPAxisRect(plot); 2253 | axisRect->setMargins(QMargins(0,0,0,0)); 2254 | QRectF posRect(axisRectPosX,axisRectPosY,axisRectWidth,axisRectHeight); 2255 | axisRectPosX += dX; 2256 | axisRectPosY += dY; 2257 | plot->axisRect()->insetLayout()->addElement(axisRect, posRect); 2258 | 2259 | QCPGraph *graph; 2260 | 2261 | if(i != nbCurves -1) { 2262 | graph = plot->addGraph(axisRect->axis(QCPAxis::atBottom), axisRect->axis(QCPAxis::atLeft)); 2263 | graph->setPen(QPen(QColor(0,0,255, 150 - (100*double(i)/double(nbCurves))))); 2264 | graph->setBrush(QBrush(Qt::white)); 2265 | axisRect->axis(QCPAxis::atBottom)->setRange(-18,20); 2266 | axisRect->axis(QCPAxis::atLeft)->setRange(-0.1,3); 2267 | axisRect->axis(QCPAxis::atBottom)->grid()->setZeroLinePen(Qt::NoPen); 2268 | axisRect->axis(QCPAxis::atLeft)->grid()->setZeroLinePen(Qt::NoPen); 2269 | } else { 2270 | 2271 | graph = plot->addGraph(axisRect->axis(QCPAxis::atTop), axisRect->axis(QCPAxis::atRight)); 2272 | graph->setPen(QPen(QColor(0,0,255, 150 - (100*double(i)/double(nbCurves))))); 2273 | graph->setBrush(QBrush(Qt::white)); 2274 | axisRect->axis(QCPAxis::atTop)->setRange(-18,20); 2275 | axisRect->axis(QCPAxis::atRight)->setRange(-0.1,3); 2276 | axisRect->axis(QCPAxis::atBottom)->setRange(-18,20); 2277 | axisRect->axis(QCPAxis::atLeft)->setRange(-0.1,3); 2278 | 2279 | axisRect->axis(QCPAxis::atBottom)->grid()->setZeroLinePen(Qt::NoPen); 2280 | axisRect->axis(QCPAxis::atLeft)->grid()->setZeroLinePen(Qt::NoPen); 2281 | axisRect->axis(QCPAxis::atTop)->setVisible(true); 2282 | axisRect->axis(QCPAxis::atRight)->setVisible(true); 2283 | axisRect->axis(QCPAxis::atTop)->setTickLabelSide(QCPAxis::lsInside); 2284 | axisRect->axis(QCPAxis::atRight)->setVisible(true); 2285 | axisRect->axis(QCPAxis::atRight)->setTickLabelSide(QCPAxis::lsInside); 2286 | 2287 | 2288 | axisRect->axis(QCPAxis::atTop)->grid()->setVisible(true); 2289 | axisRect->axis(QCPAxis::atRight)->grid()->setVisible(true); 2290 | } 2291 | 2292 | if(i==0) { 2293 | graph->setPen(QPen(QColor(0,0,255))); 2294 | axisRect->axis(QCPAxis::atBottom)->grid()->setVisible(false); 2295 | axisRect->axis(QCPAxis::atLeft)->grid()->setVisible(false); 2296 | axisRect->axis(QCPAxis::atBottom)->setVisible(true); 2297 | axisRect->axis(QCPAxis::atLeft)->setTickLabelSide(QCPAxis::lsInside); 2298 | axisRect->axis(QCPAxis::atBottom)->setTickLabelSide(QCPAxis::lsInside); 2299 | } 2300 | 2301 | if(i > 0 ) { 2302 | axisRect->axis(QCPAxis::atBottom)->setVisible(false); 2303 | axisRect->axis(QCPAxis::atLeft)->setVisible(false); 2304 | } 2305 | 2306 | } 2307 | 2308 | QTimer *timer = new QTimer(); 2309 | connect(timer, &QTimer::timeout, 2310 | [=]() { 2311 | 2312 | double secs = QCPAxisTickerDateTime::dateTimeToKey(QDateTime::currentDateTime()); 2313 | int n = 500; 2314 | double phase = secs*5; 2315 | double k = 3; 2316 | QVector x(n), y(n); 2317 | // plot->graph(40)->data().data()->clear(); 2318 | for (int i=0; ibounded(3.0) * qAbs(qExp(-x[i]*QRandomGenerator::global()->bounded(100.0)*x[i]/20.0)*qSin(k*x[i]+phase)); 2322 | } 2323 | 2324 | for(int j=0; jgraph(j)->data()->set(*plot->graph(j+1)->data()); 2326 | } 2327 | 2328 | plot->graph(nbCurves-1)->setData(x, y); 2329 | 2330 | plot->replot(); 2331 | } 2332 | 2333 | ); 2334 | 2335 | timer->start(250); 2336 | 2337 | } 2338 | 2339 | void MainWindow::setupBitFieldDemo(int row, int col, bool openGl) 2340 | { 2341 | QWidget *widget = new QWidget(); 2342 | widget->setWindowTitle("Bitfields Demo"); 2343 | widget->setMinimumHeight(400); 2344 | widget->setMaximumHeight(400); 2345 | 2346 | QCustomPlot *plot = new QCustomPlot(); 2347 | plot->setOpenGl(openGl); 2348 | QStatusBar *bar = new QStatusBar(); 2349 | 2350 | QVBoxLayout *layout = new QVBoxLayout(); 2351 | layout->addWidget(new QLabel(widget->windowTitle()), 0); 2352 | layout->addWidget(plot, 1); 2353 | layout->addWidget(bar, 0); 2354 | widget->setLayout(layout); 2355 | 2356 | _loGrid->addWidget(widget,row,col,1,1); 2357 | 2358 | QCPTextElement *textValue = new QCPTextElement(plot); 2359 | QCPLayoutGrid *subLayout = new QCPLayoutGrid; 2360 | subLayout->setRowSpacing(0); 2361 | 2362 | plot->plotLayout()->clear(); 2363 | plot->plotLayout()->addElement(0, 0, textValue); // insert axis rect in first row 2364 | plot->plotLayout()->addElement(1, 0, subLayout); 2365 | 2366 | QCPMarginGroup *marginGroup = new QCPMarginGroup(plot); 2367 | for(int i=0; i<16; i++) { 2368 | QCPAxisRect *leftRect = new QCPAxisRect(plot); 2369 | leftRect->setMinimumSize(10, 10); 2370 | QCPAxisRect *rightRect = new QCPAxisRect(plot); 2371 | rightRect->setMinimumSize(10, 10); 2372 | 2373 | subLayout->addElement(i, 0, leftRect); 2374 | subLayout->addElement(i, 1, rightRect); 2375 | 2376 | leftRect->setMarginGroup(QCP::msLeft, marginGroup); 2377 | rightRect->setMarginGroup(QCP::msRight, marginGroup); 2378 | 2379 | QCPGraph *leftGraph = plot->addGraph(leftRect->axis(QCPAxis::atBottom), leftRect->axis(QCPAxis::atLeft)); 2380 | leftGraph->valueAxis()->setRange(0, 1); 2381 | leftGraph->keyAxis()->setVisible(false); 2382 | leftGraph->valueAxis()->setTicks(false); 2383 | leftGraph->valueAxis()->setTickLabels(false); 2384 | leftGraph->valueAxis()->grid()->setVisible(false); 2385 | leftGraph->valueAxis()->setLabel(QString::number(i)); 2386 | leftGraph->setPen(Qt::NoPen); 2387 | leftGraph->setBrush(Qt::red); 2388 | leftGraph->setLineStyle(QCPGraph::lsStepRight); 2389 | QCPGraph *rightGraph = plot->addGraph(rightRect->axis(QCPAxis::atBottom), rightRect->axis(QCPAxis::atLeft)); 2390 | rightGraph->valueAxis()->setRange(0, 1); 2391 | rightGraph->keyAxis()->setVisible(false); 2392 | rightGraph->valueAxis()->setTicks(false); 2393 | rightGraph->valueAxis()->setTickLabels(false); 2394 | rightGraph->valueAxis()->grid()->setVisible(false); 2395 | rightGraph->valueAxis()->setLabel(QString::number(16+i)); 2396 | rightGraph->setPen(Qt::NoPen); 2397 | rightGraph->setBrush(Qt::red); 2398 | rightGraph->setLineStyle(QCPGraph::lsStepLeft); 2399 | } 2400 | 2401 | QTimer *timer = new QTimer(); 2402 | connect(timer, &QTimer::timeout, 2403 | [=]() { 2404 | double secs = QCPAxisTickerDateTime::dateTimeToKey(QDateTime::currentDateTime()); 2405 | static quint32 value = 0; 2406 | textValue->setText(QString::number(value) + QString(" - ") + QString::number( value, 16 )); 2407 | std::bitset<32> bits(value); 2408 | 2409 | for (std::size_t i = 0; i < bits.size(); ++i) { 2410 | 2411 | QCPAxisRect *ar = qobject_cast(subLayout->element(i%16,i/16)); 2412 | if(ar) { 2413 | if(bits[i]) 2414 | ar->graphs().at(0)->addData(secs, 1); 2415 | else 2416 | ar->graphs().at(0)->addData(secs, 0); 2417 | 2418 | ar->graphs().at(0)->data()->removeBefore(secs-10); 2419 | ar->graphs().at(0)->keyAxis()->rescale(); 2420 | } 2421 | } 2422 | value++; 2423 | plot->replot(); 2424 | 2425 | } 2426 | ); 2427 | timer->start(100); 2428 | 2429 | 2430 | } 2431 | 2432 | void MainWindow::setupPlayground(QCustomPlot *customPlot) 2433 | { 2434 | Q_UNUSED(customPlot) 2435 | } 2436 | 2437 | MainWindow::~MainWindow() 2438 | { 2439 | delete ui; 2440 | } 2441 | -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | ** ** 3 | ** QCustomPlot, an easy to use, modern plotting widget for Qt ** 4 | ** Copyright (C) 2011-2018 Emanuel Eichhammer ** 5 | ** ** 6 | ** This program is free software: you can redistribute it and/or modify ** 7 | ** it under the terms of the GNU General Public License as published by ** 8 | ** the Free Software Foundation, either version 3 of the License, or ** 9 | ** (at your option) any later version. ** 10 | ** ** 11 | ** This program is distributed in the hope that it will be useful, ** 12 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** 13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** 14 | ** GNU General Public License for more details. ** 15 | ** ** 16 | ** You should have received a copy of the GNU General Public License ** 17 | ** along with this program. If not, see http://www.gnu.org/licenses/. ** 18 | ** ** 19 | **************************************************************************** 20 | ** Author: Emanuel Eichhammer ** 21 | ** Website/Contact: http://www.qcustomplot.com/ ** 22 | ** Date: 25.06.18 ** 23 | ** Version: 2.0.1 ** 24 | ****************************************************************************/ 25 | 26 | /************************************************************************************************************ 27 | ** ** 28 | ** This is the example code for QCustomPlot. ** 29 | ** ** 30 | ** It demonstrates basic and some advanced capabilities of the widget. The interesting code is inside ** 31 | ** the "setup(...)Demo" functions of MainWindow. ** 32 | ** ** 33 | ** In order to see a demo in action, call the respective "setup(...)Demo" function inside the ** 34 | ** MainWindow constructor. Alternatively you may call setupDemo(i) where i is the index of the demo ** 35 | ** you want (for those, see MainWindow constructor comments). All other functions here are merely a ** 36 | ** way to easily create screenshots of all demos for the website. I.e. a timer is set to successively ** 37 | ** setup all the demos and make a screenshot of the window area and save it in the ./screenshots ** 38 | ** directory. ** 39 | ** ** 40 | *************************************************************************************************************/ 41 | 42 | #ifndef MAINWINDOW_H 43 | #define MAINWINDOW_H 44 | 45 | #include 46 | #include 47 | #include "qcustomplot.h" // the header file of QCustomPlot. Don't forget to add it to your project, if you use an IDE, so it gets compiled. 48 | #include "axistag.h" 49 | 50 | namespace Ui { 51 | class MainWindow; 52 | } 53 | 54 | class MainWindow : public QMainWindow 55 | { 56 | Q_OBJECT 57 | 58 | public: 59 | explicit MainWindow(QWidget *parent = nullptr); 60 | ~MainWindow(); 61 | 62 | void setupDemo(bool openGl); 63 | void setupQuadraticDemo(int row, int col, bool openGl); 64 | void setupSimpleDemo(int row, int col, bool openGl); 65 | void setupSincScatterDemo(int row, int col, bool openGl); 66 | void setupScatterStyleDemo(int row, int col, bool openGl); 67 | void setupLineStyleDemo(int row, int col, bool openGl); 68 | void setupScatterPixmapDemo(int row, int col, bool openGl); 69 | void setupDateDemo(int row, int col, bool openGl); 70 | void setupTextureBrushDemo(int row, int col, bool openGl); 71 | void setupMultiAxisDemo(int row, int col, bool openGl); 72 | void setupLogarithmicDemo(int row, int col, bool openGl); 73 | void setupRealtimeDataDemo(int row, int col, bool openGl); 74 | void setupRealtimeThresholdDemo(int row, int col, bool openGl); 75 | void setupRealtimeBrushDemo(int row, int col, bool openGl); 76 | void setupRealtimeEcgDemo(int row, int col, bool openGl); 77 | void setupParametricCurveDemo(int row, int col, bool openGl); 78 | void setupBarChartDemo(int row, int col, bool openGl); 79 | void setupStatisticalDemo(int row, int col, bool openGl); 80 | void setupSimpleItemDemo(int row, int col, bool openGl); 81 | void setupItemDemo(int row, int col, bool openGl); 82 | void setupStyledDemo(int row, int col, bool openGl); 83 | void setupAdvancedAxesDemo(int row, int col, bool openGl); 84 | void setupColorMapDemo(int row, int col, bool openGl); 85 | void setupFinancialDemo(int row, int col, bool openGl); 86 | void setupAxisTagDemo(int row, int col, bool openGl); 87 | void setupHistoryDemo(int row, int col, bool openGl); 88 | void setupBitFieldDemo(int row, int col, bool openGl); 89 | void setupPlayground(QCustomPlot *customPlot); 90 | 91 | private slots: 92 | 93 | private: 94 | Ui::MainWindow *ui; 95 | QGridLayout *_loGrid; 96 | }; 97 | 98 | #endif // MAINWINDOW_H 99 | -------------------------------------------------------------------------------- /mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 713 10 | 592 11 | 12 | 13 | 14 | QCustomPlot plot examples 15 | 16 | 17 | 18 | 19 | 20 | 21 | true 22 | 23 | 24 | 25 | 26 | 0 27 | 0 28 | 693 29 | 572 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /plot-examples.pro: -------------------------------------------------------------------------------- 1 | # 2 | # QCustomPlot Plot Examples 3 | # 4 | 5 | QT += core gui 6 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport 7 | 8 | CONFIG += c++11 9 | DEFINES += QCUSTOMPLOT_USE_OPENGL 10 | 11 | TARGET = plot-examples 12 | TEMPLATE = app 13 | 14 | SOURCES += main.cpp\ 15 | mainwindow.cpp \ 16 | qcustomplot.cpp \ 17 | axistag.cpp 18 | 19 | HEADERS += mainwindow.h \ 20 | qcustomplot.h \ 21 | axistag.h 22 | 23 | FORMS += mainwindow.ui 24 | 25 | RESOURCES += \ 26 | images.qrc 27 | 28 | -------------------------------------------------------------------------------- /qcpex.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrnSlr/QCPExamplesCollection/e5c34a3ca27237b77088d7148b82e27e5844a5a2/qcpex.gif -------------------------------------------------------------------------------- /solarpanels.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrnSlr/QCPExamplesCollection/e5c34a3ca27237b77088d7148b82e27e5844a5a2/solarpanels.jpg -------------------------------------------------------------------------------- /sun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrnSlr/QCPExamplesCollection/e5c34a3ca27237b77088d7148b82e27e5844a5a2/sun.png --------------------------------------------------------------------------------