Results 1 to 3 of 3

Thread: Odd behavior when changing scale engines

  1. #1
    Join Date
    Oct 2019
    Qt products

    Default 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):
    Qt Code:
    1. QwtPlotClient::QwtPlotClient(QWidget *parent)
    2. : QDialog(parent),
    3. m_plot(new QwtPlot)
    4. {
    5. m_ui.setupUi(this);
    6. m_ui.plotFrame->layout()->addWidget(m_plot);
    7. m_plot->axisScaleEngine(QwtPlot::yLeft)->setAttribute(QwtScaleEngine::Floating, true);
    9. auto points = QVector<QPointF>() << QPointF(0, 1) << QPointF(1, 3) << QPointF(2, 7) << QPointF(3, 12) << QPointF(4, 18);
    10. auto curve1 = new QwtPlotCurve("Curve 1");
    11. curve1->setSamples(points);
    12. curve1->setSymbol(new QwtSymbol(QwtSymbol::Ellipse, QBrush(Qt::red), QPen(Qt::darkRed), QSize(8, 8)));
    13. curve1->setPen(QPen(Qt::red));
    14. curve1->setCurveAttribute(QwtPlotCurve::Fitted, true);
    15. curve1->attach(m_plot);
    17. connect(m_ui.initButton, &QPushButton::clicked, this, [this]()
    18. {
    19. // Step 1: linear scale engine, auto scale off, range to [1;100]
    20. m_plot->setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine());
    21. m_plot->setAxisAutoScale(QwtPlot::yLeft, false);
    22. m_plot->setAxisScale(QwtPlot::yLeft, 1, 100);
    23. m_plot->replot();
    24. });
    25. connect(m_ui.autoScaleOnButton, &QPushButton::clicked, this, [this]()
    26. {
    27. // Step 2: auto scale on
    28. m_plot->setAxisAutoScale(QwtPlot::yLeft, true);
    29. m_plot->replot();
    30. });
    31. connect(m_ui.autoScaleOffButton, &QPushButton::clicked, this, [this]()
    32. {
    33. // Step 3: auto scale off
    34. m_plot->setAxisAutoScale(QwtPlot::yLeft, false);
    35. m_plot->replot();
    36. });
    37. connect(m_ui.logButton, &QPushButton::clicked, this, [this]()
    38. {
    39. // Step 4: apply log scale engine
    40. m_plot->setAxisScaleEngine(QwtPlot::yLeft, new QwtLogScaleEngine());
    41. m_plot->replot();
    42. });
    43. }
    To copy to clipboard, switch view to plain text mode 

    Ah, I forgot: Qt 5.14.0 and Qwt 6.2.0 and also Qwt 6.2.1
    Last edited by mwh; 15th November 2023 at 13:28.

  2. #2
    Join Date
    Feb 2006
    Munich, Germany
    Thanked 879 Times in 827 Posts
    Qt products
    Qt3 Qt4 Qt/Embedded
    MacOS X Unix/X11 Windows

    Default 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:

    Qt Code:
    1. const auto scaleDiv = plot->axisScaleDiv( axisId );
    2. plot->setAxisScale( axisId, scaleDiv.lowerBound(), scaleDiv.upperBound() );
    To copy to clipboard, switch view to plain text mode 
    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.


  3. #3
    Join Date
    Oct 2019
    Qt products

    Default 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).

Similar Threads

  1. Replies: 2
    Last Post: 21st July 2013, 20:35
  2. Replies: 4
    Last Post: 26th September 2011, 22:55
  3. Problem with events changing behavior of QListWidget
    By riklaunim in forum Qt Programming
    Replies: 10
    Last Post: 22nd December 2008, 19:10
  4. Changing mouse grabbing behavior?
    By FlyingSaucrDude in forum Qt Programming
    Replies: 0
    Last Post: 11th November 2008, 01:04
  5. Changing Scrollbar behavior
    By croftj in forum Qt Programming
    Replies: 2
    Last Post: 25th May 2008, 12:05


Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.