# --------------------------------------------------------------------------- # # PIECTRL Control wxPython IMPLEMENTATION # Python Code By: # # Andrea Gavana, @ 31 Oct 2005 # Latest Revision: 16 Jul 2012, 15.00 GMT # # # TODO List/Caveats # # 1. Maybe Integrate The Very Nice PyOpenGL Implementation Of A PieChart Coded # By Will McGugan? # # 2. Not Tested On Other Platforms, Only On Windows 2000/XP, With Python 2.4.1 # And wxPython 2.6.1.0 # # For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please # Write To Me At: # # andrea.gavana@gmail.com # andrea.gavana@maerskoil.com # # Or, Obviously, To The wxPython Mailing List!!! # # Tags: phoenix-port, unittest, documented, py3-port # # End Of Comments # --------------------------------------------------------------------------- # """ :class:`PieCtrl` and :class:`ProgressPie` are simple classes that reproduce the behavior of a pie chart. Description =========== :class:`PieCtrl` and :class:`ProgressPie` are simple classes that reproduce the behavior of a pie chart. They use only pure wxPython classes/methods, without external dependencies. :class:`PieCtrl` is somewhat a "static" control, that you may create in order to display a simple pie chart on a :class:`Panel` or similar. :class:`ProgressPie` tries to emulate the behavior of :class:`ProgressDialog`, but using a pie chart instead of a gauge. Usage ===== Usage example:: import wx import wx.lib.agw.piectrl as PC class MyFrame(wx.Frame): def __init__(self, parent): wx.Frame.__init__(self, parent, -1, "PieCtrl Demo") panel = wx.Panel(self) # create a simple PieCtrl with 3 sectors mypie = PC.PieCtrl(panel, -1, wx.DefaultPosition, wx.Size(180,270)) part = PC.PiePart() part.SetLabel("Label 1") part.SetValue(300) part.SetColour(wx.Colour(200, 50, 50)) mypie._series.append(part) part = PC.PiePart() part.SetLabel("Label 2") part.SetValue(200) part.SetColour(wx.Colour(50, 200, 50)) mypie._series.append(part) part = PC.PiePart() part.SetLabel("helloworld label 3") part.SetValue(50) part.SetColour(wx.Colour(50, 50, 200)) mypie._series.append(part) # create a ProgressPie progress_pie = PC.ProgressPie(panel, 100, 50, -1, wx.DefaultPosition, wx.Size(180, 200), wx.SIMPLE_BORDER) progress_pie.SetBackColour(wx.Colour(150, 200, 255)) progress_pie.SetFilledColour(wx.Colour(255, 0, 0)) progress_pie.SetUnfilledColour(wx.WHITE) progress_pie.SetHeight(20) main_sizer = wx.BoxSizer(wx.HORIZONTAL) main_sizer.Add(mypie, 1, wx.EXPAND | wx.ALL, 5) main_sizer.Add(progress_pie, 1, wx.EXPAND | wx.ALL, 5) panel.SetSizer(main_sizer) main_sizer.Layout() # our normal wxApp-derived class, as usual app = wx.App(0) frame = MyFrame(None) app.SetTopWindow(frame) frame.Show() app.MainLoop() Methods and Settings ==================== With :class:`PieCtrl` you can: - Create a :class:`PieCtrl` with different sectors; - Set the sector values, colours and labels; - Assign a legend to the :class:`PieCtrl`; - Use an image as the :class:`PieCtrl` background; - Change the vertical rotation (perspective) of the :class:`PieCtrl`; - Show/hide the segment edges. Window Styles ============= `No particular window styles are available for this class.` Events Processing ================= `No custom events are available for this class.` License And Version =================== :class:`PieCtrl` is distributed under the wxPython license. Latest revision: Andrea Gavana @ 16 Jul 2012, 15.00 GMT Version 0.3 """ #---------------------------------------------------------------------- # Beginning Of PIECTRL wxPython Code #---------------------------------------------------------------------- import wx from math import pi, sin, cos #---------------------------------------------------------------------- # Class PieCtrlLegend # This Class Handles The Legend For The Classic PieCtrl. #---------------------------------------------------------------------- class PieCtrlLegend(wx.Window): """ This class displays a legend window for the classic :class:`PieCtrl`. """ def __init__(self, parent, title, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0): """ Default class constructor. :param `parent`: the :class:`PieCtrlLegend` parent; :param `title`: the legend title; :param `id`: window identifier. A value of -1 indicates a default value; :param `pos`: the control position. A value of (-1, -1) indicates a default position, chosen by either the windowing system or wxPython, depending on platform; :param `size`: the control size. A value of (-1, -1) indicates a default size, chosen by either the windowing system or wxPython, depending on platform; :param `style`: the window style (unused). """ wx.Window.__init__(self, parent, id, pos, size, style) self._title = title self._istransparent = False self._horborder = 5 self._verborder = 5 self._titlecolour = wx.Colour(0, 0, 127) self._labelcolour = wx.BLACK self._labelfont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) self._backcolour = wx.Colour(255, 255, 0) self._backgroundDC = wx.MemoryDC() self._parent = parent self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: None) self.Bind(wx.EVT_PAINT, self.OnPaint) def SetTransparent(self, value=False): """ Toggles the legend transparency (visibility). :param `value`: ``True`` to set the legend as transparent, ``False`` otherwise. """ self._istransparent = value self.Refresh() def RecreateBackground(self, parentdc): """ Recreates the legend background. :param `parentdc`: an instance of :class:`DC`. """ w, h = self.GetSize() self._background = wx.Bitmap(w, h) self._backgroundDC.SelectObject(self._background) if self.IsTransparent(): self._backgroundDC.Blit(0, 0, w, h, parentdc, self.GetPosition().x, self.GetPosition().y) else: self._backgroundDC.SetBackground(wx.Brush(self._backcolour)) self._backgroundDC.Clear() self.Refresh() def SetHorizontalBorder(self, value): """ Sets the legend's horizontal border. :param `value`: the horizontal border thickness, in pixels. """ self._horborder = value self.Refresh() def GetHorizontalBorder(self): """ Returns the legend's horizontal border, in pixels. """ return self._horborder def SetVerticalBorder(self, value): """ Sets the legend's vertical border. :param `value`: the horizontal border thickness, in pixels. """ self._verborder = value self.Refresh() def GetVerticalBorder(self): """ Returns the legend's vertical border, in pixels. """ return self._verborder def SetLabelColour(self, colour): """ Sets the legend label colour. :param `colour`: a valid :class:`Colour` object. """ self._labelcolour = colour self.Refresh() def GetLabelColour(self): """ Returns the legend label colour. """ return self._labelcolour def SetLabelFont(self, font): """ Sets the legend label font. :param `font`: a valid :class:`Font` object. """ self._labelfont = font self.Refresh() def GetLabelFont(self): """ Returns the legend label font. """ return self._labelfont def SetBackColour(self, colour): """ Sets the legend background colour. :param `colour`: a valid :class:`Colour` object. """ self._backcolour = colour self.Refresh() def GetBackColour(self): """ Returns the legend background colour. """ return self._backcolour def IsTransparent(self): """ Returns whether the legend background is transparent or not. """ return self._istransparent def OnPaint(self, event): """ Handles the ``wx.EVT_PAINT`` event for :class:`PieCtrlLegend`. :param `event`: a :class:`PaintEvent` event to be processed. """ pdc = wx.PaintDC(self) w, h = self.GetSize() bmp = wx.Bitmap(w, h) mdc = wx.MemoryDC() mdc.SelectObject(bmp) if self.IsTransparent(): parentdc = wx.ClientDC(self.GetParent()) mdc.Blit(0, 0, w, h, self._backgroundDC, 0, 0) else: mdc.SetBackground(wx.Brush(self._backcolour)) mdc.Clear() dy = self._verborder mdc.SetFont(self._labelfont) mdc.SetTextForeground(self._labelcolour) maxwidth = 0 for ii in range(len(self._parent._series)): tw, th = mdc.GetTextExtent(self._parent._series[ii].GetLabel()) mdc.SetBrush(wx.Brush(self._parent._series[ii].GetColour())) mdc.DrawCircle(self._horborder+5, dy+th//2, 5) mdc.DrawText(self._parent._series[ii].GetLabel(), self._horborder+15, dy) dy = dy + th + 3 maxwidth = max(maxwidth, int(2*self._horborder+tw+15)) dy = dy + self._verborder if w != maxwidth or h != dy: self.SetSize((maxwidth, dy)) pdc.Blit(0, 0, w, h, mdc, 0, 0) #---------------------------------------------------------------------- # Class PiePart # This Class Handles The Legend Segments Properties, Such As Value, # Colour And Label. #---------------------------------------------------------------------- class PiePart(object): """ This class handles the legend segments properties, such as value, colour and label. """ def __init__(self, value=0, colour=wx.BLACK, label=""): """ Default class constructor. :param `value`: the pie part value; :param `colour`: the pie part colour; :param `label`: the pie part text label. """ self._value = value self._colour = colour self._label = label def SetValue(self, value): """ Sets the segment absolute value. :param `value`: a floating point number representing the :class:`PiePart` value. """ self._value = value def GetValue(self): """ Returns the segment absolute value. """ return self._value def SetColour(self, colour): """ Sets the segment colour. :param `colour`: a valid :class:`Colour` object. """ self._colour = colour def GetColour(self): """ Returns the segment colour. """ return self._colour def SetLabel(self, label): """ Sets the segment label. :param `label`: the pie part text label. """ self._label = label def GetLabel(self): """ Returns the segment label. """ return self._label #---------------------------------------------------------------------- # Class PieCtrl # This Is The Main PieCtrl Implementation, Used Also By ProgressPie. #---------------------------------------------------------------------- class PieCtrl(wx.Window): """ :class:`PieCtrl` is somewhat a "static" control, that you may create in order to display a simple pie chart on a :class:`Panel` or similar. """ def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, name="PieCtrl"): """ Default class constructor. :param `parent`: the :class:`PieCtrl` parent. Must not be ``None``; :param `id`: window identifier. A value of -1 indicates a default value; :param `pos`: the control position. A value of (-1, -1) indicates a default position, chosen by either the windowing system or wxPython, depending on platform; :param `size`: the control size. A value of (-1, -1) indicates a default size, chosen by either the windowing system or wxPython, depending on platform; :param `style`: the window style (unused); :param `name`: the window name. """ wx.Window.__init__(self, parent, id, pos, size, style, name) self._angle = pi/12.0 self._rotationangle = 0 self._height = 10 self._background = wx.NullBitmap self._canvasbitmap = wx.Bitmap(1, 1) self._canvasDC = wx.MemoryDC() self._backcolour = wx.WHITE self._showedges = True self._series = [] self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: None) self.Bind(wx.EVT_SIZE, self.OnSize) self.Bind(wx.EVT_PAINT, self.OnPaint) self.RecreateCanvas() self._legend = PieCtrlLegend(self, "PieCtrl", -1, wx.Point(10,10), wx.Size(100,75)) def SetBackground(self, bmp): """ Sets the :class:`PieCtrl` background image. :param `bmp`: a valid :class:`Bitmap` object. """ self._background = bmp self.Refresh() def GetBackground(self): """ Returns the :class:`PieCtrl` background image. """ return self._background def OnSize(self, event): """ Handles the ``wx.EVT_SIZE`` event for :class:`PieCtrl`. :param `event`: a :class:`SizeEvent` event to be processed. """ self.RecreateCanvas() self.Refresh() event.Skip() def RecreateCanvas(self): """ Recreates the :class:`PieCtrl` container (canvas). """ self._canvasbitmap = wx.Bitmap(self.GetSize().GetWidth(), self.GetSize().GetHeight()) self._canvasDC.SelectObject(self._canvasbitmap) def GetPartAngles(self): """ Returns the angles associated to all segments. """ angles = [] total = 0.0 for ii in range(len(self._series)): total = total + self._series[ii].GetValue() current = 0.0 angles.append(current) for ii in range(len(self._series)): current = current + self._series[ii].GetValue() angles.append(360.0*current/total) return angles def SetAngle(self, angle): """ Sets the orientation angle for :class:`PieCtrl`. :param `angle`: the orientation angle for :class:`PieCtrl`, in radians. """ if angle < 0: angle = 0 if angle > pi/2: angle = pi/2 self._angle = angle self.Refresh() def GetAngle(self): """ Returns the orientation angle for :class:`PieCtrl`, in radians. """ return self._angle def SetRotationAngle(self, angle): """ Sets the angle at which the first sector starts. :param `angle`: the first sector angle, in radians. """ if angle < 0: angle = 0 if angle > 2*pi: angle = 2*pi self._rotationangle = angle self.Refresh() def GetRotationAngle(self): """ Returns the angle at which the first sector starts, in radians. """ return self._rotationangle def SetShowEdges(self, value=True): """ Sets whether the :class:`PieCtrl` edges are visible or not. :param `value`: ``True`` to show the edges, ``False`` to hide them. """ self._showedges = value self.Refresh() def GetShowEdges(self): """ Returns whether the :class:`PieCtrl` edges are visible or not. """ return self._showedges def SetBackColour(self, colour): """ Sets the :class:`PieCtrl` background colour. :param `colour`: a valid :class:`Colour` object. """ self._backcolour = colour self.Refresh() def GetBackColour(self): """ Returns the :class:`PieCtrl` background colour. """ return self._backcolour def SetHeight(self, value): """ Sets the height (in pixels) of the :class:`PieCtrl`. :param `value`: the new height of the widget, in pixels. """ self._height = value def GetHeight(self): """ Returns the height (in pixels) of the :class:`PieCtrl`. """ return self._height def GetLegend(self): """ Returns the :class:`PieCtrl` legend. """ return self._legend def DrawParts(self, dc, cx, cy, w, h): """ Draws the :class:`PieCtrl` external edges. :param `dc`: an instance of :class:`DC`; :param `cx`: the part `x` coordinate; :param `cy`: the part `y` coordinate; :param `w`: the control's width; :param `h`: the control's height. """ angles = self.GetPartAngles() oldpen = dc.GetPen() if self._showedges: dc.SetPen(wx.BLACK_PEN) for ii in range(len(angles)): if ii > 0: if not self._showedges: dc.SetPen(wx.Pen(self._series[ii-1].GetColour())) dc.SetBrush(wx.Brush(self._series[ii-1].GetColour())) if angles[ii-1] != angles[ii]: dc.DrawEllipticArc(0, int((1-sin(self._angle))*(h//2)+cy), w, int(h*sin(self._angle)), angles[ii-1]+self._rotationangle/pi*180, angles[ii]+self._rotationangle/pi*180) if len(self._series) == 1: dc.SetBrush(wx.Brush(self._series[0].GetColour())) dc.DrawEllipticArc(0, int((1-sin(self._angle))*(h//2)+cy), w, int(h*sin(self._angle)), 0, 360) dc.SetPen(oldpen) def Draw(self, pdc): """ Draws all the sectors of :class:`PieCtrl`. :param `dc`: an instance of :class:`DC`. """ w, h = self.GetSize() self._canvasDC.SetBackground(wx.WHITE_BRUSH) self._canvasDC.Clear() if self._background != wx.NullBitmap: for ii in range(0, w, self._background.GetWidth()): for jj in range(0, h, self._background.GetHeight()): self._canvasDC.DrawBitmap(self._background, ii, jj) else: self._canvasDC.SetBackground(wx.Brush(self._backcolour)) self._canvasDC.Clear() if len(self._series) > 0: if self._angle <= pi/2: self.DrawParts(self._canvasDC, 0, int(self._height*cos(self._angle)), w, h) else: self.DrawParts(self._canvasDC, 0, 0, w, h) points = [[0, 0]]*4 triangle = [[0, 0]]*3 self._canvasDC.SetPen(wx.Pen(wx.BLACK)) angles = self.GetPartAngles() angleindex = 0 self._canvasDC.SetBrush(wx.Brush(wx.Colour(self._series[angleindex].GetColour().Red(), self._series[angleindex].GetColour().Green(), self._series[angleindex].GetColour().Blue()))) changeangle = False x = 0.0 while x <= 2*pi: changeangle = False if angleindex < len(angles): if x/pi*180.0 >= angles[angleindex+1]: changeangle = True x = angles[angleindex+1]*pi/180.0 points[0] = points[1] px = int(w/2.0*(1+cos(x+self._rotationangle))) py = int(h/2.0-sin(self._angle)*h/2.0*sin(x+self._rotationangle)-1) points[1] = [px, py] triangle[0] = [w // 2, h // 2] triangle[1] = points[0] triangle[2] = points[1] if x > 0: self._canvasDC.SetBrush(wx.Brush(self._series[angleindex].GetColour())) oldPen = self._canvasDC.GetPen() self._canvasDC.SetPen(wx.Pen(self._series[angleindex].GetColour())) self._canvasDC.DrawPolygon([wx.Point(pts[0], pts[1]) for pts in triangle]) self._canvasDC.SetPen(oldPen) if changeangle: angleindex = angleindex + 1 x = x + 0.05 x = 2*pi points[0] = points[1] px = int(w/2.0 * (1+cos(x+self._rotationangle))) py = int(h/2.0-sin(self._angle)*h/2.0*sin(x+self._rotationangle)-1) points[1] = [px, py] triangle[0] = [w // 2, h // 2] triangle[1] = points[0] triangle[2] = points[1] self._canvasDC.SetBrush(wx.Brush(self._series[angleindex].GetColour())) oldPen = self._canvasDC.GetPen() self._canvasDC.SetPen(wx.Pen(self._series[angleindex].GetColour())) self._canvasDC.DrawPolygon([wx.Point(pts[0], pts[1]) for pts in triangle]) self._canvasDC.SetPen(oldPen) angleindex = 0 x = 0.0 while x <= 2*pi: changeangle = False if angleindex < len(angles): if x/pi*180 >= angles[angleindex+1]: changeangle = True x = angles[angleindex+1]*pi/180 points[0] = points[1] points[3] = points[2] px = int(w/2.0 * (1+cos(x+self._rotationangle))) py = int(h/2.0-sin(self._angle)*h/2.0*sin(x+self._rotationangle)-1) points[1] = [px, py] points[2] = [px, int(py+self._height*cos(self._angle))] if w > 0: curColour = wx.Colour(int(self._series[angleindex].GetColour().Red()*(1.0-float(px)/w)), int(self._series[angleindex].GetColour().Green()*(1.0-float(px)/w)), int(self._series[angleindex].GetColour().Blue()*(1.0-float(px)/w))) if not self._showedges: self._canvasDC.SetPen(wx.Pen(curColour)) self._canvasDC.SetBrush(wx.Brush(curColour)) if sin(x+self._rotationangle) < 0 and sin(x-0.05+self._rotationangle) <= 0 and x > 0: self._canvasDC.DrawPolygon([wx.Point(pts[0], pts[1]) for pts in points]) if changeangle: angleindex = angleindex + 1 x = x + 0.05 x = 2*pi points[0] = points[1] points[3] = points[2] px = int(w/2.0 * (1+cos(x+self._rotationangle))) py = int(h/2.0-sin(self._angle)*h/2.0*sin(x+self._rotationangle)-1) points[1] = [px, py] points[2] = [px, int(py+self._height*cos(self._angle))] if w > 0: curColour = wx.Colour(int(self._series[angleindex].GetColour().Red()*(1.0-float(px)/w)), int(self._series[angleindex].GetColour().Green()*(1.0-float(px)/w)), int(self._series[angleindex].GetColour().Blue()*(1.0-float(px)/w))) if not self._showedges: self._canvasDC.SetPen(wx.Pen(curColour)) self._canvasDC.SetBrush(wx.Brush(curColour)) if sin(x+self._rotationangle) < 0 and sin(x-0.05+self._rotationangle) <= 0: self._canvasDC.DrawPolygon([wx.Point(pts[0], pts[1]) for pts in points]) if self._angle <= pi/2: self.DrawParts(self._canvasDC, 0, 0, w, h) else: self.DrawParts(self._canvasDC, 0, int(self._height*cos(self._angle)), w, h) pdc.Blit(0, 0, w, h, self._canvasDC, 0, 0) self._legend.RecreateBackground(self._canvasDC) def OnPaint(self, event): """ Handles the ``wx.EVT_PAINT`` event for :class:`PieCtrl`. :param `event`: a :class:`PaintEvent` event to be processed. """ pdc = wx.PaintDC(self) self.Draw(pdc) #---------------------------------------------------------------------- # Class ProgressPie # This Is The Main ProgressPie Implementation. Is Is A Subclassing Of # PieCtrl, With 2 Sectors. #---------------------------------------------------------------------- class ProgressPie(PieCtrl): """ :class:`ProgressPie` tries to emulate the behavior of :class:`ProgressDialog`, but using a pie chart instead of a gauge. """ def __init__(self, parent, maxvalue, value, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0): """ Default class constructor. :param `parent`: the :class:`PieCtrl` parent. Must not be ``None``; :param `id`: window identifier. A value of -1 indicates a default value; :param `pos`: the control position. A value of (-1, -1) indicates a default position, chosen by either the windowing system or wxPython, depending on platform; :param `size`: the control size. A value of (-1, -1) indicates a default size, chosen by either the windowing system or wxPython, depending on platform; :param `style`: the window style (unused); :param `name`: the window name. """ PieCtrl.__init__(self, parent, id, pos, size, style) self._maxvalue = maxvalue self._value = value self.GetLegend().Hide() self._filledcolour = wx.Colour(0, 0, 127) self._unfilledcolour = wx.WHITE part = PiePart() part.SetColour(self._filledcolour) a = min(float(value), maxvalue) part.SetValue(max(a, 0.0)) self._series.append(part) part = PiePart() part.SetColour(self._unfilledcolour) part.SetValue(max(0.0, maxvalue-part.GetValue())) self._series.append(part) def SetValue(self, value): """ Sets the :class:`ProgressPie` value. :param `value`: a floating point number representing the new value. """ self._value = min(value, self._maxvalue) self._series[0].SetValue(max(self._value, 0.0)) self._series[1].SetValue(max(self._maxvalue-self._value, 0.0)) self.Refresh() def GetValue(self): """ Returns the :class:`ProgressPie` value. """ return self._value def SetMaxValue(self, value): """ Sets the :class:`ProgressPie` maximum value. :param `value`: a floating point number representing the maximum value. """ self._maxvalue = value self._value = min(self._value, self._maxvalue) self._series[0].SetValue(max(self._value, 0.0)) self._series[1].SetValue(max(self._maxvalue-self._value, 0.0)) self.Refresh() def GetMaxValue(self): """ Returns the :class:`ProgressPie` maximum value. """ return self._maxvalue def SetFilledColour(self, colour): """ Sets the colour that progressively fills the :class:`ProgressPie` . :param `colour`: a valid :class:`Colour` object. """ self._filledcolour = colour self._series[0].SetColour(self._filledcolour) self.Refresh() def SetUnfilledColour(self, colour): """ Sets the colour that is filled. :param `colour`: a valid :class:`Colour` object. """ self._unfilledcolour= colour self._series[1].SetColour(self._unfilledcolour) self.Refresh() def GetFilledColour(self): """ Returns the colour that progressively fills the :class:`ProgressPie`. """ return self._filledcolour def GetUnfilledColour(self): """ Returns the colour that is filled. """ return self._unfilledcolour if __name__ == '__main__': import wx class MyFrame(wx.Frame): def __init__(self, parent): wx.Frame.__init__(self, parent, -1, "PieCtrl Demo") panel = wx.Panel(self) # create a simple PieCtrl with 3 sectors mypie = PieCtrl(panel, -1, wx.DefaultPosition, wx.Size(180,270)) part = PiePart() part.SetLabel("Label 1") part.SetValue(300) part.SetColour(wx.Colour(200, 50, 50)) mypie._series.append(part) part = PiePart() part.SetLabel("Label 2") part.SetValue(200) part.SetColour(wx.Colour(50, 200, 50)) mypie._series.append(part) part = PiePart() part.SetLabel("helloworld label 3") part.SetValue(50) part.SetColour(wx.Colour(50, 50, 200)) mypie._series.append(part) # create a ProgressPie progress_pie = ProgressPie(panel, 100, 50, -1, wx.DefaultPosition, wx.Size(180, 200), wx.SIMPLE_BORDER) progress_pie.SetBackColour(wx.Colour(150, 200, 255)) progress_pie.SetFilledColour(wx.Colour(255, 0, 0)) progress_pie.SetUnfilledColour(wx.WHITE) progress_pie.SetHeight(20) main_sizer = wx.BoxSizer(wx.HORIZONTAL) main_sizer.Add(mypie, 1, wx.EXPAND | wx.ALL, 5) main_sizer.Add(progress_pie, 1, wx.EXPAND | wx.ALL, 5) panel.SetSizer(main_sizer) main_sizer.Layout() # our normal wxApp-derived class, as usual app = wx.App(0) frame = MyFrame(None) app.SetTopWindow(frame) frame.Show() app.MainLoop()