Title: Matplotlib and PyQt5 Plotting Figure
Tags: python;matplotlib;pyqt5
Question: Trying to plot a pie chart with python in PyQt5 and Matplotlib and I'm having some issues. I'm able to have a pie chart and the data I want to display in it, but I'm trying to update the chart if I feed it new data when I call a certain function.
mplvl is the widget name that I am adding the figure to.
Every time I call this function it just adds another subplot. I've tried clearing the plot, clearing the figure, but I cannot get it to just delete and redraw the figure. I think I'm confused at how Matplotlib truly works, but any help would be appreciated.
import datetime
import calendar as cal
import sys
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QDialog, QMainWindow, QMessageBox, QTableWidgetItem
from PyQt5.uic import loadUi
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import (FigureCanvasQTAgg as FigureCanvas)
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
loadUi('main.ui', self)
self.date_from.setDate(QtCore.QDate(c_date.year, c_date.month, 1))
self.date_to.setDate(QtCore.QDate(c_date.year, c_date.month, cal.monthrange(c_date.year, c_date.month)[1]))
self.date_from.dateChanged.connect(self.fcn_date_changed)
self.date_to.dateChanged.connect(self.fcn_date_changed)
def fcn_date_changed(self):
print("from: " + self.date_from.text() + " to: " + self.date_to.text())
labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
sizes = [15, 30, 45, 10]
fig = Figure()
ax1 = fig.add_subplot(111)
ax1.set_title('Percentage Spending by Category')
ax1.pie(sizes, labels=labels, autopct='%1.1f%%', shadow=False, startangle=90)
main.canvas = FigureCanvas(fig)
main.mplvl.addWidget(main.canvas)
if __name__ == "__main__":
app = QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
sys.exit(app.exec_())
Below is main.ui:
<?xml version="1.0" encoding="UTF-8"?&gt;
<ui version="4.0"&gt;
<class&gt;MainWindow</class&gt;
<widget class="QMainWindow" name="MainWindow"&gt;
<property name="geometry"&gt;
<rect&gt;
<x&gt;0</x&gt;
<y&gt;0</y&gt;
<width&gt;861</width&gt;
<height&gt;611</height&gt;
</rect&gt;
</property&gt;
<property name="windowTitle"&gt;
<string&gt;MainWindow</string&gt;
</property&gt;
<widget class="QWidget" name="centralwidget"&gt;
<widget class="QPushButton" name="btn_add_item"&gt;
<property name="geometry"&gt;
<rect&gt;
<x&gt;10</x&gt;
<y&gt;10</y&gt;
<width&gt;71</width&gt;
<height&gt;41</height&gt;
</rect&gt;
</property&gt;
<property name="text"&gt;
<string&gt;Add Item</string&gt;
</property&gt;
</widget&gt;
<widget class="QPushButton" name="btn_edit_item"&gt;
<property name="geometry"&gt;
<rect&gt;
<x&gt;190</x&gt;
<y&gt;540</y&gt;
<width&gt;81</width&gt;
<height&gt;23</height&gt;
</rect&gt;
</property&gt;
<property name="text"&gt;
<string&gt;Edit Item</string&gt;
</property&gt;
</widget&gt;
<widget class="QListWidget" name="recent_items"&gt;
<property name="geometry"&gt;
<rect&gt;
<x&gt;10</x&gt;
<y&gt;130</y&gt;
<width&gt;351</width&gt;
<height&gt;401</height&gt;
</rect&gt;
</property&gt;
</widget&gt;
<widget class="QLabel" name="lbl_recent_items"&gt;
<property name="geometry"&gt;
<rect&gt;
<x&gt;10</x&gt;
<y&gt;110</y&gt;
<width&gt;251</width&gt;
<height&gt;16</height&gt;
</rect&gt;
</property&gt;
<property name="text"&gt;
<string&gt;Recent Items</string&gt;
</property&gt;
</widget&gt;
<widget class="QPushButton" name="btn_delete_item"&gt;
<property name="geometry"&gt;
<rect&gt;
<x&gt;280</x&gt;
<y&gt;540</y&gt;
<width&gt;81</width&gt;
<height&gt;23</height&gt;
</rect&gt;
</property&gt;
<property name="text"&gt;
<string&gt;Delete Item</string&gt;
</property&gt;
</widget&gt;
<widget class="QWidget" name="mplwindow" native="true"&gt;
<property name="geometry"&gt;
<rect&gt;
<x&gt;380</x&gt;
<y&gt;130</y&gt;
<width&gt;471</width&gt;
<height&gt;401</height&gt;
</rect&gt;
</property&gt;
<property name="sizePolicy"&gt;
<sizepolicy hsizetype="Preferred" vsizetype="Preferred"&gt;
<horstretch&gt;0</horstretch&gt;
<verstretch&gt;0</verstretch&gt;
</sizepolicy&gt;
</property&gt;
<layout class="QVBoxLayout" name="mplvl"/&gt;
</widget&gt;
<widget class="QPushButton" name="btn_view_items"&gt;
<property name="geometry"&gt;
<rect&gt;
<x&gt;280</x&gt;
<y&gt;100</y&gt;
<width&gt;81</width&gt;
<height&gt;23</height&gt;
</rect&gt;
</property&gt;
<property name="text"&gt;
<string&gt;View Items</string&gt;
</property&gt;
</widget&gt;
<widget class="QDateEdit" name="date_from"&gt;
<property name="geometry"&gt;
<rect&gt;
<x&gt;110</x&gt;
<y&gt;60</y&gt;
<width&gt;110</width&gt;
<height&gt;21</height&gt;
</rect&gt;
</property&gt;
<property name="calendarPopup"&gt;
<bool&gt;true</bool&gt;
</property&gt;
</widget&gt;
<widget class="QDateEdit" name="date_to"&gt;
<property name="geometry"&gt;
<rect&gt;
<x&gt;250</x&gt;
<y&gt;60</y&gt;
<width&gt;110</width&gt;
<height&gt;21</height&gt;
</rect&gt;
</property&gt;
<property name="calendarPopup"&gt;
<bool&gt;true</bool&gt;
</property&gt;
</widget&gt;
<widget class="QLabel" name="lbl_showing_items1"&gt;
<property name="geometry"&gt;
<rect&gt;
<x&gt;10</x&gt;
<y&gt;60</y&gt;
<width&gt;101</width&gt;
<height&gt;21</height&gt;
</rect&gt;
</property&gt;
<property name="text"&gt;
<string&gt;Showing items from: </string&gt;
</property&gt;
</widget&gt;
<widget class="QLabel" name="lbl_showing_items1_2"&gt;
<property name="geometry"&gt;
<rect&gt;
<x&gt;230</x&gt;
<y&gt;60</y&gt;
<width&gt;21</width&gt;
<height&gt;21</height&gt;
</rect&gt;
</property&gt;
<property name="text"&gt;
<string&gt;to:</string&gt;
</property&gt;
</widget&gt;
</widget&gt;
<widget class="QMenuBar" name="menubar"&gt;
<property name="geometry"&gt;
<rect&gt;
<x&gt;0</x&gt;
<y&gt;0</y&gt;
<width&gt;861</width&gt;
<height&gt;21</height&gt;
</rect&gt;
</property&gt;
</widget&gt;
<widget class="QStatusBar" name="statusbar"/&gt;
</widget&gt;
<resources/&gt;
<connections/&gt;
</ui&gt;
Comment: I think I got it.

