Search code examples
matplotlibwxpython

can embed matplotlib bar graph in wxPython panel but not pie chart


I'm brand new to matplotlib. I have found many examples of embedding bar graphs and plots into a wxPython panel. When I try to replace a graph or plot with a pie chart, the pie chart displays and only when it closes does the panel displays. It doesn't embed. I've been searching for 2 days.

I would like to embed this or this pie chart into this example.

I can't take the code for the pie chart and replace the code for the graph in the example. (Which means I'm missing something pretty big)

This is what I have tried:

import wx
import matplotlib
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas

import matplotlib.pyplot as plt

class MainFrame(wx.Frame):
    """docstring for MainFrame"""
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, title=">>>> by www.UmarYusuf.com", size=(800, 580))

    # Add SplitterWindow panels
    self.split_win = wx.SplitterWindow(self)
    self.top_split = MatplotPanel(self.split_win)
    self.bottom_split = wx.Panel(self.split_win, style=wx.SUNKEN_BORDER)
    self.split_win.SplitHorizontally(self.top_split, self.bottom_split, 480)

    # Add some contrls/widgets (StaticText and Buttons)
    # Add Text control to the bottom_split window
    self.text1 = wx.StaticText(self.bottom_split, -1, u"You can also plot from file", size=(250, 30), pos=(510, 10), style=wx.ALIGN_CENTER)
    self.text1.SetBackgroundColour('Gray')
    font = wx.Font(15, wx.SWISS, wx.NORMAL, wx.NORMAL)
    self.text1.SetFont(font)

    # Add Buttons to the bottom_split window and bind them to plot functions
    self.Button1 = wx.Button(self.bottom_split, -1, "Plot1", size=(80, 40), pos=(10, 10))
    self.Button1.Bind(wx.EVT_BUTTON, self.plot1)

    self.Button2 = wx.Button(self.bottom_split, -1, "Plot2", size=(80, 40), pos=(110, 10))
    self.Button2.Bind(wx.EVT_BUTTON, self.plot2)

    self.Button3 = wx.Button(self.bottom_split, -1, "Plot3", size=(80, 40), pos=(210, 10))
    self.Button3.Bind(wx.EVT_BUTTON, self.plot3)


def plot1(self, event):
    pass

def plot2(self, event):
    pass

def plot3(self, event):
    pass

def plot4(self, event):
    pass

def plot5(self, event):
    pass


class MatplotPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent,-1,size=(50,50))

    self.figure = Figure()

    # Pie chart, where the slices will be ordered and plotted counter-clockwise:
    labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
    sizes = [15, 30, 45, 10]
    explode = (0, 0.1, 0, 0)  # only "explode" the 2nd slice (i.e. 'Hogs')

    fig1, ax1 = plt.subplots()
    ax1.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%',
        shadow=True, startangle=90)
    ax1.axis('equal')  # Equal aspect ratio ensures that pie is drawn as a circle.

    plt.show()
    self.canvas = FigureCanvas(self, -1, self.figure)


app = wx.App()
frame = MainFrame(None).Show()
app.MainLoop()

Thank you.


Solution

  • There is a question about embedding matplotlib into wxpython, where the answer is showing a minimal example. Several examples are also available on the matplotlib examples page.

    The main problem you are facing here is that you are creating two different figures. The first one, self.figure = Figure(), is the one you connect to the canvas, but the second one, fig1 is the one you plot your graph to. The second one is the one shown in a new window when plt.show() gets called. However, calling plt.show() does not make any sense when embedding into GUIs since the GUI should take care of showing the figure.

    Therefore the MatplotPanel class from the question should look like this:

    class MatplotPanel(wx.Panel):
        def __init__(self, parent):
            wx.Panel.__init__(self, parent,-1,size=(50,50))
    
            self.figure = Figure()
            labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
            sizes = [15, 30, 45, 10]
    
            ax1 = self.figure.add_subplot(111)
            ax1.pie(sizes, labels=labels, autopct='%1.1f%%')
            ax1.axis('equal')
            self.canvas = FigureCanvas(self, -1, self.figure)