Plotting a graph in QWidget with matplotlib - matplotlib

I want to draw a graph in QWidget using matplotlib library:
enter image description here
class MplCanvas(FigureCanvasQTAgg):
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
super(MplCanvas, self).__init__(fig)
Part of the code related to Ui_MainWindow which widget is defined:
self.widget = QtWidgets.QWidget(self.tab_3)
self.widget.setGeometry(QtCore.QRect(0, 0, 741, 241))
self.widget.setObjectName("widget")
The codes related to the function....I want to write the code in this section:
How to link to the widget in this part of the diagram?
``` def plot(self):
### plot
sc = MplCanvas(self, width=5, height=4, dpi=100)
sc.axes.plot([0,1,2,3,4], [10,1,20,3,40])
self.widget.setLayout(sc)
self.show()
TypeError: setLayout(self, QLayout): argument 1 has unexpected type 'MplCanvas'

Related

Colorbar in plots with embedded plots

While I managed to put a plot inside a plot (see the question here), I am finding trouble putting a colorbar to the larger (outside) plot. The code below is as simple as it gets, but for some reason it places the colorbar in the wrong axis:
import numpy as np
from numpy import random
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
# Canvas
fig, ax1 = plt.subplots(figsize=(12, 10))
left, bottom, width, height = [0.65, 0.15, 0.32, 0.30]
ax2 = fig.add_axes([left, bottom, width, height])
# Labels
xlabel = 'x'
ylabel = 'y'
cbarlabel = 'Color'
cmap = plt.get_cmap('turbo')
# Data
x, y, z = np.random.rand(3,200)
# Plotting
sc = ax1.scatter(x, y, marker='o', c=z, cmap=cmap)
ax2.scatter(x, y, c=z, cmap=cmap)
#
ax1.set_xlabel(xlabel)
ax1.set_ylabel(ylabel)
ax1.legend(fontsize=12, loc='upper left')
plt.tight_layout()
# Colormap
ax1 = plt.gca()
divider = make_axes_locatable(plt.gca())
cax = divider.append_axes("right", "2%", pad="1%")
cbar = plt.colorbar(sc, cax=cax) # Colorbar
cbar.set_label(cbarlabel, rotation=270, labelpad=30)
sc.set_clim(vmin=min(z), vmax=max(z))
#
plt.show()
I have also tried inset_axes as in the documentation example, to no avail.
The trick is to actually set active axes with plt.sca(ax1) and then create colorbar. I also simplified a code little bit.
Here is modified code putting colormap to the large plot:
import matplotlib.pyplot as plt
import numpy as np
from numpy import random
# Canvas
fig, ax1 = plt.subplots(figsize=(12, 10))
left, bottom, width, height = [0.45, 0.15, 0.32, 0.30]
ax2 = fig.add_axes([left, bottom, width, height])
# Labels
xlabel = 'x'
ylabel = 'y'
cbarlabel = 'Color'
cmap = plt.get_cmap('turbo')
# Data
x, y, z = np.random.rand(3,200)
# Plotting
sc = ax1.scatter(x, y, marker='o', c=z, cmap=cmap)
ax2.scatter(x, y, c=z, cmap=cmap)
# Set active axes
plt.sca(ax1)
cbar = plt.colorbar(sc) # Colorbar
cbar.set_label(cbarlabel, rotation=270, labelpad=30)
sc.set_clim(vmin=min(z), vmax=max(z))
#
ax1.set_xlabel(xlabel)
ax1.set_ylabel(ylabel)
ax1.legend(fontsize=12, loc='upper left')
plt.tight_layout()
plt.show()
Resulting in:

add scrollbar to preserve figure size in PyQt5 when plotting multiple figures

I am trying to plot multiple graphs in a pyqt5 window widget. I was able to do that but the size of the figure would just be "compressed" if I add more graphs to the window. See the comparison by running below code and clicking Push for Window 1 vs Push for Window 2.
I wanted to add a scrollbar to the canvas, so that I can preserve the size of the graphs, just like putting multiple graphs in a word file and use the scrollbar to move up and down to review the graphs. How should I do that?
import sys
import pandas as pd
import numpy as np
from PyQt5.QtWidgets import (
QApplication,
QLabel,
QMainWindow,
QPushButton,
QVBoxLayout,
QWidget,
)
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
import matplotlib.pyplot as plt
class AnotherWindow1(QWidget):
def __init__(self):
super().__init__()
self.figure = plt.figure(figsize=(45,15))
self.canvas = FigureCanvas(self.figure)
layout = QVBoxLayout()
button1 = QPushButton("Plot")
button1.clicked.connect(self.plot)
button2 = QPushButton("Back")
button2.clicked.connect(self.close_window)
layout.addWidget(button1)
layout.addWidget(button2)
layout.addWidget(self.canvas)
self.setLayout(layout)
def close_window(self):
self.close()
def plot(self):
self.figure.clear()
ax1 = self.figure.add_subplot(111)
data = pd.DataFrame(np.random.rand(5))
data.plot(ax=ax1)
self.canvas.draw()
class AnotherWindow2(QWidget):
def __init__(self):
super().__init__()
self.figure = plt.figure(figsize=(45,15))
self.canvas = FigureCanvas(self.figure)
self.canvas2 = FigureCanvas(self.figure)
self.canvas3 = FigureCanvas(self.figure)
layout = QVBoxLayout()
button1 = QPushButton("Plot")
button1.clicked.connect(self.plot)
button2 = QPushButton("Back")
button2.clicked.connect(self.close_window)
layout.addWidget(button1)
layout.addWidget(button2)
layout.addWidget(self.canvas)
layout.addWidget(self.canvas2)
layout.addWidget(self.canvas3)
self.setLayout(layout)
def close_window(self):
self.close()
def plot(self):
self.figure.clear()
ax1 = self.figure.add_subplot(111)
data = pd.DataFrame(np.random.rand(5))
data.plot(ax=ax1)
self.canvas.draw()
ax2 = self.figure.add_subplot(111)
data = pd.DataFrame(np.random.rand(5))
data.plot(ax=ax2)
self.canvas2.draw()
ax2 = self.figure.add_subplot(111)
data = pd.DataFrame(np.random.rand(5))
data.plot(ax=ax2)
self.canvas3.draw()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.window1 = AnotherWindow1()
self.window2 = AnotherWindow2()
l = QVBoxLayout()
button1 = QPushButton("Push for Window 1")
button1.clicked.connect(self.show_window1)
l.addWidget(button1)
button2 = QPushButton("Push for Window 2")
button2.clicked.connect(self.show_window2)
l.addWidget(button2)
w = QWidget()
w.setLayout(l)
self.setCentralWidget(w)
def show_window1(self):
self.window1.show()
def show_window2(self):
self.window2.show()
app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec()
You have to use a QScrollArea that contains a QWidget as a container for the canvas
import sys
import pandas as pd
import numpy as np
from PyQt5.QtWidgets import (
QApplication,
QLabel,
QMainWindow,
QPushButton,
QScrollArea,
QVBoxLayout,
QWidget,
)
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
class AnotherWindow1(QWidget):
def __init__(self):
super().__init__()
self.figure = Figure(figsize=(45, 15))
self.canvas = FigureCanvas(self.figure)
button1 = QPushButton("Plot")
button1.clicked.connect(self.plot)
button2 = QPushButton("Back")
button2.clicked.connect(self.close_window)
layout = QVBoxLayout(self)
layout.addWidget(button1)
layout.addWidget(button2)
layout.addWidget(self.canvas)
def close_window(self):
self.close()
def plot(self):
self.figure.clear()
ax1 = self.figure.add_subplot(111)
data = pd.DataFrame(np.random.rand(5))
data.plot(ax=ax1)
self.canvas.draw()
class AnotherWindow2(QWidget):
def __init__(self):
super().__init__()
self.figure = Figure(figsize=(45, 15))
self.canvas = FigureCanvas(self.figure)
self.canvas.setMinimumSize(640, 480)
self.canvas2 = FigureCanvas(self.figure)
self.canvas2.setMinimumSize(640, 480)
self.canvas3 = FigureCanvas(self.figure)
self.canvas3.setMinimumSize(640, 480)
canvas_scrollarea = QScrollArea(widgetResizable=True)
canvas_container = QWidget()
canvas_scrollarea.setWidget(canvas_container)
canvas_layout = QVBoxLayout(canvas_container)
canvas_layout.addWidget(self.canvas)
canvas_layout.addWidget(self.canvas2)
canvas_layout.addWidget(self.canvas3)
button1 = QPushButton("Plot")
button1.clicked.connect(self.plot)
button2 = QPushButton("Back")
button2.clicked.connect(self.close_window)
layout = QVBoxLayout(self)
layout.addWidget(button1)
layout.addWidget(button2)
layout.addWidget(canvas_scrollarea)
def close_window(self):
self.close()
def plot(self):
self.figure.clear()
ax1 = self.figure.add_subplot(111)
data = pd.DataFrame(np.random.rand(5))
data.plot(ax=ax1)
self.canvas.draw()
ax2 = self.figure.add_subplot(111)
data = pd.DataFrame(np.random.rand(5))
data.plot(ax=ax2)
self.canvas2.draw()
ax2 = self.figure.add_subplot(111)
data = pd.DataFrame(np.random.rand(5))
data.plot(ax=ax2)
self.canvas3.draw()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.window1 = AnotherWindow1()
self.window2 = AnotherWindow2()
button1 = QPushButton("Push for Window 1")
button1.clicked.connect(self.show_window1)
button2 = QPushButton("Push for Window 2")
button2.clicked.connect(self.show_window2)
w = QWidget()
l = QVBoxLayout(w)
l.addWidget(button1)
l.addWidget(button2)
self.setCentralWidget(w)
def show_window1(self):
self.window1.show()
def show_window2(self):
self.window2.show()
app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec()

Donut piechart in mplcanvas

In my pyqt5 I am trying to plot donut chart but I cannot find where I did mistake here. It failed when I plot center circle.I used a Qtwidget and convert into an mplwidget class. I added two classes MplCanvas and MplWidget in the same file.
Here is my code:
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import*
from matplotlib.backends.backend_qt5agg import FigureCanvas
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
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):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
self.ax1 = fig.subplots()
super(MplCanvas, self).__init__(fig)
class MplWidget(QWidget):
def __init__(self, parent = None):
QWidget.__init__(self, parent)
self.canvas = FigureCanvas(Figure())
vertical_layout = QVBoxLayout()
vertical_layout.addWidget(self.canvas)
self.canvas.axes = self.canvas.figure.add_subplot(111)
self.canvas.axes.set_position([0.03, 0.2,0.95, 0.7])
self.setLayout(vertical_layout)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.Mplwidget = MplWidget(self.centralwidget)
self.Mplwidget.setObjectName("Mplwidget")
self.verticalLayout.addWidget(self.Mplwidget)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
W=self.Mplwidget.canvas.axes
W.clear()
labels = ['a','b','c','d']
data =[40,10,30,20]
colors = ['#ff9999','#66b3ff','#99ff99','#ffcc99']
W.pie(data,colors = colors,labels=labels, autopct='%1.1f%%', startangle=90, pctdistance=0.85)
#draw circle
centre_circle = plt.Circle((0,0),0.70,fc='white')
fig = plt.gcf()
fig.gca().add_artist(centre_circle)
# Equal aspect ratio ensures that pie is drawn as a circle
W.axis('equal')
plt.tight_layout()
self.Mplwidget.canvas.draw()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
If you are going to embed a plot in Qt then don't use pyplot but canvas:
import sys
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QWidget
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.figure import Figure
from matplotlib.patches import Circle
class MplCanvas(FigureCanvasQTAgg):
def __init__(self, parent=None, width=5, height=4, dpi=100):
super(MplCanvas, self).__init__(Figure(figsize=(width, height), dpi=dpi))
self.axes = self.figure.add_subplot(111)
self.setParent(parent)
class MplWidget(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.canvas = MplCanvas()
labels = ["a", "b", "c", "d"]
data = [40, 10, 30, 20]
colors = ["#ff9999", "#66b3ff", "#99ff99", "#ffcc99"]
self.canvas.axes.pie(
data,
colors=colors,
labels=labels,
autopct="%1.1f%%",
startangle=90,
pctdistance=0.85,
)
centre_circle = Circle((0, 0), 0.70, fc="white")
self.canvas.axes.add_artist(centre_circle)
self.canvas.axes.axis("equal")
self.canvas.figure.tight_layout()
vertical_layout = QVBoxLayout(self)
vertical_layout.addWidget(self.canvas)
def main():
app = QApplication(sys.argv)
widget = MplWidget()
widget.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

How to translate Matplotlib to pyQt5

I am working on pyqt5 and I have to use some matplotlib I looked on how to embeed the matplotlib in pyqt5 using matplotlib.backends.backend_qt5agg but I still have couple of line that I couldn't set them to work for pyqt5
I mean I still don't know how to show this on my canvas ?
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)
#self.compute_initial_figure(self,img)
FigureCanvas.__init__(self, fig)
self.setParent(parent)
FigureCanvas.setSizePolicy(self,
QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
def compute_initial_figure(self,img):
pass
class MyStaticMplCanvas(MyMplCanvas):
"""Simple canvas with a sine plot."""
def compute_initial_figure(self,img):
pattern,code,label = self.freeman(img) #iam getting this from another function
na = plt.imshow(label,cmap='Greys')
plt.plot([i[1] for i in pattern],[i[0] for i in pattern ])
plt.show()
#t = arange(0.0, 3.0, 0.01)
#s = sin(2*pi*t)
#self.axes.plot(t,s)
and inside my MainWindow I am just using a normal class instance :
self.sc = MyStaticMplCanvas(self.tab_2, width=2, height=2,
dpi=100)
self.sc.setGeometry(QtCore.QRect(70, 320, 300, 300))
Well, your code isn't reproducible but this is a version that works with PyQt5. What certainly wouldn't work in your code -- I think -- is calling plt.show(). You want to plot with the figure object generated with MyMplCanvas, and I think pyplot will use its own UI instead of that
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from PyQt5 import QtWidgets
import sys
import numpy as np
class MyMplCanvas(FigureCanvas):
def __init__(self, parent=None, width=5.4, height=4, dpi=100):
self.fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = self.fig.add_subplot(111)
self.compute_initial_figure()
FigureCanvas.__init__(self, self.fig)
self.setParent(parent)
FigureCanvas.setSizePolicy(self, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
def compute_initial_figure(self):
pass
class MyStaticMplCanvas(MyMplCanvas):
def compute_initial_figure(self):
dat = np.random.uniform(0, 10, (20, 2))
self.axes.scatter(dat[:, 0], dat[:, 1])
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
canvas = MyStaticMplCanvas()
self.setCentralWidget(canvas)
def main():
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

Matplotlib events handling not working [duplicate]

Here is my sample code on jupyter notebook:
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(np.random.rand(10))
def onclick(event):
print('button=%d, x=%d, y=%d, xdata=%f, ydata=%f' %
(event.button, event.x, event.y, event.xdata, event.ydata))
cid = fig.canvas.mpl_connect('button_press_event', onclick)
Jupyter by default shows png images of the plot. In order to get an interactive figure, you would need the %matplotlib notebook backend.
The next problem is that it's currently not possible to interactively print to the cell output. This exact example is already subject of this GitHub issue. A solution may be expected for matplotlib version 2.1.
As of now you might want to print the output to the figure canvas, e.g. as figure title.
To give an example:
import matplotlib.pyplot as plt
import numpy as np
%matplotlib notebook
fig = plt.figure();
ax = fig.add_subplot(111)
ax.plot(np.random.rand(10))
def onclick(event):
a = ('button=%d, x=%d, y=%d, xdata=%f, ydata=%f' %
(event.button, event.x, event.y, event.xdata, event.ydata))
ax.set_title(a)
cid = fig.canvas.mpl_connect('button_press_event', onclick)
plt.show()