##// END OF EJS Templates
Handles log scales for y-axis and color scale
Alexandre Leroux -
r928:42fd5c9b7ed8
parent child
Show More
@@ -1,166 +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/qcustomplot.h>
7 #include <Visualization/qcustomplot.h>
8
8
9 Q_LOGGING_CATEGORY(LOG_AxisRenderingUtils, "AxisRenderingUtils")
9 Q_LOGGING_CATEGORY(LOG_AxisRenderingUtils, "AxisRenderingUtils")
10
10
11 namespace {
11 namespace {
12
12
13 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
13 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
14
14
15 /// Format for datetimes on a axis
15 /// Format for datetimes on a axis
16 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
16 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
17
17
18 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
18 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
19 /// non-time data
19 /// non-time data
20 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
20 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis, QCPAxis::ScaleType scaleType)
21 {
21 {
22 if (isTimeAxis) {
22 if (isTimeAxis) {
23 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
23 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
24 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
24 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
25 dateTicker->setDateTimeSpec(Qt::UTC);
25 dateTicker->setDateTimeSpec(Qt::UTC);
26
26
27 return dateTicker;
27 return dateTicker;
28 }
28 }
29 else if (scaleType == QCPAxis::stLogarithmic) {
30 return QSharedPointer<QCPAxisTickerLog>::create();
31 }
29 else {
32 else {
30 // default ticker
33 // default ticker
31 return QSharedPointer<QCPAxisTicker>::create();
34 return QSharedPointer<QCPAxisTicker>::create();
32 }
35 }
33 }
36 }
34
37
35 /**
38 /**
36 * Sets properties of the axis passed as parameter
39 * Sets properties of the axis passed as parameter
37 * @param axis the axis to set
40 * @param axis the axis to set
38 * @param unit the unit to set for the axis
41 * @param unit the unit to set for the axis
39 * @param scaleType the scale type to set for the axis
42 * @param scaleType the scale type to set for the axis
40 */
43 */
41 void setAxisProperties(QCPAxis &axis, const Unit &unit,
44 void setAxisProperties(QCPAxis &axis, const Unit &unit,
42 QCPAxis::ScaleType scaleType = QCPAxis::stLinear)
45 QCPAxis::ScaleType scaleType = QCPAxis::stLinear)
43 {
46 {
44 // label (unit name)
47 // label (unit name)
45 axis.setLabel(unit.m_Name);
48 axis.setLabel(unit.m_Name);
46
49
47 // scale type
50 // scale type
48 axis.setScaleType(scaleType);
51 axis.setScaleType(scaleType);
52 if (scaleType == QCPAxis::stLogarithmic) {
53 // Scientific notation
54 axis.setNumberPrecision(0);
55 axis.setNumberFormat("eb");
56 }
49
57
50 // ticker (depending on the type of unit)
58 // ticker (depending on the type of unit)
51 axis.setTicker(axisTicker(unit.m_TimeUnit));
59 axis.setTicker(axisTicker(unit.m_TimeUnit, scaleType));
52 }
60 }
53
61
54 /**
62 /**
55 * Delegate used to set axes properties
63 * Delegate used to set axes properties
56 */
64 */
57 template <typename T, typename Enabled = void>
65 template <typename T, typename Enabled = void>
58 struct AxisSetter {
66 struct AxisSetter {
59 static void setProperties(T &, QCustomPlot &, QCPColorScale &)
67 static void setProperties(T &, QCustomPlot &, QCPColorScale &)
60 {
68 {
61 // Default implementation does nothing
69 // Default implementation does nothing
62 qCCritical(LOG_AxisRenderingUtils()) << "Can't set axis properties: unmanaged type of data";
70 qCCritical(LOG_AxisRenderingUtils()) << "Can't set axis properties: unmanaged type of data";
63 }
71 }
64 };
72 };
65
73
66 /**
74 /**
67 * Specialization of AxisSetter for scalars and vectors
75 * Specialization of AxisSetter for scalars and vectors
68 * @sa ScalarSeries
76 * @sa ScalarSeries
69 * @sa VectorSeries
77 * @sa VectorSeries
70 */
78 */
71 template <typename T>
79 template <typename T>
72 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
80 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
73 or std::is_base_of<VectorSeries, T>::value> > {
81 or std::is_base_of<VectorSeries, T>::value> > {
74 static void setProperties(T &dataSeries, QCustomPlot &plot, QCPColorScale &)
82 static void setProperties(T &dataSeries, QCustomPlot &plot, QCPColorScale &)
75 {
83 {
76 dataSeries.lockRead();
84 dataSeries.lockRead();
77 auto xAxisUnit = dataSeries.xAxisUnit();
85 auto xAxisUnit = dataSeries.xAxisUnit();
78 auto valuesUnit = dataSeries.valuesUnit();
86 auto valuesUnit = dataSeries.valuesUnit();
79 dataSeries.unlock();
87 dataSeries.unlock();
80
88
81 setAxisProperties(*plot.xAxis, xAxisUnit);
89 setAxisProperties(*plot.xAxis, xAxisUnit);
82 setAxisProperties(*plot.yAxis, valuesUnit);
90 setAxisProperties(*plot.yAxis, valuesUnit);
83 }
91 }
84 };
92 };
85
93
86 /**
94 /**
87 * Specialization of AxisSetter for spectrograms
95 * Specialization of AxisSetter for spectrograms
88 * @sa SpectrogramSeries
96 * @sa SpectrogramSeries
89 */
97 */
90 template <typename T>
98 template <typename T>
91 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
99 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
92 static void setProperties(T &dataSeries, QCustomPlot &plot, QCPColorScale &colorScale)
100 static void setProperties(T &dataSeries, QCustomPlot &plot, QCPColorScale &colorScale)
93 {
101 {
94 dataSeries.lockRead();
102 dataSeries.lockRead();
95 auto xAxisUnit = dataSeries.xAxisUnit();
103 auto xAxisUnit = dataSeries.xAxisUnit();
96 /// @todo ALX: use iterators here
104 /// @todo ALX: use iterators here
97 auto yAxisUnit = dataSeries.yAxis().unit();
105 auto yAxisUnit = dataSeries.yAxis().unit();
98 auto valuesUnit = dataSeries.valuesUnit();
106 auto valuesUnit = dataSeries.valuesUnit();
99 dataSeries.unlock();
107 dataSeries.unlock();
100
108
101 setAxisProperties(*plot.xAxis, xAxisUnit);
109 setAxisProperties(*plot.xAxis, xAxisUnit);
102 setAxisProperties(*plot.yAxis, yAxisUnit);
110 setAxisProperties(*plot.yAxis, yAxisUnit, QCPAxis::stLogarithmic);
103
111
104 // Displays color scale in plot
112 // Displays color scale in plot
105 plot.plotLayout()->insertRow(0);
113 plot.plotLayout()->insertRow(0);
106 plot.plotLayout()->addElement(0, 0, &colorScale);
114 plot.plotLayout()->addElement(0, 0, &colorScale);
107 colorScale.setType(QCPAxis::atTop);
115 colorScale.setType(QCPAxis::atTop);
108 colorScale.setMinimumMargins(QMargins{0, 0, 0, 0});
116 colorScale.setMinimumMargins(QMargins{0, 0, 0, 0});
109
117
110 // Aligns color scale with axes
118 // Aligns color scale with axes
111 auto marginGroups = plot.axisRect()->marginGroups();
119 auto marginGroups = plot.axisRect()->marginGroups();
112 for (auto it = marginGroups.begin(), end = marginGroups.end(); it != end; ++it) {
120 for (auto it = marginGroups.begin(), end = marginGroups.end(); it != end; ++it) {
113 colorScale.setMarginGroup(it.key(), it.value());
121 colorScale.setMarginGroup(it.key(), it.value());
114 }
122 }
115
123
116 // Set color scale properties
124 // Set color scale properties
117 colorScale.setLabel(valuesUnit.m_Name);
125 setAxisProperties(*colorScale.axis(), valuesUnit, QCPAxis::stLogarithmic);
118 colorScale.setDataScaleType(QCPAxis::stLogarithmic); // Logarithmic scale
119 }
126 }
120 };
127 };
121
128
122 /**
129 /**
123 * 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
124 * @tparam T the data series' type
131 * @tparam T the data series' type
125 */
132 */
126 template <typename T>
133 template <typename T>
127 struct AxisHelper : public IAxisHelper {
134 struct AxisHelper : public IAxisHelper {
128 explicit AxisHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
135 explicit AxisHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
129
136
130 void setProperties(QCustomPlot &plot, QCPColorScale &colorScale) override
137 void setProperties(QCustomPlot &plot, QCPColorScale &colorScale) override
131 {
138 {
132 AxisSetter<T>::setProperties(m_DataSeries, plot, colorScale);
139 AxisSetter<T>::setProperties(m_DataSeries, plot, colorScale);
133 }
140 }
134
141
135 T &m_DataSeries;
142 T &m_DataSeries;
136 };
143 };
137
144
138 } // namespace
145 } // namespace
139
146
140 QString formatValue(double value, const QCPAxis &axis)
147 QString formatValue(double value, const QCPAxis &axis)
141 {
148 {
142 // 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
143 if (auto axisTicker = qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker())) {
150 if (auto axisTicker = qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker())) {
144 return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT);
151 return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT);
145 }
152 }
146 else {
153 else {
147 return QString::number(value);
154 return QString::number(value);
148 }
155 }
149 }
156 }
150
157
151 std::unique_ptr<IAxisHelper>
158 std::unique_ptr<IAxisHelper>
152 IAxisHelperFactory::create(std::shared_ptr<IDataSeries> dataSeries) noexcept
159 IAxisHelperFactory::create(std::shared_ptr<IDataSeries> dataSeries) noexcept
153 {
160 {
154 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
161 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
155 return std::make_unique<AxisHelper<ScalarSeries> >(*scalarSeries);
162 return std::make_unique<AxisHelper<ScalarSeries> >(*scalarSeries);
156 }
163 }
157 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
164 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
158 return std::make_unique<AxisHelper<SpectrogramSeries> >(*spectrogramSeries);
165 return std::make_unique<AxisHelper<SpectrogramSeries> >(*spectrogramSeries);
159 }
166 }
160 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
167 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
161 return std::make_unique<AxisHelper<VectorSeries> >(*vectorSeries);
168 return std::make_unique<AxisHelper<VectorSeries> >(*vectorSeries);
162 }
169 }
163 else {
170 else {
164 return std::make_unique<AxisHelper<IDataSeries> >(*dataSeries);
171 return std::make_unique<AxisHelper<IDataSeries> >(*dataSeries);
165 }
172 }
166 }
173 }
General Comments 1
Under Review
author

Auto status change to "Under Review"

You need to be logged in to leave comments. Login now