diff 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
line wrap: on
line diff
--- a/py/stats2.py	Sun May 11 08:32:31 2014 -0700
+++ b/py/stats2.py	Mon May 26 19:50:02 2014 -0700
@@ -26,12 +26,19 @@
  stroke-width:2;
  stroke-opacity:1;
 }}
+g.bar3d polygon {{
+ fill:#{0};
+ fill-opacity:1;
+ stroke:#000000;
+ stroke-width:1;
+ stroke-opacity:1;
+}}
 </style>
 """
 framerect = '<rect width="750" height="500" x="100" y="50" class="frame"/>\n'
 barstr = '<rect width="{0}" height="{1}" x="{2}" y="{3}" class="bar"/>\n'
 xllabel = '<text x="{0}" y="570" font-size="15" text-anchor="middle">{1}</text>\n'
-ylabel = '<text x="90" y="{0}" font-size="16" text-anchor="end">{1}</text>\n'
+ylabel = '<text x="90" y="{0:.2f}" font-size="16" text-anchor="end">{1}</text>\n'
 xlabelf = '<text x="475" y="590" font-size="15" text-anchor="middle">{0}</text>\n'
 ltitle = '<text x="100" y="35" font-size="16" text-anchor="start">{0}</text>\n'
 ctitle = '<text x="475" y="34" font-size="18" text-anchor="middle">{0}</text>\n'
@@ -43,6 +50,28 @@
 </g>
 """
 
+def makepolygon(coords):
+  points = [ "{0:.2f},{1:.2f}".format(pt[0], pt[1]) for pt in coords ]
+  pointstr = " ".join(points)
+  return '<polygon points="{}"/>\n'.format(pointstr)
+
+def bar3d(x, w, h):
+  ydelta = w / 2
+  xdelta = ydelta / 3
+  flowerleft = (x, 550)
+  flowerright = (x + w, 550)
+  fupperleft = (x, 550 - h)
+  fupperright = (x + w, 550 - h)
+  blowerright = (x + w + xdelta, 550 - ydelta)
+  bupperleft = (x + xdelta, 550 - h - ydelta)
+  bupperright = (x + w + xdelta, 550 - h - ydelta)
+  frontface = makepolygon([flowerleft, flowerright, fupperright, fupperleft])
+  rightface = makepolygon([blowerright, flowerright, fupperright, bupperright])
+  topface = makepolygon([bupperleft, bupperright, fupperright, fupperleft])
+  gopen = '<g class="bar3d" clip-path="url(#framer)">\n'
+  gclose = '</g>\n'
+  return gopen + "".join([frontface, rightface, topface]) + gclose
+
 class SVGChart():
   def __init__(self, filename):
     self.of = open(filename, "w", encoding="utf-8")
@@ -61,7 +90,7 @@
   size = 0
   while True:
     for i in ll:
-      if i * m > x:
+      if i * m > x * 1.1:
         size = i
         lim = i * m
         break
@@ -90,13 +119,17 @@
   xlgraph = SVGChart("{0}/xl-{1}.svg".format(svgpath, game.uname))
   xlgraph.style("0000ff")
   xlgraph.write(framerect)
+  xlgraph.write('<clipPath id="framer">\n')
+  xlgraph.write(framerect)
+  xlgraph.write('</clipPath>\n')
   xldivs, xlmax = ylimits(max([ pt[1] for pt in xldata ]))
   scale = 500 / xlmax
   for xl, count in xldata:
     barx = xl * 50 + 60
-    barh = round(scale * count)
+    barh = scale * count
     bary = 550 - barh
-    xlgraph.write(barstr.format(30, barh, barx, bary))
+    if count > 0:
+      xlgraph.write(bar3d(barx, 30, barh))
     xlgraph.write(xllabel.format(barx + 15, xl))
   for yl in range(xldivs + 1):
     labeln = int(xlmax * yl / xldivs)
@@ -116,14 +149,18 @@
   scoregraph = SVGChart("{0}/score-{1}.svg".format(svgpath, game.uname))
   scoregraph.style("ffff00")
   scoregraph.write(framerect)
+  scoregraph.write('<clipPath id="framer">\n')
+  scoregraph.write(framerect)
+  scoregraph.write('</clipPath>\n')
   scoredivs, scoremax = ylimits(max([ pt[1] for pt in scoredata ]))
   scale = 500 / scoremax
   for block, count in scoredata:
     n = block // scorewidth
     barx = n * 75 + 100
-    barh = round(scale * count)
+    barh = scale * count
     bary = 550 - barh
-    scoregraph.write(barstr.format(75, barh, barx, bary))
+    if count > 0:
+      scoregraph.write(bar3d(barx, 75, barh))
     scoregraph.write(xllabel.format(barx, block))
   for yl in range(scoredivs + 1):
     labeln = int(scoremax * yl / scoredivs)
@@ -139,13 +176,17 @@
   deepgraph = SVGChart("{0}/deep-{1}.svg".format(svgpath, game.uname))
   deepgraph.style("808000")
   deepgraph.write(framerect)
+  deepgraph.write('<clipPath id="framer">\n')
+  deepgraph.write(framerect)
+  deepgraph.write('</clipPath>\n')
   deepdivs, deepmax = ylimits(max([ pt[1] for pt in deepdata ]))
   scale = 500 / deepmax
   for lev, count in deepdata:
     barx = lev * 25 + 75
-    barh = round(scale * count)
+    barh = scale * count
     bary = 550 - barh
-    deepgraph.write(barstr.format(25, barh, barx, bary))
+    if count > 0:
+      deepgraph.write(bar3d(barx, 25, barh))
     if lev % 3 == 0:
       deepgraph.write(xllabel.format(barx + 12.5, lev))
   for yl in range(deepdivs + 1):