2

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"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>861</width>
    <height>611</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QPushButton" name="btn_add_item">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>10</y>
      <width>71</width>
      <height>41</height>
     </rect>
    </property>
    <property name="text">
     <string>Add Item</string>
    </property>
   </widget>
   <widget class="QPushButton" name="btn_edit_item">
    <property name="geometry">
     <rect>
      <x>190</x>
      <y>540</y>
      <width>81</width>
      <height>23</height>
     </rect>
    </property>
    <property name="text">
     <string>Edit Item</string>
    </property>
   </widget>
   <widget class="QListWidget" name="recent_items">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>130</y>
      <width>351</width>
      <height>401</height>
     </rect>
    </property>
   </widget>
   <widget class="QLabel" name="lbl_recent_items">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>110</y>
      <width>251</width>
      <height>16</height>
     </rect>
    </property>
    <property name="text">
     <string>Recent Items</string>
    </property>
   </widget>
   <widget class="QPushButton" name="btn_delete_item">
    <property name="geometry">
     <rect>
      <x>280</x>
      <y>540</y>
      <width>81</width>
      <height>23</height>
     </rect>
    </property>
    <property name="text">
     <string>Delete Item</string>
    </property>
   </widget>
   <widget class="QWidget" name="mplwindow" native="true">
    <property name="geometry">
     <rect>
      <x>380</x>
      <y>130</y>
      <width>471</width>
      <height>401</height>
     </rect>
    </property>
    <property name="sizePolicy">
     <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
      <horstretch>0</horstretch>
      <verstretch>0</verstretch>
     </sizepolicy>
    </property>
    <layout class="QVBoxLayout" name="mplvl"/>
   </widget>
   <widget class="QPushButton" name="btn_view_items">
    <property name="geometry">
     <rect>
      <x>280</x>
      <y>100</y>
      <width>81</width>
      <height>23</height>
     </rect>
    </property>
    <property name="text">
     <string>View Items</string>
    </property>
   </widget>
   <widget class="QDateEdit" name="date_from">
    <property name="geometry">
     <rect>
      <x>110</x>
      <y>60</y>
      <width>110</width>
      <height>21</height>
     </rect>
    </property>
    <property name="calendarPopup">
     <bool>true</bool>
    </property>
   </widget>
   <widget class="QDateEdit" name="date_to">
    <property name="geometry">
     <rect>
      <x>250</x>
      <y>60</y>
      <width>110</width>
      <height>21</height>
     </rect>
    </property>
    <property name="calendarPopup">
     <bool>true</bool>
    </property>
   </widget>
   <widget class="QLabel" name="lbl_showing_items1">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>60</y>
      <width>101</width>
      <height>21</height>
     </rect>
    </property>
    <property name="text">
     <string>Showing items from: </string>
    </property>
   </widget>
   <widget class="QLabel" name="lbl_showing_items1_2">
    <property name="geometry">
     <rect>
      <x>230</x>
      <y>60</y>
      <width>21</width>
      <height>21</height>
     </rect>
    </property>
    <property name="text">
     <string>to:</string>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>861</width>
     <height>21</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>
1
  • I think I got it. Commented Oct 8, 2019 at 12:44

1 Answer 1

4

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()
Sign up to request clarification or add additional context in comments.

2 Comments

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?
@Robert Yes, check the official example: matplotlib.org/3.1.1/gallery/user_interfaces/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.