comparison py/stats2.py @ 56:5cf88bd4e556

stats2.py: add some 3D perspective to the graphs.
author John "Elwin" Edwards
date Mon, 26 May 2014 19:50:02 -0700
parents 0f4163dbbafc
children 876786c55450
comparison
equal deleted inserted replaced
55:e421ea2519ec 56:5cf88bd4e556
24 fill-opacity:1; 24 fill-opacity:1;
25 stroke:#000000; 25 stroke:#000000;
26 stroke-width:2; 26 stroke-width:2;
27 stroke-opacity:1; 27 stroke-opacity:1;
28 }} 28 }}
29 g.bar3d polygon {{
30 fill:#{0};
31 fill-opacity:1;
32 stroke:#000000;
33 stroke-width:1;
34 stroke-opacity:1;
35 }}
29 </style> 36 </style>
30 """ 37 """
31 framerect = '<rect width="750" height="500" x="100" y="50" class="frame"/>\n' 38 framerect = '<rect width="750" height="500" x="100" y="50" class="frame"/>\n'
32 barstr = '<rect width="{0}" height="{1}" x="{2}" y="{3}" class="bar"/>\n' 39 barstr = '<rect width="{0}" height="{1}" x="{2}" y="{3}" class="bar"/>\n'
33 xllabel = '<text x="{0}" y="570" font-size="15" text-anchor="middle">{1}</text>\n' 40 xllabel = '<text x="{0}" y="570" font-size="15" text-anchor="middle">{1}</text>\n'
34 ylabel = '<text x="90" y="{0}" font-size="16" text-anchor="end">{1}</text>\n' 41 ylabel = '<text x="90" y="{0:.2f}" font-size="16" text-anchor="end">{1}</text>\n'
35 xlabelf = '<text x="475" y="590" font-size="15" text-anchor="middle">{0}</text>\n' 42 xlabelf = '<text x="475" y="590" font-size="15" text-anchor="middle">{0}</text>\n'
36 ltitle = '<text x="100" y="35" font-size="16" text-anchor="start">{0}</text>\n' 43 ltitle = '<text x="100" y="35" font-size="16" text-anchor="start">{0}</text>\n'
37 ctitle = '<text x="475" y="34" font-size="18" text-anchor="middle">{0}</text>\n' 44 ctitle = '<text x="475" y="34" font-size="18" text-anchor="middle">{0}</text>\n'
38 rtitle = '<text x="850" y="35" font-size="16" text-anchor="end">{0}</text>\n' 45 rtitle = '<text x="850" y="35" font-size="16" text-anchor="end">{0}</text>\n'
39 ylabelf = """<g transform="translate(100, 300)"> 46 ylabelf = """<g transform="translate(100, 300)">
40 <g transform="rotate(-90)"> 47 <g transform="rotate(-90)">
41 <text x="0" y="-60" font-size="16" text-anchor="middle">{0}</text> 48 <text x="0" y="-60" font-size="16" text-anchor="middle">{0}</text>
42 </g> 49 </g>
43 </g> 50 </g>
44 """ 51 """
52
53 def makepolygon(coords):
54 points = [ "{0:.2f},{1:.2f}".format(pt[0], pt[1]) for pt in coords ]
55 pointstr = " ".join(points)
56 return '<polygon points="{}"/>\n'.format(pointstr)
57
58 def bar3d(x, w, h):
59 ydelta = w / 2
60 xdelta = ydelta / 3
61 flowerleft = (x, 550)
62 flowerright = (x + w, 550)
63 fupperleft = (x, 550 - h)
64 fupperright = (x + w, 550 - h)
65 blowerright = (x + w + xdelta, 550 - ydelta)
66 bupperleft = (x + xdelta, 550 - h - ydelta)
67 bupperright = (x + w + xdelta, 550 - h - ydelta)
68 frontface = makepolygon([flowerleft, flowerright, fupperright, fupperleft])
69 rightface = makepolygon([blowerright, flowerright, fupperright, bupperright])
70 topface = makepolygon([bupperleft, bupperright, fupperright, fupperleft])
71 gopen = '<g class="bar3d" clip-path="url(#framer)">\n'
72 gclose = '</g>\n'
73 return gopen + "".join([frontface, rightface, topface]) + gclose
45 74
46 class SVGChart(): 75 class SVGChart():
47 def __init__(self, filename): 76 def __init__(self, filename):
48 self.of = open(filename, "w", encoding="utf-8") 77 self.of = open(filename, "w", encoding="utf-8")
49 self.of.write(dochead) 78 self.of.write(dochead)
59 ll = [2, 3, 4, 5, 6, 8, 10, 15] 88 ll = [2, 3, 4, 5, 6, 8, 10, 15]
60 m = 1 89 m = 1
61 size = 0 90 size = 0
62 while True: 91 while True:
63 for i in ll: 92 for i in ll:
64 if i * m > x: 93 if i * m > x * 1.1:
65 size = i 94 size = i
66 lim = i * m 95 lim = i * m
67 break 96 break
68 if size: 97 if size:
69 break 98 break
88 117
89 def mkxlgraph(game, xldata): 118 def mkxlgraph(game, xldata):
90 xlgraph = SVGChart("{0}/xl-{1}.svg".format(svgpath, game.uname)) 119 xlgraph = SVGChart("{0}/xl-{1}.svg".format(svgpath, game.uname))
91 xlgraph.style("0000ff") 120 xlgraph.style("0000ff")
92 xlgraph.write(framerect) 121 xlgraph.write(framerect)
122 xlgraph.write('<clipPath id="framer">\n')
123 xlgraph.write(framerect)
124 xlgraph.write('</clipPath>\n')
93 xldivs, xlmax = ylimits(max([ pt[1] for pt in xldata ])) 125 xldivs, xlmax = ylimits(max([ pt[1] for pt in xldata ]))
94 scale = 500 / xlmax 126 scale = 500 / xlmax
95 for xl, count in xldata: 127 for xl, count in xldata:
96 barx = xl * 50 + 60 128 barx = xl * 50 + 60
97 barh = round(scale * count) 129 barh = scale * count
98 bary = 550 - barh 130 bary = 550 - barh
99 xlgraph.write(barstr.format(30, barh, barx, bary)) 131 if count > 0:
132 xlgraph.write(bar3d(barx, 30, barh))
100 xlgraph.write(xllabel.format(barx + 15, xl)) 133 xlgraph.write(xllabel.format(barx + 15, xl))
101 for yl in range(xldivs + 1): 134 for yl in range(xldivs + 1):
102 labeln = int(xlmax * yl / xldivs) 135 labeln = int(xlmax * yl / xldivs)
103 labelh = 550 + 8 - 500 * yl / xldivs 136 labelh = 550 + 8 - 500 * yl / xldivs
104 xlgraph.write(ylabel.format(labelh, labeln)) 137 xlgraph.write(ylabel.format(labelh, labeln))
114 else: 147 else:
115 scorewidth = 1000 148 scorewidth = 1000
116 scoregraph = SVGChart("{0}/score-{1}.svg".format(svgpath, game.uname)) 149 scoregraph = SVGChart("{0}/score-{1}.svg".format(svgpath, game.uname))
117 scoregraph.style("ffff00") 150 scoregraph.style("ffff00")
118 scoregraph.write(framerect) 151 scoregraph.write(framerect)
152 scoregraph.write('<clipPath id="framer">\n')
153 scoregraph.write(framerect)
154 scoregraph.write('</clipPath>\n')
119 scoredivs, scoremax = ylimits(max([ pt[1] for pt in scoredata ])) 155 scoredivs, scoremax = ylimits(max([ pt[1] for pt in scoredata ]))
120 scale = 500 / scoremax 156 scale = 500 / scoremax
121 for block, count in scoredata: 157 for block, count in scoredata:
122 n = block // scorewidth 158 n = block // scorewidth
123 barx = n * 75 + 100 159 barx = n * 75 + 100
124 barh = round(scale * count) 160 barh = scale * count
125 bary = 550 - barh 161 bary = 550 - barh
126 scoregraph.write(barstr.format(75, barh, barx, bary)) 162 if count > 0:
163 scoregraph.write(bar3d(barx, 75, barh))
127 scoregraph.write(xllabel.format(barx, block)) 164 scoregraph.write(xllabel.format(barx, block))
128 for yl in range(scoredivs + 1): 165 for yl in range(scoredivs + 1):
129 labeln = int(scoremax * yl / scoredivs) 166 labeln = int(scoremax * yl / scoredivs)
130 labelh = 550 + 8 - 500 * yl / scoredivs 167 labelh = 550 + 8 - 500 * yl / scoredivs
131 scoregraph.write(ylabel.format(labelh, labeln)) 168 scoregraph.write(ylabel.format(labelh, labeln))
137 174
138 def mkdeepgraph(game, deepdata): 175 def mkdeepgraph(game, deepdata):
139 deepgraph = SVGChart("{0}/deep-{1}.svg".format(svgpath, game.uname)) 176 deepgraph = SVGChart("{0}/deep-{1}.svg".format(svgpath, game.uname))
140 deepgraph.style("808000") 177 deepgraph.style("808000")
141 deepgraph.write(framerect) 178 deepgraph.write(framerect)
179 deepgraph.write('<clipPath id="framer">\n')
180 deepgraph.write(framerect)
181 deepgraph.write('</clipPath>\n')
142 deepdivs, deepmax = ylimits(max([ pt[1] for pt in deepdata ])) 182 deepdivs, deepmax = ylimits(max([ pt[1] for pt in deepdata ]))
143 scale = 500 / deepmax 183 scale = 500 / deepmax
144 for lev, count in deepdata: 184 for lev, count in deepdata:
145 barx = lev * 25 + 75 185 barx = lev * 25 + 75
146 barh = round(scale * count) 186 barh = scale * count
147 bary = 550 - barh 187 bary = 550 - barh
148 deepgraph.write(barstr.format(25, barh, barx, bary)) 188 if count > 0:
189 deepgraph.write(bar3d(barx, 25, barh))
149 if lev % 3 == 0: 190 if lev % 3 == 0:
150 deepgraph.write(xllabel.format(barx + 12.5, lev)) 191 deepgraph.write(xllabel.format(barx + 12.5, lev))
151 for yl in range(deepdivs + 1): 192 for yl in range(deepdivs + 1):
152 labeln = int(deepmax * yl / deepdivs) 193 labeln = int(deepmax * yl / deepdivs)
153 labelh = 550 + 8 - 500 * yl / deepdivs 194 labelh = 550 + 8 - 500 * yl / deepdivs