+++ /dev/null
-import wx
-import math
-import random
-
-class RadarGraph(wx.Window):
- """
- A simple radar graph that plots a collection of values in the
- range of 0-100 onto a polar coordinate system designed to easily
- show outliers, etc. You might use this kind of graph to monitor
- some sort of resource allocation metrics, and a quick glance at
- the graph can tell you when conditions are good (within some
- accepted tolerance level) or approaching critical levels (total
- resource consumption).
- """
- def __init__(self, parent, title, labels):
- wx.Window.__init__(self, parent)
- self.title = title
- self.labels = labels
- self.data = [0.0] * len(labels)
- self.titleFont = wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD)
- self.labelFont = wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL)
-
- self.InitBuffer()
-
- self.Bind(wx.EVT_SIZE, self.OnSize)
- self.Bind(wx.EVT_PAINT, self.OnPaint)
-
-
- def OnSize(self, evt):
- # When the window size changes we need a new buffer.
- self.InitBuffer()
-
-
- def OnPaint(self, evt):
- # This automatically Blits self.buffer to a wx.PaintDC when
- # the dc is destroyed, and so nothing else needs done.
- dc = wx.BufferedPaintDC(self, self.buffer)
-
-
- def InitBuffer(self):
- # Create the buffer bitmap to be the same size as the window,
- # then draw our graph to it. Since we use wx.BufferedDC
- # whatever is drawn to the buffer is also drawn to the window.
- w, h = self.GetClientSize()
- self.buffer = wx.EmptyBitmap(w, h)
- dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
- self.DrawGraph(dc)
-
-
- def GetData(self):
- return self.data
-
- def SetData(self, newData):
- assert len(newData) == len(self.data)
- self.data = newData[:]
-
- # The data has changed, so update the buffer and the window
- dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
- self.DrawGraph(dc)
-
-
- def PolarToCartesian(self, radius, angle, cx, cy):
- x = radius * math.cos(math.radians(angle))
- y = radius * math.sin(math.radians(angle))
- return (cx+x, cy-y)
-
-
- def DrawGraph(self, dc):
- spacer = 10
- scaledmax = 150.0
-
- dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
- dc.Clear()
- dw, dh = dc.GetSize()
-
- # Find out where to draw the title and do it
- dc.SetFont(self.titleFont)
- tw, th = dc.GetTextExtent(self.title)
- dc.DrawText(self.title, (dw-tw)/2, spacer)
-
- # find the center of the space below the title
- th = th + 2*spacer
- cx = dw/2
- cy = (dh-th)/2 + th
-
- # calculate a scale factor to use for drawing the graph based
- # on the minimum available width or height
- mindim = min(cx, (dh-th)/2)
- scale = mindim/scaledmax
-
- # draw the graph axis and "bulls-eye" with rings at scaled 25,
- # 50, 75 and 100 positions
- dc.SetPen(wx.Pen("black", 1))
- dc.SetBrush(wx.TRANSPARENT_BRUSH)
- dc.DrawCircle(cx,cy, 25*scale)
- dc.DrawCircle(cx,cy, 50*scale)
- dc.DrawCircle(cx,cy, 75*scale)
- dc.DrawCircle(cx,cy, 100*scale)
-
- dc.SetPen(wx.Pen("black", 2))
- dc.DrawLine(cx-110*scale, cy, cx+110*scale, cy)
- dc.DrawLine(cx, cy-110*scale, cx, cy+110*scale)
-
- # Now find the coordinates for each data point, draw the
- # labels, and find the max data point
- dc.SetFont(self.labelFont)
- maxval = 0
- angle = 0
- polypoints = []
- for i, label in enumerate(self.labels):
- val = self.data[i]
- point = self.PolarToCartesian(val*scale, angle, cx, cy)
- polypoints.append(point)
- x, y = self.PolarToCartesian(125*scale, angle, cx,cy)
- dc.DrawText(label, x, y)
- if val > maxval:
- maxval = val
- angle = angle + 360/len(self.labels)
-
- # Set the brush color based on the max value (green is good,
- # red is bad)
- c = "forest green"
- if maxval > 70:
- c = "yellow"
- if maxval > 95:
- c = "red"
-
- # Finally, draw the plot data as a filled polygon
- dc.SetBrush(wx.Brush(c))
- dc.SetPen(wx.Pen("navy", 3))
- dc.DrawPolygon(polypoints)
-
-
-
-class TestFrame(wx.Frame):
- def __init__(self):
- wx.Frame.__init__(self, None, title="Double Buffered Drawing",
- size=(480,480))
- self.plot = RadarGraph(self, "Sample 'Radar' Plot",
- ["A", "B", "C", "D", "E", "F", "G", "H"])
-
- # Set some random initial data values
- data = []
- for d in self.plot.GetData():
- data.append(random.randint(0, 75))
- self.plot.SetData(data)
-
- # Create a timer to update the data values
- self.Bind(wx.EVT_TIMER, self.OnTimeout)
- self.timer = wx.Timer(self)
- self.timer.Start(500)
-
-
- def OnTimeout(self, evt):
- # simulate the positive or negative growth of each data value
- data = []
- for d in self.plot.GetData():
- val = d + random.uniform(-5, 5)
- if val < 0:
- val = 0
- if val > 110:
- val = 110
- data.append(val)
- self.plot.SetData(data)
-
-
-app = wx.PySimpleApp()
-frm = TestFrame()
-frm.Show()
-app.MainLoop()