diff --git a/TODO.md b/TODO.md index 200b7ab09ce7f..a89dbace15e34 100644 --- a/TODO.md +++ b/TODO.md @@ -2,13 +2,10 @@ List of TODO items for Panoramix ## Improvments -* GROUPED boolean for table view * datasource in explore mode could be a dropdown * [sql] make "Test Connection" test further -* in/notin filters autocomplete * [druid] Allow for post aggregations (ratios!) * in/notin filters autocomplete -* [sql] make "Test Connection" test further ## Better Javascript enables * Async on Druidify! in exploration page diff --git a/panoramix/forms.py b/panoramix/forms.py index 3213d3e4bb2f9..b017f68076afd 100644 --- a/panoramix/forms.py +++ b/panoramix/forms.py @@ -128,6 +128,10 @@ def __init__(self, viz): 'Columns', choices=self.choicify(datasource.groupby_column_names), description="One or many fields to pivot as columns"), + 'all_columns': SelectMultipleSortableField( + 'Columns', + choices=self.choicify(datasource.column_names), + description="Columns to display"), 'granularity': FreeFormSelectField( 'Time Granularity', default="one day", choices=self.choicify([ @@ -335,10 +339,14 @@ def __init__(self, viz): "Whether to display the min and max values of the axis")), 'rich_tooltip': BetterBooleanField( "Rich Tooltip", default=True, - description="The rich tooltip shows a list of all series for that point in time"), + description=( + "The rich tooltip shows a list of all series for that" + " point in time")), 'y_axis_zero': BetterBooleanField( "Y Axis Zero", default=False, - description="Force the Y axis to start at 0 instead of the minimum value"), + description=( + "Force the Y axis to start at 0 instead of the minimum " + "value")), 'y_log_scale': BetterBooleanField( "Y Log", default=False, description="Use a log scale for the Y axis"), diff --git a/panoramix/models.py b/panoramix/models.py index a2357b27a95a6..a8eb617f260a1 100644 --- a/panoramix/models.py +++ b/panoramix/models.py @@ -377,7 +377,8 @@ def query( is_timeseries=True, timeseries_limit=15, row_limit=None, inner_from_dttm=None, inner_to_dttm=None, - extras=None): + extras=None, + columns=None): # For backward compatibility if granularity not in self.dttm_cols: @@ -427,15 +428,20 @@ def query( select_exprs.append(outer) inner_groupby_exprs.append(inner) inner_select_exprs.append(inner) + elif columns: + for s in columns: + select_exprs.append(s) + metrics_exprs = [] - if is_timeseries: + if is_timeseries and groupby: select_exprs += [timestamp] groupby_exprs += [timestamp] select_exprs += metrics_exprs qry = select(select_exprs) from_clause = table(self.table_name) - qry = qry.group_by(*groupby_exprs) + if groupby: + qry = qry.group_by(*groupby_exprs) time_filter = [ timestamp >= from_dttm.isoformat(), @@ -466,7 +472,8 @@ def query( having_clause_and += [text(extras['having'])] qry = qry.where(and_(*(time_filter + where_clause_and))) qry = qry.having(and_(*having_clause_and)) - qry = qry.order_by(desc(main_metric_expr)) + if groupby: + qry = qry.order_by(desc(main_metric_expr)) qry = qry.limit(row_limit) if timeseries_limit and groupby: @@ -492,6 +499,7 @@ def query( con=engine ) sql = sqlparse.format(sql, reindent=True) + print(sql) return QueryResult( df=df, duration=datetime.now() - qry_start_dttm, query=sql) @@ -779,7 +787,8 @@ def query( timeseries_limit=None, row_limit=None, inner_from_dttm=None, inner_to_dttm=None, - extras=None): + extras=None, + select=None): qry_start_dttm = datetime.now() inner_from_dttm = inner_from_dttm or from_dttm diff --git a/panoramix/static/panoramix.css b/panoramix/static/panoramix.css index 1ea5b1c2833a0..7c2ce689e5b2d 100644 --- a/panoramix/static/panoramix.css +++ b/panoramix/static/panoramix.css @@ -1,3 +1,9 @@ +html>body{ + margin: 0px; !important +} +.container-fluid { + text-align: left; +} input[type="checkbox"] { display: inline-block; width: 16px; diff --git a/panoramix/static/widgets/viz_pivot_table.js b/panoramix/static/widgets/viz_pivot_table.js index dfd5649a6b616..42382daad0910 100644 --- a/panoramix/static/widgets/viz_pivot_table.js +++ b/panoramix/static/widgets/viz_pivot_table.js @@ -4,26 +4,24 @@ px.registerWidget('pivot_table', function(data_attribute) { var form_data = data_attribute.form_data; function refresh(done) { - token.load(data_attribute.json_endpoint, function(response, status, xhr){ - if(status=="error"){ + $.getJSON(data_attribute.json_endpoint, function(json){ + token.html(json.data); + if (form_data.groupby.length == 1){ + var table = token.find('table').DataTable({ + paging: false, + searching: false, + }); + table.column('-1').order( 'desc' ).draw(); + } + token.show(); + done(json); + }).fail(function(xhr){ var err = '
' + xhr.responseText + '
'; token.html(err); token.show(); - } - else{ - if (form_data.groupby.length == 1){ - var table = token.find('table').DataTable({ - paging: false, - searching: false, - }); - table.column('-1').order( 'desc' ).draw(); - } - } - token.show(); - done(); + done(); }); } - return { render: refresh, resize: refresh, diff --git a/panoramix/templates/panoramix/viz_pivot_table.html b/panoramix/templates/panoramix/viz_pivot_table.html index 9fe1398ea1c53..062c23bfd5530 100644 --- a/panoramix/templates/panoramix/viz_pivot_table.html +++ b/panoramix/templates/panoramix/viz_pivot_table.html @@ -1,18 +1,7 @@ {% macro viz_html(viz) %} - {% if viz.request.args.get("async") == "true" %} - {{ viz.get_df().to_html(na_rep='', classes="dataframe table table-striped table-bordered table-condensed")|safe }} - {% else %} - - {% endif %} {% endmacro %} {% macro viz_js(viz) %} - {% if viz.form_data.get("async") != "true" %} - - {% endif %} {% endmacro %} {% macro viz_css(viz) %} diff --git a/panoramix/templates/panoramix/viz_table.html b/panoramix/templates/panoramix/viz_table.html index ef26a192fa900..9497ff9128ca0 100644 --- a/panoramix/templates/panoramix/viz_table.html +++ b/panoramix/templates/panoramix/viz_table.html @@ -2,7 +2,7 @@ {% if viz.request.args.get("async") == "true" %} {% set df = viz.get_df() %}
- +
{% for col in df.columns if not col.endswith('__perc') %} diff --git a/panoramix/viz.py b/panoramix/viz.py index 3f42103bdaec9..667d9810f34af 100644 --- a/panoramix/viz.py +++ b/panoramix/viz.py @@ -242,9 +242,21 @@ class TableViz(BaseViz): 'fields': ( 'granularity', ('since', 'until'), - 'metrics', 'groupby', 'row_limit' ) + }, + { + 'label': "GROUP BY", + 'fields': ( + 'groupby', + 'metrics', + ) + }, + { + 'label': "NOT GROUPED BY", + 'fields': ( + 'all_columns', + ) },) css_files = ['lib/dataTables/dataTables.bootstrap.css'] is_timeseries = False @@ -261,6 +273,14 @@ def json_endpoint(self): def query_obj(self): d = super(TableViz, self).query_obj() + fd = self.form_data + if fd.get('all_columns') and (fd.get('groupby') or fd.get('metrics')): + raise Exception( + "Choose either fields to [Group By] and [Metrics] or " + "[Columns], not both") + if fd.get('all_columns'): + d['columns'] = fd.get('all_columns') + d['groupby'] = [] d['is_timeseries'] = False d['timeseries_limit'] = None return d @@ -301,10 +321,6 @@ class PivotTableViz(BaseViz): ) },) - @property - def json_endpoint(self): - return self.get_url(async='true', standalone='true', skip_libs='true') - def query_obj(self): d = super(PivotTableViz, self).query_obj() groupby = self.form_data.get('groupby') @@ -343,6 +359,13 @@ def get_df(self): ) return df + def get_json_data(self): + return dumps(self.get_df().to_html( + na_rep='', + classes=( + "dataframe table table-striped table-bordered " + "table-condensed table-hover"))) + class MarkupViz(BaseViz): viz_type = "markup"