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

Graph area, bar(h), line and scatter are working.

parent 42060dae
......@@ -63,7 +63,7 @@ DEF_GRAPH = {
"rot": 0,
"stacked": True,
"width": 0.8,
"ylim": []}
"ylim": ""}
DEF_PLOT = \
"""{
......
......@@ -4,12 +4,15 @@
"""
import json
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from gluon import current
from gluon.storage import Storage
from gluon.tools import PluginManager
from model_report import AGGREGATE_FUNCS
from matplotlib_tools import ticks_and_labels
from plugin_dbui import Selector, Store
from StringIO import StringIO
......@@ -19,17 +22,6 @@ FIELD_TYPES = {"gridcolumn": "string",
"datecolumn": "date",
"numbercolumn": "float"}
GRAPHS = ("area",
"bar",
"barh",
"box",
"hexbin",
"hist",
"kde",
"line",
"pie",
"scatter")
GROUPING = {"ftype": "grouping",
"groupHeaderTpl": "{name}"}
......@@ -38,6 +30,7 @@ GROUPING_SUMMARY = {"ftype": "groupingsummary",
"startCollapsed": False}
MSG_NO_DATAINDEX = "The property dataIndex is missing."
MSG_NO_KIND = "The graph parameter kind is missing."
MSG_NO_XTYPE = "The property xtype is missing."
SUMMARY = {"ftype": "summary"}
......@@ -210,30 +203,99 @@ class Graph2(object):
selector.graph = json.loads(selector.graph)
config_graph = (selector.graph if selector.is_graph else config.graph)
kind = config_graph[u"kind"]
# protection
if config_graph[u"kind"] not in GRAPHS:
if selector.is_graph and kind in (None, ""):
raise ReportException(MSG_NO_KIND)
if len(kind) == 0:
self.ax = None
return
# tune the graph configuration
if len(config_graph[u"ylim"]) == 0:
# alias
group_field_x = config.group_field_x
group_field_y = config.group_field_y
metric_field_z = config.metric_field_z
# decode ylim
ylim = config_graph[u"ylim"]
if len(ylim) == 0:
del config_graph[u"ylim"]
else:
config_graph[u"ylim"] = (int(el) for el in ylim.split(","))
# setup the matplotlib back-end
mpl.use(backend)
mpl.rcParams['legend.fontsize'] = 7
# plot the DataFrame
ax = (metric2d.df
.set_index(config.group_field_y)
.transpose()
.plot(**config_graph))
# setup matplotlib style
mpl.rcParams['xtick.major.size'] = 8
mpl.rcParams['xtick.minor.size'] = 4
mpl.rcParams['ytick.major.size'] = 8
mpl.rcParams['ytick.minor.size'] = 4
# plot the DataFrame without summary rows or columns
if kind in ("bar", "barh"):
ax = (metric2d.df0
.set_index(config.group_field_y)
.transpose()
.plot(**config_graph))
elif kind in ("area", "line"):
df1 = metric2d.df0.transpose()
df1.columns = df1.loc["line", :]
df1 = df1[df1.index != "line"]
del config_graph[u"width"]
linewidth = config_graph[u"linewidth"]
config_graph[u"linewidth"] = (1 if linewidth == 0 else linewidth)
ax = df1.plot(**config_graph)
elif kind in ("scatter"):
df1 = metric2d.df0.transpose()
df1.columns = df1.loc["line", :]
df1 = (df1[df1.index != "line"]
.reset_index())
del config_graph[u"width"]
del config_graph[u"colormap"]
# choose color from the Spectral colormap
colors = plt.cm.Spectral(np.linspace(0., 1., df1.columns.size))
ax = None
for i, col in enumerate(df1.columns):
if col == group_field_x:
continue
ax = df1.plot(ax=ax,
color=colors[i],
x=group_field_x,
y=col, **config_graph)
# tick and axis labels
xlabel, ylabel = group_field_x, metric_field_z
ylabel = \
(ylabel + " (stacked)" if config_graph[u"stacked"] else ylabel)
if kind == "barh":
xlabel, ylabel = ylabel, xlabel
if group_field_x == "year":
ax.xaxis.set_major_formatter(mpl.ticker.FormatStrFormatter("%i"))
if group_field_y == "year":
ax.yaxis.set_major_formatter(mpl.ticker.FormatStrFormatter("%i"))
# polish legend
if config_graph[u"legend"] in (True, "reverse"):
ticks_and_labels(ax, xlabel, ylabel)
# legend
legend = ax.get_legend()
if legend is not None:
ax.get_legend().set_title("")
# keep the plot for latter use
......@@ -410,6 +472,11 @@ class Metric2D2(BaseReport):
"""Generate the Metric2D and related configurations for ``Ext.grid.Panel``
and ``Ext.data.Store``.
Attributes:
df (pandas.DataFrame): metric with summary rows and columns.
df0 (pandas.DataFrame): metric without summary rows and columns.
is_summary (bool):
Args:
id_report: report identifier in the database
......@@ -423,6 +490,8 @@ class Metric2D2(BaseReport):
db = current.globalenv["db"]
BaseReport.__init__(self, db.metrics2d2, id_report)
self.is_summary = False
# ....................................................................
#
# build the 2D table
......@@ -452,10 +521,10 @@ class Metric2D2(BaseReport):
df = self._add_summaries(df)
# move the index to column in order to ease the data extraction
df = df.reset_index()
# update the attribute df for a later use
self.df = df
self.df = df = df.reset_index()
if self.is_summary:
self.df0 = self.df0.reset_index()
# ....................................................................
#
......@@ -533,8 +602,10 @@ class Metric2D2(BaseReport):
# preserve the original DataFrame in order to avoid pollution
# when series of summaries is computed
self.df0 = df
if len(summary_x["functions"]) > 0 or len(summary_y["functions"]) > 0:
self.df0 = df0 = df.copy()
self.is_summary = True
dfx = self.summaries(df0, summary_x, axis="columns")
df = pd.concat((df, dfx), axis="columns")
......
......@@ -61,10 +61,7 @@ Ext.define("Event.form.field.Graph", {
kind: ["area",
"bar",
"barh",
"hexbin",
"hist",
"line",
"pie",
"scatter"
],
......@@ -93,6 +90,13 @@ Ext.define("Event.form.field.Graph", {
store: me.kind
}),
type: "string"
},
ylim: {
editor: Ext.create("Ext.form.field.Text", {
allowBlank: true,
emptyText: "min, max"
}),
type: "string"
}
};
......
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