⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 plot.bpy

📁 Python.Tkinter编程实例代码多多学习
💻 BPY
字号:
from Tkinter import *
from Canvas import Line, CanvasText
import string, math
from utils import *
from math import pi

class GraphPoints:
    def __init__(self, points, attr):
        self.points = points
	self.scaled = self.points
        self.attributes = {}
        for name, value in self._attributes.items():
            try:
                value = attr[name]
            except KeyError: pass
            self.attributes[name] = value

    def boundingBox(self):
        return minBound(self.points),  maxBound(self.points)

    def fitToScale(self, scale=(1,1), shift=(0,0)):
        self.scaled = []
        for x,y in self.points:
            self.scaled.append((scale[0]*x)+shift[0],\
                               (scale[1]*y)+shift[1])

class GraphLine(GraphPoints):
    def __init__(self, points, **attr):
        GraphPoints.__init__(self, points, attr)

    _attributes = {'color':       'black',
                   'width':        1,
                   'smooth':       0,
                   'splinesteps': 12}

    def draw(self, canvas):
	color  = self.attributes['color']
	width  = self.attributes['width']
        smooth = self.attributes['smooth']
        steps  = self.attributes['splinesteps']
	arguments = (canvas,)
        if smooth:
            for i in range(len(self.points)):
                x1, y1 = self.scaled[i]
                arguments = arguments + (x1, y1)
        else:
            for i in range(len(self.points)-1):
                x1, y1 = self.scaled[i]
                x2, y2 = self.scaled[i+1]
                arguments = arguments + (x1, y1, x2, y2)
	apply(Line, arguments, {'fill': color, 'width': width,
                                'smooth': smooth,
                                'splinesteps': steps})

class GraphSymbols(GraphPoints):
    def __init__(self, points, **attr):
        GraphPoints.__init__(self, points, attr)

    _attributes = {'color': 'black',
                   'width': 1,
                   'fillcolor': 'black',
                   'size': 2,
                   'fillstyle': '',
                   'outline': 'black',
                   'marker': 'circle'}

    def draw(self, canvas):
	color     = self.attributes['color']
        size      = self.attributes['size']
        fillcolor = self.attributes['fillcolor']
        marker    = self.attributes['marker']
        fillstyle = self.attributes['fillstyle']

	self._drawmarkers(canvas, self.scaled, marker, color,
                          fillstyle, fillcolor, size)

    def _drawmarkers(self, c, coords, marker='circle', color='black',
                     fillstyle='', fillcolor='', size=2):
        l = []
        f = eval('self._' +marker)
        for xc, yc in coords:
            id = f(c, xc, yc, outline=color, size=size,
                   fill=fillcolor, fillstyle=fillstyle)
            if type(id) is type(()):
                for item in id: l.append(item)
            else:
                l.append(id)
        return l
    
    def _circle(self, c, xc, yc, size=1, fill='', outline='black',
                fillstyle=''):
        id = c.create_oval(xc-0.5, yc-0.5, xc+0.5, yc+0.5, 
                           fill=fill, outline=outline,
                           stipple=fillstyle)
        c.scale(id, xc, yc, size*5, size*5)
        return id

    def _dot(self, c, xc, yc, size=1, fill='', outline='black',
             fillstyle=''):
        id = c.create_oval(xc-0.5, yc-0.5, xc+0.5, yc+0.5, 
                           fill=fill, outline=outline,
                           stipple=fillstyle)
        c.scale(id, xc, yc, size*2.5, size*2.5)
        return id

    def _square(self, c, xc, yc, size=1, fill='', outline='black',
                fillstyle=''):
        id = c.create_rectangle(xc-0.5, yc-0.5, xc+0.5, yc+0.5,
                                fill=fill, outline=outline,
                                stipple=fillstyle)
        c.scale(id, xc, yc, size*5, size*5)
        return id
    
    def _triangle(self, c, xc, yc, size=1, fill='', outline='black',
                  fillstyle=''):
        id = c.create_polygon(-0.5, 0.288675134595,
                              0.5, 0.288675134595,
                              0.0, -0.577350269189, fill=fill,
                              outline=outline, stipple=fillstyle)
        c.move(id, xc, yc)
        c.scale(id, xc, yc, size*5, size*5)
        return id

    def _triangle_down(self, c, xc, yc, size=1, fill='',
                       outline='black', fillstyle=''):
        id = c.create_polygon(-0.5, -0.288675134595,
                              0.5, -0.288675134595,
                              0.0, 0.577350269189, fill=fill,
                              outline=outline, stipple=fillstyle)
        c.move(id, xc, yc)
        c.scale(id, xc, yc, size*5, size*5)
        return id

    def _cross(self, c, xc, yc, size=1, fill='black', outline=None,
               fillstyle=''):
        if outline: fill=outline
        id1 = c.create_line(xc-0.5, yc-0.5, xc+0.5, yc+0.5,
                            fill=fill)
        id2 = c.create_line(xc-0.5, yc+0.5, xc+0.5, yc-0.5,
                            fill=fill)
        c.scale(id1, xc, yc, size*5, size*5)
        c.scale(id2, xc, yc, size*5, size*5)
        return id1, id2

    def _plus(self, c, xc, yc, size=1, fill='black', outline=None,
              fillstyle=''):
        if outline: fill=outline
        id1 = c.create_line(xc-0.5, yc, xc+0.5, yc, fill=fill)
        id2 = c.create_line(xc, yc+0.5, xc, yc-0.5, fill=fill)
        c.scale(id1, xc, yc, size*5, size*5)
        c.scale(id2, xc, yc, size*5, size*5)
        return id1, id2

