author  robin <robin@reportlab.com> 
Tue, 07 Mar 2017 10:00:34 +0000  
changeset 4330  617ffa6bbdc8 
parent 4252  fe660f227cac 
child 4370  823a8c33ce43 
permissions  rwrr 
4330  1 
#Copyright ReportLab Europe Ltd. 20002017 
1555  2 
#see license.txt for license details 
2332  3 
#history http://www.reportlab.co.uk/cgibin/viewcvs.cgi/public/reportlab/trunk/reportlab/graphics/charts/utils.py 
3032  4 

4252  5 
__version__='3.3.0' 
3032  6 
__doc__="Utilities used here and there." 
827  7 
from time import mktime, gmtime, strftime 
3566  8 
from math import log10, pi, floor, sin, cos, sqrt, hypot 
3534  9 
import weakref 
4116
cf49463fc067
Fix a bunch of undefined names. Mostly typos or missing imports.
Matthew Duggan <mgithub@guarana.org>
parents:
3721
diff
changeset

10 
from reportlab.graphics.shapes import transformPoint, transformPoints, inverse, Ellipse, Group, String, Path, numericXShift 
3534  11 
from reportlab.lib.utils import flatten 
12 
from reportlab.pdfbase.pdfmetrics import stringWidth 

827  13 

832  14 
### Dinu's stuff used in some line plots (likely to vansih). 
827  15 
def mkTimeTuple(timeString): 
16 
"Convert a 'dd/mm/yyyy' formatted string to a tuple for use in the time module." 

17 

18 
list = [0] * 9 

3721  19 
dd, mm, yyyy = list(map(int, timeString.split('/'))) 
827  20 
list[:3] = [yyyy, mm, dd] 
1683  21 

827  22 
return tuple(list) 
23 

24 
def str2seconds(timeString): 

25 
"Convert a number of seconds since the epoch into a date string." 

26 

27 
return mktime(mkTimeTuple(timeString)) 

28 

29 
def seconds2str(seconds): 

30 
"Convert a date string into the number of seconds since the epoch." 

31 

32 
return strftime('%Y%m%d', gmtime(seconds)) 

33 

832  34 
### Aaron's rounding function for making nice values on axes. 
827  35 
def nextRoundNumber(x): 
36 
"""Return the first 'nice round number' greater than or equal to x 

37 

38 
Used in selecting apropriate tick mark intervals; we say we want 

39 
an interval which places ticks at least 10 points apart, work out 

40 
what that is in chart space, and ask for the nextRoundNumber(). 

41 
Tries the series 1,2,5,10,20,50,100.., going up or down as needed. 

42 
""" 

1683  43 

827  44 
#guess to nearest order of magnitude 
45 
if x in (0, 1): 

46 
return x 

47 

48 
if x < 0: 

49 
return 1.0 * nextRoundNumber(x) 

50 
else: 

51 
lg = int(log10(x)) 

52 

53 
if lg == 0: 

54 
if x < 1: 

55 
base = 0.1 

56 
else: 

57 
base = 1.0 

58 
elif lg < 0: 

59 
base = 10.0 ** (lg  1) 

60 
else: 

61 
base = 10.0 ** lg # e.g. base(153) = 100 

62 
# base will always be lower than x 

63 

64 
if base >= x: 

65 
return base * 1.0 

66 
elif (base * 2) >= x: 

67 
return base * 2.0 

68 
elif (base * 5) >= x: 

69 
return base * 5.0 

70 
else: 

71 
return base * 10.0 

832  72 

73 
_intervals=(.1, .2, .25, .5) 

74 
_j_max=len(_intervals)1 

75 
def find_interval(lo,hi,I=5): 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

76 
'determine tick parameters for range [lo, hi] using I intervals' 
832  77 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

78 
if lo >= hi: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

79 
if lo==hi: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

80 
if lo==0: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

81 
lo = .1 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

82 
hi = .1 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

83 
else: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

84 
lo = 0.9*lo 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

85 
hi = 1.1*hi 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

86 
else: 
3721  87 
raise ValueError("lo>hi") 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

88 
x=(hi  lo)/float(I) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

89 
b= (x>0 and (x<1 or x>10)) and 10**floor(log10(x)) or 1 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

90 
b = b 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

91 
while 1: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

92 
a = x/b 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

93 
if a<=_intervals[1]: break 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

94 
b = b*10 
832  95 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

96 
j = 0 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

97 
while a>_intervals[j]: j = j + 1 
832  98 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

99 
while 1: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

100 
ss = _intervals[j]*b 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

101 
n = lo/ss 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

102 
l = int(n)(n<0) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

103 
n = ss*l 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

104 
x = ss*(l+I) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

105 
a = I*ss 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

106 
if n>0: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

107 
if a>=hi: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

108 
n = 0.0 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

