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
This commit is contained in:
jkriege2 2019-06-11 16:59:19 +02:00
parent 9ff9076e63
commit 8abb2492fa
23 changed files with 1507 additions and 13 deletions

View File

@ -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)

View File

@ -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>

View File

@ -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

View File

@ -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]

View File

@ -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]

View File

@ -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]

View File

@ -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]

View 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)

View File

@ -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();
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB