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