##// END OF EJS Templates
Separate the initialization of the properties of the graph of the update of the units of the graph....
Separate the initialization of the properties of the graph of the update of the units of the graph. The initialization of the properties is carried out when adding a variable in the graph, the update of the units is carried out when loading the data of this variable

File last commit:

r1305:3d74b7d22319
r1308:41b7c6aab8be
Show More
VisualizationGraphHelper.cpp
361 lines | 12.4 KiB | text/x-c | CppLexer
/ gui / src / Visualization / VisualizationGraphHelper.cpp
Correction for pull request
r243 #include "Visualization/VisualizationGraphHelper.h"
Alexandre Leroux
Creates factory that is responsible of creation of QCustomPlot components relative to a variable
r181 #include "Visualization/qcustomplot.h"
Alexandre Leroux
Mesh generation for QColorMap (4)...
r1037 #include <Data/DataSeriesUtils.h>
Alexandre Leroux
Handles creations for scalar series
r182 #include <Data/ScalarSeries.h>
Alexandre Leroux
Implements spectrograms display (1)...
r905 #include <Data/SpectrogramSeries.h>
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 #include <Data/VectorSeries.h>
Alexandre Leroux
Handles creations for scalar series
r182
Alexandre Leroux
Creates factory that is responsible of creation of QCustomPlot components relative to a variable
r181 #include <Variable/Variable.h>
Correction for pull request
r243 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
Alexandre Leroux
Creates factory that is responsible of creation of QCustomPlot components relative to a variable
r181
Alexandre Leroux
Handles creations for scalar series
r182 namespace {
Add current progression for thread fix
r364 class SqpDataContainer : public QCPGraphDataContainer {
public:
Alexandre Leroux
Updates UI to not call the sort method when update graphs, as data series are already sorted
r453 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
Add current progression for thread fix
r364 };
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 /**
Add mofif for clang format
r591 * Struct used to create plottables, depending on the type of the data series from which to create
* them
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 * @tparam T the data series' type
* @remarks Default implementation can't create plottables
*/
template <typename T, typename Enabled = void>
struct PlottablesCreator {
Alexandre Leroux
Updates VisualizationGraphHelper to use variable's type instead of dataseries
r1305 static PlottablesMap createPlottables(QCustomPlot &)
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 {
qCCritical(LOG_DataSeries())
<< QObject::tr("Can't create plottables: unmanaged data series type");
return {};
The mock plugin can now create data with view operation
r235 }
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 };
The mock plugin can now create data with view operation
r235
Alexandre Leroux
Updates VisualizationGraphHelper to use variable's type instead of dataseries
r1305 PlottablesMap createGraphs(QCustomPlot &plot, int nbGraphs)
{
PlottablesMap result{};
// Creates {nbGraphs} QCPGraph to add to the plot
for (auto i = 0; i < nbGraphs; ++i) {
auto graph = plot.addGraph();
result.insert({i, graph});
}
plot.replot();
return result;
}
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 /**
Alexandre Leroux
Updates VisualizationGraphHelper to use variable's type instead of dataseries
r1305 * Specialization of PlottablesCreator for scalars
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 * @sa ScalarSeries
*/
template <typename T>
Alexandre Leroux
Updates VisualizationGraphHelper to use variable's type instead of dataseries
r1305 struct PlottablesCreator<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value> > {
static PlottablesMap createPlottables(QCustomPlot &plot) { return createGraphs(plot, 1); }
};
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583
Alexandre Leroux
Updates VisualizationGraphHelper to use variable's type instead of dataseries
r1305 /**
* Specialization of PlottablesCreator for vectors
* @sa VectorSeries
*/
template <typename T>
struct PlottablesCreator<T, typename std::enable_if_t<std::is_base_of<VectorSeries, T>::value> > {
static PlottablesMap createPlottables(QCustomPlot &plot) { return createGraphs(plot, 3); }
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 };
Initialisation of the graph range at creation in a new graphe, or inside...
r548
Alexandre Leroux
Implements spectrograms display (1)...
r905 /**
* Specialization of PlottablesCreator for spectrograms
* @sa SpectrogramSeries
*/
template <typename T>
struct PlottablesCreator<T,
typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
Alexandre Leroux
Updates VisualizationGraphHelper to use variable's type instead of dataseries
r1305 static PlottablesMap createPlottables(QCustomPlot &plot)
Alexandre Leroux
Implements spectrograms display (1)...
r905 {
PlottablesMap result{};
result.insert({0, new QCPColorMap{plot.xAxis, plot.yAxis}});
plot.replot();
return result;
}
};
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 /**
Add mofif for clang format
r591 * Struct used to update plottables, depending on the type of the data series from which to update
* them
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 * @tparam T the data series' type
* @remarks Default implementation can't update plottables
*/
template <typename T, typename Enabled = void>
struct PlottablesUpdater {
Alexandre Leroux
Refactors VisualizationGraphWidget::setYRange()...
r903 static void setPlotYAxisRange(T &, const SqpRange &, QCustomPlot &)
{
Alexandre Leroux
(Minor) Removes obsolete code
r908 qCCritical(LOG_VisualizationGraphHelper())
Alexandre Leroux
Refactors VisualizationGraphWidget::setYRange()...
r903 << QObject::tr("Can't set plot y-axis range: unmanaged data series type");
}
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 static void updatePlottables(T &, PlottablesMap &, const SqpRange &, bool)
{
Alexandre Leroux
(Minor) Removes obsolete code
r908 qCCritical(LOG_VisualizationGraphHelper())
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 << QObject::tr("Can't update plottables: unmanaged data series type");
}
};
Alexandre Leroux
Handles creations for scalar series
r182
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 /**
* Specialization of PlottablesUpdater for scalars and vectors
* @sa ScalarSeries
* @sa VectorSeries
*/
template <typename T>
struct PlottablesUpdater<T,
typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
or std::is_base_of<VectorSeries, T>::value> > {
Alexandre Leroux
Refactors VisualizationGraphWidget::setYRange()...
r903 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
{
auto minValue = 0., maxValue = 0.;
dataSeries.lockRead();
auto valuesBounds = dataSeries.valuesBounds(xAxisRange.m_TStart, xAxisRange.m_TEnd);
auto end = dataSeries.cend();
if (valuesBounds.first != end && valuesBounds.second != end) {
auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
minValue = rangeValue(valuesBounds.first->minValue());
maxValue = rangeValue(valuesBounds.second->maxValue());
}
dataSeries.unlock();
plot.yAxis->setRange(QCPRange{minValue, maxValue});
}
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
bool rescaleAxes)
{
// For each plottable to update, resets its data
std::map<int, QSharedPointer<SqpDataContainer> > dataContainers{};
for (const auto &plottable : plottables) {
if (auto graph = dynamic_cast<QCPGraph *>(plottable.second)) {
auto dataContainer = QSharedPointer<SqpDataContainer>::create();
graph->setData(dataContainer);
dataContainers.insert({plottable.first, dataContainer});
}
}
Add thread protection for DataSeries...
r636 dataSeries.lockRead();
Alexandre Leroux
Handles creations for scalar series
r182
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 // - Gets the data of the series included in the current range
Add mofif for clang format
r591 // - Updates each plottable by adding, for each data item, a point that takes x-axis data
// and value data. The correct value is retrieved according to the index of the component
Alexandre Leroux
(Refactoring) Renames IDataSeries::subData()
r605 auto subDataIts = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 for (auto it = subDataIts.first; it != subDataIts.second; ++it) {
for (const auto &dataContainer : dataContainers) {
auto componentIndex = dataContainer.first;
dataContainer.second->appendGraphData(
QCPGraphData(it->x(), it->value(componentIndex)));
}
}
The mock plugin can now create data with view operation
r235
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 dataSeries.unlock();
Alexandre Leroux
Handles axes properties
r183
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 if (!plottables.empty()) {
auto plot = plottables.begin()->second->parentPlot();
Alexandre Leroux
Handles axes properties
r183
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 if (rescaleAxes) {
plot->rescaleAxes();
}
}
Alexandre Leroux
Handles creations for scalar series
r182 }
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 };
Alexandre Leroux
Implements spectrograms display (2)...
r906 /**
* Specialization of PlottablesUpdater for spectrograms
* @sa SpectrogramSeries
*/
template <typename T>
struct PlottablesUpdater<T,
typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
Alexandre Leroux
Implements spectrograms display (3)...
r907 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
{
double min, max;
Alexandre Leroux
Updates access to y-axis properties of the data series (1)...
r1030 std::tie(min, max) = dataSeries.yBounds();
Alexandre Leroux
Implements spectrograms display (3)...
r907
if (!std::isnan(min) && !std::isnan(max)) {
plot.yAxis->setRange(QCPRange{min, max});
}
}
Alexandre Leroux
Implements spectrograms display (2)...
r906 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
bool rescaleAxes)
{
if (plottables.empty()) {
qCDebug(LOG_VisualizationGraphHelper())
<< QObject::tr("Can't update spectrogram: no colormap has been associated");
return;
}
// Gets the colormap to update (normally there is only one colormap)
Q_ASSERT(plottables.size() == 1);
auto colormap = dynamic_cast<QCPColorMap *>(plottables.at(0));
Q_ASSERT(colormap != nullptr);
dataSeries.lockRead();
Alexandre Leroux
Mesh generation for QColorMap (4)...
r1037 // Processing spectrogram data for display in QCustomPlot
Alexandre Leroux
Implements spectrograms display (2)...
r906 auto its = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
Alexandre Leroux
Mesh generation for QColorMap (4)...
r1037 // Computes logarithmic y-axis resolution for the spectrogram
auto yData = its.first->y();
auto yResolution = DataSeriesUtils::resolution(yData.begin(), yData.end(), true);
// Generates mesh for colormap
auto mesh = DataSeriesUtils::regularMesh(
its.first, its.second, DataSeriesUtils::Resolution{dataSeries.xResolution()},
yResolution);
dataSeries.unlock();
Alexandre Leroux
Implements spectrograms display (2)...
r906
Alexandre Leroux
Mesh generation for QColorMap (4)...
r1037 colormap->data()->setSize(mesh.m_NbX, mesh.m_NbY);
if (!mesh.isEmpty()) {
colormap->data()->setRange(
QCPRange{mesh.m_XMin, mesh.xMax()},
// y-axis range is converted to linear values
QCPRange{std::pow(10, mesh.m_YMin), std::pow(10, mesh.yMax())});
Alexandre Leroux
Introduces NaN and zero values in data of the mock spectrogram...
r923
Alexandre Leroux
Mesh generation for QColorMap (4)...
r1037 // Sets values
auto index = 0;
for (auto it = mesh.m_Data.begin(), end = mesh.m_Data.end(); it != end; ++it, ++index) {
auto xIndex = index % mesh.m_NbX;
auto yIndex = index / mesh.m_NbX;
Alexandre Leroux
Introduces NaN and zero values in data of the mock spectrogram...
r923
Alexandre Leroux
Mesh generation for QColorMap (4)...
r1037 colormap->data()->setCell(xIndex, yIndex, *it);
// Makes the NaN values to be transparent in the colormap
if (std::isnan(*it)) {
Alexandre Leroux
Introduces NaN and zero values in data of the mock spectrogram...
r923 colormap->data()->setAlpha(xIndex, yIndex, 0);
}
Alexandre Leroux
Implements spectrograms display (2)...
r906 }
}
// Rescales axes
auto plot = colormap->parentPlot();
if (rescaleAxes) {
plot->rescaleAxes();
}
}
};
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 /**
* Helper used to create/update plottables
*/
struct IPlottablesHelper {
virtual ~IPlottablesHelper() noexcept = default;
virtual PlottablesMap create(QCustomPlot &plot) const = 0;
Alexandre Leroux
Refactors VisualizationGraphWidget::setYRange()...
r903 virtual void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const = 0;
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 virtual void update(PlottablesMap &plottables, const SqpRange &range,
bool rescaleAxes = false) const = 0;
};
/**
* Default implementation of IPlottablesHelper, which takes data series to create/update plottables
* @tparam T the data series' type
*/
template <typename T>
struct PlottablesHelper : public IPlottablesHelper {
Alexandre Leroux
Updates VisualizationGraphHelper to use variable's type instead of dataseries
r1305 explicit PlottablesHelper(std::shared_ptr<T> dataSeries) : m_DataSeries{dataSeries} {}
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583
PlottablesMap create(QCustomPlot &plot) const override
{
Alexandre Leroux
Updates VisualizationGraphHelper to use variable's type instead of dataseries
r1305 return PlottablesCreator<T>::createPlottables(plot);
Alexandre Leroux
Handles creations for scalar series
r182 }
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 void update(PlottablesMap &plottables, const SqpRange &range, bool rescaleAxes) const override
{
Alexandre Leroux
Updates VisualizationGraphHelper to use variable's type instead of dataseries
r1305 if (m_DataSeries) {
PlottablesUpdater<T>::updatePlottables(*m_DataSeries, plottables, range, rescaleAxes);
}
else {
qCCritical(LOG_VisualizationGraphHelper()) << "Can't update plottables: inconsistency "
"between the type of data series and the "
"type supposed";
}
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 }
Alexandre Leroux
Handles creations for scalar series
r182
Alexandre Leroux
Refactors VisualizationGraphWidget::setYRange()...
r903 void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const override
{
Alexandre Leroux
Updates VisualizationGraphHelper to use variable's type instead of dataseries
r1305 if (m_DataSeries) {
PlottablesUpdater<T>::setPlotYAxisRange(*m_DataSeries, xAxisRange, plot);
}
else {
qCCritical(LOG_VisualizationGraphHelper()) << "Can't update plottables: inconsistency "
"between the type of data series and the "
"type supposed";
}
Alexandre Leroux
Refactors VisualizationGraphWidget::setYRange()...
r903 }
Alexandre Leroux
Updates VisualizationGraphHelper to use variable's type instead of dataseries
r1305 std::shared_ptr<T> m_DataSeries;
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 };
Alexandre Leroux
Handles creations for scalar series
r182
Alexandre Leroux
Updates VisualizationGraphHelper to use variable's type instead of dataseries
r1305 /// Creates IPlottablesHelper according to the type of data series a variable holds
std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<Variable> variable) noexcept
Initialisation of the graph range at creation in a new graphe, or inside...
r548 {
Alexandre Leroux
Updates VisualizationGraphHelper to use variable's type instead of dataseries
r1305 switch (variable->type()) {
case DataSeriesType::SCALAR:
return std::make_unique<PlottablesHelper<ScalarSeries> >(
std::dynamic_pointer_cast<ScalarSeries>(variable->dataSeries()));
case DataSeriesType::SPECTROGRAM:
return std::make_unique<PlottablesHelper<SpectrogramSeries> >(
std::dynamic_pointer_cast<SpectrogramSeries>(variable->dataSeries()));
case DataSeriesType::VECTOR:
return std::make_unique<PlottablesHelper<VectorSeries> >(
std::dynamic_pointer_cast<VectorSeries>(variable->dataSeries()));
default:
// Creates default helper
break;
Initialisation of the graph range at creation in a new graphe, or inside...
r548 }
Alexandre Leroux
Updates VisualizationGraphHelper to use variable's type instead of dataseries
r1305
return std::make_unique<PlottablesHelper<IDataSeries> >(nullptr);
Initialisation of the graph range at creation in a new graphe, or inside...
r548 }
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 } // namespace
Alexandre Leroux
Creates factory that is responsible of creation of QCustomPlot components relative to a variable
r181
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 PlottablesMap VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
QCustomPlot &plot) noexcept
{
Alexandre Leroux
Creates factory that is responsible of creation of QCustomPlot components relative to a variable
r181 if (variable) {
Alexandre Leroux
Updates VisualizationGraphHelper to use variable's type instead of dataseries
r1305 auto helper = createHelper(variable);
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 auto plottables = helper->create(plot);
return plottables;
Alexandre Leroux
Creates factory that is responsible of creation of QCustomPlot components relative to a variable
r181 }
else {
Correction for pull request
r243 qCDebug(LOG_VisualizationGraphHelper())
Alexandre Leroux
Creates factory that is responsible of creation of QCustomPlot components relative to a variable
r181 << QObject::tr("Can't create graph plottables : the variable is null");
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 return PlottablesMap{};
Alexandre Leroux
Creates factory that is responsible of creation of QCustomPlot components relative to a variable
r181 }
}
The mock plugin can now create data with view operation
r235
Alexandre Leroux
Refactors VisualizationGraphWidget::setYRange()...
r903 void VisualizationGraphHelper::setYAxisRange(std::shared_ptr<Variable> variable,
QCustomPlot &plot) noexcept
{
if (variable) {
Alexandre Leroux
Updates VisualizationGraphHelper to use variable's type instead of dataseries
r1305 auto helper = createHelper(variable);
Alexandre Leroux
Refactors VisualizationGraphWidget::setYRange()...
r903 helper->setYAxisRange(variable->range(), plot);
}
else {
qCDebug(LOG_VisualizationGraphHelper())
<< QObject::tr("Can't set y-axis range of plot: the variable is null");
}
}
Alexandre Leroux
Uses std::shared_ptr
r587 void VisualizationGraphHelper::updateData(PlottablesMap &plottables,
Alexandre Leroux
Updates VisualizationGraphHelper to use variable's type instead of dataseries
r1305 std::shared_ptr<Variable> variable,
The dataSeries of a variable is now shared istead of uniq to avoid...
r542 const SqpRange &dateTime)
The mock plugin can now create data with view operation
r235 {
Alexandre Leroux
Updates VisualizationGraphHelper to use variable's type instead of dataseries
r1305 auto helper = createHelper(variable);
Alexandre Leroux
Updates VisualizationGraphHelper to handle vectors
r583 helper->update(plottables, dateTime);
The mock plugin can now create data with view operation
r235 }