Change-Id: If95cb839ad81ca2a842ff7f6926847ac3928d8f2 Former-commit-id:db24201469
[formerlybbad83c21a
] [formerly6f60751ec6
] [formerlydb24201469
[formerlybbad83c21a
] [formerly6f60751ec6
] [formerlyc5575f9624
[formerly6f60751ec6
[formerly 77e1a4d8f5237e5fae930c1e00589c752f8b3738]]]] Former-commit-id:c5575f9624
Former-commit-id:62f4f1bafb
[formerly8139e0dfb7
] [formerly 33159773a1764cd4fb517d13a3cff0a11feaa433 [formerly8de539020d
]] Former-commit-id: 094fceec6e1d9989f5e80a4efe1310f8a093b3ef [formerly451eb54a36
] Former-commit-id:f553c93092
640 lines
22 KiB
Python
640 lines
22 KiB
Python
##
|
|
# This software was developed and / or modified by Raytheon Company,
|
|
# pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
|
#
|
|
# U.S. EXPORT CONTROLLED TECHNICAL DATA
|
|
# This software product contains export-restricted data whose
|
|
# export/transfer/disclosure is restricted by U.S. law. Dissemination
|
|
# to non-U.S. persons whether in the United States or abroad requires
|
|
# an export license or other authorization.
|
|
#
|
|
# Contractor Name: Raytheon Company
|
|
# Contractor Address: 6825 Pine Street, Suite 340
|
|
# Mail Stop B8
|
|
# Omaha, NE 68106
|
|
# 402.291.0100
|
|
#
|
|
# See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
|
# further licensing information.
|
|
##
|
|
#
|
|
# Name:
|
|
# GraphWidget.py
|
|
# GFS1-NHD:A7895.0000-SCRIPT;1.7
|
|
#
|
|
# Status:
|
|
# DELIVERED
|
|
#
|
|
# History:
|
|
# Revision 1.7 (DELIVERED)
|
|
# Created: 24-AUG-2005 19:21:46 TROJAN
|
|
# spr 7002
|
|
#
|
|
# Revision 1.6 (DELIVERED)
|
|
# Created: 07-JUL-2005 12:45:24 TROJAN
|
|
# spr 6913
|
|
#
|
|
# Revision 1.5 (DELIVERED)
|
|
# Created: 12-MAY-2005 14:36:46 TROJAN
|
|
# spr 6839
|
|
#
|
|
# Revision 1.4 (REVIEW)
|
|
# Created: 07-MAY-2005 11:33:44 OBERFIEL
|
|
# Added Item Header Block
|
|
#
|
|
# Revision 1.3 (DELIVERED)
|
|
# Created: 25-APR-2005 20:40:03 TROJAN
|
|
# stdr917
|
|
#
|
|
# Revision 1.2 (DELIVERED)
|
|
# Created: 02-APR-2005 17:02:16 TROJAN
|
|
# spr 6763
|
|
#
|
|
# Revision 1.1 (DELIVERED)
|
|
# Created: 09-JUL-2004 19:53:23 OBERFIEL
|
|
# date and time created -2147483647/-2147483648/-2147481748
|
|
# -2147483648:-2147483648:-2147483648 by oberfiel
|
|
#
|
|
# Change Document History:
|
|
# 1:
|
|
# Change Document: GFS1-NHD_SPR_7002
|
|
# Action Date: 02-SEP-2005 12:22:12
|
|
# Relationship Type: In Response to
|
|
# Status: CLOSED
|
|
# Title: AvnFPS: Change ceiling and visibility axes annotation in the weater plot dialog
|
|
#
|
|
#
|
|
# GraphWidget.py
|
|
# Based on: John E. Grayson, 'Python and Tkinter Programming',
|
|
# Manning, 2000, Chapter 11
|
|
# last update: 08/24/05
|
|
|
|
from Tkinter import *
|
|
import math
|
|
|
|
BIG = 10000000
|
|
|
|
def minBound(clist):
|
|
x = min([BIG]+[c[0] for c in clist])
|
|
y = min([BIG]+[min(c[1:]) for c in clist])
|
|
return x, y
|
|
|
|
def maxBound(clist):
|
|
x = max([-BIG]+[c[0] for c in clist])
|
|
y = max([-BIG]+[max(c[1:]) for c in clist])
|
|
return x, y
|
|
|
|
###############################################################################
|
|
class Points:
|
|
_attributes = {
|
|
'tags': ('point',)
|
|
}
|
|
|
|
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.attributes.get('anchor', 0.0)
|
|
self.anchor = scale[1]*self.attributes.get('anchor', 0.0)+shift[1]
|
|
if not self.points:
|
|
self.scaled = []
|
|
return
|
|
dim = len(self.points[0])
|
|
sc = [scale[0]]+[scale[1]]*(dim-1)
|
|
sh = [shift[0]]+[shift[1]]*(dim-1)
|
|
def _map(x):
|
|
y = [None]*dim
|
|
for i in range(dim):
|
|
if x[i] is not None:
|
|
y[i] = sc[i]*x[i]+sh[i]
|
|
return y
|
|
self.scaled = [_map(x) for x in self.points]
|
|
|
|
def draw(self, canvas):
|
|
pass
|
|
|
|
###############################################################################
|
|
class Line(Points):
|
|
_attributes = {
|
|
'fill': 'black',
|
|
'width': 1,
|
|
'smooth': 0,
|
|
'splinesteps': 12,
|
|
'tags': ('line',)
|
|
}
|
|
|
|
def __init__(self, points, **attr):
|
|
Points.__init__(self, points, **attr)
|
|
|
|
def draw(self, canvas):
|
|
arguments = ()
|
|
if self.attributes['smooth']:
|
|
for i in range(len(self.points)):
|
|
x1, y1 = self.scaled[i]
|
|
if y1 is not None:
|
|
arguments = arguments + (x1, y1)
|
|
else:
|
|
for i in range(len(self.points)-1):
|
|
x1, y1 = self.scaled[i]
|
|
x2, y2 = self.scaled[i+1]
|
|
if None not in (y1, y2):
|
|
arguments = arguments + (x1, y1, x2, y2)
|
|
canvas.create_line(*arguments, **self.attributes)
|
|
|
|
###############################################################################
|
|
class Bars(Points):
|
|
_attributes = {
|
|
'fill': 'black',
|
|
'width': 1,
|
|
'size': 3,
|
|
'stipple': '',
|
|
'outline': 'black',
|
|
'tags': ('bars',)
|
|
}
|
|
|
|
def __init__(self, points, **attr):
|
|
Points.__init__(self, points, **attr)
|
|
self.spread = self.attributes['size']
|
|
del self.attributes['size']
|
|
|
|
def draw(self, canvas):
|
|
if self.spread == 'auto':
|
|
npoints = len(self.points)
|
|
self.spread = (self.scaled[npoints-1][0]-self.scaled[0][0]) \
|
|
/ (npoints-1) / 2.5
|
|
for i in range(npoints):
|
|
x1, y1 = self.scaled[i]
|
|
if y1 is not None:
|
|
canvas.create_rectangle(x1-self.spread, y1, x1+self.spread,
|
|
self.anchor, **self.attributes)
|
|
|
|
###############################################################################
|
|
class Steps(Points):
|
|
_attributes = {
|
|
'fill': 'black',
|
|
'width': 1,
|
|
'tags': ('steps',)
|
|
}
|
|
|
|
def __init__(self, points, **attr):
|
|
Points.__init__(self, points, **attr)
|
|
|
|
def draw(self, canvas):
|
|
npoints = len(self.points)
|
|
arguments = ()
|
|
for i in range(npoints-1):
|
|
x1, y1 = self.scaled[i]
|
|
if y1 is None:
|
|
continue
|
|
x2, y2 = self.scaled[i+1]
|
|
if y2 is None:
|
|
arguments = arguments + (x1, y1, x2, y1)
|
|
else:
|
|
arguments = arguments + (x1, y1, x2, y1, x2, y2)
|
|
if arguments:
|
|
canvas.create_line(*arguments, **self.attributes)
|
|
|
|
###############################################################################
|
|
class StepsRange(Points):
|
|
_attributes = {
|
|
'fill': 'black',
|
|
'width': 1,
|
|
'stipple': '',
|
|
'tags': ('stepsrange',)
|
|
}
|
|
|
|
def __init__(self, points, **attr):
|
|
Points.__init__(self, points, **attr)
|
|
self.attributes['outline'] = self.attributes['fill']
|
|
|
|
def draw(self, canvas):
|
|
npoints = len(self.points)
|
|
d1 = dict(self.attributes)
|
|
d2 = dict(self.attributes)
|
|
del d2['stipple']
|
|
del d2['outline']
|
|
for i in range(npoints-1):
|
|
x1, y11, y12 = self.scaled[i]
|
|
x2, y21, y22 = self.scaled[i+1]
|
|
if None not in (y11, y12):
|
|
canvas.create_rectangle(x1, y11, x2, y12, **d1)
|
|
if None not in (y21, y22):
|
|
canvas.create_line(x2, y11, x2, y21, **d2)
|
|
|
|
###############################################################################
|
|
class Winds(Points):
|
|
_attributes = {
|
|
'fill': 'black',
|
|
'width': 1,
|
|
'font': 'fixed',
|
|
'tags': ('wind',)
|
|
}
|
|
_relrad = 0.1
|
|
_rel10kt = 0.4
|
|
_relspace = 0.18
|
|
_relwidth = 0.2
|
|
_arrowshape = (0.2, 0.25, 0.1)
|
|
|
|
def __init__(self, points, winds, **attr):
|
|
assert(len(points) == len(winds))
|
|
points = [(x, 0) for x in points]
|
|
Points.__init__(self, points, **attr)
|
|
self.winds = winds
|
|
self.textattr = dict(self.attributes)
|
|
self.ovalattr = dict(self.attributes)
|
|
del self.attributes['font']
|
|
del self.textattr['width']
|
|
self.ovalattr['outline'] = self.ovalattr['fill']
|
|
del self.ovalattr['fill']
|
|
del self.ovalattr['font']
|
|
|
|
def _drawWind(self, canvas, xc, yc, data):
|
|
dd, ff = data.get('dd', None), data.get('ff', None)
|
|
if None in (dd, ff):
|
|
return
|
|
gg = data.get('gg', None)
|
|
if dd == 0:
|
|
r = 2.0*self._relrad*self.len
|
|
elif dd == 'VRB':
|
|
r = 3.0*self._relrad*self.len
|
|
else:
|
|
r = self._relrad*self.len
|
|
x0, y0 = xc - r, yc - r
|
|
x1, y1 = xc + r, yc + r
|
|
canvas.create_oval(x0, y0, x1, y1, **self.ovalattr)
|
|
if dd == 0 or dd == 'VRB':
|
|
if gg is not None:
|
|
self.textattr['text'] = str(gg)
|
|
self.textattr['anchor'] = 'n'
|
|
canvas.create_text(xc, yc+r+2, **self.textattr)
|
|
return
|
|
dd = math.radians(dd-90.0)
|
|
ddbarb = dd + 1.0
|
|
dx, dy = self.len*math.cos(dd), self.len*math.sin(dd)
|
|
# annotated arrow
|
|
if gg is not None:
|
|
x0, y0 = xc - dx * self._relrad, yc - dy * self._relrad
|
|
x1, y1 = xc - dx, yc - dy
|
|
canvas.create_line(x0, y0, x1, y1, arrow='last',
|
|
arrowshape=self.shape, **self.attributes)
|
|
if x0 < x1:
|
|
self.textattr['anchor'] = 'w'
|
|
off = 2
|
|
else:
|
|
self.textattr['anchor'] = 'e'
|
|
off = -2
|
|
self.textattr['text'] = str(gg)
|
|
canvas.create_text(x1+off, y1, **self.textattr)
|
|
x0, y0 = xc + dx*self._relrad, yc + dy*self._relrad
|
|
x1, y1 = xc + dx, yc + dy
|
|
canvas.create_line(x0, y0, x1, y1, **self.attributes)
|
|
dx1 = self.len*self._rel10kt*math.cos(ddbarb)
|
|
dy1 = self.len*self._rel10kt*math.sin(ddbarb)
|
|
x0, y0 = x1, y1
|
|
while ff > 47.5:
|
|
x1 = x0 - self._relwidth * dx + dx1
|
|
y1 = y0 - self._relwidth * dy + dy1
|
|
x2 = x0 - self._relwidth * dx
|
|
y2 = y0 - self._relwidth * dy
|
|
canvas.create_line(x0, y0, x1, y1, x2, y2, **self.attributes)
|
|
x0 = x2 - self._relspace * dx
|
|
y0 = y2 - self._relspace * dy
|
|
ff -= 50.0
|
|
while ff > 7.5:
|
|
x1, y1 = x0 + dx1, y0 + dy1
|
|
canvas.create_line(x0, y0, x1, y1, **self.attributes)
|
|
x0 -= self._relspace * dx
|
|
y0 -= self._relspace * dy
|
|
ff -= 10
|
|
if ff > 2.5:
|
|
x1, y1 = x0 + 0.5 * dx1, y0 + 0.5 * dy1
|
|
canvas.create_line(x0, y0, x1, y1, **self.attributes)
|
|
|
|
def boundingBox(self):
|
|
p1, p2 = Points.boundingBox(self)
|
|
return (p1[0], p1[1]-1.0), (p2[0], p2[1]+1.0)
|
|
|
|
def fitToScale(self, scale=(1,1), shift=(0,0)):
|
|
Points.fitToScale(self, scale, shift)
|
|
f = abs(scale[1])
|
|
self.len = f*0.8
|
|
self.shape = tuple([f*x for x in self._arrowshape])
|
|
|
|
def draw(self, canvas):
|
|
npoints = len(self.points)
|
|
for i in range(npoints):
|
|
if self.winds[i] is not None:
|
|
x1, y1 = self.scaled[i]
|
|
self._drawWind(canvas, x1, y1, self.winds[i])
|
|
|
|
###############################################################################
|
|
class Objects:
|
|
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 Graph(Frame):
|
|
_multiples = [(2., math.log10(2.0)), (5., math.log10(5.0))]
|
|
|
|
def __init__(self, master, width, height, **kw):
|
|
try:
|
|
bg = kw['background']
|
|
del kw['background']
|
|
except KeyError:
|
|
bg = 'white'
|
|
try:
|
|
font = kw['font']
|
|
del kw['font']
|
|
except KeyError:
|
|
font = 'fixed'
|
|
Frame.__init__(self, master, **kw)
|
|
self.font = font
|
|
self.canvas = Canvas(self, width=width, height=height, background=bg)
|
|
self.canvas.pack(fill='both', expand='yes')
|
|
border_w = self.canvas.winfo_reqwidth() - int(self.canvas.cget('width'))
|
|
border_h = self.canvas.winfo_reqheight() - \
|
|
int(self.canvas.cget('height'))
|
|
self.border = (border_w, border_h)
|
|
self.canvas.bind('<Configure>', self._reconfigure)
|
|
self.plotarea_size = [None, None]
|
|
self._setsize()
|
|
self.last_drawn = None
|
|
|
|
def _setsize(self):
|
|
self.width = int(self.canvas.cget('width'))
|
|
self.height = int(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 _axisInterval(self, spec, lower, upper):
|
|
if spec is None:
|
|
return None
|
|
if spec == 'minimal':
|
|
if lower == upper:
|
|
return lower, upper+1.0
|
|
else:
|
|
return lower, upper
|
|
if spec == 'auto':
|
|
range = upper-lower
|
|
if range == 0.0:
|
|
return lower, upper+1.0
|
|
log = math.log10(range)
|
|
power = math.floor(log)
|
|
fraction = log-power
|
|
if fraction <= 0.05:
|
|
power = power-1
|
|
grid = 10.0**power
|
|
lower = lower - lower % grid
|
|
mod = upper % grid
|
|
if mod != 0:
|
|
upper = upper - mod + grid
|
|
return lower, upper
|
|
if type(spec) == type(()) or type(spec) == type([]):
|
|
return spec[0][0], spec[-1][0]
|
|
raise ValueError, str(spec) + ': illegal axis specification'
|
|
|
|
def _drawGrid(self, xaxis, yaxis, bb1, bb2, scale, shift, xticks, yticks,
|
|
numYLabels):
|
|
dd_line = {'fill': 'black', 'width': 1, 'stipple': 'gray50'}
|
|
dd_text = {'fill': 'black'}
|
|
if self.font is not None:
|
|
dd_text['font'] = self.font
|
|
c = self.canvas
|
|
p1 = (scale[0]*xaxis[0])+shift[0], (scale[1]*bb1[1])+shift[1]
|
|
p2 = (scale[0]*xaxis[1])+shift[0], (scale[1]*bb2[1])+shift[1]
|
|
c.create_rectangle(p1[0], p1[1], p2[0], p2[1], width=1)
|
|
if xticks:
|
|
for x, label in xticks:
|
|
px = (scale[0]*x)+shift[0]
|
|
c.create_line(px, p1[1], px, p2[1], **dd_line)
|
|
dd_text['text'] = label
|
|
dd_text['anchor'] = 'n'
|
|
c.create_text(px, p1[1]+2, **dd_text)
|
|
dd_text['anchor'] = 's'
|
|
c.create_text(px, p2[1]+2, **dd_text)
|
|
|
|
if yticks:
|
|
for y, label in yticks:
|
|
py = (scale[1]*y)+shift[1]
|
|
c.create_line(p1[0], py, p2[0], py, **dd_line)
|
|
dd_text['text'] = label.rstrip()
|
|
dd_text['anchor'] = 'e'
|
|
c.create_text(p1[0]-2, py, **dd_text)
|
|
dd_text['text'] = label.lstrip()
|
|
dd_text['anchor'] = 'w'
|
|
c.create_text(p2[0]+3, py, **dd_text)
|
|
# test
|
|
for y, label in yticks[1:-1]:
|
|
py = (scale[1]*y)+shift[1]
|
|
dd_text['text'] = label.rstrip()
|
|
dd_text['anchor'] = 'e'
|
|
for k in range(1, numYLabels):
|
|
x = p1[0] + k*(p2[0]-p1[0])/(numYLabels)
|
|
c.create_text(x, py, **dd_text)
|
|
|
|
def _drawAxes(self, xaxis, yaxis, bb1, bb2, scale, shift, xticks, yticks):
|
|
dd_line = {'fill': 'black', 'width': 1}
|
|
dd_text = {'fill': 'black'}
|
|
if self.font is not None:
|
|
dd_text['font'] = self.font
|
|
c = self.canvas
|
|
if xaxis is not None:
|
|
for y, d, anchor in [(bb1[1], -3, 'n'), (bb2[1], 3, 's')]:
|
|
p1 = (scale[0]*xaxis[0])+shift[0], (scale[1]*y)+shift[1]
|
|
p2 = (scale[0]*xaxis[1])+shift[0], (scale[1]*y)+shift[1]
|
|
c.create_line(p1[0], p1[1], p2[0], p2[1], **dd_line)
|
|
if xticks:
|
|
dd_text['anchor'] = anchor
|
|
for x, label in xticks:
|
|
p = (scale[0]*x)+shift[0], (scale[1]*y)+shift[1]
|
|
c.create_line(p[0], p[1], p[0], p[1]+d, **dd_line)
|
|
dd_text['text'] = label
|
|
c.create_text(p[0], p[1]+1, **dd_text)
|
|
|
|
if yaxis is not None:
|
|
for x, d, anchor in [(bb1[0], -3, 'e'), (bb2[0], 3, 'w')]:
|
|
p1 = (scale[0]*x)+shift[0], (scale[1]*yaxis[0])+shift[1]
|
|
p2 = (scale[0]*x)+shift[0], (scale[1]*yaxis[1])+shift[1]
|
|
c.create_line(p1[0], p1[1], p2[0], p2[1], **dd_line)
|
|
if yticks:
|
|
dd_text['anchor'] = anchor
|
|
for y, label in yticks:
|
|
p = (scale[0]*x)+shift[0], (scale[1]*y)+shift[1]
|
|
c.create_line(p[0], p[1], p[0]-d, p[1], **dd_line)
|
|
dd_text['text'] = label.rstrip()
|
|
c.create_text(p[0]+d+1, p[1], **dd_text)
|
|
|
|
def _ticks(self, lower, upper, spec):
|
|
if type(spec) == type(()):
|
|
return spec
|
|
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.0**power
|
|
if power > 3 or power < -3:
|
|
format = '%+7.0e'
|
|
elif power >= 0:
|
|
digits = max(1, int(power))
|
|
format = '%' + str(digits) +'.0f'
|
|
else:
|
|
digits = -int(power)
|
|
format = '%'+str(digits+2)+'.'+str(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
|
|
|
|
def _textBoundingBox(self, text):
|
|
bg = self.canvas.cget('background')
|
|
dd = {'anchor': 'nw', 'text': text, 'fill': bg}
|
|
if self.font is not None:
|
|
dd['font'] = self.font
|
|
item = self.canvas.create_text(0., 0., **dd)
|
|
bb = self.canvas.bbox(item)
|
|
self.canvas.delete(item)
|
|
return bb
|
|
|
|
def bind(self, *args):
|
|
self.canvas.bind(*args)
|
|
|
|
def clear(self, tags='all'):
|
|
self.canvas.delete(tags)
|
|
|
|
def _reconfigure(self, event):
|
|
new_width = event.width-self.border[0]
|
|
new_height = event.height-self.border[1]
|
|
width = int(self.canvas.cget('width'))
|
|
height = int(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()
|
|
if self.last_drawn is not None:
|
|
self.draw(*self.last_drawn)
|
|
|
|
def draw(self, graphics, xaxisspec=None, yaxisspec=None, grid=False,
|
|
numYLabels=0):
|
|
seq = []
|
|
for o in graphics.objects:
|
|
seq.extend(o.attributes['tags'])
|
|
self.tags = tuple(seq)
|
|
|
|
self.last_drawn = (graphics, xaxisspec, yaxisspec, grid)
|
|
text_width = [0., 0.]
|
|
text_height = [0., 0.]
|
|
p1, p2 = graphics.boundingBox()
|
|
xaxis = self._axisInterval(xaxisspec, p1[0], p2[0])
|
|
yaxis = self._axisInterval(yaxisspec, p1[1], p2[1])
|
|
if xaxis is not None:
|
|
p1 = xaxis[0], p1[1]
|
|
p2 = xaxis[1], p2[1]
|
|
xticks = self._ticks(xaxis[0], xaxis[1], xaxisspec)
|
|
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], yaxisspec)
|
|
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]-2*text1[0]-2*text2[0]) / (p2[0]-p1[0]),
|
|
(self.plotarea_size[1]-2*text1[1]-2*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])
|
|
if grid:
|
|
self._drawGrid(xaxis, yaxis, p1, p2, scale, shift, xticks, yticks,
|
|
numYLabels)
|
|
else:
|
|
self._drawAxes(xaxis, yaxis, p1, p2, scale, shift, xticks, yticks)
|
|
graphics.fitToScale(scale, shift)
|
|
graphics.draw(self.canvas)
|
|
|
|
###############################################################################
|
|
if __name__ == '__main__':
|
|
root = Tk()
|
|
root.title('Graph Widget - Bar Graph')
|
|
|
|
data = [(0,30),(1,145),(2,151),(3,147),(4,22),(5,31),
|
|
(6,77),(7,125),(8,220),(9,550),(10,560),(11,340)]
|
|
data2 = [(0,30,30),(1,145,145),(2,151,151),(3,147,160),(4,22,50),(5,31,31),
|
|
(6,77,77),(7,125,160),(8,220,220),(9,550,700),(10,560,680),(11,340,340)]
|
|
data3 = [0, 1, 4, 8]
|
|
winds = [{'dd': 0, 'ff': 0}, {'dd': 30, 'ff': 24, 'gg': 35}, \
|
|
{'dd': 210, 'ff': 12}, {'dd': 330, 'ff': 65}]
|
|
xaxis = ((-0.5, ''),)+tuple([(d[0], str(d[0])+'.') for d in data])+\
|
|
((11.5, ''),)
|
|
# xaxis = ((-0.5, ''),)+tuple([(d, str(d)+'.') for d in data3])+((8.5, ''),)
|
|
# line1 = Bars(data, fill='green', size='auto')
|
|
line1 = Line(data, color='red', width=1, smooth=0)
|
|
# line2 = Steps(data, color='blue', width=1)
|
|
line2 = StepsRange(data2, fill='blue')
|
|
line3 = Winds(data3, winds, fill='red')
|
|
|
|
graphObject = Objects([line1])
|
|
|
|
f = Frame(root)
|
|
graph = Graph(f, 500, 350, relief=SUNKEN, background='gray90',
|
|
font='helvb17gr', border=2)
|
|
graph.pack(side=LEFT, fill='both', expand='yes')
|
|
graph.draw(graphObject, xaxis, 'auto', grid=True)
|
|
f.pack(side=TOP, expand='yes', fill='both')
|
|
|
|
Button(root, text='Clear', command=graph.clear).pack(side=LEFT)
|
|
Button(root, text='Quit', command=root.quit).pack(side=RIGHT)
|
|
|
|
root.mainloop()
|