109 
x = a 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

110 
elif hi<0: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

111 
a = a 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

112 
if lo>a: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

113 
n = a 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

114 
x = 0 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

115 
if hi<=x and n<=lo: break 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

116 
j = j + 1 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

117 
if j>_j_max: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

118 
j = 0 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

119 
b = b*10 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

120 
return n, x, ss, lo  n + x  hi 
832  121 

1331  122 
def find_good_grid(lower,upper,n=(4,5,6,7,8,9), grid=None): 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

123 
if grid: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

124 
t = divmod(lower,grid)[0] * grid 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

125 
hi, z = divmod(upper,grid) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

126 
if z>1e8: hi = hi+1 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

127 
hi = hi*grid 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

128 
else: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

129 
try: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

130 
n[0] 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

131 
except TypeError: 
3721  132 
n = range(max(1,n2),max(n+3,2)) 
832  133 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

134 
w = 1e308 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

135 
for i in n: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

136 
z=find_interval(lower,upper,i) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

137 
if z[3]<w: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

138 
t, hi, grid = z[:3] 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

139 
w=z[3] 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

140 
return t, hi, grid 
832  141 

3412
8f046ab1b050
axes.py: add support for labelVOffset to AdjYValueAxis
rgbecker
parents:
3393
diff
changeset

142 
def ticks(lower, upper, n=(4,5,6,7,8,9), split=1, percent=0, grid=None, labelVOffset=0): 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

143 
''' 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

144 
return tick positions and labels for range lower<=x<=upper 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

145 
n=number of intervals to try (can be a list or sequence) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

146 
split=1 return ticks then labels else (tick,label) pairs 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

147 
''' 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

148 
t, hi, grid = find_good_grid(lower, upper, n, grid) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

149 
power = floor(log10(grid)) 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

150 
if power==0: power = 1 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

151 
w = grid/10.**power 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

152 
w = int(w)!=w 
1683  153 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

154 
if power > 3 or power < 3: 
3326  155 
format = '%+'+repr(w+7)+'.0e' 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

156 
else: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

157 
if power >= 0: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

158 
digits = int(power)+w 
3326  159 
format = '%' + repr(digits)+'.0f' 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

160 
else: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

161 
digits = wint(power) 
3326  162 
format = '%'+repr(digits+2)+'.'+repr(digits)+'f' 
1683  163 

1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

164 
if percent: format=format+'%%' 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

165 
T = [] 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

166 
n = int(float(hit)/grid+0.1)+1 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

167 
if split: 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

168 
labels = [] 
3721  169 
for i in range(n): 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

170 
v = t+grid*i 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

171 
T.append(v) 
3412
8f046ab1b050
axes.py: add support for labelVOffset to AdjYValueAxis
rgbecker
parents:
3393
diff
changeset

172 
labels.append(format % (v+labelVOffset)) 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

173 
return T, labels 
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

174 
else: 
3721  175 
for i in range(n): 
1677
1450177dd19e
Exterminated all tab characters and added a test to make sure
andy_robinson
parents:
1557
diff
changeset

176 
v = t+grid*i 
3412
8f046ab1b050
axes.py: add support for labelVOffset to AdjYValueAxis
rgbecker
parents:
3393
diff
changeset

177 
T.append((v, format % (v+labelVOffset))) 
2846  178 
return T 
179 

180 
def findNones(data): 

3019  181 
m = len(data) 
2846  182 
if None in data: 
183 
b = 0 

184 
while b<m and data[b] is None: 

185 
b += 1 

186 
if b==m: return data 

3019  187 
l = m1 
188 
while data[l] is None: 

189 
l = 1 

190 
l+=1 

191 
if b or l: data = data[b:l] 

3721  192 
I = [i for i in range(len(data)) if data[i] is None] 
2846  193 
for i in I: 
194 
data[i] = 0.5*(data[i1]+data[i+1]) 

195 
return b, l, data 

3019  196 
return 0,m,data 
2846  197 

198 
def pairFixNones(pairs): 

199 
Y = [x[1] for x in pairs] 

200 
b,l,nY = findNones(Y) 

3019  201 
m = len(Y) 
202 
if b or l<m or nY!=Y: 

203 
if b or l<m: pairs = pairs[b:l] 

2847
437c2e2335f2
graphics: fix utils and factorize some axis behaviour
rgbecker
parents:
2846
diff
changeset

204 
pairs = [(x[0],y) for x,y in zip(pairs,nY)] 
2846  205 
return pairs 
206 

207 
def maverage(data,n=6): 

2847
437c2e2335f2
graphics: fix utils and factorize some axis behaviour
rgbecker
parents:
2846
diff
changeset

208 
data = (n1)*[data[0]]+data 
3721  209 
data = [float(sum(data[in:i]))/n for i in range(n,len(data)+1)] 
2846  210 
return data 
211 