Here is the accepted answer: The logic is to:
create a single AxesSubplot,
clean it,
call the function that implements the plot (in your case pie()) and
call draw() to paint it.
# ...
self.date_to.dateChanged.connect(self.fcn_date_changed)
fig = Figure()
self.canvas = FigureCanvas(fig)
self.mplvl.addWidget(self.canvas)
self.ax1 = fig.add_subplot(111)
self.ax1.pie([])
def fcn_date_changed(self):
self.ax1.clear()
self.ax1.set_title("Percentage Spending by Category")
print("from: " + self.date_from.text() + " to: " + self.date_to.text())
labels = "Frogs", "Hogs", "Dogs", "Logs"
sizes = [15, 30, 45, 10]
self.ax1.pie(
sizes, labels=labels, autopct="%1.1f%%", shadow=False, startangle=90
self.ax1.figure.canvas.draw()
Comment for this answer: @Robert Yes, check the official example: https://matplotlib.org/3.1.1/gallery/user_interfaces/embedding_in_qt_sgskip.html
Comment for this answer: Thanks this worked! Although I admit I'm not sure what the difference is between your version and mine. Is it because I was adding the figure every time, vs yours that clears/adds the subplot every time?


{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 1, 'CommentCount': 1, 'ContentLicense': 'CC BY-SA 4.0', 'CreationDate': '2019:00:10/07/19', 'FavoriteCount': None, 'PostTypeId': 1, 'Tags': '<python><matplotlib><pyqt5>', 'Title': 'Matplotlib and PyQt5 Plotting Figure', 'ViewCount': 663, 'id': 58278424, 'user_AboutMe': None, 'user_AccountId': 14619176.0, 'user_DisplayName': 'Robert', 'user_Reputation': 45.0, 'user_Views': 11.0, 'user_id': 10558412.0}}