I have a PyQt window that needs to have both a plot and navigation toolbar. However, I can't seem to get the two objects to mesh together; i.e., with the toolbar on top of the plot, expanding the same horizontal length, scaling appropriately, and not overlapping. Below is my minimum, working example. thank you so much for taking a look!
import sys, os
from pyface.qt import QtGui, QtCore
os.environ['ETS_TOOLKIT'] = 'qt4'
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import random
class App(QtGui.QMainWindow):
def __init__(self):
super(App, self).__init__()
self.left = 10
self.top = 10
self.title = 'Minimum, working example'
self.width = 640
self.height = 400
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
m = PlotCanvas(self, width=5, height=4)
m.move(0,0)
self.show()
class PlotCanvas(FigureCanvas):
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
FigureCanvas.__init__(self, fig)
self.setParent(parent)
FigureCanvas.updateGeometry(self)
##########################
#trouble seems to be here:
fig.set_tight_layout(True)
self.canvas = FigureCanvas(fig)
self.toolbar = NavigationToolbar(self.canvas, self)
##########################
self.plot()
def plot(self):
data = [random.random() for i in range(25)]
ax = self.figure.add_subplot(111)
ax.plot(data, 'r-')
ax.set_title("Is this getting overlapped by the toolbar?")
self.draw()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
When you use self.canvas = FigureCanvas (fig)
you are creating another FigureCanvas
, why create another ?, it is not necessary.
Why are they overlapping?
The position of a child widget is relative to the parent, in this case it is self.toolbar is the children of self.canvas so the self.toolbar will be within the self.canvas.
In order to handle the position and size of the widgets, Qt offers the layouts, and in this case it is necessary. On the other hand, there is no need for the toolbar to be inside the PlotCanvas class. And finally when using QMainWindow you should not place the widgets directly since it has a custom layout so you must create a centralwidget.
import sys, os
from pyface.qt import QtGui, QtCore
os.environ['ETS_TOOLKIT'] = 'qt4'
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import random
class App(QtGui.QMainWindow):
def __init__(self):
super(App, self).__init__()
self.left = 10
self.top = 10
self.title = 'Minimum, working example'
self.width = 640
self.height = 400
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
centralwidget = QtGui.QWidget()
self.setCentralWidget(centralwidget)
m = PlotCanvas(self, width=5, height=4)
toolbar = NavigationToolbar(m, self)
vbl = QtGui.QVBoxLayout(centralwidget)
vbl.addWidget(toolbar)
vbl.addWidget(m)
self.show()
class PlotCanvas(FigureCanvas):
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
FigureCanvas.__init__(self, fig)
self.setParent(parent)
self.updateGeometry()
fig.set_tight_layout(True)
self.plot()
def plot(self):
data = [random.random() for i in range(25)]
ax = self.figure.add_subplot(111)
ax.plot(data, 'r-')
ax.set_title("Is this getting overlapped by the toolbar?")
self.draw()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())