author | robin <robin@reportlab.com> |
Tue, 07 Mar 2017 10:00:34 +0000 | |
changeset 4330 | 617ffa6bbdc8 |
parent 4252 | fe660f227cac |
child 4370 | 823a8c33ce43 |
permissions | -rw-r--r-- |
4330 | 1 |
#Copyright ReportLab Europe Ltd. 2000-2017 |
1555 | 2 |
#see license.txt for license details |
2332 | 3 |
#history http://www.reportlab.co.uk/cgi-bin/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>1e-8: 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,n-2),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 = w-int(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(hi-t)/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 = m-1 |
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[i-1]+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 = (n-1)*[data[0]]+data |
3721 | 209 |
data = [float(sum(data[i-n: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+'.default-collector.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((x1-x0),(y1-y0)) |
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 = x01-x00,y01-y00 |
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 = x11-x10,y11-y10 |
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)<1e-8: |
8f3fe2729f66
charts/utils.py: added xyDist & lineSegmentIntersect
rgbecker
parents:
3412
diff
changeset
|
327 |
if abs(qpr)<1e-8: 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((phi-hsig*beta)/pi180-sig90) # 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') |