QCustomPlot Discussion and Comments

Problem with multiple y axes with different scale and a single x axisReturn to overview

Hi!

I want to create a plot similar to the top graph of example #18 (advanced axes demo). First I remove the two default y axes, because I don't need them. Then I add 3 new y axes, two on the left side, one on the right side. Finally I add 4 graphs, two of which use the first custom y axis and the other two graphs use the remaining two y axes. The data to be displayed by the graphs only has the time on the x axis in common, the y data are completely unrelated and have very different scaling. Whenever new data comes in the 4 graphs are updated and their axes are rescaled to display the most recent value with a +-10% range.

Now for my problems.

1. the plot correctly shows the vertical grid lines, but not a single horizontal grid line. Why?
2. the plot does not respect the different scales of the individual graphs but scales everything in respect to the last added axis.

I am really running out of ideas what is missing and wrong here. The "advanced axes demo" perfectly shows that something similar like I need is definitely possible, but I cannot find anything that my code is missing or doing wrong.

This is the code to create the axes and the graphs:

m_mtpAxis = axisRect->addAxis(QCPAxis::atRight);
m_mtpAxis->setBasePen(bluePen);
m_mtpAxis->setTickPen(bluePen);
m_mtpAxis->setSubTickPen(bluePen);
m_mtpAxis->setLabelColor(bluePen.color());
m_mtpAxis->setTickLabelColor(bluePen.color());
m_mtpAxis->setLabelFont(labelFont);
m_mtpAxis->setTickLabelFont(labelFont);
m_mtpAxis->setLabel("kg/h");
m_mtpAxis->setVisible(true);

m_weightAxis = axisRect->addAxis(QCPAxis::atLeft);
m_weightAxis->setBasePen(redPen);
m_weightAxis->setTickPen(redPen);
m_weightAxis->setSubTickPen(redPen);
m_weightAxis->setLabelColor(redPen.color());
m_weightAxis->setTickLabelColor(redPen.color());
m_weightAxis->setLabelFont(labelFont);
m_weightAxis->setTickLabelFont(labelFont);
m_weightAxis->setLabel("kg");
m_weightAxis->setVisible(true);

m_rpmAxis = axisRect->addAxis(QCPAxis::atLeft);
m_rpmAxis->setBasePen(greenPen);
m_rpmAxis->setTickPen(greenPen);
m_rpmAxis->setSubTickPen(greenPen);
m_rpmAxis->setLabelColor(greenPen.color());
m_rpmAxis->setTickLabelColor(greenPen.color());
m_rpmAxis->setLabelFont(labelFont);
m_rpmAxis->setTickLabelFont(labelFont);
m_rpmAxis->setLabel("rpm");
m_rpmAxis->setVisible(true);

foreach(QCPAxisRect *rect, plotter->axisRects())
{
	foreach(QCPAxis *axis, rect->axes())
	{
		axis->setLayer("axes");
		axis->grid()->setLayer("grid");
	}
}

// add two "mtp" graphs and one "weight" and one "rpm" graph
plotter->addGraph(plotter->xAxis, m_mtpAxis);
plotter->addGraph(plotter->xAxis, m_mtpAxis);
plotter->addGraph(plotter->xAxis, m_weightAxis);
plotter->addGraph(plotter->xAxis, m_rpmAxis);

This is the code which updates the graphs:

plotter->graph(0)->addData(measurementTime, setpointMTP);
plotter->graph(1)->addData(measurementTime, measuredMTP);
plotter->graph(2)->addData(measurementTime, measuredWeight);
plotter->graph(3)->addData(measurementTime, currentSetpointRPM);

// adapt the x axis range in case more than 180 seconds have passed
if(measurementTime >= GRAPH_TIME)
{
	plotter->xAxis->setRange(measurementTime-GRAPH_TIME, measurementTime+1.0);
}

// adapt the y axes in case the current values are outside the currently visible range
if(m_mtpAxis[component]->range().contains(measuredMTP) == false || m_mtpAxis[component]->range().contains(measuredMTP) == false)
{
	double minV = qMin(measuredMTP, setpointMTP);
	double maxV = qMax(measuredMTP, setpointMTP);
	m_mtpAxis[component]->setRange(minV*0.9, maxV*1.1);
}
if(m_weightAxis[component]->range().contains(measuredWeight) == false)
{
	m_mtpAxis[component]->setRange(measuredWeight*0.9, measuredWeight*1.1);
}
if(m_rpmAxis[component]->range().contains(currentSetpointRPM) == false)
{
	m_rpmAxis[component]->setRange(currentSetpointRPM*0.9, currentSetpointRPM*1.1);
}

plotter->replot();

I can't see were you set the grid of the new axes to visible, may that be problem 1? Like m_weightAxis->grid()->setVisible(true).

With problem 2 I'm not sure. You are trying to set the autoranging manually in the slot which updates the graph by calling setRange. Is the problem there? Do you know aboug graph->rescaleValueAxis and axis->rescale? doc will help.

Explicitly setting the grid visible did the trick. I think I checked the source of QCustomPlot and IIRC the grid was visible by default. It seems I was wrong.

Regarding the axis scaling, the rescale methods are not want I want, because they do a rescale to make all data visible. But I just want the most recent data to be visible.
This works perfectly for the first axis on the left side, but not for any further axes on the left side or any axis on the right side at all.

I'm not sure what you mean by the axis scale is only set with respect to the last added axis. Your code is also not clear, in the first method you assign a QCPAxis instance to m_mtpAxis and in the second case you then apply the [] operator to m_mtpAxis. So if component > 0 I'd expect your program to crash because you dereference starting past the QCPAxis memory block.

Maybe you can create a minimal example to demonstrate what you mean, e.g. with only two left y axes, then I'll be able to better point you into the right direction.

The [] operator was a typo due to changing the real code to the example code above.

Anyway, in the meantime I found the reason. As you can see in the 2nd example code I was checking whether the weight axis' range contains the current value or not, but then I set a new range for the mtp axis. This cannot work out as expected. Now everything is fine. All grid lines are visible and all graphs are correctly scaled as I expect it.

Thanks a lot for the help, even if it was just a stupid fault by me.

Excellent! Good to hear everything worked itself out.

I agree