Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Big JS refactor #83

Merged
merged 1 commit into from
Dec 15, 2015
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -2,18 +2,23 @@
List of TODO items for Panoramix

## Improvments
* [druid] Allow for post aggregations (ratios!)
* [sql] define column based grouping
* [sql] make "Test Connection" test further
* csv export out of table view
* csv export
* json export (options)
* in/notin filters autocomplete
* [druid] Allow for post aggregations (ratios!)

## Better Javascript enables
* Async on Druidify! in exploration page
* Async form reload onchange of viz_type dropdown
* Reintroduce query and stopwatch
* Fix resize / refresh
* Configurable widget auto refresh in Dashboard view

## New Features
* Annotations layers

## Low value
* [sql] define column based grouping

## Community
* Creat a proper doc
* Usage vid
*
9 changes: 9 additions & 0 deletions panoramix/static/panoramix.css
Original file line number Diff line number Diff line change
@@ -11,6 +11,15 @@ form div {
color: white;
}

.header span{
margin-left: 3px;
}

#timer {
width: 80px;
text-align: right;
}

.notbtn {
cursor: default;
}
40 changes: 33 additions & 7 deletions panoramix/static/panoramix.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
var timer;
var px = (function() {

var visualizations = [];
@@ -14,18 +15,43 @@ var px = (function() {
}

function initializeWidget(data) {
var token = $('#' + data.token);
var name = data['viz_name'];
var initializer = visualizations[name];
var widget = initializer ? initializer(data) : makeNullWidget();
var user_defined_widget = initializer ? initializer(data) : makeNullWidget();
var dttm = 0;
var timer;
var stopwatch = function () {
dttm += 10;
$('#timer').text(Math.round(dttm/10)/100 + " sec");
}
var done = function (data) {
clearInterval(timer);
token.find("img.loading").hide();
if(data !== undefined)
$("#query_container").html(data.query);
$('#timer').removeClass('btn-warning');
$('span.query').removeClass('disabled');
$('#timer').addClass('btn-success');
}
widget = {
render: function() {
timer = setInterval(stopwatch, 10);
user_defined_widget.render(done);
},
resize: function() {
user_defined_widget.resize();
},
};
return widget;
}

function initializeDatasourceView() {
function getParam(name) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(location.search);
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
function initializeDatasourceView() {
function getParam(name) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(location.search);
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}

$(".select2").select2({dropdownAutoWidth : true});
8 changes: 4 additions & 4 deletions panoramix/static/widgets/viz_bignumber.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.viz_bignumber g.axis text {
.big_number g.axis text {
font-size: 10px;
font-weight: normal;
color: gray;
@@ -8,18 +8,18 @@
font-weight: none;
}

.viz_bignumber text.big {
.big_number text.big {
stroke: black;
text-anchor: middle;
fill: black;
}

.viz_bignumber g.tick line {
.big_number g.tick line {
stroke-width: 1px;
stroke: grey;
}

.viz_bignumber .domain {
.big_number .domain {
fill: none;
stroke: black;
stroke-width: 1;
4 changes: 3 additions & 1 deletion panoramix/static/widgets/viz_bignumber.js
Original file line number Diff line number Diff line change
@@ -4,14 +4,15 @@ px.registerWidget('big_number', function(data_attribute) {
var json_callback = data_attribute['json_endpoint'];
var div = d3.select('#' + token_name);

function render() {
function render(done) {
d3.json(json_callback, function(error, payload){
json = payload.data;
div.html("");
//Define the percentage bounds that define color from red to green
if (error != null){
var err = '<div class="alert alert-danger">' + error.responseText + '</div>';
div.html(err);
done(payload);
return '';
}
var color_range = [-1, 1];
@@ -136,6 +137,7 @@ px.registerWidget('big_number', function(data_attribute) {
div.select('g.digits').transition().duration(500).attr('opacity', 1);
div.select('g.axis').transition().duration(500).attr('opacity', 0);
});
done(payload);
});
};

11 changes: 11 additions & 0 deletions panoramix/static/widgets/viz_markup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
px.registerWidget('markup', function(data_attribute) {

function refresh(done) {
$('#code').attr('rows', '15')
done();
}
return {
render: refresh,
resize: refresh,
};
});
13 changes: 6 additions & 7 deletions panoramix/static/widgets/viz_nvd3.js
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ function viz_nvd3(data_attribute) {
var token = d3.select('#' + token_name);
var json_callback = data_attribute['json_endpoint'];
var chart = undefined;
var data = {};

function UTC(dttm){
return v = new Date(dttm.getUTCFullYear(), dttm.getUTCMonth(), dttm.getUTCDate(), dttm.getUTCHours(), dttm.getUTCMinutes(), dttm.getUTCSeconds());
@@ -27,17 +28,14 @@ function viz_nvd3(data_attribute) {
"#FFAA91", "#B4A76C", "#9CA299", "#565A5C"
];
var jtoken = $('#' + token_name);
var loading = $('#' + token_name).find("img.loading");
var chart_div = $('#' + token_name).find("div.chart");

var refresh = function() {
var refresh = function(done) {
chart_div.hide();
loading.show();
$.getJSON(json_callback, function(payload) {
var data = payload.data;
var viz = payload;
var viz_type = viz.form_data.viz_type;
$("#query_container").html(data.query);
nv.addGraph(function() {
if (viz_type === 'line') {
if (viz.form_data.show_brush) {
@@ -157,10 +155,11 @@ function viz_nvd3(data_attribute) {
return chart;
});
chart_div.show();
loading.hide();
}).fail(function(xhr) {
done(data);
})
.fail(function(xhr) {
var err = '<div class="alert alert-danger">' + xhr.responseText + '</div>';
loading.hide();
done(data);
chart_div.show();
chart_div.html(err);
});
3 changes: 3 additions & 0 deletions panoramix/static/widgets/viz_pivot_table.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
li.widget.pivot_table div.token {
overflow: auto;
}
32 changes: 32 additions & 0 deletions panoramix/static/widgets/viz_pivot_table.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
px.registerWidget('pivot_table', function(data_attribute) {
var token_name = data_attribute['token'];
var token = $('#' + token_name);
var form_data = data_attribute.form_data;

function refresh(done) {
token.load(data_attribute.json_endpoint, function(response, status, xhr){
if(status=="error"){
var err = '<div class="alert alert-danger">' + xhr.responseText + '</div>';
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();
});
}

return {
render: refresh,
resize: refresh,
};

});
4 changes: 2 additions & 2 deletions panoramix/static/widgets/viz_sunburst.js
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ Modified from http://bl.ocks.org/kerryrodden/7090426

function viz_sunburst(data_attribute) {
var token = d3.select('#' + data_attribute.token);
var render = function() {
var render = function(done) {
// Breadcrumb dimensions: width, height, spacing, width of tip/tail.
var b = {
w: 100, h: 30, s: 3, t: 10
@@ -48,7 +48,7 @@ function viz_sunburst(data_attribute) {
}
var tree = buildHierarchy(json.data);
createVisualization(tree);
token.select("img.loading").remove();
done(json);
});

// Main function to draw and set up the visualization, once we have the data.
3 changes: 3 additions & 0 deletions panoramix/static/widgets/viz_table.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
li.widget.table div.token {
overflow: auto;
}
31 changes: 31 additions & 0 deletions panoramix/static/widgets/viz_table.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
px.registerWidget('table', function(data_attribute) {

var token_name = data_attribute['token'];
var token = $('#' + token_name);

function refresh(done) {
token.load(data_attribute.json_endpoint, function(response, status, xhr){
if(status=="error"){
var err = '<div class="alert alert-danger">' + xhr.responseText + '</div>';
token.html(err);
token.show();
done();
}
else{
var table = token.find('table').DataTable({
paging: false,
searching: false,
});
table.column('-1').order( 'desc' ).draw();
}
token.show();
done();
});
}

return {
render: refresh,
resize: refresh,
};

});
4 changes: 3 additions & 1 deletion panoramix/static/widgets/viz_wordcloud.js
Original file line number Diff line number Diff line change
@@ -4,11 +4,12 @@ px.registerWidget('word_cloud', function(data_attribute) {
var json_callback = data_attribute['json_endpoint'];
var token = d3.select('#' + token_name);

function refresh() {
function refresh(done) {
d3.json(json_callback, function(error, json) {
if (error != null){
var err = '<div class="alert alert-danger">' + error.responseText + '</div>';
token.html(err);
done();
return '';
}
var data = json.data;
@@ -62,6 +63,7 @@ px.registerWidget('word_cloud', function(data_attribute) {
})
.text(function(d) { return d.text; });
}
done(data);
});
}

5 changes: 4 additions & 1 deletion panoramix/templates/panoramix/dashboard.html
Original file line number Diff line number Diff line change
@@ -109,7 +109,10 @@ <h2>
</tr>
</tbody>
</table>
{{ viz_macros.viz_html(viz) }}
<div id="{{ viz.token }}" class="token" style="height: 100%;">
<img src="{{ url_for("static", filename="img/loading.gif") }}" class="loading" alt="loading">
{{ viz_macros.viz_html(viz) }}
</div>
</li>
{% endfor %}
</ul>
17 changes: 10 additions & 7 deletions panoramix/templates/panoramix/explore.html
Original file line number Diff line number Diff line change
@@ -33,8 +33,9 @@
</a>
</span>
<span>{{ form.get_field("viz_type")(class_="select2") }}</span>
<span class="btn btn-info pull-right"
<span class="btn btn-info pull-right disabled query"
data-toggle="modal" data-target="#query_modal">query</span>
<span class="btn btn-warning pull-right notbtn" id="timer">0 sec</span>
<hr/>
</div>
<div class="row">
@@ -129,16 +130,18 @@
{% endblock %}
{% include 'appbuilder/flash.html' %}
<div
id="{{ viz.token }}"
class="viz widget {{ viz.viz_type }}"
data-widget="{{ viz.get_data_attribute() }}"
style="height: 700px;">
<img src="{{ url_for("static", filename="img/loading.gif") }}" class="loading" alt="loading">
{% block viz_html %}
{% if viz.error_msg %}
<div class="alert alert-danger">{{ viz.error_msg }}</div>
{% endif %}
{% if viz.warning_msg %}
<div class="alert alert-warning">{{ viz.warning_msg }}</div>
{% endif %}
{% if viz.error_msg %}
<div class="alert alert-danger">{{ viz.error_msg }}</div>
{% endif %}
{% if viz.warning_msg %}
<div class="alert alert-warning">{{ viz.warning_msg }}</div>
{% endif %}
{% endblock %}
</div>
</div>
4 changes: 1 addition & 3 deletions panoramix/templates/panoramix/viz_bignumber.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
{% macro viz_html(viz) %}
<div id="{{ viz.token }}" class="viz_bignumber" style="height: 100%;">
<img src="{{ url_for("static", filename="img/loading.gif") }}" class="loading">
</div>
<div id="{{ viz.token }}" class="viz_bignumber" style="height: 100%;"></div>
{% endmacro %}

{% macro viz_js(viz) %}
3 changes: 0 additions & 3 deletions panoramix/templates/panoramix/viz_nvd3.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
{% macro viz_html(viz) %}
<div id="{{ viz.token }}" style="height:100%; width: 100%">
<img src="{{ url_for("static", filename="img/loading.gif") }}" class="loading">
<div class="chart with-3d-shadow with-transitions" style="height:100%; width: 100%"></div>
</div>
{% endmacro %}

{% macro viz_js(viz) %}
26 changes: 2 additions & 24 deletions panoramix/templates/panoramix/viz_pivot_table.html
Original file line number Diff line number Diff line change
@@ -1,37 +1,15 @@
{% 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 }}

{{ 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">
<div id="{{ viz.token }}" style="display: none;overflow: auto; height: 100%;"></div>
{% 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') and 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 %}
7 changes: 1 addition & 6 deletions panoramix/templates/panoramix/viz_sunburst.html
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
{% macro viz_html(viz) %}
<div id="{{ viz.token }}" class="token">
<div id="chart">
<img src="{{ url_for("static", filename="img/loading.gif") }}" class="loading">
</div>
</div>
<div id="chart"></div>
{% endmacro %}

{% macro viz_js(viz) %}
{% endmacro %}

{% macro viz_css(viz) %}
{% endmacro %}

75 changes: 25 additions & 50 deletions panoramix/templates/panoramix/viz_table.html
Original file line number Diff line number Diff line change
@@ -1,61 +1,36 @@
{% macro viz_html(viz) %}
{% if viz.request.args.get("async") == "true" %}
{% set df = viz.get_df() %}
<table class="dataframe table table-striped table-bordered table-condensed">
<thead>
<tr>
{% for col in df.columns if not col.endswith('__perc') %}
<th>{{ col }}</th>
<div class="table">
<table class="dataframe table table-striped table-bordered table-condensed">
<thead>
<tr>
{% for col in df.columns if not col.endswith('__perc') %}
<th>{{ col }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in df.to_dict(orient="records") %}
<tr>
{% for col in df.columns if not col.endswith('__perc') %}
{% if col + '__perc' in df.columns %}
<td style="background-image: linear-gradient(to right, lightgrey, lightgrey {{ row[col+'__perc'] }}%, rgba(0,0,0,0) {{ row[col+'__perc'] }}%">
{{ row[col] }}
</td>
{% else %}
<td>{{ row[col] }}</td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in df.to_dict(orient="records") %}
<tr>
{% for col in df.columns if not col.endswith('__perc') %}
{% if col + '__perc' in df.columns %}
<td style="background-image: linear-gradient(to right, lightgrey, lightgrey {{ row[col+'__perc'] }}%, rgba(0,0,0,0) {{ row[col+'__perc'] }}%">
{{ row[col] }}
</td>
{% else %}
<td>{{ row[col] }}</td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<div id="{{ viz.token }}" style="display: none;overflow: auto; height: 100%;"></div>
<img src="{{ url_for("static", filename="img/loading.gif") }}" class="loading">
</tbody>
</table>
</div>
{% 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{
var table = token.find('table').DataTable({
paging: false,
searching: false,
});
table.column('-1').order( 'desc' ).draw();
}
token.show();
token.parent().find("img.loading").hide();
});
});
</script>
{% endif %}
{% endmacro %}

{% macro viz_css(viz) %}
4 changes: 1 addition & 3 deletions panoramix/templates/panoramix/viz_word_cloud.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
{% macro viz_html(viz) %}
<div id="{{ viz.token }}" style="height: 100%;">
<img src="{{ url_for("static", filename="img/loading.gif") }}" class="loading">
</div>
<div id="{{ viz.token }}" style="height: 100%;"></div>
{% endmacro %}

{% macro viz_js(viz) %}
33 changes: 28 additions & 5 deletions panoramix/viz.py
Original file line number Diff line number Diff line change
@@ -65,6 +65,7 @@ def __init__(self, datasource, form_data):
if k in form.data}
defaults.update(data)
self.form_data = defaults
self.query = ""

self.form_data['previous_viz_type'] = self.viz_type
self.token = self.form_data.get(
@@ -127,6 +128,7 @@ def get_df(self, query_obj=None):
self.results = None

self.results = self.datasource.query(**query_obj)
self.query = self.results.query
df = self.results.df
if df is None or df.empty:
raise Exception("No data, review your incantations!")
@@ -201,20 +203,26 @@ def query_obj(self):
def get_json(self):
payload = {
'data': json.loads(self.get_json_data()),
'query': self.query,
'form_data': self.form_data,
}
return json.dumps(payload)

def get_json_data(self):
return json.dumps([])

@property
def json_endpoint(self):
return self.get_url(json="true")

def get_data_attribute(self):
content = {
'viz_name': self.viz_type,
'json_endpoint': self.get_url(json="true"),
'json_endpoint': self.json_endpoint,
'token': self.token,
'form_data': self.form_data,
}
return json.dumps(content)
return dumps(content)

class TableViz(BaseViz):
viz_type = "table"
@@ -234,7 +242,14 @@ class TableViz(BaseViz):
is_timeseries = False
js_files = [
'lib/dataTables/jquery.dataTables.min.js',
'lib/dataTables/dataTables.bootstrap.js']
'lib/dataTables/dataTables.bootstrap.js',
'widgets/viz_table.js',
]
css_files = ['widgets/viz_table.css']

@property
def json_endpoint(self):
return self.get_url(async='true', standalone='true', skip_libs='true')

def query_obj(self):
d = super(TableViz, self).query_obj()
@@ -257,11 +272,14 @@ class PivotTableViz(BaseViz):
viz_type = "pivot_table"
verbose_name = "Pivot Table"
template = 'panoramix/viz_pivot_table.html'
css_files = ['lib/dataTables/dataTables.bootstrap.css']
css_files = [
'lib/dataTables/dataTables.bootstrap.css',
'widgets/viz_pivot_table.css']
is_timeseries = False
js_files = [
'lib/dataTables/jquery.dataTables.min.js',
'lib/dataTables/dataTables.bootstrap.js']
'lib/dataTables/dataTables.bootstrap.js',
'widgets/viz_pivot_table.js']
fieldsets = (
{
'label': None,
@@ -275,6 +293,10 @@ 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')
@@ -318,6 +340,7 @@ class MarkupViz(BaseViz):
viz_type = "markup"
verbose_name = "Markup Widget"
template = 'panoramix/viz_markup.html'
js_files = ['widgets/viz_markup.js']
fieldsets = (
{
'label': None,