##// END OF EJS Templates
MultiComponent TS almost complete...
jeandet -
r1432:db5304cf6c8c
parent child
Show More
@@ -1,1 +1,1
1 Subproject commit 41273d8529cddde1c8b6bcea03d71d9cd1a18c06
1 Subproject commit 9a080a34054c21a67236f761e8843005c07ff0ba
@@ -1,213 +1,217
1 #include "Visualization/AxisRenderingUtils.h"
1 #include "Visualization/AxisRenderingUtils.h"
2
2
3 #include <Data/ScalarTimeSerie.h>
3 #include <Data/ScalarTimeSerie.h>
4 #include <Data/SpectrogramTimeSerie.h>
4 #include <Data/SpectrogramTimeSerie.h>
5 #include <Data/VectorTimeSerie.h>
5 #include <Data/VectorTimeSerie.h>
6
6
7 #include <Variable/Variable2.h>
7 #include <Variable/Variable2.h>
8
8
9 #include <Visualization/SqpColorScale.h>
9 #include <Visualization/SqpColorScale.h>
10 #include <Visualization/qcustomplot.h>
10 #include <Visualization/qcustomplot.h>
11
11
12 Q_LOGGING_CATEGORY(LOG_AxisRenderingUtils, "AxisRenderingUtils")
12 Q_LOGGING_CATEGORY(LOG_AxisRenderingUtils, "AxisRenderingUtils")
13
13
14 namespace
14 namespace
15 {
15 {
16
16
17 /// Format for datetimes on a axis
17 /// Format for datetimes on a axis
18 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
18 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
19
19
20 const auto NUMBER_FORMAT = 'g';
20 const auto NUMBER_FORMAT = 'g';
21 const auto NUMBER_PRECISION = 9;
21 const auto NUMBER_PRECISION = 9;
22
22
23 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
23 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
24 /// non-time data
24 /// non-time data
25 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis, QCPAxis::ScaleType scaleType)
25 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis, QCPAxis::ScaleType scaleType)
26 {
26 {
27 if (isTimeAxis)
27 if (isTimeAxis)
28 {
28 {
29 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
29 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
30 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
30 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
31 dateTicker->setDateTimeSpec(Qt::UTC);
31 dateTicker->setDateTimeSpec(Qt::UTC);
32
32
33 return dateTicker;
33 return dateTicker;
34 }
34 }
35 else if (scaleType == QCPAxis::stLogarithmic)
35 else if (scaleType == QCPAxis::stLogarithmic)
36 {
36 {
37 return QSharedPointer<QCPAxisTickerLog>::create();
37 return QSharedPointer<QCPAxisTickerLog>::create();
38 }
38 }
39 else
39 else
40 {
40 {
41 // default ticker
41 // default ticker
42 return QSharedPointer<QCPAxisTicker>::create();
42 return QSharedPointer<QCPAxisTicker>::create();
43 }
43 }
44 }
44 }
45
45
46 /**
46 /**
47 * Sets properties of the axis passed as parameter
47 * Sets properties of the axis passed as parameter
48 * @param axis the axis to set
48 * @param axis the axis to set
49 * @param unit the unit to set for the axis
49 * @param unit the unit to set for the axis
50 * @param scaleType the scale type to set for the axis
50 * @param scaleType the scale type to set for the axis
51 */
51 */
52 void setAxisProperties(QCPAxis& axis, const std::string& unit, bool isTime,
52 void setAxisProperties(QCPAxis& axis, const std::string& unit, bool isTime,
53 QCPAxis::ScaleType scaleType = QCPAxis::stLinear)
53 QCPAxis::ScaleType scaleType = QCPAxis::stLinear)
54 {
54 {
55 // label (unit name)
55 // label (unit name)
56 axis.setLabel(QString::fromStdString(unit));
56 axis.setLabel(QString::fromStdString(unit));
57
57
58 // scale type
58 // scale type
59 axis.setScaleType(scaleType);
59 axis.setScaleType(scaleType);
60 if (scaleType == QCPAxis::stLogarithmic)
60 if (scaleType == QCPAxis::stLogarithmic)
61 {
61 {
62 // Scientific notation
62 // Scientific notation
63 axis.setNumberPrecision(0);
63 axis.setNumberPrecision(0);
64 axis.setNumberFormat("eb");
64 axis.setNumberFormat("eb");
65 }
65 }
66
66
67 // ticker (depending on the type of unit)
67 // ticker (depending on the type of unit)
68 axis.setTicker(axisTicker(isTime, scaleType));
68 axis.setTicker(axisTicker(isTime, scaleType));
69 }
69 }
70
70
71 /**
71 /**
72 * Delegate used to set axes properties
72 * Delegate used to set axes properties
73 */
73 */
74 template <typename T, typename Enabled = void>
74 template <typename T, typename Enabled = void>
75 struct AxisSetter
75 struct AxisSetter
76 {
76 {
77 static void setProperties(QCustomPlot&, SqpColorScale&)
77 static void setProperties(QCustomPlot&, SqpColorScale&)
78 {
78 {
79 // Default implementation does nothing
79 // Default implementation does nothing
80 qCCritical(LOG_AxisRenderingUtils()) << "Can't set axis properties: unmanaged type of data";
80 qCCritical(LOG_AxisRenderingUtils()) << "Can't set axis properties: unmanaged type of data";
81 }
81 }
82
82
83 static void setUnits(T&, QCustomPlot&, SqpColorScale&)
83 static void setUnits(T&, QCustomPlot&, SqpColorScale&)
84 {
84 {
85 // Default implementation does nothing
85 // Default implementation does nothing
86 qCCritical(LOG_AxisRenderingUtils()) << "Can't set axis units: unmanaged type of data";
86 qCCritical(LOG_AxisRenderingUtils()) << "Can't set axis units: unmanaged type of data";
87 }
87 }
88 };
88 };
89
89
90 /**
90 /**
91 * Specialization of AxisSetter for scalars and vectors
91 * Specialization of AxisSetter for scalars and vectors
92 * @sa ScalarSeries
92 * @sa ScalarSeries
93 * @sa VectorSeries
93 * @sa VectorSeries
94 */
94 */
95 template <typename T>
95 template <typename T>
96 struct AxisSetter<T,
96 struct AxisSetter<T,
97 typename std::enable_if_t<std::is_base_of<ScalarTimeSerie, T>::value
97 typename std::enable_if_t<std::is_base_of<ScalarTimeSerie, T>::value
98 or std::is_base_of<VectorTimeSerie, T>::value>>
98 or std::is_base_of<VectorTimeSerie, T>::value
99 or std::is_base_of<MultiComponentTimeSerie, T>::value>>
99 {
100 {
100 static void setProperties(QCustomPlot&, SqpColorScale&)
101 static void setProperties(QCustomPlot&, SqpColorScale&)
101 {
102 {
102 // Nothing to do
103 // Nothing to do
103 }
104 }
104
105
105 static void setUnits(T& dataSeries, QCustomPlot& plot, SqpColorScale&)
106 static void setUnits(T& dataSeries, QCustomPlot& plot, SqpColorScale&)
106 {
107 {
107 auto serie = dynamic_cast<TimeSeries::ITimeSerie*>(&dataSeries);
108 auto serie = dynamic_cast<TimeSeries::ITimeSerie*>(&dataSeries);
108 setAxisProperties(*plot.xAxis, "s", true);
109 setAxisProperties(*plot.xAxis, "s", true);
109 setAxisProperties(*plot.yAxis, serie->unit(1), false);
110 setAxisProperties(*plot.yAxis, serie->unit(1), false);
110 }
111 }
111 };
112 };
112
113
113 /**
114 /**
114 * Specialization of AxisSetter for spectrograms
115 * Specialization of AxisSetter for spectrograms
115 * @sa SpectrogramSeries
116 * @sa SpectrogramSeries
116 */
117 */
117 template <typename T>
118 template <typename T>
118 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<SpectrogramTimeSerie, T>::value>>
119 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<SpectrogramTimeSerie, T>::value>>
119 {
120 {
120 static void setProperties(QCustomPlot& plot, SqpColorScale& colorScale)
121 static void setProperties(QCustomPlot& plot, SqpColorScale& colorScale)
121 {
122 {
122 // Displays color scale in plot
123 // Displays color scale in plot
123 plot.plotLayout()->insertRow(0);
124 plot.plotLayout()->insertRow(0);
124 plot.plotLayout()->addElement(0, 0, colorScale.m_Scale);
125 plot.plotLayout()->addElement(0, 0, colorScale.m_Scale);
125 colorScale.m_Scale->setType(QCPAxis::atTop);
126 colorScale.m_Scale->setType(QCPAxis::atTop);
126 colorScale.m_Scale->setMinimumMargins(QMargins { 0, 0, 0, 0 });
127 colorScale.m_Scale->setMinimumMargins(QMargins { 0, 0, 0, 0 });
127
128
128 // Aligns color scale with axes
129 // Aligns color scale with axes
129 auto marginGroups = plot.axisRect()->marginGroups();
130 auto marginGroups = plot.axisRect()->marginGroups();
130 for (auto it = marginGroups.begin(), end = marginGroups.end(); it != end; ++it)
131 for (auto it = marginGroups.begin(), end = marginGroups.end(); it != end; ++it)
131 {
132 {
132 colorScale.m_Scale->setMarginGroup(it.key(), it.value());
133 colorScale.m_Scale->setMarginGroup(it.key(), it.value());
133 }
134 }
134
135
135 // Set color scale properties
136 // Set color scale properties
136 colorScale.m_AutomaticThreshold = true;
137 colorScale.m_AutomaticThreshold = true;
137 }
138 }
138
139
139 static void setUnits(T& dataSeries, QCustomPlot& plot, SqpColorScale& colorScale)
140 static void setUnits(T& dataSeries, QCustomPlot& plot, SqpColorScale& colorScale)
140 {
141 {
141 auto serie = dynamic_cast<TimeSeries::ITimeSerie*>(&dataSeries);
142 auto serie = dynamic_cast<TimeSeries::ITimeSerie*>(&dataSeries);
142 setAxisProperties(*plot.xAxis, "s", true);
143 setAxisProperties(*plot.xAxis, "s", true);
143 setAxisProperties(*plot.yAxis, serie->unit(1), false, QCPAxis::stLogarithmic);
144 setAxisProperties(*plot.yAxis, serie->unit(1), false, QCPAxis::stLogarithmic);
144 setAxisProperties(
145 setAxisProperties(
145 *colorScale.m_Scale->axis(), serie->unit(2), false, QCPAxis::stLogarithmic);
146 *colorScale.m_Scale->axis(), serie->unit(2), false, QCPAxis::stLogarithmic);
146 }
147 }
147 };
148 };
148
149
149 /**
150 /**
150 * Default implementation of IAxisHelper, which takes data series to set axes properties
151 * Default implementation of IAxisHelper, which takes data series to set axes properties
151 * @tparam T the data series' type
152 * @tparam T the data series' type
152 */
153 */
153 template <typename T>
154 template <typename T>
154 struct AxisHelper : public IAxisHelper
155 struct AxisHelper : public IAxisHelper
155 {
156 {
156 explicit AxisHelper(std::shared_ptr<T> dataSeries) : m_DataSeries { dataSeries } {}
157 explicit AxisHelper(std::shared_ptr<T> dataSeries) : m_DataSeries { dataSeries } {}
157
158
158 void setProperties(QCustomPlot& plot, SqpColorScale& colorScale) override
159 void setProperties(QCustomPlot& plot, SqpColorScale& colorScale) override
159 {
160 {
160 AxisSetter<T>::setProperties(plot, colorScale);
161 AxisSetter<T>::setProperties(plot, colorScale);
161 }
162 }
162
163
163 void setUnits(QCustomPlot& plot, SqpColorScale& colorScale) override
164 void setUnits(QCustomPlot& plot, SqpColorScale& colorScale) override
164 {
165 {
165 if (m_DataSeries)
166 if (m_DataSeries)
166 {
167 {
167 AxisSetter<T>::setUnits(*m_DataSeries, plot, colorScale);
168 AxisSetter<T>::setUnits(*m_DataSeries, plot, colorScale);
168 }
169 }
169 else
170 else
170 {
171 {
171 qCCritical(LOG_AxisRenderingUtils()) << "Can't set units: inconsistency between the "
172 qCCritical(LOG_AxisRenderingUtils()) << "Can't set units: inconsistency between the "
172 "type of data series and the type supposed";
173 "type of data series and the type supposed";
173 }
174 }
174 }
175 }
175
176
176 std::shared_ptr<T> m_DataSeries;
177 std::shared_ptr<T> m_DataSeries;
177 };
178 };
178
179
179 } // namespace
180 } // namespace
180
181
181 QString formatValue(double value, const QCPAxis& axis)
182 QString formatValue(double value, const QCPAxis& axis)
182 {
183 {
183 // If the axis is a time axis, formats the value as a date
184 // If the axis is a time axis, formats the value as a date
184 if (auto axisTicker = qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker()))
185 if (auto axisTicker = qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker()))
185 {
186 {
186 return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT);
187 return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT);
187 }
188 }
188 else
189 else
189 {
190 {
190 return QString::number(value, NUMBER_FORMAT, NUMBER_PRECISION);
191 return QString::number(value, NUMBER_FORMAT, NUMBER_PRECISION);
191 }
192 }
192 }
193 }
193
194
194 std::unique_ptr<IAxisHelper> IAxisHelperFactory::create(Variable2& variable) noexcept
195 std::unique_ptr<IAxisHelper> IAxisHelperFactory::create(Variable2& variable) noexcept
195 {
196 {
196 switch (variable.type())
197 switch (variable.type())
197 {
198 {
198 case DataSeriesType::SCALAR:
199 case DataSeriesType::SCALAR:
199 return std::make_unique<AxisHelper<ScalarTimeSerie>>(
200 return std::make_unique<AxisHelper<ScalarTimeSerie>>(
200 std::dynamic_pointer_cast<ScalarTimeSerie>(variable.data()));
201 std::dynamic_pointer_cast<ScalarTimeSerie>(variable.data()));
201 case DataSeriesType::SPECTROGRAM:
202 case DataSeriesType::SPECTROGRAM:
202 return std::make_unique<AxisHelper<SpectrogramTimeSerie>>(
203 return std::make_unique<AxisHelper<SpectrogramTimeSerie>>(
203 std::dynamic_pointer_cast<SpectrogramTimeSerie>(variable.data()));
204 std::dynamic_pointer_cast<SpectrogramTimeSerie>(variable.data()));
204 case DataSeriesType::VECTOR:
205 case DataSeriesType::VECTOR:
205 return std::make_unique<AxisHelper<VectorTimeSerie>>(
206 return std::make_unique<AxisHelper<VectorTimeSerie>>(
206 std::dynamic_pointer_cast<VectorTimeSerie>(variable.data()));
207 std::dynamic_pointer_cast<VectorTimeSerie>(variable.data()));
208 case DataSeriesType::MULTICOMPONENT:
209 return std::make_unique<AxisHelper<MultiComponentTimeSerie>>(
210 std::dynamic_pointer_cast<MultiComponentTimeSerie>(variable.data()));
207 default:
211 default:
208 // Creates default helper
212 // Creates default helper
209 break;
213 break;
210 }
214 }
211
215
212 return std::make_unique<AxisHelper<TimeSeries::ITimeSerie>>(nullptr);
216 return std::make_unique<AxisHelper<TimeSeries::ITimeSerie>>(nullptr);
213 }
217 }
@@ -1,133 +1,136
1 #include "Visualization/PlottablesRenderingUtils.h"
1 #include "Visualization/PlottablesRenderingUtils.h"
2
2
3 #include <Common/ColorUtils.h>
3 #include <Common/ColorUtils.h>
4
4
5 #include <Variable/Variable2.h>
5 #include <Variable/Variable2.h>
6
6
7 #include <Visualization/qcustomplot.h>
7 #include <Visualization/qcustomplot.h>
8
8
9 Q_LOGGING_CATEGORY(LOG_PlottablesRenderingUtils, "PlottablesRenderingUtils")
9 Q_LOGGING_CATEGORY(LOG_PlottablesRenderingUtils, "PlottablesRenderingUtils")
10
10
11 namespace
11 namespace
12 {
12 {
13
13
14 /**
14 /**
15 * Delegate used to set plottables properties
15 * Delegate used to set plottables properties
16 */
16 */
17 template <typename T, typename Enabled = void>
17 template <typename T, typename Enabled = void>
18 struct PlottablesSetter
18 struct PlottablesSetter
19 {
19 {
20 static void setProperties(PlottablesMap&)
20 static void setProperties(PlottablesMap&)
21 {
21 {
22 // Default implementation does nothing
22 // Default implementation does nothing
23 qCCritical(LOG_PlottablesRenderingUtils())
23 qCCritical(LOG_PlottablesRenderingUtils())
24 << "Can't set plottables properties: unmanaged type of data";
24 << "Can't set plottables properties: unmanaged type of data";
25 }
25 }
26 };
26 };
27
27
28 /**
28 /**
29 * Specialization of PlottablesSetter for scalars and vectors
29 * Specialization of PlottablesSetter for scalars and vectors
30 * @sa ScalarSeries
30 * @sa ScalarSeries
31 * @sa VectorSeries
31 * @sa VectorSeries
32 */
32 */
33 template <typename T>
33 template <typename T>
34 struct PlottablesSetter<T,
34 struct PlottablesSetter<T,
35 typename std::enable_if_t<std::is_base_of<ScalarTimeSerie, T>::value
35 typename std::enable_if_t<std::is_base_of<ScalarTimeSerie, T>::value
36 or std::is_base_of<VectorTimeSerie, T>::value>>
36 or std::is_base_of<VectorTimeSerie, T>::value
37 or std::is_base_of<MultiComponentTimeSerie, T>::value>>
37 {
38 {
38 static void setProperties(PlottablesMap& plottables)
39 static void setProperties(PlottablesMap& plottables)
39 {
40 {
40 // Finds the plottable with the highest index to determine the number of colors to generate
41 // Finds the plottable with the highest index to determine the number of colors to generate
41 auto end = plottables.cend();
42 auto end = plottables.cend();
42 auto maxPlottableIndexIt = std::max_element(plottables.cbegin(), end,
43 auto maxPlottableIndexIt = std::max_element(plottables.cbegin(), end,
43 [](const auto& it1, const auto& it2) { return it1.first < it2.first; });
44 [](const auto& it1, const auto& it2) { return it1.first < it2.first; });
44 auto componentCount = maxPlottableIndexIt != end ? maxPlottableIndexIt->first + 1 : 0;
45 auto componentCount = maxPlottableIndexIt != end ? maxPlottableIndexIt->first + 1 : 0;
45
46
46 // Generates colors for each component
47 // Generates colors for each component
47 auto colors = ColorUtils::colors(Qt::blue, Qt::red, componentCount);
48 auto colors = ColorUtils::colors(Qt::blue, Qt::red, componentCount);
48
49
49 // For each component of the data series, creates a QCPGraph to add to the plot
50 // For each component of the data series, creates a QCPGraph to add to the plot
50 for (auto i = 0; i < componentCount; ++i)
51 for (auto i = 0; i < componentCount; ++i)
51 {
52 {
52 auto graphIt = plottables.find(i);
53 auto graphIt = plottables.find(i);
53 if (graphIt != end)
54 if (graphIt != end)
54 {
55 {
55 graphIt->second->setPen(QPen { colors.at(i) });
56 graphIt->second->setPen(QPen { colors.at(i) });
56 }
57 }
57 }
58 }
58 }
59 }
59 };
60 };
60
61
61 /**
62 /**
62 * Specialization of PlottablesSetter for spectrograms
63 * Specialization of PlottablesSetter for spectrograms
63 * @sa SpectrogramSeries
64 * @sa SpectrogramSeries
64 */
65 */
65 template <typename T>
66 template <typename T>
66 struct PlottablesSetter<T,
67 struct PlottablesSetter<T,
67 typename std::enable_if_t<std::is_base_of<SpectrogramTimeSerie, T>::value>>
68 typename std::enable_if_t<std::is_base_of<SpectrogramTimeSerie, T>::value>>
68 {
69 {
69 static void setProperties(PlottablesMap& plottables)
70 static void setProperties(PlottablesMap& plottables)
70 {
71 {
71 // Checks that for a spectrogram there is only one plottable, that is a colormap
72 // Checks that for a spectrogram there is only one plottable, that is a colormap
72 if (plottables.size() != 1)
73 if (plottables.size() != 1)
73 {
74 {
74 return;
75 return;
75 }
76 }
76
77
77 if (auto colormap = dynamic_cast<QCPColorMap*>(plottables.begin()->second))
78 if (auto colormap = dynamic_cast<QCPColorMap*>(plottables.begin()->second))
78 {
79 {
79 colormap->setInterpolate(false); // No value interpolation
80 colormap->setInterpolate(false); // No value interpolation
80 colormap->setTightBoundary(true);
81 colormap->setTightBoundary(true);
81
82
82 // Finds color scale in the colormap's plot to associate with it
83 // Finds color scale in the colormap's plot to associate with it
83 auto plot = colormap->parentPlot();
84 auto plot = colormap->parentPlot();
84 auto plotElements = plot->plotLayout()->elements(false);
85 auto plotElements = plot->plotLayout()->elements(false);
85 for (auto plotElement : plotElements)
86 for (auto plotElement : plotElements)
86 {
87 {
87 if (auto colorScale = dynamic_cast<QCPColorScale*>(plotElement))
88 if (auto colorScale = dynamic_cast<QCPColorScale*>(plotElement))
88 {
89 {
89 colormap->setColorScale(colorScale);
90 colormap->setColorScale(colorScale);
90 }
91 }
91 }
92 }
92
93
93 colormap->rescaleDataRange();
94 colormap->rescaleDataRange();
94 }
95 }
95 else
96 else
96 {
97 {
97 qCCritical(LOG_PlottablesRenderingUtils()) << "Can't get colormap of the spectrogram";
98 qCCritical(LOG_PlottablesRenderingUtils()) << "Can't get colormap of the spectrogram";
98 }
99 }
99 }
100 }
100 };
101 };
101
102
102 /**
103 /**
103 * Default implementation of IPlottablesHelper, which takes data series to set plottables properties
104 * Default implementation of IPlottablesHelper, which takes data series to set plottables properties
104 * @tparam T the data series' type
105 * @tparam T the data series' type
105 */
106 */
106 template <typename T>
107 template <typename T>
107 struct PlottablesHelper : public IPlottablesHelper
108 struct PlottablesHelper : public IPlottablesHelper
108 {
109 {
109 void setProperties(PlottablesMap& plottables) override
110 void setProperties(PlottablesMap& plottables) override
110 {
111 {
111 PlottablesSetter<T>::setProperties(plottables);
112 PlottablesSetter<T>::setProperties(plottables);
112 }
113 }
113 };
114 };
114
115
115 } // namespace
116 } // namespace
116
117
117 std::unique_ptr<IPlottablesHelper> IPlottablesHelperFactory::create(Variable2& variable) noexcept
118 std::unique_ptr<IPlottablesHelper> IPlottablesHelperFactory::create(Variable2& variable) noexcept
118 {
119 {
119 switch (variable.type())
120 switch (variable.type())
120 {
121 {
121 case DataSeriesType::SCALAR:
122 case DataSeriesType::SCALAR:
122 return std::make_unique<PlottablesHelper<ScalarTimeSerie>>();
123 return std::make_unique<PlottablesHelper<ScalarTimeSerie>>();
123 case DataSeriesType::SPECTROGRAM:
124 case DataSeriesType::SPECTROGRAM:
124 return std::make_unique<PlottablesHelper<SpectrogramTimeSerie>>();
125 return std::make_unique<PlottablesHelper<SpectrogramTimeSerie>>();
125 case DataSeriesType::VECTOR:
126 case DataSeriesType::VECTOR:
126 return std::make_unique<PlottablesHelper<VectorTimeSerie>>();
127 return std::make_unique<PlottablesHelper<VectorTimeSerie>>();
128 case DataSeriesType::MULTICOMPONENT:
129 return std::make_unique<PlottablesHelper<MultiComponentTimeSerie>>();
127 default:
130 default:
128 // Returns default helper
131 // Returns default helper
129 break;
132 break;
130 }
133 }
131
134
132 return std::make_unique<PlottablesHelper<TimeSeries::ITimeSerie>>();
135 return std::make_unique<PlottablesHelper<TimeSeries::ITimeSerie>>();
133 }
136 }
@@ -1,519 +1,527
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/VectorTimeSerie.h>
6 #include <Data/VectorTimeSerie.h>
7
7
8 #include <Variable/Variable2.h>
8 #include <Variable/Variable2.h>
9
9
10 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
10 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
11
11
12 namespace
12 namespace
13 {
13 {
14
14
15 class SqpDataContainer : public QCPGraphDataContainer
15 class SqpDataContainer : public QCPGraphDataContainer
16 {
16 {
17 public:
17 public:
18 void appendGraphData(const QCPGraphData& data) { mData.append(data); }
18 void appendGraphData(const QCPGraphData& data) { mData.append(data); }
19 };
19 };
20
20
21 /**
21 /**
22 * Struct used to create plottables, depending on the type of the data series from which to create
22 * Struct used to create plottables, depending on the type of the data series from which to create
23 * them
23 * them
24 * @tparam T the data series' type
24 * @tparam T the data series' type
25 * @remarks Default implementation can't create plottables
25 * @remarks Default implementation can't create plottables
26 */
26 */
27 template <typename T, typename Enabled = void>
27 template <typename T, typename Enabled = void>
28 struct PlottablesCreator
28 struct PlottablesCreator
29 {
29 {
30 static PlottablesMap createPlottables(QCustomPlot&, const std::shared_ptr<T>& dataSeries)
30 static PlottablesMap createPlottables(QCustomPlot&, const std::shared_ptr<T>& dataSeries)
31 {
31 {
32 return {};
32 return {};
33 }
33 }
34 };
34 };
35
35
36 PlottablesMap createGraphs(QCustomPlot& plot, int nbGraphs)
36 PlottablesMap createGraphs(QCustomPlot& plot, int nbGraphs)
37 {
37 {
38 PlottablesMap result {};
38 PlottablesMap result {};
39
39
40 // Creates {nbGraphs} QCPGraph to add to the plot
40 // Creates {nbGraphs} QCPGraph to add to the plot
41 for (auto i = 0; i < nbGraphs; ++i)
41 for (auto i = 0; i < nbGraphs; ++i)
42 {
42 {
43 auto graph = plot.addGraph();
43 auto graph = plot.addGraph();
44 result.insert({ i, graph });
44 result.insert({ i, graph });
45 }
45 }
46
46
47 plot.replot();
47 plot.replot();
48
48
49 return result;
49 return result;
50 }
50 }
51
51
52 /**
52 /**
53 * Specialization of PlottablesCreator for scalars
53 * Specialization of PlottablesCreator for scalars
54 * @sa ScalarSeries
54 * @sa ScalarSeries
55 */
55 */
56 template <typename T>
56 template <typename T>
57 struct PlottablesCreator<T, typename std::enable_if_t<std::is_base_of<ScalarTimeSerie, T>::value>>
57 struct PlottablesCreator<T, typename std::enable_if_t<std::is_base_of<ScalarTimeSerie, T>::value>>
58 {
58 {
59 static PlottablesMap createPlottables(QCustomPlot& plot, const std::shared_ptr<T>& dataSeries)
59 static PlottablesMap createPlottables(QCustomPlot& plot, const std::shared_ptr<T>& dataSeries)
60 {
60 {
61 return createGraphs(plot, 1);
61 return createGraphs(plot, 1);
62 }
62 }
63 };
63 };
64
64
65 /**
65 /**
66 * Specialization of PlottablesCreator for vectors
66 * Specialization of PlottablesCreator for vectors
67 * @sa VectorSeries
67 * @sa VectorSeries
68 */
68 */
69 template <typename T>
69 template <typename T>
70 struct PlottablesCreator<T, typename std::enable_if_t<std::is_base_of<VectorTimeSerie, T>::value>>
70 struct PlottablesCreator<T, typename std::enable_if_t<std::is_base_of<VectorTimeSerie, T>::value>>
71 {
71 {
72 static PlottablesMap createPlottables(QCustomPlot& plot, const std::shared_ptr<T>& dataSeries)
72 static PlottablesMap createPlottables(QCustomPlot& plot, const std::shared_ptr<T>& dataSeries)
73 {
73 {
74 return createGraphs(plot, 3);
74 return createGraphs(plot, 3);
75 }
75 }
76 };
76 };
77
77
78 /**
78 /**
79 * Specialization of PlottablesCreator for MultiComponentTimeSeries
79 * Specialization of PlottablesCreator for MultiComponentTimeSeries
80 * @sa VectorSeries
80 * @sa VectorSeries
81 */
81 */
82 template <typename T>
82 template <typename T>
83 struct PlottablesCreator<T,
83 struct PlottablesCreator<T,
84 typename std::enable_if_t<std::is_base_of<MultiComponentTimeSerie, T>::value>>
84 typename std::enable_if_t<std::is_base_of<MultiComponentTimeSerie, T>::value>>
85 {
85 {
86 static PlottablesMap createPlottables(QCustomPlot& plot, const std::shared_ptr<T>& dataSeries)
86 static PlottablesMap createPlottables(QCustomPlot& plot, const std::shared_ptr<T>& dataSeries)
87 {
87 {
88 return createGraphs(plot, dataSeries->size(1));
88 return createGraphs(plot, dataSeries->size(1));
89 }
89 }
90 };
90 };
91
91
92 /**
92 /**
93 * Specialization of PlottablesCreator for spectrograms
93 * Specialization of PlottablesCreator for spectrograms
94 * @sa SpectrogramSeries
94 * @sa SpectrogramSeries
95 */
95 */
96 template <typename T>
96 template <typename T>
97 struct PlottablesCreator<T,
97 struct PlottablesCreator<T,
98 typename std::enable_if_t<std::is_base_of<SpectrogramTimeSerie, T>::value>>
98 typename std::enable_if_t<std::is_base_of<SpectrogramTimeSerie, T>::value>>
99 {
99 {
100 static PlottablesMap createPlottables(QCustomPlot& plot, const std::shared_ptr<T>& dataSeries)
100 static PlottablesMap createPlottables(QCustomPlot& plot, const std::shared_ptr<T>& dataSeries)
101 {
101 {
102 PlottablesMap result {};
102 PlottablesMap result {};
103 result.insert({ 0, new QCPColorMap { plot.xAxis, plot.yAxis } });
103 result.insert({ 0, new QCPColorMap { plot.xAxis, plot.yAxis } });
104
104
105 plot.replot();
105 plot.replot();
106
106
107 return result;
107 return result;
108 }
108 }
109 };
109 };
110
110
111 /**
111 /**
112 * Struct used to update plottables, depending on the type of the data series from which to update
112 * Struct used to update plottables, depending on the type of the data series from which to update
113 * them
113 * them
114 * @tparam T the data series' type
114 * @tparam T the data series' type
115 * @remarks Default implementation can't update plottables
115 * @remarks Default implementation can't update plottables
116 */
116 */
117 template <typename T, typename Enabled = void>
117 template <typename T, typename Enabled = void>
118 struct PlottablesUpdater
118 struct PlottablesUpdater
119 {
119 {
120 static void setPlotYAxisRange(T&, const DateTimeRange&, QCustomPlot&)
120 static void setPlotYAxisRange(T&, const DateTimeRange&, QCustomPlot&)
121 {
121 {
122 qCCritical(LOG_VisualizationGraphHelper())
122 qCCritical(LOG_VisualizationGraphHelper())
123 << QObject::tr("Can't set plot y-axis range: unmanaged data series type");
123 << QObject::tr("Can't set plot y-axis range: unmanaged data series type");
124 }
124 }
125
125
126 static void updatePlottables(T&, PlottablesMap&, const DateTimeRange&, bool)
126 static void updatePlottables(T&, PlottablesMap&, const DateTimeRange&, bool)
127 {
127 {
128 qCCritical(LOG_VisualizationGraphHelper())
128 qCCritical(LOG_VisualizationGraphHelper())
129 << QObject::tr("Can't update plottables: unmanaged data series type");
129 << QObject::tr("Can't update plottables: unmanaged data series type");
130 }
130 }
131 };
131 };
132
132
133 /**
133 /**
134 * Specialization of PlottablesUpdater for scalars and vectors
134 * Specialization of PlottablesUpdater for scalars and vectors
135 * @sa ScalarSeries
135 * @sa ScalarSeries
136 * @sa VectorSeries
136 * @sa VectorSeries
137 */
137 */
138 template <typename T>
138 template <typename T>
139 struct PlottablesUpdater<T, typename std::enable_if_t<std::is_base_of<ScalarTimeSerie, T>::value>>
139 struct PlottablesUpdater<T, typename std::enable_if_t<std::is_base_of<ScalarTimeSerie, T>::value>>
140 {
140 {
141 static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot)
141 static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot)
142 {
142 {
143 auto minValue = 0., maxValue = 0.;
143 auto minValue = 0., maxValue = 0.;
144 if (auto serie = dynamic_cast<ScalarTimeSerie*>(&dataSeries))
144 if (auto serie = dynamic_cast<ScalarTimeSerie*>(&dataSeries))
145 {
145 {
146 if (serie->size())
146 if (serie->size())
147 {
147 {
148 maxValue = (*std::max_element(std::begin(*serie), std::end(*serie))).v();
148 maxValue = (*std::max_element(std::begin(*serie), std::end(*serie))).v();
149 minValue = (*std::min_element(std::begin(*serie), std::end(*serie))).v();
149 minValue = (*std::min_element(std::begin(*serie), std::end(*serie))).v();
150 }
150 }
151 }
151 }
152 plot.yAxis->setRange(QCPRange { minValue, maxValue });
152 plot.yAxis->setRange(QCPRange { minValue, maxValue });
153 }
153 }
154
154
155 static void updatePlottables(
155 static void updatePlottables(
156 T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes)
156 T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes)
157 {
157 {
158
158
159 // For each plottable to update, resets its data
159 // For each plottable to update, resets its data
160 for (const auto& plottable : plottables)
160 for (const auto& plottable : plottables)
161 {
161 {
162 if (auto graph = dynamic_cast<QCPGraph*>(plottable.second))
162 if (auto graph = dynamic_cast<QCPGraph*>(plottable.second))
163 {
163 {
164 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
164 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
165 if (auto serie = dynamic_cast<ScalarTimeSerie*>(&dataSeries))
165 if (auto serie = dynamic_cast<ScalarTimeSerie*>(&dataSeries))
166 {
166 {
167 std::for_each(
167 std::for_each(
168 std::begin(*serie), std::end(*serie), [&dataContainer](const auto& value) {
168 std::begin(*serie), std::end(*serie), [&dataContainer](const auto& value) {
169 dataContainer->appendGraphData(QCPGraphData(value.t(), value.v()));
169 dataContainer->appendGraphData(QCPGraphData(value.t(), value.v()));
170 });
170 });
171 }
171 }
172 graph->setData(dataContainer);
172 graph->setData(dataContainer);
173 }
173 }
174 }
174 }
175
175
176 if (!plottables.empty())
176 if (!plottables.empty())
177 {
177 {
178 auto plot = plottables.begin()->second->parentPlot();
178 auto plot = plottables.begin()->second->parentPlot();
179
179
180 if (rescaleAxes)
180 if (rescaleAxes)
181 {
181 {
182 plot->rescaleAxes();
182 plot->rescaleAxes();
183 }
183 }
184 }
184 }
185 }
185 }
186 };
186 };
187
187
188
188
189 template <typename T>
189 template <typename T>
190 struct PlottablesUpdater<T, typename std::enable_if_t<std::is_base_of<VectorTimeSerie, T>::value>>
190 struct PlottablesUpdater<T, typename std::enable_if_t<std::is_base_of<VectorTimeSerie, T>::value>>
191 {
191 {
192 static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot)
192 static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot)
193 {
193 {
194 double minValue = 0., maxValue = 0.;
194 double minValue = 0., maxValue = 0.;
195 if (auto serie = dynamic_cast<VectorTimeSerie*>(&dataSeries))
195 if (auto serie = dynamic_cast<VectorTimeSerie*>(&dataSeries))
196 {
196 {
197 std::for_each(
197 std::for_each(
198 std::begin(*serie), std::end(*serie), [&minValue, &maxValue](const auto& v) {
198 std::begin(*serie), std::end(*serie), [&minValue, &maxValue](const auto& v) {
199 minValue = std::min({ minValue, v.v().x, v.v().y, v.v().z });
199 minValue = std::min({ minValue, v.v().x, v.v().y, v.v().z });
200 maxValue = std::max({ maxValue, v.v().x, v.v().y, v.v().z });
200 maxValue = std::max({ maxValue, v.v().x, v.v().y, v.v().z });
201 });
201 });
202 }
202 }
203
203
204 plot.yAxis->setRange(QCPRange { minValue, maxValue });
204 plot.yAxis->setRange(QCPRange { minValue, maxValue });
205 }
205 }
206
206
207 static void updatePlottables(
207 static void updatePlottables(
208 T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes)
208 T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes)
209 {
209 {
210
210
211 // For each plottable to update, resets its data
211 // For each plottable to update, resets its data
212 for (const auto& plottable : plottables)
212 for (const auto& plottable : plottables)
213 {
213 {
214 if (auto graph = dynamic_cast<QCPGraph*>(plottable.second))
214 if (auto graph = dynamic_cast<QCPGraph*>(plottable.second))
215 {
215 {
216 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
216 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
217 if (auto serie = dynamic_cast<VectorTimeSerie*>(&dataSeries))
217 if (auto serie = dynamic_cast<VectorTimeSerie*>(&dataSeries))
218 {
218 {
219 switch (plottable.first)
219 switch (plottable.first)
220 {
220 {
221 case 0:
221 case 0:
222 std::for_each(std::begin(*serie), std::end(*serie),
222 std::for_each(std::begin(*serie), std::end(*serie),
223 [&dataContainer](const auto& value) {
223 [&dataContainer](const auto& value) {
224 dataContainer->appendGraphData(
224 dataContainer->appendGraphData(
225 QCPGraphData(value.t(), value.v().x));
225 QCPGraphData(value.t(), value.v().x));
226 });
226 });
227 break;
227 break;
228 case 1:
228 case 1:
229 std::for_each(std::begin(*serie), std::end(*serie),
229 std::for_each(std::begin(*serie), std::end(*serie),
230 [&dataContainer](const auto& value) {
230 [&dataContainer](const auto& value) {
231 dataContainer->appendGraphData(
231 dataContainer->appendGraphData(
232 QCPGraphData(value.t(), value.v().y));
232 QCPGraphData(value.t(), value.v().y));
233 });
233 });
234 break;
234 break;
235 case 2:
235 case 2:
236 std::for_each(std::begin(*serie), std::end(*serie),
236 std::for_each(std::begin(*serie), std::end(*serie),
237 [&dataContainer](const auto& value) {
237 [&dataContainer](const auto& value) {
238 dataContainer->appendGraphData(
238 dataContainer->appendGraphData(
239 QCPGraphData(value.t(), value.v().z));
239 QCPGraphData(value.t(), value.v().z));
240 });
240 });
241 break;
241 break;
242 default:
242 default:
243 break;
243 break;
244 }
244 }
245 }
245 }
246 graph->setData(dataContainer);
246 graph->setData(dataContainer);
247 }
247 }
248 }
248 }
249
249
250 if (!plottables.empty())
250 if (!plottables.empty())
251 {
251 {
252 auto plot = plottables.begin()->second->parentPlot();
252 auto plot = plottables.begin()->second->parentPlot();
253
253
254 if (rescaleAxes)
254 if (rescaleAxes)
255 {
255 {
256 plot->rescaleAxes();
256 plot->rescaleAxes();
257 }
257 }
258 }
258 }
259 }
259 }
260 };
260 };
261
261
262
262
263 template <typename T>
263 template <typename T>
264 struct PlottablesUpdater<T, typename std::enable_if_t<std::is_base_of<MultiComponentTimeSerie, T>::value>>
264 struct PlottablesUpdater<T,
265 typename std::enable_if_t<std::is_base_of<MultiComponentTimeSerie, T>::value>>
265 {
266 {
266 static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot)
267 static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot)
267 {
268 {
268 double minValue = 0., maxValue = 0.;
269 double minValue = 0., maxValue = 0.;
269 if (auto serie = dynamic_cast<MultiComponentTimeSerie*>(&dataSeries))
270 if (auto serie = dynamic_cast<MultiComponentTimeSerie*>(&dataSeries))
270 {
271 {
271 // TODO
272 // TODO
272 // std::for_each(
273 // std::for_each(
273 // std::begin(*serie), std::end(*serie), [&minValue, &maxValue](const auto& v) {
274 // std::begin(*serie), std::end(*serie), [&minValue, &maxValue](const
274 // minValue = std::min({ minValue, std::min_element(v.begin(),v.end()) });
275 // auto& v) {
275 // maxValue = std::max({ maxValue, std::max_element(v.begin(),v.end()) });
276 // minValue = std::min({ minValue,
276 // });
277 // std::min_element(v.begin(),v.end()) }); maxValue = std::max({
278 // maxValue, std::max_element(v.begin(),v.end()) });
279 // });
277 }
280 }
278
281
279 plot.yAxis->setRange(QCPRange { minValue, maxValue });
282 plot.yAxis->setRange(QCPRange { minValue, maxValue });
280 }
283 }
281
284
282 static void updatePlottables(
285 static void updatePlottables(
283 T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes)
286 T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes)
284 {
287 {
285 for (const auto& plottable : plottables)
288 for (const auto& plottable : plottables)
286 {
289 {
287 if (auto graph = dynamic_cast<QCPGraph*>(plottable.second))
290 if (auto graph = dynamic_cast<QCPGraph*>(plottable.second))
288 {
291 {
289 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
292 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
290 if (auto serie = dynamic_cast<MultiComponentTimeSerie*>(&dataSeries))
293 if (auto serie = dynamic_cast<MultiComponentTimeSerie*>(&dataSeries))
291 {
294 {
292 // TODO
295 // TODO
296 std::for_each(std::begin(*serie), std::end(*serie),
297 [&dataContainer, component = plottable.first](const auto& value) {
298 dataContainer->appendGraphData(
299 QCPGraphData(value.t(), value[component]));
300 });
293 }
301 }
294 graph->setData(dataContainer);
302 graph->setData(dataContainer);
295 }
303 }
296 }
304 }
297
305
298 if (!plottables.empty())
306 if (!plottables.empty())
299 {
307 {
300 auto plot = plottables.begin()->second->parentPlot();
308 auto plot = plottables.begin()->second->parentPlot();
301
309
302 if (rescaleAxes)
310 if (rescaleAxes)
303 {
311 {
304 plot->rescaleAxes();
312 plot->rescaleAxes();
305 }
313 }
306 }
314 }
307 }
315 }
308 };
316 };
309
317
310 /**
318 /**
311 * Specialization of PlottablesUpdater for spectrograms
319 * Specialization of PlottablesUpdater for spectrograms
312 * @sa SpectrogramSeries
320 * @sa SpectrogramSeries
313 */
321 */
314 template <typename T>
322 template <typename T>
315 struct PlottablesUpdater<T,
323 struct PlottablesUpdater<T,
316 typename std::enable_if_t<std::is_base_of<SpectrogramTimeSerie, T>::value>>
324 typename std::enable_if_t<std::is_base_of<SpectrogramTimeSerie, T>::value>>
317 {
325 {
318 static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot)
326 static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot)
319 {
327 {
320 // TODO
328 // TODO
321 // double min, max;
329 // double min, max;
322 // std::tie(min, max) = dataSeries.yBounds();
330 // std::tie(min, max) = dataSeries.yBounds();
323
331
324 // if (!std::isnan(min) && !std::isnan(max))
332 // if (!std::isnan(min) && !std::isnan(max))
325 // {
333 // {
326 // plot.yAxis->setRange(QCPRange { min, max });
334 // plot.yAxis->setRange(QCPRange { min, max });
327 // }
335 // }
328 }
336 }
329
337
330 static void updatePlottables(
338 static void updatePlottables(
331 T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes)
339 T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes)
332 {
340 {
333 // TODO
341 // TODO
334 // if (plottables.empty())
342 // if (plottables.empty())
335 // {
343 // {
336 // qCDebug(LOG_VisualizationGraphHelper())
344 // qCDebug(LOG_VisualizationGraphHelper())
337 // << QObject::tr("Can't update spectrogram: no colormap has been
345 // << QObject::tr("Can't update spectrogram: no colormap has been
338 // associated");
346 // associated");
339 // return;
347 // return;
340 // }
348 // }
341
349
342 // // Gets the colormap to update (normally there is only one colormap)
350 // // Gets the colormap to update (normally there is only one colormap)
343 // Q_ASSERT(plottables.size() == 1);
351 // Q_ASSERT(plottables.size() == 1);
344 // auto colormap = dynamic_cast<QCPColorMap*>(plottables.at(0));
352 // auto colormap = dynamic_cast<QCPColorMap*>(plottables.at(0));
345 // Q_ASSERT(colormap != nullptr);
353 // Q_ASSERT(colormap != nullptr);
346
354
347 // dataSeries.lockRead();
355 // dataSeries.lockRead();
348
356
349 // // Processing spectrogram data for display in QCustomPlot
357 // // Processing spectrogram data for display in QCustomPlot
350 // auto its = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
358 // auto its = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
351
359
352 // // Computes logarithmic y-axis resolution for the spectrogram
360 // // Computes logarithmic y-axis resolution for the spectrogram
353 // auto yData = its.first->y();
361 // auto yData = its.first->y();
354 // auto yResolution = DataSeriesUtils::resolution(yData.begin(), yData.end(), true);
362 // auto yResolution = DataSeriesUtils::resolution(yData.begin(), yData.end(), true);
355
363
356 // // Generates mesh for colormap
364 // // Generates mesh for colormap
357 // auto mesh = DataSeriesUtils::regularMesh(its.first, its.second,
365 // auto mesh = DataSeriesUtils::regularMesh(its.first, its.second,
358 // DataSeriesUtils::Resolution { dataSeries.xResolution() }, yResolution);
366 // DataSeriesUtils::Resolution { dataSeries.xResolution() }, yResolution);
359
367
360 // dataSeries.unlock();
368 // dataSeries.unlock();
361
369
362 // colormap->data()->setSize(mesh.m_NbX, mesh.m_NbY);
370 // colormap->data()->setSize(mesh.m_NbX, mesh.m_NbY);
363 // if (!mesh.isEmpty())
371 // if (!mesh.isEmpty())
364 // {
372 // {
365 // colormap->data()->setRange(QCPRange { mesh.m_XMin, mesh.xMax() },
373 // colormap->data()->setRange(QCPRange { mesh.m_XMin, mesh.xMax() },
366 // // y-axis range is converted to linear values
374 // // y-axis range is converted to linear values
367 // QCPRange { std::pow(10, mesh.m_YMin), std::pow(10, mesh.yMax()) });
375 // QCPRange { std::pow(10, mesh.m_YMin), std::pow(10, mesh.yMax()) });
368
376
369 // // Sets values
377 // // Sets values
370 // auto index = 0;
378 // auto index = 0;
371 // for (auto it = mesh.m_Data.begin(), end = mesh.m_Data.end(); it != end; ++it,
379 // for (auto it = mesh.m_Data.begin(), end = mesh.m_Data.end(); it != end; ++it,
372 // ++index)
380 // ++index)
373 // {
381 // {
374 // auto xIndex = index % mesh.m_NbX;
382 // auto xIndex = index % mesh.m_NbX;
375 // auto yIndex = index / mesh.m_NbX;
383 // auto yIndex = index / mesh.m_NbX;
376
384
377 // colormap->data()->setCell(xIndex, yIndex, *it);
385 // colormap->data()->setCell(xIndex, yIndex, *it);
378
386
379 // // Makes the NaN values to be transparent in the colormap
387 // // Makes the NaN values to be transparent in the colormap
380 // if (std::isnan(*it))
388 // if (std::isnan(*it))
381 // {
389 // {
382 // colormap->data()->setAlpha(xIndex, yIndex, 0);
390 // colormap->data()->setAlpha(xIndex, yIndex, 0);
383 // }
391 // }
384 // }
392 // }
385 // }
393 // }
386
394
387 // // Rescales axes
395 // // Rescales axes
388 // auto plot = colormap->parentPlot();
396 // auto plot = colormap->parentPlot();
389
397
390 // if (rescaleAxes)
398 // if (rescaleAxes)
391 // {
399 // {
392 // plot->rescaleAxes();
400 // plot->rescaleAxes();
393 // }
401 // }
394 }
402 }
395 };
403 };
396
404
397 /**
405 /**
398 * Helper used to create/update plottables
406 * Helper used to create/update plottables
399 */
407 */
400 struct IPlottablesHelper
408 struct IPlottablesHelper
401 {
409 {
402 virtual ~IPlottablesHelper() noexcept = default;
410 virtual ~IPlottablesHelper() noexcept = default;
403 virtual PlottablesMap create(QCustomPlot& plot) const = 0;
411 virtual PlottablesMap create(QCustomPlot& plot) const = 0;
404 virtual void setYAxisRange(const DateTimeRange& xAxisRange, QCustomPlot& plot) const = 0;
412 virtual void setYAxisRange(const DateTimeRange& xAxisRange, QCustomPlot& plot) const = 0;
405 virtual void update(
413 virtual void update(
406 PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes = false) const = 0;
414 PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes = false) const = 0;
407 };
415 };
408
416
409 /**
417 /**
410 * Default implementation of IPlottablesHelper, which takes data series to create/update plottables
418 * Default implementation of IPlottablesHelper, which takes data series to create/update plottables
411 * @tparam T the data series' type
419 * @tparam T the data series' type
412 */
420 */
413 template <typename T>
421 template <typename T>
414 struct PlottablesHelper : public IPlottablesHelper
422 struct PlottablesHelper : public IPlottablesHelper
415 {
423 {
416 explicit PlottablesHelper(std::shared_ptr<T> dataSeries) : m_DataSeries { dataSeries } {}
424 explicit PlottablesHelper(std::shared_ptr<T> dataSeries) : m_DataSeries { dataSeries } {}
417
425
418 PlottablesMap create(QCustomPlot& plot) const override
426 PlottablesMap create(QCustomPlot& plot) const override
419 {
427 {
420 return PlottablesCreator<T>::createPlottables(plot, m_DataSeries);
428 return PlottablesCreator<T>::createPlottables(plot, m_DataSeries);
421 }
429 }
422
430
423 void update(
431 void update(
424 PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes) const override
432 PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes) const override
425 {
433 {
426 if (m_DataSeries)
434 if (m_DataSeries)
427 {
435 {
428 PlottablesUpdater<T>::updatePlottables(*m_DataSeries, plottables, range, rescaleAxes);
436 PlottablesUpdater<T>::updatePlottables(*m_DataSeries, plottables, range, rescaleAxes);
429 }
437 }
430 else
438 else
431 {
439 {
432 qCCritical(LOG_VisualizationGraphHelper()) << "Can't update plottables: inconsistency "
440 qCCritical(LOG_VisualizationGraphHelper()) << "Can't update plottables: inconsistency "
433 "between the type of data series and the "
441 "between the type of data series and the "
434 "type supposed";
442 "type supposed";
435 }
443 }
436 }
444 }
437
445
438 void setYAxisRange(const DateTimeRange& xAxisRange, QCustomPlot& plot) const override
446 void setYAxisRange(const DateTimeRange& xAxisRange, QCustomPlot& plot) const override
439 {
447 {
440 if (m_DataSeries)
448 if (m_DataSeries)
441 {
449 {
442 PlottablesUpdater<T>::setPlotYAxisRange(*m_DataSeries, xAxisRange, plot);
450 PlottablesUpdater<T>::setPlotYAxisRange(*m_DataSeries, xAxisRange, plot);
443 }
451 }
444 else
452 else
445 {
453 {
446 qCCritical(LOG_VisualizationGraphHelper()) << "Can't update plottables: inconsistency "
454 qCCritical(LOG_VisualizationGraphHelper()) << "Can't update plottables: inconsistency "
447 "between the type of data series and the "
455 "between the type of data series and the "
448 "type supposed";
456 "type supposed";
449 }
457 }
450 }
458 }
451
459
452 std::shared_ptr<T> m_DataSeries;
460 std::shared_ptr<T> m_DataSeries;
453 };
461 };
454
462
455 /// Creates IPlottablesHelper according to the type of data series a variable holds
463 /// Creates IPlottablesHelper according to the type of data series a variable holds
456 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<Variable2> variable) noexcept
464 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<Variable2> variable) noexcept
457 {
465 {
458 switch (variable->type())
466 switch (variable->type())
459 {
467 {
460 case DataSeriesType::SCALAR:
468 case DataSeriesType::SCALAR:
461 return std::make_unique<PlottablesHelper<ScalarTimeSerie>>(
469 return std::make_unique<PlottablesHelper<ScalarTimeSerie>>(
462 std::dynamic_pointer_cast<ScalarTimeSerie>(variable->data()));
470 std::dynamic_pointer_cast<ScalarTimeSerie>(variable->data()));
463 case DataSeriesType::SPECTROGRAM:
471 case DataSeriesType::SPECTROGRAM:
464 return std::make_unique<PlottablesHelper<SpectrogramTimeSerie>>(
472 return std::make_unique<PlottablesHelper<SpectrogramTimeSerie>>(
465 std::dynamic_pointer_cast<SpectrogramTimeSerie>(variable->data()));
473 std::dynamic_pointer_cast<SpectrogramTimeSerie>(variable->data()));
466 case DataSeriesType::VECTOR:
474 case DataSeriesType::VECTOR:
467 return std::make_unique<PlottablesHelper<VectorTimeSerie>>(
475 return std::make_unique<PlottablesHelper<VectorTimeSerie>>(
468 std::dynamic_pointer_cast<VectorTimeSerie>(variable->data()));
476 std::dynamic_pointer_cast<VectorTimeSerie>(variable->data()));
469 case DataSeriesType::MULTICOMPONENT:
477 case DataSeriesType::MULTICOMPONENT:
470 return std::make_unique<PlottablesHelper<MultiComponentTimeSerie>>(
478 return std::make_unique<PlottablesHelper<MultiComponentTimeSerie>>(
471 std::dynamic_pointer_cast<MultiComponentTimeSerie>(variable->data()));
479 std::dynamic_pointer_cast<MultiComponentTimeSerie>(variable->data()));
472 default:
480 default:
473 // Creates default helper
481 // Creates default helper
474 break;
482 break;
475 }
483 }
476
484
477 return std::make_unique<PlottablesHelper<TimeSeries::ITimeSerie>>(nullptr);
485 return std::make_unique<PlottablesHelper<TimeSeries::ITimeSerie>>(nullptr);
478 }
486 }
479
487
480 } // namespace
488 } // namespace
481
489
482 PlottablesMap VisualizationGraphHelper::create(
490 PlottablesMap VisualizationGraphHelper::create(
483 std::shared_ptr<Variable2> variable, QCustomPlot& plot) noexcept
491 std::shared_ptr<Variable2> variable, QCustomPlot& plot) noexcept
484 {
492 {
485 if (variable)
493 if (variable)
486 {
494 {
487 auto helper = createHelper(variable);
495 auto helper = createHelper(variable);
488 auto plottables = helper->create(plot);
496 auto plottables = helper->create(plot);
489 return plottables;
497 return plottables;
490 }
498 }
491 else
499 else
492 {
500 {
493 qCDebug(LOG_VisualizationGraphHelper())
501 qCDebug(LOG_VisualizationGraphHelper())
494 << QObject::tr("Can't create graph plottables : the variable is null");
502 << QObject::tr("Can't create graph plottables : the variable is null");
495 return PlottablesMap {};
503 return PlottablesMap {};
496 }
504 }
497 }
505 }
498
506
499 void VisualizationGraphHelper::setYAxisRange(
507 void VisualizationGraphHelper::setYAxisRange(
500 std::shared_ptr<Variable2> variable, QCustomPlot& plot) noexcept
508 std::shared_ptr<Variable2> variable, QCustomPlot& plot) noexcept
501 {
509 {
502 if (variable)
510 if (variable)
503 {
511 {
504 auto helper = createHelper(variable);
512 auto helper = createHelper(variable);
505 helper->setYAxisRange(variable->range(), plot);
513 helper->setYAxisRange(variable->range(), plot);
506 }
514 }
507 else
515 else
508 {
516 {
509 qCDebug(LOG_VisualizationGraphHelper())
517 qCDebug(LOG_VisualizationGraphHelper())
510 << QObject::tr("Can't set y-axis range of plot: the variable is null");
518 << QObject::tr("Can't set y-axis range of plot: the variable is null");
511 }
519 }
512 }
520 }
513
521
514 void VisualizationGraphHelper::updateData(
522 void VisualizationGraphHelper::updateData(
515 PlottablesMap& plottables, std::shared_ptr<Variable2> variable, const DateTimeRange& dateTime)
523 PlottablesMap& plottables, std::shared_ptr<Variable2> variable, const DateTimeRange& dateTime)
516 {
524 {
517 auto helper = createHelper(variable);
525 auto helper = createHelper(variable);
518 helper->update(plottables, dateTime);
526 helper->update(plottables, dateTime);
519 }
527 }
@@ -1,61 +1,67
1 import sys
1 import sys
2 sys.path.append("/home/jeandet/Documents/prog/build-SciQLop-Desktop-Debug/core")
2 sys.path.append("/home/jeandet/Documents/prog/build-SciQLop-Desktop-Debug/core")
3 import traceback
3 import traceback
4 import os
4 import os
5 from datetime import datetime, timedelta, timezone
5 from datetime import datetime, timedelta, timezone
6 import PythonProviders
6 import PythonProviders
7 import pysciqlopcore
7 import pysciqlopcore
8 import numpy as np
8 import numpy as np
9 import pandas as pds
9 import pandas as pds
10 import requests
10 import requests
11 import copy
11 from spwc.amda import AMDA
12 from spwc.amda import AMDA
12
13
13 amda = AMDA()
14 amda = AMDA()
14
15
15 def get_sample(metadata,start,stop):
16 def get_sample(metadata,start,stop):
16 ts_type = pysciqlopcore.ScalarTimeSerie
17 ts_type = pysciqlopcore.ScalarTimeSerie
17 try:
18 try:
18 param_id = None
19 param_id = None
19 for key,value in metadata:
20 for key,value in metadata:
20 if key == 'xml:id':
21 if key == 'xml:id':
21 param_id = value
22 param_id = value
22 elif key == 'type':
23 elif key == 'type':
23 if value == 'vector':
24 if value == 'vector':
24 ts_type = pysciqlopcore.VectorTimeSerie
25 ts_type = pysciqlopcore.VectorTimeSerie
25 tstart=datetime.datetime.utcfromtimestamp(start)
26 elif value == 'multicomponent':
26 tend=datetime.datetime.utcfromtimestamp(stop)
27 ts_type = pysciqlopcore.MultiComponentTimeSerie
28 tstart=datetime.datetime.fromtimestamp(start, tz=timezone.utc)
29 tend=datetime.datetime.fromtimestamp(stop, tz=timezone.utc)
27 df = amda.get_parameter(start_time=tstart, stop_time=tend, parameter_id=param_id)
30 df = amda.get_parameter(start_time=tstart, stop_time=tend, parameter_id=param_id)
28 #t = np.array([d.timestamp()-7200 for d in df.index])
31 #t = np.array([d.timestamp()-7200 for d in df.index])
29 t = np.array([d.timestamp() for d in df.index])
32 t = np.array([d.timestamp() for d in df.index])
30 values = df.values
33 values = df.values
31 return ts_type(t,values)
34 return ts_type(t,values.transpose())
32 return ts_type(1)
35 return ts_type(1)
33 except Exception as e:
36 except Exception as e:
34 print(traceback.format_exc())
37 print(traceback.format_exc())
35 print("Error in amda.py ",str(e))
38 print("Error in amda.py ",str(e))
36 return ts_type(1)
39 return ts_type(1)
37
40
38
41
39 if len(amda.component) is 0:
42 if len(amda.component) is 0:
40 amda.update_inventory()
43 amda.update_inventory()
41 parameters = amda.parameter.copy()
44 parameters = copy.deepcopy(amda.parameter)
42 for name,component in amda.component.items():
45 for name,component in amda.component.items():
43 if 'components' in parameters[component['parameter']]:
46 if 'components' in parameters[component['parameter']]:
44 parameters[component['parameter']]['components'].append(component)
47 parameters[component['parameter']]['components'].append(component)
45 else:
48 else:
46 parameters[component['parameter']]['components']=[component]
49 parameters[component['parameter']]['components']=[component]
47
50
48 products = []
51 products = []
49 for key,parameter in parameters.items():
52 for key,parameter in parameters.items():
50 path = f"/AMDA/{parameter['mission']}/{parameter['instrument']}/{parameter['dataset']}/{parameter['name']}"
53 path = f"/AMDA/{parameter['mission']}/{parameter['instrument']}/{parameter['dataset']}/{parameter['name']}"
51 components = [component['name'] for component in parameter.get('components',[])]
54 components = [component['name'] for component in parameter.get('components',[])]
52 metadata = [ (key,item) for key,item in parameter.items() if key is not 'components' ]
55 metadata = [ (key,item) for key,item in parameter.items() if key is not 'components' ]
53 if parameter.get('size',0) is '3':
56 n_components = parameter.get('size',0)
57 if n_components is '3':
54 metadata.append(("type","vector"))
58 metadata.append(("type","vector"))
59 elif n_components !=0:
60 metadata.append(("type","multicomponent"))
55 else:
61 else:
56 metadata.append(("type","scalar"))
62 metadata.append(("type","scalar"))
57 products.append( (path, components, metadata))
63 products.append( (path, components, metadata))
58
64
59 PythonProviders.register_product(products, get_sample)
65 PythonProviders.register_product(products, get_sample)
60
66
61
67
@@ -1,17 +1,44
1 import sys
1 import sys
2 sys.path.append("/home/jeandet/Documents/prog/build-SciQLop-Desktop-Debug/core")
2 sys.path.append("/home/jeandet/Documents/prog/build-SciQLop-Desktop-Debug/core")
3 import PythonProviders
3 import PythonProviders
4 import pysciqlopcore
4 import pysciqlopcore
5 import numpy as np
5 import numpy as np
6
6
7 someglobal = 1
7 someglobal = 1
8
8
9 def test(name,start,stop):
9 def make_scalar(x):
10 x = np.arange(start, stop)
11 y = np.cos(x/10.)
10 y = np.cos(x/10.)
12 return pysciqlopcore.ScalarTimeSerie(x,y)
11 return pysciqlopcore.ScalarTimeSerie(x,y)
13
12
13 def make_vector(x):
14 v=np.ones((3,len(x)))
15 for i in range(3):
16 v[:][i] = np.cos(x/10. + float(i))
17 return pysciqlopcore.VectorTimeSerie(x,v)
18
19
20 def make_multicomponent(x):
21 v=np.ones((4,len(x)))
22 for i in range(4):
23 v[:][i] = float(i+1) * np.cos(x/10. + float(i))
24 return pysciqlopcore.MultiComponentTimeSerie(x,v)
25
26
27 def get_data(metadata,start,stop):
28 x = np.arange(start, stop)
29 for key,value in metadata:
30 if key == 'xml:id':
31 param_id = value
32 elif key == 'type':
33 if value == 'vector':
34 return make_vector(x)
35 elif value == 'multicomponent':
36 return make_multicomponent(x)
37 return make_scalar(x)
38
39
40
14
41
15 #PythonProviders.register_product(["/folder1/folder2/product1", "/folder1/folder3/product2", "/folder4/folder5/product3"],test)
42 PythonProviders.register_product([("/tests/scalar",[],[("type","scalar")]), ("/tests/vector",[],[("type","vector")]), ("/tests/multicomponent",[],[("type","multicomponent"),('size','4')])],get_data)
16
43
17
44
General Comments 0
You need to be logged in to leave comments. Login now