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

Populate the modules graph_tools mainly with do_linechart and its friends.

parent ad664c18
......@@ -6,85 +6,34 @@ import matplotlib
from datetime import datetime
from graph_tools import (do_labels,
do_legend,
do_tick,
do_title,
from graph_tools import (do_linechart,
mathplotlib_backend_server,
savefig)
from pandas import DataFrame
from plugin_dbui import Selector
from reporting_tools import repr_team_project
mathplotlib_backend_server()
def index():
"""Prototype to generate the number of publication per month.
"""Generate graph showing the number of publication per month / year
either as a linechart or as a stacked histograms.
"""
fields = ('cumulative','id_graphs', 'year_start','year_end')
selector = Selector(virtdb.graph_selector, exclude_fields=fields)
# graph_cfg = db.graphs[selector.id_graphs]
# alias
publications = db.publications
year_end = selector.year_end
year_start = selector.year_start
# query directive to count publications including
# foreign key constraints and user requirements
# related to team, project, authors roles and year
query = selector.query(publications)
if year_start and not year_end:
query &= publications.submitted[0:4] == year_start
elif year_start and year_end:
q_start = publications.submitted[0:4] >= year_start
q_end = publications.submitted[0:4] <= year_end
query &= ((q_start) & (q_end))
# count the number of publications
# they are grouped per year and and per month
group_by = [publications.submitted[:4], publications.submitted[5:7]]
count = publications.id.count()
rows = db(query).select(publications.submitted,
count,
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:
submitted = row.publications.submitted
if len(submitted) == 4:
continue
data.append([repr_time(submitted), row[count]])
df = DataFrame(data, columns=['time', 'count'])
mathplotlib_backend_server()
# move to a DataSerie in which values are ordered by time (month, ...)
df = df.set_index('time')
# graph configuration
graph = db.graphs[selector.id_graphs]
# cumulative serie
if selector.cumulative:
df = df.cumsum()
# stacked chart
if graph.stack_axis:
return "Not yet implemented..."
# instantiate the plot
ax = df.plot(legend=False)
do_labels(ax, "", "Number of publications / month")
do_tick(ax)
# line char
else:
ax = do_linechart(db.publications, selector)
# delegate the rendering to the view
return dict(data=savefig(ax, "svg"), title=do_title(db, selector))
return dict(data=savefig(ax, "svg"))
......@@ -3,18 +3,29 @@
"""
import matplotlib
import re
from datetime import datetime
from gluon import current
from pandas import DataFrame
from reporting_tools import repr_team_project
from regex import REG_SUBMITTED
from StringIO import StringIO
FROM_TO = "from %s to %s"
TITLE = "Publications"
TITLE_CUMSUM = "Cumulative sum of publications"
def do_labels(ax, xlabel, ylabel):
"""Deal with axes label.
Args:
ax (matplotlib.AxesSubplot): axes subplot
xlabel (str): label for the horizontal axis.
ylabel (str): label for the vertical axis.
"""
ax.set_xlabel(xlabel, x=1, horizontalalignment='right')
......@@ -37,6 +48,95 @@ def do_legend(ax):
ncol=2)
def do_linechart(publications, selector):
"""Build a line chart showing the number of publications as a function
of the time.
Args:
publications (gluon.dal.Table): the publications table.
selector (plugin_dbui.Selector): the selector with user criteria.
Returns:
matplotlib.AxesSubplot: axes subplot
"""
db = publications._db
rx_submitted = re.compile(REG_SUBMITTED)
# query directive to count publications including
# foreign key constraints and user requirements
# related to team, project, authors roles and year
query = do_query(publications, selector)
# count the number of publications
# they are grouped per year and and per month
group_by = [publications.submitted[:4], publications.submitted[5:7]]
count = publications.id.count()
rows = db(query).select(publications.submitted,
count,
groupby=group_by,
orderby=group_by)
# build the dataframe
# the index of the DataSerie is the time (month, ...)
data = []
time_cvt = get_time_converter(selector.year_start, selector.year_end)
for row in rows:
submitted = row.publications.submitted
if not rx_submitted.match(submitted):
continue
data.append([time_cvt(submitted), row[count]])
df = DataFrame(data, columns=['time', 'count'])
df = df.set_index('time')
# cumulative serie
if selector.cumulative:
df = df.cumsum()
# instantiate the plot
ax = df.plot(legend=False)
do_labels(ax, "", "Number of publications / month")
do_tick(ax)
do_title(ax, db, selector)
return ax
def do_query(publications, selector):
"""Construct the query to select publications according
to user criteria, team, project, year, ...
Args:
publications (gluon.dal.Table): the publications table.
selector (plugin_dbui.Selector): the selector with user criteria.
Returns:
gluon.DAL.Query: the query for the database.
"""
year_end = selector.year_end
year_start = selector.year_start
# query directive to count publications including
# foreign key constraints and user requirements
# related to team, project, authors roles and year
query = selector.query(publications)
if year_start and not year_end:
query &= publications.submitted[0:4] == year_start
elif year_start and year_end:
q_start = publications.submitted[0:4] >= year_start
q_end = publications.submitted[0:4] <= year_end
query &= ((q_start) & (q_end))
return query
def do_tick(ax):
"""Polish the tick mark
......@@ -49,33 +149,51 @@ def do_tick(ax):
ax.tick_params(which='minor', length=4)
def do_title(db, selector):
def do_title(ax, db, selector):
"""Build the title string.
Args:
ax (matplotlib.AxesSubplot): axes subplot
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)
title = "%s %s" % (T(TITLE_CUMSUM), team_project)
else:
title = "%s %s" % (T("Publications"), team_project)
title = "%s %s" % (T(TITLE), team_project)
period = ""
if selector.year_start and selector.year_end:
period = T("from %s to %s") % (selector.year_start, selector.year_end)
period = T(FROM_TO) % (selector.year_start, selector.year_end)
elif selector.year_start:
period = str(selector.year_start)
return "%s %s" % (title, period)
title = "%s %s" % (title, period)
ax.set_title(title.decode("utf-8"))
def get_time_converter(year_start, year_end):
"""Return the function to compute the time value.
Args:
year_start (str): year defining the begining of the period.
year_end (str): year defining the end of the period.
Returns:
reference to a function: the argument of the function is the
submitted date.
"""
if year_start and not year_end:
return lambda s: datetime.strptime(s[:7], "%Y-%m").strftime("%b")
else:
return lambda s: datetime.strptime(s[:7], "%Y-%m").strftime("%b %y")
def mathplotlib_backend_server():
......
......@@ -3,16 +3,10 @@
#
# The python controller return image as a string:
# - data (string)
# - title (string)
#
#--------------------------------------------------------------------------
import urllib
#
# The title
#
response.write(H2(title, _class="dbui-h2 dbui-small-cap"))
# encode special charactier bo be used in the image URI
data = urllib.quote(data)
......
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