JKQTPlotter trunk/v5.0.0
an extensive Qt5+Qt6 Plotter framework (including a feature-richt plotter widget, a speed-optimized, but limited variant and a LaTeX equation renderer!), written fully in C/C++ and without external dependencies
Loading...
Searching...
No Matches
jkqtpstathistogram.h
1/*
2 Copyright (c) 2008-2024 Jan W. Krieger (<jan@jkrieger.de>)
3
4 last modification: $LastChangedDate$ (revision $Rev$)
5
6 This software is free software: you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License (LGPL) as published by
8 the Free Software Foundation, either version 2.1 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License (LGPL) for more details.
15
16 You should have received a copy of the GNU Lesser General Public License (LGPL)
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20
21#ifndef JKQTPSTATHISTOGRAM_H_INCLUDED
22#define JKQTPSTATHISTOGRAM_H_INCLUDED
23
24#include <stdint.h>
25#include <cmath>
26#include <stdlib.h>
27#include <string.h>
28#include <iostream>
29#include <stdio.h>
30#include <limits>
31#include <vector>
32#include <utility>
33#include <cfloat>
34#include <ostream>
35#include <iomanip>
36#include <sstream>
37#include "jkqtmath/jkqtmath_imexport.h"
38#include "jkqtmath/jkqtplinalgtools.h"
39#include "jkqtmath/jkqtparraytools.h"
40#include "jkqtcommon/jkqtpdebuggingtools.h"
41#include "jkqtmath/jkqtpstatbasics.h"
42
43
44
45
46/*! \brief defines where the returned x-coordinates (in histogramXOut) lie inside a histogram bin
47 \ingroup jkqtptools_math_statistics_1dhist
48 \see jkqtpstatHistogram()
49*/
51 XIsLeft, /*!< \brief x-location is the left edge of the bin */
52 XIsMid, /*!< \brief x-location is the middle of the bin */
53 XIsRight /*!< \brief x-location is the right edge of the bin */
54};
55
56/*! \brief calculate an autoranged 1-dimensional histogram from the given data range \a first ... \a last, bins defined by their number
57 \ingroup jkqtptools_math_statistics_1dhist
58
59 \tparam InputIt standard iterator type of \a first and \a last.
60 \tparam OutputIt standard output iterator type used for the outliers output \a histogramXOut and \a histogramYOut, use e.g. std::back_inserter
61 \param first iterator pointing to the first item in the dataset to use \f$ X_1 \f$
62 \param last iterator pointing behind the last item in the dataset to use \f$ X_N \f$
63 \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
64 \param[out] histogramYOut output iterator that receives counts/frequencies of the histogram bins
65 \param bins number of bins in the output histogram
66 \param normalized indicates whether the histogram has to be normalized
67 \param cummulative if \c true, a cummulative histogram is calculated
68 \param binXMode defines where the returned x-coordinates (in histogramXOut) lie inside the histogram bin (see JKQTPStatHistogramBinXMode)
69
70 \see jkqtpstatAddHHistogram1DAutoranged()
71*/
72template <class InputIt, class OutputIt>
73inline void jkqtpstatHistogram1DAutoranged(InputIt first, InputIt last, OutputIt histogramXOut, OutputIt histogramYOut, int bins=11, bool normalized=true, bool cummulative=false, JKQTPStatHistogramBinXMode binXMode=JKQTPStatHistogramBinXMode::XIsLeft) {
74 double minV=0, maxV=0;
75 size_t N=0;
76 jkqtpstatMinMax<InputIt>(first, last, minV, maxV, nullptr, nullptr, &N);
77
78 std::vector<double> histX;
79 std::vector<double> histY;
80
81 const double range=maxV-minV;
82 const double binw=range/static_cast<double>(bins);
83
84 // initialize the histogram
85 for (int i=0; i<bins; i++) {
86 histX.push_back(minV+static_cast<double>(i)*binw);
87 histY.push_back(0);
88 }
89
90 // calculate the histogram
91 for (auto it=first; it!=last; ++it) {
92 const double v=jkqtp_todouble(*it);
93 if (JKQTPIsOKFloat(v)) {
94 size_t b=jkqtp_bounded<size_t>(0, static_cast<size_t>(floor((v-minV)/binw)), bins-1);
95 histY[b]++;
96 }
97 }
98
99
100 // output the histogram
101 double xoffset=0;
102 if (binXMode==JKQTPStatHistogramBinXMode::XIsRight) xoffset=binw;
103 if (binXMode==JKQTPStatHistogramBinXMode::XIsMid) xoffset=binw/2.0;
104
105 double NNorm=1;
106 if (normalized) {
107 NNorm=static_cast<double>(N);
108 }
109 double h=0;
110 for (size_t i=0; i<histX.size(); i++) {
111 *histogramXOut=histX[i]+xoffset;
112 if (cummulative) h+=(histY[i]/NNorm);
113 else h=histY[i]/NNorm;
114 *histogramYOut=h;
115 ++histogramXOut;
116 ++histogramYOut;
117 }
118}
119
120/*! \brief calculate an autoranged 1-dimensional histogram from the given data range \a first ... \a last, bins defined by their width
121 \ingroup jkqtptools_math_statistics_1dhist
122
123 \tparam InputIt standard iterator type of \a first and \a last.
124 \tparam OutputIt standard output iterator type used for the outliers output \a histogramXOut and \a histogramYOut, use e.g. std::back_inserter
125 \param first iterator pointing to the first item in the dataset to use \f$ X_1 \f$
126 \param last iterator pointing behind the last item in the dataset to use \f$ X_N \f$
127 \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
128 \param[out] histogramYOut output iterator that receives counts/frequencies of the histogram bins
129 \param binWidth width of the bins
130 \param normalized indicates whether the histogram has to be normalized
131 \param cummulative if \c true, a cummulative histogram is calculated
132 \param binXMode defines where the returned x-coordinates (in histogramXOut) lie inside the histogram bin (see JKQTPStatHistogramBinXMode)
133
134 \see jkqtpstatAddHHistogram1DAutoranged()
135*/
136template <class InputIt, class OutputIt>
137inline void jkqtpstatHistogram1DAutoranged(InputIt first, InputIt last, OutputIt histogramXOut, OutputIt histogramYOut, double binWidth, bool normalized=true, bool cummulative=false, JKQTPStatHistogramBinXMode binXMode=JKQTPStatHistogramBinXMode::XIsLeft) {
138 double minV=0, maxV=0;
139 size_t N=0;
140 jkqtpstatMinMax<InputIt>(first, last, minV, maxV, nullptr, nullptr, &N);
141
142 std::vector<double> histX;
143 std::vector<double> histY;
144
145 const double range=maxV-minV;
146 const double binw=binWidth;
147 const int bins=static_cast<int>(ceil(range/binWidth));
148
149 // initialize the histogram
150 for (int i=0; i<bins; i++) {
151 histX.push_back(minV+static_cast<double>(i)*binw);
152 histY.push_back(0);
153 }
154
155 // calculate the histogram
156 for (auto it=first; it!=last; ++it) {
157 const double v=jkqtp_todouble(*it);
158 if (JKQTPIsOKFloat(v)) {
159 size_t b=jkqtp_bounded<size_t>(0, static_cast<size_t>(floor((v-minV)/binw)), bins-1);
160 histY[b]++;
161 }
162 }
163
164
165 // output the histogram
166 double xoffset=0;
167 if (binXMode==JKQTPStatHistogramBinXMode::XIsRight) xoffset=binw;
168 if (binXMode==JKQTPStatHistogramBinXMode::XIsMid) xoffset=binw/2.0;
169
170 double NNorm=1;
171 if (normalized) {
172 NNorm=static_cast<double>(N);
173 }
174 double h=0;
175 for (size_t i=0; i<histX.size(); i++) {
176 *histogramXOut=histX[i]+xoffset;
177 if (cummulative) h+=(histY[i]/NNorm);
178 else h=histY[i]/NNorm;
179 *histogramYOut=h;
180 ++histogramXOut;
181 ++histogramYOut; }
182}
183
184
185
186/*! \brief calculate an autoranged 1-dimensional histogram from the given data range \a first ... \a last, bins defined the range \a binsFirst ... \a binsLast
187 \ingroup jkqtptools_math_statistics_1dhist
188
189 \tparam InputIt standard iterator type of \a first and \a last.
190 \tparam BinsInputIt standard iterator type of \a binsFirst and \a binsLast.
191 \tparam OutputIt standard output iterator type used for the outliers output \a histogramXOut and \a histogramYOut, use e.g. std::back_inserter
192 \param first iterator pointing to the first item in the dataset to use \f$ X_1 \f$
193 \param last iterator pointing behind the last item in the dataset to use \f$ X_N \f$
194 \param binsFirst iterator pointing to the first item in the set of histogram bins
195 \param binsLast iterator pointing behind the last item in the set of histogram bins
196 \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
197 \param[out] histogramYOut output iterator that receives counts/frequencies of the histogram bins
198 \param normalized indicates whether the histogram has to be normalized
199 \param cummulative if \c true, a cummulative histogram is calculated
200 \param binXMode defines where the returned x-coordinates (in histogramXOut) lie inside the histogram bin (see JKQTPStatHistogramBinXMode)
201
202 \see jkqtpstatAddHHistogram1D()
203*/
204template <class InputIt, class BinsInputIt, class OutputIt>
205inline void jkqtpstatHistogram1D(InputIt first, InputIt last, BinsInputIt binsFirst, BinsInputIt binsLast, OutputIt histogramXOut, OutputIt histogramYOut, bool normalized=true, bool cummulative=false, JKQTPStatHistogramBinXMode binXMode=JKQTPStatHistogramBinXMode::XIsLeft) {
206 double minV=0, maxV=0;
207 size_t N=0;
208 jkqtpstatMinMax<InputIt>(first, last, minV, maxV, nullptr, nullptr, &N);
209
210 std::vector<double> histX;
211 std::vector<double> histY;
212
213
214 // initialize the histogram
215 for (auto it=binsFirst; it!=binsLast; ++it) {
216 histX.push_back(jkqtp_todouble(*it));
217 histY.push_back(0);
218 }
219 std::sort(histX.begin(), histX.end());
220
221 // calculate the histogram
222 for (auto it=first; it!=last; ++it) {
223 const double v=jkqtp_todouble(*it);
224 if (JKQTPIsOKFloat(v)) {
225 auto itb=std::lower_bound(histX.begin(), histX.end(), v);
226 size_t bin=jkqtp_bounded<size_t>(0,static_cast<size_t>(std::abs(std::distance(histX.begin(), itb))), histY.size()-1);
227 histY[bin]++;
228 }
229 }
230
231
232 // output the histogram
233 double NNorm=1;
234 if (normalized) {
235 NNorm=static_cast<double>(N);
236 }
237 double h=0;
238 for (size_t i=0; i<histX.size(); i++) {
239 double xoffset=0;
240 double binw=1;
242 if (i==0 && i+1<histX.size()) binw=histX[1]-histX[0];
243 else if (i==histX.size()-1 && static_cast<int>(i)-1>0) binw=histX[histX.size()-1]-histX[histX.size()-2];
244 else if (i<histX.size() && i+1<histX.size()) binw=histX[i+1]-histX[i];
245 if (binXMode==JKQTPStatHistogramBinXMode::XIsRight) xoffset=binw;
246 if (binXMode==JKQTPStatHistogramBinXMode::XIsMid) xoffset=binw/2.0;
247 }
248
249 *histogramXOut=histX[i]+xoffset;
250 if (cummulative) h+=(histY[i]/NNorm);
251 else h=histY[i]/NNorm;
252 *histogramYOut=h;
253 ++histogramXOut;
254 ++histogramYOut; }
255}
256
257
258
259
260
261
262
263
264
265/*! \brief calculate a 2-dimensional histogram from the given data range \a firstX / \a firstY ... \a lastY / \a lastY
266 \ingroup jkqtptools_math_statistics_2dhist
267
268 \tparam InputItX standard iterator type of \a firstX and \a lastX.
269 \tparam InputItY standard iterator type of \a firstY and \a lastY.
270 \tparam OutputIt standard output iterator type used for the outliers output \a histogramXOut and \a histogramYOut, use e.g. std::back_inserter
271 \param firstX iterator pointing to the first x-position item in the dataset to use \f$ X_1 \f$
272 \param lastX iterator pointing behind the last x-position item in the dataset to use \f$ X_N \f$
273 \param firstY iterator pointing to the first y-position item in the dataset to use \f$ Y_1 \f$
274 \param lastY iterator pointing behind the last y-position item in the dataset to use \f$ Y_N \f$
275 \param[out] histogramImgOut output iterator that receives counts of the histogram bins in row-major ordering
276 \param xmin position of the first histogram bin in x-direction
277 \param xmax position of the last histogram bin in x-direction
278 \param ymin position of the first histogram bin in y-direction
279 \param ymax position of the last histogram bin in y-direction
280 \param xbins number of bins in x-direction (i.e. width of the output histogram \a histogramImgOut )
281 \param ybins number of bins in y-direction (i.e. height of the output histogram \a histogramImgOut )
282 \param normalized indicates whether the histogram has to be normalized
283
284 \see jkqtpstatAddHHistogram1DAutoranged()
285*/
286template <class InputItX, class InputItY, class OutputIt>
287inline 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) {
288
289 const double binwx=fabs(xmax-xmin)/static_cast<double>(xbins);
290 const double binwy=fabs(ymax-ymin)/static_cast<double>(ybins);
291
292 std::vector<double> hist;
293 std::fill_n(std::back_inserter(hist), xbins*ybins, 0.0);
294
295 // calculate the histogram
296 auto itX=firstX;
297 auto itY=firstY;
298 size_t N=0;
299 for (; (itX!=lastX) && (itY!=lastY); ++itX, ++itY) {
300 const double vx=jkqtp_todouble(*itX);
301 const double vy=jkqtp_todouble(*itY);
302 if (JKQTPIsOKFloat(vx) && JKQTPIsOKFloat(vy)) {
303 const size_t bx=jkqtp_bounded<size_t>(0, static_cast<size_t>(floor((vx-xmin)/binwx)), xbins-1);
304 const size_t by=jkqtp_bounded<size_t>(0, static_cast<size_t>(floor((vy-ymin)/binwy)), ybins-1);
305 hist[by*xbins+bx]++;
306 N++;
307 }
308 }
309
310
311 // output the histogram
312 double NNorm=1;
313 if (normalized) {
314 NNorm=static_cast<double>(N);
315 }
316 std::transform(hist.begin(), hist.end(), histogramImgOut, [NNorm](double v) { return v/NNorm; });
317}
318
319
320
321
322
323
324
325#endif // JKQTPSTATHISTOGRAM_H_INCLUDED
326
327
constexpr double jkqtp_todouble(const T &d)
converts a boolean to a double, is used to convert boolean to double by JKQTPDatastore
Definition jkqtpmathtools.h:113
bool JKQTPIsOKFloat(T v)
check whether the dlotaing point number is OK (i.e. non-inf, non-NAN)
Definition jkqtpmathtools.h:496
void jkqtpstatHistogram1D(InputIt first, InputIt last, BinsInputIt binsFirst, BinsInputIt binsLast, OutputIt histogramXOut, OutputIt histogramYOut, bool normalized=true, bool cummulative=false, JKQTPStatHistogramBinXMode binXMode=JKQTPStatHistogramBinXMode::XIsLeft)
calculate an autoranged 1-dimensional histogram from the given data range first .....
Definition jkqtpstathistogram.h:205
void jkqtpstatHistogram1DAutoranged(InputIt first, InputIt last, OutputIt histogramXOut, OutputIt histogramYOut, int bins=11, bool normalized=true, bool cummulative=false, JKQTPStatHistogramBinXMode binXMode=JKQTPStatHistogramBinXMode::XIsLeft)
calculate an autoranged 1-dimensional histogram from the given data range first .....
Definition jkqtpstathistogram.h:73
JKQTPStatHistogramBinXMode
defines where the returned x-coordinates (in histogramXOut) lie inside a histogram bin
Definition jkqtpstathistogram.h:50
@ XIsLeft
x-location is the left edge of the bin
@ XIsMid
x-location is the middle of the bin
@ XIsRight
x-location is the right edge of the bin
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)
calculate a 2-dimensional histogram from the given data range firstX / firstY ... lastY / lastY
Definition jkqtpstathistogram.h:287