Skip to content

Commit

Permalink
Move histogram-related functions to their own file, start adding supp…
Browse files Browse the repository at this point in the history
…ort for the 'explore' DSL parser, add a stub for iframe-specfic CSS.
  • Loading branch information
beaugunderson committed Feb 28, 2012
1 parent e9e6a76 commit 2c3c771
Show file tree
Hide file tree
Showing 7 changed files with 737 additions and 73 deletions.
Empty file added css/iframe.css
Empty file.
13 changes: 8 additions & 5 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@
'js-lib/codemirror2/lib/util/simple-hint.js',
'js-lib/codemirror2/lib/util/javascript-hint.js',

'parser/explore.js',

'js/d3-histogram.js',
'js/viz-histogram.js',

'js/config.js',
'js/script.js',
Expand Down Expand Up @@ -133,11 +136,11 @@ <h3>Function definition</h3>
</div>

<div class="modal-body">
<textarea id="function-definition">
// You're writing the body of a function that receives
// an argument named 'value'. This allows you to coerce
// a value that's not numeric to a number for graphing.
return value;</textarea>
<p>
Valid variables are <code>values</code>. Valid functions are <code>add</code>, <code>subtract</code>, <code>abs</code>, <code>parseInteger</code>, <code>parseFloat</code>, <code>length</code>, and <code>uniqueCharacters</code>. They can be nested.
</p>

<textarea id="function-definition"></textarea>

<div id="function-output-wrapper">
<strong>Output:</strong> <span id="function-output"></span>
Expand Down
87 changes: 19 additions & 68 deletions js/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,6 @@ function formatField(field) {
'</li>', field);
}

function formatHistogramField(field) {
return sprintf(
'<li>' +
'%(name)s' +
'</li>', field);
}

function updateSource(collection) {
$('#numbers, #strings').html('');

Expand Down Expand Up @@ -309,6 +302,7 @@ var graphTypes = {
}
};

