+"""
+Generate various plots
+"""
+import matplotlib
+matplotlib.use('Agg')
+import matplotlib.pyplot as plt
+from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
+import numpy as np
+import datetime
+
+from cStringIO import StringIO
+from pylons import request, response
+
+from bluechips.lib.base import *
+import bluechips.lib.totals
+from bluechips import model
+from bluechips.model import meta, orm, User, Expenditure, Split, Transfer
+
+import time
+
+def get_share(transaction, user):
+ if type(transaction) == Expenditure:
+ amount = transaction.share(user)
+ if transaction.spender == user:
+ amount -= transaction.amount
+ return amount
+ else:
+ if user == transaction.debtor:
+ return -transaction.amount
+ elif user == transaction.creditor:
+ return transaction.amount
+ else:
+ return model.types.Currency(0)
+
+class GraphController(BaseController):
+ def balance(self):
+ """
+ Create a plot showing the net balance for each user over the
+ course of time.
+ """
+ t0 = time.time()
+ users = meta.Session.query(User).filter(User.resident==True).all()
+ expenditures = meta.Session.query(Expenditure).\
+ options(orm.eagerload_all(Expenditure.splits, Split.user)).\
+ all()
+ transfers = meta.Session.query(Transfer).\
+ options(orm.eagerload(Transfer.debtor, Transfer.creditor)).\
+ all()
+
+ transactions = expenditures + transfers
+ transactions.sort(key=lambda x: x.date)
+
+ t1 = time.time()
+ totals = dict()
+ dates = [t.date for t in transactions]
+ for u in users:
+ totals[u.name] = np.cumsum([get_share(t,u) for t in transactions])
+
+ t2 = time.time()
+ fig = plt.figure()
+ canvas = FigureCanvas(fig)
+ ax = fig.add_subplot(1,1,1)
+ ax.set_color_cycle(plt.cm.jet(np.linspace(0,1,len(users))))
+ lines = dict()
+ ymax = 0
+ for u,y in totals.items():
+ lines[u] = plt.step(dates,totals[u], label=u, lw=2)
+
+ ax.legend(loc='best')
+ ax.grid(True)
+ plt.axis('tight')
+ ax.set_xlim(xmin=datetime.date.today()-datetime.timedelta(days=365))
+ ax.set_ylim(ymin=0)
+ fig.autofmt_xdate(rotation=30)
+ ax.xaxis.set_major_formatter(matplotlib.dates.DateFormatter("%h"))
+ ax.set_yticklabels(map(lambda x: '%s$%i'%('-' if x<0 else '',abs(x)//100),
+ ax.yaxis.get_majorticklocs()))
+
+ t3 = time.time()
+ s = StringIO()
+ canvas.print_figure(s)
+ response.headers['Content-Type'] = 'image/png'
+ t4 = time.time()
+# print t1-t0, t2-t1, t3-t2, t4-t3
+ return s.getvalue()
+
+ def pie(self):
+ ruser = request.environ['user']
+
+ debts = []
+ debtors = []
+ credits = []
+ creditors = []
+ explode_debt = []
+ explode_credit = []
+ eps = model.types.Currency("2.00")
+ net = bluechips.lib.totals.debts().items()
+ net.sort(key=lambda x: x[1])
+ for user, amount in net:
+ if amount > eps:
+ debtors.append(user.name)
+ debts.append(amount)
+ explode_debt.append(0.1 if user == ruser else 0)
+ elif amount < -eps:
+ creditors.append(user.name)
+ credits.append(-amount)
+ explode_credit.append(0.1 if user == ruser else 0)
+
+ fig = plt.figure(figsize=(6,3))
+ canvas = FigureCanvas(fig)
+
+ ax1 = fig.add_axes([0.05,0.1,0.4,0.8])
+ ax1.pie(debts,
+ explode=explode_debt,
+ labels=debtors,
+ colors=plt.cm.YlOrRd(np.linspace(0.05,0.95,len(debtors))))
+ ax1.set_title('Debtors')
+
+ ax2 = fig.add_axes([0.55,0.1,0.4,0.8])
+ ax2.pie(credits,
+ explode=explode_credit,
+ labels=creditors,
+ colors=plt.cm.Blues(np.linspace(0.05,0.95,len(creditors))))
+ ax2.set_title('Creditors')
+
+# ax.legend(loc='best')
+# ax.grid(True)
+# plt.axis('tight')
+# ax.set_xlim(xmin=datetime.date.today()-datetime.timedelta(days=365))
+# ax.set_ylim(ymin=0)
+# fig.autofmt_xdate(rotation=30)
+# ax.xaxis.set_major_formatter(matplotlib.dates.DateFormatter("%h"))
+# ax.set_yticklabels(map(lambda x: '%s$%i'%('-' if x<0 else '',abs(x)//100),
+# ax.yaxis.get_majorticklocs()))
+
+ s = StringIO()
+ canvas.print_figure(s, dpi=72)
+ response.headers['Content-Type'] = 'image/png'
+ return s.getvalue()