statistics library: added functions for 2D histograms and 2D kernel density estimates
statistics library: added adaptor functions for 2D histograms and 2D kernel density estimates added examples for the two above
@ -82,6 +82,7 @@ addSimpleTest(imageplot_nodatastore)
|
||||
addSimpleTest(datastore)
|
||||
addSimpleTest(datastore_iterators)
|
||||
addSimpleTest(datastore_statistics)
|
||||
addSimpleTest(datastore_statistics_2d)
|
||||
addSimpleTest(datastore_regression)
|
||||
addSimpleTest(contourplot)
|
||||
#addSimpleTest(rgbimageplot_opencv)
|
||||
|
@ -162,6 +162,9 @@ All test-projects are Qt-projects that use qmake to build. You can load them int
|
||||
<tr><td> \image html jkqtplotter_simpletest_datastore_regression_small.png
|
||||
<td> \subpage JKQTPlotterBasicJKQTPDatastoreRegression
|
||||
<td> Advanced 1-Dimensional Statistical Computation with JKQTPDatastore<br>using the internal statistics library<br>Regression Analysis (with the Statistics Library)<br>robust regression (IRLS)<br>weighted regression<br>non-linear regression<br>polynomial fitting
|
||||
<tr><td> \image html jkqtplotter_simpletest_datastore_statistics_2d_small.png
|
||||
<td> \subpage JKQTPlotterBasicJKQTPDatastoreStatistics2D
|
||||
<td> Advanced 2-Dimensional Statistical Computation with JKQTPDatastore<br>using the internal statistics library (see \ref jkqtptools_math_statistics )<br>histograms<br>kernel density estimates (KDE)
|
||||
</table>
|
||||
|
||||
|
||||
|
@ -66,6 +66,7 @@ All test-projects are Qt-projects that use qmake to build. You can load them int
|
||||
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/simpletest_datastore_iterators_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_iterators) | [Tutorial: Iterator-based access to JKQTPDatastore](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_iterators) | Iterator-based Data Management with JKQTPDatastore |
|
||||
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_datastore_statistics_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_statistics) | [Tutorial: Advanced 1-Dimensional Statistics with JKQTPDatastore](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_statistics) | Advanced 1-Dimensional Statistical Computation with JKQTPDatastore<br>using the internal statistics library<br>basic statistics (mean, standard deviation, ...)<br>boxplots<br>histograms<br>kernel density estimates (KDE) |
|
||||
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_datastore_regression_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_regression) | [Tutorial: Regression Analysis (with the Statistics Library)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_regression) | Advanced 1-Dimensional Statistical Computation with JKQTPDatastore<br>using the internal statistics library<br>Regression Analysis (with the Statistics Library)<br>robust regression (IRLS)<br>weighted regression<br>non-linear regression<br>polynomial fitting |
|
||||
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_datastore_statistics_2d_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_statistics_2d) | [Tutorial: Advanced 2-Dimensional Statistics with JKQTPDatastore](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_statistics_2d) | Advanced 2-Dimensional Statistical Computation with JKQTPDatastore<br>using the internal statistics library<br>histograms<br>kernel density estimates (KDE) |
|
||||
|
||||
|
||||
## More Complex Examples
|
||||
|
@ -5,6 +5,7 @@
|
||||
[JKQTPlotterBasicJKQTPDatastoreIterators]: @ref JKQTPlotterBasicJKQTPDatastoreIterators "Iterator-Based usage of JKQTPDatastore"
|
||||
[JKQTPlotterBasicJKQTPDatastoreStatistics]: @ref JKQTPlotterBasicJKQTPDatastoreStatistics "Advanced 1-Dimensional Statistics with JKQTPDatastore"
|
||||
[JKQTPlotterBasicJKQTPDatastoreRegression]: @ref JKQTPlotterBasicJKQTPDatastoreRegression "Regression Analysis (with the Statistics Library)"
|
||||
[JKQTPlotterBasicJKQTPDatastoreStatistics2D]: @ref JKQTPlotterBasicJKQTPDatastoreStatistics2D "Advanced 2-Dimensional Statistics with JKQTPDatastore"
|
||||
[statisticslibrary]: @ref jkqtptools_math_statistics "JKQTPlotter Statistics Library"
|
||||
|
||||
This tutorial project (see `./examples/simpletest_datastore/`) explains several options of JKQTPDatastore, which is the class used to centrally store the data for (most) graphs on a JKQTPlotter widget.
|
||||
@ -13,6 +14,7 @@ This tutorial project (see `./examples/simpletest_datastore/`) explains several
|
||||
- [JKQTPlotterBasicJKQTPDatastore]
|
||||
- [JKQTPlotterBasicJKQTPDatastoreIterators]
|
||||
- [JKQTPlotterBasicJKQTPDatastoreStatistics]
|
||||
- [JKQTPlotterBasicJKQTPDatastoreStatistics2D]
|
||||
- [JKQTPlotterBasicJKQTPDatastoreRegression]
|
||||
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
[JKQTPlotterBasicJKQTPDatastoreIterators]: @ref JKQTPlotterBasicJKQTPDatastoreIterators "Iterator-Based usage of JKQTPDatastore"
|
||||
[JKQTPlotterBasicJKQTPDatastoreStatistics]: @ref JKQTPlotterBasicJKQTPDatastoreStatistics "Advanced 1-Dimensional Statistics with JKQTPDatastore"
|
||||
[JKQTPlotterBasicJKQTPDatastoreRegression]: @ref JKQTPlotterBasicJKQTPDatastoreRegression "Regression Analysis (with the Statistics Library)"
|
||||
[JKQTPlotterBasicJKQTPDatastoreStatistics2D]: @ref JKQTPlotterBasicJKQTPDatastoreStatistics2D "Advanced 2-Dimensional Statistics with JKQTPDatastore"
|
||||
[statisticslibrary]: @ref jkqtptools_math_statistics "JKQTPlotter Statistics Library"
|
||||
|
||||
This tutorial project (see `./examples/simpletest_datastore_iterators/`) explains how to use the iterator-based interface to JKQTPDatastore.
|
||||
@ -13,6 +14,7 @@ This tutorial project (see `./examples/simpletest_datastore_iterators/`) explain
|
||||
- [JKQTPlotterBasicJKQTPDatastore]
|
||||
- [JKQTPlotterBasicJKQTPDatastoreIterators]
|
||||
- [JKQTPlotterBasicJKQTPDatastoreStatistics]
|
||||
- [JKQTPlotterBasicJKQTPDatastoreStatistics2D]
|
||||
- [JKQTPlotterBasicJKQTPDatastoreRegression]
|
||||
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
[JKQTPlotterBasicJKQTPDatastoreIterators]: @ref JKQTPlotterBasicJKQTPDatastoreIterators "Iterator-Based usage of JKQTPDatastore"
|
||||
[JKQTPlotterBasicJKQTPDatastoreStatistics]: @ref JKQTPlotterBasicJKQTPDatastoreStatistics "Advanced 1-Dimensional Statistics with JKQTPDatastore"
|
||||
[JKQTPlotterBasicJKQTPDatastoreRegression]: @ref JKQTPlotterBasicJKQTPDatastoreRegression "Regression Analysis (with the Statistics Library)"
|
||||
[JKQTPlotterBasicJKQTPDatastoreStatistics2D]: @ref JKQTPlotterBasicJKQTPDatastoreStatistics2D "Advanced 2-Dimensional Statistics with JKQTPDatastore"
|
||||
[statisticslibrary]: @ref jkqtptools_math_statistics "JKQTPlotter Statistics Library"
|
||||
|
||||
|
||||
@ -13,6 +14,7 @@ This tutorial project (see `./examples/simpletest_datastore_statistics/`) explai
|
||||
- [JKQTPlotterBasicJKQTPDatastore]
|
||||
- [JKQTPlotterBasicJKQTPDatastoreIterators]
|
||||
- [JKQTPlotterBasicJKQTPDatastoreStatistics]
|
||||
- [JKQTPlotterBasicJKQTPDatastoreStatistics2D]
|
||||
- [JKQTPlotterBasicJKQTPDatastoreRegression]
|
||||
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
[JKQTPlotterBasicJKQTPDatastoreIterators]: @ref JKQTPlotterBasicJKQTPDatastoreIterators "Iterator-Based usage of JKQTPDatastore"
|
||||
[JKQTPlotterBasicJKQTPDatastoreStatistics]: @ref JKQTPlotterBasicJKQTPDatastoreStatistics "Advanced 1-Dimensional Statistics with JKQTPDatastore"
|
||||
[JKQTPlotterBasicJKQTPDatastoreRegression]: @ref JKQTPlotterBasicJKQTPDatastoreRegression "Regression Analysis (with the Statistics Library)"
|
||||
[JKQTPlotterBasicJKQTPDatastoreStatistics2D]: @ref JKQTPlotterBasicJKQTPDatastoreStatistics2D "Advanced 2-Dimensional Statistics with JKQTPDatastore"
|
||||
[statisticslibrary]: @ref jkqtptools_math_statistics "JKQTPlotter Statistics Library"
|
||||
|
||||
|
||||
@ -14,6 +15,7 @@ This tutorial project (see `./examples/simpletest_datastore_statistics/`) explai
|
||||
- [JKQTPlotterBasicJKQTPDatastore]
|
||||
- [JKQTPlotterBasicJKQTPDatastoreIterators]
|
||||
- [JKQTPlotterBasicJKQTPDatastoreStatistics]
|
||||
- [JKQTPlotterBasicJKQTPDatastoreStatistics2D]
|
||||
- [JKQTPlotterBasicJKQTPDatastoreRegression]
|
||||
|
||||
[TOC]
|
||||
|
287
examples/simpletest_datastore_statistics_2d/README.md
Normal file
@ -0,0 +1,287 @@
|
||||
# Tutorial (JKQTPDatastore): Advanced 2-Dimensional Statistics with JKQTPDatastore {#JKQTPlotterBasicJKQTPDatastoreStatistics2D}
|
||||
|
||||
|
||||
[JKQTPlotterBasicJKQTPDatastore]: @ref JKQTPlotterBasicJKQTPDatastore "Basic Usage of JKQTPDatastore"
|
||||
[JKQTPlotterBasicJKQTPDatastoreIterators]: @ref JKQTPlotterBasicJKQTPDatastoreIterators "Iterator-Based usage of JKQTPDatastore"
|
||||
[JKQTPlotterBasicJKQTPDatastoreStatistics]: @ref JKQTPlotterBasicJKQTPDatastoreStatistics "Advanced 1-Dimensional Statistics with JKQTPDatastore"
|
||||
[JKQTPlotterBasicJKQTPDatastoreRegression]: @ref JKQTPlotterBasicJKQTPDatastoreRegression "Regression Analysis (with the Statistics Library)"
|
||||
[JKQTPlotterBasicJKQTPDatastoreStatistics2D]: @ref JKQTPlotterBasicJKQTPDatastoreStatistics2D "Advanced 2-Dimensional Statistics with JKQTPDatastore"
|
||||
[statisticslibrary]: @ref jkqtptools_math_statistics "JKQTPlotter Statistics Library"
|
||||
|
||||
|
||||
This tutorial project (see `./examples/simpletest_datastore_statistics_2d/`) explains several advanced functions of JKQTPDatastore in combination with the [[statisticslibrary]] conatined in JKQTPlotter.
|
||||
|
||||
***Note*** that there are additional tutorial explaining other aspects of data mangement in JKQTPDatastore:
|
||||
- [JKQTPlotterBasicJKQTPDatastore]
|
||||
- [JKQTPlotterBasicJKQTPDatastoreIterators]
|
||||
- [JKQTPlotterBasicJKQTPDatastoreStatistics]
|
||||
- [JKQTPlotterBasicJKQTPDatastoreStatistics2D]
|
||||
- [JKQTPlotterBasicJKQTPDatastoreRegression]
|
||||
|
||||
[TOC]
|
||||
|
||||
The source code of the main application can be found in [`jkqtplotter_simpletest_datastore_statistics_2d.cpp`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_statistics_2d/jkqtplotter_simpletest_datastore_statistics_2d.cpp).
|
||||
This tutorial cites only parts of this code to demonstrate different ways of working with data for the graphs.
|
||||
|
||||
# Generating different sets of random numbers
|
||||
|
||||
The code segments below will fill different instances of JKQTPlotter with different statistical plots. All these plots are based on either of two sets of random number pairs (i.e. x/y-locations) generated as shown here:
|
||||
```.cpp
|
||||
size_t randomdatacolx_small=datastore1->addColumn("random data, x");
|
||||
size_t randomdatacoly_small=datastore1->addColumn("random data, y");
|
||||
size_t randomdatacoldist_small=datastore1->addColumn("random data, distribution/class");
|
||||
size_t randomdatacolx=datastore1->addColumn("random data, x");
|
||||
size_t randomdatacoly=datastore1->addColumn("random data, y");
|
||||
size_t randomdatacoldist=datastore1->addColumn("random data, distribution/class");
|
||||
// random number generators:
|
||||
std::random_device rd;
|
||||
std::mt19937 gen{rd()};
|
||||
std::uniform_int_distribution<> ddecide(0,2);
|
||||
std::normal_distribution<> d1x{5,3};
|
||||
std::normal_distribution<> d1y{5,1};
|
||||
std::normal_distribution<> d2x{10,2};
|
||||
std::normal_distribution<> d2y{10,5};
|
||||
for (size_t i=0; i<500; i++) {
|
||||
double rx=0,ry=0;
|
||||
const int decide=ddecide(gen);
|
||||
if (decide==0) {
|
||||
rx=d1x(gen);
|
||||
ry=d1y(gen);
|
||||
} else {
|
||||
rx=d2x(gen);
|
||||
ry=d2y(gen);
|
||||
}
|
||||
if (i<150) {
|
||||
datastore1->appendToColumn(randomdatacolx_small, rx);
|
||||
datastore1->appendToColumn(randomdatacoly_small, ry);
|
||||
datastore1->appendToColumn(randomdatacoldist_small, std::min(1,decide));
|
||||
}
|
||||
datastore1->appendToColumn(randomdatacolx, rx);
|
||||
datastore1->appendToColumn(randomdatacoly, ry);
|
||||
datastore1->appendToColumn(randomdatacoldist, std::min(1,decide));
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
The columns `randomdatacolx` and `randomdatacoly` will contain 500 random numbers. Each one is drawn either from the normal distributions `d1x`/`d1y`, or `d2x`/`d2y`. The decision, which of the two to use is based on the result of a third random distribution `ddecide`, which only returns 0, 1 or 2 (`d1x`/`d1y` is chosen for `ddecide==0`). The column `randomdatacoldist` finally encodes which pair of distributions was chosen. The three columns `randomdatacolx_small`, `randomdatacoly_small` and `randomdatacoldist_small` represent a subset of the first 150 numbers from the full dataset.
|
||||
The columns are generated empty by calling `JKQTPDatastore::addColumn()` with only a name. Then the actual values are added by calling `JKQTPDatastore::appendToColumn()`.
|
||||
|
||||
The datasets generated above can be plotted using a simple scatterplot (here shown for the full dataset only):
|
||||
```.cpp
|
||||
JKQTPXYParametrizedScatterGraph* gDataHist;
|
||||
plothist->addGraph(gDataHist=new JKQTPXYParametrizedScatterGraph(plothist));
|
||||
gDataHist->setXYColumns(randomdatacolx,randomdatacoly);
|
||||
gDataHist->setSymbolColumn(randomdatacoldist);
|
||||
QMap<double, JKQTPGraphSymbols> mapped;
|
||||
mapped[0]=JKQTPGraphSymbols::JKQTPCross;
|
||||
mapped[1]=JKQTPGraphSymbols::JKQTPPlus;
|
||||
gDataHist->setMappedSymbolColumnFunctor(mapped);
|
||||
gDataHist->setSymbolSize(5);
|
||||
gDataHist->setSymbolColor(QColorWithAlphaF(QColor("red"), 0.7));
|
||||
gDataHist->setDrawLine(false);
|
||||
gDataHist->setTitle(QString("random data, $N="+QString::number(datastore1->getRows(randomdatacoldist))+"$"));
|
||||
```
|
||||
|
||||
In addition to get an idea of the used distributions, we can add two ellipses indicating the (doubled) standard deviations of the two distributions:
|
||||
|
||||
```.cpp
|
||||
// 2.3. to visualize the initial distributions, we draw an ellipse indicating the
|
||||
// variance of the distributions
|
||||
JKQTPGeoEllipse* gEll1Hist;
|
||||
JKQTPGeoEllipse* gEll2Hist;
|
||||
plothist->addGraph(gEll1Hist=new JKQTPGeoEllipse(plothist, d1x.mean(), d1y.mean(),d1x.stddev()*2.0,d1y.stddev()*2.0));
|
||||
plothist->addGraph(gEll2Hist=new JKQTPGeoEllipse(plothist, d2x.mean(), d2y.mean(),d2x.stddev()*2.0,d2y.stddev()*2.0));
|
||||
```
|
||||
|
||||
The resulting plot looks like this:
|
||||
|
||||
![jkqtplotter_simpletest_datastore_statistics_2d_scatteronly](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_datastore_statistics_2d_scatteronly.png)
|
||||
|
||||
|
||||
# Marginal Statistics
|
||||
|
||||
To explore the statistical properties of a 2D dataset, it is often useful to draw the marginal histograms, i.e. the histograms of one of the two variables. To do so, we use the function `jkqtpstatAddHHistogram1DAutoranged()` and `jkqtpstatAddVHistogram1DAutoranged()` that were introduced in [JKQTPlotterBasicJKQTPDatastoreStatistics] and are explained in detail there:
|
||||
|
||||
```.cpp
|
||||
jkqtpstatAddHHistogram1DAutoranged(plothistBottom->getPlotter(), datastore1->begin(randomdatacolx), datastore1->end(randomdatacolx), 1.0, true);
|
||||
jkqtpstatAddVHistogram1DAutoranged(plothistLeft->getPlotter(), datastore1->begin(randomdatacoly), datastore1->end(randomdatacoly), 1.0, true);
|
||||
```
|
||||
|
||||
Note that the plots are put into `JKQTPlotter`-instances `plothistBottom` and `plothistLeft`. These are put into a global `QGridSizer` just below and left of the main histogram plot `plothist`. The axes of these plots are linked to the main plot, so zooming one affects the other plot too and their axes are inverted, so the drawn histogram elongates to the left and to the bottom (starting with 0 at the main plot `plothist`):
|
||||
|
||||
```.cpp
|
||||
QGridLayout* lay;
|
||||
JKQTPlotter* plothist=new JKQTPlotter(&mainWidget);
|
||||
lay->addWidget(plothist,0,1);
|
||||
plothist->getPlotter()->setPlotLabel("Histograms");
|
||||
JKQTPDatastore* datastore1=plothist->getDatastore();
|
||||
JKQTPlotter* plothistLeft=new JKQTPlotter(datastore1, &mainWidget);
|
||||
lay->addWidget(plothistLeft,0,0);
|
||||
JKQTPlotter* plothistBottom=new JKQTPlotter(datastore1, &mainWidget);
|
||||
lay->addWidget(plothistBottom,1,1);
|
||||
plothistLeft->synchronizeYToMaster(plothist);
|
||||
plothistLeft->setAbsoluteX(0,1);
|
||||
plothistLeft->getXAxis()->setInverted(true);
|
||||
plothistLeft->getXAxis()->setShowZeroAxis(false);
|
||||
plothistLeft->getYAxis()->setShowZeroAxis(false);
|
||||
plothistLeft->getYAxis()->setDrawMode1(JKQTPCADMLine);
|
||||
plothistLeft->getYAxis()->setDrawMode2(JKQTPCADMLineTicks);
|
||||
plothistLeft->setGrid(false);
|
||||
plothistBottom->synchronizeXToMaster(plothist);
|
||||
plothistBottom->setAbsoluteY(0,1);
|
||||
plothistBottom->getYAxis()->setInverted(true);
|
||||
plothistBottom->getXAxis()->setShowZeroAxis(false);
|
||||
plothistBottom->getYAxis()->setShowZeroAxis(false);
|
||||
plothistBottom->getXAxis()->setDrawMode1(JKQTPCADMLine);
|
||||
plothistBottom->getXAxis()->setDrawMode2(JKQTPCADMLineTicks);
|
||||
plothistBottom->setGrid(false);
|
||||
plothistBottom->setMousePositionShown(false);
|
||||
```
|
||||
|
||||
This results in a graph like this:
|
||||
|
||||
![jkqtplotter_simpletest_datastore_statistics_2d_marginhist](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_datastore_statistics_2d_marginhist.png)
|
||||
|
||||
With the same method, also marginal Kernel Density Estimates can be drawn:
|
||||
|
||||
```.cpp
|
||||
double bwx=jkqtpstatEstimateKDEBandwidth(datastore1->begin(randomdatacolx_small), datastore1->end(randomdatacolx_small));
|
||||
jkqtpstatAddHKDE1DAutoranged(plotkdeBottom->getPlotter(), datastore1->begin(randomdatacolx_small), datastore1->end(randomdatacolx_small), 0.01, &jkqtpstatKernel1DGaussian, bwx);
|
||||
double bwy=jkqtpstatEstimateKDEBandwidth(datastore1->begin(randomdatacoly_small), datastore1->end(randomdatacoly_small));
|
||||
jkqtpstatAddVKDE1DAutoranged(plotkdeRight->getPlotter(), datastore1->begin(randomdatacoly_small), datastore1->end(randomdatacoly_small), 0.01, &jkqtpstatKernel1DGaussian, bwy);
|
||||
```
|
||||
|
||||
![jkqtplotter_simpletest_datastore_statistics_2d_marginkde](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_datastore_statistics_2d_marginkde.png)
|
||||
|
||||
|
||||
# 2D Histogram
|
||||
|
||||
Calculating 2D-Histograms is implemented in `jkqtpstatHistogram2D()` from the [statisticslibrary]. This functions calculates a histogram on a given grid with the first bin at `xmin,ymin` and the last bin at `xmax,ymax`, containing `Nx,Ny` bins in x-/y-direction. You can use the result to fill new image column (with `Nx` columns and `Ny` rows) in a `JKQTPDatastore`, which can then be used to draw the histogram.
|
||||
|
||||
First we have to determine the x- and y-range of data and calculate the number of bins from these:
|
||||
|
||||
```.cpp
|
||||
double xmin=0, xmax=0;
|
||||
double ymin=0, ymax=0;
|
||||
jkqtpstatMinMax(datastore1->begin(randomdatacolx), datastore1->end(randomdatacolx), xmin,xmax);
|
||||
jkqtpstatMinMax(datastore1->begin(randomdatacoly), datastore1->end(randomdatacoly), ymin,ymax);
|
||||
size_t Nx=jkqtp_ceilTo<size_t>((xmax-xmin)/2.0);
|
||||
size_t Ny=jkqtp_ceilTo<size_t>((ymax-ymin)/2.0);
|
||||
```
|
||||
|
||||
Now we can add the image column
|
||||
```.cpp
|
||||
size_t histcol=datastore1->addImageColumn(Nx, Ny, "2d histogram");
|
||||
```
|
||||
and calculate the histogram:
|
||||
```.cpp
|
||||
jkqtpstatHistogram2D(datastore1->begin(randomdatacolx), datastore1->end(randomdatacolx), datastore1->begin(randomdatacoly), datastore1->end(randomdatacoly),
|
||||
datastore1->begin(histcol),
|
||||
xmin, xmax, ymin, ymax,
|
||||
Nx, Ny, true);
|
||||
```
|
||||
|
||||
Finally the histogram is drawn using a `JKQTPColumnMathImage`:
|
||||
```.cpp
|
||||
JKQTPColumnMathImage* gHist;
|
||||
plothist->addGraph(gHist=new JKQTPColumnMathImage(plothist));
|
||||
gHist->setImageColumn(static_cast<int>(histcol));
|
||||
gHist->setX(xmin);
|
||||
gHist->setY(ymin);
|
||||
gHist->setWidth(xmax-xmin);
|
||||
gHist->setHeight(ymax-ymin);
|
||||
gHist->setTitle("2D Histogram");
|
||||
```
|
||||
|
||||
The resulting image plot looks like this:
|
||||
|
||||
![jkqtplotter_simpletest_datastore_statistics_2d_hist](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_datastore_statistics_2d_hist.png)
|
||||
|
||||
There is also an "adaptor" which significanty reduce the amount of coude you have to type (i.e. it replaces all the code above):
|
||||
|
||||
```.cpp
|
||||
jkqtpstatAddHistogram2DImage(plothist->getPlotter(), datastore1->begin(randomdatacolx), datastore1->end(randomdatacolx), datastore1->begin(randomdatacoly), datastore1->end(randomdatacoly), Nx, Ny, true);
|
||||
jkqtpstatAddHistogram2DContour(plothist->getPlotter(), datastore1->begin(randomdatacolx), datastore1->end(randomdatacolx), datastore1->begin(randomdatacoly), datastore1->end(randomdatacoly), Nx, Ny, true);
|
||||
```
|
||||
|
||||
These differ in the type of plot that is added `jkqtpstatAddHistogram2DImage()` adds an image graph (`JKQTPColumnMathImage`) and `jkqtpstatAddHistogram2DContour()` adds a contour plot (`JKQTPColumnContourPlot`). A contour plot may look like this:
|
||||
|
||||
|
||||
![jkqtplotter_simpletest_datastore_statistics_2d_histcontour](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_datastore_statistics_2d_histcontour.png)
|
||||
|
||||
|
||||
|
||||
|
||||
# Kernel Density Estimates (KDE)
|
||||
|
||||
Especially when only few samples from a distribution are available, histograms are not good at representing the underlying data distribution. In such cases, [Kernel Density Estimates (KDE)](https://en.wikipedia.org/wiki/Multivariate_kernel_density_estimation) can help, which are basically a smoothed variant of a histogram. The [statisticslibrary] supports calculating them via e.g. `jkqtpstatKDE2D()`:
|
||||
|
||||
This functions calculates a histogram on a given grid with the first bin at `xmin,ymin` and the last bin at `xmax,ymax`, containing `Nx,Ny` bins in x-/y-direction. You can use the result to fill new image column (with `Nx` columns and `Ny` rows) in a `JKQTPDatastore`, which can then be used to draw the histogram.
|
||||
|
||||
First we have to determine the x- and y-range of data and calculate the number of bins from these:
|
||||
|
||||
```.cpp
|
||||
double xmin=0, xmax=0;
|
||||
double ymin=0, ymax=0;
|
||||
jkqtpstatMinMax(datastore1->begin(randomdatacolx_small), datastore1->end(randomdatacolx_small), xmin,xmax);
|
||||
jkqtpstatMinMax(datastore1->begin(randomdatacoly_small), datastore1->end(randomdatacoly_small), ymin,ymax);
|
||||
Nx=jkqtp_ceilTo<size_t>((xmax-xmin)/0.1);
|
||||
Ny=jkqtp_ceilTo<size_t>((ymax-ymin)/0.1);
|
||||
```
|
||||
We can also estimate the KDE-bandwidth for both directions now:
|
||||
```.cpp
|
||||
bwx=jkqtpstatEstimateKDEBandwidth2D(datastore1->begin(randomdatacolx_small), datastore1->end(randomdatacolx_small));
|
||||
bwy=jkqtpstatEstimateKDEBandwidth2D(datastore1->begin(randomdatacoly_small), datastore1->end(randomdatacoly_small));
|
||||
```
|
||||
|
||||
Now we can add the image column
|
||||
```.cpp
|
||||
size_t kdecol=datastore1->addImageColumn(Nx, Ny, "2d KDE");
|
||||
```
|
||||
and calculate the histogram:
|
||||
```.cpp
|
||||
jkqtpstatKDE2D(datastore1->begin(randomdatacolx_small), datastore1->end(randomdatacolx_small), datastore1->begin(randomdatacoly_small), datastore1->end(randomdatacoly_small),
|
||||
datastore1->begin(kdecol),
|
||||
xmin, xmax, ymin, ymax, Nx, Ny,
|
||||
&jkqtpstatKernel2DGaussian, bwx, bwy);
|
||||
```
|
||||
|
||||
Finally the histogram is drawn using a `JKQTPColumnMathImage`:
|
||||
```.cpp
|
||||
JKQTPColumnMathImage* gKDE;
|
||||
plotkde->addGraph(gKDE=new JKQTPColumnMathImage(plotkde));
|
||||
gKDE->setImageColumn(static_cast<int>(kdecol));
|
||||
gKDE->setX(xmin);
|
||||
gKDE->setY(ymin);
|
||||
gKDE->setWidth(xmax-xmin);
|
||||
gKDE->setHeight(ymax-ymin);
|
||||
gKDE->setTitle("2D KDE");
|
||||
```
|
||||
|
||||
The resulting plot image looks like this:
|
||||
|
||||
![jkqtplotter_simpletest_datastore_statistics_2d_kde](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_datastore_statistics_2d_kde.png)
|
||||
|
||||
Note that calculating a KDE is a rather time-consuming task. The KDE in the image above took about 8s to calculate (from 150 datapairs and on a 193*267 pixel grid), whereas the corresponding histogram took only 1ms to calculate!
|
||||
|
||||
There is also an "adaptor" which significanty reduce the amount of coude you have to type (i.e. it replaces all the code above):
|
||||
|
||||
```.cpp
|
||||
jkqtpstatAddKDE2DImage(plotkde->getPlotter(), datastore1->begin(randomdatacolx_small), datastore1->end(randomdatacolx_small), datastore1->begin(randomdatacoly_small), datastore1->end(randomdatacoly_small), Nx, Ny, &jkqtpstatKernel2DGaussian, bwx, bwy);
|
||||
jkqtpstatAddKDE2DContour(plotkde->getPlotter(), datastore1->begin(randomdatacolx_small), datastore1->end(randomdatacolx_small), datastore1->begin(randomdatacoly_small), datastore1->end(randomdatacoly_small), Nx, Ny, &jkqtpstatKernel2DGaussian, bwx, bwy);
|
||||
```
|
||||
|
||||
These differ in the type of plot that is added `jkqtpstatAddKDE2DImage()` adds an image graph (`JKQTPColumnMathImage`) and `jkqtpstatAddKDE2DContour()` adds a contour plot (`JKQTPColumnContourPlot`). the first is shown in the screenshot above, the latter looks like this:
|
||||
|
||||
![jkqtplotter_simpletest_datastore_statistics_2d_kdecontour](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_datastore_statistics_2d_kdecontour.png)
|
||||
|
||||
|
||||
|
||||
|
||||
# Screenshot of the full Program
|
||||
|
||||
The output of the full test program [`jkqtplotter_simpletest_datastore_statistics_2d.cpp`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_statistics_2d/jkqtplotter_simpletest_datastore_statistics_2d.cpp) looks like this:
|
||||
|
||||
![jkqtplotter_simpletest_datastore_statistics_2d](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_datastore_statistics_2d.png)
|
||||
|
||||
|
@ -0,0 +1,277 @@
|
||||
/** \example jkqtplotter_simpletest_datastore_statistics_2d.cpp
|
||||
* Explains how to use the internal statistics library (see \ref jkqtptools_statistics ) together with JKQTPDatastore to generate advanced plots for 2-dimensional data.
|
||||
*
|
||||
* \ref JKQTPlotterBasicJKQTPDatastoreStatistics2D
|
||||
*/
|
||||
|
||||
#include <QApplication>
|
||||
#include "jkqtplotter/jkqtplotter.h"
|
||||
#include "jkqtplotter/jkqtpgraphsimage.h"
|
||||
#include "jkqtplotter/jkqtpgraphsstatisticsadaptors.h"
|
||||
#include "jkqtplotter/jkqtpgraphsgeometric.h"
|
||||
#include "jkqtplotter/jkqtpgraphsscatter.h"
|
||||
#include "jkqtcommon/jkqtpstatisticstools.h"
|
||||
#include "jkqtcommon/jkqtpstringtools.h"
|
||||
#include <random>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
QElapsedTimer timer;
|
||||
|
||||
|
||||
// 1. create a window with several plotters and get a pointer to the internal datastores (for convenience)
|
||||
QWidget mainWidget;
|
||||
QGridLayout* lay;
|
||||
mainWidget.setLayout(lay=new QGridLayout);
|
||||
JKQTPlotter* plothist=new JKQTPlotter(&mainWidget);
|
||||
lay->addWidget(plothist,0,1);
|
||||
plothist->getPlotter()->setPlotLabel("Histograms");
|
||||
JKQTPDatastore* datastore1=plothist->getDatastore();
|
||||
JKQTPlotter* plothistLeft=new JKQTPlotter(datastore1, &mainWidget);
|
||||
lay->addWidget(plothistLeft,0,0);
|
||||
JKQTPlotter* plothistBottom=new JKQTPlotter(datastore1, &mainWidget);
|
||||
lay->addWidget(plothistBottom,1,1);
|
||||
plothistLeft->synchronizeYToMaster(plothist);
|
||||
plothistLeft->setAbsoluteX(0,1);
|
||||
plothistLeft->getXAxis()->setInverted(true);
|
||||
plothistLeft->getXAxis()->setShowZeroAxis(false);
|
||||
plothistLeft->getYAxis()->setShowZeroAxis(false);
|
||||
plothistLeft->getYAxis()->setDrawMode1(JKQTPCADMLine);
|
||||
plothistLeft->getYAxis()->setDrawMode2(JKQTPCADMLineTicks);
|
||||
plothistLeft->setGrid(false);
|
||||
plothistBottom->synchronizeXToMaster(plothist);
|
||||
plothistBottom->setAbsoluteY(0,1);
|
||||
plothistBottom->getYAxis()->setInverted(true);
|
||||
plothistBottom->getXAxis()->setShowZeroAxis(false);
|
||||
plothistBottom->getYAxis()->setShowZeroAxis(false);
|
||||
plothistBottom->getXAxis()->setDrawMode1(JKQTPCADMLine);
|
||||
plothistBottom->getXAxis()->setDrawMode2(JKQTPCADMLineTicks);
|
||||
plothistBottom->setGrid(false);
|
||||
plothistBottom->setMousePositionShown(false);
|
||||
|
||||
|
||||
JKQTPlotter* plotkde=new JKQTPlotter(datastore1, &mainWidget);
|
||||
plotkde->getPlotter()->setPlotLabel("Kernel Density Estimate");
|
||||
lay->addWidget(plotkde,0,2);
|
||||
JKQTPlotter* plotkdeRight=new JKQTPlotter(datastore1, &mainWidget);
|
||||
lay->addWidget(plotkdeRight,0,3);
|
||||
JKQTPlotter* plotkdeBottom=new JKQTPlotter(datastore1, &mainWidget);
|
||||
lay->addWidget(plotkdeBottom,1,2);
|
||||
plotkdeRight->synchronizeYToMaster(plotkde);
|
||||
plotkdeRight->setAbsoluteX(0,1);
|
||||
plotkdeRight->getXAxis()->setShowZeroAxis(false);
|
||||
plotkdeRight->getYAxis()->setShowZeroAxis(false);
|
||||
plotkdeRight->getYAxis()->setDrawMode1(JKQTPCADMLine);
|
||||
plotkdeRight->getYAxis()->setDrawMode2(JKQTPCADMLineTicks);
|
||||
plotkdeRight->setGrid(false);
|
||||
plotkdeBottom->synchronizeXToMaster(plotkde);
|
||||
plotkdeBottom->setAbsoluteY(0,1);
|
||||
plotkdeBottom->getYAxis()->setInverted(true);
|
||||
plotkdeBottom->getXAxis()->setShowZeroAxis(false);
|
||||
plotkdeBottom->getYAxis()->setShowZeroAxis(false);
|
||||
plotkdeBottom->getXAxis()->setDrawMode1(JKQTPCADMLine);
|
||||
plotkdeBottom->getXAxis()->setDrawMode2(JKQTPCADMLineTicks);
|
||||
plotkdeBottom->setGrid(false);
|
||||
plotkdeBottom->setMousePositionShown(false);
|
||||
|
||||
lay->setColumnStretch(0,1);
|
||||
lay->setColumnStretch(1,3);
|
||||
lay->setColumnStretch(2,3);
|
||||
lay->setColumnStretch(3,1);
|
||||
lay->setRowStretch(0,3);
|
||||
lay->setRowStretch(1,1);
|
||||
|
||||
|
||||
// 2.1. Now we create two vectors with random values
|
||||
// randomdatacolx: random x-positions, drawn from one of two gaussian distributions
|
||||
// randomdatacoly: random y-positions, drawn from one of two gaussian distributions
|
||||
// randomdatacoldist: indicates, which if the two sets of gaussian distributions was chosen for each datapoint
|
||||
size_t randomdatacolx_small=datastore1->addColumn("random data, x");
|
||||
size_t randomdatacoly_small=datastore1->addColumn("random data, y");
|
||||
size_t randomdatacoldist_small=datastore1->addColumn("random data, distribution/class");
|
||||
size_t randomdatacolx=datastore1->addColumn("random data, x");
|
||||
size_t randomdatacoly=datastore1->addColumn("random data, y");
|
||||
size_t randomdatacoldist=datastore1->addColumn("random data, distribution/class");
|
||||
// random number generators:
|
||||
std::random_device rd;
|
||||
std::mt19937 gen{rd()};
|
||||
std::uniform_int_distribution<> ddecide(0,2);
|
||||
std::normal_distribution<> d1x{5,3};
|
||||
std::normal_distribution<> d1y{5,1};
|
||||
std::normal_distribution<> d2x{10,2};
|
||||
std::normal_distribution<> d2y{10,5};
|
||||
for (size_t i=0; i<500; i++) {
|
||||
double rx=0,ry=0;
|
||||
const int decide=ddecide(gen);
|
||||
if (decide==0) {
|
||||
rx=d1x(gen);
|
||||
ry=d1y(gen);
|
||||
} else {
|
||||
rx=d2x(gen);
|
||||
ry=d2y(gen);
|
||||
}
|
||||
if (i<150) {
|
||||
datastore1->appendToColumn(randomdatacolx_small, rx);
|
||||
datastore1->appendToColumn(randomdatacoly_small, ry);
|
||||
datastore1->appendToColumn(randomdatacoldist_small, std::min(1,decide));
|
||||
}
|
||||
datastore1->appendToColumn(randomdatacolx, rx);
|
||||
datastore1->appendToColumn(randomdatacoly, ry);
|
||||
datastore1->appendToColumn(randomdatacoldist, std::min(1,decide));
|
||||
}
|
||||
|
||||
// 2.2. To visualize the data, a simple JKQTPPeakStreamGraph is used:
|
||||
JKQTPXYParametrizedScatterGraph* gDataHist;
|
||||
plothist->addGraph(gDataHist=new JKQTPXYParametrizedScatterGraph(plothist));
|
||||
gDataHist->setXYColumns(randomdatacolx,randomdatacoly);
|
||||
gDataHist->setSymbolColumn(randomdatacoldist);
|
||||
QMap<double, JKQTPGraphSymbols> mapped;
|
||||
mapped[0]=JKQTPGraphSymbols::JKQTPCross;
|
||||
mapped[1]=JKQTPGraphSymbols::JKQTPPlus;
|
||||
gDataHist->setMappedSymbolColumnFunctor(mapped);
|
||||
gDataHist->setSymbolSize(5);
|
||||
gDataHist->setSymbolColor(QColorWithAlphaF(QColor("red"), 0.7));
|
||||
gDataHist->setDrawLine(false);
|
||||
gDataHist->setTitle(QString("random data, $N="+QString::number(datastore1->getRows(randomdatacoldist))+"$"));
|
||||
JKQTPXYParametrizedScatterGraph* gDataKDE;
|
||||
plotkde->addGraph(gDataKDE=new JKQTPXYParametrizedScatterGraph(plotkde));
|
||||
gDataKDE->setXYColumns(randomdatacolx_small,randomdatacoly_small);
|
||||
gDataKDE->setSymbolColumn(randomdatacoldist_small);
|
||||
gDataKDE->setSymbolSize(3);
|
||||
gDataKDE->setSymbolColor(QColorWithAlphaF(QColor("red"), 0.7));
|
||||
gDataKDE->setMappedSymbolColumnFunctor(mapped);
|
||||
gDataKDE->setDrawLine(false);
|
||||
gDataKDE->setTitle(QString("random data, $N="+QString::number(datastore1->getRows(randomdatacoldist_small))+"$"));
|
||||
|
||||
// 2.3. to visualize the initial distributions, we draw an ellipse indicating the
|
||||
// variance of the distributions
|
||||
JKQTPGeoEllipse* gEll1Hist;
|
||||
JKQTPGeoEllipse* gEll2Hist;
|
||||
JKQTPGeoEllipse* gEll1KDE;
|
||||
JKQTPGeoEllipse* gEll2KDE;
|
||||
plothist->addGraph(gEll1Hist=new JKQTPGeoEllipse(plothist, d1x.mean(), d1y.mean(),d1x.stddev()*2.0,d1y.stddev()*2.0));
|
||||
plothist->addGraph(gEll2Hist=new JKQTPGeoEllipse(plothist, d2x.mean(), d2y.mean(),d2x.stddev()*2.0,d2y.stddev()*2.0));
|
||||
plotkde->addGraph(gEll1KDE=new JKQTPGeoEllipse(plothist, d1x.mean(), d1y.mean(),d1x.stddev()*2.0,d1y.stddev()*2.0));
|
||||
plotkde->addGraph(gEll2KDE=new JKQTPGeoEllipse(plothist, d2x.mean(), d2y.mean(),d2x.stddev()*2.0,d2y.stddev()*2.0));
|
||||
|
||||
|
||||
// 3. Marginal (1D) Statistics of the x-position and y-position deistributions:
|
||||
// 3.1. First we calculate the x/y marginal histograms, as desribed in https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_statistics
|
||||
timer.start();
|
||||
jkqtpstatAddHHistogram1DAutoranged(plothistBottom->getPlotter(), datastore1->begin(randomdatacolx), datastore1->end(randomdatacolx), 1.0, true);
|
||||
jkqtpstatAddVHistogram1DAutoranged(plothistLeft->getPlotter(), datastore1->begin(randomdatacoly), datastore1->end(randomdatacoly), 1.0, true);
|
||||
qDebug()<<"histogram, 1D: "<<timer.elapsed()/2.0<<"ms";
|
||||
// 3.2. Also we calculate the x/y marginal kernel density estimates, as desribed in https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_statistics
|
||||
timer.start();
|
||||
double bwx=jkqtpstatEstimateKDEBandwidth(datastore1->begin(randomdatacolx_small), datastore1->end(randomdatacolx_small));
|
||||
qDebug()<<bwx;
|
||||
jkqtpstatAddHKDE1DAutoranged(plotkdeBottom->getPlotter(), datastore1->begin(randomdatacolx_small), datastore1->end(randomdatacolx_small), 0.01, &jkqtpstatKernel1DGaussian, bwx);
|
||||
double bwy=jkqtpstatEstimateKDEBandwidth(datastore1->begin(randomdatacoly_small), datastore1->end(randomdatacoly_small));
|
||||
qDebug()<<bwy;
|
||||
jkqtpstatAddVKDE1DAutoranged(plotkdeRight->getPlotter(), datastore1->begin(randomdatacoly_small), datastore1->end(randomdatacoly_small), 0.01, &jkqtpstatKernel1DGaussian, bwy);
|
||||
qDebug()<<"KDE+bandwidth, 1D: "<<timer.elapsed()/2.0<<"ms";
|
||||
|
||||
|
||||
// 4. 2D Histogram
|
||||
double xmin=0, xmax=0;
|
||||
double ymin=0, ymax=0;
|
||||
timer.start();
|
||||
jkqtpstatMinMax(datastore1->begin(randomdatacolx), datastore1->end(randomdatacolx), xmin,xmax);
|
||||
jkqtpstatMinMax(datastore1->begin(randomdatacoly), datastore1->end(randomdatacoly), ymin,ymax);
|
||||
size_t Nx=jkqtp_ceilTo<size_t>((xmax-xmin)/2.0);
|
||||
size_t Ny=jkqtp_ceilTo<size_t>((ymax-ymin)/2.0);
|
||||
size_t histcol=datastore1->addImageColumn(Nx, Ny, "2d histogram");
|
||||
jkqtpstatHistogram2D(datastore1->begin(randomdatacolx), datastore1->end(randomdatacolx), datastore1->begin(randomdatacoly), datastore1->end(randomdatacoly),
|
||||
datastore1->begin(histcol),
|
||||
xmin, xmax, ymin, ymax,
|
||||
Nx, Ny, true);
|
||||
qDebug()<<"histogram, 2D: "<<timer.elapsed()<<"ms";
|
||||
JKQTPColumnMathImage* gHist;
|
||||
plothist->addGraph(gHist=new JKQTPColumnMathImage(plothist));
|
||||
gHist->setImageColumn(static_cast<int>(histcol));
|
||||
gHist->setX(xmin);
|
||||
gHist->setY(ymin);
|
||||
gHist->setWidth(xmax-xmin);
|
||||
gHist->setHeight(ymax-ymin);
|
||||
gHist->setTitle("2D Histogram");
|
||||
qDebug()<<xmin<<xmax<<Nx;
|
||||
qDebug()<<ymin<<ymax<<Ny;
|
||||
|
||||
// There also exist "adaptors", which execute the complete code above in one call.
|
||||
// Two flavors exist:
|
||||
// jkqtpstatAddHistogram2DImage() adds an image plot as shown above
|
||||
// jkqtpstatAddHistogram2DContour() adds a contour plot
|
||||
//jkqtpstatAddHistogram2DImage(plothist->getPlotter(), datastore1->begin(randomdatacolx), datastore1->end(randomdatacolx), datastore1->begin(randomdatacoly), datastore1->end(randomdatacoly), Nx, Ny, true);
|
||||
//jkqtpstatAddHistogram2DContour(plothist->getPlotter(), datastore1->begin(randomdatacolx), datastore1->end(randomdatacolx), datastore1->begin(randomdatacoly), datastore1->end(randomdatacoly), size_t(50),size_t(50), true);
|
||||
|
||||
|
||||
|
||||
// 5. 2D KDE
|
||||
xmin=0; xmax=0;
|
||||
ymin=0; ymax=0;
|
||||
timer.start();
|
||||
jkqtpstatMinMax(datastore1->begin(randomdatacolx_small), datastore1->end(randomdatacolx_small), xmin,xmax);
|
||||
jkqtpstatMinMax(datastore1->begin(randomdatacoly_small), datastore1->end(randomdatacoly_small), ymin,ymax);
|
||||
Nx=jkqtp_ceilTo<size_t>((xmax-xmin)/0.1);
|
||||
Ny=jkqtp_ceilTo<size_t>((ymax-ymin)/0.1);
|
||||
bwx=jkqtpstatEstimateKDEBandwidth2D(datastore1->begin(randomdatacolx_small), datastore1->end(randomdatacolx_small));
|
||||
qDebug()<<bwx;
|
||||
bwy=jkqtpstatEstimateKDEBandwidth2D(datastore1->begin(randomdatacoly_small), datastore1->end(randomdatacoly_small));
|
||||
qDebug()<<bwy;
|
||||
qDebug()<<xmin<<xmax<<Nx;
|
||||
qDebug()<<ymin<<ymax<<Ny;
|
||||
size_t kdecol=datastore1->addImageColumn(Nx, Ny, "2d KDE");
|
||||
jkqtpstatKDE2D(datastore1->begin(randomdatacolx_small), datastore1->end(randomdatacolx_small), datastore1->begin(randomdatacoly_small), datastore1->end(randomdatacoly_small),
|
||||
datastore1->begin(kdecol),
|
||||
xmin, xmax, ymin, ymax, Nx, Ny,
|
||||
&jkqtpstatKernel2DGaussian, bwx, bwy);
|
||||
qDebug()<<"KDE, 2D: "<<timer.elapsed()<<"ms";
|
||||
JKQTPColumnMathImage* gKDE;
|
||||
plotkde->addGraph(gKDE=new JKQTPColumnMathImage(plotkde));
|
||||
gKDE->setImageColumn(static_cast<int>(kdecol));
|
||||
gKDE->setX(xmin);
|
||||
gKDE->setY(ymin);
|
||||
gKDE->setWidth(xmax-xmin);
|
||||
gKDE->setHeight(ymax-ymin);
|
||||
gKDE->setTitle("2D KDE");
|
||||
|
||||
// There also exist "adaptors", which execute the complete code above in one call.
|
||||
// Two flavors exist:
|
||||
// jkqtpstatAddKDE2DImage() adds an image plot as shown above
|
||||
// jkqtpstatAddKDE2DContour() adds a contour plot
|
||||
//jkqtpstatAddKDE2DImage(plotkde->getPlotter(), datastore1->begin(randomdatacolx_small), datastore1->end(randomdatacolx_small), datastore1->begin(randomdatacoly_small), datastore1->end(randomdatacoly_small), Nx, Ny, &jkqtpstatKernel2DGaussian, bwx, bwy);
|
||||
//jkqtpstatAddKDE2DContour(plotkde->getPlotter(), datastore1->begin(randomdatacolx_small), datastore1->end(randomdatacolx_small), datastore1->begin(randomdatacoly_small), datastore1->end(randomdatacoly_small), Nx, Ny, &jkqtpstatKernel2DGaussian, bwx, bwy);
|
||||
|
||||
|
||||
|
||||
// autoscale the plot so the graph is contained
|
||||
plothist->zoomToFit();
|
||||
plothist->setGrid(false);
|
||||
plothist->getXAxis()->setShowZeroAxis(false);
|
||||
plothist->getYAxis()->setShowZeroAxis(false);
|
||||
plothist->getPlotter()->setKeyBackgroundColor(QColorWithAlphaF("white", 0.25), Qt::SolidPattern);
|
||||
plothist->getPlotter()->moveGraphTop(gDataHist);
|
||||
plothist->getPlotter()->moveGraphTop(gEll1Hist);
|
||||
plothist->getPlotter()->moveGraphTop(gEll2Hist);
|
||||
plothistBottom->zoomToFit(false, true);
|
||||
plothistLeft->zoomToFit(true, false);
|
||||
plotkde->zoomToFit();
|
||||
plotkde->setGrid(false);
|
||||
plotkde->getXAxis()->setShowZeroAxis(false);
|
||||
plotkde->getYAxis()->setShowZeroAxis(false);
|
||||
plotkde->getPlotter()->setKeyBackgroundColor(QColorWithAlphaF("white", 0.25), Qt::SolidPattern);
|
||||
plotkde->getPlotter()->moveGraphTop(gDataKDE);
|
||||
plotkde->getPlotter()->moveGraphTop(gEll1KDE);
|
||||
plotkde->getPlotter()->moveGraphTop(gEll2KDE);
|
||||
plotkdeBottom->zoomToFit(false, true);
|
||||
plotkdeRight->zoomToFit(true, false);
|
||||
|
||||
// show plotter and make it a decent size
|
||||
mainWidget.show();
|
||||
mainWidget.resize(1200,600);
|
||||
|
||||
return app.exec();
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
# source code for this simple demo
|
||||
SOURCES = jkqtplotter_simpletest_datastore_statistics_2d.cpp
|
||||
|
||||
# configure Qt
|
||||
CONFIG += link_prl qt
|
||||
QT += core gui xml svg
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport
|
||||
|
||||
# output executable name
|
||||
TARGET = jkqtplotter_simpletest_datastore_statistics_2d
|
||||
|
||||
# include JKQTPlotter source headers and link against library
|
||||
DEPENDPATH += ../../lib ../../staticlib/jkqtplotterlib
|
||||
INCLUDEPATH += ../../lib
|
||||
CONFIG (debug, debug|release) {
|
||||
LIBS += -L../../staticlib/jkqtplotterlib/debug -ljkqtplotterlib_debug
|
||||
} else {
|
||||
LIBS += -L../../staticlib/jkqtplotterlib/release -ljkqtplotterlib
|
||||
}
|
||||
message("LIBS = $$LIBS")
|
||||
|
||||
win32-msvc*: DEFINES += _USE_MATH_DEFINES
|
||||
win32-msvc*: DEFINES += NOMINMAX
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,8 @@
|
||||
TEMPLATE = subdirs
|
||||
|
||||
SUBDIRS += jkqtplotterlib jkqtplotter_simpletest_datastore_statistics_2d
|
||||
|
||||
jkqtplotterlib.file = ../../staticlib/jkqtplotterlib/jkqtplotterlib.pro
|
||||
|
||||
jkqtplotter_simpletest_datastore_statistics_2d.file=$$PWD/jkqtplotter_simpletest_datastore_statistics_2d.pro
|
||||
jkqtplotter_simpletest_datastore_statistics_2d.depends = jkqtplotterlib
|
@ -115,6 +115,60 @@ inline T jkqtp_roundTo(const double& v) {
|
||||
return static_cast<T>(round(v));
|
||||
}
|
||||
|
||||
/** \brief round a double \a v using ceil() and convert it to a specified type T (static_cast!)
|
||||
* \ingroup jkqtptools_math_basic
|
||||
*
|
||||
* \tparam T a numeric datatype (int, double, ...)
|
||||
* \param v the value to ceil and cast
|
||||
*
|
||||
* this is equivalent to
|
||||
* \code
|
||||
* static_cast<T>(ceil(v));
|
||||
* \endcode
|
||||
*
|
||||
* \callergraph
|
||||
*/
|
||||
template<typename T>
|
||||
inline T jkqtp_ceilTo(const double& v) {
|
||||
return static_cast<T>(ceil(v));
|
||||
}
|
||||
|
||||
/** \brief round a double \a v using trunc() and convert it to a specified type T (static_cast!)
|
||||
* \ingroup jkqtptools_math_basic
|
||||
*
|
||||
* \tparam T a numeric datatype (int, double, ...)
|
||||
* \param v the value to trunc and cast
|
||||
*
|
||||
* this is equivalent to
|
||||
* \code
|
||||
* static_cast<T>(trunc(v));
|
||||
* \endcode
|
||||
*
|
||||
* \callergraph
|
||||
*/
|
||||
template<typename T>
|
||||
inline T jkqtp_truncTo(const double& v) {
|
||||
return static_cast<T>(trunc(v));
|
||||
}
|
||||
|
||||
/** \brief round a double \a v using floor() and convert it to a specified type T (static_cast!)
|
||||
* \ingroup jkqtptools_math_basic
|
||||
*
|
||||
* \tparam T a numeric datatype (int, double, ...)
|
||||
* \param v the value to floor and cast
|
||||
*
|
||||
* this is equivalent to
|
||||
* \code
|
||||
* static_cast<T>(floor(v));
|
||||
* \endcode
|
||||
*
|
||||
* \callergraph
|
||||
*/
|
||||
template<typename T>
|
||||
inline T jkqtp_floorTo(const double& v) {
|
||||
return static_cast<T>(floor(v));
|
||||
}
|
||||
|
||||
|
||||
/** \brief round a double \a v using round() and convert it to a specified type T (static_cast!).
|
||||
* Finally the value is bounded to the range \a min ... \a max
|
||||
|
@ -1425,6 +1425,66 @@ inline void jkqtpstatHistogram1D(InputIt first, InputIt last, BinsInputIt binsFi
|
||||
|
||||
|
||||
|
||||
/*! \brief calculate a 2-dimensional histogram from the given data range \a firstX / \a firstY ... \a lastY / \a lastY
|
||||
\ingroup jkqtptools_math_statistics_2dhist
|
||||
|
||||
\tparam InputItX standard iterator type of \a firstX and \a lastX.
|
||||
\tparam InputItY standard iterator type of \a firstY and \a lastY.
|
||||
\tparam OutputIt standard output iterator type used for the outliers output \a histogramXOut and \a histogramYOut, use e.g. std::back_inserter
|
||||
\param firstX iterator pointing to the first x-position item in the dataset to use \f$ X_1 \f$
|
||||
\param lastX iterator pointing behind the last x-position item in the dataset to use \f$ X_N \f$
|
||||
\param firstY iterator pointing to the first y-position item in the dataset to use \f$ Y_1 \f$
|
||||
\param lastY iterator pointing behind the last y-position item in the dataset to use \f$ Y_N \f$
|
||||
\param[out] histogramImgOut output iterator that receives counts of the histogram bins in row-major ordering
|
||||
\param xmin position of the first histogram bin in x-direction
|
||||
\param xmax position of the last histogram bin in x-direction
|
||||
\param ymin position of the first histogram bin in y-direction
|
||||
\param ymax position of the last histogram bin in y-direction
|
||||
\param xbins number of bins in x-direction (i.e. width of the output histogram \a histogramImgOut )
|
||||
\param ybins number of bins in y-direction (i.e. height of the output histogram \a histogramImgOut )
|
||||
\param normalized indicates whether the histogram has to be normalized
|
||||
|
||||
\see jkqtpstatAddHHistogram1DAutoranged()
|
||||
*/
|
||||
template <class InputItX, class InputItY, class OutputIt>
|
||||
inline void jkqtpstatHistogram2D(InputItX firstX, InputItX lastX, InputItY firstY, InputItY lastY, OutputIt histogramImgOut, double xmin, double xmax, double ymin, double ymax, size_t xbins=10, size_t ybins=10, bool normalized=true) {
|
||||
|
||||
const double binwx=fabs(xmax-xmin)/static_cast<double>(xbins);
|
||||
const double binwy=fabs(ymax-ymin)/static_cast<double>(ybins);
|
||||
|
||||
std::vector<double> hist;
|
||||
std::fill_n(std::back_inserter(hist), xbins*ybins, 0.0);
|
||||
|
||||
// calculate the histogram
|
||||
auto itX=firstX;
|
||||
auto itY=firstY;
|
||||
size_t N=0;
|
||||
for (; (itX!=lastX) && (itY!=lastY); ++itX, ++itY) {
|
||||
const double vx=jkqtp_todouble(*itX);
|
||||
const double vy=jkqtp_todouble(*itY);
|
||||
if (JKQTPIsOKFloat(vx) && JKQTPIsOKFloat(vy)) {
|
||||
const size_t bx=jkqtp_bounded<size_t>(0, static_cast<size_t>(floor((vx-xmin)/binwx)), xbins-1);
|
||||
const size_t by=jkqtp_bounded<size_t>(0, static_cast<size_t>(floor((vy-ymin)/binwy)), ybins-1);
|
||||
hist[by*xbins+bx]++;
|
||||
N++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// output the histogram
|
||||
double NNorm=1;
|
||||
if (normalized) {
|
||||
NNorm=static_cast<double>(N);
|
||||
}
|
||||
std::transform(hist.begin(), hist.end(), histogramImgOut, [NNorm](double v) { return v/NNorm; });
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \brief a 1D Gaussian kernel function, e.g. for Kernel Density Estimation
|
||||
\ingroup jkqtptools_math_statistics_1dkde_kernels
|
||||
@ -1580,6 +1640,7 @@ inline double jkqtpstatEvaluateKernelSum(double t, InputIt first, InputIt last,
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
if (cnt==0) return 0.0;
|
||||
return res/static_cast<double>(cnt)/bandwidth;
|
||||
}
|
||||
|
||||
@ -1605,7 +1666,7 @@ inline double jkqtpstatEvaluateKernelSum(double t, InputIt first, InputIt last,
|
||||
|
||||
\warning this functions is getting very slow for large dataset, as for each point in the resulting histogram N kernel functions have to be evaluated.
|
||||
|
||||
\see en.wikipedia.org/wiki/Kernel_density_estimation, \ref JKQTPlotterBasicJKQTPDatastoreStatistics
|
||||
\see https://en.wikipedia.org/wiki/Kernel_density_estimation, \ref JKQTPlotterBasicJKQTPDatastoreStatistics
|
||||
*/
|
||||
template <class InputIt, class OutputIt>
|
||||
inline void jkqtpstatKDE1DAutoranged(InputIt first, InputIt last, OutputIt KDEXOut, OutputIt KDEYOut, int Nout=100, const std::function<double(double)>& kernel=std::function<double(double)>(&jkqtpstatKernel1DGaussian), double bandwidth=1.0, bool cummulative=false) {
|
||||
@ -1657,7 +1718,7 @@ inline void jkqtpstatKDE1DAutoranged(InputIt first, InputIt last, OutputIt KDEXO
|
||||
|
||||
\warning this functions is getting very slow for large dataset, as for each point in the resulting histogram N kernel functions have to be evaluated.
|
||||
|
||||
\see en.wikipedia.org/wiki/Kernel_density_estimation, \ref JKQTPlotterBasicJKQTPDatastoreStatistics
|
||||
\see https://en.wikipedia.org/wiki/Kernel_density_estimation, \ref JKQTPlotterBasicJKQTPDatastoreStatistics
|
||||
*/
|
||||
template <class InputIt, class OutputIt>
|
||||
inline void jkqtpstatKDE1DAutoranged(InputIt first, InputIt last, OutputIt KDEXOut, OutputIt KDEYOut, double binWidth, const std::function<double(double)>& kernel=std::function<double(double)>(&jkqtpstatKernel1DGaussian), double bandwidth=1.0, bool cummulative=false) {
|
||||
@ -1674,13 +1735,13 @@ inline void jkqtpstatKDE1DAutoranged(InputIt first, InputIt last, OutputIt KDEXO
|
||||
|
||||
// calculate the KDE
|
||||
for (int i=0; i<Nout; i++) {
|
||||
histX.push_back(minV+static_cast<double>(i)*binw+binw/2.0);
|
||||
histY.push_back(jkqtpstatEvaluateKernelSum(*(histX.end()), first, last, kernel, bandwidth));
|
||||
const double xi=minV+static_cast<double>(i)*binw+binw/2.0;
|
||||
histX.push_back(xi);
|
||||
histY.push_back(jkqtpstatEvaluateKernelSum(xi, first, last, kernel, bandwidth));
|
||||
}
|
||||
|
||||
|
||||
// output the KDE
|
||||
|
||||
double h=0;
|
||||
for (size_t i=0; i<histX.size(); i++) {
|
||||
*++KDEXOut=histX[i];
|
||||
@ -1709,7 +1770,7 @@ inline void jkqtpstatKDE1DAutoranged(InputIt first, InputIt last, OutputIt KDEXO
|
||||
\param bandwidth bandwidth used for the KDE
|
||||
\param cummulative if \c true, a cummulative KDE is calculated
|
||||
|
||||
\see en.wikipedia.org/wiki/Kernel_density_estimation, \ref JKQTPlotterBasicJKQTPDatastoreStatistics
|
||||
\see https://en.wikipedia.org/wiki/Kernel_density_estimation, \ref JKQTPlotterBasicJKQTPDatastoreStatistics
|
||||
*/
|
||||
template <class InputIt, class BinsInputIt, class OutputIt>
|
||||
inline void jkqtpstatKDE1D(InputIt first, InputIt last, BinsInputIt binsFirst, BinsInputIt binsLast, OutputIt KDEXOut, OutputIt KDEYOut, const std::function<double(double)>& kernel=std::function<double(double)>(&jkqtpstatKernel1DGaussian), double bandwidth=1.0, bool cummulative=false) {
|
||||
@ -1763,7 +1824,7 @@ inline void jkqtpstatKDE1D(InputIt first, InputIt last, BinsInputIt binsFirst, B
|
||||
\param bandwidth bandwidth used for the KDE
|
||||
\param cummulative if \c true, a cummulative KDE is calculated
|
||||
|
||||
\see en.wikipedia.org/wiki/Kernel_density_estimation, \ref JKQTPlotterBasicJKQTPDatastoreStatistics
|
||||
\see https://en.wikipedia.org/wiki/Kernel_density_estimation, \ref JKQTPlotterBasicJKQTPDatastoreStatistics
|
||||
*/
|
||||
template <class InputIt, class OutputIt>
|
||||
inline void jkqtpstatKDE1D(InputIt first, InputIt last, double binXLeft, double binXDelta, double binXRight, OutputIt KDEXOut, OutputIt KDEYOut, const std::function<double(double)>& kernel=std::function<double(double)>(&jkqtpstatKernel1DGaussian), double bandwidth=1.0, bool cummulative=false) {
|
||||
@ -1799,6 +1860,126 @@ inline void jkqtpstatKDE1D(InputIt first, InputIt last, double binXLeft, double
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \brief evaluates the Kernel Density Estimator (KDE) at a given position
|
||||
\ingroup jkqtptools_math_statistics_1dkde
|
||||
|
||||
evaluates \f[ \tilde{f}(x,y):=\frac{1}{N\cdot\sqrt{\text{bandwidthx}}\cdot\sqrt{\text{bandwidthy}}}\cdot\sum\limits_{i=0}^{N-1}K\left(\frac{x-x_i}{\text{bandwidthx}},\frac{y-y_i}{\text{bandwidthy}}\right) \f]
|
||||
|
||||
\tparam InputItX standard iterator type of \a firstX and \a lastX.
|
||||
\tparam InputItY standard iterator type of \a firstY and \a lastY.
|
||||
\param x where to evaluate the kernel sum, x-coordinate
|
||||
\param y where to evaluate the kernel sum, y-coordinate
|
||||
\param firstX iterator pointing to the first x-position item in the dataset to use \f$ X_1 \f$
|
||||
\param lastX iterator pointing behind the last x-position item in the dataset to use \f$ X_N \f$
|
||||
\param firstY iterator pointing to the first y-position item in the dataset to use \f$ Y_1 \f$
|
||||
\param lastY iterator pointing behind the last y-position item in the dataset to use \f$ Y_N \f$
|
||||
\param kernel the kernel function to use (e.g. jkqtpstatKernel1DGaussian() )
|
||||
\param kernel the kernel function to use (e.g. jkqtpstatKernel2DGaussian() )
|
||||
\param bandwidthX x-bandwidth used for the KDE
|
||||
\param bandwidthY y-bandwidth used for the KDE
|
||||
|
||||
*/
|
||||
template <class InputItX, class InputItY>
|
||||
inline double jkqtpstatEvaluateKernelSum2D(double x, double y, InputItX firstX, InputItX lastX, InputItY firstY, InputItY lastY, const std::function<double(double,double)>& kernel, double bandwidthX, double bandwidthY) {
|
||||
double res=0;
|
||||
size_t cnt=0;
|
||||
auto itX=firstX;
|
||||
auto itY=firstY;
|
||||
for (; (itX!=lastX)&&(itY!=lastY); ++itX, ++itY) {
|
||||
const double vx=jkqtp_todouble(*itX);
|
||||
const double vy=jkqtp_todouble(*itY);
|
||||
if (JKQTPIsOKFloat(vx) && JKQTPIsOKFloat(vy)) {
|
||||
const double vvx=(x-vx)/bandwidthX;
|
||||
const double vvy=(y-vy)/bandwidthY;
|
||||
res+=kernel(vvx,vvy);
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
if (cnt==0) return 0.0;
|
||||
return res/static_cast<double>(cnt)/sqrt(bandwidthX*bandwidthY);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \brief calculate an autoranged 2-dimensional Kernel Density Estimation (KDE) from the given data range \a firstX / \a firstY ... \a lastY / \a lastY
|
||||
\ingroup jkqtptools_math_statistics_2dkde
|
||||
|
||||
\tparam InputItX standard iterator type of \a firstX and \a lastX.
|
||||
\tparam InputItY standard iterator type of \a firstY and \a lastY.
|
||||
\tparam OutputIt standard output iterator type used for the outliers output \a histogramXOut and \a histogramYOut, use e.g. std::back_inserter
|
||||
\param firstX iterator pointing to the first x-position item in the dataset to use \f$ X_1 \f$
|
||||
\param lastX iterator pointing behind the last x-position item in the dataset to use \f$ X_N \f$
|
||||
\param firstY iterator pointing to the first y-position item in the dataset to use \f$ Y_1 \f$
|
||||
\param lastY iterator pointing behind the last y-position item in the dataset to use \f$ Y_N \f$
|
||||
\param[out] histogramImgOut output iterator that receives counts of the histogram bins in row-major ordering
|
||||
\param xmin position of the first histogram bin in x-direction
|
||||
\param xmax position of the last histogram bin in x-direction
|
||||
\param ymin position of the first histogram bin in y-direction
|
||||
\param ymax position of the last histogram bin in y-direction
|
||||
\param xbins number of bins in x-direction (i.e. width of the output histogram \a histogramImgOut )
|
||||
\param ybins number of bins in y-direction (i.e. height of the output histogram \a histogramImgOut )
|
||||
\param kernel the kernel function to use (e.g. jkqtpstatKernel2DGaussian() )
|
||||
\param bandwidthX x-bandwidth used for the KDE
|
||||
\param bandwidthY y-bandwidth used for the KDE
|
||||
|
||||
\see https://en.wikipedia.org/wiki/Multivariate_kernel_density_estimation, \ref JKQTPlotterBasicJKQTPDatastoreStatistics
|
||||
*/
|
||||
|
||||
template <class InputItX, class InputItY, class OutputIt>
|
||||
inline void jkqtpstatKDE2D(InputItX firstX, InputItX lastX, InputItY firstY, InputItY lastY, OutputIt histogramImgOut, double xmin, double xmax, double ymin, double ymax, size_t xbins, size_t ybins, const std::function<double(double,double)>& kernel=std::function<double(double,double)>(&jkqtpstatKernel2DGaussian), double bandwidthX=1.0, double bandwidthY=1.0) {
|
||||
|
||||
const double binwx=fabs(xmax-xmin)/static_cast<double>(xbins);
|
||||
const double binwy=fabs(ymax-ymin)/static_cast<double>(ybins);
|
||||
|
||||
double y=ymin;
|
||||
auto itOut=histogramImgOut;
|
||||
for (size_t by=0; by<ybins; by++) {
|
||||
double x=xmin;
|
||||
for (size_t bx=0; bx<xbins; bx++) {
|
||||
const double vv=jkqtpstatEvaluateKernelSum2D(x,y, firstX, lastX,firstY,lastY, kernel, bandwidthX,bandwidthY);
|
||||
*itOut=vv;
|
||||
//std::cout<<x<<","<<y<<","<<vv<<*itOut<<std::endl;
|
||||
x+=binwx;
|
||||
++itOut;
|
||||
}
|
||||
y+=binwy;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \brief estimates a bandwidth for a 2-dimensional Kernel Density Estimator (KDE) of the given data \a first ... \a last using Scott's rule
|
||||
\ingroup jkqtptools_math_statistics_2dkde
|
||||
|
||||
evaluates \f[ h = \hat{\sigma} n^{-1/(d+4)},\ \ \ \ \ d=2 \f]
|
||||
|
||||
\tparam InputIt standard iterator type of \a first and \a last.
|
||||
\param first iterator pointing to the first item in the dataset to use \f$ X_1 \f$
|
||||
\param last iterator pointing behind the last item in the dataset to use \f$ X_N \f$
|
||||
\return the estimated bandwidth
|
||||
|
||||
\see https://en.wikipedia.org/wiki/Multivariate_kernel_density_estimation#Rule_of_thumb
|
||||
|
||||
*/
|
||||
template <class InputIt>
|
||||
inline double jkqtpstatEstimateKDEBandwidth2D(InputIt first, InputIt last) {
|
||||
size_t N=0;
|
||||
const double sigma=jkqtpstatStdDev(first, last, nullptr, &N);
|
||||
return sigma/pow(static_cast<double>(N), 1.0/(2.0+4.0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \brief calculate the linear regression coefficients for a given data range \a firstX / \a firstY ... \a lastX / \a lastY where the model is \f$ f(x)=a+b\cdot x \f$
|
||||
So this function solves the least-squares optimization problem: \f[ (a^\ast, b^\ast)=\mathop{\mathrm{arg\;min}}\limits_{a,b}\sum\limits_i\left(y_i-(a+b\cdot x_i)\right)^2 \f]
|
||||
\ingroup jkqtptools_math_statistics_regression
|
||||
@ -2496,6 +2677,129 @@ inline double jkqtpstatWeightedSumOfDeviations(InputItX firstX, InputItX lastX,
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///*! \brief evaluates the Kernel Density Estimator (KDE) at a given position
|
||||
// \ingroup jkqtptools_math_statistics_2dkde
|
||||
|
||||
// evaluates \f[ \tilde{f}(t_x, t_y):=\frac{1}{N\cdot\sqrt{\text{bandwidthX}*\text{bandwidthY}}}\cdot\sum\limits_{i=0}^{N-1}K\left(\frac{t_x-x_i}{\text{bandwidthX}}, \frac{t_y-y_i}{\text{bandwidthY}}\right) \f]
|
||||
|
||||
// \param tx evaluate at this x-coordinate
|
||||
// \param ty evaluate at this y-coordinate
|
||||
// \param inputX input data array x-values
|
||||
// \param inputY input data array y-values
|
||||
// \param mask if \c !=nullptr use only the datapoints, where \c mask[i]==maskUseValue
|
||||
// \param N number of entries in mask and input
|
||||
// \param kernel a kernel function or functor, e.g. jkqtpstatKernel2DGaussian()
|
||||
// \param bandwidthX a smoothing parameter in x direction
|
||||
// \param bandwidthY a smoothing parameter in y direction
|
||||
// \param maskUseValue see mask
|
||||
|
||||
//*/
|
||||
//template <class T, class THIST, typename TKERNEL>
|
||||
//inline THIST jkqtpstatEvaluate2DKernelSum(THIST tx, THIST ty, const T* inputX, const T* inputY, const bool* mask, long long N, TKERNEL kernel, THIST bandwidthX=1.0, THIST bandwidthY=1.0, bool maskUseValue=false) {
|
||||
// if (!inputX || !inputY || N<=0) return 0.0;
|
||||
|
||||
// THIST res=0;
|
||||
// THIST cnt=0;
|
||||
// for (long long i=0; i<N; i++) {
|
||||
// if ((!mask || mask[i]==maskUseValue) && JKQTPIsOKFloat(inputX[i]) && JKQTPIsOKFloat(inputY[i])) {
|
||||
// const THIST vx=(tx-(THIST)inputX[i])/bandwidthX;
|
||||
// const THIST vy=(ty-(THIST)inputY[i])/bandwidthY;
|
||||
// res+=kernel(vx, vy);
|
||||
// cnt++;
|
||||
// }
|
||||
// }
|
||||
// return res/cnt/sqrt(bandwidthX)/sqrt(bandwidthY);
|
||||
//}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///*! \brief calculates a running average over the given data, the returned array is smaller (N-avgSize) than the input. The new size is returned, or the old size on error
|
||||
// \ingroup jkqtptools_math_statistics
|
||||
|
||||
//*/
|
||||
//template <class T>
|
||||
//inline int jkqtpstatRunningAverage(T* data, long long N, int avgSize) {
|
||||
// if (N>=avgSize && data) {
|
||||
// int it=0;
|
||||
// while (it<N-avgSize) {
|
||||
// T s=0;
|
||||
// for (int i=it; i<it+avgSize; i++) {
|
||||
// s+=data[i];
|
||||
// }
|
||||
// data[it]=s/T(avgSize);
|
||||
// it++;
|
||||
// }
|
||||
// return N-avgSize;
|
||||
// }
|
||||
// return N;
|
||||
//}
|
||||
|
||||
///*! \brief calculates a running average over the given data, the returned array is smaller (N-avgSize) than the input. The new size is returned, or the old size on error
|
||||
// \ingroup jkqtptools_math_statistics
|
||||
|
||||
// if dataX is given, it is also reduced to the new x values.
|
||||
//*/
|
||||
//template <class T>
|
||||
//inline int jkqtpstatRunningAverage(T* dataX, T* data, long long N, int avgSize) {
|
||||
// if (N>=avgSize && data) {
|
||||
// int it=0;
|
||||
// while (it<N-avgSize) {
|
||||
// T s=0;
|
||||
// T sX=0;
|
||||
// for (int i=it; i<it+avgSize; i++) {
|
||||
// s+=data[i];
|
||||
// sX+=dataX[i];
|
||||
// }
|
||||
// data[it]=s/T(avgSize);
|
||||
// dataX[it]=sX/T(avgSize);
|
||||
// it++;
|
||||
// }
|
||||
// return N-avgSize;
|
||||
// }
|
||||
// return N;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///*! \brief lookup the given value \a data in the given \a lut, which images the range \a lmin ... \lmax to \a lut_size values of type TLUT.
|
||||
// \ingroup jkqtptools_math_statistics
|
||||
|
||||
// If the given data is out of range, then the nearest lut bound is returned.
|
||||
//*/
|
||||
//template <class T, class TLUT>
|
||||
//inline TLUT jkqtpstatLookupLUT(const T& data, const T& lmin, const T& lmax, const TLUT* lut, int lut_size) {
|
||||
// if (!lut || lut_size<=0) return 0;
|
||||
// int idx=(data-lmin)*T(lut_size-1)/(lmax-lmin);
|
||||
// if (idx<0) return lut[0];
|
||||
// else if (idx>=lut_size) return lut[lut_size-1];
|
||||
// return lut[idx];
|
||||
//}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // JKQTPSTATISTICSTOOLS_H_INCLUDED
|
||||
|
||||
|
||||
|
@ -28,6 +28,9 @@
|
||||
#include "jkqtplotter/jkqtpgraphssinglecolumnsymbols.h"
|
||||
#include "jkqtplotter/jkqtpgraphsbarchart.h"
|
||||
#include "jkqtplotter/jkqtpgraphsevaluatedfunction.h"
|
||||
#include "jkqtplotter/jkqtpgraphsimage.h"
|
||||
#include "jkqtplotter/jkqtpgraphscontour.h"
|
||||
|
||||
|
||||
#ifndef JKQTPGRAPHSSTATISTICSADAPTORS_H_INCLUDED
|
||||
#define JKQTPGRAPHSSTATISTICSADAPTORS_H_INCLUDED
|
||||
@ -389,8 +392,8 @@ inline JKQTPBarHorizontalGraph* jkqtpstatAddVHistogram1DAutoranged(JKQTBasePlott
|
||||
size_t histcolY=plotter->getDatastore()->addColumn(histogramcolumnBaseName+", values");
|
||||
jkqtpstatHistogram1DAutoranged(first, last, plotter->getDatastore()->backInserter(histcolX), plotter->getDatastore()->backInserter(histcolY), bins, normalized, cummulative, JKQTPStatHistogramBinXMode::XIsMid);
|
||||
JKQTPBarHorizontalGraph* resO=new JKQTPBarHorizontalGraph(plotter);
|
||||
resO->setXColumn(histcolX);
|
||||
resO->setYColumn(histcolY);
|
||||
resO->setXColumn(histcolY);
|
||||
resO->setYColumn(histcolX);
|
||||
resO->setTitle(histogramcolumnBaseName);
|
||||
plotter->addGraph(resO);
|
||||
return resO;
|
||||
@ -425,8 +428,8 @@ inline JKQTPBarHorizontalGraph* jkqtpstatAddVHistogram1DAutoranged(JKQTBasePlott
|
||||
size_t histcolY=plotter->getDatastore()->addColumn(histogramcolumnBaseName+", values");
|
||||
jkqtpstatHistogram1DAutoranged(first, last, plotter->getDatastore()->backInserter(histcolX), plotter->getDatastore()->backInserter(histcolY), binWidth, normalized, cummulative, JKQTPStatHistogramBinXMode::XIsMid);
|
||||
JKQTPBarHorizontalGraph* resO=new JKQTPBarHorizontalGraph(plotter);
|
||||
resO->setXColumn(histcolX);
|
||||
resO->setYColumn(histcolY);
|
||||
resO->setXColumn(histcolY);
|
||||
resO->setYColumn(histcolX);
|
||||
resO->setTitle(histogramcolumnBaseName);
|
||||
plotter->addGraph(resO);
|
||||
return resO;
|
||||
@ -463,8 +466,8 @@ inline JKQTPBarHorizontalGraph* jkqtpstatAddVHistogram1D(JKQTBasePlotter* plotte
|
||||
size_t histcolY=plotter->getDatastore()->addColumn(histogramcolumnBaseName+", values");
|
||||
jkqtpstatHistogram1D(first, last, binsFirst, binsLast, plotter->getDatastore()->backInserter(histcolX), plotter->getDatastore()->backInserter(histcolY), normalized, cummulative, JKQTPStatHistogramBinXMode::XIsMid);
|
||||
JKQTPBarHorizontalGraph* resO=new JKQTPBarHorizontalGraph(plotter);
|
||||
resO->setXColumn(histcolX);
|
||||
resO->setYColumn(histcolY);
|
||||
resO->setXColumn(histcolY);
|
||||
resO->setYColumn(histcolX);
|
||||
resO->setTitle(histogramcolumnBaseName);
|
||||
plotter->addGraph(resO);
|
||||
return resO;
|
||||
@ -477,6 +480,221 @@ inline JKQTPBarHorizontalGraph* jkqtpstatAddVHistogram1D(JKQTBasePlotter* plotte
|
||||
|
||||
|
||||
|
||||
/*! \brief calculate calculate a 2-dimensional histogram and add a JKQTPColumnMathImage to the given plotter, where the histogram is calculated from the given data range \a firstX / \a firstY ... \a lastY / \a lastY
|
||||
\ingroup jkqtptools_math_statistics_adaptors
|
||||
|
||||
\tparam InputItX standard iterator type of \a firstX and \a lastX.
|
||||
\tparam InputItY standard iterator type of \a firstY and \a lastY.
|
||||
\param plotter the plotter to which to add the resulting graph
|
||||
\param firstX iterator pointing to the first x-position item in the dataset to use \f$ X_1 \f$
|
||||
\param lastX iterator pointing behind the last x-position item in the dataset to use \f$ X_N \f$
|
||||
\param firstY iterator pointing to the first y-position item in the dataset to use \f$ Y_1 \f$
|
||||
\param lastY iterator pointing behind the last y-position item in the dataset to use \f$ Y_N \f$
|
||||
\param xbins number of bins in x-direction
|
||||
\param ybins number of bins in y-direction
|
||||
\param normalized indicates whether the histogram has to be normalized
|
||||
\param histogramcolumnBaseName this string is used in building the column names for the histogram data columns
|
||||
\param[out] oxmin position of the first histogram bin in x-direction
|
||||
\param[out] oxmax position of the last histogram bin in x-direction
|
||||
\param[out] oymin position of the first histogram bin in y-direction
|
||||
\param[out] oymax position of the last histogram bin in y-direction
|
||||
\return a graph class pointer (of type \c JKQTPColumnMathImage ) displaying the histogram data
|
||||
|
||||
\image html jkqtplotter_simpletest_datastore_statistics_2d_hist.png
|
||||
|
||||
\see jkqtpstatHistogram2D(), \ref JKQTPlotterBasicJKQTPDatastoreStatistics2D
|
||||
*/
|
||||
template <class InputItX, class InputItY>
|
||||
inline JKQTPColumnMathImage* jkqtpstatAddHistogram2DImage(JKQTBasePlotter* plotter, InputItX firstX, InputItX lastX, InputItY firstY, InputItY lastY, size_t xbins=10, size_t ybins=10, bool normalized=true, const QString& histogramcolumnBaseName=QString("histogram"), double* oxmin=nullptr, double* oxmax=nullptr, double* oymin=nullptr, double* oymax=nullptr) {
|
||||
double xmin=0, xmax=0;
|
||||
double ymin=0, ymax=0;
|
||||
jkqtpstatMinMax(firstX,lastX, xmin,xmax);
|
||||
jkqtpstatMinMax(firstY,lastY, ymin,ymax);
|
||||
size_t histcol=plotter->getDatastore()->addImageColumn(xbins, ybins, histogramcolumnBaseName);
|
||||
jkqtpstatHistogram2D(firstX,lastX,firstY,lastY,
|
||||
plotter->getDatastore()->begin(histcol),
|
||||
xmin, xmax, ymin, ymax,
|
||||
xbins, ybins, normalized);
|
||||
JKQTPColumnMathImage* gHist;
|
||||
plotter->addGraph(gHist=new JKQTPColumnMathImage(plotter));
|
||||
gHist->setImageColumn(static_cast<int>(histcol));
|
||||
gHist->setX(xmin);
|
||||
gHist->setY(ymin);
|
||||
gHist->setWidth(xmax-xmin);
|
||||
gHist->setHeight(ymax-ymin);
|
||||
gHist->setTitle(QObject::tr("2D Histogram"));
|
||||
if (oxmax) *oxmax=xmax;
|
||||
if (oxmin) *oxmin=xmin;
|
||||
if (oymax) *oymax=ymax;
|
||||
if (oymin) *oymin=ymin;
|
||||
return gHist;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \brief calculate calculate a 2-dimensional histogram and add a JKQTPColumnContourPlot to the given plotter, where the histogram is calculated from the given data range \a firstX / \a firstY ... \a lastY / \a lastY
|
||||
\ingroup jkqtptools_math_statistics_adaptors
|
||||
|
||||
\tparam InputItX standard iterator type of \a firstX and \a lastX.
|
||||
\tparam InputItY standard iterator type of \a firstY and \a lastY.
|
||||
\param plotter the plotter to which to add the resulting graph
|
||||
\param firstX iterator pointing to the first x-position item in the dataset to use \f$ X_1 \f$
|
||||
\param lastX iterator pointing behind the last x-position item in the dataset to use \f$ X_N \f$
|
||||
\param firstY iterator pointing to the first y-position item in the dataset to use \f$ Y_1 \f$
|
||||
\param lastY iterator pointing behind the last y-position item in the dataset to use \f$ Y_N \f$
|
||||
\param xbins number of bins in x-direction
|
||||
\param ybins number of bins in y-direction
|
||||
\param normalized indicates whether the histogram has to be normalized
|
||||
\param histogramcolumnBaseName this string is used in building the column names for the histogram data columns
|
||||
\param[out] oxmin position of the first histogram bin in x-direction
|
||||
\param[out] oxmax position of the last histogram bin in x-direction
|
||||
\param[out] oymin position of the first histogram bin in y-direction
|
||||
\param[out] oymax position of the last histogram bin in y-direction
|
||||
\return a graph class pointer (of type \c JKQTPColumnContourPlot ) displaying the histogram data as a contour plot
|
||||
|
||||
\image html jkqtplotter_simpletest_datastore_statistics_2d_histcontour.png
|
||||
|
||||
\see jkqtpstatHistogram2D(), \ref JKQTPlotterBasicJKQTPDatastoreStatistics2D
|
||||
*/
|
||||
template <class InputItX, class InputItY>
|
||||
inline JKQTPColumnContourPlot* jkqtpstatAddHistogram2DContour(JKQTBasePlotter* plotter, InputItX firstX, InputItX lastX, InputItY firstY, InputItY lastY, size_t xbins=10, size_t ybins=10, bool normalized=true, const QString& histogramcolumnBaseName=QString("histogram"), double* oxmin=nullptr, double* oxmax=nullptr, double* oymin=nullptr, double* oymax=nullptr) {
|
||||
double xmin=0, xmax=0;
|
||||
double ymin=0, ymax=0;
|
||||
jkqtpstatMinMax(firstX,lastX, xmin,xmax);
|
||||
jkqtpstatMinMax(firstY,lastY, ymin,ymax);
|
||||
size_t histcol=plotter->getDatastore()->addImageColumn(xbins, ybins, histogramcolumnBaseName);
|
||||
jkqtpstatHistogram2D(firstX,lastX,firstY,lastY,
|
||||
plotter->getDatastore()->begin(histcol),
|
||||
xmin, xmax, ymin, ymax,
|
||||
xbins, ybins, true);
|
||||
JKQTPColumnContourPlot* gHist;
|
||||
plotter->addGraph(gHist=new JKQTPColumnContourPlot(plotter));
|
||||
gHist->setImageColumn(static_cast<int>(histcol));
|
||||
gHist->setX(xmin);
|
||||
gHist->setY(ymin);
|
||||
gHist->setWidth(xmax-xmin);
|
||||
gHist->setHeight(ymax-ymin);
|
||||
gHist->setTitle(QObject::tr("2D Histogram"));
|
||||
gHist->createContourLevels(5);
|
||||
if (oxmax) *oxmax=xmax;
|
||||
if (oxmin) *oxmin=xmin;
|
||||
if (oymax) *oymax=ymax;
|
||||
if (oymin) *oymin=ymin;
|
||||
return gHist;
|
||||
}
|
||||
/*! \brief calculate calculate a 2-dimensional histogram and add a JKQTPColumnMathImage to the given plotter, where the histogram is calculated from the given data range \a firstX / \a firstY ... \a lastY / \a lastY
|
||||
\ingroup jkqtptools_math_statistics_adaptors
|
||||
|
||||
\tparam InputItX standard iterator type of \a firstX and \a lastX.
|
||||
\tparam InputItY standard iterator type of \a firstY and \a lastY.
|
||||
\param plotter the plotter to which to add the resulting graph
|
||||
\param firstX iterator pointing to the first x-position item in the dataset to use \f$ X_1 \f$
|
||||
\param lastX iterator pointing behind the last x-position item in the dataset to use \f$ X_N \f$
|
||||
\param firstY iterator pointing to the first y-position item in the dataset to use \f$ Y_1 \f$
|
||||
\param lastY iterator pointing behind the last y-position item in the dataset to use \f$ Y_N \f$
|
||||
\param xbinwidth width of bins in x-direction
|
||||
\param ybinwidth width of bins in y-direction
|
||||
\param normalized indicates whether the histogram has to be normalized
|
||||
\param histogramcolumnBaseName this string is used in building the column names for the histogram data columns
|
||||
\param[out] oxmin position of the first histogram bin in x-direction
|
||||
\param[out] oxmax position of the last histogram bin in x-direction
|
||||
\param[out] oymin position of the first histogram bin in y-direction
|
||||
\param[out] oymax position of the last histogram bin in y-direction
|
||||
\return a graph class pointer (of type \c JKQTPColumnMathImage ) displaying the histogram data
|
||||
|
||||
\image html jkqtplotter_simpletest_datastore_statistics_2d_hist.png
|
||||
|
||||
\see jkqtpstatHistogram2D(), \ref JKQTPlotterBasicJKQTPDatastoreStatistics2D
|
||||
*/
|
||||
template <class InputItX, class InputItY>
|
||||
inline JKQTPColumnMathImage* jkqtpstatAddHistogram2DImage(JKQTBasePlotter* plotter, InputItX firstX, InputItX lastX, InputItY firstY, InputItY lastY, double xbinwidth, double ybinwidth, bool normalized=true, const QString& histogramcolumnBaseName=QString("histogram"), double* oxmin=nullptr, double* oxmax=nullptr, double* oymin=nullptr, double* oymax=nullptr) {
|
||||
double xmin=0, xmax=0;
|
||||
double ymin=0, ymax=0;
|
||||
jkqtpstatMinMax(firstX,lastX, xmin,xmax);
|
||||
jkqtpstatMinMax(firstY,lastY, ymin,ymax);
|
||||
size_t Nx=jkqtp_ceilTo<size_t>((xmax-xmin)/xbinwidth);
|
||||
size_t Ny=jkqtp_ceilTo<size_t>((ymax-ymin)/ybinwidth);
|
||||
size_t histcol=plotter->getDatastore()->addImageColumn(Nx, Ny, histogramcolumnBaseName);
|
||||
jkqtpstatHistogram2D(firstX,lastX,firstY,lastY,
|
||||
plotter->getDatastore()->begin(histcol),
|
||||
xmin, xmax, ymin, ymax,
|
||||
Nx, Ny, normalized);
|
||||
JKQTPColumnMathImage* gHist;
|
||||
plotter->addGraph(gHist=new JKQTPColumnMathImage(plotter));
|
||||
gHist->setImageColumn(static_cast<int>(histcol));
|
||||
gHist->setX(xmin);
|
||||
gHist->setY(ymin);
|
||||
gHist->setWidth(xmax-xmin);
|
||||
gHist->setHeight(ymax-ymin);
|
||||
gHist->setTitle(QObject::tr("2D Histogram"));
|
||||
if (oxmax) *oxmax=xmax;
|
||||
if (oxmin) *oxmin=xmin;
|
||||
if (oymax) *oymax=ymax;
|
||||
if (oymin) *oymin=ymin;
|
||||
return gHist;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \brief calculate calculate a 2-dimensional histogram and add a JKQTPColumnContourPlot to the given plotter, where the histogram is calculated from the given data range \a firstX / \a firstY ... \a lastY / \a lastY
|
||||
\ingroup jkqtptools_math_statistics_adaptors
|
||||
|
||||
\tparam InputItX standard iterator type of \a firstX and \a lastX.
|
||||
\tparam InputItY standard iterator type of \a firstY and \a lastY.
|
||||
\param plotter the plotter to which to add the resulting graph
|
||||
\param firstX iterator pointing to the first x-position item in the dataset to use \f$ X_1 \f$
|
||||
\param lastX iterator pointing behind the last x-position item in the dataset to use \f$ X_N \f$
|
||||
\param firstY iterator pointing to the first y-position item in the dataset to use \f$ Y_1 \f$
|
||||
\param lastY iterator pointing behind the last y-position item in the dataset to use \f$ Y_N \f$
|
||||
\param xbinwidth width of bins in x-direction
|
||||
\param ybinwidth width of bins in y-direction
|
||||
\param normalized indicates whether the histogram has to be normalized
|
||||
\param histogramcolumnBaseName this string is used in building the column names for the histogram data columns
|
||||
\param[out] oxmin position of the first histogram bin in x-direction
|
||||
\param[out] oxmax position of the last histogram bin in x-direction
|
||||
\param[out] oymin position of the first histogram bin in y-direction
|
||||
\param[out] oymax position of the last histogram bin in y-direction
|
||||
\return a graph class pointer (of type \c JKQTPColumnContourPlot ) displaying the histogram data as a contour plot
|
||||
|
||||
\image html jkqtplotter_simpletest_datastore_statistics_2d_histcontour.png
|
||||
|
||||
\see jkqtpstatHistogram2D(), \ref JKQTPlotterBasicJKQTPDatastoreStatistics2D
|
||||
|
||||
*/
|
||||
template <class InputItX, class InputItY>
|
||||
inline JKQTPColumnContourPlot* jkqtpstatAddHistogram2DContour(JKQTBasePlotter* plotter, InputItX firstX, InputItX lastX, InputItY firstY, InputItY lastY, double xbinwidth, double ybinwidth, bool normalized=true, const QString& histogramcolumnBaseName=QString("histogram"), double* oxmin=nullptr, double* oxmax=nullptr, double* oymin=nullptr, double* oymax=nullptr) {
|
||||
double xmin=0, xmax=0;
|
||||
double ymin=0, ymax=0;
|
||||
jkqtpstatMinMax(firstX,lastX, xmin,xmax);
|
||||
jkqtpstatMinMax(firstY,lastY, ymin,ymax);
|
||||
size_t Nx=jkqtp_ceilTo<size_t>((xmax-xmin)/xbinwidth);
|
||||
size_t Ny=jkqtp_ceilTo<size_t>((ymax-ymin)/ybinwidth);
|
||||
size_t histcol=plotter->getDatastore()->addImageColumn(Nx, Ny, histogramcolumnBaseName);
|
||||
jkqtpstatHistogram2D(firstX,lastX,firstY,lastY,
|
||||
plotter->getDatastore()->begin(histcol),
|
||||
xmin, xmax, ymin, ymax,
|
||||
Nx, Ny, normalized);
|
||||
JKQTPColumnContourPlot* gHist;
|
||||
plotter->addGraph(gHist=new JKQTPColumnContourPlot(plotter));
|
||||
gHist->setImageColumn(static_cast<int>(histcol));
|
||||
gHist->setX(xmin);
|
||||
gHist->setY(ymin);
|
||||
gHist->setWidth(xmax-xmin);
|
||||
gHist->setHeight(ymax-ymin);
|
||||
gHist->setTitle(QObject::tr("2D Histogram"));
|
||||
gHist->createContourLevels(5);
|
||||
if (oxmax) *oxmax=xmax;
|
||||
if (oxmin) *oxmin=xmin;
|
||||
if (oymax) *oymax=ymax;
|
||||
if (oymin) *oymin=ymin;
|
||||
return gHist;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -651,6 +869,312 @@ inline JKQTPXYLineGraph* jkqtpstatAddHKDE1D(JKQTBasePlotter* plotter, InputIt fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \brief calculate an autoranged vertical KDE and add a JKQTPXYLineGraph to the given plotter, where the KDE is calculated from the data range \a first ... \a last, bins defined by their number
|
||||
\ingroup jkqtptools_math_statistics_adaptors
|
||||
|
||||
|
||||
\tparam InputIt standard iterator type of \a first and \a last.
|
||||
\param plotter the plotter to which to add the resulting graph
|
||||
\param first iterator pointing to the first item in the dataset to use \f$ X_1 \f$
|
||||
\param last iterator pointing behind the last item in the dataset to use \f$ X_N \f$
|
||||
\param Nout number of points in the resulting KDE
|
||||
\param kernel the kernel function to use (e.g. jkqtpstatKernel1DGaussian() )
|
||||
\param bandwidth bandwidth used for the KDE
|
||||
\param cummulative if \c true, a cummulative KDE is calculated
|
||||
\param KDEcolumnBaseName this string is used in building the column names for the KDE data columns
|
||||
\return a graph class pointer (of type \a GraphClass ) displaying the KDE data
|
||||
|
||||
Example:
|
||||
\code
|
||||
jkqtpstatAddVKDE1DAutoranged(plot1->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), 200);
|
||||
\endcode
|
||||
|
||||
\image html jkqtplotter_simpletest_datastore_statistics_kde.png
|
||||
|
||||
|
||||
\see \ref JKQTPlotterBasicJKQTPDatastoreStatistics, jkqtpstatKDE1DAutoranged(), JKQTPXYLineGraph
|
||||
*/
|
||||
template <class InputIt>
|
||||
inline JKQTPXYLineGraph* jkqtpstatAddVKDE1DAutoranged(JKQTBasePlotter* plotter, InputIt first, InputIt last, int Nout=100, const std::function<double(double)>& kernel=std::function<double(double)>(&jkqtpstatKernel1DGaussian), double bandwidth=1.0, bool cummulative=false, const QString& KDEcolumnBaseName=QString("KDE")) {
|
||||
size_t histcolX=plotter->getDatastore()->addColumn(KDEcolumnBaseName+", positions");
|
||||
size_t histcolY=plotter->getDatastore()->addColumn(KDEcolumnBaseName+", values");
|
||||
jkqtpstatKDE1DAutoranged(first, last, plotter->getDatastore()->backInserter(histcolX), plotter->getDatastore()->backInserter(histcolY), Nout, kernel, bandwidth, cummulative);
|
||||
JKQTPXYLineGraph* resO=new JKQTPXYLineGraph(plotter);
|
||||
resO->setXColumn(histcolY);
|
||||
resO->setYColumn(histcolX);
|
||||
resO->setTitle(KDEcolumnBaseName);
|
||||
resO->setDrawLine(true);
|
||||
resO->setSymbolType(JKQTPNoSymbol);
|
||||
plotter->addGraph(resO);
|
||||
return resO;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*! \brief calculate an autoranged vertical KDE and add a JKQTPXYLineGraph to the given plotter, where the KDE is calculated from the data range \a first ... \a last, bins defined by their width
|
||||
\ingroup jkqtptools_math_statistics_adaptors
|
||||
|
||||
|
||||
\tparam InputIt standard iterator type of \a first and \a last.
|
||||
\param plotter the plotter to which to add the resulting graph
|
||||
\param first iterator pointing to the first item in the dataset to use \f$ X_1 \f$
|
||||
\param last iterator pointing behind the last item in the dataset to use \f$ X_N \f$
|
||||
\param binWidth width of the bins
|
||||
\param kernel the kernel function to use (e.g. jkqtpstatKernel1DGaussian() )
|
||||
\param bandwidth bandwidth used for the KDE
|
||||
\param cummulative if \c true, a cummulative KDE is calculated
|
||||
\param KDEcolumnBaseName this string is used in building the column names for the KDE data columns
|
||||
\return a graph class pointer (of type \a GraphClass ) displaying the KDE data
|
||||
|
||||
Example:
|
||||
\code
|
||||
jkqtpstatAddVKDE1DAutoranged(plot1->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), 0.01);
|
||||
\endcode
|
||||
|
||||
\image html jkqtplotter_simpletest_datastore_statistics_kde.png
|
||||
|
||||
|
||||
\see \ref JKQTPlotterBasicJKQTPDatastoreStatistics, jkqtpstatKDE1DAutoranged(), JKQTPXYLineGraph
|
||||
*/
|
||||
template <class InputIt>
|
||||
inline JKQTPXYLineGraph* jkqtpstatAddVKDE1DAutoranged(JKQTBasePlotter* plotter, InputIt first, InputIt last, double binWidth, const std::function<double(double)>& kernel=std::function<double(double)>(&jkqtpstatKernel1DGaussian), double bandwidth=1.0, bool cummulative=false, const QString& KDEcolumnBaseName=QString("KDE")) {
|
||||
size_t histcolX=plotter->getDatastore()->addColumn(KDEcolumnBaseName+", bins");
|
||||
size_t histcolY=plotter->getDatastore()->addColumn(KDEcolumnBaseName+", values");
|
||||
jkqtpstatKDE1DAutoranged(first, last, plotter->getDatastore()->backInserter(histcolX), plotter->getDatastore()->backInserter(histcolY), binWidth, kernel, bandwidth, cummulative);
|
||||
JKQTPXYLineGraph* resO=new JKQTPXYLineGraph(plotter);
|
||||
resO->setXColumn(histcolY);
|
||||
resO->setYColumn(histcolX);
|
||||
resO->setTitle(KDEcolumnBaseName);
|
||||
resO->setDrawLine(true);
|
||||
resO->setSymbolType(JKQTPNoSymbol);
|
||||
plotter->addGraph(resO);
|
||||
return resO;
|
||||
}
|
||||
|
||||
|
||||
/*! \brief calculate an autoranged vertical KDE and add a JKQTPXYLineGraph to the given plotter, where the KDE is calculated from the data range \a first ... \a last, bins defined by their width
|
||||
\ingroup jkqtptools_math_statistics_adaptors
|
||||
|
||||
|
||||
\tparam InputIt standard iterator type of \a first and \a last.
|
||||
\tparam BinsInputIt standard iterator type of \a binsFirst and \a binsLast.
|
||||
\param plotter the plotter to which to add the resulting graph
|
||||
\param first iterator pointing to the first item in the dataset to use \f$ X_1 \f$
|
||||
\param last iterator pointing behind the last item in the dataset to use \f$ X_N \f$
|
||||
\param binsFirst iterator pointing to the first item in the set of KDE bins
|
||||
\param binsLast iterator pointing behind the last item in the set of KDE bins
|
||||
\param kernel the kernel function to use (e.g. jkqtpstatKernel1DGaussian() )
|
||||
\param bandwidth bandwidth used for the KDE
|
||||
\param cummulative if \c true, a cummulative KDE is calculated
|
||||
\param KDEcolumnBaseName this string is used in building the column names for the KDE data columns
|
||||
\return a graph class pointer (of type \a GraphClass ) displaying the KDE data
|
||||
|
||||
Example:
|
||||
\code
|
||||
std::vector<double> bins{-2,-1.5,-1,-0.75,-0.5,-0.25,0,0.25,0.5,0.75,1,1.5,2,2.5,3,4,5,6,7,8,9,10};
|
||||
jkqtpstatAddVKDE1D(plot1->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), bins.begin(), bins.end());
|
||||
\endcode
|
||||
|
||||
\image html jkqtplotter_simpletest_datastore_statistics_kde.png
|
||||
|
||||
|
||||
\see \ref JKQTPlotterBasicJKQTPDatastoreStatistics, jkqtpstatKDE1D(), JKQTPXYLineGraph
|
||||
*/
|
||||
template <class InputIt, class BinsInputIt>
|
||||
inline JKQTPXYLineGraph* jkqtpstatAddVKDE1D(JKQTBasePlotter* plotter, InputIt first, InputIt last, BinsInputIt binsFirst, BinsInputIt binsLast, const std::function<double(double)>& kernel=std::function<double(double)>(&jkqtpstatKernel1DGaussian), double bandwidth=1.0, bool cummulative=false, const QString& KDEcolumnBaseName=QString("KDE")) {
|
||||
size_t histcolX=plotter->getDatastore()->addColumn(KDEcolumnBaseName+", bins");
|
||||
size_t histcolY=plotter->getDatastore()->addColumn(KDEcolumnBaseName+", values");
|
||||
jkqtpstatKDE1D(first, last, binsFirst, binsLast, plotter->getDatastore()->backInserter(histcolX), plotter->getDatastore()->backInserter(histcolY), kernel, bandwidth, cummulative);
|
||||
JKQTPXYLineGraph* resO=new JKQTPXYLineGraph(plotter);
|
||||
resO->setXColumn(histcolY);
|
||||
resO->setYColumn(histcolX);
|
||||
resO->setTitle(KDEcolumnBaseName);
|
||||
resO->setDrawLine(true);
|
||||
resO->setSymbolType(JKQTPNoSymbol);
|
||||
plotter->addGraph(resO);
|
||||
return resO;
|
||||
}
|
||||
|
||||
/*! \brief calculate an autoranged vertical KDE and add a JKQTPXYLineGraph to the given plotter, where the KDE is calculated from the data range \a first ... \a last, evaluation positions are given by the range \a binXLeft ... \a binXRight (in steps of \a binxDelta )
|
||||
\ingroup jkqtptools_math_statistics_adaptors
|
||||
|
||||
|
||||
\tparam InputIt standard iterator type of \a first and \a last.
|
||||
\param plotter the plotter to which to add the resulting graph
|
||||
\param first iterator pointing to the first item in the dataset to use \f$ X_1 \f$
|
||||
\param last iterator pointing behind the last item in the dataset to use \f$ X_N \f$
|
||||
\param binXLeft first x-position, where to evaluate the KDE
|
||||
\param binXDelta distance between two x-positions at which the KDE is evaluated
|
||||
\param binXRight last x-position, where to evaluate the KDE
|
||||
\param kernel the kernel function to use (e.g. jkqtpstatKernel1DGaussian() )
|
||||
\param bandwidth bandwidth used for the KDE
|
||||
\param cummulative if \c true, a cummulative KDE is calculated
|
||||
\param KDEcolumnBaseName this string is used in building the column names for the KDE data columns
|
||||
\return a graph class pointer (of type \a GraphClass ) displaying the KDE data
|
||||
|
||||
Example:
|
||||
\code
|
||||
std::vector<double> bins{-2,-1.5,-1,-0.75,-0.5,-0.25,0,0.25,0.5,0.75,1,1.5,2,2.5,3,4,5,6,7,8,9,10};
|
||||
jkqtpstatAddVKDE1D(plot1->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), bins.begin(), bins.end());
|
||||
\endcode
|
||||
|
||||
\image html jkqtplotter_simpletest_datastore_statistics_kde.png
|
||||
|
||||
\see \ref JKQTPlotterBasicJKQTPDatastoreStatistics, jkqtpstatKDE1D(), JKQTPXYLineGraph
|
||||
*/
|
||||
template <class InputIt>
|
||||
inline JKQTPXYLineGraph* jkqtpstatAddVKDE1D(JKQTBasePlotter* plotter, InputIt first, InputIt last, double binXLeft, double binXDelta, double binXRight, const std::function<double(double)>& kernel=std::function<double(double)>(&jkqtpstatKernel1DGaussian), double bandwidth=1.0, bool cummulative=false, const QString& KDEcolumnBaseName=QString("KDE")) {
|
||||
size_t histcolX=plotter->getDatastore()->addColumn(KDEcolumnBaseName+", bins");
|
||||
size_t histcolY=plotter->getDatastore()->addColumn(KDEcolumnBaseName+", values");
|
||||
jkqtpstatKDE1D(first, last, binXLeft, binXDelta, binXRight, plotter->getDatastore()->backInserter(histcolX), plotter->getDatastore()->backInserter(histcolY), kernel, bandwidth, cummulative);
|
||||
JKQTPXYLineGraph* resO=new JKQTPXYLineGraph(plotter);
|
||||
resO->setXColumn(histcolY);
|
||||
resO->setYColumn(histcolX);
|
||||
resO->setTitle(KDEcolumnBaseName);
|
||||
resO->setDrawLine(true);
|
||||
resO->setSymbolType(JKQTPNoSymbol);
|
||||
plotter->addGraph(resO);
|
||||
return resO;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \brief calculate calculate a 2-dimensional kernel density estimate (KDE) and add a JKQTPColumnMathImage to the given plotter, where the KDE is calculated from the given data range \a firstX / \a firstY ... \a lastY / \a lastY
|
||||
\ingroup jkqtptools_math_statistics_adaptors
|
||||
|
||||
\tparam InputItX standard iterator type of \a firstX and \a lastX.
|
||||
\tparam InputItY standard iterator type of \a firstY and \a lastY.
|
||||
\param plotter the plotter to which to add the resulting graph
|
||||
\param firstX iterator pointing to the first x-position item in the dataset to use \f$ X_1 \f$
|
||||
\param lastX iterator pointing behind the last x-position item in the dataset to use \f$ X_N \f$
|
||||
\param firstY iterator pointing to the first y-position item in the dataset to use \f$ Y_1 \f$
|
||||
\param lastY iterator pointing behind the last y-position item in the dataset to use \f$ Y_N \f$
|
||||
\param xbins number of bins in x-direction (i.e. width of the output KDE)
|
||||
\param ybins number of bins in y-direction (i.e. height of the output KDE)
|
||||
\param kernel the kernel function to use (e.g. jkqtpstatKernel2DGaussian() )
|
||||
\param bandwidthX x-bandwidth used for the KDE
|
||||
\param bandwidthY y-bandwidth used for the KDE
|
||||
\param kdecolumnBaseName this string is used in building the column names for the KDE data columns
|
||||
\param[out] oxmin position of the first KDE bin in x-direction
|
||||
\param[out] oxmax position of the last KDE bin in x-direction
|
||||
\param[out] oymin position of the first KDE bin in y-direction
|
||||
\param[out] oymax position of the last KDE bin in y-direction
|
||||
\return a graph class pointer (of type \c JKQTPColumnMathImage ) displaying the KDE data
|
||||
|
||||
\image html jkqtplotter_simpletest_datastore_statistics_2d_kde.png
|
||||
|
||||
\see jkqtpstatKDE2D(), \ref JKQTPlotterBasicJKQTPDatastoreStatistics2D
|
||||
*/
|
||||
template <class InputItX, class InputItY>
|
||||
inline JKQTPColumnMathImage* jkqtpstatAddKDE2DImage(JKQTBasePlotter* plotter, InputItX firstX, InputItX lastX, InputItY firstY, InputItY lastY, size_t xbins=10, size_t ybins=10, const std::function<double(double,double)>& kernel=std::function<double(double,double)>(&jkqtpstatKernel2DGaussian), double bandwidthX=1.0, double bandwidthY=1.0, const QString& kdecolumnBaseName=QString("histogram"), double* oxmin=nullptr, double* oxmax=nullptr, double* oymin=nullptr, double* oymax=nullptr) {
|
||||
double xmin=0, xmax=0;
|
||||
double ymin=0, ymax=0;
|
||||
jkqtpstatMinMax(firstX,lastX, xmin,xmax);
|
||||
jkqtpstatMinMax(firstY,lastY, ymin,ymax);
|
||||
size_t histcol=plotter->getDatastore()->addImageColumn(xbins, ybins, kdecolumnBaseName);
|
||||
jkqtpstatKDE2D(firstX,lastX,firstY,lastY,
|
||||
plotter->getDatastore()->begin(histcol),
|
||||
xmin, xmax, ymin, ymax,
|
||||
xbins, ybins, kernel, bandwidthX, bandwidthY);
|
||||
JKQTPColumnMathImage* gHist;
|
||||
plotter->addGraph(gHist=new JKQTPColumnMathImage(plotter));
|
||||
gHist->setImageColumn(static_cast<int>(histcol));
|
||||
gHist->setX(xmin);
|
||||
gHist->setY(ymin);
|
||||
gHist->setWidth(xmax-xmin);
|
||||
gHist->setHeight(ymax-ymin);
|
||||
gHist->setTitle(QObject::tr("2D KDE"));
|
||||
if (oxmax) *oxmax=xmax;
|
||||
if (oxmin) *oxmin=xmin;
|
||||
if (oymax) *oymax=ymax;
|
||||
if (oymin) *oymin=ymin;
|
||||
return gHist;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \brief calculate calculate a 2-dimensional kernel density estimate (KDE) and add a JKQTPColumnContourPlot to the given plotter, where the KDE is calculated from the given data range \a firstX / \a firstY ... \a lastY / \a lastY
|
||||
\ingroup jkqtptools_math_statistics_adaptors
|
||||
|
||||
\tparam InputItX standard iterator type of \a firstX and \a lastX.
|
||||
\tparam InputItY standard iterator type of \a firstY and \a lastY.
|
||||
\param plotter the plotter to which to add the resulting graph
|
||||
\param firstX iterator pointing to the first x-position item in the dataset to use \f$ X_1 \f$
|
||||
\param lastX iterator pointing behind the last x-position item in the dataset to use \f$ X_N \f$
|
||||
\param firstY iterator pointing to the first y-position item in the dataset to use \f$ Y_1 \f$
|
||||
\param lastY iterator pointing behind the last y-position item in the dataset to use \f$ Y_N \f$
|
||||
\param xbins number of bins in x-direction (i.e. width of the output KDE)
|
||||
\param ybins number of bins in y-direction (i.e. height of the output KDE)
|
||||
\param kernel the kernel function to use (e.g. jkqtpstatKernel2DGaussian() )
|
||||
\param bandwidthX x-bandwidth used for the KDE
|
||||
\param bandwidthY y-bandwidth used for the KDE
|
||||
\param kdecolumnBaseName this string is used in building the column names for the KDE data columns
|
||||
\param[out] oxmin position of the first KDE bin in x-direction
|
||||
\param[out] oxmax position of the last KDE bin in x-direction
|
||||
\param[out] oymin position of the first KDE bin in y-direction
|
||||
\param[out] oymax position of the last KDE bin in y-direction
|
||||
\return a graph class pointer (of type \c JKQTPColumnContourPlot ) displaying the KDE data as a contour plot
|
||||
|
||||
\image html jkqtplotter_simpletest_datastore_statistics_2d_kdecontour.png
|
||||
|
||||
\see jkqtpstatKDE2D(), \ref JKQTPlotterBasicJKQTPDatastoreStatistics2D
|
||||
*/
|
||||
template <class InputItX, class InputItY>
|
||||
inline JKQTPColumnContourPlot* jkqtpstatAddKDE2DContour(JKQTBasePlotter* plotter, InputItX firstX, InputItX lastX, InputItY firstY, InputItY lastY, size_t xbins=10, size_t ybins=10, const std::function<double(double,double)>& kernel=std::function<double(double,double)>(&jkqtpstatKernel2DGaussian), double bandwidthX=1.0, double bandwidthY=1.0, const QString& kdecolumnBaseName=QString("histogram"), double* oxmin=nullptr, double* oxmax=nullptr, double* oymin=nullptr, double* oymax=nullptr) {
|
||||
double xmin=0, xmax=0;
|
||||
double ymin=0, ymax=0;
|
||||
jkqtpstatMinMax(firstX,lastX, xmin,xmax);
|
||||
jkqtpstatMinMax(firstY,lastY, ymin,ymax);
|
||||
size_t histcol=plotter->getDatastore()->addImageColumn(xbins, ybins, kdecolumnBaseName);
|
||||
jkqtpstatKDE2D(firstX,lastX,firstY,lastY,
|
||||
plotter->getDatastore()->begin(histcol),
|
||||
xmin, xmax, ymin, ymax,
|
||||
xbins, ybins, kernel, bandwidthX, bandwidthY);
|
||||
JKQTPColumnContourPlot* gHist;
|
||||
plotter->addGraph(gHist=new JKQTPColumnContourPlot(plotter));
|
||||
gHist->setImageColumn(static_cast<int>(histcol));
|
||||
gHist->setX(xmin);
|
||||
gHist->setY(ymin);
|
||||
gHist->setWidth(xmax-xmin);
|
||||
gHist->setHeight(ymax-ymin);
|
||||
gHist->setTitle(QObject::tr("2D KDE"));
|
||||
gHist->createContourLevels(5);
|
||||
if (oxmax) *oxmax=xmax;
|
||||
if (oxmin) *oxmin=xmin;
|
||||
if (oymax) *oymax=ymax;
|
||||
if (oymin) *oymin=ymin;
|
||||
return gHist;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \brief calculate the linear regression coefficients for a given data range \a firstX / \a firstY ... \a lastX / \a lastY where the model is \f$ f(x)=a+b\cdot x \f$
|
||||
\ingroup jkqtptools_math_statistics_adaptors
|
||||
|
||||
|
BIN
screenshots/jkqtplotter_simpletest_datastore_statistics_2d.png
Normal file
After Width: | Height: | Size: 147 KiB |
After Width: | Height: | Size: 59 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 86 KiB |
After Width: | Height: | Size: 67 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 16 KiB |