##// END OF EJS Templates
Implements methods to fill data holes of a data series
Alexandre Leroux -
r978:a292cee81aa6
parent child
Show More
@@ -1,12 +1,49
1 #ifndef SCIQLOP_DATASERIESUTILS_H
1 #ifndef SCIQLOP_DATASERIESUTILS_H
2 #define SCIQLOP_DATASERIESUTILS_H
2 #define SCIQLOP_DATASERIESUTILS_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <QLoggingCategory>
7
8 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSeriesUtils)
9
6 /**
10 /**
7 * Utility class with methods for data series
11 * Utility class with methods for data series
8 */
12 */
9 struct SCIQLOP_CORE_EXPORT DataSeriesUtils {
13 struct SCIQLOP_CORE_EXPORT DataSeriesUtils {
14 /**
15 * Processes data from a data series to complete the data holes with a fill value.
16 *
17 * A data hole is determined by the resolution passed in parameter: if, between two continuous
18 * data on the x-axis, the difference between these data is greater than the resolution, then
19 * there is one or more holes between them. The holes are filled by adding:
20 * - for the x-axis, new data corresponding to the 'step resolution' starting from the first
21 * data;
22 * - for values, a default value (fill value) for each new data added on the x-axis.
23 *
24 * For example, with :
25 * - xAxisData = [0, 1, 5, 7, 14 ]
26 * - valuesData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] (two components per x-axis data)
27 * - fillValue = NaN
28 * - and resolution = 2;
29 *
30 * For the x axis, we calculate as data holes: [3, 9, 11, 13]. These holes are added to the
31 * x-axis data, and NaNs (two per x-axis data) are added to the values:
32 * => xAxisData = [0, 1, 3, 5, 7, 9, 11, 13, 14 ]
33 * => valuesData = [0, 1, 2, 3, NaN, NaN, 4, 5, 6, 7, NaN, NaN, NaN, NaN, NaN, NaN, 8, 9]
34 *
35 * @param xAxisData the x-axis data of the data series
36 * @param valuesData the values data of the data series
37 * @param resolution the resoultion (on x-axis) used to determinate data holes
38 * @param fillValue the fill value used for data holes in the values data
39 *
40 * @remarks There is no control over the consistency between x-axis data and values data. The
41 * method considers that the data is well formed (the total number of values data is a multiple
42 * of the number of x-axis data)
43 */
44 static void fillDataHoles(std::vector<double> &xAxisData, std::vector<double> &valuesData,
45 double resolution,
46 double fillValue = std::numeric_limits<double>::quiet_NaN());
10 };
47 };
11
48
12 #endif // SCIQLOP_DATASERIESUTILS_H
49 #endif // SCIQLOP_DATASERIESUTILS_H
@@ -1,1 +1,59
1 #include "Data/DataSeriesUtils.h"
1 #include "Data/DataSeriesUtils.h"
2
3 Q_LOGGING_CATEGORY(LOG_DataSeriesUtils, "DataSeriesUtils")
4
5 void DataSeriesUtils::fillDataHoles(std::vector<double> &xAxisData, std::vector<double> &valuesData,
6 double resolution, double fillValue)
7 {
8 if (resolution == 0. || std::isnan(resolution)) {
9 qCWarning(LOG_DataSeriesUtils())
10 << "Can't fill data holes with a null resolution, no changes will be made";
11 return;
12 }
13
14 if (xAxisData.empty()) {
15 qCWarning(LOG_DataSeriesUtils())
16 << "Can't fill data holes for empty data, no changes will be made";
17 return;
18 }
19
20 // Gets the number of values per x-axis data
21 auto nbComponents = valuesData.size() / xAxisData.size();
22
23 // Generates fill values that will be used to complete values data
24 std::vector<double> fillValues(nbComponents, fillValue);
25
26 // Traverses the x-axis data
27 auto xAxisIt = xAxisData.begin();
28 while (xAxisIt != xAxisData.end()) {
29 // Stops at first value which has a gap greater than resolution with the value next to it
30 xAxisIt = std::adjacent_find(
31 xAxisIt, xAxisData.end(),
32 [resolution](const auto &a, const auto &b) { return (b - a) > resolution; });
33
34 if (xAxisIt != xAxisData.end()) {
35 auto nextXAxisIt = xAxisIt + 1;
36
37 // Gets the values that has a gap greater than resolution between them
38 auto lowValue = *xAxisIt;
39 auto highValue = *nextXAxisIt;
40
41 // Completes holes between the two values by creating new values (according to the
42 // resolution)
43 for (auto i = lowValue + resolution; i < highValue; i += resolution) {
44 // Gets the iterator of values data from which to insert fill values
45 auto nextValuesIt = valuesData.begin()
46 + std::distance(xAxisData.begin(), nextXAxisIt) * nbComponents;
47
48 // New value is inserted before nextXAxisIt
49 nextXAxisIt = xAxisData.insert(nextXAxisIt, i) + 1;
50
51 // New values are inserted before nextValuesIt
52 valuesData.insert(nextValuesIt, fillValues.begin(), fillValues.end());
53 }
54
55 // Moves to the next value to continue loop on the x-axis data
56 xAxisIt = nextXAxisIt;
57 }
58 }
59 }
General Comments 0
You need to be logged in to leave comments. Login now