Skip to content

Commit

Permalink
Allowing to define a default format string per-metric
Browse files Browse the repository at this point in the history
  • Loading branch information
mistercrunch committed Jul 13, 2016
1 parent 18b8e6f commit 556e99a
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 7 deletions.
7 changes: 7 additions & 0 deletions caravel/assets/javascripts/modules/caravel.js
Expand Up @@ -2,6 +2,7 @@ var $ = require('jquery');
var jQuery = $;
var d3 = require('d3');
var Mustache = require('mustache');
var utils = require('./utils');

// vis sources
var sourceMap = {
Expand Down Expand Up @@ -234,6 +235,12 @@ var px = (function () {
endpoint += "&force=" + this.force;
return endpoint;
},
d3format: function (col, number) {
// uses the utils memoized d3format function and formats based on
// column level defined preferences
var format = this.data.column_formats[col];
return utils.d3format(format, number);
},
done: function (data) {
clearInterval(timer);
token.find("img.loading").hide();
Expand Down
13 changes: 12 additions & 1 deletion caravel/assets/javascripts/modules/utils.js
Expand Up @@ -105,9 +105,20 @@ var fixDataTableBodyHeight = function ($tableDom, height) {
.css('max-height', height - headHeight);
};

var formatters = {};
function d3format(format, number) {
// Formats a number and memoizes formatters to be reused
format = format || '.3s';
if (!(format in formatters)) {
formatters[format] = d3.format(format);
}
return formatters[format](number);
}

module.exports = {
wrapSvgText: wrapSvgText,
showModal: showModal,
toggleCheckbox: toggleCheckbox,
fixDataTableBodyHeight: fixDataTableBodyHeight
fixDataTableBodyHeight: fixDataTableBodyHeight,
d3format: d3format
};
5 changes: 2 additions & 3 deletions caravel/assets/visualizations/table.js
Expand Up @@ -2,14 +2,13 @@ var $ = window.$ = require('jquery');
var jQuery = window.jQuery = $;
var d3 = require('d3');
var px = window.px || require('../javascripts/modules/caravel.js');
var utils = require('../javascripts/modules/utils.js');

require('./table.css');
require('datatables.net-bs');
require('../node_modules/datatables-bootstrap3-plugin/media/css/datatables-bootstrap3.css');
var utils = require('../javascripts/modules/utils');

function tableVis(slice) {
var f = d3.format('.3s');
var fC = d3.format('0,000');
var timestampFormatter;

Expand Down Expand Up @@ -120,7 +119,7 @@ function tableVis(slice) {
})
.html(function (d) {
if (d.isMetric) {
return f(d.val);
return slice.d3format(d.col, d.val);
} else {
return d.val;
}
Expand Down
24 changes: 24 additions & 0 deletions caravel/migrations/versions/f162a1dea4c4_d3format_by_metric.py
@@ -0,0 +1,24 @@
"""d3format_by_metric
Revision ID: f162a1dea4c4
Revises: 960c69cb1f5b
Create Date: 2016-07-06 22:04:28.685100
"""

# revision identifiers, used by Alembic.
revision = 'f162a1dea4c4'
down_revision = '960c69cb1f5b'

from alembic import op
import sqlalchemy as sa


def upgrade():
op.add_column('metrics', sa.Column('d3format', sa.String(length=128), nullable=True))
op.add_column('sql_metrics', sa.Column('d3format', sa.String(length=128), nullable=True))


def downgrade():
op.drop_column('sql_metrics', 'd3format')
op.drop_column('metrics', 'd3format')
2 changes: 2 additions & 0 deletions caravel/models.py
Expand Up @@ -865,6 +865,7 @@ class SqlMetric(Model, AuditMixinNullable):
expression = Column(Text)
description = Column(Text)
is_restricted = Column(Boolean, default=False, nullable=True)
d3format = Column(String(128))

@property
def sqla_col(self):
Expand Down Expand Up @@ -1493,6 +1494,7 @@ class DruidMetric(Model, AuditMixinNullable):
json = Column(Text)
description = Column(Text)
is_restricted = Column(Boolean, default=False, nullable=True)
d3format = Column(String(128))

@property
def json_obj(self):
Expand Down
2 changes: 1 addition & 1 deletion caravel/templates/caravel/dashboard.html
Expand Up @@ -2,7 +2,7 @@

{% block head_js %}
{{ super() }}
<script src="/static/assets/javascripts/dist/dashboard.entry.js"></script>
<script src="/static/assets/javascripts/dist/dashboard.entry.jsx"></script>
{% endblock %}
{% block title %}[dashboard] {{ dashboard.dashboard_title }}{% endblock %}
{% block body %}
Expand Down
11 changes: 9 additions & 2 deletions caravel/views.py
Expand Up @@ -278,7 +278,7 @@ class SqlMetricInlineView(CompactCRUDMixin, CaravelModelView): # noqa
list_columns = ['metric_name', 'verbose_name', 'metric_type']
edit_columns = [
'metric_name', 'description', 'verbose_name', 'metric_type',
'expression', 'table', 'is_restricted']
'expression', 'table', 'd3format', 'is_restricted']
description_columns = {
'expression': utils.markdown(
"a valid SQL expression as supported by the underlying backend. "
Expand All @@ -287,6 +287,13 @@ class SqlMetricInlineView(CompactCRUDMixin, CaravelModelView): # noqa
"to certain roles. Only roles with the permission "
"'metric access on XXX (the name of this metric)' "
"are allowed to access this metric"),
'd3format': utils.markdown(
"d3 formatting string as defined [here]"
"(https://github.com/d3/d3-format/blob/master/README.md#format). "
"For instance, this default formatting applies in the Table "
"visualization and allow for different metric to use different "
"formats", True
),
}
add_columns = edit_columns
page_size = 500
Expand All @@ -313,7 +320,7 @@ class DruidMetricInlineView(CompactCRUDMixin, CaravelModelView): # noqa
list_columns = ['metric_name', 'verbose_name', 'metric_type']
edit_columns = [
'metric_name', 'description', 'verbose_name', 'metric_type', 'json',
'datasource', 'is_restricted']
'datasource', 'd3format', 'is_restricted']
add_columns = edit_columns
page_size = 500
validators_columns = {
Expand Down
7 changes: 7 additions & 0 deletions caravel/viz.py
Expand Up @@ -310,6 +310,7 @@ def get_json(self):
# cache.set call can fail if the backend is down or if
# the key is too large or whatever other reasons
logging.warning("Could not cache key {}".format(cache_key))
logging.exception(e)
cache.delete(cache_key)
payload['is_cached'] = is_cached
return self.json_dumps(payload)
Expand All @@ -320,13 +321,19 @@ def json_dumps(self, obj):

@property
def data(self):
"""This is the data object serialized to the js layer"""
content = {
'csv_endpoint': self.csv_endpoint,
'form_data': self.form_data,
'json_endpoint': self.json_endpoint,
'standalone_endpoint': self.standalone_endpoint,
'token': self.token,
'viz_name': self.viz_type,
'column_formats': {
m.metric_name: m.d3format
for m in self.datasource.metrics
if m.d3format
},
}
return content

Expand Down

0 comments on commit 556e99a

Please sign in to comment.