QCustomPlot Discussion and Comments

Hide QCPPlottableLegendItems when plottable is not visibleReturn to overview

I have a chart that has multiple graphs on it that can be filtered with user input. When the user chooses to hide the graph, the graph legend item remains in the legend. I would like this to be hidden when the graph is not visible and shown when the graph is. I want this behavior because I want to be able to set up the legend once, and I want the order of the legend to remain the same when items are hidden and shown again.

I was hoping for some behavior like QCustomPlot::rescaleAxis where I could tell the legend not to draw invisible items. I did not find that.

I was able to implement the functionality that I want by changing QCPPlottableLegendItem::minimumSizeHint to look at the visibility of the plottable that it contains.

QSize QCPPlottableLegendItem::minimumSizeHint() const
{
  if (!mPlottable) return QSize();
  if (mPlottable->layer() && !mPlottable->layer()->visible()) return QSize(); // New code
  if (!mPlottable->visible()) return QSize(); // New code
  QSize result(0, 0);
  QRect textRect;
  QFontMetrics fontMetrics(getFont());
  QSize iconSize = mParentLegend->iconSize();
  textRect = fontMetrics.boundingRect(0, 0, 0, iconSize.height(), Qt::TextDontClip, mPlottable->name());
  result.setWidth(iconSize.width() + mParentLegend->iconTextPadding() + textRect.width() + mMargins.left() + mMargins.right());
  result.setHeight(qMax(textRect.height(), iconSize.height()) + mMargins.top() + mMargins.bottom());
  return result;
}

I had to check the visibility of the layer as well as the plottable because the plottable shows as visible even if it's layer is not. I was hoping to override the visible method to add this behavior to the plottable, but visible is not a virtual method.

Is this functionality that could be incorporated back into the code branch?

I am using layers to show/hide groups of graphs because I need the Z ordering and it is really easy partition the graphs when the chart is created and then not worry about what is in each partition. Great functionality.

Have a look at realVisibility. It returns the true visibility taking into account all possibilites why the layerable can be invisible.

Regarding the legend, I'm indeed also not very satisifed with the way it currently works. So expect this to go a bit smoother in a future version. Your fix is feasible, but I'm worried about the legend item spacing (QCPLegend is a QCPLayoutGrid after all, and it thus has a row spacing in between each item). Say you have a row spacing of 5 pixels and 10 invisible items in the legend, you'll end up with a 50 pixel wide gap in the legend. If it's indeed like this, I suggest setting the row spacing to zero and handling the spacing by setting according margins to the individual legend items (or just reporting a larger vertical minimal size than actually used by the drawing routines).

realVisibility works great. Thanks for pointing that out. I am not seeing a problem with the legend item spacing because I have set all of the margins to zero. It does look like the correct solution is more complicated than I suggested. I was looking for somewhere to just ignore the row in the QCPLayoutGrid when the item is not visible, but it does not look like it is quite that easy. Given the issue with the margins, I will probably go back to my work around which is recreating the legend whenever something is hidden/show, but using the realVisibilty method.

	m_pUi->customPlot->legend->clearItems(); 
	const int iPlottableCount = m_pUi->customPlot->plottableCount();
	for (int iPlottable = 0; iPlottable < iPlottableCount; ++iPlottable)
	{
		if (QCPAbstractPlottable* pPlottable = m_pUi->customPlot->plottable(iPlottable))
		{
			const bool bVisible = pPlottable->realVisibility();
			if (bVisible)
				pPlottable->addToLegend();
		}
	}