2019-01-20 23:15:10 +08:00
|
|
|
/** \example test_distributionplot.cpp
|
|
|
|
* Shows how to draw statistical values and their distribution with JKQTPlotter
|
|
|
|
*
|
|
|
|
* \ref JKQTPlotterDistributionPlot
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <QApplication>
|
|
|
|
#include "jkqtplotter/jkqtplotter.h"
|
2019-04-22 19:27:50 +08:00
|
|
|
#include "jkqtplotter/jkqtpgraphsscatter.h"
|
2019-01-20 23:15:10 +08:00
|
|
|
#include "jkqtplotter/jkqtpgraphsboxplot.h"
|
|
|
|
#include "jkqtplotter/jkqtpgraphsbarchart.h"
|
|
|
|
#include "jkqtplotter/jkqtpgraphssinglecolumnsymbols.h"
|
|
|
|
#include "jkqtplotter/jkqtpgraphsevaluatedfunction.h"
|
2019-01-26 02:24:19 +08:00
|
|
|
#include <map>
|
|
|
|
#include <random>
|
|
|
|
#include <cmath>
|
2019-01-20 23:15:10 +08:00
|
|
|
|
|
|
|
int main(int argc, char* argv[])
|
|
|
|
{
|
|
|
|
QApplication app(argc, argv);
|
|
|
|
|
|
|
|
// 1. create a plotter window and get a pointer to the internal datastore (for convenience)
|
|
|
|
JKQTPlotter plot;
|
2019-01-26 03:16:04 +08:00
|
|
|
plot.getPlotter()->setUseAntiAliasingForGraphs(true); // nicer (but slower) plotting
|
|
|
|
plot.getPlotter()->setUseAntiAliasingForSystem(true); // nicer (but slower) plotting
|
|
|
|
plot.getPlotter()->setUseAntiAliasingForText(true); // nicer (but slower) text rendering
|
2019-01-20 23:15:10 +08:00
|
|
|
JKQTPDatastore* ds=plot.getDatastore();
|
|
|
|
|
|
|
|
// 2. now we create random values drawn from a gaussian distribution
|
|
|
|
QVector<double> RANDVAL; // will store the values themselves
|
|
|
|
std::map<int, double> hist; // is used to calculate the histogram of the data
|
|
|
|
for (int i=-5; i<=15; i++) hist[i]=0;
|
|
|
|
|
|
|
|
std::random_device rd; // random number generators:
|
|
|
|
std::mt19937 gen{rd()};
|
|
|
|
|
|
|
|
// draw 301 random values from a gaussian distribution around 5 with width 3
|
|
|
|
const double th_mean=5;
|
|
|
|
const double th_std=3;
|
|
|
|
std::normal_distribution<> d{th_mean,th_std};
|
|
|
|
size_t NDATA=301;
|
|
|
|
double sum=0;
|
|
|
|
double square_sum=0;
|
|
|
|
for (size_t i=0; i<NDATA; i++) {
|
|
|
|
const double v=d(gen);
|
|
|
|
RANDVAL<<v; // store data
|
|
|
|
++hist[std::round(v)]; // calculate histogram
|
|
|
|
// accumulate data for statistics:
|
|
|
|
sum+=v;
|
|
|
|
square_sum+=(v*v);
|
|
|
|
}
|
|
|
|
// normalize histogram
|
|
|
|
for (auto& hi: hist) {
|
|
|
|
hi.second=hi.second/static_cast<double>(NDATA);
|
|
|
|
}
|
|
|
|
// sort random data in order to calculate the statistical properties:
|
|
|
|
qSort(RANDVAL);
|
|
|
|
const double rndMean=sum/static_cast<double>(NDATA);
|
|
|
|
const double rndMin=RANDVAL.first();
|
|
|
|
const double rndMax=RANDVAL.last();
|
|
|
|
const double rndMedian=RANDVAL[RANDVAL.size()/2];
|
|
|
|
const double rndQ25=RANDVAL[RANDVAL.size()/4];
|
|
|
|
const double rndQ75=RANDVAL[RANDVAL.size()*3/4];
|
2019-05-11 21:56:11 +08:00
|
|
|
const double rndMedianConfidence=2.0*1.57*fabs(rndQ75-rndQ25)/sqrt(static_cast<double>(NDATA));
|
2019-01-20 23:15:10 +08:00
|
|
|
|
|
|
|
// 3. make data available to JKQTPlotter by adding it to the internal datastore.
|
|
|
|
size_t columnRANDVAL=ds->addCopiedColumn(RANDVAL, "RANDVAL"); // copy random values
|
|
|
|
std::pair<size_t,size_t> columnHIST = ds->addCopiedMap(hist, "HIST_X", "HIST_Y"); // copy histogram
|
|
|
|
|
|
|
|
|
|
|
|
// 4. create a graph of horizontal boxplots:
|
|
|
|
JKQTPSingleColumnSymbolsGraph* graphRANDVALS=new JKQTPSingleColumnSymbolsGraph(&plot);
|
2019-01-26 20:00:40 +08:00
|
|
|
graphRANDVALS->setDataColumn(columnRANDVAL);
|
2019-01-20 23:15:10 +08:00
|
|
|
// draw data as symbols at (x,y)=(data,-0.07):
|
2019-01-26 20:00:40 +08:00
|
|
|
graphRANDVALS->setDataDirection(JKQTPSingleColumnSymbolsGraph::DataDirection::X);
|
|
|
|
graphRANDVALS->setPosition(-0.07);
|
2019-01-20 23:15:10 +08:00
|
|
|
// data should scatter around position=-0.07 with a width=0.08 (i.e. from position-width/2 ... position+width/2)
|
2019-01-26 20:00:40 +08:00
|
|
|
//graphRANDVALS->setWidth(0.08);
|
|
|
|
//graphRANDVALS->setPositionScatterStyle(JKQTPSingleColumnSymbolsGraph::RandomScatter);
|
2019-01-20 23:15:10 +08:00
|
|
|
// data should scatter around position=-0.07 in a BeeSwarmScatter-Plot
|
2019-01-26 20:00:40 +08:00
|
|
|
graphRANDVALS->setPositionScatterStyle(JKQTPSingleColumnSymbolsGraph::BeeSwarmScatter);
|
2019-01-20 23:15:10 +08:00
|
|
|
// choose small filled circles as symbols, JKQTPGraphSymbols::set their color:
|
2019-04-22 19:27:50 +08:00
|
|
|
graphRANDVALS->setSymbolType(JKQTPFilledCircle);
|
2019-01-26 20:00:40 +08:00
|
|
|
graphRANDVALS->setSymbolSize(5);
|
|
|
|
graphRANDVALS->setColor(QColor("red"));
|
2019-01-20 23:15:10 +08:00
|
|
|
// set title:
|
2019-01-26 20:00:40 +08:00
|
|
|
graphRANDVALS->setTitle("Random Data");
|
2019-01-20 23:15:10 +08:00
|
|
|
|
|
|
|
|
|
|
|
// 5. draw the histogram as barchart:
|
|
|
|
JKQTPBarVerticalGraph* graphHIST=new JKQTPBarVerticalGraph(&plot);
|
2019-01-26 20:00:40 +08:00
|
|
|
graphHIST->setXColumn(columnHIST.first);
|
|
|
|
graphHIST->setYColumn(columnHIST.second);
|
2019-01-20 23:15:10 +08:00
|
|
|
// set title:
|
2019-01-26 20:00:40 +08:00
|
|
|
graphHIST->setTitle("Histogram");
|
2019-01-20 23:15:10 +08:00
|
|
|
|
|
|
|
|
|
|
|
// 6. draw the theoretical distribution as function graph:
|
|
|
|
JKQTPXFunctionLineGraph* graphTheoDist=new JKQTPXFunctionLineGraph(&plot);
|
|
|
|
// define the gaussian function used for the random number generator
|
2019-04-22 19:27:50 +08:00
|
|
|
graphTheoDist->setPlotFunctionFunctor([&th_mean,&th_std](double x) -> double {
|
2019-01-20 23:15:10 +08:00
|
|
|
return 1.0/(th_std*sqrt(2.0*M_PI))*exp(-0.5*(x-th_mean)*(x-th_mean)/th_std/th_std);
|
|
|
|
});
|
|
|
|
// set title:
|
2019-01-26 20:00:40 +08:00
|
|
|
graphTheoDist->setTitle(QString("Theoretical Distribution $\\mu=%1, \\sigma=%2$").arg(th_mean,0, 'f', 1).arg(th_std,0, 'f', 1));
|
2019-01-20 23:15:10 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 7. create a graph of horizontal boxplots:
|
|
|
|
JKQTPBoxplotHorizontalElement* graphBoxPlot=new JKQTPBoxplotHorizontalElement(&plot);
|
2019-01-26 20:00:40 +08:00
|
|
|
graphBoxPlot->setPos(0.15);
|
|
|
|
graphBoxPlot->setMin(rndMin);
|
|
|
|
graphBoxPlot->setPercentile25(rndQ25);
|
|
|
|
graphBoxPlot->setMean(rndMean);
|
|
|
|
graphBoxPlot->setMedian(rndMedian);
|
2019-05-11 21:56:11 +08:00
|
|
|
graphBoxPlot->setMedianConfidenceIntervalWidth(rndMedianConfidence);
|
2019-01-26 20:00:40 +08:00
|
|
|
graphBoxPlot->setPercentile75(rndQ75);
|
|
|
|
graphBoxPlot->setMax(rndMax);
|
2019-05-11 21:56:11 +08:00
|
|
|
graphBoxPlot->setBoxWidthAbsolute(24);
|
|
|
|
graphBoxPlot->setMeanSize(12);
|
|
|
|
graphBoxPlot->setMeanSymbolType(JKQTPCross);
|
|
|
|
graphBoxPlot->setLineWidth(2);
|
2019-01-26 20:00:40 +08:00
|
|
|
graphBoxPlot->setTitle("Statistical Properties");
|
2019-05-11 21:56:11 +08:00
|
|
|
// set color of all elements
|
|
|
|
graphBoxPlot->setBoxplotColor(QColor("blue"), plot.getPlotter());
|
|
|
|
// change color of mean symbol
|
|
|
|
graphBoxPlot->setMeanColor(QColor("red"));
|
2019-01-20 23:15:10 +08:00
|
|
|
// make fill collor a lighter shade of the outline color
|
2019-05-11 21:56:11 +08:00
|
|
|
graphBoxPlot->setFillColor(graphBoxPlot->getLineColor().lighter(180));
|
2019-01-20 23:15:10 +08:00
|
|
|
// make whiskers dashed
|
2019-04-22 23:19:52 +08:00
|
|
|
graphBoxPlot->setWhiskerLineStyle(Qt::DashLine);
|
2019-01-20 23:15:10 +08:00
|
|
|
|
|
|
|
|
|
|
|
// 8. add the graphs to the plot, so it is actually displayed
|
|
|
|
plot.addGraph(graphRANDVALS);
|
|
|
|
plot.addGraph(graphHIST);
|
|
|
|
plot.addGraph(graphTheoDist);
|
|
|
|
plot.addGraph(graphBoxPlot);
|
|
|
|
|
|
|
|
|
|
|
|
// 9. autoscale the plot so the graph is contained
|
|
|
|
plot.setXY(-6,16,-0.1,0.2);
|
|
|
|
|
|
|
|
// 10. Move key to top-left
|
2019-01-26 03:16:04 +08:00
|
|
|
plot.getPlotter()->setKeyPosition(JKQTPKeyInsideTopLeft);
|
2019-01-20 23:15:10 +08:00
|
|
|
|
|
|
|
// 11. show plotter and make it a decent size
|
|
|
|
plot.show();
|
2019-05-11 21:56:11 +08:00
|
|
|
plot.resize(800,650);
|
2019-01-20 23:15:10 +08:00
|
|
|
|
|
|
|
return app.exec();
|
|
|
|
}
|