# -*- coding: utf-8 -*- """Definitions of the report tables """ import numpy as np from callbacks import ON_CREATE_LISTS2, ON_UPDATE_LISTS2 from gluon import current, IS_IN_SET from gluon.tools import PluginManager from pydal import Field AGGREGATE_FUNCS = { "max": np.max, "mean": np.min, "median": np.median, "min": np.min, "sem": np.max, "size": np.size, "sum": np.sum, "std": np.std, "var": np.var} DEF_COLUMNS_LISTS = \ """[{ "xtype": "rownumberer" }, { "dbfield": "?.?", "flex": 1, "text": "?", "xtype": "gridcolumn" }]""" DEF_COLUMNS_METRIC1D = \ """[{ "aggregate": "?", "align": "right", "dbfield": "?.?", "format": "0.0", "text": "?", "xtype": "numbercolumn" }]""" DEF_FEATURES = \ """[{ "ftype": "groupingsummary", "groupHeaderTpl": "{name}", "startCollapsed": false }, { "ftype": "summary" }]""" DEF_GRAPH = { "colormap": "Pastel1", "kind": "", "grid": True, "linewidth": 0, "legend": True, "loglog": False, "logx": False, "logy": False, "rot": 0, "stacked": True, "width": 0.8, "ylim": []} DEF_PLOT = \ """{ "kind": "?", "stacked": false }""" DEF_SUMMARY = { "functions": "", "labels": ""} TP_AGG = \ "The aggregation function applies on the metric field. " \ "It is computed on the subset of row having a given values for " \ "the group_field x and y." TP_COLUMNS = "Configure the column of the grid displayed in the view." TP_CONDITIONS = \ "Database query to select history records:
" \ "(db.events.event == 'People') & (db.history.data.like('%cdd%'))
" TP_GROUP_FIELD_LISTS = \ "Row are grouped according to the value of that field. " \ "It can be any field of the history table including those of " \ "the foreign tables, the individual property of the history.data " \ "dictionary, or 'year'." TP_GROUP_FIELD_METRICS = \ "Metric are computed for each value of that field. " \ "It can be any field of the history table including those of the " \ "foreign tables, the individual property of the history.data dictionary " \ "or 'year'" TP_FEATURES = "Summary value can be computed for columns." TP_SORTERS = \ "Entries are sorted according to the value of these fields. "\ "It can be any field of the history table including those of the "\ "foreign tables, the individual property of the history.data dictionary, "\ "or 'year'. Descending order is obtained by using the '~field' construct." TP_SUMMARY_X = "To sum, for example, the content of each row." TP_SUMMARY_Y = "To sum, for example, the content of each column." class Report(object): """Create the tables for the reporting: lists, metrics1d, metrics2d, and graphs. """ @staticmethod def define_tables(db, T): """Define tables for the reporting. Args: db (pyDAL.DAL): database connection T (gluon.languages.translator): language translator """ Report.graphs(db, T) Report.lists(db, T) Report.lists2(db, T) Report.metrics1d(db, T) Report.metrics2d(db, T) Report.metrics2d2(db, T) @staticmethod def graphs(db, T): """graphs table Args: db (pyDAL.DAL): database connection T (gluon.languages.translator): language translator Returns: pyDAL.Table """ def_plot = (None if db._migrate else DEF_PLOT) table = db.define_table( "graphs", Field("name", "string", length=255, notnull=True, unique=True), Field("title", "string", length=255), Field("report_type", "string", length=255, notnull=True), Field("report_name", "string", length=255, notnull=True), Field("plot", "text", notnull=True, default=def_plot), Field("definition", "text"), migrate="graphs.table") return table @staticmethod def lists(db, T): """lists table Args: db (pyDAL.DAL): database connection T (gluon.languages.translator): language translator Returns: pyDAL.Table """ def_columns = (None if db._migrate else DEF_COLUMNS_LISTS) def_features = (None if db._migrate else DEF_FEATURES) table = db.define_table( "lists", Field("name", "string", length=255, notnull=True, unique=True), Field("title", "string", length=255), Field("conditions", "text", comment=T(TP_CONDITIONS)), Field("group_field", "string", length=255, comment=T(TP_GROUP_FIELD_LISTS)), Field("sorters", "list:string", comment=TP_SORTERS), Field("columns", "text", default=def_columns, comment=T(TP_COLUMNS), notnull=True), Field("features", "text", default=def_features, comment=T(TP_FEATURES)), Field("definition", "text"), migrate="lists.table") return table @staticmethod def lists2(db, T): """lists2 table Args: db (pyDAL.DAL): database connection T (gluon.languages.translator): language translator Returns: pyDAL.Table """ migrate = current.globalenv["MIGRATE"] table = db.define_table( "lists2", Field("name", "string", length=255, notnull=True, unique=True), Field("title", "string", length=255), Field("definition", "text"), Field("source", "string", length=255, notnull=True), Field("id_events", "reference events", notnull=True, label="Event"), Field("eval", "text"), Field("query", "text"), Field("group_field", "string", length=255, comment=T(TP_GROUP_FIELD_LISTS)), Field("sorters", "list:string", comment=TP_SORTERS), # NOTE # - notnull when creating the database # - null later on in order to run callback ON_CREATE_LISTS, ... Field("columns", "text", notnull=migrate, comment=T(TP_COLUMNS)), Field("summary_group", "boolean", default=True, label=T("Summary row per group")), Field("summary_all", "boolean", default=True, label=T("Summary row")), migrate="lists2.table") sources = PluginManager("event").event.sources.keys() sources.sort() db.lists2.source.requires = IS_IN_SET(sources) db.lists2._before_insert.append(ON_CREATE_LISTS2) db.lists2._before_update.append(ON_UPDATE_LISTS2) return table @staticmethod def metrics1d(db, T): """metrics1d table Args: db (pyDAL.DAL): database connection T (gluon.languages.translator): language translator Returns: pyDAL.Table """ def_columns = (None if db._migrate else DEF_COLUMNS_METRIC1D) db.define_table( "metrics1d", Field("name", "string", length=255, notnull=True, unique=True), Field("title", "string", length=255), Field("conditions", "text", comment=T(TP_CONDITIONS)), Field("group_field", "string", length=255, comment=T(TP_GROUP_FIELD_METRICS), notnull=True), Field("columns", "text", default=def_columns, comment=T(TP_COLUMNS), notnull=True), Field("definition", "text"), migrate="metrics1d.table") @staticmethod def metrics2d(db, T): """metrics2d table Args: db (pyDAL.DAL): database connection T (gluon.languages.translator): language translator Returns: pyDAL.Table """ table = db.define_table( "metrics2d", Field("name", "string", length=255, notnull=True, unique=True), Field("title", "string", length=255), Field("conditions", "text", comment=T(TP_CONDITIONS)), Field("group_field_x", "string", length=255, notnull=True, comment=T(TP_GROUP_FIELD_METRICS)), Field("group_field_y", "string", length=255, notnull=True, comment=T(TP_GROUP_FIELD_METRICS)), Field("metric_field_z", "string", length=255, notnull=True, comment=T(TP_GROUP_FIELD_METRICS)), Field("aggregation_z", "string", length=255, notnull=True, comment=T(TP_AGG)), Field("definition", "text"), migrate="metrics2d.table") return table @staticmethod def metrics2d2(db, T): """metrics2d2 table Args: db (pyDAL.DAL): database connection T (gluon.languages.translator): language translator Returns: pyDAL.Table """ table = db.define_table( "metrics2d2", Field("name", "string", length=255, notnull=True, unique=True), Field("title", "string", length=255), Field("definition", "text"), Field("source", "string", length=255, notnull=True), Field("id_events", "reference events", label="Event", notnull=True), Field("eval", "text"), Field("query", "text"), Field("group_field_x", "string", comment=T(TP_GROUP_FIELD_METRICS), length=255, notnull=True, label="Group (x)"), Field("group_field_y", "string", comment=T(TP_GROUP_FIELD_METRICS), length=255, notnull=True, label="Group (y)"), Field("metric_field_z", "string", comment=T(TP_GROUP_FIELD_METRICS), label="Metric (z)", length=255, notnull=True), Field("aggregate_func_z", "string", comment=T(TP_AGG), default="sum", label="Aggregate (z)", length=255, notnull=True), Field("summary_x", "json", default=DEF_SUMMARY, label="Per row"), Field("summary_y", "json", default=DEF_SUMMARY, label="Per column"), Field("graph", "json", default=DEF_GRAPH), migrate="metrics2d2.table") sources = PluginManager("event").event.sources.keys() sources.sort() table.source.requires = IS_IN_SET(sources) funcs = AGGREGATE_FUNCS.keys() funcs.sort() table.aggregate_func_z.requires = IS_IN_SET(funcs) # NOTE: we have to remove the json validator to work !! table.graph.requires = None table.summary_x.requires = None table.summary_y.requires = None return table @staticmethod def tables(): """Tool returning the list of table names. Returns: list """ lst = ["graphs", "lists", "lists2", "metrics1d", "metrics2d" "metrics2d2"] return lst