QCustomPlot Discussion and Comments

wrong measured axisrect heightsReturn to overview

I use QCustomPlot inside a QMdiSubWindow. I want to set tick count for each QAxisRect basing on AxisRect current heigh. I've overriden QMdiSubWindow::resizeEvent() function for catching resize event and change accordingly axisrect(s) tick count.
More precisely, I have derived QMdiSubWindow, so I have:

void MyWindow::resizeEvent(QResizeEvent * resizeEvent)
    QList<QCPAxisRect*> rectList = mPlot->axisRects();
    for ( int index = 0; index < rectList.size(); index ++)
        QCPAxisRect* axisRect = rectList.at(index);
        for (int i = 0; i < axisRect->axisCount(QCPAxis::AxisType::atLeft); i++)
            QCPAxis * leftAxis = axisRect->axis(QCPAxis::AxisType::atLeft, i);
            int height = axisRect->rect().height();
            int tickCount = height / 20 > 0 ? height / 20 : 1;
            qDebug() << __FUNCTION__ << " strip " << index << " height " << axisRect->rect().height() << " tick count " << tickCount;

    qDebug() << __FUNCTION__ << " rect " << this->rect();

As far as I resize manually the subwindow, axisrects report consistent heights but on subwindow creation and when I maximize or reset size, heights are wrong:
when I create window and call inside the constructor a resize(800, 600) I get too small heights.
When I maximize the axisrects heights remain the same as before maximizing - thou my subwindow size report a correct size - and when I reset size - get back from "maximized state" - heights are those they should have been in maximized state. If I go on resizing manually my subwindow everything seems returned to a correct state.

Is it a library bug or my mistake?

I've reproduced the situation and it seems it's a bug in Qt of how it handles and forwards QWidget::resizeEvent, or at least a surprising inconsistency .

QCustomPlot reimplements resizeEvent itself, in order to modify its viewport/axis rects etc. and then issue a replot. When reimplementing a QMdiSubWindow::resizeEvent as you correctly did, the base class call to QMdiSubWindow::resizeEvent() in the first line of MyWindow::resizeEvent should internally cause QCustomPlot::resizeEvent to eventually be called. This works as expected when regularly resizing the window with the mouse: We first register a call to QCustomPlot::resizeEvent, and then the rest of the code of MyWindow::resizeEvent gets executed.

However, in case the window is maximized or restored, the whole behavior is different, which from my understanding can be considered a bug in Qt. Because in that case, the order is somehow reversed: First, the code of MyWindow::resizeEvent is called, and only after that QCustomPlot::resizeEvent somehow receives a deferred call. This is why your code in MyWindow::resizeEvent still sees old axis rect geometry.

The solution is simple, and overall better anyhow: Don't reimplement QMdiSubWindow::resizeEvent, but rather directly QCustomPlot::resizeEvent. So create a QCustomPlot subclass, e.g. PlotWidget, and reimplement its resizeEvent like so:

void PlotWidget::resizeEvent(QResizeEvent *resizeEvent)
  foreach (QCPAxisRect *axisRect, axisRects())
    foreach (QCPAxis *axis, axisRect->axes(QCPAxis::atLeft))
      axis->ticker()->setTickCount(qMax(axisRect->height()/20, 1));

(I've taken the liberty to make your code a little more compact, it still does the same thing though)

Note that there's a slight inefficiency because replot is called once in the base class resizeEvent at the beginning (necessary to give the axis rect its new geometry), and once again at the end of the reimplementation (to make the change of the tick count visible). But other than that it works as expected.

I've added a feature request to my todo list for the next minor release which will make size-dependent axis tick counts built-in. You'll then be able to just enable it with a QCPAxis or QCPAxisRect interface.

Thank you! I'll follow your advise.
I think that feature would be great but it should depend on some parameter value library user could assign.

Yeah, absolutely. I'm thinking about three modes:
1. fixed tick count target like now
2. A mode which tries to keep a specified pixel distance between ticks
3. A mode which tries to keep a given percentage of the font size/tick label size between the ticks

Let me suggest you another mod we had to apply in our project:
in that subwindow we arrange a column of axis rects which may have or not space between them depending on user's preference.
the problem when user wants no space inbetween is that bottom tick label of one axis rext partially overlaps with top tick label of underneath axis rect. we had to place the first and the last labels of left axis a little shifted toward the center.
If I'm not clear and you are interested I'll post an image.

Yeah please post an image and the code that leads to it. Because if you leave the margins of the axis rect set to automatic (default), there shouldn't be an issue between top/bottom labels of stacked axis rects. Only if you set to manual margins you'll be responsible to make sure labels fit yourself. If you want minimum space but still proper label margin, you should only set the QCPAxis::setPadding and QCPAxisRect::setMinimumMargins to zero. (See this image in the QCPAxisRect documentation for explanation of the padding/margin etc.)

As I can read both functions works with horizontal space. I need something which prevents labels from overlapping vertically one another, the bottom of the upper axisrect and the top of the lower one.
I don't want a "proper space" in between axis rects because I need them to simulate a whole bigger chart so I need labels to be shifted.
I had another problem: if my signal to represent ranges from 0 to 100 and I set that precise range to left axis, at 0 my graph is overlapped by bottom axis pixels so it seems cut .
I partially solved this problem by setting a 10% wider range to each left axis.

QCPMarginGroup *marginGroup = new QCPMarginGroup(mPlot);
GraphStrip *axisRect = createMultiCurveStrip( ...);

axisRect->setMarginGroup(QCP::msAll, marginGroup);

in createMultiCurveStripe there is some code I can't show but basically I set

before setting msAll in setMarginGroup and setAutoMargin I used only left and right margins but the problem happens with msAll as well.

How can I upload an image?