Show several plots in a scrollable widget with PyQt and matplotlib
Asked Answered
C

1

2

Since I didn't get an answer for this question I tried solving it with PyQt. Apparently, it's not that easy, when QScrollArea is involved...

I wrote a small test that basically does what I'm looking for, but it's not showing the scroll area and the plots inside it as I expected:

from PyQt4 import QtCore, QtGui
import os,sys

#import matplotlib
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
from matplotlib.figure import Figure

qapp = QtGui.QApplication(sys.argv)
qwidget = QtGui.QWidget()
qwidget.setGeometry(QtCore.QRect(0, 0, 500, 500))
qlayout = QtGui.QHBoxLayout(qwidget)
qwidget.setLayout(qlayout)

qscroll = QtGui.QScrollArea(qwidget)
qscroll.setGeometry(QtCore.QRect(0, 0, 500, 500))
qscroll.setFrameStyle(QtGui.QFrame.NoFrame)
qlayout.addWidget(qscroll)

qscrollContents = QtGui.QWidget()
qscrollLayout = QtGui.QVBoxLayout(qscrollContents)
qscrollLayout.setGeometry(QtCore.QRect(0, 0, 1000, 1000))

qscroll.setWidget(qscrollContents)
qscroll.setWidgetResizable(True)

for i in xrange(5):
  qfigWidget = QtGui.QWidget(qscrollContents)
  fig = Figure((5.0, 4.0), dpi=100)
  canvas = FigureCanvas(fig)
  canvas.setParent(qfigWidget)
  toolbar = NavigationToolbar(canvas, qfigWidget)
  axes = fig.add_subplot(111)
  axes.plot([1,2,3,4])
  qscrollLayout.addWidget(qfigWidget)

qscrollContents.setLayout(qscrollLayout)

qwidget.show()
exit(qapp.exec_()) 

Can anyone explain why it's not working?

Contracted answered 2/9, 2012 at 9:45 Comment(0)
P
6

You are creating a QWidget for each plot. But you don't put your canvas or toolbar in it via a layout, so they can't communicate the size information with the QWidget. By default, a QWidget has no minimumSize and the widget/layout inside the QScrollArea can make them as small as it wants in order to fit the available space (which is the size of QScrollArea).

Adding plots via layout helps, but I find that the FigureCanvas widget also doesn't have any minimum size so it can shrink. For a quick fix, you can set a minimumSize. The loop part with these fixes should look like this:

for i in xrange(5):
  qfigWidget = QtGui.QWidget(qscrollContents)

  fig = Figure((5.0, 4.0), dpi=100)
  canvas = FigureCanvas(fig)
  canvas.setParent(qfigWidget)
  toolbar = NavigationToolbar(canvas, qfigWidget)
  axes = fig.add_subplot(111)
  axes.plot([1,2,3,4])

  # place plot components in a layout
  plotLayout = QtGui.QVBoxLayout()
  plotLayout.addWidget(canvas)
  plotLayout.addWidget(toolbar)
  qfigWidget.setLayout(plotLayout)

  # prevent the canvas to shrink beyond a point
  # original size looks like a good minimum size
  canvas.setMinimumSize(canvas.size())

  qscrollLayout.addWidget(qfigWidget)
Philcox answered 2/9, 2012 at 20:52 Comment(1)
Awesome! It's much better than the fix that I came up with.Contracted

© 2022 - 2024 — McMap. All rights reserved.