This commit is contained in:
Kovid Goyal 2009-05-10 17:54:18 -07:00
parent 3e9e6a63d7
commit a4243033e0

View File

@ -6,7 +6,7 @@ __docformat__ = 'restructuredtext en'
''' '''
Keep track of donations to calibre. Keep track of donations to calibre.
''' '''
import sys, cStringIO, textwrap, traceback, re, os, time import sys, cStringIO, textwrap, traceback, re, os, time, calendar
from datetime import date, timedelta from datetime import date, timedelta
from math import sqrt from math import sqrt
os.environ['HOME'] = '/tmp' os.environ['HOME'] = '/tmp'
@ -15,7 +15,6 @@ matplotlib.use('Agg')
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import matplotlib.dates as mdates import matplotlib.dates as mdates
import cherrypy import cherrypy
from lxml import etree from lxml import etree
@ -34,6 +33,12 @@ def range_for_month(year, month):
def range_for_year(year): def range_for_year(year):
return date(year=year, month=1, day=1), date(year=year, month=12, day=31) return date(year=year, month=1, day=1), date(year=year, month=12, day=31)
def days_in_month(year, month):
c = calendar.Calendar()
ans = 0
for x in c.itermonthdays(year, month):
if x != 0: ans += 1
return ans
def rationalize_country(country): def rationalize_country(country):
if re.match('(?i)(US|USA|America)', country): if re.match('(?i)(US|USA|America)', country):
@ -140,6 +145,23 @@ class Stats:
for country in self.countries.values(): for country in self.countries.values():
country.percent = (100 * country.total/self.total) if self.total else 0. country.percent = (100 * country.total/self.total) if self.total else 0.
def get_daily_averages(self):
month_buckets, month_order = {}, []
x = self.min
for t in self.daily_totals:
month = (x.year, x.month)
if month not in month_buckets:
month_buckets[month] = 0.
month_order.append(month)
month_buckets[month] += t
x += timedelta(days=1)
c = calendar.Calendar()
month_days = [days_in_month(*x) for x in month_order]
month_averages = [month_buckets[x]/float(y) for x, y in zip(month_order, month_days)]
return month_order, month_averages
def __str__(self): def __str__(self):
buf = cStringIO.StringIO() buf = cStringIO.StringIO()
print >>buf, '\tTotal: %.2f'%self.total print >>buf, '\tTotal: %.2f'%self.total
@ -187,6 +209,7 @@ class Server(object):
TRENDS = '/tmp/donations_trend.png' TRENDS = '/tmp/donations_trend.png'
MONTH_TRENDS = '/tmp/donations_month_trend.png' MONTH_TRENDS = '/tmp/donations_month_trend.png'
AVERAGES = '/tmp/donations_averages.png'
def __init__(self, apache=False, root='/', data_file='/tmp/donations.xml'): def __init__(self, apache=False, root='/', data_file='/tmp/donations.xml'):
self.apache = apache self.apache = apache
@ -194,6 +217,21 @@ class Server(object):
self.data_file = data_file self.data_file = data_file
self.read_records() self.read_records()
def calculate_daily_averages(self):
stats = self.get_slice(self.earliest, self.latest)
fig = plt.figure(2, (10, 4), 96)#, facecolor, edgecolor, frameon, FigureClass)
fig.clear()
ax = fig.add_subplot(111)
month_order, month_averages = stats.get_daily_averages()
x = [date(y, m, 1) for y, m in month_order[:-1]]
ax.plot(x, month_averages[:-1])
ax.set_xlabel('Month')
ax.set_ylabel('Daily average ($)')
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=2))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%m/%y'))
fig.savefig(self.AVERAGES)
def calculate_month_trend(self, days=31): def calculate_month_trend(self, days=31):
stats = self.get_slice(date.today()-timedelta(days=days-1), date.today()) stats = self.get_slice(date.today()-timedelta(days=days-1), date.today())
fig = plt.figure(2, (10, 4), 96)#, facecolor, edgecolor, frameon, FigureClass) fig = plt.figure(2, (10, 4), 96)#, facecolor, edgecolor, frameon, FigureClass)
@ -269,6 +307,7 @@ Donors per day: %(dpd).2f
self.earliest, self.latest = min_date, max_date self.earliest, self.latest = min_date, max_date
self.calculate_trend() self.calculate_trend()
self.calculate_month_trend() self.calculate_month_trend()
self.calculate_daily_averages()
def get_slice(self, start_date, end_date): def get_slice(self, start_date, end_date):
stats = Stats([r for r in self.records if r.date >= start_date and r.date <= end_date], stats = Stats([r for r in self.records if r.date >= start_date and r.date <= end_date],
@ -463,10 +502,13 @@ Donors per day: %(dpd).2f
</table> </table>
<hr /> <hr />
<div style="text-align:center"> <div style="text-align:center">
<h3>Income trends for the last year</h3>
<img src="%(root)strend.png" alt="Income trends" /> <img src="%(root)strend.png" alt="Income trends" />
<h3>Income trends for the last 31 days</h3> <h3>Income trends for the last year</h3>
<img src="%(root)smonth_trend.png" alt="Month income trend" /> <img src="%(root)smonth_trend.png" alt="Month income trend" />
<h3>Income trends for the last 31 days</h3>
<img src="%(root)saverage_trend.png" alt="Daily average
income trend" />
<h3>Income trends since records started</h3>
</div> </div>
</body> </body>
</html> </html>
@ -497,6 +539,11 @@ Donors per day: %(dpd).2f
cherrypy.response.headers['Content-Type'] = 'image/png' cherrypy.response.headers['Content-Type'] = 'image/png'
return open(self.MONTH_TRENDS, 'rb').read() return open(self.MONTH_TRENDS, 'rb').read()
@expose
def average_trend_png(self):
cherrypy.response.headers['Content-Type'] = 'image/png'
return open(self.AVERAGES, 'rb').read()
@expose @expose
def show(self, period_type='month', month_month='', month_year='', def show(self, period_type='month', month_month='', month_year='',
year_year='', range_left='', range_right=''): year_year='', range_left='', range_right=''):