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