// Get the list of collections from the map
function collectionsFromMap(map) {
var collections = {};

Expand All @@ -326,6 +320,7 @@ function collectionsFromMap(map) {
return collections;
}

// Get the list of connectors from the map
function connectorsFromMap(map) {
var connectors = {};

Expand All @@ -351,6 +346,7 @@ function connectorsFromMap(map) {
return connectors;
}

// Runs when any input is changed
function validateFields() {
var graphType = getGraphType();
var source = getSource();
Expand Down Expand Up @@ -404,32 +400,6 @@ function render() {
graphType.render(data);
}

function formatHistogramData(fields, data) {
// TODO: Change data format to include context (for hovertips, etc.)
var data = [];

// XXX: Don't hardcode this?
var path = $('#graph-fields input[data-field=value]').val();

var source = getSource();

_.each(source.data, function(datum) {
data.push(propertyByPath(datum, path));
});

// Coerce strings to their length for XXX numeric fields
data = _.map(data, function(datum) {
if (typeof datum == "string") {
return datum.length;
}

return datum;
});

// Return the scrubbed data
return _.without(data, undefined, null, false, NaN, '');
}

function propertyByPath(obj, path) {
var segments = path.split('.');

Expand All @@ -446,41 +416,6 @@ function propertyByPath(obj, path) {
return currentObj;
}

function renderHistogram(data) {
var uniqueValues = _.uniq(data).length;

var settings = {
data: data,
height: 400,
bins: Math.min(uniqueValues, 25),
bottompad: 15,
toppad: 25,
labelsize: 10,
labelGenerator: function(d, i) {
var val = d3.round(d.y);

if (val == 0) {
return '';
} else {
return val;
}
},
rangeGenerator: function(d) {
return sprintf('%d', Math.ceil(d.x));
}
};

// XXX: Don't hardcode this?
var path = $('#graph-fields input[data-field=value]').val();

var source = getSource();

$('#title').html(sprintf('Histogram of <em>%s</em> data', source.name));
$('#sub-title').text(path);

$('#canvas').d3histogram(settings);
}

// XXX: Refactor this
function getSource() {
var $selected = $('#data-sources').find(':selected');
Expand All @@ -505,6 +440,22 @@ function getSource() {
}
}

function applyFunction(f, values) {
explore.yy = {
data: {
values: values
},
_: _,
apply: function(data, f) {
return _.map(data, function(datum) {
return f(datum);
});
}
};

return explore.parse(f);
}

var sources = {};

// State:
Expand Down
67 changes: 67 additions & 0 deletions js/viz-histogram.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
function formatHistogramField(field) {
return sprintf(
'<li>' +
'%(name)s' +
'</li>', field);
}

function formatHistogramData(fields, data) {
// TODO: Change data format to include context (for hovertips, etc.)
var data = [];

// XXX: Don't hardcode this?
var path = $('#graph-fields input[data-field=value]').val();

var source = getSource();

_.each(source.data, function(datum) {
data.push(propertyByPath(datum, path));
});

// Coerce strings to their length for XXX numeric fields
data = _.map(data, function(datum) {
if (typeof datum == "string") {
return datum.length;
}

return datum;
});

// Return the scrubbed data
return _.without(data, undefined, null, false, NaN, '');
}

function renderHistogram(data) {
var uniqueValues = _.uniq(data).length;

var settings = {
data: data,
height: 400,
bins: Math.min(uniqueValues, 25),
bottompad: 15,
toppad: 25,
labelsize: 10,
labelGenerator: function(d, i) {
var val = d3.round(d.y);

if (val == 0) {
return '';
} else {
return val;
}
},
rangeGenerator: function(d) {
return sprintf('%d', Math.ceil(d.x));
}
};

// XXX: Don't hardcode this?
var path = $('#graph-fields input[data-field=value]').val();

var source = getSource();

$('#title').html(sprintf('Histogram of <em>%s</em> data', source.name));
$('#sub-title').text(path);

$('#canvas').d3histogram(settings);
}
143 changes: 143 additions & 0 deletions parser/explore.jison
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
%lex

%%

\s+ /* skip */
"//".* /* ignore comment */
"/*"[\w\W]*?"*/" /* ignore comment */
"*" return '*';
"/" return '/';
"-" return '-';
"+" return '+';
"^" return '^';
"(" return '(';
")" return ')';
"[" return '[';
"]" return ']';
"," return ',';
[a-zA-Z_]+[a-zA-Z0-9_]* return 'STRING';
[0-9]+("."[0-9]*)? return 'NUMBER';
"."[0-9]+ return 'NUMBER';
<<EOF>> return 'EOF';

/lex

%left '+' '-'
%left '*' '/'
%left '^'
%left NEG POS

%%

expressions
: e EOF
{ return $1; }
;

num
: n
| '+' n
{ $$ = $2; }
| '-' n
{ $$ = -$2; }
| '(' e ')'
{ $$ = $2; }
| function
;

e
: n
| e '+' e
{ $$ = $1 + $3; }
| e '-' e
{ $$ = $1 - $3; }
| e '*' e
{ $$ = $1 * $3; }
| e '/' e
{ $$ = $1 / $3; }
| e '^' e
{ $$ = Math.pow($1, $3); }
| '+' e %prec POS
{ $$ = $2; }
| '-' e %prec NEG
{ $$ = -$2; }
| '(' e ')'
{ $$ = $2; }
| variable
| function
;

function
: id '(' e ')'
{{
switch ($1) {
case 'cos':
case 'sin':
case 'tan':
$$ = yy.apply($3, function(a) { return Math[$1](a * Math.PI / 180); });
break;
case 'acos':
case 'asin':
case 'atan':
$$ = yy.apply($3, function(a) { return Math[$1](a) / Math.PI * 180; });
break;
case 'log':
case 'exp':
case 'sqrt':
case 'abs':
$$ = yy.apply($3, function(a) { return Math[$1](a); });
break;
case 'log10':
$$ = yy.apply($3, function(a) { return Math.log(a) * Math.LOG10E; });
break;
case 'parseFloat':
$$ = yy.apply($3, function(a) { return parseFloat(a, 10); });
break;
case 'parseInt':
$$ = yy.apply($3, function(a) { return parseInt(a, 10); });
break;
case 'length':
$$ = yy.apply($3, function(a) { return a.length; });
break;
case 'uniqueCharacters':
$$ = yy.apply($3, function(a) { return yy._(a.split('')).uniq().length; });
break;
default:
throw new Error('function \'' + $1 + '\' is not defined');
}
}}
| id '(' e ',' e ')'
{{
switch ($1) {
case 'add':
$$ = yy.apply($3, function(a) { return a + $5; });
break;
case 'subtract':
$$ = yy.apply($3, function(a) { return a - $5; });
break;
case 'atan2':
$$ = Math.atan2($3, $5) / Math.PI * 180;
break;
case 'mod':
$$ = $3 % $5;
break;
default:
throw new Error('function \'' + $1 + '\' is not defined');
}
}}
;

n
: NUMBER
{ $$ = parseFloat(yytext, 10); }
;

variable
: id
{ $$ = yy.data[$1]; }
;

id
: STRING
{ $$ = yytext; }
;
Loading

0 comments on commit 2c3c771

Please sign in to comment.