Commit 0c2180ff authored by LE GAC Renaud's avatar LE GAC Renaud
Browse files

Add the column properties eval and dataIndex to Metric1D.

parent 4bbb5a59
......@@ -30,7 +30,7 @@ all columns
``"tablename.fieldname.keyname"``.
.. warning::
It should not be used with the ``rownumberer`` column.
Do not use with the ``rownumberer`` column.
``hidden``
the column is hidden when it is ``true``.
......@@ -90,10 +90,8 @@ The configuration parameters for the Metric1D column is similar to
those of the ``numbercolumn`` since the table only contains number. Therefore
it is not required to specify the column type.
``aggregate`` (*)
Many aggregation functions are available: ``count``, ``max``, ``mean``,
``median``, ``min``, ``size``, ``std``, ``sum``... In fact, all the
descriptive stats methods of the DataFrame_ class.
all column
^^^^^^^^^^
``align``
the alignment of the column.
......@@ -102,10 +100,6 @@ it is not required to specify the column type.
``columnWidth`` or ``flex``
the column width can be specified as a number or a percentage.
``dbfield`` (*)
the address of the database field encoded as ``"tablename.fieldname"`` or
``"tablename.fieldname.keyname"``.
``format``
the format string, e.g. ``"0,000.00"``.
......@@ -123,3 +117,31 @@ it is not required to specify the column type.
the summary over column values are computed.
Possible values are ``"count"``, ``"sum"``, ``"min"``, ``"max"``
and ``"average"``.
``dataIndex``
the index of the column used by the ``DataFrame``, the ``Ext.data.store``
and the ``Ext.grid.Panel``. By default, this internal parameter is equal
to the ``text`` property. However, when using the ``eval`` property, it
could be useful to index the column with short name like *a*, *b*, ...
database field column
^^^^^^^^^^^^^^^^^^^^^
``aggregate`` (*)
Many aggregation functions are available: ``count``, ``max``, ``mean``,
``median``, ``min``, ``size``, ``std``, ``sum``... In fact, all the
descriptive stats methods of the DataFrame_ class.
``dbfield`` (*)
the address of the database field encoded as ``"tablename.fieldname"`` or
``"tablename.fieldname.keyname"``.
computed column
^^^^^^^^^^^^^^^
``eval`` (*)
the string defining the mathematical operation applied between column cells,
*e.g* ``(a+b*2)/c`` where *a*, *b* and *c* are column indexes.
.. warning::
Do not use the ``dbfield`` and ``aggregate`` properties.
......@@ -29,7 +29,7 @@ import re
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.todo']
extensions = ['sphinx.ext.todo', 'sphinx.ext.mathjax']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
......
......@@ -31,9 +31,14 @@ Many aggregation functions are available: ``count``, ``max``,
descriptive stats methods of the pandas_ DataFrame_ class.
Several metric can be computed as the same time applying different aggregation
function possibly on different field.
function possibly on different fields.
A summary information can also be computed for each column. In the
Mathematical operation can be applied on the content of the different columns
and stored in the new one. For example, in :ref:`Fig 6`, the last column
contain the ratio between the *standard deviation* and the *average*, computed
for each row.
A summary row can also be computed for each column. In the
current implementation only the functions ``count``, ``sum``, ``min``,
``max`` and ``average`` are available.
......@@ -107,10 +112,14 @@ The configuration of a column requires a minimum of three properties:
``text``
the label of the column.
In order to compute a summary for the column, use the ``summaryType`` property.
Possible values are ``count``, ``sum``, ``min``, ``max`` and
In order to compute a summary row for the columns, use the ``summaryType``
property. Possible values are ``count``, ``sum``, ``min``, ``max`` and
``average``.
To add column containing the result of mathematical operation applied on
column cells, use the properties ``eval`` instead of ``dbfield`` and
``aggregate``.
Many more properties are available. They are detailed in :ref:`Appendix C`.
The following configuration has been used for the metrics of the :ref:`Fig 6`::
......@@ -121,16 +130,22 @@ The following configuration has been used for the metrics of the :ref:`Fig 6`::
"dbfield": "people.id",
"format": "0",
"text": "entrées"
}, {
}, {
"aggregate": "mean",
"align": "right",
"dataIndex": "a",
"dbfield": "people.age",
"format": "0.0",
"text": "<age>"
}, {
}, {
"aggregate": "std",
"align": "right",
"dataIndex": "b",
"dbfield": "people.age",
"format": "0.0",
"text": "σ(age)"
},{
"align": "right",
"eval": "b/a",
"text": "sigma/mean"
}]
......@@ -485,34 +485,49 @@ class Metric1D(BaseReport):
db = self.db
config = self.config
columns = [Storage(el) for el in json.loads(config.columns)]
field_groupby = self._field_groupby
index_groupby = self._index_groupby
# configuration
cfg = [Storage(dbfield=field_groupby, text=index_groupby, aggregate="")]
cfg.extend(columns)
# columns configuration
columns = [Storage(dbfield=field_groupby, text=index_groupby, aggregate="")]
columns.extend([Storage(el) for el in json.loads(config.columns)])
# extract columns associated to database field
cfg = [el for el in columns if el.dbfield]
# columns labels and operators
labels = [el.text for el in cfg]
# col_index for columns either dataIndex or text
col_index = [(el.dataIndex if el.dataIndex else el.text) for el in cfg]
# aggregation operator for each column
operators = dict()
for el in cfg:
for i in range(len(cfg)):
el = cfg[i]
if el.aggregate:
operators[el.text] = el.aggregate
operators[col_index[i]] = el.aggregate
# interrogate the database and fill the data frame
data = self._do_data(cfg)
if not data:
self.df = pd.DataFrame(columns=labels)
self.df = pd.DataFrame(columns=col_index)
return
df = pd.DataFrame(data, columns=labels)
df = pd.DataFrame(data, columns=col_index)
# aggregate the data running dedicated operator for each column
df = df.groupby(index_groupby)
df = df.agg(operators)
# computed column
for el in columns:
if el.eval:
index = (el.dataIndex if el.dataIndex else el.text)
df[index] = df.eval(el.eval)
# re-order the column to follow user configuration
# exclude the first column containing the group_by data
index = [(el.dataIndex if el.dataIndex else el.text) for el in columns[1:]]
df = df[index]
# transform year MultiIndex into Index (only for year pseudo field)
if isinstance(df.index, pd.core.index.MultiIndex):
df.index = [el[1] for el in df.index]
......@@ -582,11 +597,15 @@ class Metric1D(BaseReport):
for di in json.loads(config.columns):
# remove non Ext JS property
for key in ('aggregate', 'dbfield'):
del di[key]
for key in ('aggregate', 'dbfield', 'eval'):
if key in di:
del di[key]
# build the dataIndex and fix column type
di['dataIndex'] = di['text']
# the dataIndex
if 'dataIndex' not in di:
di['dataIndex'] = di['text']
# column type
di['xtype'] = 'numbercolumn'
grid.columns.append(di)
......
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