##// END OF EJS Templates
Mesh generation for QColorMap (4)...
Alexandre Leroux -
r995:bf7c3257108b
parent child
Show More
@@ -1,344 +1,344
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/DataSeriesUtils.h>
4 #include <Data/ScalarSeries.h>
5 #include <Data/ScalarSeries.h>
5 #include <Data/SpectrogramSeries.h>
6 #include <Data/SpectrogramSeries.h>
6 #include <Data/VectorSeries.h>
7 #include <Data/VectorSeries.h>
7
8
8 #include <Variable/Variable.h>
9 #include <Variable/Variable.h>
9
10
10 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
11 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
11
12
12 namespace {
13 namespace {
13
14
14 class SqpDataContainer : public QCPGraphDataContainer {
15 class SqpDataContainer : public QCPGraphDataContainer {
15 public:
16 public:
16 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
17 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
17 };
18 };
18
19
19 /**
20 /**
20 * Struct used to create plottables, depending on the type of the data series from which to create
21 * Struct used to create plottables, depending on the type of the data series from which to create
21 * them
22 * them
22 * @tparam T the data series' type
23 * @tparam T the data series' type
23 * @remarks Default implementation can't create plottables
24 * @remarks Default implementation can't create plottables
24 */
25 */
25 template <typename T, typename Enabled = void>
26 template <typename T, typename Enabled = void>
26 struct PlottablesCreator {
27 struct PlottablesCreator {
27 static PlottablesMap createPlottables(T &, QCustomPlot &)
28 static PlottablesMap createPlottables(T &, QCustomPlot &)
28 {
29 {
29 qCCritical(LOG_DataSeries())
30 qCCritical(LOG_DataSeries())
30 << QObject::tr("Can't create plottables: unmanaged data series type");
31 << QObject::tr("Can't create plottables: unmanaged data series type");
31 return {};
32 return {};
32 }
33 }
33 };
34 };
34
35
35 /**
36 /**
36 * Specialization of PlottablesCreator for scalars and vectors
37 * Specialization of PlottablesCreator for scalars and vectors
37 * @sa ScalarSeries
38 * @sa ScalarSeries
38 * @sa VectorSeries
39 * @sa VectorSeries
39 */
40 */
40 template <typename T>
41 template <typename T>
41 struct PlottablesCreator<T,
42 struct PlottablesCreator<T,
42 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
43 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
43 or std::is_base_of<VectorSeries, T>::value> > {
44 or std::is_base_of<VectorSeries, T>::value> > {
44 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
45 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
45 {
46 {
46 PlottablesMap result{};
47 PlottablesMap result{};
47
48
48 // Gets the number of components of the data series
49 // Gets the number of components of the data series
49 dataSeries.lockRead();
50 dataSeries.lockRead();
50 auto componentCount = dataSeries.valuesData()->componentCount();
51 auto componentCount = dataSeries.valuesData()->componentCount();
51 dataSeries.unlock();
52 dataSeries.unlock();
52
53
53 // For each component of the data series, creates a QCPGraph to add to the plot
54 // For each component of the data series, creates a QCPGraph to add to the plot
54 for (auto i = 0; i < componentCount; ++i) {
55 for (auto i = 0; i < componentCount; ++i) {
55 auto graph = plot.addGraph();
56 auto graph = plot.addGraph();
56 result.insert({i, graph});
57 result.insert({i, graph});
57 }
58 }
58
59
59 plot.replot();
60 plot.replot();
60
61
61 return result;
62 return result;
62 }
63 }
63 };
64 };
64
65
65 /**
66 /**
66 * Specialization of PlottablesCreator for spectrograms
67 * Specialization of PlottablesCreator for spectrograms
67 * @sa SpectrogramSeries
68 * @sa SpectrogramSeries
68 */
69 */
69 template <typename T>
70 template <typename T>
70 struct PlottablesCreator<T,
71 struct PlottablesCreator<T,
71 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
72 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
72 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
73 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
73 {
74 {
74 PlottablesMap result{};
75 PlottablesMap result{};
75 result.insert({0, new QCPColorMap{plot.xAxis, plot.yAxis}});
76 result.insert({0, new QCPColorMap{plot.xAxis, plot.yAxis}});
76
77
77 plot.replot();
78 plot.replot();
78
79
79 return result;
80 return result;
80 }
81 }
81 };
82 };
82
83
83 /**
84 /**
84 * Struct used to update plottables, depending on the type of the data series from which to update
85 * Struct used to update plottables, depending on the type of the data series from which to update
85 * them
86 * them
86 * @tparam T the data series' type
87 * @tparam T the data series' type
87 * @remarks Default implementation can't update plottables
88 * @remarks Default implementation can't update plottables
88 */
89 */
89 template <typename T, typename Enabled = void>
90 template <typename T, typename Enabled = void>
90 struct PlottablesUpdater {
91 struct PlottablesUpdater {
91 static void setPlotYAxisRange(T &, const SqpRange &, QCustomPlot &)
92 static void setPlotYAxisRange(T &, const SqpRange &, QCustomPlot &)
92 {
93 {
93 qCCritical(LOG_VisualizationGraphHelper())
94 qCCritical(LOG_VisualizationGraphHelper())
94 << QObject::tr("Can't set plot y-axis range: unmanaged data series type");
95 << QObject::tr("Can't set plot y-axis range: unmanaged data series type");
95 }
96 }
96
97
97 static void updatePlottables(T &, PlottablesMap &, const SqpRange &, bool)
98 static void updatePlottables(T &, PlottablesMap &, const SqpRange &, bool)
98 {
99 {
99 qCCritical(LOG_VisualizationGraphHelper())
100 qCCritical(LOG_VisualizationGraphHelper())
100 << QObject::tr("Can't update plottables: unmanaged data series type");
101 << QObject::tr("Can't update plottables: unmanaged data series type");
101 }
102 }
102 };
103 };
103
104
104 /**
105 /**
105 * Specialization of PlottablesUpdater for scalars and vectors
106 * Specialization of PlottablesUpdater for scalars and vectors
106 * @sa ScalarSeries
107 * @sa ScalarSeries
107 * @sa VectorSeries
108 * @sa VectorSeries
108 */
109 */
109 template <typename T>
110 template <typename T>
110 struct PlottablesUpdater<T,
111 struct PlottablesUpdater<T,
111 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
112 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
112 or std::is_base_of<VectorSeries, T>::value> > {
113 or std::is_base_of<VectorSeries, T>::value> > {
113 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
114 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
114 {
115 {
115 auto minValue = 0., maxValue = 0.;
116 auto minValue = 0., maxValue = 0.;
116
117
117 dataSeries.lockRead();
118 dataSeries.lockRead();
118 auto valuesBounds = dataSeries.valuesBounds(xAxisRange.m_TStart, xAxisRange.m_TEnd);
119 auto valuesBounds = dataSeries.valuesBounds(xAxisRange.m_TStart, xAxisRange.m_TEnd);
119 auto end = dataSeries.cend();
120 auto end = dataSeries.cend();
120 if (valuesBounds.first != end && valuesBounds.second != end) {
121 if (valuesBounds.first != end && valuesBounds.second != end) {
121 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
122 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
122
123
123 minValue = rangeValue(valuesBounds.first->minValue());
124 minValue = rangeValue(valuesBounds.first->minValue());
124 maxValue = rangeValue(valuesBounds.second->maxValue());
125 maxValue = rangeValue(valuesBounds.second->maxValue());
125 }
126 }
126 dataSeries.unlock();
127 dataSeries.unlock();
127
128
128 plot.yAxis->setRange(QCPRange{minValue, maxValue});
129 plot.yAxis->setRange(QCPRange{minValue, maxValue});
129 }
130 }
130
131
131 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
132 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
132 bool rescaleAxes)
133 bool rescaleAxes)
133 {
134 {
134
135
135 // For each plottable to update, resets its data
136 // For each plottable to update, resets its data
136 std::map<int, QSharedPointer<SqpDataContainer> > dataContainers{};
137 std::map<int, QSharedPointer<SqpDataContainer> > dataContainers{};
137 for (const auto &plottable : plottables) {
138 for (const auto &plottable : plottables) {
138 if (auto graph = dynamic_cast<QCPGraph *>(plottable.second)) {
139 if (auto graph = dynamic_cast<QCPGraph *>(plottable.second)) {
139 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
140 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
140 graph->setData(dataContainer);
141 graph->setData(dataContainer);
141
142
142 dataContainers.insert({plottable.first, dataContainer});
143 dataContainers.insert({plottable.first, dataContainer});
143 }
144 }
144 }
145 }
145 dataSeries.lockRead();
146 dataSeries.lockRead();
146
147
147 // - Gets the data of the series included in the current range
148 // - Gets the data of the series included in the current range
148 // - Updates each plottable by adding, for each data item, a point that takes x-axis data
149 // - Updates each plottable by adding, for each data item, a point that takes x-axis data
149 // and value data. The correct value is retrieved according to the index of the component
150 // and value data. The correct value is retrieved according to the index of the component
150 auto subDataIts = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
151 auto subDataIts = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
151 for (auto it = subDataIts.first; it != subDataIts.second; ++it) {
152 for (auto it = subDataIts.first; it != subDataIts.second; ++it) {
152 for (const auto &dataContainer : dataContainers) {
153 for (const auto &dataContainer : dataContainers) {
153 auto componentIndex = dataContainer.first;
154 auto componentIndex = dataContainer.first;
154 dataContainer.second->appendGraphData(
155 dataContainer.second->appendGraphData(
155 QCPGraphData(it->x(), it->value(componentIndex)));
156 QCPGraphData(it->x(), it->value(componentIndex)));
156 }
157 }
157 }
158 }
158
159
159 dataSeries.unlock();
160 dataSeries.unlock();
160
161
161 if (!plottables.empty()) {
162 if (!plottables.empty()) {
162 auto plot = plottables.begin()->second->parentPlot();
163 auto plot = plottables.begin()->second->parentPlot();
163
164
164 if (rescaleAxes) {
165 if (rescaleAxes) {
165 plot->rescaleAxes();
166 plot->rescaleAxes();
166 }
167 }
167
168
168 plot->replot();
169 plot->replot();
169 }
170 }
170 }
171 }
171 };
172 };
172
173
173 /**
174 /**
174 * Specialization of PlottablesUpdater for spectrograms
175 * Specialization of PlottablesUpdater for spectrograms
175 * @sa SpectrogramSeries
176 * @sa SpectrogramSeries
176 */
177 */
177 template <typename T>
178 template <typename T>
178 struct PlottablesUpdater<T,
179 struct PlottablesUpdater<T,
179 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
180 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
180 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
181 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
181 {
182 {
182 double min, max;
183 double min, max;
183 std::tie(min, max) = dataSeries.yBounds();
184 std::tie(min, max) = dataSeries.yBounds();
184
185
185 if (!std::isnan(min) && !std::isnan(max)) {
186 if (!std::isnan(min) && !std::isnan(max)) {
186 plot.yAxis->setRange(QCPRange{min, max});
187 plot.yAxis->setRange(QCPRange{min, max});
187 }
188 }
188 }
189 }
189
190
190 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
191 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
191 bool rescaleAxes)
192 bool rescaleAxes)
192 {
193 {
193 if (plottables.empty()) {
194 if (plottables.empty()) {
194 qCDebug(LOG_VisualizationGraphHelper())
195 qCDebug(LOG_VisualizationGraphHelper())
195 << QObject::tr("Can't update spectrogram: no colormap has been associated");
196 << QObject::tr("Can't update spectrogram: no colormap has been associated");
196 return;
197 return;
197 }
198 }
198
199
199 // Gets the colormap to update (normally there is only one colormap)
200 // Gets the colormap to update (normally there is only one colormap)
200 Q_ASSERT(plottables.size() == 1);
201 Q_ASSERT(plottables.size() == 1);
201 auto colormap = dynamic_cast<QCPColorMap *>(plottables.at(0));
202 auto colormap = dynamic_cast<QCPColorMap *>(plottables.at(0));
202 Q_ASSERT(colormap != nullptr);
203 Q_ASSERT(colormap != nullptr);
203
204
204 dataSeries.lockRead();
205 dataSeries.lockRead();
205
206
207 // Processing spectrogram data for display in QCustomPlot
206 auto its = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
208 auto its = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
207 /// @todo ALX: use iterators here
208 auto yAxis = dataSeries.yAxis();
209
210 // Gets properties of x-axis and y-axis to set size and range of the colormap
211 auto nbX = std::distance(its.first, its.second);
212 auto xMin = nbX != 0 ? its.first->x() : 0.;
213 auto xMax = nbX != 0 ? (its.second - 1)->x() : 0.;
214
215 auto nbY = yAxis.size();
216 auto yMin = 0., yMax = 0.;
217 if (nbY != 0) {
218 std::tie(yMin, yMax) = yAxis.bounds();
219 }
220
209
221 colormap->data()->setSize(nbX, nbY);
210 // Computes logarithmic y-axis resolution for the spectrogram
222 colormap->data()->setRange(QCPRange{xMin, xMax}, QCPRange{yMin, yMax});
211 auto yData = its.first->y();
212 auto yResolution = DataSeriesUtils::resolution(yData.begin(), yData.end(), true);
213
214 // Generates mesh for colormap
215 auto mesh = DataSeriesUtils::regularMesh(
216 its.first, its.second, DataSeriesUtils::Resolution{dataSeries.xResolution()},
217 yResolution);
218
219 dataSeries.unlock();
223
220
224 // Sets values
221 colormap->data()->setSize(mesh.m_NbX, mesh.m_NbY);
225 auto xIndex = 0;
222 if (!mesh.isEmpty()) {
226 for (auto it = its.first; it != its.second; ++it, ++xIndex) {
223 colormap->data()->setRange(
227 for (auto yIndex = 0; yIndex < nbY; ++yIndex) {
224 QCPRange{mesh.m_XMin, mesh.xMax()},
228 auto value = it->value(yIndex);
225 // y-axis range is converted to linear values
226 QCPRange{std::pow(10, mesh.m_YMin), std::pow(10, mesh.yMax())});
229
227
230 colormap->data()->setCell(xIndex, yIndex, value);
228 // Sets values
229 auto index = 0;
230 for (auto it = mesh.m_Data.begin(), end = mesh.m_Data.end(); it != end; ++it, ++index) {
231 auto xIndex = index % mesh.m_NbX;
232 auto yIndex = index / mesh.m_NbX;
231
233
232 // Processing spectrogram data for display in QCustomPlot
234 colormap->data()->setCell(xIndex, yIndex, *it);
233 /// For the moment, we just make the NaN values to be transparent in the colormap
235
234 /// @todo ALX: complete treatments (mesh generation, etc.)
236 // Makes the NaN values to be transparent in the colormap
235 if (std::isnan(value)) {
237 if (std::isnan(*it)) {
236 colormap->data()->setAlpha(xIndex, yIndex, 0);
238 colormap->data()->setAlpha(xIndex, yIndex, 0);
237 }
239 }
238 }
240 }
239 }
241 }
240
242
241 dataSeries.unlock();
242
243 // Rescales axes
243 // Rescales axes
244 auto plot = colormap->parentPlot();
244 auto plot = colormap->parentPlot();
245
245
246 if (rescaleAxes) {
246 if (rescaleAxes) {
247 plot->rescaleAxes();
247 plot->rescaleAxes();
248 }
248 }
249
249
250 plot->replot();
250 plot->replot();
251 }
251 }
252 };
252 };
253
253
254 /**
254 /**
255 * Helper used to create/update plottables
255 * Helper used to create/update plottables
256 */
256 */
257 struct IPlottablesHelper {
257 struct IPlottablesHelper {
258 virtual ~IPlottablesHelper() noexcept = default;
258 virtual ~IPlottablesHelper() noexcept = default;
259 virtual PlottablesMap create(QCustomPlot &plot) const = 0;
259 virtual PlottablesMap create(QCustomPlot &plot) const = 0;
260 virtual void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const = 0;
260 virtual void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const = 0;
261 virtual void update(PlottablesMap &plottables, const SqpRange &range,
261 virtual void update(PlottablesMap &plottables, const SqpRange &range,
262 bool rescaleAxes = false) const = 0;
262 bool rescaleAxes = false) const = 0;
263 };
263 };
264
264
265 /**
265 /**
266 * Default implementation of IPlottablesHelper, which takes data series to create/update plottables
266 * Default implementation of IPlottablesHelper, which takes data series to create/update plottables
267 * @tparam T the data series' type
267 * @tparam T the data series' type
268 */
268 */
269 template <typename T>
269 template <typename T>
270 struct PlottablesHelper : public IPlottablesHelper {
270 struct PlottablesHelper : public IPlottablesHelper {
271 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
271 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
272
272
273 PlottablesMap create(QCustomPlot &plot) const override
273 PlottablesMap create(QCustomPlot &plot) const override
274 {
274 {
275 return PlottablesCreator<T>::createPlottables(m_DataSeries, plot);
275 return PlottablesCreator<T>::createPlottables(m_DataSeries, plot);
276 }
276 }
277
277
278 void update(PlottablesMap &plottables, const SqpRange &range, bool rescaleAxes) const override
278 void update(PlottablesMap &plottables, const SqpRange &range, bool rescaleAxes) const override
279 {
279 {
280 PlottablesUpdater<T>::updatePlottables(m_DataSeries, plottables, range, rescaleAxes);
280 PlottablesUpdater<T>::updatePlottables(m_DataSeries, plottables, range, rescaleAxes);
281 }
281 }
282
282
283 void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const override
283 void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const override
284 {
284 {
285 return PlottablesUpdater<T>::setPlotYAxisRange(m_DataSeries, xAxisRange, plot);
285 return PlottablesUpdater<T>::setPlotYAxisRange(m_DataSeries, xAxisRange, plot);
286 }
286 }
287
287
288 T &m_DataSeries;
288 T &m_DataSeries;
289 };
289 };
290
290
291 /// Creates IPlottablesHelper according to a data series
291 /// Creates IPlottablesHelper according to a data series
292 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<IDataSeries> dataSeries) noexcept
292 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<IDataSeries> dataSeries) noexcept
293 {
293 {
294 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
294 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
295 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
295 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
296 }
296 }
297 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
297 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
298 return std::make_unique<PlottablesHelper<SpectrogramSeries> >(*spectrogramSeries);
298 return std::make_unique<PlottablesHelper<SpectrogramSeries> >(*spectrogramSeries);
299 }
299 }
300 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
300 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
301 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
301 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
302 }
302 }
303 else {
303 else {
304 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
304 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
305 }
305 }
306 }
306 }
307
307
308 } // namespace
308 } // namespace
309
309
310 PlottablesMap VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
310 PlottablesMap VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
311 QCustomPlot &plot) noexcept
311 QCustomPlot &plot) noexcept
312 {
312 {
313 if (variable) {
313 if (variable) {
314 auto helper = createHelper(variable->dataSeries());
314 auto helper = createHelper(variable->dataSeries());
315 auto plottables = helper->create(plot);
315 auto plottables = helper->create(plot);
316 return plottables;
316 return plottables;
317 }
317 }
318 else {
318 else {
319 qCDebug(LOG_VisualizationGraphHelper())
319 qCDebug(LOG_VisualizationGraphHelper())
320 << QObject::tr("Can't create graph plottables : the variable is null");
320 << QObject::tr("Can't create graph plottables : the variable is null");
321 return PlottablesMap{};
321 return PlottablesMap{};
322 }
322 }
323 }
323 }
324
324
325 void VisualizationGraphHelper::setYAxisRange(std::shared_ptr<Variable> variable,
325 void VisualizationGraphHelper::setYAxisRange(std::shared_ptr<Variable> variable,
326 QCustomPlot &plot) noexcept
326 QCustomPlot &plot) noexcept
327 {
327 {
328 if (variable) {
328 if (variable) {
329 auto helper = createHelper(variable->dataSeries());
329 auto helper = createHelper(variable->dataSeries());
330 helper->setYAxisRange(variable->range(), plot);
330 helper->setYAxisRange(variable->range(), plot);
331 }
331 }
332 else {
332 else {
333 qCDebug(LOG_VisualizationGraphHelper())
333 qCDebug(LOG_VisualizationGraphHelper())
334 << QObject::tr("Can't set y-axis range of plot: the variable is null");
334 << QObject::tr("Can't set y-axis range of plot: the variable is null");
335 }
335 }
336 }
336 }
337
337
338 void VisualizationGraphHelper::updateData(PlottablesMap &plottables,
338 void VisualizationGraphHelper::updateData(PlottablesMap &plottables,
339 std::shared_ptr<IDataSeries> dataSeries,
339 std::shared_ptr<IDataSeries> dataSeries,
340 const SqpRange &dateTime)
340 const SqpRange &dateTime)
341 {
341 {
342 auto helper = createHelper(dataSeries);
342 auto helper = createHelper(dataSeries);
343 helper->update(plottables, dateTime);
343 helper->update(plottables, dateTime);
344 }
344 }
General Comments 0
You need to be logged in to leave comments. Login now