class GraphObjects:
    def __init__(self, objects):
        self.objects = objects

    def boundingBox(self):
	c1, c2 = self.objects[0].boundingBox()
	for object in self.objects[1:]:
	    c1o, c2o = object.boundingBox()
	    c1 = minBound([c1, c1o])
	    c2 = maxBound([c2, c2o])
	return c1, c2

    def fitToScale(self, scale=(1,1), shift=(0,0)):
	for object in self.objects:
	    object.fitToScale(scale, shift)

    def draw(self, canvas):
	for object in self.objects:
	    object.draw(canvas)

class GraphBase(Frame):
    def __init__(self, master, width, height,
                 background='white', **kw):
        apply(Frame.__init__, (self, master), kw)
	self.canvas = Canvas(self, width=width, height=height,
			     background=background)
	self.canvas.pack(fill=BOTH, expand=YES)
        border_w = self.canvas.winfo_reqwidth() - \
                   string.atoi(self.canvas.cget('width'))
        border_h = self.canvas.winfo_reqheight() - \
                   string.atoi(self.canvas.cget('height'))
        self.border = (border_w, border_h)
        self.canvas.bind('<Configure>', self.configure)
        self.plotarea_size = [None, None]
	self._setsize()
	self.last_drawn = None
	self.font = ('Verdana', 10)

    def configure(self, event):
        new_width = event.width-self.border[0]
        new_height = event.height-self.border[1]
        width = string.atoi(self.canvas.cget('width'))
        height = string.atoi(self.canvas.cget('height'))
        if new_width == width and new_height == height:
            return
        self.canvas.configure(width=new_width, height=new_height)
        self._setsize()
        self.clear()
        self.replot()

    def bind(self, *args):
        apply(self.canvas.bind, args)

    def _setsize(self):
	self.width = string.atoi(self.canvas.cget('width'))
	self.height = string.atoi(self.canvas.cget('height'))
	self.plotarea_size[0] = 0.97 * self.width
	self.plotarea_size[1] = 0.97 * -self.height      
	xo = 0.5*(self.width-self.plotarea_size[0])
	yo = self.height-0.5*(self.height+self.plotarea_size[1])
	self.plotarea_origin = (xo, yo)
        
    def draw(self, graphics, xaxis = None, yaxis = None):
	self.last_drawn = (graphics, xaxis, yaxis)
	p1, p2 = graphics.boundingBox()
	xaxis = self._axisInterval(xaxis, p1[0], p2[0])
	yaxis = self._axisInterval(yaxis, p1[1], p2[1])
	text_width = [0., 0.]
	text_height = [0., 0.]
	if xaxis is not None:
	    p1 = xaxis[0], p1[1]
	    p2 = xaxis[1], p2[1]
 	    xticks = self._ticks(xaxis[0], xaxis[1])
 	    bb = self._textBoundingBox(xticks[0][1])
 	    text_height[1] = bb[3]-bb[1]
 	    text_width[0] = 0.5*(bb[2]-bb[0])
 	    bb = self._textBoundingBox(xticks[-1][1])
 	    text_width[1] = 0.5*(bb[2]-bb[0])
	else:
	    xticks = None
	if yaxis is not None:
	    p1 = p1[0], yaxis[0]
	    p2 = p2[0], yaxis[1]
 	    yticks = self._ticks(yaxis[0], yaxis[1])
 	    for y in yticks:
		bb = self._textBoundingBox(y[1])
		w = bb[2]-bb[0]
		text_width[0] = max(text_width[0], w)
	    h = 0.5*(bb[3]-bb[1])
	    text_height[0] = h
	    text_height[1] = max(text_height[1], h)
	else:
	    yticks = None
	text1 = [text_width[0], -text_height[1]]
	text2 = [text_width[1], -text_height[0]]
 	scale = ((self.plotarea_size[0]-text1[0]-text2[0]) / \
                 (p2[0]-p1[0]),
                 (self.plotarea_size[1]-text1[1]-text2[1]) / \
                 (p2[1]-p1[1]))
 	shift = ((-p1[0]*scale[0]) + self.plotarea_origin[0] + \
                 text1[0],
                 (-p1[1]*scale[1]) + self.plotarea_origin[1] + \
                 text1[1])
	self._drawAxes(self.canvas, xaxis, yaxis, p1, p2,
                        scale, shift, xticks, yticks)
	graphics.fitToScale(scale, shift)
	graphics.draw(self.canvas)

    def _axisInterval(self, spec, lower, upper):
	if spec is None:
	    return None
	if spec == 'minimal':
	    if lower == upper:
		return lower-0.5, upper+0.5
	    else:
		return lower, upper
	if spec == 'automatic':
	    range = upper-lower
	    if range == 0.:
		return lower-0.5, upper+0.5
	    log = math.log10(range)
	    power = math.floor(log)
	    fraction = log-power
	    if fraction <= 0.05:
		power = power-1
	    grid = 10.**power
	    lower = lower - lower % grid
	    mod = upper % grid
	    if mod != 0:
		upper = upper - mod + grid
	    return lower, upper
	if type(spec) == type(()):
	    lower, upper = spec
	    if lower <= upper:
		return lower, upper
	    else:
		return upper, lower
	raise ValueError, str(spec) + ': illegal axis specification'

    def _drawAxes(self, canvas, xaxis, yaxis,
                  bb1, bb2, scale, shift, xticks, yticks):
	dict = {'anchor': N, 'fill': 'black'}
	if self.font is not None:
	    dict['font'] = self.font
	if xaxis is not None:
	    lower, upper = xaxis
	    text = 1
	    for y, d in [(bb1[1], -3), (bb2[1], 3)]:
		p1 = (scale[0]*lower)+shift[0], (scale[1]*y)+shift[1]
		p2 = (scale[0]*upper)+shift[0], (scale[1]*y)+shift[1]
		Line(self.canvas, p1[0], p1[1], p2[0], p2[1],
                     fill = 'black', width = 1)
                if xticks:
                    for x, label in xticks:
                        p = (scale[0]*x)+shift[0], \
                            (scale[1]*y)+shift[1]
                        Line(self.canvas, p[0], p[1], p[0], p[1]+d,
                             fill = 'black', width = 1)
                        if text:
                            dict['text'] = label
                            apply(CanvasText, (self.canvas, p[0],
                                               p[1]), dict)
		text = 0

	dict['anchor'] = E
	if yaxis is not None:
	    lower, upper = yaxis
	    text = 1
	    for x, d in [(bb1[0], -3), (bb2[0], 3)]:
		p1 = (scale[0]*x)+shift[0], (scale[1]*lower)+shift[1]
		p2 = (scale[0]*x)+shift[0], (scale[1]*upper)+shift[1]
		Line(self.canvas, p1[0], p1[1], p2[0], p2[1],
                     fill = 'black', width = 1)
                if yticks:
                    for y, label in yticks:
                        p = (scale[0]*x)+shift[0], \
                            (scale[1]*y)+shift[1]
                        Line(self.canvas, p[0], p[1], p[0]-d, p[1],
                             fill = 'black', width = 1)
                        if text:
                            dict['text'] = label
                            apply(CanvasText, (self.canvas,
                                               p[0]-2, p[1]), dict)
		text = 0

    def _ticks(self, lower, upper):
	ideal = (upper-lower)/7.
	log = math.log10(ideal)
	power = math.floor(log)
	fraction = log-power
	factor = 1.
	error = fraction
	for f, lf in self._multiples:
	    e = math.fabs(fraction-lf)
	    if e < error:
		error = e
		factor = f
	grid = factor * 10.**power
        if power > 3 or power < -3:
            format = '%+7.0e'
        elif power >= 0:
            digits = max(1, int(power))
            format = '%' + `digits`+'.0f'
        else:
            digits = -int(power)
            format = '%'+`digits+2`+'.'+`digits`+'f'
	ticks = []
	t = -grid*math.floor(-lower/grid)
	while t <= upper and len(ticks) < 200:
	    ticks.append(t, format % (t,))
	    t = t + grid
	return ticks

    _multiples = [(2., math.log10(2.)), (5., math.log10(5.))]

    def _textBoundingBox(self, text):
	bg = self.canvas.cget('background')
	dict = {'anchor': NW, 'text': text, 'fill': bg}
	if self.font is not None:
	    dict['font'] = self.font
	item = apply(CanvasText, (self.canvas, 0., 0.), dict)
	bb = self.canvas.bbox(item)
	self.canvas.delete(item)
	return bb

    def replot(self):
	if self.last_drawn is not None:
	    apply(self.draw, self.last_drawn)

    def clear(self):
        self.canvas.delete('all')


if __name__ == '__main__':

    root = Tk()

    di = 5.*pi/5.
    data = []
    for i in range(18):
        data.append((float(i)*di,
                     (math.sin(float(i)*di)-math.cos(float(i)*di))))
    line  = GraphLine(data, color='gray', smooth=0)
    linea = GraphLine(data, color='blue', smooth=1, splinesteps=500)

    graphObject = GraphObjects([line, linea])

    graph  = GraphBase(root, 500, 400, relief=SUNKEN, border=2)
    graph.pack(side=TOP, fill=BOTH, expand=YES)

    graph.draw(graphObject, 'automatic', 'automatic')

    Button(root, text='Clear',  command=graph.clear).pack(side=LEFT)
    Button(root, text='Redraw', command=graph.replot).pack(side=LEFT)
    Button(root, text='Quit',   command=root.quit).pack(side=RIGHT)

    root.mainloop()

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -