QCustomPlot Discussion and Comments

Maximum and minimum zoom rangesReturn to overview

Hello there,
What I am trying to do is to limit further zoom out of the plot. I have found the event->delta() adding trick. The problem is that after i reach a certain number (for example -1000) i cannot zoom in anymore because the zooming is blocked. I cannot zoom out but also cant zoom in back. I was wondering either theres an event more specific than MouseWheel (ie. MouseWheelIn, MouseWheelOut)? Or maybe there is another way of acomplishing this.

The second thing I was wondering is either it is possible to create a zooming locks separate for each axis- for example, if i reach the zoom out limit of axis Y, then the zooming would continue only on axis X.

I Would really aprichiate any help in here, i really enjoy QCustomPlot.

Use the QCPAxis::rangeChanged signal, of the axis you wish to limit.

You may manipulate/correct the range with setRange in a slot connected to this signal. This is useful if for example a maximum range span shall not be exceeded, or if the lower/upper range shouldn't go beyond certain values. For example, the following slot would limit the x axis to only positive ranges:

if (newRange.lower < 0)
  plot->xAxis->setRange(0, newRange.size());

In your case you simply limit both boundaries of the range like this. It will be best if you only perform one setRange call with a completely fixed range, so create a temporary QCPRange fixedRange, initialize it with the given newRange, manipulate the bounds, and then pass it to a setRange call.

Could you only explain me how did you get newRange object?

The rangeChanged signal of QCPAxis provides it as parameter to you:
http://www.qcustomplot.com/documentation/classQCPAxis.html#a0894084e4c16a1736534c4095746f910

This thread will also be of interest to you:
http://www.qcustomplot.com/index.php/support/forum/486

Exacly what I needed, the code works now thank you!

I'm in the process of implementing convenience functions for QCPRange that make their bounding for such cases very easy. And while doing that I noticed (once again) that writing code that limits the ranges is slightly more tricky than it seems at first glance, if you want to do it right. So I thought I'd just post it here in case other people (or you) are interested.

The following code can be placed in a slot connected to QCPAxis::rangeChanged, and will limit the axis range to lowerBound and upperBound.

  double lowerBound = 0;
  double upperBound = 10; // note: code assumes lowerBound < upperBound
  QCPRange fixedRange(newRange);
  if (fixedRange.lower < lowerBound)
  {
    fixedRange.lower = lowerBound;
    fixedRange.upper = lowerBound + newRange.size();
    if (fixedRange.upper > upperBound || qFuzzyCompare(newRange.size(), upperBound-lowerBound))
      fixedRange.upper = upperBound;
    mCustomPlot->xAxis->setRange(fixedRange); // adapt this line to use your plot/axis
  } else if (fixedRange.upper > upperBound)
  {
    fixedRange.upper = upperBound;
    fixedRange.lower = upperBound - newRange.size();
    if (fixedRange.lower < lowerBound || qFuzzyCompare(newRange.size(), upperBound-lowerBound))
      fixedRange.lower = lowerBound;
    mCustomPlot->xAxis->setRange(fixedRange); // adapt this line to use your plot/axis
  }

How do I know the plot pointer?
I have a number of plots > 1 all dynamically created.
Thus I can not write a connect code and a function for each plot. I need this to work automatically.

I solved this using the Qt property function and included your code.
Why is such functionality not within the QCP code itsself?

void MainWindow::setupPlot(QCustomPlot *plot, QString title)
{
...
    connect(plot->xAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(xAxisChanged(QCPRange)));
    connect(plot->yAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(yAxisChanged(QCPRange)));
}

void MainWindow::updatePlotData(QCustomPlot *plot, vector<double> & y0, vector<double> & y1 )
{
...
    plot->replot();
    plot->setProperty("xmin", plot->xAxis->range().minRange());
    plot->setProperty("xmax", plot->xAxis->range().maxRange());
    plot->setProperty("ymin", plot->yAxis->range().lower);
    plot->setProperty("ymax", plot->yAxis->range().upper);
}

void MainWindow::xAxisChanged(const QCPRange & newRange)
{
    QCPAxis * axis = qobject_cast<QCPAxis *>(QObject::sender());
    QCustomPlot * plot = axis->parentPlot();

    QCPRange limitRange(plot->property("xmin").toDouble(), plot->property("xmax").toDouble());
    limitAxisRange(axis, newRange, limitRange);
}

void MainWindow::yAxisChanged(const QCPRange & newRange)
{
    QCPAxis * axis = qobject_cast<QCPAxis *>(QObject::sender());
    QCustomPlot * plot = axis->parentPlot();

    QCPRange limitRange(plot->property("ymin").toDouble(), plot->property("ymax").toDouble());
    limitAxisRange(axis, newRange, limitRange);
}


void MainWindow::limitAxisRange(QCPAxis * axis, const QCPRange & newRange, const QCPRange & limitRange)
{
    auto lowerBound = limitRange.lower;
    auto upperBound = limitRange.upper;

    // code assumes upperBound > lowerBound
    QCPRange fixedRange(newRange);
    if (fixedRange.lower < lowerBound)
    {
        fixedRange.lower = lowerBound;
        fixedRange.upper = lowerBound + newRange.size();
        if (fixedRange.upper > upperBound || qFuzzyCompare(newRange.size(), upperBound-lowerBound))
            fixedRange.upper = upperBound;
        axis->setRange(fixedRange); // adapt this line to use your plot/axis
    } else if (fixedRange.upper > upperBound)
    {
        fixedRange.upper = upperBound;
        fixedRange.lower = upperBound - newRange.size();
        if (fixedRange.lower < lowerBound || qFuzzyCompare(newRange.size(), upperBound-lowerBound))
            fixedRange.lower = lowerBound;
        axis->setRange(fixedRange); // adapt this line to use your plot/axis
    }
}

Code like this is blinking

if (fixedRange.lower < lowerBound)
    {
        fixedRange.lower = lowerBound;
        axis->setRange(fixedRange);