Commit ad664c18 authored by LE GAC Renaud's avatar LE GAC Renaud
Browse files

First version running fo linechart.

parent 552b41bc
......@@ -6,33 +6,19 @@ import matplotlib
from datetime import datetime
from graph_tools import (do_labels,
do_legend,
do_tick,
do_title,
mathplotlib_backend_server,
savefig)
from pandas import DataFrame
from plugin_dbui import Selector
from StringIO import StringIO
from reporting_tools import repr_team_project
def savefig(ax, format):
"""Save the figure as a string.
mathplotlib_backend_server()
Args:
ax (matplotlib.AxesSubplot): axes subplot
format (str): possible values are pdf, png and svg.
Return:
str:
"""
fig = ax.get_figure()
fi = StringIO()
fig.savefig(fi, format=format)
data = fi.getvalue()
fi.close()
fig.clear()
matplotlib.pyplot.close(fig)
return data
def index():
"""Prototype to generate the number of publication per month.
......@@ -48,9 +34,6 @@ def index():
year_end = selector.year_end
year_start = selector.year_start
# matplotlib backend
matplotlib.use("Agg")
# query directive to count publications including
# foreign key constraints and user requirements
# related to team, project, authors roles and year
......@@ -74,30 +57,34 @@ def index():
groupby=group_by,
orderby=group_by)
# the function to render the time axis
if year_start and not year_end:
repr_time = lambda s: datetime.strptime(s[:7], "%Y-%m").strftime("%b")
elif year_start and year_end:
repr_time = lambda s: datetime.strptime(s[:7], "%Y-%m").strftime("%b %y")
# build the dataframe
data = []
for row in rows:
# protection -- ignore publication with invalid submitted date
submitted = row.publications.submitted
if len(submitted) == 4:
continue
data.append([repr_time(submitted), row[count]])
dt = datetime.strptime(submitted[:7], "%Y-%m")
month = dt.strftime("%b")
data.append([month, row[count]])
df = DataFrame(data, columns=['month', 'count'])
df = DataFrame(data, columns=['time', 'count'])
# move to a DataSerie in which values are ordered by month
df = df.set_index('month')
# move to a DataSerie in which values are ordered by time (month, ...)
df = df.set_index('time')
# cumulative serie
df = df.cumsum()
if selector.cumulative:
df = df.cumsum()
# generate the plot
ax = df.plot()
# instantiate the plot
ax = df.plot(legend=False)
do_labels(ax, "", "Number of publications / month")
do_tick(ax)
# delegate the rendering to the view
return dict(data=savefig(ax, "svg"), title="foo")
return dict(data=savefig(ax, "svg"), title=do_title(db, selector))
......@@ -2,3 +2,117 @@
"""A collection of tools to build graphs in controllers.
"""
import matplotlib
from gluon import current
from reporting_tools import repr_team_project
from StringIO import StringIO
def do_labels(ax, xlabel, ylabel):
"""Deal with axes label.
Args:
ax (matplotlib.AxesSubplot): axes subplot
"""
ax.set_xlabel(xlabel, x=1, horizontalalignment='right')
ax.set_ylabel(ylabel, y=1, horizontalalignment='right')
def do_legend(ax):
"""Put legend at the top.
Args:
ax (matplotlib.AxesSubplot): axes subplot
"""
if ax.get_legend():
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width, box.height * 0.9])
ax.legend(loc='lower right',
bbox_to_anchor=(1.01, 1.),
fontsize=10,
ncol=2)
def do_tick(ax):
"""Polish the tick mark
Args:
ax (matplotlib.AxesSubplot): axes subplot
"""
ax.minorticks_on()
ax.tick_params(which='major', length=8)
ax.tick_params(which='minor', length=4)
def do_title(db, selector):
"""Build the title string.
Args:
db (gluon.DAL): database connection
selector (plugin_dbui.Selector): selector with user critera
Returns:
str
"""
T = current.T
team_project = repr_team_project(db, selector)
if selector.cumulative:
title = "%s %s" % (T("Sum of publications"), team_project)
else:
title = "%s %s" % (T("Publications"), team_project)
period = ""
if selector.year_start and selector.year_end:
period = T("from %s to %s") % (selector.year_start, selector.year_end)
elif selector.year_start:
period = str(selector.year_start)
return "%s %s" % (title, period)
def mathplotlib_backend_server():
"""Setup the backend for mathplotlib when running on a server.
Note:
The X11 back end is not needed on the server side. In addition,
Tkinter crashes with the message "out of stack space" when the 2nd plot
is generated.
The documentation recommend to limit the matplotlib back end to *Agg*
which is tuned to render high quality PNG image. But, it is also
design to render PDF and SVG image without the X11 interface.
"""
matplotlib.use("Agg")
def savefig(ax, fmt):
"""Save the figure as a string.
Args:
ax (matplotlib.AxesSubplot): axes subplot
fmt (str): possible values are pdf, png and svg.
Return:
str:
"""
fig = ax.get_figure()
fi = StringIO()
fig.savefig(fi, format=fmt)
data = fi.getvalue()
fi.close()
fig.clear()
matplotlib.pyplot.close(fig)
return data
......@@ -18,3 +18,19 @@
}}
<img src="data:image/svg+xml;utf8,{{=data}}" height=400></img>
{{
from datetime import datetime
#
# the footer, processing time of the request
#
delta = (datetime.now()-request.now).total_seconds()
delta = T('Processing time %s seconds') % round(delta, 2)
style = ["font-size: 10px;",
"margin-left: 10px;",
"margin-bottom: 3ex;",
"margin-top: 2ex;"]
response.write(P(delta, _style="".join(style)))
}}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment