Hello im trying to add a custom graph to the pyqt interface I have. Its not showing any data, but the placeholder matplotlib graph is showing. Any help?! Also If i plot just the graph data without putting it into PYQT, it shows up. Thanks!
class MyMplCanvas(FigureCanvas):
"""Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.)."""
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
#self.axes = fig.add_subplot(111)
# We want the axes cleared every time plot() is called
self.axes.hold(False)
self.compute_initial_figure()
FigureCanvas.__init__(self, fig)
self.setParent(parent)
FigureCanvas.setSizePolicy(self,
QtGui.QSizePolicy.Expanding,
QtGui.QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
def compute_initial_figure(self):
pass
class MyStaticMplCanvas(MyMplCanvas):
def mystatic(self, parent=None):
super(MyStaticMplCanvas, self).__init__(parent)
rate,data = read('test.wav') # reading
subplot(411)
self.plot(range(len(data)),data)
subplot(412)
self.specgram(data, NFFT=128, noverlap=0) # small window
subplot(413)
self.specgram(data, NFFT=512, noverlap=0)
subplot(414)
self.specgram(data, NFFT=1024, noverlap=0) # big window
self.show()
class ApplicationWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
l = QtGui.QVBoxLayout(self.main_widget)
sc = MyStaticMplCanvas(self.main_widget, width=5, height=4, dpi=100)
l.addWidget(sc)
In the code sample you provided, there is no call to the mystatic method that you use to plot your data. Therefore, nothing is plotted on your figure.
Moreover, It seems you are using the pyplot interface for plotting your data by calling directly subplot and plot for example in mystatic. When embedding a mpl figure in an application, it is recommended from the mpl documentation to stick to the object oriented API.
I've produced a minimal working example from the code you've provided that follows the guidelines provided in the aforementioned documentation. Hope it helps.
from PyQt4 import QtGui
import sys
import numpy as np
import matplotlib as mpl
mpl.use('Qt4Agg')
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
class MyMplCanvas(FigureCanvas):
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = mpl.figure.Figure(figsize=(width, height), dpi=dpi)
fig.set_tight_layout('tight')
super(MyMplCanvas, self).__init__(fig)
class MyStaticMplCanvas(MyMplCanvas):
def mystatic(self, parent=None):
x, y = np.random.rand(50), np.random.rand(50)
ax1 = self.figure.add_subplot(411)
ax1.plot(x,y, '.')
ax2 = self.figure.add_subplot(412)
ax2.plot(x,y, '.')
ax3 = self.figure.add_subplot(413)
ax3.plot(x,y, '.')
ax4 = self.figure.add_subplot(414)
ax4.plot(x,y, '.')
if __name__ == '__main__' :
app = QtGui.QApplication(sys.argv)
w = MyStaticMplCanvas(width=5, height=6, dpi=100)
w.mystatic()
w.show()
sys.exit(app.exec_())
which results in:
Related
I have embedded a matplotlib figure inside a plot canvas. The idea is to be able to change the figure and axes properties. But, I couldn't modify the axis after initializing. Below is a simple example:
import sys
import matplotlib
matplotlib.use('Qt5Agg')
from PyQt5 import QtCore, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.figure import Figure
class MplCanvas(FigureCanvasQTAgg):
def __init__(self, parent=None, width=5, height=4, dpi=100):
self.fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = self.fig.add_subplot(111)
super(MplCanvas, self).__init__(self.fig)
class MainWindow(QtWidgets.QWidget):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.layout = QtWidgets.QVBoxLayout(self)
self.sc = MplCanvas(self, width=5, height=4, dpi=100)
self.sc.axes.plot([0,1,2,3,4], [10,1,20,3,40])
self.layout.addWidget(self.sc)
button = QtWidgets.QPushButton('change figure properties')
button.clicked.connect(self.changeProp)
self.layout.addWidget(button)
self.show()
def changeProp(self):
# here is to change prop, e.g., tickslabel, size, color, colorbar, legend, position, ...etc
"I have tried the following to change the ticks, but doesn't work"
self.sc.fig.axes[0].set_xticklabels(self.sc.fig.axes[0].get_xticklabels(), fontsize=10, color='blue', rotation=90)
"I have also tried this, but not working"
self.sc.fig.axes[0].xaxis.set_tick_params(fontsize=10, color='blue', rotation=90)
"""
UserWarning: FixedFormatter should only be used together with FixedLocator
self.sc.axes.set_xticklabels(self.sc.axes.get_xticklabels(), fontsize=10, color='blue', rotation=90)
"""
"What is the best API to solve this "
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
app.exec_()
Apparently the 'font size' parameter in set_tick_params no, i removed it.
[tick_params][1]
Also did a redraw after the update. But, I failed to remove the warning
''User Warning: FixedFormatter should only be used together with Fixed Locator'.
def changeProp(self):
self.sc.fig.axes[0].set_xticklabels(self.sc.fig.axes[0].get_xticklabels(), fontsize=10, color='red',
rotation=90)
self.sc.fig.axes[0].xaxis.set_tick_params(color='green', width= 5, rotation=45)
self.sc.draw()
I am pretty new to PyQt5. I would like to have a button that, when clicked, generates and shows a plot. I cannot seem to find a way to use the QPushButton to call the PlotCanvas function successfully.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5 import QtWidgets, Qt
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import random
import numpy as np
import math
class GUI_Window(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.plot_button = QtWidgets.QPushButton(self)
self.plot_button.setText('Plot')
self.plot_button.setToolTip('Plots the function')
self.plot_button.move(50,240)
self.plot_button.clicked.connect(self.updater)
def updater(self):
PlotCanvas(self, inputparam=5)
print('Function has been called.')
The code above does not work (PlotCanvas doesn't plot) even though I receive the 'function has been called' printout.
However if I simply call PlotCanvas in initUI, it plots it as expected.
def initUI(self):
self.plot_button = QtWidgets.QPushButton(self)
self.plot_button.setText('Plot')
self.plot_button.setToolTip('Plots the function')
self.plot_button.move(50,240)
self.plot_button.clicked.connect(self.updater)
PlotCanvas(self, inputparam=5)
The above code plots the function as expected.
Furthermore, if I simply call the updater function without the pushbutton (shown below), the plot is shown.
def initUI(self):
self.plot_button = QtWidgets.QPushButton(self)
self.plot_button.setText('Plot')
self.plot_button.setToolTip('Plots the function')
self.plot_button.move(50,240)
#self.plot_button.clicked.connect(self.updater)
self.updater()
def updater(self):
PlotCanvas(self, inputparam=5)
print('Function has been called.')
I sense I do not know how 'self' works and by passing a clicked signal I am somehow messing things up. Any help/insight would be appreciated.
class PlotCanvas(FigureCanvas):
def __init__(self, parent=None, width=1.5, height=2, dpi=100, inputparam=0):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
FigureCanvas.__init__(self, fig)
self.setParent(parent)
self.LLA_Plotter(inputparam)
# This function performs calculations and outputs x,y data points to plot
ax = self.figure.add_subplot(111)
for i in range(0,90):
ax.scatter(x[i], y[i], color='b', s=0.6)
ax.set_title('testing plot')
plt.show()
I am attempting to write a simple application which reads KML files and plots the data onto a Matplotlib/Basemap - sort of "poor's man Google Earth" which can be used offline for a quick view of the distribution of data over geographic space.
Currently, my problem is in embedding the Basemap into the user interface. The code below creates the application but instead of displaying the map, it only displays a pair of axes.
import warnings
import sys
import numpy as np
from PyQt4 import QtCore, QtGui
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from mpl_toolkits.basemap import Basemap
warnings.filterwarnings("ignore")
class MyMplCanvas(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.setSizePolicy(self,
QtGui.QSizePolicy.Expanding,
QtGui.QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
m = Basemap()
m.drawcoastlines(color='#777799')
m.drawcountries(color='#ccccee')
m.drawmapboundary()
m.bluemarble()
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent = None):
QtGui.QMainWindow.__init__(self)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.fileMenu = QtGui.QMenu("&File", self)
self.fileMenu.addAction("Open...", self.fileOpen,
QtCore.Qt.CTRL + QtCore.Qt.Key_O)
self.fileMenu.addSeparator()
self.fileMenu.addAction("&Quit", self.fileQuit,
QtCore.Qt.CTRL + QtCore.Qt.Key_Q)
self.menuBar().addMenu(self.fileMenu)
self.statusBar().setSizeGripEnabled(True)
self.statusBar().showMessage("Ready")
self.items = QtGui.QDockWidget("Layers", self)
self.items.setFloating(False)
self.items.setFeatures(self.items.NoDockWidgetFeatures)
self.listWidget = QtGui.QListWidget()
self.listWidget.addItem("file1")
self.listWidget.addItem("file2")
self.listWidget.addItem("file3")
self.items.setWidget(self.listWidget)
self.main_widget = QtGui.QWidget(self)
l = QtGui.QVBoxLayout(self.main_widget)
sc = MyMplCanvas(self.main_widget, width=5, height=4, dpi=100)
l.addWidget(sc)
self.main_widget.setFocus()
self.setCentralWidget(self.main_widget)
self.setGeometry(100,100,650,350)
self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.items)
self.setWindowTitle("Poor's Man KML Viewer")
self.show()
def fileOpen(self):
filename = unicode(QtGui.QFileDialog.getSaveFileName(self,
"Open file", "",
"KML files (*.kml)"))
if filename:
self.listWidget.addItem(filename)
def fileQuit(self):
self.close()
def closeEvent(self, ce):
self.fileQuit()
def main():
app = QtGui.QApplication(sys.argv)
main = MainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
There are good examples of embedding Matplotlib plots into PyQt applications, but I could not find any considering Basemap.
Can anyone give me a hand?
Thanks in advance!
I would say that you are missing to tell the basemap in which axes it should reside:
m = Basemap(..., ax=self.axes)
I would also suggest not to call a varaible by the name of a python function. I.e. use m instead of map.
While this is unproblematic here, it is an easily overseen problem in other cases.
Without the use of the ax argument, Basemap would create its own figure or take the available matplotlib axes inside pyplot. Since in the embedded case, you do not want to use pyplot at all, a specific axes needs to be specified for the basemap to live in.
I am using PyQt 4 for a basic GUI and matplotlib for a plot from which I want to read the coordinates of the plotted data points. Based on these examples (simple picking example), I have the simple problem that I cannot display the coordinates of a data point in a text field such as QtGui.QLabel(). I do not understand why I cannot call the instance Window.msg in the method onpick(). Probably it is because the instance it not given to the method. I only have a basic understanding of object oriented programming (but I am working on it), so the problem is my lack of knowledge.
My question: How to display the coordinates of chosen data (by clicking on it) from a matplotlib plot in my GUI based on PyQT (in that case in my label lbl)?
Also, it would be nice to highlight the chosen data point in the plot.
Here is my code (working):
import numpy as np
import matplotlib.pyplot as plt
from PyQt4 import QtGui
import sys
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
import matplotlib.pyplot as plt
class Window(QtGui.QDialog):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.initUI()
def initUI(self):
self.msg = '0'
# a figure instance to plot on
self.figure = plt.figure()
self.canvas = FigureCanvas(self.figure)
self.toolbar = NavigationToolbar(self.canvas, self)
# a label
self.lbl = QtGui.QLabel(self.msg)
# set the layout
layout = QtGui.QVBoxLayout()
layout.addWidget(self.toolbar)
layout.addWidget(self.canvas)
layout.addWidget(self.lbl)
self.setLayout(layout)
self.plot()
def plot(self):
# random data
data = [np.random.random() for i in range(10)]
# create an axis
ax = self.figure.add_subplot(111)
# discards the old graph
ax.hold(False)
# plot data
line, = ax.plot(data, 'o', picker=5) # 5 points tolerance
self.canvas.draw()
self.canvas.mpl_connect('pick_event', Window.onpick)
def onpick(self):
thisline = self.artist
xdata = thisline.get_xdata()
ydata = thisline.get_ydata()
ind = self.ind
# show data
self.msg = (xdata[ind], ydata[ind])
print(self.msg)
# This does not work:
#Window.lbl.setText(self.msg)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
main = Window()
main.show()
sys.exit(app.exec_())
The self is being overlapped by the picker (not sure why). In any case this should work:
import numpy as np
import matplotlib.pyplot as plt
from PyQt4 import QtGui
import sys
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
import matplotlib.pyplot as plt
class Window(QtGui.QDialog):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.initUI()
def initUI(self):
self.msg = '0'
# a figure instance to plot on
self.figure = plt.figure()
self.canvas = FigureCanvas(self.figure)
self.toolbar = NavigationToolbar(self.canvas, self)
# a label
self.lbl = QtGui.QLabel(self.msg)
# set the layout
layout = QtGui.QVBoxLayout()
layout.addWidget(self.toolbar)
layout.addWidget(self.canvas)
layout.addWidget(self.lbl)
self.setLayout(layout)
self.plot()
def changelabel(arg):
main.lbl.setText(str(arg[0])+' '+str(arg[1]))
def plot(self):
# random data
data = [np.random.random() for i in range(10)]
# create an axis
ax = self.figure.add_subplot(111)
# discards the old graph
ax.hold(False)
# plot data
line, = ax.plot(data, 'o', picker=5) # 5 points tolerance
self.canvas.draw()
self.canvas.mpl_connect('pick_event', Window.onpick)
def onpick(self):
thisline = self.artist
xdata = thisline.get_xdata()
ydata = thisline.get_ydata()
ind = self.ind
# show data
self.msg = (xdata[ind], ydata[ind])
print(self.msg)
# Window.changelabel(self.msg)
main.lbl.setText(str(self.msg[0])+' '+str(self.msg[1]))
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
main = Window()
main.show()
sys.exit(app.exec_())
, the change is in the setText function, since I call it directly from the variable (no self or Window).
main.lbl.setText(str(self.msg[0])+' '+str(self.msg[1]))
I've created a qt app that can be used to display matplotlib figures in multiple tabs. Now I'm trying to get the standard matplotlib navigation toolbar to work for all the figures in the various tabs. So far I've only managed to get it working in one of the figures, but not all.
Here's the code:
from PyQt4 import QtCore
from PyQt4 import QtGui as qt
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
from matplotlib.figure import Figure
import itertools
class MultiTabNavTool(NavigationToolbar):
#====================================================================================================
def __init__(self, canvases, tabs, parent=None):
self.canvases = canvases
self.tabs = tabs
NavigationToolbar.__init__(self, canvases[0], parent)
#====================================================================================================
def get_canvas(self):
return self.canvases[self.tabs.currentIndex()]
def set_canvas(self, canvas):
self._canvas = canvas
canvas = property(get_canvas, set_canvas)
class MplMultiTab(qt.QMainWindow):
#====================================================================================================
def __init__(self, parent=None, figures=None, labels=None):
qt.QMainWindow.__init__(self, parent)
self.main_frame = qt.QWidget()
self.tabWidget = qt.QTabWidget( self.main_frame )
self.create_tabs( figures, labels )
# Create the navigation toolbar, tied to the canvas
self.mpl_toolbar = MultiTabNavTool(self.canvases, self.tabWidget, self.main_frame)
self.vbox = vbox = qt.QVBoxLayout()
vbox.addWidget(self.mpl_toolbar)
vbox.addWidget(self.tabWidget)
self.main_frame.setLayout(vbox)
self.setCentralWidget(self.main_frame)
#====================================================================================================
def create_tabs(self, figures, labels ):
if labels is None: labels = []
figures = [Figure()] if figures is None else figures #initialise with empty figure in first tab if no figures provided
self.canvases = [self.add_tab(fig, lbl)
for (fig, lbl) in itertools.zip_longest(figures, labels) ]
#====================================================================================================
def add_tab(self, fig=None, name=None):
'''dynamically add tabs with embedded matplotlib canvas with this function.'''
# Create the mpl Figure and FigCanvas objects.
if fig is None:
fig = Figure()
ax = fig.add_subplot(111)
canvas = fig.canvas if fig.canvas else FigureCanvas(fig)
canvas.setParent(self.tabWidget)
canvas.setFocusPolicy( QtCore.Qt.ClickFocus )
#self.tabs.append( tab )
name = 'Tab %i'%(self.tabWidget.count()+1) if name is None else name
self.tabWidget.addTab(canvas, name)
return canvas
A basic usage example would be:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(1, 2*np.pi, 100)
figures = []
for i in range(1,3):
fig, ax = plt.subplots()
y = np.sin(np.pi*i*x)+0.1*np.random.randn(100)
ax.plot(x,y)
figures.append( fig )
app = qt.QApplication(sys.argv)
ui = MplMultiTab( figures=figures )
ui.show()
app.exec_()
Are there any matplotlib ninjas out there who might know how I can get the navigation toolbar to play with the multiple figure canvasses?
I think you can create toolbar for every canvas and show/hide them when tabs.currentTab changed:
class MultiTabNavTool(qt.QWidget):
def __init__(self, canvases, tabs, parent=None):
qt.QWidget.__init__(self, parent)
self.canvases = canvases
self.tabs = tabs
self.toolbars = [NavigationToolbar(canvas, parent) for canvas in self.canvases]
vbox = qt.QVBoxLayout()
for toolbar in self.toolbars:
vbox.addWidget(toolbar)
self.setLayout(vbox)
self.switch_toolbar()
self.tabs.currentChanged.connect(self.switch_toolbar)
def switch_toolbar(self):
for toolbar in self.toolbars:
toolbar.setVisible(False)
self.toolbars[self.tabs.currentIndex()].setVisible(True)