From d9e9a5aa6705cc315fe78d5b05935f6476825a62 Mon Sep 17 00:00:00 2001 From: jkriege2 Date: Tue, 18 Jun 2019 19:36:54 +0200 Subject: [PATCH] added adaptor functions for violin plots --- doc/dox/jkqtplotter.dox | 4 +- .../JKQTPViolinplotVerticalElement_small.png | Bin 0 -> 11227 bytes .../jkqtpstatAddHViolinplotHistogram.png | Bin 0 -> 3048 bytes ...statAddHViolinplotHistogramAndOutliers.png | Bin 0 -> 3608 bytes doc/images/jkqtpstatAddHViolinplotKDE.png | Bin 0 -> 5484 bytes .../jkqtpstatAddHViolinplotKDEAndOutliers.png | Bin 0 -> 4522 bytes .../jkqtpstatAddVViolinplotHistogram.png | Bin 0 -> 3006 bytes ...statAddVViolinplotHistogramAndOutliers.png | Bin 0 -> 3387 bytes doc/images/jkqtpstatAddVViolinplotKDE.png | Bin 0 -> 5356 bytes .../jkqtpstatAddVViolinplotKDEAndOutliers.png | Bin 0 -> 5337 bytes examples/simpletest_violinplot/README.md | 12 + .../jkqtplotter_simpletest_violinplot.cpp | 11 + lib/jkqtcommon/jkqtpstatbasics.h | 2 +- .../jkqtpgraphsstatisticsadaptors.h | 549 ++++++++++++++++++ 14 files changed, 575 insertions(+), 3 deletions(-) create mode 100644 doc/images/JKQTPViolinplotVerticalElement_small.png create mode 100644 doc/images/jkqtpstatAddHViolinplotHistogram.png create mode 100644 doc/images/jkqtpstatAddHViolinplotHistogramAndOutliers.png create mode 100644 doc/images/jkqtpstatAddHViolinplotKDE.png create mode 100644 doc/images/jkqtpstatAddHViolinplotKDEAndOutliers.png create mode 100644 doc/images/jkqtpstatAddVViolinplotHistogram.png create mode 100644 doc/images/jkqtpstatAddVViolinplotHistogramAndOutliers.png create mode 100644 doc/images/jkqtpstatAddVViolinplotKDE.png create mode 100644 doc/images/jkqtpstatAddVViolinplotKDEAndOutliers.png diff --git a/doc/dox/jkqtplotter.dox b/doc/dox/jkqtplotter.dox index f4ea364b2e..eea6936ecc 100644 --- a/doc/dox/jkqtplotter.dox +++ b/doc/dox/jkqtplotter.dox @@ -378,7 +378,7 @@ This group assembles graphs that show their data with symbols and optionally wit \image html jkqtplotter_simpletest_boxplot_small.png JKQTPBoxplotVerticalGraph, JKQTPBoxplotHorizontalGraph - \image html JKQTPViolinplotVerticalElement.png + \image html JKQTPViolinplotVerticalElement_small.png JKQTPViolinplotVerticalElement, JKQTPViolinplotHorizontalElement @@ -422,7 +422,7 @@ This group assembles graphs that show their data with symbols and optionally wit \image html geo_boxplot_small.png JKQTPBoxplotVerticalElement, JKQTPBoxplotHorizontalElement - \image html JKQTPViolinplotVerticalElement.png + \image html JKQTPViolinplotVerticalElement_small.png JKQTPViolinplotVerticalElement, JKQTPViolinplotHorizontalElement diff --git a/doc/images/JKQTPViolinplotVerticalElement_small.png b/doc/images/JKQTPViolinplotVerticalElement_small.png new file mode 100644 index 0000000000000000000000000000000000000000..98088d55781273cf194c963a6b72f5aeb9d4fc34 GIT binary patch literal 11227 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 FV1irQlgt1B literal 0 HcmV?d00001 diff --git a/doc/images/jkqtpstatAddHViolinplotHistogram.png b/doc/images/jkqtpstatAddHViolinplotHistogram.png new file mode 100644 index 0000000000000000000000000000000000000000..043609687571445b324b03854321ac7d7ff45fe1 GIT binary patch literal 3048 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 literal 0 HcmV?d00001 diff --git a/doc/images/jkqtpstatAddHViolinplotKDE.png b/doc/images/jkqtpstatAddHViolinplotKDE.png new file mode 100644 index 0000000000000000000000000000000000000000..da37387b882a09eda364290769044f44481ab56a GIT binary patch literal 5484 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 literal 0 HcmV?d00001 diff --git a/doc/images/jkqtpstatAddHViolinplotKDEAndOutliers.png b/doc/images/jkqtpstatAddHViolinplotKDEAndOutliers.png new file mode 100644 index 0000000000000000000000000000000000000000..fb7f51392e785d685059f8f71c13597068f9d2dd GIT binary patch literal 4522 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 IM6N<$f;BIM;Q#;t literal 0 HcmV?d00001 diff --git a/doc/images/jkqtpstatAddVViolinplotHistogram.png b/doc/images/jkqtpstatAddVViolinplotHistogram.png new file mode 100644 index 0000000000000000000000000000000000000000..dcd026c0fa360c0357627c16a7d2bf9797eabc30 GIT binary patch literal 3006 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 ZBp*Apf8Ah@9{+hQU}Ir#UVIdH@eg_&aAN=f literal 0 HcmV?d00001 diff --git a/doc/images/jkqtpstatAddVViolinplotHistogramAndOutliers.png b/doc/images/jkqtpstatAddVViolinplotHistogramAndOutliers.png new file mode 100644 index 0000000000000000000000000000000000000000..081d1fc10d614552cc2e7f55c6224744ad40d757 GIT binary patch literal 3387 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 literal 0 HcmV?d00001 diff --git a/doc/images/jkqtpstatAddVViolinplotKDE.png b/doc/images/jkqtpstatAddVViolinplotKDE.png new file mode 100644 index 0000000000000000000000000000000000000000..656df4c5ef5ddeee224c1d85159504a92e8cc0c0 GIT binary patch literal 5356 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 literal 0 HcmV?d00001 diff --git a/doc/images/jkqtpstatAddVViolinplotKDEAndOutliers.png b/doc/images/jkqtpstatAddVViolinplotKDEAndOutliers.png new file mode 100644 index 0000000000000000000000000000000000000000..7da10abb23e07c6429aa0d10cc5f248e7012deae GIT binary patch literal 5337 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, datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -5); + jkqtpstatAddHViolinplotHistogramAndOutliers(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -5); + jkqtpstatAddVViolinplotHistogram(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -10); + jkqtpstatAddHViolinplotHistogram(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -10); + jkqtpstatAddVViolinplotKDEAndOutliers(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -15); + jkqtpstatAddHViolinplotKDEAndOutliers(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -15); + jkqtpstatAddVViolinplotKDE(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -20); + jkqtpstatAddHViolinplotKDE(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -20); +``` diff --git a/examples/simpletest_violinplot/jkqtplotter_simpletest_violinplot.cpp b/examples/simpletest_violinplot/jkqtplotter_simpletest_violinplot.cpp index 7810d9882f..c39d6f2050 100644 --- a/examples/simpletest_violinplot/jkqtplotter_simpletest_violinplot.cpp +++ b/examples/simpletest_violinplot/jkqtplotter_simpletest_violinplot.cpp @@ -137,6 +137,17 @@ void showPlot() { gViol3->setViolinPositionMode(pos); gViol3->setTitle("box violin plot "+d3_latex); + // Note that there also exist "adapters" that allow to draw violin plots in one line of code: + /*jkqtpstatAddVViolinplotHistogramAndOutliers(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -5); + jkqtpstatAddHViolinplotHistogramAndOutliers(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -5); + jkqtpstatAddVViolinplotHistogram(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -10); + jkqtpstatAddHViolinplotHistogram(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -10); + jkqtpstatAddVViolinplotKDEAndOutliers(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -15); + jkqtpstatAddHViolinplotKDEAndOutliers(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -15); + jkqtpstatAddVViolinplotKDE(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -20); + jkqtpstatAddHViolinplotKDE(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -20); + */ + // autoscale and style the plot plot->zoomToFit(); plot->getPlotter()->setKeyPosition(JKQTPKeyInsideBottomRight); diff --git a/lib/jkqtcommon/jkqtpstatbasics.h b/lib/jkqtcommon/jkqtpstatbasics.h index 5e5f2ecb09..1de8886f01 100644 --- a/lib/jkqtcommon/jkqtpstatbasics.h +++ b/lib/jkqtcommon/jkqtpstatbasics.h @@ -967,7 +967,7 @@ inline void jkqtpstat5NumberStatisticsAndOutliersOfSortedVector(const TVector& d \see https://en.wikipedia.org/wiki/Five-number_summary, jkqtpstatAddVBoxplotAndOutliers, jkqtpstatAddHBoxplotAndOutliers, jkqtpstatAddVBoxplot, jkqtpstatAddHBoxplot, \ref JKQTPlotterBasicJKQTPDatastoreStatistics */ template -inline void jkqtpstat5NumberStatistics(InputIt first, InputIt last, double* minimum=nullptr, double minimumQuantile=0, double* median=nullptr, double* maximum=nullptr, double maximumQuantile=1, double quantile1Spec=0.25, double* quantile1=nullptr, double quantile2Spec=0.75, double* quantile2=nullptr, double* IQR=nullptr, double* IQRSignificance=nullptr, size_t* Noutput=nullptr) { +inline void jkqtpstat5NumberStatistics(InputIt first, InputIt last, double* minimum, double minimumQuantile=0, double* median=nullptr, double* maximum=nullptr, double maximumQuantile=1, double quantile1Spec=0.25, double* quantile1=nullptr, double quantile2Spec=0.75, double* quantile2=nullptr, double* IQR=nullptr, double* IQRSignificance=nullptr, size_t* Noutput=nullptr) { std::vector dataFiltered; jkqtpstatFilterGoodFloat(first, last, std::back_inserter(dataFiltered)); std::sort(dataFiltered.begin(), dataFiltered.end()); diff --git a/lib/jkqtplotter/jkqtpgraphsstatisticsadaptors.h b/lib/jkqtplotter/jkqtpgraphsstatisticsadaptors.h index 38bb6d74b6..f698dd3873 100644 --- a/lib/jkqtplotter/jkqtpgraphsstatisticsadaptors.h +++ b/lib/jkqtplotter/jkqtpgraphsstatisticsadaptors.h @@ -32,6 +32,7 @@ #include "jkqtplotter/jkqtpgraphscontour.h" #include "jkqtplotter/jkqtpgraphsimpulses.h" #include "jkqtplotter/jkqtpgraphsfilledcurve.h" +#include "jkqtplotter/jkqtpgraphsviolinplot.h" #ifndef JKQTPGRAPHSSTATISTICSADAPTORS_H_INCLUDED @@ -252,6 +253,554 @@ inline std::pair jk + + + + + +/*! \brief add a JKQTPViolinplotHorizontalElement to the given plotter, where the Violinplot values are calculated from the data range \a first ... \a last , uses a kernel density estimate as density distribution estimate + \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 violinposY y-coordinate of the Violinplot + \param kernel the kernel function to use (e.g. jkqtpstatKernel1DGaussian() ) + \param bandwidth bandwidth used for the KDE, if <0 then \c jkqtpstatEstimateKDEBandwidth(first,last) is called + \param distBasename name basing for added columns + \param violinDistSamples number of samples of the distribution (between min and max) + \return a Violinplot element with its values initialized from the given data range + + Example: + \code + jkqtpstatAddHViolinplotKDE(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -20); + \endcode + + \image html JKQTPGraphViolinplot_ViolinHBoth.png + + + \see \ref JKQTPlotterViolinplotGraphs, JKQTPViolinplotHorizontalElement, jkqtpstatKDE1DAutoranged() +*/ +template +inline JKQTPViolinplotHorizontalElement* jkqtpstatAddHViolinplotKDE(JKQTBasePlotter* plotter, InputIt first, InputIt last, double violinposY, const std::function& kernel=std::function(&jkqtpstatKernel1DGaussian), double bandwidth=-1, const QString& distBasename=QString("violin plot distribution"), int violinDistSamples=100) { + if (bandwidth<=0) bandwidth=jkqtpstatEstimateKDEBandwidth(first,last); + JKQTPStat5NumberStatistics stat=jkqtpstat5NumberStatistics(first, last); + size_t cViol1Cat=plotter->getDatastore()->addColumn(distBasename+", category"); + size_t cViol1Freq=plotter->getDatastore()->addColumn(distBasename+", KDE"); + jkqtpstatKDE1DAutoranged(first, last, plotter->getDatastore()->backInserter(cViol1Cat), plotter->getDatastore()->backInserter(cViol1Freq), + violinDistSamples, kernel, bandwidth); + JKQTPViolinplotHorizontalElement* res=new JKQTPViolinplotHorizontalElement(plotter); + res->setMin(stat.minimum); + res->setMax(stat.maximum); + res->setMedian(stat.median); + res->setMean(jkqtpstatAverage(first, last)); + res->setDrawMean(true); + res->setDrawMedian(true); + res->setDrawMinMax(true); + res->setPos(violinposY); + res->setViolinPositionColumn(cViol1Cat); + res->setViolinFrequencyColumn(cViol1Freq); + plotter->addGraph(res); + return res; +} + + + + +/*! \brief add a JKQTPViolinplotHorizontalElement to the given plotter, where the Violinplot values are calculated from the data range \a first ... \a last , uses a histogram as density distribution estimate + \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 violinposY y-coordinate of the Violinplot + \param distBasename name basing for added columns + \param violinDistSamples number of bin of the distribution (between min and max) + \return a Violinplot element with its values initialized from the given data range + + Example: + \code + jkqtpstatAddHViolinplotHistogram(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -10); + \endcode + + \image html jkqtpstatAddHViolinplotHistogram.png + + + \see \ref JKQTPlotterViolinplotGraphs, JKQTPViolinplotHorizontalElement, jkqtpstatHistogram1DAutoranged() +*/ +template +inline JKQTPViolinplotHorizontalElement* jkqtpstatAddHViolinplotHistogram(JKQTBasePlotter* plotter, InputIt first, InputIt last, double violinposY, const QString& distBasename=QString("violin plot distribution"), int violinDistSamples=21) { + JKQTPStat5NumberStatistics stat=jkqtpstat5NumberStatistics(first, last); + size_t cViol1Cat=plotter->getDatastore()->addColumn(distBasename+", category"); + size_t cViol1Freq=plotter->getDatastore()->addColumn(distBasename+", histogram"); + jkqtpstatHistogram1DAutoranged(first, last, plotter->getDatastore()->backInserter(cViol1Cat), plotter->getDatastore()->backInserter(cViol1Freq), + violinDistSamples); + JKQTPViolinplotHorizontalElement* res=new JKQTPViolinplotHorizontalElement(plotter); + res->setMin(stat.minimum); + res->setMax(stat.maximum); + res->setMedian(stat.median); + res->setMean(jkqtpstatAverage(first, last)); + res->setDrawMean(true); + res->setDrawMedian(true); + res->setDrawMinMax(true); + res->setPos(violinposY); + res->setViolinPositionColumn(cViol1Cat); + res->setViolinFrequencyColumn(cViol1Freq); + res->setViolinStyle(JKQTPViolinplotHorizontalElement::StepViolin); + plotter->addGraph(res); + return res; +} + + + + +/*! \brief add a JKQTPViolinplotVerticalElement to the given plotter, where the Violinplot values are calculated from the data range \a first ... \a last , uses a kernel density estimate as density distribution estimate + \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 violinposY y-coordinate of the Violinplot + \param kernel the kernel function to use (e.g. jkqtpstatKernel1DGaussian() ) + \param bandwidth bandwidth used for the KDE, if <0 then \c jkqtpstatEstimateKDEBandwidth(first,last) is called + \param distBasename name basing for added columns + \param violinDistSamples number of samples of the distribution (between min and max) + \return a Violinplot element with its values initialized from the given data range + + Example: + \code + jkqtpstatAddVViolinplotKDE(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -20); + \endcode + + \image html jkqtpstatAddVViolinplotKDE.png + + + \see \ref JKQTPlotterViolinplotGraphs, JKQTPViolinplotVerticalElement, jkqtpstatKDE1DAutoranged() +*/ +template +inline JKQTPViolinplotVerticalElement* jkqtpstatAddVViolinplotKDE(JKQTBasePlotter* plotter, InputIt first, InputIt last, double violinposY, const std::function& kernel=std::function(&jkqtpstatKernel1DGaussian), double bandwidth=-1, const QString& distBasename=QString("violin plot distribution"), int violinDistSamples=100) { + if (bandwidth<=0) bandwidth=jkqtpstatEstimateKDEBandwidth(first,last); + JKQTPStat5NumberStatistics stat=jkqtpstat5NumberStatistics(first, last); + size_t cViol1Cat=plotter->getDatastore()->addColumn(distBasename+", category"); + size_t cViol1Freq=plotter->getDatastore()->addColumn(distBasename+", KDE"); + jkqtpstatKDE1DAutoranged(first, last, plotter->getDatastore()->backInserter(cViol1Cat), plotter->getDatastore()->backInserter(cViol1Freq), + violinDistSamples, kernel, bandwidth); + JKQTPViolinplotVerticalElement* res=new JKQTPViolinplotVerticalElement(plotter); + res->setMin(stat.minimum); + res->setMax(stat.maximum); + res->setMedian(stat.median); + res->setMean(jkqtpstatAverage(first, last)); + res->setDrawMean(true); + res->setDrawMedian(true); + res->setDrawMinMax(true); + res->setPos(violinposY); + res->setViolinPositionColumn(cViol1Cat); + res->setViolinFrequencyColumn(cViol1Freq); + plotter->addGraph(res); + return res; +} + + + + +/*! \brief add a JKQTPViolinplotVerticalElement to the given plotter, where the Violinplot values are calculated from the data range \a first ... \a last , uses a histogram as density distribution estimate + \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 violinposY y-coordinate of the Violinplot + \param distBasename name basing for added columns + \param violinDistSamples number of bin of the distribution (between min and max) + \return a Violinplot element with its values initialized from the given data range + + Example: + \code + jkqtpstatAddVViolinplotHistogram(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -10); + \endcode + + \image html jkqtpstatAddVViolinplotHistogram.png + + + \see \ref JKQTPlotterViolinplotGraphs, JKQTPViolinplotVerticalElement, jkqtpstatHistogram1DAutoranged() +*/ +template +inline JKQTPViolinplotVerticalElement* jkqtpstatAddVViolinplotHistogram(JKQTBasePlotter* plotter, InputIt first, InputIt last, double violinposY, const QString& distBasename=QString("violin plot distribution"), int violinDistSamples=21) { + JKQTPStat5NumberStatistics stat=jkqtpstat5NumberStatistics(first, last); + size_t cViol1Cat=plotter->getDatastore()->addColumn(distBasename+", category"); + size_t cViol1Freq=plotter->getDatastore()->addColumn(distBasename+", histogram"); + jkqtpstatHistogram1DAutoranged(first, last, plotter->getDatastore()->backInserter(cViol1Cat), plotter->getDatastore()->backInserter(cViol1Freq), + violinDistSamples); + JKQTPViolinplotVerticalElement* res=new JKQTPViolinplotVerticalElement(plotter); + res->setMin(stat.minimum); + res->setMax(stat.maximum); + res->setMedian(stat.median); + res->setMean(jkqtpstatAverage(first, last)); + res->setDrawMean(true); + res->setDrawMedian(true); + res->setDrawMinMax(true); + res->setPos(violinposY); + res->setViolinPositionColumn(cViol1Cat); + res->setViolinFrequencyColumn(cViol1Freq); + res->setViolinStyle(JKQTPViolinplotVerticalElement::StepViolin); + plotter->addGraph(res); + return res; +} + + + + + + + + + + +/*! \brief add a JKQTPViolinplotHorizontalElement and an outliers graph to the given plotter, where the Violinplot values are calculated from the data range \a first ... \a last , uses a kernel density estimate as density distribution estimate + \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 violinposY y-coordinate of the Violinplot + \param kernel the kernel function to use (e.g. jkqtpstatKernel1DGaussian() ) + \param bandwidth bandwidth used for the KDE, if <0 then \c jkqtpstatEstimateKDEBandwidth(first,last) is called + \param minimumQuantile specifies a quantile for the return value minimum (default is 0 for the real minimum, but you could e.g. use 0.05 for the 5% quantile!) + \param maximumQuantile specifies a quantile for the return value maximum (default is 1 for the real maximum, but you could e.g. use 0.95 for the 95% quantile!) + \param distBasename name basing for added columns + \param violinDistSamples number of samples of the distribution (between min and max) + \return a Violinplot element with its values initialized from the given data range + + Example: + \code + jkqtpstatAddHViolinplotKDEAndOutliers(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -15); + \endcode + + \image html jkqtpstatAddHViolinplotKDEAndOutliers.png + + + \see \ref JKQTPlotterViolinplotGraphs, JKQTPViolinplotHorizontalElement, jkqtpstatKDE1DAutoranged() +*/ +template +inline std::pair jkqtpstatAddHViolinplotKDEAndOutliers(JKQTBasePlotter* plotter, InputIt first, InputIt last, double violinposY, const std::function& kernel=std::function(&jkqtpstatKernel1DGaussian), double bandwidth=-1, double minimumQuantile=0.03, double maximumQuantile=0.97, const QString& distBasename=QString("violin plot distribution"), int violinDistSamples=100) { + size_t cOutliersY=plotter->getDatastore()->addColumn(distBasename+", outliers, value"); + std::vector datain, datause; + std::copy(first, last, std::back_inserter(datain)); + std::sort(datain.begin(), datain.end()); + datause.reserve(datain.size()); + size_t i0=jkqtp_boundedRoundTo(0,minimumQuantile*static_cast(datain.size()),datain.size()-1); + size_t i1=jkqtp_boundedRoundTo(0,maximumQuantile*static_cast(datain.size()),datain.size()-1); + for (size_t i=0; i=i1) { + plotter->getDatastore()->appendToColumn(cOutliersY, datain[i]); + } else { + datause.push_back(datain[i]); + } + } + + + + if (datause.size()>0) { + if (bandwidth<=0) bandwidth=jkqtpstatEstimateKDEBandwidth(datause.begin(), datause.end()); + size_t cViol1Cat=plotter->getDatastore()->addColumn(distBasename+", category"); + size_t cViol1Freq=plotter->getDatastore()->addColumn(distBasename+", KDE"); + jkqtpstatKDE1DAutoranged(datause.begin(), datause.end(), plotter->getDatastore()->backInserter(cViol1Cat), plotter->getDatastore()->backInserter(cViol1Freq), + violinDistSamples, kernel, bandwidth); + JKQTPViolinplotHorizontalElement* res=new JKQTPViolinplotHorizontalElement(plotter); + res->setMin(datause[0]); + res->setMax(datause[datause.size()-1]); + res->setMedian(jkqtpstatMedianOfSortedVector(datause)); + res->setMean(jkqtpstatAverage(datause.begin(), datause.end())); + res->setDrawMean(true); + res->setDrawMedian(true); + res->setDrawMinMax(true); + res->setPos(violinposY); + res->setViolinPositionColumn(cViol1Cat); + res->setViolinFrequencyColumn(cViol1Freq); + plotter->addGraph(res); + + JKQTPSingleColumnSymbolsGraph* resO=new JKQTPSingleColumnSymbolsGraph(plotter); + resO->setDataColumn(cOutliersY); + resO->setPosition(violinposY); + resO->setPositionScatterStyle(JKQTPSingleColumnSymbolsGraph::NoScatter); + resO->setDataDirection(JKQTPSingleColumnSymbolsGraph::DataDirection::X); + resO->setColor(res->getKeyLabelColor()); + resO->setTitle(""); + + plotter->addGraph(res); + plotter->addGraph(resO); + return std::pair(res,resO); + } else { + return std::pair(nullptr,nullptr); + } + +} + + + + + +/*! \brief add a JKQTPViolinplotHorizontalElement and an outliers graph to the given plotter, where the Violinplot values are calculated from the data range \a first ... \a last , uses a histogram as density distribution estimate + \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 violinposY y-coordinate of the Violinplot + \param minimumQuantile specifies a quantile for the return value minimum (default is 0 for the real minimum, but you could e.g. use 0.05 for the 5% quantile!) + \param maximumQuantile specifies a quantile for the return value maximum (default is 1 for the real maximum, but you could e.g. use 0.95 for the 95% quantile!) + \param distBasename name basing for added columns + \param violinDistSamples number of samples of the distribution (between min and max) + \return a Violinplot element with its values initialized from the given data range + + Example: + \code + jkqtpstatAddHViolinplotHistogramAndOutliers(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -5); + \endcode + + \image html jkqtpstatAddHViolinplotHistogramAndOutliers.png + + + \see \ref JKQTPlotterViolinplotGraphs, JKQTPViolinplotHorizontalElement, jkqtpstatHistogram1DAutoranged() +*/ +template +inline std::pair jkqtpstatAddHViolinplotHistogramAndOutliers(JKQTBasePlotter* plotter, InputIt first, InputIt last, double violinposY, double minimumQuantile=0.03, double maximumQuantile=0.97, const QString& distBasename=QString("violin plot distribution"), int violinDistSamples=21) { + size_t cOutliersY=plotter->getDatastore()->addColumn(distBasename+", outliers, value"); + std::vector datain, datause; + std::copy(first, last, std::back_inserter(datain)); + std::sort(datain.begin(), datain.end()); + datause.reserve(datain.size()); + size_t i0=jkqtp_boundedRoundTo(0,minimumQuantile*static_cast(datain.size()),datain.size()-1); + size_t i1=jkqtp_boundedRoundTo(0,maximumQuantile*static_cast(datain.size()),datain.size()-1); + for (size_t i=0; i=i1) { + plotter->getDatastore()->appendToColumn(cOutliersY, datain[i]); + } else { + datause.push_back(datain[i]); + } + } + + + + if (datause.size()>0) { + size_t cViol1Cat=plotter->getDatastore()->addColumn(distBasename+", category"); + size_t cViol1Freq=plotter->getDatastore()->addColumn(distBasename+", Histogram"); + jkqtpstatHistogram1DAutoranged(datause.begin(), datause.end(), plotter->getDatastore()->backInserter(cViol1Cat), plotter->getDatastore()->backInserter(cViol1Freq), violinDistSamples); + JKQTPViolinplotHorizontalElement* res=new JKQTPViolinplotHorizontalElement(plotter); + res->setMin(datause[0]); + res->setMax(datause[datause.size()-1]); + res->setMedian(jkqtpstatMedianOfSortedVector(datause)); + res->setMean(jkqtpstatAverage(datause.begin(), datause.end())); + res->setDrawMean(true); + res->setDrawMedian(true); + res->setDrawMinMax(true); + res->setPos(violinposY); + res->setViolinPositionColumn(cViol1Cat); + res->setViolinFrequencyColumn(cViol1Freq); + res->setViolinStyle(JKQTPViolinplotVerticalElement::StepViolin); + plotter->addGraph(res); + + JKQTPSingleColumnSymbolsGraph* resO=new JKQTPSingleColumnSymbolsGraph(plotter); + resO->setDataColumn(cOutliersY); + resO->setPosition(violinposY); + resO->setPositionScatterStyle(JKQTPSingleColumnSymbolsGraph::NoScatter); + resO->setDataDirection(JKQTPSingleColumnSymbolsGraph::DataDirection::X); + resO->setColor(res->getKeyLabelColor()); + resO->setTitle(""); + + plotter->addGraph(res); + plotter->addGraph(resO); + return std::pair(res,resO); + } else { + return std::pair(nullptr,nullptr); + } + +} + + + + + + + + + +/*! \brief add a JKQTPViolinplotVerticalElement and an outliers graph to the given plotter, where the Violinplot values are calculated from the data range \a first ... \a last , uses a kernel density estimate as density distribution estimate + \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 violinposY y-coordinate of the Violinplot + \param kernel the kernel function to use (e.g. jkqtpstatKernel1DGaussian() ) + \param bandwidth bandwidth used for the KDE, if <0 then \c jkqtpstatEstimateKDEBandwidth(first,last) is called + \param minimumQuantile specifies a quantile for the return value minimum (default is 0 for the real minimum, but you could e.g. use 0.05 for the 5% quantile!) + \param maximumQuantile specifies a quantile for the return value maximum (default is 1 for the real maximum, but you could e.g. use 0.95 for the 95% quantile!) + \param distBasename name basing for added columns + \param violinDistSamples number of samples of the distribution (between min and max) + \return a Violinplot element with its values initialized from the given data range + + Example: + \code + jkqtpstatAddVViolinplotKDEAndOutliers(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -15); + \endcode + + \image html jkqtpstatAddVViolinplotKDEAndOutliers.png + + + \see \ref JKQTPlotterViolinplotGraphs, JKQTPViolinplotVerticalElement, jkqtpstatKDE1DAutoranged() +*/ +template +inline std::pair jkqtpstatAddVViolinplotKDEAndOutliers(JKQTBasePlotter* plotter, InputIt first, InputIt last, double violinposY, const std::function& kernel=std::function(&jkqtpstatKernel1DGaussian), double bandwidth=-1, double minimumQuantile=0.03, double maximumQuantile=0.97, const QString& distBasename=QString("violin plot distribution"), int violinDistSamples=100) { + size_t cOutliersY=plotter->getDatastore()->addColumn(distBasename+", outliers, value"); + std::vector datain, datause; + std::copy(first, last, std::back_inserter(datain)); + std::sort(datain.begin(), datain.end()); + datause.reserve(datain.size()); + size_t i0=jkqtp_boundedRoundTo(0,minimumQuantile*static_cast(datain.size()),datain.size()-1); + size_t i1=jkqtp_boundedRoundTo(0,maximumQuantile*static_cast(datain.size()),datain.size()-1); + for (size_t i=0; i=i1) { + plotter->getDatastore()->appendToColumn(cOutliersY, datain[i]); + } else { + datause.push_back(datain[i]); + } + } + + + + if (datause.size()>0) { + if (bandwidth<=0) bandwidth=jkqtpstatEstimateKDEBandwidth(datause.begin(), datause.end()); + size_t cViol1Cat=plotter->getDatastore()->addColumn(distBasename+", category"); + size_t cViol1Freq=plotter->getDatastore()->addColumn(distBasename+", KDE"); + jkqtpstatKDE1DAutoranged(datause.begin(), datause.end(), plotter->getDatastore()->backInserter(cViol1Cat), plotter->getDatastore()->backInserter(cViol1Freq), + violinDistSamples, kernel, bandwidth); + JKQTPViolinplotVerticalElement* res=new JKQTPViolinplotVerticalElement(plotter); + res->setMin(datause[0]); + res->setMax(datause[datause.size()-1]); + res->setMedian(jkqtpstatMedianOfSortedVector(datause)); + res->setMean(jkqtpstatAverage(datause.begin(), datause.end())); + res->setDrawMean(true); + res->setDrawMedian(true); + res->setDrawMinMax(true); + res->setPos(violinposY); + res->setViolinPositionColumn(cViol1Cat); + res->setViolinFrequencyColumn(cViol1Freq); + plotter->addGraph(res); + + JKQTPSingleColumnSymbolsGraph* resO=new JKQTPSingleColumnSymbolsGraph(plotter); + resO->setDataColumn(cOutliersY); + resO->setPosition(violinposY); + resO->setPositionScatterStyle(JKQTPSingleColumnSymbolsGraph::NoScatter); + resO->setDataDirection(JKQTPSingleColumnSymbolsGraph::DataDirection::Y); + resO->setColor(res->getKeyLabelColor()); + resO->setTitle(""); + + plotter->addGraph(res); + plotter->addGraph(resO); + return std::pair(res,resO); + } else { + return std::pair(nullptr,nullptr); + } + +} + + + + + +/*! \brief add a JKQTPViolinplotVerticalElement and an outliers graph to the given plotter, where the Violinplot values are calculated from the data range \a first ... \a last , uses a histogram as density distribution estimate + \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 violinposY y-coordinate of the Violinplot + \param minimumQuantile specifies a quantile for the return value minimum (default is 0 for the real minimum, but you could e.g. use 0.05 for the 5% quantile!) + \param maximumQuantile specifies a quantile for the return value maximum (default is 1 for the real maximum, but you could e.g. use 0.95 for the 95% quantile!) + \param distBasename name basing for added columns + \param violinDistSamples number of samples of the distribution (between min and max) + \return a Violinplot element with its values initialized from the given data range + + Example: + \code + jkqtpstatAddVViolinplotHistogramAndOutliers(plot->getPlotter(), datastore1->begin(randomdatacol1), datastore1->end(randomdatacol1), -5); + \endcode + + \image html jkqtpstatAddVViolinplotHistogramAndOutliers.png + + + \see \ref JKQTPlotterViolinplotGraphs, JKQTPViolinplotVerticalElement, jkqtpstatHistogram1DAutoranged() +*/ +template +inline std::pair jkqtpstatAddVViolinplotHistogramAndOutliers(JKQTBasePlotter* plotter, InputIt first, InputIt last, double violinposY, double minimumQuantile=0.03, double maximumQuantile=0.97, const QString& distBasename=QString("violin plot distribution"), int violinDistSamples=21) { + size_t cOutliersY=plotter->getDatastore()->addColumn(distBasename+", outliers, value"); + std::vector datain, datause; + std::copy(first, last, std::back_inserter(datain)); + std::sort(datain.begin(), datain.end()); + datause.reserve(datain.size()); + size_t i0=jkqtp_boundedRoundTo(0,minimumQuantile*static_cast(datain.size()),datain.size()-1); + size_t i1=jkqtp_boundedRoundTo(0,maximumQuantile*static_cast(datain.size()),datain.size()-1); + for (size_t i=0; i=i1) { + plotter->getDatastore()->appendToColumn(cOutliersY, datain[i]); + } else { + datause.push_back(datain[i]); + } + } + + + + if (datause.size()>0) { + size_t cViol1Cat=plotter->getDatastore()->addColumn(distBasename+", category"); + size_t cViol1Freq=plotter->getDatastore()->addColumn(distBasename+", Histogram"); + jkqtpstatHistogram1DAutoranged(datause.begin(), datause.end(), plotter->getDatastore()->backInserter(cViol1Cat), plotter->getDatastore()->backInserter(cViol1Freq), violinDistSamples); + JKQTPViolinplotVerticalElement* res=new JKQTPViolinplotVerticalElement(plotter); + res->setMin(datause[0]); + res->setMax(datause[datause.size()-1]); + res->setMedian(jkqtpstatMedianOfSortedVector(datause)); + res->setMean(jkqtpstatAverage(datause.begin(), datause.end())); + res->setDrawMean(true); + res->setDrawMedian(true); + res->setDrawMinMax(true); + res->setPos(violinposY); + res->setViolinPositionColumn(cViol1Cat); + res->setViolinFrequencyColumn(cViol1Freq); + res->setViolinStyle(JKQTPViolinplotVerticalElement::StepViolin); + plotter->addGraph(res); + + JKQTPSingleColumnSymbolsGraph* resO=new JKQTPSingleColumnSymbolsGraph(plotter); + resO->setDataColumn(cOutliersY); + resO->setPosition(violinposY); + resO->setPositionScatterStyle(JKQTPSingleColumnSymbolsGraph::NoScatter); + resO->setDataDirection(JKQTPSingleColumnSymbolsGraph::DataDirection::Y); + resO->setColor(res->getKeyLabelColor()); + resO->setTitle(""); + + plotter->addGraph(res); + plotter->addGraph(resO); + return std::pair(res,resO); + } else { + return std::pair(nullptr,nullptr); + } + +} + + + + + + + + /*! \brief calculate an autoranged histogram and add a JKQTPBarVerticalGraph to the given plotter, where the histogram is calculated from the data range \a first ... \a last, bins defined by their number \ingroup jkqtptools_math_statistics_adaptors