Skip to content

Commit

Permalink
Merge pull request #66 from mistercrunch/pivot_table
Browse files Browse the repository at this point in the history
Adding a PivotTableViz
  • Loading branch information
mistercrunch committed Nov 26, 2015
2 parents 7cd3696 + b0f7b3c commit 852e3c6
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 0 deletions.
14 changes: 14 additions & 0 deletions panoramix/bin/panoramix
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,20 @@ The source dataset came from [here](https://github.com/hadley/babynames)
session.add(slc)
slices.append(slc)

slice_name = "Pivot Table"
slc = session.query(Slice).filter_by(slice_name=slice_name).first()
if not slc:
slc = Slice(
slice_name=slice_name,
viz_type='pivot_table',
datasource_type='table',
table=tbl,
params=get_slice_json(
slice_name, viz_type="pivot_table", metrics=['sum__num'],
groupby=['name'], columns=['state']))
session.add(slc)
slices.append(slc)

print("Creating a dashboard")
Dash = models.Dashboard
dash = session.query(Dash).filter_by(dashboard_title="Births").first()
Expand Down
13 changes: 13 additions & 0 deletions panoramix/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ def __init__(self, viz):
'Group by',
choices=self.choicify(datasource.groupby_column_names),
description="One or many fields to group by"),
'columns': SelectMultipleField(
'Columns',
choices=self.choicify(datasource.groupby_column_names),
description="One or many fields to pivot as columns"),
'granularity': TextField(
'Time Granularity', default="one day",
description=(
Expand Down Expand Up @@ -182,6 +186,14 @@ def __init__(self, viz):
default='linear',
description="Line interpolation as defined by d3.js"),
'code': TextAreaField("Code", description="Put your code here", default=''),
'pandas_aggfunc': SelectField(
"Aggregation function",
choices=self.choicify([
'sum', 'mean', 'min', 'max', 'median', 'stdev', 'var']),
default='sum',
description=(
"Aggregate function to apply when pivoting and "
"computing the total rows and columns")),
'size_from': TextField(
"Font Size From",
default="20",
Expand Down Expand Up @@ -241,6 +253,7 @@ def get_form(self, previous=False):
field_css_classes = {k: ['form-control'] for k in px_form_fields.keys()}
select2 = [
'viz_type',
'viz_type', 'columns', 'pandas_aggfunc',
'row_limit', 'rolling_type', 'series',
'entity', 'x', 'y', 'size', 'rotation', 'metric', 'limit',
'markup_type',]
Expand Down
41 changes: 41 additions & 0 deletions panoramix/templates/panoramix/viz_pivot_table.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{% 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 %}
<div id="{{ viz.token }}" style="display: none;overflow: auto; height: 100%;"></div>
<img src="{{ url_for("static", filename="img/loading.gif") }}" class="loading">
{% endif %}
{% endmacro %}

{% macro viz_js(viz) %}
{% if viz.form_data.get("async") != "true" %}
<script>
$( document ).ready(function() {
var url = "{{ viz.get_url(async="true", standalone="true", skip_libs="true")|safe }}";
var token = $("#{{ viz.token }}");
token.load(url, function(response, status, xhr){
if(status=="error"){
var err = '<div class="alert alert-danger">' + xhr.responseText + '</div>';
token.html(err);
token.show();
}
else{
{% if viz.form_data.get('groupby')|length == 1 %}
var table = token.find('table').DataTable({
paging: false,
searching: false,
});
table.column('-1').order( 'desc' ).draw();
{% endif %}
}
token.show();
token.parent().find("img.loading").hide();
});
});
</script>
{% endif %}
{% endmacro %}

{% macro viz_css(viz) %}
{% endmacro %}
55 changes: 55 additions & 0 deletions panoramix/viz.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,60 @@ def get_df(self):
return df


class PivotTableViz(BaseViz):
viz_type = "pivot_table"
verbose_name = "Pivot Table"
template = 'panoramix/viz_pivot_table.html'
css_files = ['lib/dataTables/dataTables.bootstrap.css']
is_timeseries = False
js_files = [
'lib/dataTables/jquery.dataTables.min.js',
'lib/dataTables/dataTables.bootstrap.js']
form_fields = [
'viz_type',
'granularity',
('since', 'until'),
'groupby',
'columns',
'metrics',
'pandas_aggfunc',
]

def query_obj(self):
d = super(PivotTableViz, self).query_obj()
groupby = self.form_data.get('groupby')
columns = self.form_data.get('columns')
metrics = self.form_data.get('metrics')
if not groupby:
raise Exception("Please choose at least one \"Group by\" field ")
if not metrics:
raise Exception("Please choose at least one metric")
if (
any(v in groupby for v in columns) or
any(v in columns for v in groupby)):
raise Exception("groupby and columns can't overlap")

d['groupby'] = list(set(d['groupby']) | set(self.form_data.get('columns')))
d['is_timeseries'] = False
d['timeseries_limit'] = None
return d

def get_df(self):
df = super(PivotTableViz, self).get_df()
if (
self.form_data.get("granularity") == "all" and
'timestamp' in df):
del df['timestamp']
df = df.pivot_table(
index=self.form_data.get('groupby'),
columns=self.form_data.get('columns'),
values=self.form_data.get('metrics'),
aggfunc=self.form_data.get('pandas_aggfunc'),
margins=True,
)
return df


class MarkupViz(BaseViz):
viz_type = "markup"
verbose_name = "Markup Widget"
Expand Down Expand Up @@ -648,6 +702,7 @@ def get_json_data(self):

viz_types_list = [
TableViz,
PivotTableViz,
NVD3TimeSeriesViz,
NVD3CompareTimeSeriesViz,
NVD3TimeSeriesStackedViz,
Expand Down

0 comments on commit 852e3c6

Please sign in to comment.