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