Added the sample code from wxPython In Action to the samples dir
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@42925 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
170
wxPython/samples/wxPIA_book/Chapter-12/radargraph.py
Normal file
170
wxPython/samples/wxPIA_book/Chapter-12/radargraph.py
Normal file
@@ -0,0 +1,170 @@
|
||||
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()
|
Reference in New Issue
Block a user