##// END OF EJS Templates
Add continuous auto scale for color scale on spectrograms...
jeandet -
r1466:15fc74768e17
parent child
Show More
@@ -1,545 +1,545
1 #include "Visualization/VisualizationGraphHelper.h"
1 #include "Visualization/VisualizationGraphHelper.h"
2 #include "Visualization/qcustomplot.h"
2 #include "Visualization/qcustomplot.h"
3
3
4 #include <Data/ScalarTimeSerie.h>
4 #include <Data/ScalarTimeSerie.h>
5 #include <Data/SpectrogramTimeSerie.h>
5 #include <Data/SpectrogramTimeSerie.h>
6 #include <Data/TimeSeriesUtils.h>
6 #include <Data/TimeSeriesUtils.h>
7 #include <Data/VectorTimeSerie.h>
7 #include <Data/VectorTimeSerie.h>
8
8
9 #include <Common/cpp_utils.h>
9 #include <Common/cpp_utils.h>
10 #include <Variable/Variable2.h>
10 #include <Variable/Variable2.h>
11 #include <algorithm>
11 #include <algorithm>
12
12
13 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
13 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
14
14
15 namespace
15 namespace
16 {
16 {
17
17
18 class SqpDataContainer : public QCPGraphDataContainer
18 class SqpDataContainer : public QCPGraphDataContainer
19 {
19 {
20 public:
20 public:
21 void appendGraphData(const QCPGraphData& data) { mData.append(data); }
21 void appendGraphData(const QCPGraphData& data) { mData.append(data); }
22 };
22 };
23
23
24 /**
24 /**
25 * Struct used to create plottables, depending on the type of the data series from which to create
25 * Struct used to create plottables, depending on the type of the data series from which to create
26 * them
26 * them
27 * @tparam T the data series' type
27 * @tparam T the data series' type
28 * @remarks Default implementation can't create plottables
28 * @remarks Default implementation can't create plottables
29 */
29 */
30 template <typename T, typename Enabled = void>
30 template <typename T, typename Enabled = void>
31 struct PlottablesCreator
31 struct PlottablesCreator
32 {
32 {
33 static PlottablesMap createPlottables(QCustomPlot&, const std::shared_ptr<T>& dataSeries)
33 static PlottablesMap createPlottables(QCustomPlot&, const std::shared_ptr<T>& dataSeries)
34 {
34 {
35 return {};
35 return {};
36 }
36 }
37 };
37 };
38
38
39 PlottablesMap createGraphs(QCustomPlot& plot, int nbGraphs)
39 PlottablesMap createGraphs(QCustomPlot& plot, int nbGraphs)
40 {
40 {
41 PlottablesMap result {};
41 PlottablesMap result {};
42
42
43 // Creates {nbGraphs} QCPGraph to add to the plot
43 // Creates {nbGraphs} QCPGraph to add to the plot
44 for (auto i = 0; i < nbGraphs; ++i)
44 for (auto i = 0; i < nbGraphs; ++i)
45 {
45 {
46 auto graph = plot.addGraph();
46 auto graph = plot.addGraph();
47 result.insert({ i, graph });
47 result.insert({ i, graph });
48 }
48 }
49
49
50 plot.replot();
50 plot.replot();
51
51
52 return result;
52 return result;
53 }
53 }
54
54
55 /**
55 /**
56 * Specialization of PlottablesCreator for scalars
56 * Specialization of PlottablesCreator for scalars
57 * @sa ScalarSeries
57 * @sa ScalarSeries
58 */
58 */
59 template <typename T>
59 template <typename T>
60 struct PlottablesCreator<T, typename std::enable_if_t<std::is_base_of<ScalarTimeSerie, T>::value>>
60 struct PlottablesCreator<T, typename std::enable_if_t<std::is_base_of<ScalarTimeSerie, T>::value>>
61 {
61 {
62 static PlottablesMap createPlottables(QCustomPlot& plot, const std::shared_ptr<T>& dataSeries)
62 static PlottablesMap createPlottables(QCustomPlot& plot, const std::shared_ptr<T>& dataSeries)
63 {
63 {
64 return createGraphs(plot, 1);
64 return createGraphs(plot, 1);
65 }
65 }
66 };
66 };
67
67
68 /**
68 /**
69 * Specialization of PlottablesCreator for vectors
69 * Specialization of PlottablesCreator for vectors
70 * @sa VectorSeries
70 * @sa VectorSeries
71 */
71 */
72 template <typename T>
72 template <typename T>
73 struct PlottablesCreator<T, typename std::enable_if_t<std::is_base_of<VectorTimeSerie, T>::value>>
73 struct PlottablesCreator<T, typename std::enable_if_t<std::is_base_of<VectorTimeSerie, T>::value>>
74 {
74 {
75 static PlottablesMap createPlottables(QCustomPlot& plot, const std::shared_ptr<T>& dataSeries)
75 static PlottablesMap createPlottables(QCustomPlot& plot, const std::shared_ptr<T>& dataSeries)
76 {
76 {
77 return createGraphs(plot, 3);
77 return createGraphs(plot, 3);
78 }
78 }
79 };
79 };
80
80
81 /**
81 /**
82 * Specialization of PlottablesCreator for MultiComponentTimeSeries
82 * Specialization of PlottablesCreator for MultiComponentTimeSeries
83 * @sa VectorSeries
83 * @sa VectorSeries
84 */
84 */
85 template <typename T>
85 template <typename T>
86 struct PlottablesCreator<T,
86 struct PlottablesCreator<T,
87 typename std::enable_if_t<std::is_base_of<MultiComponentTimeSerie, T>::value>>
87 typename std::enable_if_t<std::is_base_of<MultiComponentTimeSerie, T>::value>>
88 {
88 {
89 static PlottablesMap createPlottables(QCustomPlot& plot, const std::shared_ptr<T>& dataSeries)
89 static PlottablesMap createPlottables(QCustomPlot& plot, const std::shared_ptr<T>& dataSeries)
90 {
90 {
91 return createGraphs(plot, dataSeries->size(1));
91 return createGraphs(plot, dataSeries->size(1));
92 }
92 }
93 };
93 };
94
94
95 /**
95 /**
96 * Specialization of PlottablesCreator for spectrograms
96 * Specialization of PlottablesCreator for spectrograms
97 * @sa SpectrogramSeries
97 * @sa SpectrogramSeries
98 */
98 */
99 template <typename T>
99 template <typename T>
100 struct PlottablesCreator<T,
100 struct PlottablesCreator<T,
101 typename std::enable_if_t<std::is_base_of<SpectrogramTimeSerie, T>::value>>
101 typename std::enable_if_t<std::is_base_of<SpectrogramTimeSerie, T>::value>>
102 {
102 {
103 static PlottablesMap createPlottables(QCustomPlot& plot, const std::shared_ptr<T>& dataSeries)
103 static PlottablesMap createPlottables(QCustomPlot& plot, const std::shared_ptr<T>& dataSeries)
104 {
104 {
105 PlottablesMap result {};
105 PlottablesMap result {};
106 result.insert({ 0, new QCPColorMap { plot.xAxis, plot.yAxis } });
106 result.insert({ 0, new QCPColorMap { plot.xAxis, plot.yAxis } });
107
107
108 plot.replot();
108 plot.replot();
109
109
110 return result;
110 return result;
111 }
111 }
112 };
112 };
113
113
114 /**
114 /**
115 * Struct used to update plottables, depending on the type of the data series from which to update
115 * Struct used to update plottables, depending on the type of the data series from which to update
116 * them
116 * them
117 * @tparam T the data series' type
117 * @tparam T the data series' type
118 * @remarks Default implementation can't update plottables
118 * @remarks Default implementation can't update plottables
119 */
119 */
120 template <typename T, typename Enabled = void>
120 template <typename T, typename Enabled = void>
121 struct PlottablesUpdater
121 struct PlottablesUpdater
122 {
122 {
123 static void setPlotYAxisRange(T&, const DateTimeRange&, QCustomPlot&)
123 static void setPlotYAxisRange(T&, const DateTimeRange&, QCustomPlot&)
124 {
124 {
125 qCCritical(LOG_VisualizationGraphHelper())
125 qCCritical(LOG_VisualizationGraphHelper())
126 << QObject::tr("Can't set plot y-axis range: unmanaged data series type");
126 << QObject::tr("Can't set plot y-axis range: unmanaged data series type");
127 }
127 }
128
128
129 static void updatePlottables(T&, PlottablesMap&, const DateTimeRange&, bool)
129 static void updatePlottables(T&, PlottablesMap&, const DateTimeRange&, bool)
130 {
130 {
131 qCCritical(LOG_VisualizationGraphHelper())
131 qCCritical(LOG_VisualizationGraphHelper())
132 << QObject::tr("Can't update plottables: unmanaged data series type");
132 << QObject::tr("Can't update plottables: unmanaged data series type");
133 }
133 }
134 };
134 };
135
135
136 /**
136 /**
137 * Specialization of PlottablesUpdater for scalars and vectors
137 * Specialization of PlottablesUpdater for scalars and vectors
138 * @sa ScalarSeries
138 * @sa ScalarSeries
139 * @sa VectorSeries
139 * @sa VectorSeries
140 */
140 */
141 template <typename T>
141 template <typename T>
142 struct PlottablesUpdater<T, typename std::enable_if_t<std::is_base_of<ScalarTimeSerie, T>::value>>
142 struct PlottablesUpdater<T, typename std::enable_if_t<std::is_base_of<ScalarTimeSerie, T>::value>>
143 {
143 {
144 static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot)
144 static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot)
145 {
145 {
146 auto minValue = 0., maxValue = 0.;
146 auto minValue = 0., maxValue = 0.;
147 if (auto serie = dynamic_cast<ScalarTimeSerie*>(&dataSeries))
147 if (auto serie = dynamic_cast<ScalarTimeSerie*>(&dataSeries))
148 {
148 {
149 if (serie->size())
149 if (serie->size())
150 {
150 {
151 maxValue = (*std::max_element(std::begin(*serie), std::end(*serie))).v();
151 maxValue = (*std::max_element(std::begin(*serie), std::end(*serie))).v();
152 minValue = (*std::min_element(std::begin(*serie), std::end(*serie))).v();
152 minValue = (*std::min_element(std::begin(*serie), std::end(*serie))).v();
153 }
153 }
154 }
154 }
155 plot.yAxis->setRange(QCPRange { minValue, maxValue });
155 plot.yAxis->setRange(QCPRange { minValue, maxValue });
156 }
156 }
157
157
158 static void updatePlottables(
158 static void updatePlottables(
159 T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes)
159 T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes)
160 {
160 {
161
161
162 // For each plottable to update, resets its data
162 // For each plottable to update, resets its data
163 for (const auto& plottable : plottables)
163 for (const auto& plottable : plottables)
164 {
164 {
165 if (auto graph = dynamic_cast<QCPGraph*>(plottable.second))
165 if (auto graph = dynamic_cast<QCPGraph*>(plottable.second))
166 {
166 {
167 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
167 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
168 if (auto serie = dynamic_cast<ScalarTimeSerie*>(&dataSeries))
168 if (auto serie = dynamic_cast<ScalarTimeSerie*>(&dataSeries))
169 {
169 {
170 std::for_each(
170 std::for_each(
171 std::begin(*serie), std::end(*serie), [&dataContainer](const auto& value) {
171 std::begin(*serie), std::end(*serie), [&dataContainer](const auto& value) {
172 dataContainer->appendGraphData(QCPGraphData(value.t(), value.v()));
172 dataContainer->appendGraphData(QCPGraphData(value.t(), value.v()));
173 });
173 });
174 }
174 }
175 graph->setData(dataContainer);
175 graph->setData(dataContainer);
176 }
176 }
177 }
177 }
178
178
179 if (!plottables.empty())
179 if (!plottables.empty())
180 {
180 {
181 auto plot = plottables.begin()->second->parentPlot();
181 auto plot = plottables.begin()->second->parentPlot();
182
182
183 if (rescaleAxes)
183 if (rescaleAxes)
184 {
184 {
185 plot->rescaleAxes();
185 plot->rescaleAxes();
186 }
186 }
187 }
187 }
188 }
188 }
189 };
189 };
190
190
191
191
192 template <typename T>
192 template <typename T>
193 struct PlottablesUpdater<T, typename std::enable_if_t<std::is_base_of<VectorTimeSerie, T>::value>>
193 struct PlottablesUpdater<T, typename std::enable_if_t<std::is_base_of<VectorTimeSerie, T>::value>>
194 {
194 {
195 static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot)
195 static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot)
196 {
196 {
197 double minValue = 0., maxValue = 0.;
197 double minValue = 0., maxValue = 0.;
198 if (auto serie = dynamic_cast<VectorTimeSerie*>(&dataSeries))
198 if (auto serie = dynamic_cast<VectorTimeSerie*>(&dataSeries))
199 {
199 {
200 std::for_each(
200 std::for_each(
201 std::begin(*serie), std::end(*serie), [&minValue, &maxValue](const auto& v) {
201 std::begin(*serie), std::end(*serie), [&minValue, &maxValue](const auto& v) {
202 minValue = std::min({ minValue, v.v().x, v.v().y, v.v().z });
202 minValue = std::min({ minValue, v.v().x, v.v().y, v.v().z });
203 maxValue = std::max({ maxValue, v.v().x, v.v().y, v.v().z });
203 maxValue = std::max({ maxValue, v.v().x, v.v().y, v.v().z });
204 });
204 });
205 }
205 }
206
206
207 plot.yAxis->setRange(QCPRange { minValue, maxValue });
207 plot.yAxis->setRange(QCPRange { minValue, maxValue });
208 }
208 }
209
209
210 static void updatePlottables(
210 static void updatePlottables(
211 T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes)
211 T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes)
212 {
212 {
213
213
214 // For each plottable to update, resets its data
214 // For each plottable to update, resets its data
215 for (const auto& plottable : plottables)
215 for (const auto& plottable : plottables)
216 {
216 {
217 if (auto graph = dynamic_cast<QCPGraph*>(plottable.second))
217 if (auto graph = dynamic_cast<QCPGraph*>(plottable.second))
218 {
218 {
219 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
219 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
220 if (auto serie = dynamic_cast<VectorTimeSerie*>(&dataSeries))
220 if (auto serie = dynamic_cast<VectorTimeSerie*>(&dataSeries))
221 {
221 {
222 switch (plottable.first)
222 switch (plottable.first)
223 {
223 {
224 case 0:
224 case 0:
225 std::for_each(std::begin(*serie), std::end(*serie),
225 std::for_each(std::begin(*serie), std::end(*serie),
226 [&dataContainer](const auto& value) {
226 [&dataContainer](const auto& value) {
227 dataContainer->appendGraphData(
227 dataContainer->appendGraphData(
228 QCPGraphData(value.t(), value.v().x));
228 QCPGraphData(value.t(), value.v().x));
229 });
229 });
230 break;
230 break;
231 case 1:
231 case 1:
232 std::for_each(std::begin(*serie), std::end(*serie),
232 std::for_each(std::begin(*serie), std::end(*serie),
233 [&dataContainer](const auto& value) {
233 [&dataContainer](const auto& value) {
234 dataContainer->appendGraphData(
234 dataContainer->appendGraphData(
235 QCPGraphData(value.t(), value.v().y));
235 QCPGraphData(value.t(), value.v().y));
236 });
236 });
237 break;
237 break;
238 case 2:
238 case 2:
239 std::for_each(std::begin(*serie), std::end(*serie),
239 std::for_each(std::begin(*serie), std::end(*serie),
240 [&dataContainer](const auto& value) {
240 [&dataContainer](const auto& value) {
241 dataContainer->appendGraphData(
241 dataContainer->appendGraphData(
242 QCPGraphData(value.t(), value.v().z));
242 QCPGraphData(value.t(), value.v().z));
243 });
243 });
244 break;
244 break;
245 default:
245 default:
246 break;
246 break;
247 }
247 }
248 }
248 }
249 graph->setData(dataContainer);
249 graph->setData(dataContainer);
250 }
250 }
251 }
251 }
252
252
253 if (!plottables.empty())
253 if (!plottables.empty())
254 {
254 {
255 auto plot = plottables.begin()->second->parentPlot();
255 auto plot = plottables.begin()->second->parentPlot();
256
256
257 if (rescaleAxes)
257 if (rescaleAxes)
258 {
258 {
259 plot->rescaleAxes();
259 plot->rescaleAxes();
260 }
260 }
261 }
261 }
262 }
262 }
263 };
263 };
264
264
265
265
266 template <typename T>
266 template <typename T>
267 struct PlottablesUpdater<T,
267 struct PlottablesUpdater<T,
268 typename std::enable_if_t<std::is_base_of<MultiComponentTimeSerie, T>::value>>
268 typename std::enable_if_t<std::is_base_of<MultiComponentTimeSerie, T>::value>>
269 {
269 {
270 static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot)
270 static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot)
271 {
271 {
272 double minValue = 0., maxValue = 0.;
272 double minValue = 0., maxValue = 0.;
273 if (auto serie = dynamic_cast<MultiComponentTimeSerie*>(&dataSeries))
273 if (auto serie = dynamic_cast<MultiComponentTimeSerie*>(&dataSeries))
274 {
274 {
275 std::for_each(
275 std::for_each(
276 std::begin(*serie), std::end(*serie), [&minValue, &maxValue](const auto& v) {
276 std::begin(*serie), std::end(*serie), [&minValue, &maxValue](const auto& v) {
277 minValue = std::min(minValue, std::min_element(v.begin(), v.end())->v());
277 minValue = std::min(minValue, std::min_element(v.begin(), v.end())->v());
278 maxValue = std::max(maxValue, std::max_element(v.begin(), v.end())->v());
278 maxValue = std::max(maxValue, std::max_element(v.begin(), v.end())->v());
279 });
279 });
280 }
280 }
281 plot.yAxis->setRange(QCPRange { minValue, maxValue });
281 plot.yAxis->setRange(QCPRange { minValue, maxValue });
282 }
282 }
283
283
284 static void updatePlottables(
284 static void updatePlottables(
285 T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes)
285 T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes)
286 {
286 {
287 for (const auto& plottable : plottables)
287 for (const auto& plottable : plottables)
288 {
288 {
289 if (auto graph = dynamic_cast<QCPGraph*>(plottable.second))
289 if (auto graph = dynamic_cast<QCPGraph*>(plottable.second))
290 {
290 {
291 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
291 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
292 if (auto serie = dynamic_cast<MultiComponentTimeSerie*>(&dataSeries))
292 if (auto serie = dynamic_cast<MultiComponentTimeSerie*>(&dataSeries))
293 {
293 {
294 // TODO
294 // TODO
295 std::for_each(std::begin(*serie), std::end(*serie),
295 std::for_each(std::begin(*serie), std::end(*serie),
296 [&dataContainer, component = plottable.first](const auto& value) {
296 [&dataContainer, component = plottable.first](const auto& value) {
297 dataContainer->appendGraphData(
297 dataContainer->appendGraphData(
298 QCPGraphData(value.t(), value[component]));
298 QCPGraphData(value.t(), value[component]));
299 });
299 });
300 }
300 }
301 graph->setData(dataContainer);
301 graph->setData(dataContainer);
302 }
302 }
303 }
303 }
304
304
305 if (!plottables.empty())
305 if (!plottables.empty())
306 {
306 {
307 auto plot = plottables.begin()->second->parentPlot();
307 auto plot = plottables.begin()->second->parentPlot();
308
308
309 if (rescaleAxes)
309 if (rescaleAxes)
310 {
310 {
311 plot->rescaleAxes();
311 plot->rescaleAxes();
312 }
312 }
313 }
313 }
314 }
314 }
315 };
315 };
316
316
317 /**
317 /**
318 * Specialization of PlottablesUpdater for spectrograms
318 * Specialization of PlottablesUpdater for spectrograms
319 * @sa SpectrogramSeries
319 * @sa SpectrogramSeries
320 */
320 */
321 template <typename T>
321 template <typename T>
322 struct PlottablesUpdater<T,
322 struct PlottablesUpdater<T,
323 typename std::enable_if_t<std::is_base_of<SpectrogramTimeSerie, T>::value>>
323 typename std::enable_if_t<std::is_base_of<SpectrogramTimeSerie, T>::value>>
324 {
324 {
325 static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot)
325 static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot)
326 {
326 {
327 auto [minValue, maxValue] = dataSeries.axis_range(1);
327 auto [minValue, maxValue] = dataSeries.axis_range(1);
328 std::cout << "min=" << minValue << " max=" << maxValue << std::endl;
328 std::cout << "min=" << minValue << " max=" << maxValue << std::endl;
329 plot.yAxis->setRange(QCPRange { minValue, maxValue });
329 plot.yAxis->setRange(QCPRange { minValue, maxValue });
330 }
330 }
331
331
332 static void updatePlottables(
332 static void updatePlottables(
333 T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes)
333 T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes)
334 {
334 {
335 if (plottables.empty())
335 if (plottables.empty())
336 {
336 {
337 qCDebug(LOG_VisualizationGraphHelper())
337 qCDebug(LOG_VisualizationGraphHelper())
338 << QObject::tr("Can't update spectrogram: no colormap has been associated");
338 << QObject::tr("Can't update spectrogram: no colormap has been associated");
339 return;
339 return;
340 }
340 }
341
341
342 // Gets the colormap to update (normally there is only one colormap)
342 // Gets the colormap to update (normally there is only one colormap)
343 Q_ASSERT(plottables.size() == 1);
343 Q_ASSERT(plottables.size() == 1);
344 auto colormap = dynamic_cast<QCPColorMap*>(plottables.at(0));
344 auto colormap = dynamic_cast<QCPColorMap*>(plottables.at(0));
345 Q_ASSERT(colormap != nullptr);
345 Q_ASSERT(colormap != nullptr);
346 auto plot = colormap->parentPlot();
346 auto plot = colormap->parentPlot();
347 auto [minValue, maxValue] = dataSeries.axis_range(1);
347 auto [minValue, maxValue] = dataSeries.axis_range(1);
348 plot->yAxis->setRange(QCPRange { minValue, maxValue });
348 plot->yAxis->setRange(QCPRange { minValue, maxValue });
349 if (auto serie = dynamic_cast<SpectrogramTimeSerie*>(&dataSeries))
349 if (auto serie = dynamic_cast<SpectrogramTimeSerie*>(&dataSeries))
350 {
350 {
351 if (serie->size(0) > 2)
351 if (serie->size(0) > 2)
352 {
352 {
353 const auto& xAxis = serie->axis(0);
353 const auto& xAxis = serie->axis(0);
354 auto yAxis = serie->axis(1); // copy for in place reverse order
354 auto yAxis = serie->axis(1); // copy for in place reverse order
355 std::reverse(std::begin(yAxis), std::end(yAxis));
355 std::reverse(std::begin(yAxis), std::end(yAxis));
356 auto xAxisProperties = TimeSeriesUtils::axis_analysis<TimeSeriesUtils::IsLinear,
356 auto xAxisProperties = TimeSeriesUtils::axis_analysis<TimeSeriesUtils::IsLinear,
357 TimeSeriesUtils::CheckMedian>(xAxis);
357 TimeSeriesUtils::CheckMedian>(xAxis);
358 auto yAxisProperties = TimeSeriesUtils::axis_analysis<TimeSeriesUtils::IsLog,
358 auto yAxisProperties = TimeSeriesUtils::axis_analysis<TimeSeriesUtils::IsLog,
359 TimeSeriesUtils::DontCheckMedian>(yAxis);
359 TimeSeriesUtils::DontCheckMedian>(yAxis);
360
360
361 int colormap_h_size = std::min(32000,
361 int colormap_h_size = std::min(32000,
362 static_cast<int>(xAxisProperties.range / xAxisProperties.max_resolution));
362 static_cast<int>(xAxisProperties.range / xAxisProperties.max_resolution));
363 auto colormap_v_size
363 auto colormap_v_size
364 = static_cast<int>(yAxisProperties.range / yAxisProperties.max_resolution);
364 = static_cast<int>(yAxisProperties.range / yAxisProperties.max_resolution);
365
365
366 colormap->data()->setSize(colormap_h_size, colormap_v_size);
366 colormap->data()->setSize(colormap_h_size, colormap_v_size);
367 colormap->data()->setRange(
367 colormap->data()->setRange(
368 QCPRange { serie->begin()->t(), (serie->end() - 1)->t() },
368 QCPRange { serie->begin()->t(), (serie->end() - 1)->t() },
369 { minValue, maxValue });
369 { minValue, maxValue });
370
370
371 std::vector<std::pair<int, int>> y_access_pattern;
371 std::vector<std::pair<int, int>> y_access_pattern;
372 for (int y_index = 0, cel_index = 0; y_index < colormap_v_size; y_index++)
372 for (int y_index = 0, cel_index = 0; y_index < colormap_v_size; y_index++)
373 {
373 {
374 double current_y = pow(
374 double current_y = pow(
375 10., (yAxisProperties.max_resolution * y_index) + std::log10(minValue));
375 10., (yAxisProperties.max_resolution * y_index) + std::log10(minValue));
376 if (current_y > yAxis[cel_index])
376 if (current_y > yAxis[cel_index])
377 cel_index++;
377 cel_index++;
378 y_access_pattern.push_back({ y_index, yAxis.size() - 1 - cel_index });
378 y_access_pattern.push_back({ y_index, yAxis.size() - 1 - cel_index });
379 }
379 }
380
380
381 auto line = serie->begin();
381 auto line = serie->begin();
382 double current_time = xAxis[0];
382 double current_time = xAxis[0];
383 int x_index = 0;
383 int x_index = 0;
384
384
385 while (x_index < colormap_h_size)
385 while (x_index < colormap_h_size)
386 {
386 {
387 if (current_time > (line + 1)->t())
387 if (current_time > (line + 1)->t())
388 {
388 {
389 line++;
389 line++;
390 }
390 }
391 if ((current_time - xAxis[0])
391 if ((current_time - xAxis[0])
392 > (x_index * xAxisProperties.range / colormap_h_size))
392 > (x_index * xAxisProperties.range / colormap_h_size))
393 {
393 {
394 x_index++;
394 x_index++;
395 }
395 }
396 if (line->t() <= (current_time + xAxisProperties.max_resolution))
396 if (line->t() <= (current_time + xAxisProperties.max_resolution))
397 {
397 {
398 std::for_each(std::cbegin(y_access_pattern), std::cend(y_access_pattern),
398 std::for_each(std::cbegin(y_access_pattern), std::cend(y_access_pattern),
399 [&colormap, &line, x_index](const auto& acc) {
399 [&colormap, &line, x_index](const auto& acc) {
400 colormap->data()->setCell(x_index, acc.first, (*line)[acc.second]);
400 colormap->data()->setCell(x_index, acc.first, (*line)[acc.second]);
401 });
401 });
402 }
402 }
403 else
403 else
404 {
404 {
405 for (int y_index = 0; y_index < colormap_v_size; y_index++)
405 for (int y_index = 0; y_index < colormap_v_size; y_index++)
406 {
406 {
407 colormap->data()->setCell(x_index, y_index, std::nan(""));
407 colormap->data()->setCell(x_index, y_index, std::nan(""));
408 }
408 }
409 }
409 }
410 current_time += xAxisProperties.max_resolution;
410 current_time += xAxisProperties.max_resolution;
411 }
411 }
412 }
412 }
413
413 colormap->rescaleDataRange(true);
414 if (rescaleAxes)
414 if (rescaleAxes)
415 {
415 {
416 plot->rescaleAxes();
416 plot->rescaleAxes();
417 }
417 }
418 }
418 }
419 }
419 }
420 };
420 };
421
421
422 /**
422 /**
423 * Helper used to create/update plottables
423 * Helper used to create/update plottables
424 */
424 */
425 struct IPlottablesHelper
425 struct IPlottablesHelper
426 {
426 {
427 virtual ~IPlottablesHelper() noexcept = default;
427 virtual ~IPlottablesHelper() noexcept = default;
428 virtual PlottablesMap create(QCustomPlot& plot) const = 0;
428 virtual PlottablesMap create(QCustomPlot& plot) const = 0;
429 virtual void setYAxisRange(const DateTimeRange& xAxisRange, QCustomPlot& plot) const = 0;
429 virtual void setYAxisRange(const DateTimeRange& xAxisRange, QCustomPlot& plot) const = 0;
430 virtual void update(
430 virtual void update(
431 PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes = false) const = 0;
431 PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes = false) const = 0;
432 };
432 };
433
433
434 /**
434 /**
435 * Default implementation of IPlottablesHelper, which takes data series to create/update
435 * Default implementation of IPlottablesHelper, which takes data series to create/update
436 * plottables
436 * plottables
437 * @tparam T the data series' type
437 * @tparam T the data series' type
438 */
438 */
439 template <typename T>
439 template <typename T>
440 struct PlottablesHelper : public IPlottablesHelper
440 struct PlottablesHelper : public IPlottablesHelper
441 {
441 {
442 explicit PlottablesHelper(std::shared_ptr<T> dataSeries) : m_DataSeries { dataSeries } {}
442 explicit PlottablesHelper(std::shared_ptr<T> dataSeries) : m_DataSeries { dataSeries } {}
443
443
444 PlottablesMap create(QCustomPlot& plot) const override
444 PlottablesMap create(QCustomPlot& plot) const override
445 {
445 {
446 return PlottablesCreator<T>::createPlottables(plot, m_DataSeries);
446 return PlottablesCreator<T>::createPlottables(plot, m_DataSeries);
447 }
447 }
448
448
449 void update(
449 void update(
450 PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes) const override
450 PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes) const override
451 {
451 {
452 if (m_DataSeries)
452 if (m_DataSeries)
453 {
453 {
454 PlottablesUpdater<T>::updatePlottables(*m_DataSeries, plottables, range, rescaleAxes);
454 PlottablesUpdater<T>::updatePlottables(*m_DataSeries, plottables, range, rescaleAxes);
455 }
455 }
456 else
456 else
457 {
457 {
458 qCCritical(LOG_VisualizationGraphHelper()) << "Can't update plottables: inconsistency "
458 qCCritical(LOG_VisualizationGraphHelper()) << "Can't update plottables: inconsistency "
459 "between the type of data series and the "
459 "between the type of data series and the "
460 "type supposed";
460 "type supposed";
461 }
461 }
462 }
462 }
463
463
464 void setYAxisRange(const DateTimeRange& xAxisRange, QCustomPlot& plot) const override
464 void setYAxisRange(const DateTimeRange& xAxisRange, QCustomPlot& plot) const override
465 {
465 {
466 if (m_DataSeries)
466 if (m_DataSeries)
467 {
467 {
468 PlottablesUpdater<T>::setPlotYAxisRange(*m_DataSeries, xAxisRange, plot);
468 PlottablesUpdater<T>::setPlotYAxisRange(*m_DataSeries, xAxisRange, plot);
469 }
469 }
470 else
470 else
471 {
471 {
472 qCCritical(LOG_VisualizationGraphHelper()) << "Can't update plottables: inconsistency "
472 qCCritical(LOG_VisualizationGraphHelper()) << "Can't update plottables: inconsistency "
473 "between the type of data series and the "
473 "between the type of data series and the "
474 "type supposed";
474 "type supposed";
475 }
475 }
476 }
476 }
477
477
478 std::shared_ptr<T> m_DataSeries;
478 std::shared_ptr<T> m_DataSeries;
479 };
479 };
480
480
481 /// Creates IPlottablesHelper according to the type of data series a variable holds
481 /// Creates IPlottablesHelper according to the type of data series a variable holds
482 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<Variable2> variable) noexcept
482 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<Variable2> variable) noexcept
483 {
483 {
484 switch (variable->type())
484 switch (variable->type())
485 {
485 {
486 case DataSeriesType::SCALAR:
486 case DataSeriesType::SCALAR:
487 return std::make_unique<PlottablesHelper<ScalarTimeSerie>>(
487 return std::make_unique<PlottablesHelper<ScalarTimeSerie>>(
488 std::dynamic_pointer_cast<ScalarTimeSerie>(variable->data()));
488 std::dynamic_pointer_cast<ScalarTimeSerie>(variable->data()));
489 case DataSeriesType::SPECTROGRAM:
489 case DataSeriesType::SPECTROGRAM:
490 return std::make_unique<PlottablesHelper<SpectrogramTimeSerie>>(
490 return std::make_unique<PlottablesHelper<SpectrogramTimeSerie>>(
491 std::dynamic_pointer_cast<SpectrogramTimeSerie>(variable->data()));
491 std::dynamic_pointer_cast<SpectrogramTimeSerie>(variable->data()));
492 case DataSeriesType::VECTOR:
492 case DataSeriesType::VECTOR:
493 return std::make_unique<PlottablesHelper<VectorTimeSerie>>(
493 return std::make_unique<PlottablesHelper<VectorTimeSerie>>(
494 std::dynamic_pointer_cast<VectorTimeSerie>(variable->data()));
494 std::dynamic_pointer_cast<VectorTimeSerie>(variable->data()));
495 case DataSeriesType::MULTICOMPONENT:
495 case DataSeriesType::MULTICOMPONENT:
496 return std::make_unique<PlottablesHelper<MultiComponentTimeSerie>>(
496 return std::make_unique<PlottablesHelper<MultiComponentTimeSerie>>(
497 std::dynamic_pointer_cast<MultiComponentTimeSerie>(variable->data()));
497 std::dynamic_pointer_cast<MultiComponentTimeSerie>(variable->data()));
498 default:
498 default:
499 // Creates default helper
499 // Creates default helper
500 break;
500 break;
501 }
501 }
502
502
503 return std::make_unique<PlottablesHelper<TimeSeries::ITimeSerie>>(nullptr);
503 return std::make_unique<PlottablesHelper<TimeSeries::ITimeSerie>>(nullptr);
504 }
504 }
505
505
506 } // namespace
506 } // namespace
507
507
508 PlottablesMap VisualizationGraphHelper::create(
508 PlottablesMap VisualizationGraphHelper::create(
509 std::shared_ptr<Variable2> variable, QCustomPlot& plot) noexcept
509 std::shared_ptr<Variable2> variable, QCustomPlot& plot) noexcept
510 {
510 {
511 if (variable)
511 if (variable)
512 {
512 {
513 auto helper = createHelper(variable);
513 auto helper = createHelper(variable);
514 auto plottables = helper->create(plot);
514 auto plottables = helper->create(plot);
515 return plottables;
515 return plottables;
516 }
516 }
517 else
517 else
518 {
518 {
519 qCDebug(LOG_VisualizationGraphHelper())
519 qCDebug(LOG_VisualizationGraphHelper())
520 << QObject::tr("Can't create graph plottables : the variable is null");
520 << QObject::tr("Can't create graph plottables : the variable is null");
521 return PlottablesMap {};
521 return PlottablesMap {};
522 }
522 }
523 }
523 }
524
524
525 void VisualizationGraphHelper::setYAxisRange(
525 void VisualizationGraphHelper::setYAxisRange(
526 std::shared_ptr<Variable2> variable, QCustomPlot& plot) noexcept
526 std::shared_ptr<Variable2> variable, QCustomPlot& plot) noexcept
527 {
527 {
528 if (variable)
528 if (variable)
529 {
529 {
530 auto helper = createHelper(variable);
530 auto helper = createHelper(variable);
531 helper->setYAxisRange(variable->range(), plot);
531 helper->setYAxisRange(variable->range(), plot);
532 }
532 }
533 else
533 else
534 {
534 {
535 qCDebug(LOG_VisualizationGraphHelper())
535 qCDebug(LOG_VisualizationGraphHelper())
536 << QObject::tr("Can't set y-axis range of plot: the variable is null");
536 << QObject::tr("Can't set y-axis range of plot: the variable is null");
537 }
537 }
538 }
538 }
539
539
540 void VisualizationGraphHelper::updateData(
540 void VisualizationGraphHelper::updateData(
541 PlottablesMap& plottables, std::shared_ptr<Variable2> variable, const DateTimeRange& dateTime)
541 PlottablesMap& plottables, std::shared_ptr<Variable2> variable, const DateTimeRange& dateTime)
542 {
542 {
543 auto helper = createHelper(variable);
543 auto helper = createHelper(variable);
544 helper->update(plottables, dateTime);
544 helper->update(plottables, dateTime);
545 }
545 }
General Comments 0
You need to be logged in to leave comments. Login now