/** \example test_multiplot.cpp * JKQTPlotter: Examples: Laying out Several Plots * * \ref JKQTPlotterMultiPlotLayout */ #include #include "jkqtplotter/jkqtplotter.h" #include "jkqtplotter/graphs/jkqtpscatter.h" #include "jkqtplotter/graphs/jkqtpparsedfunction.h" #include "jkqtplotter/graphs/jkqtpbarchart.h" #include #include #include "test_multiplot_ui.h" int main(int argc, char* argv[]) { QApplication app(argc, argv); // 1. create a widget QWidget mainWidget; mainWidget.setWindowTitle("JKQTPlotter(s) in a QGridLayout"); // 2. Create a QGridLayout for the plots and add it to the widget. QGridLayout* layout=new QGridLayout(); mainWidget.setLayout(layout); // 3.1 create a main plotter widget and add it to the layout JKQTPlotter* plotMain=new JKQTPlotter(&mainWidget); layout->addWidget(plotMain, 0,0); JKQTPDatastore* ds=plotMain->getDatastore(); // 3.2 create a second and third plotter widget and add them to the // layout below and at the bottom right of the plotMain. // Also configure it to use the same datastore as plotMain JKQTPlotter* plotResid=new JKQTPlotter(false, &mainWidget, ds); layout->addWidget(plotResid, 1,0); JKQTPlotter* plotResidHist=new JKQTPlotter(false, &mainWidget, ds); layout->addWidget(plotResidHist, 1,1); // 3.3 synchronize width/x-axis of plotResid to width/x-axis of plotMain plotResid->synchronizeToMaster(plotMain, JKQTBasePlotter::sdXAxis, true, true, true); // 3.4 synchronize y-axis of width/plotResidHist to y-axis of width/plotResid plotResidHist->synchronizeToMaster(plotResid, JKQTBasePlotter::sdYAxis, true, true, true); // 3.5 ensure that the plot are printed/exported in whole, when printing in plotMain plotMain->getPlotter()->setGridPrinting(true); plotMain->getPlotter()->addGridPrintingPlotter(0,1,plotResid->getPlotter()); plotMain->getPlotter()->addGridPrintingPlotter(1,1,plotResidHist->getPlotter()); // 3.6 set relative sizes of the plots via the layout (small plots have 1/3 the width and height of the large plot layout->setRowStretch(0,3); layout->setRowStretch(1,1); layout->setColumnStretch(0,3); layout->setColumnStretch(1,1); // 4. now we create some (artificial) data: // - in plotMain we show an exponential curve and and some datapoints // - in plotResid we show the residuals, i.e. the difference between the curve and the datapoints // - in plotResidHist we will show a histogram of the residuals (calculated in histogram) std::random_device rd; std::mt19937 gen(rd()); std::normal_distribution<> d(0,0.5); std::vector dataX, dataY, dataRY; std::map histogram; const int Ndata=60; for(int n=0; n(Ndata)*static_cast(n)-0.5; const double y=2.0*(1.0+cos(x)); const double yd=y+d(gen); dataX.push_back(x); dataY.push_back(yd); dataRY.push_back(y-yd); // calculate a simple type of histogram in a std:map, bins are 1/4=0.25 wide const double hbin=std::round((y-yd)*4.0)/4.0; if (histogram.find(hbin)==histogram.end()) { histogram[hbin]=0; } else { histogram[hbin]++; } } // 5. and add the data to the datastore size_t cX=ds->addCopiedColumn(dataX, "dataX"); size_t cY=ds->addCopiedColumn(dataY, "dataY"); size_t cRY=ds->addCopiedColumn(dataRY, "residY"); std::pair cH=ds->addCopiedMap(histogram, "histX", "histY"); // 5.1 plot of the data JKQTPXYLineGraph* graphD=new JKQTPXYLineGraph(plotMain); graphD->setXColumn(cX); graphD->setYColumn(cY); graphD->setDrawLine(false); graphD->setSymbolType(JKQTPCross); graphD->setSymbolSize(10); graphD->setTitle("measurement data"); plotMain->addGraph(graphD); // 5.2 plot of the graph as an interpreted function, set as string "2*(1+cos(x))" JKQTPXParsedFunctionLineGraph* graphFit=new JKQTPXParsedFunctionLineGraph(plotMain); graphFit->setFunction("2*(1+cos(x))"); graphFit->setTitle("fit"); plotMain->addGraph(graphFit); // 5.3 residuals plot JKQTPXYLineGraph* graphResid=new JKQTPXYLineGraph(plotResid); graphResid->setXColumn(cX); graphResid->setYColumn(cRY); graphResid->setDrawLine(false); graphResid->setSymbolType(JKQTPPlus); graphResid->setSymbolSize(10); graphResid->setDrawLine(true); graphResid->setLineWidth(0.5); graphResid->setTitle("residuals"); plotResid->addGraph(graphResid); // 5.3 residual histogram plot JKQTPBarHorizontalGraph* graphResidHist=new JKQTPBarHorizontalGraph(plotResidHist); graphResidHist->setXColumn(cH.second); graphResidHist->setYColumn(cH.first); graphResidHist->setTitle("histogram"); plotResidHist->addGraph(graphResidHist); // 6.1 axis labels, distributed over the several plots plotMain->getYAxis()->setAxisLabel("y axis"); plotResid->getXAxis()->setAxisLabel("x axis"); plotResid->getYAxis()->setAxisLabel("residuals"); plotResidHist->getXAxis()->setAxisLabel("frequency"); // 6.2 switch off the tick labels on the axes that directly face another plot plotMain->getXAxis()->setDrawMode1(JKQTPCADMLineTicks); plotResidHist->getYAxis()->setDrawMode1(JKQTPCADMLineTicks); // 6.3 show tick labels on the rhs y-axis of the residual histogram plot plotResidHist->getYAxis()->setDrawMode2(JKQTPCADMLineTicksTickLabels); // 6.4 hide keys in all plots but the main plot plotResid->getPlotter()->setShowKey(false); plotResidHist->getPlotter()->setShowKey(false); // 6.5 hide position label and toolbars in the plots except main plot plotResid->setToolbarEnabled(false); plotResid->setMousePositionShown(false); plotResidHist->setToolbarEnabled(false); plotResidHist->setMousePositionShown(false); plotMain->setToolbarEnabled(true); // 7. scale plots automatically to data plotResidHist->setAbsoluteX(0, 20); plotResid->zoomToFit(); plotResidHist->zoomToFit(); plotMain->zoomToFit(); // 8. show plotter and make it a decent size mainWidget.show(); mainWidget.move(32,32); mainWidget.resize(800,600); // 9. create a second window, which controls the synchronization and layout between the plots TestMultiplotUI controlWindow(plotMain, plotResid, plotResidHist, layout); controlWindow.move(850,32); controlWindow.show(); return app.exec(); }