##// END OF EJS Templates
Uses SciQlop color scale in graphs
Alexandre Leroux -
r1050:761051f0c06c
parent child
Show More
@@ -1,37 +1,37
1 #ifndef SCIQLOP_AXISRENDERINGUTILS_H
1 #ifndef SCIQLOP_AXISRENDERINGUTILS_H
2 #define SCIQLOP_AXISRENDERINGUTILS_H
2 #define SCIQLOP_AXISRENDERINGUTILS_H
3
3
4 #include <memory>
4 #include <memory>
5
5
6 #include <QtCore/QLoggingCategory>
6 #include <QtCore/QLoggingCategory>
7 #include <QtCore/QString>
7 #include <QtCore/QString>
8
8
9 Q_DECLARE_LOGGING_CATEGORY(LOG_AxisRenderingUtils)
9 Q_DECLARE_LOGGING_CATEGORY(LOG_AxisRenderingUtils)
10
10
11 class IDataSeries;
11 class IDataSeries;
12 class QCPAxis;
12 class QCPAxis;
13 class QCPColorScale;
14 class QCustomPlot;
13 class QCustomPlot;
14 class SqpColorScale;
15
15
16 /// Formats a data value according to the axis on which it is present
16 /// Formats a data value according to the axis on which it is present
17 QString formatValue(double value, const QCPAxis &axis);
17 QString formatValue(double value, const QCPAxis &axis);
18
18
19 /**
19 /**
20 * Helper used to handle axes rendering
20 * Helper used to handle axes rendering
21 */
21 */
22 struct IAxisHelper {
22 struct IAxisHelper {
23 virtual ~IAxisHelper() noexcept = default;
23 virtual ~IAxisHelper() noexcept = default;
24
24
25 /// Set properties of the plot's axes and the color scale associated to plot passed as
25 /// Set properties of the plot's axes and the color scale associated to plot passed as
26 /// parameters
26 /// parameters
27 /// @param plot the plot for which to set axe properties
27 /// @param plot the plot for which to set axe properties
28 /// @param colorScale the color scale for which to set properties
28 /// @param colorScale the color scale for which to set properties
29 virtual void setProperties(QCustomPlot &plot, QCPColorScale &colorScale) = 0;
29 virtual void setProperties(QCustomPlot &plot, SqpColorScale &colorScale) = 0;
30 };
30 };
31
31
32 struct IAxisHelperFactory {
32 struct IAxisHelperFactory {
33 /// Creates IAxisHelper according to a data series
33 /// Creates IAxisHelper according to a data series
34 static std::unique_ptr<IAxisHelper> create(std::shared_ptr<IDataSeries> dataSeries) noexcept;
34 static std::unique_ptr<IAxisHelper> create(std::shared_ptr<IDataSeries> dataSeries) noexcept;
35 };
35 };
36
36
37 #endif // SCIQLOP_AXISRENDERINGUTILS_H
37 #endif // SCIQLOP_AXISRENDERINGUTILS_H
@@ -1,174 +1,173
1 #include "Visualization/AxisRenderingUtils.h"
1 #include "Visualization/AxisRenderingUtils.h"
2
2
3 #include <Data/ScalarSeries.h>
3 #include <Data/ScalarSeries.h>
4 #include <Data/SpectrogramSeries.h>
4 #include <Data/SpectrogramSeries.h>
5 #include <Data/VectorSeries.h>
5 #include <Data/VectorSeries.h>
6
6
7 #include <Visualization/SqpColorScale.h>
7 #include <Visualization/qcustomplot.h>
8 #include <Visualization/qcustomplot.h>
8
9
9 Q_LOGGING_CATEGORY(LOG_AxisRenderingUtils, "AxisRenderingUtils")
10 Q_LOGGING_CATEGORY(LOG_AxisRenderingUtils, "AxisRenderingUtils")
10
11
11 namespace {
12 namespace {
12
13
13 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
14 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
14
15
15 /// Format for datetimes on a axis
16 /// Format for datetimes on a axis
16 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
17 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
17
18
18 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
19 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
19 /// non-time data
20 /// non-time data
20 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis, QCPAxis::ScaleType scaleType)
21 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis, QCPAxis::ScaleType scaleType)
21 {
22 {
22 if (isTimeAxis) {
23 if (isTimeAxis) {
23 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
24 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
24 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
25 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
25 dateTicker->setDateTimeSpec(Qt::UTC);
26 dateTicker->setDateTimeSpec(Qt::UTC);
26
27
27 return dateTicker;
28 return dateTicker;
28 }
29 }
29 else if (scaleType == QCPAxis::stLogarithmic) {
30 else if (scaleType == QCPAxis::stLogarithmic) {
30 return QSharedPointer<QCPAxisTickerLog>::create();
31 return QSharedPointer<QCPAxisTickerLog>::create();
31 }
32 }
32 else {
33 else {
33 // default ticker
34 // default ticker
34 return QSharedPointer<QCPAxisTicker>::create();
35 return QSharedPointer<QCPAxisTicker>::create();
35 }
36 }
36 }
37 }
37
38
38 /**
39 /**
39 * Sets properties of the axis passed as parameter
40 * Sets properties of the axis passed as parameter
40 * @param axis the axis to set
41 * @param axis the axis to set
41 * @param unit the unit to set for the axis
42 * @param unit the unit to set for the axis
42 * @param scaleType the scale type to set for the axis
43 * @param scaleType the scale type to set for the axis
43 */
44 */
44 void setAxisProperties(QCPAxis &axis, const Unit &unit,
45 void setAxisProperties(QCPAxis &axis, const Unit &unit,
45 QCPAxis::ScaleType scaleType = QCPAxis::stLinear)
46 QCPAxis::ScaleType scaleType = QCPAxis::stLinear)
46 {
47 {
47 // label (unit name)
48 // label (unit name)
48 axis.setLabel(unit.m_Name);
49 axis.setLabel(unit.m_Name);
49
50
50 // scale type
51 // scale type
51 axis.setScaleType(scaleType);
52 axis.setScaleType(scaleType);
52 if (scaleType == QCPAxis::stLogarithmic) {
53 if (scaleType == QCPAxis::stLogarithmic) {
53 // Scientific notation
54 // Scientific notation
54 axis.setNumberPrecision(0);
55 axis.setNumberPrecision(0);
55 axis.setNumberFormat("eb");
56 axis.setNumberFormat("eb");
56 }
57 }
57
58
58 // ticker (depending on the type of unit)
59 // ticker (depending on the type of unit)
59 axis.setTicker(axisTicker(unit.m_TimeUnit, scaleType));
60 axis.setTicker(axisTicker(unit.m_TimeUnit, scaleType));
60 }
61 }
61
62
62 /**
63 /**
63 * Delegate used to set axes properties
64 * Delegate used to set axes properties
64 */
65 */
65 template <typename T, typename Enabled = void>
66 template <typename T, typename Enabled = void>
66 struct AxisSetter {
67 struct AxisSetter {
67 static void setProperties(T &, QCustomPlot &, QCPColorScale &)
68 static void setProperties(T &, QCustomPlot &, SqpColorScale &)
68 {
69 {
69 // Default implementation does nothing
70 // Default implementation does nothing
70 qCCritical(LOG_AxisRenderingUtils()) << "Can't set axis properties: unmanaged type of data";
71 qCCritical(LOG_AxisRenderingUtils()) << "Can't set axis properties: unmanaged type of data";
71 }
72 }
72 };
73 };
73
74
74 /**
75 /**
75 * Specialization of AxisSetter for scalars and vectors
76 * Specialization of AxisSetter for scalars and vectors
76 * @sa ScalarSeries
77 * @sa ScalarSeries
77 * @sa VectorSeries
78 * @sa VectorSeries
78 */
79 */
79 template <typename T>
80 template <typename T>
80 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
81 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
81 or std::is_base_of<VectorSeries, T>::value> > {
82 or std::is_base_of<VectorSeries, T>::value> > {
82 static void setProperties(T &dataSeries, QCustomPlot &plot, QCPColorScale &)
83 static void setProperties(T &dataSeries, QCustomPlot &plot, SqpColorScale &)
83 {
84 {
84 dataSeries.lockRead();
85 dataSeries.lockRead();
85 auto xAxisUnit = dataSeries.xAxisUnit();
86 auto xAxisUnit = dataSeries.xAxisUnit();
86 auto valuesUnit = dataSeries.valuesUnit();
87 auto valuesUnit = dataSeries.valuesUnit();
87 dataSeries.unlock();
88 dataSeries.unlock();
88
89
89 setAxisProperties(*plot.xAxis, xAxisUnit);
90 setAxisProperties(*plot.xAxis, xAxisUnit);
90 setAxisProperties(*plot.yAxis, valuesUnit);
91 setAxisProperties(*plot.yAxis, valuesUnit);
91 }
92 }
92 };
93 };
93
94
94 /**
95 /**
95 * Specialization of AxisSetter for spectrograms
96 * Specialization of AxisSetter for spectrograms
96 * @sa SpectrogramSeries
97 * @sa SpectrogramSeries
97 */
98 */
98 template <typename T>
99 template <typename T>
99 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
100 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
100 static void setProperties(T &dataSeries, QCustomPlot &plot, QCPColorScale &colorScale)
101 static void setProperties(T &dataSeries, QCustomPlot &plot, SqpColorScale &colorScale)
101 {
102 {
102 dataSeries.lockRead();
103 dataSeries.lockRead();
103 auto xAxisUnit = dataSeries.xAxisUnit();
104 auto xAxisUnit = dataSeries.xAxisUnit();
104 auto yAxisUnit = dataSeries.yAxisUnit();
105 auto yAxisUnit = dataSeries.yAxisUnit();
105 auto valuesUnit = dataSeries.valuesUnit();
106 auto valuesUnit = dataSeries.valuesUnit();
106 dataSeries.unlock();
107 dataSeries.unlock();
107
108
108 setAxisProperties(*plot.xAxis, xAxisUnit);
109 setAxisProperties(*plot.xAxis, xAxisUnit);
109 setAxisProperties(*plot.yAxis, yAxisUnit, QCPAxis::stLogarithmic);
110 setAxisProperties(*plot.yAxis, yAxisUnit, QCPAxis::stLogarithmic);
110
111
111 // Displays color scale in plot
112 // Displays color scale in plot
112 plot.plotLayout()->insertRow(0);
113 plot.plotLayout()->insertRow(0);
113 plot.plotLayout()->addElement(0, 0, &colorScale);
114 plot.plotLayout()->addElement(0, 0, colorScale.m_Scale);
114 colorScale.setType(QCPAxis::atTop);
115 colorScale.m_Scale->setType(QCPAxis::atTop);
115 colorScale.setMinimumMargins(QMargins{0, 0, 0, 0});
116 colorScale.m_Scale->setMinimumMargins(QMargins{0, 0, 0, 0});
116
117
117 // Aligns color scale with axes
118 // Aligns color scale with axes
118 auto marginGroups = plot.axisRect()->marginGroups();
119 auto marginGroups = plot.axisRect()->marginGroups();
119 for (auto it = marginGroups.begin(), end = marginGroups.end(); it != end; ++it) {
120 for (auto it = marginGroups.begin(), end = marginGroups.end(); it != end; ++it) {
120 colorScale.setMarginGroup(it.key(), it.value());
121 colorScale.m_Scale->setMarginGroup(it.key(), it.value());
121 }
122 }
122
123
123 // Set color scale properties
124 // Set color scale properties
124 setAxisProperties(*colorScale.axis(), valuesUnit, QCPAxis::stLogarithmic);
125 setAxisProperties(*colorScale.m_Scale->axis(), valuesUnit, QCPAxis::stLogarithmic);
125 /// @todo ALX: temp data range, remove it when widget to set data range is implemented
126 colorScale.setDataRange(QCPRange{8.32e2, 1.77e7});
127 }
126 }
128 };
127 };
129
128
130 /**
129 /**
131 * Default implementation of IAxisHelper, which takes data series to set axes properties
130 * Default implementation of IAxisHelper, which takes data series to set axes properties
132 * @tparam T the data series' type
131 * @tparam T the data series' type
133 */
132 */
134 template <typename T>
133 template <typename T>
135 struct AxisHelper : public IAxisHelper {
134 struct AxisHelper : public IAxisHelper {
136 explicit AxisHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
135 explicit AxisHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
137
136
138 void setProperties(QCustomPlot &plot, QCPColorScale &colorScale) override
137 void setProperties(QCustomPlot &plot, SqpColorScale &colorScale) override
139 {
138 {
140 AxisSetter<T>::setProperties(m_DataSeries, plot, colorScale);
139 AxisSetter<T>::setProperties(m_DataSeries, plot, colorScale);
141 }
140 }
142
141
143 T &m_DataSeries;
142 T &m_DataSeries;
144 };
143 };
145
144
146 } // namespace
145 } // namespace
147
146
148 QString formatValue(double value, const QCPAxis &axis)
147 QString formatValue(double value, const QCPAxis &axis)
149 {
148 {
150 // If the axis is a time axis, formats the value as a date
149 // If the axis is a time axis, formats the value as a date
151 if (auto axisTicker = qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker())) {
150 if (auto axisTicker = qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker())) {
152 return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT);
151 return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT);
153 }
152 }
154 else {
153 else {
155 return QString::number(value);
154 return QString::number(value);
156 }
155 }
157 }
156 }
158
157
159 std::unique_ptr<IAxisHelper>
158 std::unique_ptr<IAxisHelper>
160 IAxisHelperFactory::create(std::shared_ptr<IDataSeries> dataSeries) noexcept
159 IAxisHelperFactory::create(std::shared_ptr<IDataSeries> dataSeries) noexcept
161 {
160 {
162 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
161 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
163 return std::make_unique<AxisHelper<ScalarSeries> >(*scalarSeries);
162 return std::make_unique<AxisHelper<ScalarSeries> >(*scalarSeries);
164 }
163 }
165 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
164 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
166 return std::make_unique<AxisHelper<SpectrogramSeries> >(*spectrogramSeries);
165 return std::make_unique<AxisHelper<SpectrogramSeries> >(*spectrogramSeries);
167 }
166 }
168 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
167 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
169 return std::make_unique<AxisHelper<VectorSeries> >(*vectorSeries);
168 return std::make_unique<AxisHelper<VectorSeries> >(*vectorSeries);
170 }
169 }
171 else {
170 else {
172 return std::make_unique<AxisHelper<IDataSeries> >(*dataSeries);
171 return std::make_unique<AxisHelper<IDataSeries> >(*dataSeries);
173 }
172 }
174 }
173 }
@@ -1,127 +1,122
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 <Data/ScalarSeries.h>
5 #include <Data/ScalarSeries.h>
6 #include <Data/SpectrogramSeries.h>
6 #include <Data/SpectrogramSeries.h>
7 #include <Data/VectorSeries.h>
7 #include <Data/VectorSeries.h>
8
8
9 #include <Visualization/qcustomplot.h>
9 #include <Visualization/qcustomplot.h>
10
10
11 Q_LOGGING_CATEGORY(LOG_PlottablesRenderingUtils, "PlottablesRenderingUtils")
11 Q_LOGGING_CATEGORY(LOG_PlottablesRenderingUtils, "PlottablesRenderingUtils")
12
12
13 namespace {
13 namespace {
14
14
15 /// Default gradient used for colormap
16 const auto DEFAULT_COLORMAP_GRADIENT = QCPColorGradient::gpJet;
17
18 /**
15 /**
19 * Delegate used to set plottables properties
16 * Delegate used to set plottables properties
20 */
17 */
21 template <typename T, typename Enabled = void>
18 template <typename T, typename Enabled = void>
22 struct PlottablesSetter {
19 struct PlottablesSetter {
23 static void setProperties(T &, PlottablesMap &)
20 static void setProperties(T &, PlottablesMap &)
24 {
21 {
25 // Default implementation does nothing
22 // Default implementation does nothing
26 qCCritical(LOG_PlottablesRenderingUtils())
23 qCCritical(LOG_PlottablesRenderingUtils())
27 << "Can't set plottables properties: unmanaged type of data";
24 << "Can't set plottables properties: unmanaged type of data";
28 }
25 }
29 };
26 };
30
27
31 /**
28 /**
32 * Specialization of PlottablesSetter for scalars and vectors
29 * Specialization of PlottablesSetter for scalars and vectors
33 * @sa ScalarSeries
30 * @sa ScalarSeries
34 * @sa VectorSeries
31 * @sa VectorSeries
35 */
32 */
36 template <typename T>
33 template <typename T>
37 struct PlottablesSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
34 struct PlottablesSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
38 or std::is_base_of<VectorSeries, T>::value> > {
35 or std::is_base_of<VectorSeries, T>::value> > {
39 static void setProperties(T &dataSeries, PlottablesMap &plottables)
36 static void setProperties(T &dataSeries, PlottablesMap &plottables)
40 {
37 {
41 // Gets the number of components of the data series
38 // Gets the number of components of the data series
42 dataSeries.lockRead();
39 dataSeries.lockRead();
43 auto componentCount = dataSeries.valuesData()->componentCount();
40 auto componentCount = dataSeries.valuesData()->componentCount();
44 dataSeries.unlock();
41 dataSeries.unlock();
45
42
46 // Generates colors for each component
43 // Generates colors for each component
47 auto colors = ColorUtils::colors(Qt::blue, Qt::red, componentCount);
44 auto colors = ColorUtils::colors(Qt::blue, Qt::red, componentCount);
48
45
49 // For each component of the data series, creates a QCPGraph to add to the plot
46 // For each component of the data series, creates a QCPGraph to add to the plot
50 for (auto i = 0; i < componentCount; ++i) {
47 for (auto i = 0; i < componentCount; ++i) {
51 auto graph = plottables.at(i);
48 auto graph = plottables.at(i);
52 graph->setPen(QPen{colors.at(i)});
49 graph->setPen(QPen{colors.at(i)});
53 }
50 }
54 }
51 }
55 };
52 };
56
53
57 /**
54 /**
58 * Specialization of PlottablesSetter for spectrograms
55 * Specialization of PlottablesSetter for spectrograms
59 * @sa SpectrogramSeries
56 * @sa SpectrogramSeries
60 */
57 */
61 template <typename T>
58 template <typename T>
62 struct PlottablesSetter<T,
59 struct PlottablesSetter<T,
63 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
60 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
64 static void setProperties(T &, PlottablesMap &plottables)
61 static void setProperties(T &, PlottablesMap &plottables)
65 {
62 {
66 // Checks that for a spectrogram there is only one plottable, that is a colormap
63 // Checks that for a spectrogram there is only one plottable, that is a colormap
67 if (plottables.size() != 1) {
64 if (plottables.size() != 1) {
68 return;
65 return;
69 }
66 }
70
67
71 if (auto colormap = dynamic_cast<QCPColorMap *>(plottables.begin()->second)) {
68 if (auto colormap = dynamic_cast<QCPColorMap *>(plottables.begin()->second)) {
72 colormap->setInterpolate(false); // No value interpolation
69 colormap->setInterpolate(false); // No value interpolation
73 colormap->setTightBoundary(true);
70 colormap->setTightBoundary(true);
74
71
75 // Finds color scale in the colormap's plot to associate with it
72 // Finds color scale in the colormap's plot to associate with it
76 auto plot = colormap->parentPlot();
73 auto plot = colormap->parentPlot();
77 auto plotElements = plot->plotLayout()->elements(false);
74 auto plotElements = plot->plotLayout()->elements(false);
78 for (auto plotElement : plotElements) {
75 for (auto plotElement : plotElements) {
79 if (auto colorScale = dynamic_cast<QCPColorScale *>(plotElement)) {
76 if (auto colorScale = dynamic_cast<QCPColorScale *>(plotElement)) {
80 colormap->setColorScale(colorScale);
77 colormap->setColorScale(colorScale);
81 }
78 }
82 }
79 }
83
80
84 // Sets gradient used for color scale
85 colormap->setGradient(DEFAULT_COLORMAP_GRADIENT);
86 colormap->rescaleDataRange();
81 colormap->rescaleDataRange();
87 }
82 }
88 else {
83 else {
89 qCCritical(LOG_PlottablesRenderingUtils()) << "Can't get colormap of the spectrogram";
84 qCCritical(LOG_PlottablesRenderingUtils()) << "Can't get colormap of the spectrogram";
90 }
85 }
91 }
86 }
92 };
87 };
93
88
94 /**
89 /**
95 * Default implementation of IPlottablesHelper, which takes data series to set plottables properties
90 * Default implementation of IPlottablesHelper, which takes data series to set plottables properties
96 * @tparam T the data series' type
91 * @tparam T the data series' type
97 */
92 */
98 template <typename T>
93 template <typename T>
99 struct PlottablesHelper : public IPlottablesHelper {
94 struct PlottablesHelper : public IPlottablesHelper {
100 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
95 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
101
96
102 void setProperties(PlottablesMap &plottables) override
97 void setProperties(PlottablesMap &plottables) override
103 {
98 {
104 PlottablesSetter<T>::setProperties(m_DataSeries, plottables);
99 PlottablesSetter<T>::setProperties(m_DataSeries, plottables);
105 }
100 }
106
101
107 T &m_DataSeries;
102 T &m_DataSeries;
108 };
103 };
109
104
110 } // namespace
105 } // namespace
111
106
112 std::unique_ptr<IPlottablesHelper>
107 std::unique_ptr<IPlottablesHelper>
113 IPlottablesHelperFactory::create(std::shared_ptr<IDataSeries> dataSeries) noexcept
108 IPlottablesHelperFactory::create(std::shared_ptr<IDataSeries> dataSeries) noexcept
114 {
109 {
115 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
110 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
116 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
111 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
117 }
112 }
118 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
113 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
119 return std::make_unique<PlottablesHelper<SpectrogramSeries> >(*spectrogramSeries);
114 return std::make_unique<PlottablesHelper<SpectrogramSeries> >(*spectrogramSeries);
120 }
115 }
121 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
116 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
122 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
117 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
123 }
118 }
124 else {
119 else {
125 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
120 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
126 }
121 }
127 }
122 }
@@ -1,255 +1,256
1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
2 #include "Visualization/AxisRenderingUtils.h"
2 #include "Visualization/AxisRenderingUtils.h"
3 #include "Visualization/ColorScaleEditor.h"
3 #include "Visualization/ColorScaleEditor.h"
4 #include "Visualization/PlottablesRenderingUtils.h"
4 #include "Visualization/PlottablesRenderingUtils.h"
5 #include "Visualization/SqpColorScale.h"
5 #include "Visualization/VisualizationGraphWidget.h"
6 #include "Visualization/VisualizationGraphWidget.h"
6 #include "Visualization/qcustomplot.h"
7 #include "Visualization/qcustomplot.h"
7
8
8 #include <Common/DateUtils.h>
9 #include <Common/DateUtils.h>
9
10
10 #include <Data/IDataSeries.h>
11 #include <Data/IDataSeries.h>
11
12
12 #include <SqpApplication.h>
13 #include <SqpApplication.h>
13
14
14 namespace {
15 namespace {
15
16
16 /// Name of the axes layer in QCustomPlot
17 /// Name of the axes layer in QCustomPlot
17 const auto AXES_LAYER = QStringLiteral("axes");
18 const auto AXES_LAYER = QStringLiteral("axes");
18
19
19 /// Icon used to show x-axis properties
20 /// Icon used to show x-axis properties
20 const auto HIDE_AXIS_ICON_PATH = QStringLiteral(":/icones/down.png");
21 const auto HIDE_AXIS_ICON_PATH = QStringLiteral(":/icones/down.png");
21
22
22 /// Name of the overlay layer in QCustomPlot
23 /// Name of the overlay layer in QCustomPlot
23 const auto OVERLAY_LAYER = QStringLiteral("overlay");
24 const auto OVERLAY_LAYER = QStringLiteral("overlay");
24
25
25 /// Pixmap used to show x-axis properties
26 /// Pixmap used to show x-axis properties
26 const auto SHOW_AXIS_ICON_PATH = QStringLiteral(":/icones/up.png");
27 const auto SHOW_AXIS_ICON_PATH = QStringLiteral(":/icones/up.png");
27
28
28 const auto TOOLTIP_FORMAT = QStringLiteral("key: %1\nvalue: %2");
29 const auto TOOLTIP_FORMAT = QStringLiteral("key: %1\nvalue: %2");
29
30
30 /// Offset used to shift the tooltip of the mouse
31 /// Offset used to shift the tooltip of the mouse
31 const auto TOOLTIP_OFFSET = QPoint{20, 20};
32 const auto TOOLTIP_OFFSET = QPoint{20, 20};
32
33
33 /// Tooltip display rectangle (the tooltip is hidden when the mouse leaves this rectangle)
34 /// Tooltip display rectangle (the tooltip is hidden when the mouse leaves this rectangle)
34 const auto TOOLTIP_RECT = QRect{10, 10, 10, 10};
35 const auto TOOLTIP_RECT = QRect{10, 10, 10, 10};
35
36
36 /// Timeout after which the tooltip is displayed
37 /// Timeout after which the tooltip is displayed
37 const auto TOOLTIP_TIMEOUT = 500;
38 const auto TOOLTIP_TIMEOUT = 500;
38
39
39 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
40 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
40 {
41 {
41 tracer.setInterpolating(false);
42 tracer.setInterpolating(false);
42 tracer.setStyle(QCPItemTracer::tsCircle);
43 tracer.setStyle(QCPItemTracer::tsCircle);
43 tracer.setSize(3);
44 tracer.setSize(3);
44 tracer.setPen(QPen(Qt::black));
45 tracer.setPen(QPen(Qt::black));
45 tracer.setBrush(Qt::black);
46 tracer.setBrush(Qt::black);
46 }
47 }
47
48
48 QPixmap pixmap(const QString &iconPath) noexcept
49 QPixmap pixmap(const QString &iconPath) noexcept
49 {
50 {
50 return QIcon{iconPath}.pixmap(QSize{16, 16});
51 return QIcon{iconPath}.pixmap(QSize{16, 16});
51 }
52 }
52
53
53 void initClosePixmapStyle(QCPItemPixmap &pixmap) noexcept
54 void initClosePixmapStyle(QCPItemPixmap &pixmap) noexcept
54 {
55 {
55 // Icon
56 // Icon
56 pixmap.setPixmap(
57 pixmap.setPixmap(
57 sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize{16, 16}));
58 sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize{16, 16}));
58
59
59 // Position
60 // Position
60 pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
61 pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
61 pixmap.topLeft->setCoords(1, 0);
62 pixmap.topLeft->setCoords(1, 0);
62 pixmap.setClipToAxisRect(false);
63 pixmap.setClipToAxisRect(false);
63
64
64 // Can be selected
65 // Can be selected
65 pixmap.setSelectable(true);
66 pixmap.setSelectable(true);
66 }
67 }
67
68
68 void initXAxisPixmapStyle(QCPItemPixmap &itemPixmap) noexcept
69 void initXAxisPixmapStyle(QCPItemPixmap &itemPixmap) noexcept
69 {
70 {
70 // Icon
71 // Icon
71 itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH));
72 itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH));
72
73
73 // Position
74 // Position
74 itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
75 itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
75 itemPixmap.topLeft->setCoords(0, 1);
76 itemPixmap.topLeft->setCoords(0, 1);
76 itemPixmap.setClipToAxisRect(false);
77 itemPixmap.setClipToAxisRect(false);
77
78
78 // Can be selected
79 // Can be selected
79 itemPixmap.setSelectable(true);
80 itemPixmap.setSelectable(true);
80 }
81 }
81
82
82 void initTitleTextStyle(QCPItemText &text) noexcept
83 void initTitleTextStyle(QCPItemText &text) noexcept
83 {
84 {
84 // Font and background styles
85 // Font and background styles
85 text.setColor(Qt::gray);
86 text.setColor(Qt::gray);
86 text.setBrush(Qt::white);
87 text.setBrush(Qt::white);
87
88
88 // Position
89 // Position
89 text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
90 text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
90 text.position->setType(QCPItemPosition::ptAxisRectRatio);
91 text.position->setType(QCPItemPosition::ptAxisRectRatio);
91 text.position->setCoords(0.5, 0);
92 text.position->setCoords(0.5, 0);
92 }
93 }
93
94
94 } // namespace
95 } // namespace
95
96
96 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
97 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
97 explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget &graphWidget)
98 explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget &graphWidget)
98 : m_Plot{graphWidget.plot()},
99 : m_Plot{graphWidget.plot()},
99 m_PointTracer{new QCPItemTracer{&m_Plot}},
100 m_PointTracer{new QCPItemTracer{&m_Plot}},
100 m_TracerTimer{},
101 m_TracerTimer{},
101 m_ClosePixmap{new QCPItemPixmap{&m_Plot}},
102 m_ClosePixmap{new QCPItemPixmap{&m_Plot}},
102 m_TitleText{new QCPItemText{&m_Plot}},
103 m_TitleText{new QCPItemText{&m_Plot}},
103 m_XAxisPixmap{new QCPItemPixmap{&m_Plot}},
104 m_XAxisPixmap{new QCPItemPixmap{&m_Plot}},
104 m_ShowXAxis{true},
105 m_ShowXAxis{true},
105 m_XAxisLabel{},
106 m_XAxisLabel{},
106 m_ColorScale{new QCPColorScale{&m_Plot}}
107 m_ColorScale{SqpColorScale{m_Plot}}
107 {
108 {
108 initPointTracerStyle(*m_PointTracer);
109 initPointTracerStyle(*m_PointTracer);
109
110
110 m_TracerTimer.setInterval(TOOLTIP_TIMEOUT);
111 m_TracerTimer.setInterval(TOOLTIP_TIMEOUT);
111 m_TracerTimer.setSingleShot(true);
112 m_TracerTimer.setSingleShot(true);
112
113
113 // Inits "close button" in plot overlay
114 // Inits "close button" in plot overlay
114 m_ClosePixmap->setLayer(OVERLAY_LAYER);
115 m_ClosePixmap->setLayer(OVERLAY_LAYER);
115 initClosePixmapStyle(*m_ClosePixmap);
116 initClosePixmapStyle(*m_ClosePixmap);
116
117
117 // Connects pixmap selection to graph widget closing
118 // Connects pixmap selection to graph widget closing
118 QObject::connect(m_ClosePixmap, &QCPItemPixmap::selectionChanged,
119 QObject::connect(m_ClosePixmap, &QCPItemPixmap::selectionChanged,
119 [&graphWidget](bool selected) {
120 [&graphWidget](bool selected) {
120 if (selected) {
121 if (selected) {
121 graphWidget.close();
122 graphWidget.close();
122 }
123 }
123 });
124 });
124
125
125 // Inits graph name in plot overlay
126 // Inits graph name in plot overlay
126 m_TitleText->setLayer(OVERLAY_LAYER);
127 m_TitleText->setLayer(OVERLAY_LAYER);
127 m_TitleText->setText(graphWidget.name());
128 m_TitleText->setText(graphWidget.name());
128 initTitleTextStyle(*m_TitleText);
129 initTitleTextStyle(*m_TitleText);
129
130
130 // Inits "show x-axis button" in plot overlay
131 // Inits "show x-axis button" in plot overlay
131 m_XAxisPixmap->setLayer(OVERLAY_LAYER);
132 m_XAxisPixmap->setLayer(OVERLAY_LAYER);
132 initXAxisPixmapStyle(*m_XAxisPixmap);
133 initXAxisPixmapStyle(*m_XAxisPixmap);
133
134
134 // Connects pixmap selection to graph x-axis showing/hiding
135 // Connects pixmap selection to graph x-axis showing/hiding
135 QObject::connect(m_XAxisPixmap, &QCPItemPixmap::selectionChanged, [this]() {
136 QObject::connect(m_XAxisPixmap, &QCPItemPixmap::selectionChanged, [this]() {
136 if (m_XAxisPixmap->selected()) {
137 if (m_XAxisPixmap->selected()) {
137 // Changes the selection state and refreshes the x-axis
138 // Changes the selection state and refreshes the x-axis
138 m_ShowXAxis = !m_ShowXAxis;
139 m_ShowXAxis = !m_ShowXAxis;
139 updateXAxisState();
140 updateXAxisState();
140 m_Plot.layer(AXES_LAYER)->replot();
141 m_Plot.layer(AXES_LAYER)->replot();
141
142
142 // Deselects the x-axis pixmap and updates icon
143 // Deselects the x-axis pixmap and updates icon
143 m_XAxisPixmap->setSelected(false);
144 m_XAxisPixmap->setSelected(false);
144 m_XAxisPixmap->setPixmap(
145 m_XAxisPixmap->setPixmap(
145 pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH));
146 pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH));
146 m_Plot.layer(OVERLAY_LAYER)->replot();
147 m_Plot.layer(OVERLAY_LAYER)->replot();
147 }
148 }
148 });
149 });
149 }
150 }
150
151
151 /// Updates state of x-axis according to the current selection of x-axis pixmap
152 /// Updates state of x-axis according to the current selection of x-axis pixmap
152 /// @remarks the method doesn't call plot refresh
153 /// @remarks the method doesn't call plot refresh
153 void updateXAxisState() noexcept
154 void updateXAxisState() noexcept
154 {
155 {
155 m_Plot.xAxis->setTickLabels(m_ShowXAxis);
156 m_Plot.xAxis->setTickLabels(m_ShowXAxis);
156 m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString{});
157 m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString{});
157 }
158 }
158
159
159 QCustomPlot &m_Plot;
160 QCustomPlot &m_Plot;
160 QCPItemTracer *m_PointTracer;
161 QCPItemTracer *m_PointTracer;
161 QTimer m_TracerTimer;
162 QTimer m_TracerTimer;
162 QCPItemPixmap *m_ClosePixmap; /// Graph's close button
163 QCPItemPixmap *m_ClosePixmap; /// Graph's close button
163 QCPItemText *m_TitleText; /// Graph's title
164 QCPItemText *m_TitleText; /// Graph's title
164 QCPItemPixmap *m_XAxisPixmap;
165 QCPItemPixmap *m_XAxisPixmap;
165 bool m_ShowXAxis; /// X-axis properties are shown or hidden
166 bool m_ShowXAxis; /// X-axis properties are shown or hidden
166 QString m_XAxisLabel;
167 QString m_XAxisLabel;
167 QCPColorScale *m_ColorScale; /// Color scale used for some types of graphs (as spectrograms)
168 SqpColorScale m_ColorScale; /// Color scale used for some types of graphs (as spectrograms)
168 };
169 };
169
170
170 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(
171 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(
171 VisualizationGraphWidget &graphWidget)
172 VisualizationGraphWidget &graphWidget)
172 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(graphWidget)}
173 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(graphWidget)}
173 {
174 {
174 }
175 }
175
176
176 void VisualizationGraphRenderingDelegate::onMouseDoubleClick(QMouseEvent *event) noexcept
177 void VisualizationGraphRenderingDelegate::onMouseDoubleClick(QMouseEvent *event) noexcept
177 {
178 {
178 // Opens color scale editor if color scale is double clicked
179 // Opens color scale editor if color scale is double clicked
179 if (auto colorScale
180 if (auto colorScale
180 = dynamic_cast<QCPColorScale *>(impl->m_Plot.layoutElementAt(event->pos()))) {
181 = dynamic_cast<QCPColorScale *>(impl->m_Plot.layoutElementAt(event->pos()))) {
181 ColorScaleEditor{}.exec();
182 ColorScaleEditor{}.exec();
182 }
183 }
183 }
184 }
184
185
185 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
186 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
186 {
187 {
187 // Cancels pending refresh
188 // Cancels pending refresh
188 impl->m_TracerTimer.disconnect();
189 impl->m_TracerTimer.disconnect();
189
190
190 // Reinits tracers
191 // Reinits tracers
191 impl->m_PointTracer->setGraph(nullptr);
192 impl->m_PointTracer->setGraph(nullptr);
192 impl->m_PointTracer->setVisible(false);
193 impl->m_PointTracer->setVisible(false);
193 impl->m_Plot.replot();
194 impl->m_Plot.replot();
194
195
195 // Gets the graph under the mouse position
196 // Gets the graph under the mouse position
196 auto eventPos = event->pos();
197 auto eventPos = event->pos();
197 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
198 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
198 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
199 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
199 auto graphData = graph->data();
200 auto graphData = graph->data();
200
201
201 // Gets the closest data point to the mouse
202 // Gets the closest data point to the mouse
202 auto graphDataIt = graphData->findBegin(mouseKey);
203 auto graphDataIt = graphData->findBegin(mouseKey);
203 if (graphDataIt != graphData->constEnd()) {
204 if (graphDataIt != graphData->constEnd()) {
204 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
205 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
205 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
206 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
206
207
207 // Displays point tracer
208 // Displays point tracer
208 impl->m_PointTracer->setGraph(graph);
209 impl->m_PointTracer->setGraph(graph);
209 impl->m_PointTracer->setGraphKey(graphDataIt->key);
210 impl->m_PointTracer->setGraphKey(graphDataIt->key);
210 impl->m_PointTracer->setLayer(
211 impl->m_PointTracer->setLayer(
211 impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer
212 impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer
212 impl->m_PointTracer->setVisible(true);
213 impl->m_PointTracer->setVisible(true);
213 impl->m_Plot.replot();
214 impl->m_Plot.replot();
214
215
215 // Starts timer to show tooltip after timeout
216 // Starts timer to show tooltip after timeout
216 auto showTooltip = [ tooltip = TOOLTIP_FORMAT.arg(key, value), eventPos, this ]()
217 auto showTooltip = [ tooltip = TOOLTIP_FORMAT.arg(key, value), eventPos, this ]()
217 {
218 {
218 QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip,
219 QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip,
219 &impl->m_Plot, TOOLTIP_RECT);
220 &impl->m_Plot, TOOLTIP_RECT);
220 };
221 };
221
222
222 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip);
223 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip);
223 impl->m_TracerTimer.start();
224 impl->m_TracerTimer.start();
224 }
225 }
225 }
226 }
226 }
227 }
227
228
228 void VisualizationGraphRenderingDelegate::setAxesProperties(
229 void VisualizationGraphRenderingDelegate::setAxesProperties(
229 std::shared_ptr<IDataSeries> dataSeries) noexcept
230 std::shared_ptr<IDataSeries> dataSeries) noexcept
230 {
231 {
231 // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected
232 // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected
232 impl->m_XAxisLabel = dataSeries->xAxisUnit().m_Name;
233 impl->m_XAxisLabel = dataSeries->xAxisUnit().m_Name;
233
234
234 auto axisHelper = IAxisHelperFactory::create(dataSeries);
235 auto axisHelper = IAxisHelperFactory::create(dataSeries);
235 axisHelper->setProperties(impl->m_Plot, *impl->m_ColorScale);
236 axisHelper->setProperties(impl->m_Plot, impl->m_ColorScale);
236
237
237 // Updates x-axis state
238 // Updates x-axis state
238 impl->updateXAxisState();
239 impl->updateXAxisState();
239
240
240 impl->m_Plot.layer(AXES_LAYER)->replot();
241 impl->m_Plot.layer(AXES_LAYER)->replot();
241 }
242 }
242
243
243 void VisualizationGraphRenderingDelegate::setPlottablesProperties(
244 void VisualizationGraphRenderingDelegate::setPlottablesProperties(
244 std::shared_ptr<IDataSeries> dataSeries, PlottablesMap &plottables) noexcept
245 std::shared_ptr<IDataSeries> dataSeries, PlottablesMap &plottables) noexcept
245 {
246 {
246 auto plottablesHelper = IPlottablesHelperFactory::create(dataSeries);
247 auto plottablesHelper = IPlottablesHelperFactory::create(dataSeries);
247 plottablesHelper->setProperties(plottables);
248 plottablesHelper->setProperties(plottables);
248 }
249 }
249
250
250 void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept
251 void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept
251 {
252 {
252 auto overlay = impl->m_Plot.layer(OVERLAY_LAYER);
253 auto overlay = impl->m_Plot.layer(OVERLAY_LAYER);
253 overlay->setVisible(show);
254 overlay->setVisible(show);
254 overlay->replot();
255 overlay->replot();
255 }
256 }
General Comments 0
You need to be logged in to leave comments. Login now