212 
def pairMaverage(data,n=6): 

213 
return [(x[0],s) for x,s in zip(data, maverage([x[1] for x in data],n))] 

3385  214 

3387  215 
class DrawTimeCollector(object): 
3385  216 
''' 
217 
generic mechanism for collecting information about nodes at the time they are about to be drawn 

218 
''' 

3388
793d353cbc08
shapes.py, utils.py more support for draw time collector
rgbecker
parents:
3387
diff
changeset

219 
def __init__(self,formats=['gif']): 
3385  220 
self._nodes = weakref.WeakKeyDictionary() 
221 
self.clear() 

3387  222 
self._pmcanv = None 
3393
1a1c9637d79f
graphics: minor changes to drawTimeCollector support
rgbecker
parents:
3390
diff
changeset

223 
self.formats = formats 
1a1c9637d79f
graphics: minor changes to drawTimeCollector support
rgbecker
parents:
3390
diff
changeset

224 
self.disabled = False 
3385  225 

226 
def clear(self): 

227 
self._info = [] 

228 
self._info_append = self._info.append 

229 

230 
def record(self,func,node,*args,**kwds): 

231 
self._nodes[node] = (func,args,kwds) 

232 
node.__dict__['_drawTimeCallback'] = self 

233 

234 
def __call__(self,node,canvas,renderer): 

235 
func = self._nodes.get(node,None) 

236 
if func: 

237 
func, args, kwds = func 

238 
i = func(node,canvas,renderer, *args, **kwds) 

239 
if i is not None: self._info_append(i) 

240 

241 
@staticmethod 

242 
def rectDrawTimeCallback(node,canvas,renderer,**kwds): 

243 
A = getattr(canvas,'ctm',None) 

244 
if not A: return 

245 
x1 = node.x 

246 
y1 = node.y 

247 
x2 = x1 + node.width 

248 
y2 = y1 + node.height 

249 

250 
D = kwds.copy() 

3387  251 
D['rect']=DrawTimeCollector.transformAndFlatten(A,((x1,y1),(x2,y2))) 
3385  252 
return D 
3387  253 

254 
@staticmethod 

255 
def transformAndFlatten(A,p): 

256 
''' transform an flatten a list of points 

257 
A transformation matrix 

258 
p points [(x0,y0),....(xk,yk).....] 

259 
''' 

260 
if tuple(A)!=(1,0,0,1,0,0): 

261 
iA = inverse(A) 

262 
p = transformPoints(iA,p) 

263 
return tuple(flatten(p)) 

264 

265 
@property 

266 
def pmcanv(self): 

267 
if not self._pmcanv: 

268 
import renderPM 

269 
self._pmcanv = renderPM.PMCanvas(1,1) 

270 
return self._pmcanv 

271 

272 
def wedgeDrawTimeCallback(self,node,canvas,renderer,**kwds): 

273 
A = getattr(canvas,'ctm',None) 

274 
if not A: return 

275 
if isinstance(node,Ellipse): 

276 
c = self.pmcanv 

277 
c.ellipse(node.cx, node.cy, node.rx,node.ry) 

278 
p = c.vpath 

279 
p = [(x[1],x[2]) for x in p] 

280 
else: 

281 
p = node.asPolygon().points 

3721  282 
p = [(p[i],p[i+1]) for i in range(0,len(p),2)] 
3387  283 

284 
D = kwds.copy() 

285 
D['poly'] = self.transformAndFlatten(A,p) 

286 
return D 

3388
793d353cbc08
shapes.py, utils.py more support for draw time collector
rgbecker
parents:
3387
diff
changeset

287 

793d353cbc08
shapes.py, utils.py more support for draw time collector
rgbecker
parents:
3387
diff
changeset

288 
def save(self,fnroot): 
793d353cbc08
shapes.py, utils.py more support for draw time collector
rgbecker
parents:
3387
diff
changeset

289 
''' 
793d353cbc08
shapes.py, utils.py more support for draw time collector
rgbecker
parents:
3387
diff
changeset

290 
save the current information known to this collector 
793d353cbc08
shapes.py, utils.py more support for draw time collector
rgbecker
parents:
3387
diff
changeset

291 
fnroot is the root name of a resource to name the saved info 
793d353cbc08
shapes.py, utils.py more support for draw time collector
rgbecker
parents:
3387
diff
changeset

292 
override this to get the right semantics for your collector 
793d353cbc08
shapes.py, utils.py more support for draw time collector
rgbecker
parents:
3387
diff
changeset

293 
''' 
793d353cbc08
shapes.py, utils.py more support for draw time collector
rgbecker
parents:
3387
diff
changeset

294 
import pprint 
793d353cbc08
shapes.py, utils.py more support for draw time collector
rgbecker
parents:
3387
diff
changeset

