changeset 38:d2c3c29ca4f9

Add a new statistics script that creates SVG plots.
author John "Elwin" Edwards
date Fri, 10 Jan 2014 07:15:39 -0500
parents c045d4dcf88a
children a97a20571526
files lighttpd/conf.d/mime.conf py/stats2.py web/scoring/index.html web/scoring/scores.css
diffstat 4 files changed, 240 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lighttpd/conf.d/mime.conf	Fri Jan 10 07:15:39 2014 -0500
@@ -0,0 +1,78 @@
+#######################################################################
+##
+##  MimeType handling
+## -------------------
+##
+## http://www.lighttpd.net/documentation/configuration.html#mimetypes
+##
+## Use the "Content-Type" extended attribute to obtain mime type if
+## possible
+##
+mimetype.use-xattr        = "disable"
+
+##
+## mimetype mapping
+##
+mimetype.assign             = (
+  ".pdf"          =>      "application/pdf",
+  ".sig"          =>      "application/pgp-signature",
+  ".spl"          =>      "application/futuresplash",
+  ".class"        =>      "application/octet-stream",
+  ".ps"           =>      "application/postscript",
+  ".torrent"      =>      "application/x-bittorrent",
+  ".dvi"          =>      "application/x-dvi",
+  ".gz"           =>      "application/x-gzip",
+  ".pac"          =>      "application/x-ns-proxy-autoconfig",
+  ".swf"          =>      "application/x-shockwave-flash",
+  ".tar.gz"       =>      "application/x-tgz",
+  ".tgz"          =>      "application/x-tgz",
+  ".tar"          =>      "application/x-tar",
+  ".zip"          =>      "application/zip",
+  ".mp3"          =>      "audio/mpeg",
+  ".m3u"          =>      "audio/x-mpegurl",
+  ".wma"          =>      "audio/x-ms-wma",
+  ".wax"          =>      "audio/x-ms-wax",
+  ".ogg"          =>      "application/ogg",
+  ".wav"          =>      "audio/x-wav",
+  ".gif"          =>      "image/gif",
+  ".jpg"          =>      "image/jpeg",
+  ".jpeg"         =>      "image/jpeg",
+  ".png"          =>      "image/png",
+  ".svg"          =>      "image/svg+xml",
+  ".xbm"          =>      "image/x-xbitmap",
+  ".xpm"          =>      "image/x-xpixmap",
+  ".xwd"          =>      "image/x-xwindowdump",
+  ".css"          =>      "text/css",
+  ".html"         =>      "text/html",
+  ".htm"          =>      "text/html",
+  ".js"           =>      "text/javascript",
+  ".asc"          =>      "text/plain",
+  ".c"            =>      "text/plain",
+  ".cpp"          =>      "text/plain",
+  ".log"          =>      "text/plain",
+  ".conf"         =>      "text/plain",
+  ".text"         =>      "text/plain",
+  ".txt"          =>      "text/plain",
+  ".spec"         =>      "text/plain",
+  ".dtd"          =>      "text/xml",
+  ".xml"          =>      "text/xml",
+  ".mpeg"         =>      "video/mpeg",
+  ".mpg"          =>      "video/mpeg",
+  ".mov"          =>      "video/quicktime",
+  ".qt"           =>      "video/quicktime",
+  ".avi"          =>      "video/x-msvideo",
+  ".asf"          =>      "video/x-ms-asf",
+  ".asx"          =>      "video/x-ms-asf",
+  ".wmv"          =>      "video/x-ms-wmv",
+  ".bz2"          =>      "application/x-bzip",
+  ".tbz"          =>      "application/x-bzip-compressed-tar",
+  ".tar.bz2"      =>      "application/x-bzip-compressed-tar",
+  ".rpm"          =>      "application/x-rpm",
+  # make the default mime type application/octet-stream.
+  ""              =>      "application/octet-stream",
+ )
+
+
+#
+#######################################################################
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/py/stats2.py	Fri Jan 10 07:15:39 2014 -0500
@@ -0,0 +1,147 @@
+#!/usr/bin/python3
+
+import psycopg2
+import rlgall
+from datetime import datetime
+
+sitename = "rlgallery.org"
+svgpath = rlgall.webdir
+timestr = datetime.utcnow().strftime("%Y-%m-%d %H:%M")
+
+dochead = """<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="900" height="600">
+"""
+stylesheet = """<style type="text/css">
+rect.frame {{
+ fill:#ffffff;
+ fill-opacity:1;
+ stroke:#000000;
+ stroke-width:4;
+ stroke-opacity:1;
+}}
+rect.bar {{
+ fill:#{0};
+ fill-opacity:1;
+ stroke:#000000;
+ stroke-width:2;
+ 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'
+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'
+rtitle = '<text x="850" y="35" font-size="16" text-anchor="end">{0}</text>\n'
+ylabelf = """<g transform="translate(100, 300)">
+ <g transform="rotate(-90)">
+ <text x="0" y="-60" font-size="16" text-anchor="middle">{0}</text>
+ </g>
+</g>
+"""
+
+def ylimits(x):
+  ll = [2, 3, 4, 5, 6, 8, 10, 15]
+  m = 1
+  size = 0
+  while True:
+    for i in ll:
+      if i * m > x:
+        size = i
+        lim = i * m
+        break
+    if size:
+      break
+    else:
+      m *= 10
+  if size in [3, 6]:
+    if lim == 3:
+      divs = 3
+    else:
+      divs = 6
+  elif size in [4, 8]:
+    divs = 4
+  else:
+    if lim == 2:
+      divs = 2
+    else:
+      divs = 5
+  return divs, lim
+
+con = psycopg2.connect("dbname=rlg")
+cur = con.cursor()
+
+for game in rlgall.gamelist:
+  xlq = "SELECT count(*) FROM {0} WHERE xl = %s;".format(game.uname)
+  scrq = "SELECT count(*) FROM {0} WHERE score >= %s AND score < %s;".format(game.uname)
+  xls = range(1, 16)
+  scoreblocks = range(10)
+  xlcounts = []
+  scorecounts = []
+  for xl in xls:
+    cur.execute(xlq, [xl])
+    xlcounts.append(cur.fetchone()[0])
+  for sn in scoreblocks:
+    lscore = sn * 1000
+    if sn == 9:
+      hscore = 32000
+    else:
+      hscore = (sn + 1) * 1000
+    cur.execute(scrq, (lscore, hscore))
+    scorecounts.append(cur.fetchone()[0])
+  xlgraph = open("{0}/xl-{1}.svg".format(svgpath, game.uname), "w")
+  scoregraph = open("{0}/score-{1}.svg".format(svgpath, game.uname), "w")
+  xlgraph.write(dochead)
+  scoregraph.write(dochead)
+  xlgraph.write(stylesheet.format("0000ff"))
+  scoregraph.write(stylesheet.format("ffff00"))
+  xlgraph.write(framerect)
+  scoregraph.write(framerect)
+
+  xldivs, xlmax = ylimits(max(xlcounts))
+  scale = 500 / xlmax
+  for xl, count in zip(xls, xlcounts):
+    barx = xl * 50 + 60
+    barh = round(scale * count)
+    bary = 550 - barh
+    xlgraph.write(barstr.format(30, barh, barx, bary))
+    xlgraph.write(xllabel.format(barx + 15, xl))
+  for yl in range(xldivs + 1):
+    labeln = int(xlmax * yl / xldivs)
+    labelh = 550 + 8 - 500 * yl / xldivs
+    xlgraph.write(ylabel.format(labelh, labeln))
+
+  scoredivs, scoremax = ylimits(max(scorecounts))
+  scale = 500 / scoremax
+  for block, count in zip(scoreblocks, scorecounts):
+    barx = block * 75 + 100
+    barh = round(scale * count)
+    bary = 550 - barh
+    scoregraph.write(barstr.format(75, barh, barx, bary))
+    scoregraph.write(xllabel.format(barx, block * 1000))
+  for yl in range(scoredivs + 1):
+    labeln = int(scoremax * yl / scoredivs)
+    labelh = 550 + 8 - 500 * yl / scoredivs
+    scoregraph.write(ylabel.format(labelh, labeln))
+
+  xlgraph.write(xlabelf.format("Experience level"))
+  xlgraph.write(ylabelf.format("# of games"))
+  scoregraph.write(xlabelf.format("Score"))
+  scoregraph.write(ylabelf.format("# of games"))
+  xlgraph.write(ltitle.format(sitename))
+  xlgraph.write(ctitle.format(game.name))
+  xlgraph.write(rtitle.format(timestr))
+  scoregraph.write(ltitle.format(sitename))
+  scoregraph.write(ctitle.format(game.name))
+  scoregraph.write(rtitle.format(timestr))
+  xlgraph.write('</svg>\n')
+  xlgraph.close()
+  scoregraph.write('</svg>\n')
+  scoregraph.close()
+
+cur.close()
+con.close()
+exit()
--- a/web/scoring/index.html	Tue Jan 07 21:57:33 2014 -0500
+++ b/web/scoring/index.html	Fri Jan 10 07:15:39 2014 -0500
@@ -14,7 +14,18 @@
 <li><a href="./high.cgi">High Scores</a></li>
 <li><a href="./players/">Explorers</a></li>
 </ul>
+<h2>Statistics</h2>
 </div>
+<div class=graph><img src="./xl-rogue3.svg" alt="Rogue V3 experience"></div>
+<div class=graph><img src="./xl-rogue4.svg" alt="Rogue V4 experience"></div>
+<div class=graph><img src="./xl-rogue5.svg" alt="Rogue V5 experience"></div>
+<div class=graph><img src="./xl-srogue.svg" alt="Super-Rogue experience"></div>
+<div class=graph><img src="./xl-arogue5.svg" alt="Advanced Rogue 5 experience"></div>
+<div class=graph><img src="./score-rogue3.svg" alt="Rogue V3 scores"></div>
+<div class=graph><img src="./score-rogue4.svg" alt="Rogue V4 scores"></div>
+<div class=graph><img src="./score-rogue5.svg" alt="Rogue V5 scores"></div>
+<div class=graph><img src="./score-srogue.svg" alt="Super-Rogue scores"></div>
+<div class=graph><img src="./score-arogue5.svg" alt="Advanced Rogue 5 scores"></div>
 <div class="foot"><a href="/">rlgallery.org</a> <a href="/recent.cgi">Recent Games</a> <a href="/scoring/high.cgi">High Scores</a></div>
 </body>
 </html> 
--- a/web/scoring/scores.css	Tue Jan 07 21:57:33 2014 -0500
+++ b/web/scoring/scores.css	Fri Jan 10 07:15:39 2014 -0500
@@ -31,6 +31,10 @@
 	background-color: #FFE0E0;
 }
 
+div.graph {
+	margin: 1em auto;
+}
+
 span.shdata {
 	display: table-cell;
 	font-weight: bold;