vue-bokeh
Version:
A wrapper around bokehjs embedded
468 lines (452 loc) • 12.4 kB
JavaScript
var $, Document, _, bar, cumsum, embed, hexcolor2rgb, is_dark, models, num2hexcolor, palettes, pie, sprintf, sum;
_ = require("underscore");
$ = require("jquery");
sprintf = require("sprintf");
Document = require("../document").Document;
embed = require("../embed");
models = require("./models");
palettes = require("../palettes/palettes");
sum = function(array) {
return array.reduce(((function(_this) {
return function(a, b) {
return a + b;
};
})(this)), 0);
};
cumsum = function(array) {
var result;
result = [];
array.reduce((function(a, b, i) {
return result[i] = a + b;
}), 0);
return result;
};
num2hexcolor = function(num) {
return sprintf("#%06x", num);
};
hexcolor2rgb = function(color) {
var b, g, r;
r = parseInt(color.substr(1, 2), 16);
g = parseInt(color.substr(3, 2), 16);
b = parseInt(color.substr(5, 2), 16);
return [r, g, b];
};
is_dark = function(arg) {
var b, g, l, r;
r = arg[0], g = arg[1], b = arg[2];
l = 1 - (0.299 * r + 0.587 * g + 0.114 * b) / 255;
return l >= 0.6;
};
pie = function(data, opts) {
var angle_span, colors, cumulative_values, cx, cy, end_angle, end_angles, g1, g2, h1, half_angles, half_radius, hover, i, inner_radius, k, labels, normalized_values, outer_radius, palette, plot, r1, r2, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, source, start_angle, start_angles, text_angles, text_colors, text_cx, text_cy, to_cartesian, to_radians, tooltip, total_value, values, xdr, ydr;
if (opts == null) {
opts = {};
}
labels = [];
values = [];
for (i = k = 0, ref = Math.min(data.labels.length, data.values.length); 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) {
if (data.values[i] > 0) {
labels.push(data.labels[i]);
values.push(data.values[i]);
}
}
start_angle = (ref1 = opts.start_angle) != null ? ref1 : 0;
end_angle = (ref2 = opts.end_angle) != null ? ref2 : start_angle + 2 * Math.PI;
angle_span = Math.abs(end_angle - start_angle);
to_radians = function(x) {
return angle_span * x;
};
total_value = sum(values);
normalized_values = values.map(function(v) {
return v / total_value;
});
cumulative_values = cumsum(normalized_values);
end_angles = cumulative_values.map(function(v) {
return start_angle + to_radians(v);
});
start_angles = [start_angle].concat(end_angles.slice(0, -1));
half_angles = _.zip(start_angles, end_angles).map((function(_this) {
return function(arg) {
var end, start;
start = arg[0], end = arg[1];
return (start + end) / 2;
};
})(this));
if (opts.center == null) {
cx = 0;
cy = 0;
} else if (_.isArray(opts.center)) {
cx = opts.center[0];
cy = opts.center[1];
} else {
cx = opts.center.x;
cy = opts.center.y;
}
inner_radius = (ref3 = opts.inner_radius) != null ? ref3 : 0;
outer_radius = (ref4 = opts.outer_radius) != null ? ref4 : 1;
if (_.isArray(opts.palette)) {
palette = opts.palette;
} else {
palette = palettes[(ref5 = opts.palette) != null ? ref5 : "Spectral11"].map(num2hexcolor);
}
colors = (function() {
var m, ref6, results;
results = [];
for (i = m = 0, ref6 = normalized_values.length; 0 <= ref6 ? m < ref6 : m > ref6; i = 0 <= ref6 ? ++m : --m) {
results.push(palette[i % palette.length]);
}
return results;
})();
text_colors = colors.map(function(c) {
if (is_dark(hexcolor2rgb(c))) {
return "white";
} else {
return "black";
}
});
to_cartesian = function(r, alpha) {
return [r * Math.cos(alpha), r * Math.sin(alpha)];
};
half_radius = (inner_radius + outer_radius) / 2;
ref6 = _.unzip(half_angles.map((function(_this) {
return function(half_angle) {
return to_cartesian(half_radius, half_angle);
};
})(this))), text_cx = ref6[0], text_cy = ref6[1];
text_cx = text_cx.map(function(x) {
return x + cx;
});
text_cy = text_cy.map(function(y) {
return y + cy;
});
text_angles = half_angles.map(function(a) {
if (a >= Math.PI / 2 && a <= 3 * Math.PI / 2) {
return a + Math.PI;
} else {
return a;
}
});
source = new Bokeh.ColumnDataSource({
data: {
labels: labels,
values: values,
percentages: normalized_values.map((function(_this) {
return function(v) {
return sprintf("%.2f%%", v * 100);
};
})(this)),
start_angles: start_angles,
end_angles: end_angles,
text_angles: text_angles,
colors: colors,
text_colors: text_colors,
text_cx: text_cx,
text_cy: text_cy
}
});
g1 = new models.AnnularWedge({
x: cx,
y: cy,
inner_radius: inner_radius,
outer_radius: outer_radius,
start_angle: {
field: "start_angles"
},
end_angle: {
field: "end_angles"
},
line_color: null,
line_width: 1,
fill_color: {
field: "colors"
}
});
h1 = new models.AnnularWedge({
x: cx,
y: cy,
inner_radius: inner_radius,
outer_radius: outer_radius,
start_angle: {
field: "start_angles"
},
end_angle: {
field: "end_angles"
},
line_color: null,
line_width: 1,
fill_color: {
field: "colors"
},
fill_alpha: 0.8
});
r1 = new models.GlyphRenderer({
data_source: source,
glyph: g1,
hover_glyph: h1
});
g2 = new models.Text({
x: {
field: "text_cx"
},
y: {
field: "text_cy"
},
text: {
field: (ref7 = opts.slice_labels) != null ? ref7 : "labels"
},
angle: {
field: "text_angles"
},
text_align: "center",
text_baseline: "middle",
text_color: {
field: "text_colors"
},
text_font_size: "9pt"
});
r2 = new models.GlyphRenderer({
data_source: source,
glyph: g2
});
xdr = new models.DataRange1d({
renderers: [r1],
range_padding: 0.2
});
ydr = new models.DataRange1d({
renderers: [r1],
range_padding: 0.2
});
plot = new models.Plot({
x_range: xdr,
y_range: ydr
});
if (opts.width != null) {
plot.plot_width = opts.width;
}
if (opts.height != null) {
plot.plot_height = opts.height;
}
plot.add_renderers(r1, r2);
tooltip = "<div>@labels</div><div><b>@values</b> (@percentages)</div>";
hover = new models.HoverTool({
renderers: [r1],
tooltips: tooltip
});
plot.add_tools(hover);
return plot;
};
bar = function(data, opts) {
var anchor, attachment, bottom, column_names, columns, dy, g1, hover, i, j, k, label, labels, left, len, len1, len2, len3, len4, m, n, name, o, orientation, p, palette, plot, q, r, r1, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, ref8, renderers, right, row, rows, s, source, stacked, tooltip, top, v, xaxis, xdr, xformatter, yaxis, ydr;
if (opts == null) {
opts = {};
}
column_names = data[0];
rows = data.slice(1);
columns = (function() {
var k, len, results;
results = [];
for (k = 0, len = column_names.length; k < len; k++) {
name = column_names[k];
results.push([]);
}
return results;
})();
for (k = 0, len = rows.length; k < len; k++) {
row = rows[k];
for (i = m = 0, len1 = row.length; m < len1; i = ++m) {
v = row[i];
columns[i].push(v);
}
}
labels = _.map(columns[0], function(v) {
return v.toString();
});
columns = columns.slice(1);
yaxis = new models.CategoricalAxis();
ydr = new models.FactorRange({
factors: labels
});
if (opts.axis_number_format != null) {
xformatter = new models.NumeralTickFormatter({
format: opts.axis_number_format
});
} else {
xformatter = new models.BasicTickFormatter();
}
xaxis = new models.LinearAxis({
formatter: xformatter
});
xdr = new models.DataRange1d({
start: 0
});
if (_.isArray(opts.palette)) {
palette = opts.palette;
} else {
palette = palettes[(ref = opts.palette) != null ? ref : "Spectral11"].map(num2hexcolor);
}
stacked = (ref1 = opts.stacked) != null ? ref1 : false;
orientation = (ref2 = opts.orientation) != null ? ref2 : "horizontal";
renderers = [];
if (stacked) {
left = [];
right = [];
for (i = n = 0, ref3 = columns.length; 0 <= ref3 ? n < ref3 : n > ref3; i = 0 <= ref3 ? ++n : --n) {
bottom = [];
top = [];
for (j = o = 0, len2 = labels.length; o < len2; j = ++o) {
label = labels[j];
if (i === 0) {
left.push(0);
right.push(columns[i][j]);
} else {
left[j] += columns[i - 1][j];
right[j] += columns[i][j];
}
bottom.push(label + ":0");
top.push(label + ":1");
}
source = new Bokeh.ColumnDataSource({
data: {
left: _.clone(left),
right: _.clone(right),
top: top,
bottom: bottom,
labels: labels,
values: columns[i],
columns: (function() {
var len3, p, ref4, results;
ref4 = columns[i];
results = [];
for (p = 0, len3 = ref4.length; p < len3; p++) {
v = ref4[p];
results.push(column_names[i + 1]);
}
return results;
})()
}
});
g1 = new models.Quad({
left: {
field: "left"
},
bottom: {
field: "bottom"
},
right: {
field: "right"
},
top: {
field: "top"
},
line_color: null,
fill_color: palette[i % palette.length]
});
r1 = new models.GlyphRenderer({
data_source: source,
glyph: g1
});
renderers.push(r1);
}
} else {
dy = 1 / columns.length;
for (i = p = 0, ref4 = columns.length; 0 <= ref4 ? p < ref4 : p > ref4; i = 0 <= ref4 ? ++p : --p) {
left = [];
right = [];
bottom = [];
top = [];
for (j = q = 0, len3 = labels.length; q < len3; j = ++q) {
label = labels[j];
left.push(0);
right.push(columns[i][j]);
bottom.push(label + ":" + (i * dy));
top.push(label + ":" + ((i + 1) * dy));
}
source = new Bokeh.ColumnDataSource({
data: {
left: left,
right: right,
top: top,
bottom: bottom,
labels: labels,
values: columns[i],
columns: (function() {
var len4, ref5, results, s;
ref5 = columns[i];
results = [];
for (s = 0, len4 = ref5.length; s < len4; s++) {
v = ref5[s];
results.push(column_names[i + 1]);
}
return results;
})()
}
});
g1 = new models.Quad({
left: {
field: "left"
},
bottom: {
field: "bottom"
},
right: {
field: "right"
},
top: {
field: "top"
},
line_color: null,
fill_color: palette[i % palette.length]
});
r1 = new models.GlyphRenderer({
data_source: source,
glyph: g1
});
renderers.push(r1);
}
}
if (orientation === "vertical") {
ref5 = [ydr, xdr], xdr = ref5[0], ydr = ref5[1];
ref6 = [yaxis, xaxis], xaxis = ref6[0], yaxis = ref6[1];
for (s = 0, len4 = renderers.length; s < len4; s++) {
r = renderers[s];
data = r.data_source.data;
ref7 = [data.bottom, data.left], data.left = ref7[0], data.bottom = ref7[1];
ref8 = [data.top, data.right], data.right = ref8[0], data.top = ref8[1];
}
}
plot = new models.Plot({
x_range: xdr,
y_range: ydr
});
if (opts.width != null) {
plot.plot_width = opts.width;
}
if (opts.height != null) {
plot.plot_height = opts.height;
}
plot.add_renderers.apply(plot, renderers);
plot.add_layout(yaxis, "left");
plot.add_layout(xaxis, "below");
tooltip = "<div>@labels</div><div>@columns: <b>@values</b></div>";
if (orientation === "horizontal") {
anchor = "right_center";
attachment = "horizontal";
} else {
anchor = "top_center";
attachment = "vertical";
}
hover = new models.HoverTool({
renderers: renderers,
tooltips: tooltip,
point_policy: "snap_to_data",
anchor: anchor,
attachment: attachment,
show_arrow: opts.show_arrow
});
plot.add_tools(hover);
return plot;
};
module.exports = {
pie: pie,
bar: bar
};