295 
f=open(fnroot+'.defaultcollector.out','w') 
793d353cbc08
shapes.py, utils.py more support for draw time collector
rgbecker
parents:
3387
diff
changeset

296 
try: 
793d353cbc08
shapes.py, utils.py more support for draw time collector
rgbecker
parents:
3387
diff
changeset

297 
pprint.pprint(self._info,f) 
793d353cbc08
shapes.py, utils.py more support for draw time collector
rgbecker
parents:
3387
diff
changeset

298 
finally: 
793d353cbc08
shapes.py, utils.py more support for draw time collector
rgbecker
parents:
3387
diff
changeset

299 
f.close() 
3532
8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

300 

3721  301 
def xyDist(xxx_todo_changeme, xxx_todo_changeme1 ): 
3532
8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

302 
'''return distance between two points''' 
3721  303 
(x0,y0) = xxx_todo_changeme 
304 
(x1,y1) = xxx_todo_changeme1 

3566  305 
return hypot((x1x0),(y1y0)) 
3532
8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

306 

3721  307 
def lineSegmentIntersect(xxx_todo_changeme2, xxx_todo_changeme3, xxx_todo_changeme4, xxx_todo_changeme5 
3532
8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

308 
): 
3721  309 
(x00,y00) = xxx_todo_changeme2 
310 
(x01,y01) = xxx_todo_changeme3 

311 
(x10,y10) = xxx_todo_changeme4 

312 
(x11,y11) = xxx_todo_changeme5 

3532
8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

313 
p = x00,y00 
8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

314 
r = x01x00,y01y00 
8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

315 

8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

316 

8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

317 
q = x10,y10 
8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

318 
s = x11x10,y11y10 
8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

319 

8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

320 
rs = float(r[0]*s[1]r[1]*s[0]) 
8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

321 
qp = q[0]p[0],q[1]p[1] 
8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

322 

8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

323 
qpr = qp[0]*r[1]qp[1]*r[0] 
8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

324 
qps = qp[0]*s[1]qp[1]*s[0] 
8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

325 

8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

326 
if abs(rs)<1e8: 
8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

327 
if abs(qpr)<1e8: return 'collinear' 
8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

328 
return None 
8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

329 

8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

330 
t = qps/rs 
8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

331 
u = qpr/rs 
8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

332 

8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

333 
if 0<=t<=1 and 0<=u<=1: 
8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset

334 
return p[0]+t*r[0], p[1]+t*r[1] 
3534  335 

336 
def makeCircularString(x, y, radius, angle, text, fontName, fontSize, inside=0, G=None,textAnchor='start'): 

337 
'''make a group with circular text in it''' 

338 
if not G: G = Group() 

339 

340 
angle %= 360 

341 
pi180 = pi/180 

342 
phi = angle*pi180 

343 
width = stringWidth(text, fontName, fontSize) 

344 
sig = inside and 1 or 1 

345 
hsig = sig*0.5 

346 
sig90 = sig*90 

347 

348 
if textAnchor!='start': 

349 
if textAnchor=='middle': 

350 
phi += sig*(0.5*width)/radius 

351 
elif textAnchor=='end': 

352 
phi += sig*float(width)/radius 

353 
elif textAnchor=='numeric': 

354 
phi += sig*float(numericXShift(textAnchor,text,width,fontName,fontSize,None))/radius 

355 

356 
for letter in text: 

357 
width = stringWidth(letter, fontName, fontSize) 

358 
beta = float(width)/radius 

359 
h = Group() 

360 
h.add(String(0, 0, letter, fontName=fontName,fontSize=fontSize,textAnchor="start")) 

361 
h.translate(x+cos(phi)*radius,y+sin(phi)*radius) #translate to radius and angle 

362 
h.rotate((phihsig*beta)/pi180sig90) # rotate as needed 

363 
G.add(h) #add to main group 

364 
phi = sig*beta #increment 

365 

366 
return G 

3645  367 

368 
class CustomDrawChanger: 

369 
''' 

370 
a class to simplify making changes at draw time 

371 
''' 

372 
def __init__(self): 

373 
self.store = None 

374 

375 
def __call__(self,change,obj): 

376 
if change: 

377 
self.store = self._changer(obj) 

378 
assert isinstance(self.store,dict), '%s.changer should return a dict of changed attributes' % self.__class__.__name__ 

379 
elif self.store is not None: 

3721  380 
for a,v in self.store.items(): 
3645  381 
setattr(obj,a,v) 
382 
self.store = None 

383 

384 
def _changer(self,obj): 

385 
''' 

386 
When implemented this method should return a dictionary of 

387 
original attribute values so that a future self(False,obj) 

388 
can restore them. 

389 
''' 

390 
raise RuntimeError('Abstract method _changer called') 