Re: Odd behavior when changing scale engines
The following steps are required to reproduce this behavior (I will add code at the end). The following is meant for the yLeft axis as an example. Also, the floating attribute for the axis is set to true.
1. Set a linear scale engine, set auto scale mode for the axis off and set the range to [1;y2], e.g. y2 = 100
2. Set auto scale mode on (this sets the range to the min and max of the sample points, in my example below to [1;18])
3. Set auto scale mode off again (this does not change the scale (which is correct!), it is still at [1;18])
4. Apply a log scale engine
The expected result is that the log scale on the axis still has the range of [1;18]. However, after applying the log scale the range is set to the range from step 1 (y2 = 100).
If you change y2 in step 1 to a different number, step 4 will set the range to that number instead.
Here is the sample code (the ui file contains the qwt plot and 4 buttons, one for each of the steps):
Code:
QwtPlotClient
::QwtPlotClient(QWidget *parent
){
m_ui.setupUi(this);
m_ui.plotFrame->layout()->addWidget(m_plot);
curve1->setSamples(points);
curve1
->setPen
(QPen(Qt
::red));
curve1->attach(m_plot);
connect(m_ui.initButton, &QPushButton::clicked, this, [this]()
{
// Step 1: linear scale engine, auto scale off, range to [1;100]
m_plot
->setAxisAutoScale
(QwtPlot::yLeft,
false);
m_plot
->setAxisScale
(QwtPlot::yLeft,
1,
100);
m_plot->replot();
});
connect(m_ui.autoScaleOnButton, &QPushButton::clicked, this, [this]()
{
// Step 2: auto scale on
m_plot
->setAxisAutoScale
(QwtPlot::yLeft,
true);
m_plot->replot();
});
connect(m_ui.autoScaleOffButton, &QPushButton::clicked, this, [this]()
{
// Step 3: auto scale off
m_plot
->setAxisAutoScale
(QwtPlot::yLeft,
false);
m_plot->replot();
});
connect(m_ui.logButton, &QPushButton::clicked, this, [this]()
{
// Step 4: apply log scale engine
m_plot
->setAxisScaleEngine
(QwtPlot::yLeft,
new QwtLogScaleEngine
());
m_plot->replot();
});
}
Ah, I forgot: Qt 5.14.0 and Qwt 6.2.0 and also Qwt 6.2.1
Re: Odd behavior when changing scale engines
Boundaries and ticks of an axis are defined by a QwtScaleDiv, that can be set in 3 ways:
- setting boundaries and ticks ( = QwtPlot::setAxisScaleDiv( ... ) )
- setting boundaries, calculating ticks ( = QwtPlot::setAxisScale( min, max ) )
- calculating boundaries and ticks from the content ( = QwtPlot::setAxisAutoScale( true ) )
The question now is how to update boundaries/ticks after the autoscaler had been disabled. The current implementation falls back to the boundaries that had been set by setAxisScale before. Your expectation would be, that the autoscaler modifies these boundaries with the calculated ones. IMO both valid strategies.
What makes the situation confusing: disabling the autoscaler does not invalidate boundaries and ticks. So the update is postponed to the next operation that changes a parameter that affects the calulation of the ticks from the boundaries. In your example it is changing the scale engine, but it also happens with setAxisMaxMinor/setAxisMaxMajor.
So what to do:
IMO disabling the autoscaler should have an immediate effect on the scales. However this might break many applications, that rely on having no changes here. To avoid this incompatibility the boundaries have to be adjusted like in what I described as "your expectation". Unfortunately this introduces incompatibilities for applications that have an update sequence like in your code.
Another way to disable the autoscaler with the existing implementation would be:
Code:
const auto scaleDiv = plot->axisScaleDiv( axisId );
plot->setAxisScale( axisId, scaleDiv.lowerBound(), scaleDiv.upperBound() );
However this would be no solution for your example. The linear autoscaler sets the lower boundary to 0, what is not defined for a logarithmic scale. So in the end workaround or suggested fix are not very useful, when changing the engine. Not 100% sure if it is worth introducing incompatibilities then.
Uwe
Re: Odd behavior when changing scale engines
I understand that this is not an easy case since there may be very different opinions on what the correct behaviour should be. As an example, I do not agree that disabling the autoscaler should have an immediate effect on the current scale, at least not on the min-max values. I regard auto scaling as a state for the min-max of the axis: if enabled, changing the sample points should change the min-max (depending on the change of points of course); if disabled, changing the points should have no effect on min-max at all.
Maybe someone will come up with a good solution for the problem.
For now, we found a workaround in our code that works. Transferred to the example code above, we save the current min-max of the axis before changing the scale engine and call setAxisScale with these values afterwards (with regard to negative or zero min-max values of course).