/* Copyright (c) 2008-2022 Jan W. Krieger () last modification: $LastChangedDate$ (revision $Rev$) This software is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation, either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License (LGPL) for more details. You should have received a copy of the GNU Lesser General Public License (LGPL) along with this program. If not, see . */ #ifndef JKQTPSTATHISTOGRAM_H_INCLUDED #define JKQTPSTATHISTOGRAM_H_INCLUDED #include #include #include #include #include #include #include #include #include #include #include #include #include #include "jkqtmath/jkqtmath_imexport.h" #include "jkqtmath/jkqtplinalgtools.h" #include "jkqtmath/jkqtparraytools.h" #include "jkqtcommon/jkqtpdebuggingtools.h" #include "jkqtmath/jkqtpstatbasics.h" /*! \brief defines where the returned x-coordinates (in histogramXOut) lie inside a histogram bin \ingroup jkqtptools_math_statistics_1dhist \see jkqtpstatHistogram() */ enum class JKQTPStatHistogramBinXMode { XIsLeft, /*!< \brief x-location is the left edge of the bin */ XIsMid, /*!< \brief x-location is the middle of the bin */ XIsRight /*!< \brief x-location is the right edge of the bin */ }; /*! \brief calculate an autoranged 1-dimensional histogram from the given data range \a first ... \a last, bins defined by their number \ingroup jkqtptools_math_statistics_1dhist \tparam InputIt standard iterator type of \a first and \a last. \tparam OutputIt standard output iterator type used for the outliers output \a histogramXOut and \a histogramYOut, use e.g. std::back_inserter \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[out] histogramXOut output iterator that receives x-positions of the histogram bins. Location of this value inside the bin range is defined by \a binXMode \param[out] histogramYOut output iterator that receives counts/frequencies of the histogram bins \param bins number of bins in the output histogram \param normalized indicates whether the histogram has to be normalized \param cummulative if \c true, a cummulative histogram is calculated \param binXMode defines where the returned x-coordinates (in histogramXOut) lie inside the histogram bin (see JKQTPStatHistogramBinXMode) \see jkqtpstatAddHHistogram1DAutoranged() */ template inline void jkqtpstatHistogram1DAutoranged(InputIt first, InputIt last, OutputIt histogramXOut, OutputIt histogramYOut, int bins=11, bool normalized=true, bool cummulative=false, JKQTPStatHistogramBinXMode binXMode=JKQTPStatHistogramBinXMode::XIsLeft) { double minV=0, maxV=0; size_t N=0; jkqtpstatMinMax(first, last, minV, maxV, nullptr, nullptr, &N); std::vector histX; std::vector histY; const double range=maxV-minV; const double binw=range/static_cast(bins); // initialize the histogram for (int i=0; i(i)*binw); histY.push_back(0); } // calculate the histogram for (auto it=first; it!=last; ++it) { const double v=jkqtp_todouble(*it); if (JKQTPIsOKFloat(v)) { size_t b=jkqtp_bounded(0, static_cast(floor((v-minV)/binw)), bins-1); histY[b]++; } } // output the histogram double xoffset=0; if (binXMode==JKQTPStatHistogramBinXMode::XIsRight) xoffset=binw; if (binXMode==JKQTPStatHistogramBinXMode::XIsMid) xoffset=binw/2.0; double NNorm=1; if (normalized) { NNorm=static_cast(N); } double h=0; for (size_t i=0; i inline void jkqtpstatHistogram1DAutoranged(InputIt first, InputIt last, OutputIt histogramXOut, OutputIt histogramYOut, double binWidth, bool normalized=true, bool cummulative=false, JKQTPStatHistogramBinXMode binXMode=JKQTPStatHistogramBinXMode::XIsLeft) { double minV=0, maxV=0; size_t N=0; jkqtpstatMinMax(first, last, minV, maxV, nullptr, nullptr, &N); std::vector histX; std::vector histY; const double range=maxV-minV; const double binw=binWidth; const int bins=static_cast(ceil(range/binWidth)); // initialize the histogram for (int i=0; i(i)*binw); histY.push_back(0); } // calculate the histogram for (auto it=first; it!=last; ++it) { const double v=jkqtp_todouble(*it); if (JKQTPIsOKFloat(v)) { size_t b=jkqtp_bounded(0, static_cast(floor((v-minV)/binw)), bins-1); histY[b]++; } } // output the histogram double xoffset=0; if (binXMode==JKQTPStatHistogramBinXMode::XIsRight) xoffset=binw; if (binXMode==JKQTPStatHistogramBinXMode::XIsMid) xoffset=binw/2.0; double NNorm=1; if (normalized) { NNorm=static_cast(N); } double h=0; for (size_t i=0; i inline void jkqtpstatHistogram1D(InputIt first, InputIt last, BinsInputIt binsFirst, BinsInputIt binsLast, OutputIt histogramXOut, OutputIt histogramYOut, bool normalized=true, bool cummulative=false, JKQTPStatHistogramBinXMode binXMode=JKQTPStatHistogramBinXMode::XIsLeft) { double minV=0, maxV=0; size_t N=0; jkqtpstatMinMax(first, last, minV, maxV, nullptr, nullptr, &N); std::vector histX; std::vector histY; // initialize the histogram for (auto it=binsFirst; it!=binsLast; ++it) { histX.push_back(jkqtp_todouble(*it)); histY.push_back(0); } std::sort(histX.begin(), histX.end()); // calculate the histogram for (auto it=first; it!=last; ++it) { const double v=jkqtp_todouble(*it); if (JKQTPIsOKFloat(v)) { auto itb=std::lower_bound(histX.begin(), histX.end(), v); size_t bin=jkqtp_bounded(0,static_cast(std::abs(std::distance(histX.begin(), itb))), histY.size()-1); histY[bin]++; } } // output the histogram double NNorm=1; if (normalized) { NNorm=static_cast(N); } double h=0; for (size_t i=0; i(i)-1>0) binw=histX[histX.size()-1]-histX[histX.size()-2]; else if (i 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(xbins); const double binwy=fabs(ymax-ymin)/static_cast(ybins); std::vector 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(0, static_cast(floor((vx-xmin)/binwx)), xbins-1); const size_t by=jkqtp_bounded(0, static_cast(floor((vy-ymin)/binwy)), ybins-1); hist[by*xbins+bx]++; N++; } } // output the histogram double NNorm=1; if (normalized) { NNorm=static_cast(N); } std::transform(hist.begin(), hist.end(), histogramImgOut, [NNorm](double v) { return v/NNorm; }); } #endif // JKQTPSTATHISTOGRAM_H_INCLUDED