diff options
author | Zachary Sloan | 2013-11-20 20:23:53 +0000 |
---|---|---|
committer | Zachary Sloan | 2013-11-20 20:23:53 +0000 |
commit | 36cd8acc08477038664fc3532016036f3696f734 (patch) | |
tree | 77c8f096a9cb5a111336c7444eea2ce753fb0a1a | |
parent | f1e215c78f2d5889cad18d36c1c28623c924b768 (diff) | |
download | genenetwork2-36cd8acc08477038664fc3532016036f3696f734.tar.gz |
Created a box plot
Made the bar chart use a gradient if colored by something with more
than 6 distinct values
Put figures in tabs under the Charts/Figures part of the trait page
-rw-r--r-- | wqflask/wqflask/static/new/css/box_plot.css | 20 | ||||
-rw-r--r-- | wqflask/wqflask/static/new/javascript/bar_chart.coffee | 100 | ||||
-rw-r--r-- | wqflask/wqflask/static/new/javascript/bar_chart.js | 108 | ||||
-rw-r--r-- | wqflask/wqflask/static/new/javascript/box.js | 307 | ||||
-rw-r--r-- | wqflask/wqflask/static/new/javascript/box_plot.coffee | 50 | ||||
-rw-r--r-- | wqflask/wqflask/static/new/javascript/show_trait.coffee | 389 | ||||
-rw-r--r-- | wqflask/wqflask/static/new/javascript/show_trait.js | 426 | ||||
-rw-r--r-- | wqflask/wqflask/templates/show_trait.html | 2 | ||||
-rw-r--r-- | wqflask/wqflask/templates/show_trait_statistics_new.html | 76 |
9 files changed, 1396 insertions, 82 deletions
diff --git a/wqflask/wqflask/static/new/css/box_plot.css b/wqflask/wqflask/static/new/css/box_plot.css new file mode 100644 index 00000000..4c743b33 --- /dev/null +++ b/wqflask/wqflask/static/new/css/box_plot.css @@ -0,0 +1,20 @@ +.box {
+ font: 10px sans-serif;
+}
+
+.box line,
+.box rect,
+.box circle {
+ fill: #fff;
+ stroke: #000;
+ stroke-width: 1.5px;
+}
+
+.box .center {
+ stroke-dasharray: 3,3;
+}
+
+.box .outlier {
+ fill: none;
+ stroke: #ccc;
+}
\ No newline at end of file diff --git a/wqflask/wqflask/static/new/javascript/bar_chart.coffee b/wqflask/wqflask/static/new/javascript/bar_chart.coffee index 0ab70e0d..749a7dc0 100644 --- a/wqflask/wqflask/static/new/javascript/bar_chart.coffee +++ b/wqflask/wqflask/static/new/javascript/bar_chart.coffee @@ -1,19 +1,17 @@ root = exports ? this class Bar_Chart - constructor: (@sample_list, @attribute_names) -> + constructor: (@sample_list, @sample_group) -> @get_samples() console.log("sample names:", @sample_names) + if @sample_attr_vals.length > 0 + @get_distinct_attr_vals() + @get_attr_color_dict() #Used to calculate the bottom margin so sample names aren't cut off longest_sample_name = d3.max(sample.length for sample in @sample_names) - @margin = - top: 20 - right: 20 - bottom: longest_sample_name * 7 - left: 40 - + @margin = {top: 20, right: 20, bottom: longest_sample_name * 7, left: 40} @plot_width = @sample_vals.length * 15 - @margin.left - @margin.right @plot_height = 500 - @margin.top - @margin.bottom @@ -57,6 +55,7 @@ class Bar_Chart else return @attr_color_dict[attribute][d[2][attribute]] ) + @add_legend(attribute, @distinct_attr_vals[attribute]) ) @@ -79,7 +78,7 @@ class Bar_Chart return @plot_height - @y_scale(d[1]) ) .style("fill", (d) => - if @attributes.length > 0 && attribute != "None" + if @attributes.length > 0 return @attr_color_dict[attribute][d[2][attribute]] else return "steelblue" @@ -107,7 +106,7 @@ class Bar_Chart return @plot_height - @y_scale(d[1]) ) .style("fill", (d) => - if @attributes.length > 0 && attribute != "None" + if @attributes.length > 0 return @attr_color_dict[attribute][d[2][attribute]] else return "steelblue" @@ -122,23 +121,33 @@ class Bar_Chart $('.x.axis').remove() @add_x_axis(x_scale) ) - - d3.select("#color_by_trait").on("click", => - @color_by_trait() - ) get_attr_color_dict: () -> - color = d3.scale.category20() @attr_color_dict = {} - console.log("attribute_names:", @attribute_names) - for own key, attribute_info of @attribute_names + console.log("distinct_attr_vals:", @distinct_attr_vals) + for own key, distinct_vals of @distinct_attr_vals this_color_dict = {} - for value, i in attribute_info.distinct_values - this_color_dict[value] = color(i) - @attr_color_dict[attribute_info.name] = this_color_dict - - - + if distinct_vals.length < 10 + color = d3.scale.category10() + for value, i in distinct_vals + this_color_dict[value] = color(i) + else + console.log("distinct_values:", distinct_vals) + if _.every(distinct_vals, (d) => + if isNaN(d) + return false + else + return true + ) + color_range = d3.scale.linear() + .domain([d3.min(distinct_vals), + d3.max(distinct_vals)]) + .range([0,4]) + for value, i in distinct_vals + console.log("color_range(value):", color_range(parseInt(value))) + this_color_dict[value] = d3.rgb("lightblue").darker(color_range(parseInt(value))) + #this_color_dict[value] = "rgb(0, 0, " + color_range(parseInt(value)) + ")" + @attr_color_dict[key] = this_color_dict get_samples: () -> @sample_names = (sample.name for sample in @sample_list when sample.value != null) @@ -153,8 +162,16 @@ class Bar_Chart attr_vals[attribute] = sample["extra_attributes"][attribute] @sample_attr_vals.push(attr_vals) @samples = _.zip(@sample_names, @sample_vals, @sample_attr_vals) - @get_attr_color_dict() - console.log("samples:", @samples) + + get_distinct_attr_vals: () -> + @distinct_attr_vals = {} + for sample in @sample_attr_vals + for attribute of sample + if not @distinct_attr_vals[attribute] + @distinct_attr_vals[attribute] = [] + if sample[attribute] not in @distinct_attr_vals[attribute] + @distinct_attr_vals[attribute].push(sample[attribute]) + #console.log("distinct_attr_vals:", @distinct_attr_vals) create_svg: () -> svg = d3.select("#bar_chart") @@ -248,6 +265,41 @@ class Bar_Chart ) console.log("sorted:", sorted) return sorted + + add_legend: (attribute, distinct_vals) -> + legend = @svg.append("g") + .attr("class", "legend") + .attr("height", 100) + .attr("width", 100) + .attr('transform', 'translate(-20,50)') + + legend_rect = legend.selectAll('rect') + .data(distinct_vals) + .enter() + .append("rect") + .attr("x", @plot_width - 65) + .attr("width", 10) + .attr("height", 10) + .attr("y", (d, i) => + return i * 20 + ) + .style("fill", (d) => + console.log("TEST:", @attr_color_dict[attribute][d]) + return @attr_color_dict[attribute][d] + ) + + legend_text = legend.selectAll('text') + .data(distinct_vals) + .enter() + .append("text") + .attr("x", @plot_width - 52) + .attr("y", (d, i) => + return i*20 + 9 + ) + .text((d) => + return d + ) + color_by_trait: () -> console.log("Before load") diff --git a/wqflask/wqflask/static/new/javascript/bar_chart.js b/wqflask/wqflask/static/new/javascript/bar_chart.js index ab011de1..20fab15c 100644 --- a/wqflask/wqflask/static/new/javascript/bar_chart.js +++ b/wqflask/wqflask/static/new/javascript/bar_chart.js @@ -1,19 +1,24 @@ // Generated by CoffeeScript 1.6.1 (function() { var Bar_Chart, root, - __hasProp = {}.hasOwnProperty; + __hasProp = {}.hasOwnProperty, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; root = typeof exports !== "undefined" && exports !== null ? exports : this; Bar_Chart = (function() { - function Bar_Chart(sample_list, attribute_names) { + function Bar_Chart(sample_list, sample_group) { var longest_sample_name, sample, _this = this; this.sample_list = sample_list; - this.attribute_names = attribute_names; + this.sample_group = sample_group; this.get_samples(); console.log("sample names:", this.sample_names); + if (this.sample_attr_vals.length > 0) { + this.get_distinct_attr_vals(); + this.get_attr_color_dict(); + } longest_sample_name = d3.max((function() { var _i, _len, _ref, _results; _ref = this.sample_names; @@ -44,7 +49,7 @@ var attribute; attribute = $("#color_attribute").val(); if ($("#update_bar_chart").html() === 'Sort By Name') { - return _this.svg.selectAll(".bar").data(_this.sorted_samples()).transition().duration(1000).style("fill", function(d) { + _this.svg.selectAll(".bar").data(_this.sorted_samples()).transition().duration(1000).style("fill", function(d) { if (attribute === "None") { return "steelblue"; } else { @@ -54,7 +59,7 @@ return d[1]; }); } else { - return _this.svg.selectAll(".bar").data(_this.samples).transition().duration(1000).style("fill", function(d) { + _this.svg.selectAll(".bar").data(_this.samples).transition().duration(1000).style("fill", function(d) { if (attribute === "None") { return "steelblue"; } else { @@ -62,6 +67,7 @@ } }); } + return _this.add_legend(attribute, _this.distinct_attr_vals[attribute]); }); d3.select("#update_bar_chart").on("click", function() { var attribute, sortItems, sorted_sample_names, x_scale; @@ -78,7 +84,7 @@ }).attr("height", function(d) { return _this.plot_height - _this.y_scale(d[1]); }).style("fill", function(d) { - if (_this.attributes.length > 0 && attribute !== "None") { + if (_this.attributes.length > 0) { return _this.attr_color_dict[attribute][d[2][attribute]]; } else { return "steelblue"; @@ -106,7 +112,7 @@ }).attr("height", function(d) { return _this.plot_height - _this.y_scale(d[1]); }).style("fill", function(d) { - if (_this.attributes.length > 0 && attribute !== "None") { + if (_this.attributes.length > 0) { return _this.attr_color_dict[attribute][d[2][attribute]]; } else { return "steelblue"; @@ -119,28 +125,43 @@ return _this.add_x_axis(x_scale); } }); - d3.select("#color_by_trait").on("click", function() { - return _this.color_by_trait(); - }); } Bar_Chart.prototype.get_attr_color_dict = function() { - var attribute_info, color, i, key, this_color_dict, value, _i, _len, _ref, _ref1, _results; - color = d3.scale.category20(); + var color, color_range, distinct_vals, i, key, this_color_dict, value, _i, _j, _len, _len1, _ref, _results, + _this = this; this.attr_color_dict = {}; - console.log("attribute_names:", this.attribute_names); - _ref = this.attribute_names; + console.log("distinct_attr_vals:", this.distinct_attr_vals); + _ref = this.distinct_attr_vals; _results = []; for (key in _ref) { if (!__hasProp.call(_ref, key)) continue; - attribute_info = _ref[key]; + distinct_vals = _ref[key]; this_color_dict = {}; - _ref1 = attribute_info.distinct_values; - for (i = _i = 0, _len = _ref1.length; _i < _len; i = ++_i) { - value = _ref1[i]; - this_color_dict[value] = color(i); + if (distinct_vals.length < 10) { + color = d3.scale.category10(); + for (i = _i = 0, _len = distinct_vals.length; _i < _len; i = ++_i) { + value = distinct_vals[i]; + this_color_dict[value] = color(i); + } + } else { + console.log("distinct_values:", distinct_vals); + if (_.every(distinct_vals, function(d) { + if (isNaN(d)) { + return false; + } else { + return true; + } + })) { + color_range = d3.scale.linear().domain([d3.min(distinct_vals), d3.max(distinct_vals)]).range([0, 4]); + for (i = _j = 0, _len1 = distinct_vals.length; _j < _len1; i = ++_j) { + value = distinct_vals[i]; + console.log("color_range(value):", color_range(parseInt(value))); + this_color_dict[value] = d3.rgb("lightblue").darker(color_range(parseInt(value))); + } + } } - _results.push(this.attr_color_dict[attribute_info.name] = this_color_dict); + _results.push(this.attr_color_dict[key] = this_color_dict); } return _results; }; @@ -194,9 +215,33 @@ this.sample_attr_vals.push(attr_vals); } } - this.samples = _.zip(this.sample_names, this.sample_vals, this.sample_attr_vals); - this.get_attr_color_dict(); - return console.log("samples:", this.samples); + return this.samples = _.zip(this.sample_names, this.sample_vals, this.sample_attr_vals); + }; + + Bar_Chart.prototype.get_distinct_attr_vals = function() { + var attribute, sample, _i, _len, _ref, _results; + this.distinct_attr_vals = {}; + _ref = this.sample_attr_vals; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + sample = _ref[_i]; + _results.push((function() { + var _ref1, _results1; + _results1 = []; + for (attribute in sample) { + if (!this.distinct_attr_vals[attribute]) { + this.distinct_attr_vals[attribute] = []; + } + if (_ref1 = sample[attribute], __indexOf.call(this.distinct_attr_vals[attribute], _ref1) < 0) { + _results1.push(this.distinct_attr_vals[attribute].push(sample[attribute])); + } else { + _results1.push(void 0); + } + } + return _results1; + }).call(this)); + } + return _results; }; Bar_Chart.prototype.create_svg = function() { @@ -255,6 +300,23 @@ return sorted; }; + Bar_Chart.prototype.add_legend = function(attribute, distinct_vals) { + var legend, legend_rect, legend_text, + _this = this; + legend = this.svg.append("g").attr("class", "legend").attr("height", 100).attr("width", 100).attr('transform', 'translate(-20,50)'); + legend_rect = legend.selectAll('rect').data(distinct_vals).enter().append("rect").attr("x", this.plot_width - 65).attr("width", 10).attr("height", 10).attr("y", function(d, i) { + return i * 20; + }).style("fill", function(d) { + console.log("TEST:", _this.attr_color_dict[attribute][d]); + return _this.attr_color_dict[attribute][d]; + }); + return legend_text = legend.selectAll('text').data(distinct_vals).enter().append("text").attr("x", this.plot_width - 52).attr("y", function(d, i) { + return i * 20 + 9; + }).text(function(d) { + return d; + }); + }; + Bar_Chart.prototype.color_by_trait = function() { console.log("Before load"); $('#collections_holder').load('/collections/list #collections_list'); diff --git a/wqflask/wqflask/static/new/javascript/box.js b/wqflask/wqflask/static/new/javascript/box.js new file mode 100644 index 00000000..aae80f05 --- /dev/null +++ b/wqflask/wqflask/static/new/javascript/box.js @@ -0,0 +1,307 @@ +//Taken from http://bl.ocks.org/mbostock/4061502
+
+(function() {
+
+// Inspired by http://informationandvisualization.de/blog/box-plot
+d3.box = function() {
+ var width = 1,
+ height = 1,
+ duration = 0,
+ domain = null,
+ value = Number,
+ whiskers = boxWhiskers,
+ quartiles = boxQuartiles,
+ tickFormat = null;
+
+ // For each small multiple…
+ function box(g) {
+ g.each(function(d, i) {
+ console.log("d:", d)
+ console.log("domain:", domain)
+ d = d.map(value).sort(d3.ascending);
+ var g = d3.select(this),
+ n = d.length,
+ min = d[0],
+ max = d[n - 1];
+
+ // Compute quartiles. Must return exactly 3 elements.
+ var quartileData = d.quartiles = quartiles(d);
+
+ // Compute whiskers. Must return exactly 2 elements, or null.
+ var whiskerIndices = whiskers && whiskers.call(this, d, i),
+ whiskerData = whiskerIndices && whiskerIndices.map(function(i) { return d[i]; });
+
+ // Compute outliers. If no whiskers are specified, all data are "outliers".
+ // We compute the outliers as indices, so that we can join across transitions!
+ var outlierIndices = whiskerIndices
+ ? d3.range(0, whiskerIndices[0]).concat(d3.range(whiskerIndices[1] + 1, n))
+ : d3.range(n);
+
+ // Compute the new x-scale.
+ var x1 = d3.scale.linear()
+ .domain(domain && domain.call(this, d, i) || [min, max])
+ .range([height, 0]);
+
+ // Retrieve the old x-scale, if this is an update.
+ var x0 = this.__chart__ || d3.scale.linear()
+ .domain([0, Infinity])
+ .range(x1.range());
+
+ // Stash the new scale.
+ this.__chart__ = x1;
+
+ // Note: the box, median, and box tick elements are fixed in number,
+ // so we only have to handle enter and update. In contrast, the outliers
+ // and other elements are variable, so we need to exit them! Variable
+ // elements also fade in and out.
+
+ // Update center line: the vertical line spanning the whiskers.
+ var center = g.selectAll("line.center")
+ .data(whiskerData ? [whiskerData] : []);
+
+ center.enter().insert("line", "rect")
+ .attr("class", "center")
+ .attr("x1", width / 2)
+ .attr("y1", function(d) { return x0(d[0]); })
+ .attr("x2", width / 2)
+ .attr("y2", function(d) { return x0(d[1]); })
+ .style("opacity", 1e-6)
+ .transition()
+ .duration(duration)
+ .style("opacity", 1)
+ .attr("y1", function(d) { return x1(d[0]); })
+ .attr("y2", function(d) { return x1(d[1]); });
+
+ center.transition()
+ .duration(duration)
+ .style("opacity", 1)
+ .attr("y1", function(d) { return x1(d[0]); })
+ .attr("y2", function(d) { return x1(d[1]); });
+
+ center.exit().transition()
+ .duration(duration)
+ .style("opacity", 1e-6)
+ .attr("y1", function(d) { return x1(d[0]); })
+ .attr("y2", function(d) { return x1(d[1]); })
+ .remove();
+
+ // Update innerquartile box.
+ var box = g.selectAll("rect.box")
+ .data([quartileData]);
+
+ box.enter().append("rect")
+ .attr("class", "box")
+ .attr("x", 0)
+ .attr("y", function(d) { return x0(d[2]); })
+ .attr("width", width)
+ .attr("height", function(d) { return x0(d[0]) - x0(d[2]); })
+ .transition()
+ .duration(duration)
+ .attr("y", function(d) { return x1(d[2]); })
+ .attr("height", function(d) { return x1(d[0]) - x1(d[2]); });
+
+ box.transition()
+ .duration(duration)
+ .attr("y", function(d) { return x1(d[2]); })
+ .attr("height", function(d) { return x1(d[0]) - x1(d[2]); });
+
+ // Update median line.
+ var medianLine = g.selectAll("line.median")
+ .data([quartileData[1]]);
+
+ medianLine.enter().append("line")
+ .attr("class", "median")
+ .attr("x1", 0)
+ .attr("y1", x0)
+ .attr("x2", width)
+ .attr("y2", x0)
+ .transition()
+ .duration(duration)
+ .attr("y1", x1)
+ .attr("y2", x1);
+
+ medianLine.transition()
+ .duration(duration)
+ .attr("y1", x1)
+ .attr("y2", x1);
+
+ // Update whiskers.
+ var whisker = g.selectAll("line.whisker")
+ .data(whiskerData || []);
+
+ whisker.enter().insert("line", "circle, text")
+ .attr("class", "whisker")
+ .attr("x1", 0)
+ .attr("y1", x0)
+ .attr("x2", width)
+ .attr("y2", x0)
+ .style("opacity", 1e-6)
+ .transition()
+ .duration(duration)
+ .attr("y1", x1)
+ .attr("y2", x1)
+ .style("opacity", 1);
+
+ whisker.transition()
+ .duration(duration)
+ .attr("y1", x1)
+ .attr("y2", x1)
+ .style("opacity", 1);
+
+ whisker.exit().transition()
+ .duration(duration)
+ .attr("y1", x1)
+ .attr("y2", x1)
+ .style("opacity", 1e-6)
+ .remove();
+
+ // Update outliers.
+ var outlier = g.selectAll("circle.outlier")
+ .data(outlierIndices, Number);
+
+ outlier.enter().insert("circle", "text")
+ .attr("class", "outlier")
+ .attr("r", 5)
+ .attr("cx", width / 2)
+ .attr("cy", function(i) { return x0(d[i]); })
+ .style("opacity", 1e-6)
+ .transition()
+ .duration(duration)
+ .attr("cy", function(i) { return x1(d[i]); })
+ .style("opacity", 1);
+
+ outlier.transition()
+ .duration(duration)
+ .attr("cy", function(i) { return x1(d[i]); })
+ .style("opacity", 1);
+
+ outlier.exit().transition()
+ .duration(duration)
+ .attr("cy", function(i) { return x1(d[i]); })
+ .style("opacity", 1e-6)
+ .remove();
+
+ // Compute the tick format.
+ var format = tickFormat || x1.tickFormat(8);
+
+ // Update box ticks.
+ var boxTick = g.selectAll("text.box")
+ .data(quartileData);
+
+ console.log("quartileData:", quartileData);
+
+ boxTick.enter().append("text")
+ .attr("class", "box")
+ .attr("dy", ".3em")
+ .attr("dx", function(d, i) { return i & 1 ? 6 : -6 })
+ .attr("x", function(d, i) { return i & 1 ? width : 0 })
+ .attr("y", x0)
+ .attr("text-anchor", function(d, i) { return i & 1 ? "start" : "end"; })
+ .text(format)
+ .transition()
+ .duration(duration)
+ .attr("y", x1);
+
+ boxTick.transition()
+ .duration(duration)
+ .text(format)
+ .attr("y", x1);
+
+ // Update whisker ticks. These are handled separately from the box
+ // ticks because they may or may not exist, and we want don't want
+ // to join box ticks pre-transition with whisker ticks post-.
+ var whiskerTick = g.selectAll("text.whisker")
+ .data(whiskerData || []);
+
+ whiskerTick.enter().append("text")
+ .attr("class", "whisker")
+ .attr("dy", ".3em")
+ .attr("dx", 6)
+ .attr("x", width)
+ .attr("y", x0)
+ .text(format)
+ .style("opacity", 1e-6)
+ .transition()
+ .duration(duration)
+ .attr("y", x1)
+ .style("opacity", 1);
+
+ whiskerTick.transition()
+ .duration(duration)
+ .text(format)
+ .attr("y", x1)
+ .style("opacity", 1);
+
+ whiskerTick.exit().transition()
+ .duration(duration)
+ .attr("y", x1)
+ .style("opacity", 1e-6)
+ .remove();
+ });
+ d3.timer.flush();
+ }
+
+ box.width = function(x) {
+ if (!arguments.length) return width;
+ width = x;
+ return box;
+ };
+
+ box.height = function(x) {
+ if (!arguments.length) return height;
+ height = x;
+ return box;
+ };
+
+ box.tickFormat = function(x) {
+ if (!arguments.length) return tickFormat;
+ tickFormat = x;
+ return box;
+ };
+
+ box.duration = function(x) {
+ if (!arguments.length) return duration;
+ duration = x;
+ return box;
+ };
+
+ box.domain = function(x) {
+ if (!arguments.length) return domain;
+ domain = x == null ? x : d3.functor(x);
+ return box;
+ };
+
+ box.value = function(x) {
+ if (!arguments.length) return value;
+ value = x;
+ return box;
+ };
+
+ box.whiskers = function(x) {
+ if (!arguments.length) return whiskers;
+ whiskers = x;
+ return box;
+ };
+
+ box.quartiles = function(x) {
+ if (!arguments.length) return quartiles;
+ quartiles = x;
+ return box;
+ };
+
+ return box;
+};
+
+function boxWhiskers(d) {
+ return [0, d.length - 1];
+}
+
+function boxQuartiles(d) {
+ return [
+ d3.quantile(d, .25),
+ d3.quantile(d, .5),
+ d3.quantile(d, .75)
+ ];
+}
+
+})();
\ No newline at end of file diff --git a/wqflask/wqflask/static/new/javascript/box_plot.coffee b/wqflask/wqflask/static/new/javascript/box_plot.coffee new file mode 100644 index 00000000..562bd1dc --- /dev/null +++ b/wqflask/wqflask/static/new/javascript/box_plot.coffee @@ -0,0 +1,50 @@ +root = exports ? this
+
+class Box_Plot
+ constructor: (@sample_list, @sample_group) ->
+ @get_samples()
+
+ @margin = {top: 10, right: 50, bottom: 20, left: 50}
+ @plot_width = 120 - @margin.left - @margin.right
+ @plot_height = 500 - @margin.top - @margin.bottom
+
+ @min = d3.min(@sample_vals)
+ @max = d3.max(@sample_vals) * 1.1
+
+ @svg = @create_svg()
+
+ @enter_data()
+
+
+ get_samples: () ->
+ @sample_names = (sample.name for sample in @sample_list when sample.value != null)
+ @sample_vals = (sample.value for sample in @sample_list when sample.value != null)
+ @samples = _.zip(@sample_names, @sample_vals)
+
+ create_svg: () -> d3.chart.box()
+ .whiskers(@inter_quartile_range(1.5))
+ .width(@plot_width)
+ .height(@plot_height)
+ .domain([@min, @max])
+
+ enter_data: () ->
+ d3.select("#box_plot").selectAll("svg")
+ .data(@sample_vals)
+ .enter().append("svg:svg")
+ .attr("class", "box")
+ .attr("width", @plot_width)
+ .attr("height", @plot_height)
+ .call(@svg)
+
+ inter_quartile_range: (k) ->
+ return (d, i) =>
+ q1 = d.quartiles[0],
+ q3 = d.quartiles[2],
+ inter_quartile_range = (q3 - q1) * k
+ i = -1
+ j = d.length
+ while (d[++i] < q1 - inter_quartile_range)
+ while (d[--j] > q3 + inter_quartile_range)
+ return [i, j]
+
+
\ No newline at end of file diff --git a/wqflask/wqflask/static/new/javascript/show_trait.coffee b/wqflask/wqflask/static/new/javascript/show_trait.coffee index 55eb1f56..8bcca85d 100644 --- a/wqflask/wqflask/static/new/javascript/show_trait.coffee +++ b/wqflask/wqflask/static/new/javascript/show_trait.coffee @@ -59,25 +59,404 @@ Stat_Table_Rows = [ ] $ -> + class Bar_Chart + constructor: (@sample_list, @sample_group) -> + @get_samples() + console.log("sample names:", @sample_names) + if @sample_attr_vals.length > 0 + @get_distinct_attr_vals() + @get_attr_color_dict() + + #Used to calculate the bottom margin so sample names aren't cut off + longest_sample_name = d3.max(sample.length for sample in @sample_names) + + @margin = {top: 20, right: 20, bottom: longest_sample_name * 7, left: 40} + @plot_width = @sample_vals.length * 15 - @margin.left - @margin.right + @plot_height = 500 - @margin.top - @margin.bottom + + @x_buffer = @plot_width/20 + @y_buffer = @plot_height/20 + + @y_min = d3.min(@sample_vals) + @y_max = d3.max(@sample_vals) * 1.1 + + @svg = @create_svg() + + @plot_height -= @y_buffer + @create_scales() + @create_graph() + + d3.select("#color_attribute").on("change", => + attribute = $("#color_attribute").val() + if $("#update_bar_chart").html() == 'Sort By Name' + @svg.selectAll(".bar") + .data(@sorted_samples()) + .transition() + .duration(1000) + .style("fill", (d) => + if attribute == "None" + return "steelblue" + else + return @attr_color_dict[attribute][d[2][attribute]] + ) + .select("title") + .text((d) => + return d[1] + ) + else + @svg.selectAll(".bar") + .data(@samples) + .transition() + .duration(1000) + .style("fill", (d) => + if attribute == "None" + return "steelblue" + else + return @attr_color_dict[attribute][d[2][attribute]] + ) + @add_legend(attribute, @distinct_attr_vals[attribute]) + ) + + + d3.select("#update_bar_chart").on("click", => + if @attributes.length > 0 + attribute = $("#color_attribute").val() + if $("#update_bar_chart").html() == 'Sort By Value' + $("#update_bar_chart").html('Sort By Name') + sortItems = (a, b) -> + return a[1] - b[1] + + @svg.selectAll(".bar") + .data(@sorted_samples()) + .transition() + .duration(1000) + .attr("y", (d) => + return @y_scale(d[1]) + ) + .attr("height", (d) => + return @plot_height - @y_scale(d[1]) + ) + .style("fill", (d) => + if @attributes.length > 0 + return @attr_color_dict[attribute][d[2][attribute]] + else + return "steelblue" + ) + .select("title") + .text((d) => + return d[1] + ) + sorted_sample_names = (sample[0] for sample in @sorted_samples()) + x_scale = d3.scale.ordinal() + .domain(sorted_sample_names) + .rangeBands([0, @plot_width], .1) + $('.x.axis').remove() + @add_x_axis(x_scale) + else + $("#update_bar_chart").html('Sort By Value') + @svg.selectAll(".bar") + .data(@samples) + .transition() + .duration(1000) + .attr("y", (d) => + return @y_scale(d[1]) + ) + .attr("height", (d) => + return @plot_height - @y_scale(d[1]) + ) + .style("fill", (d) => + if @attributes.length > 0 + return @attr_color_dict[attribute][d[2][attribute]] + else + return "steelblue" + ) + .select("title") + .text((d) => + return d[1] + ) + x_scale = d3.scale.ordinal() + .domain(@sample_names) + .rangeBands([0, @plot_width], .1) + $('.x.axis').remove() + @add_x_axis(x_scale) + ) + + d3.select("#color_by_trait").on("click", => + @color_by_trait() + ) + + get_attr_color_dict: () -> + @attr_color_dict = {} + console.log("distinct_attr_vals:", @distinct_attr_vals) + for own key, distinct_vals of @distinct_attr_vals + this_color_dict = {} + if distinct_vals.length < 10 + color = d3.scale.category10() + for value, i in distinct_vals + this_color_dict[value] = color(i) + else + console.log("distinct_values:", distinct_vals) + if _.every(distinct_vals, (d) => + if isNaN(d) + return false + else + return true + ) + color_range = d3.scale.linear() + .domain([d3.min(distinct_vals), + d3.max(distinct_vals)]) + .range([0,4]) + for value, i in distinct_vals + console.log("color_range(value):", color_range(parseInt(value))) + this_color_dict[value] = d3.rgb("lightblue").darker(color_range(parseInt(value))) + #this_color_dict[value] = "rgb(0, 0, " + color_range(parseInt(value)) + ")" + @attr_color_dict[key] = this_color_dict + + get_samples: () -> + @sample_names = (sample.name for sample in @sample_list when sample.value != null) + @sample_vals = (sample.value for sample in @sample_list when sample.value != null) + @attributes = (key for key of @sample_list[0]["extra_attributes"]) + console.log("attributes:", @attributes) + @sample_attr_vals = [] + if @attributes.length > 0 + for sample in @sample_list + attr_vals = {} + for attribute in @attributes + attr_vals[attribute] = sample["extra_attributes"][attribute] + @sample_attr_vals.push(attr_vals) + @samples = _.zip(@sample_names, @sample_vals, @sample_attr_vals) + + get_distinct_attr_vals: () -> + @distinct_attr_vals = {} + for sample in @sample_attr_vals + for attribute of sample + if not @distinct_attr_vals[attribute] + @distinct_attr_vals[attribute] = [] + if sample[attribute] not in @distinct_attr_vals[attribute] + @distinct_attr_vals[attribute].push(sample[attribute]) + #console.log("distinct_attr_vals:", @distinct_attr_vals) + + create_svg: () -> + svg = d3.select("#bar_chart") + .append("svg") + .attr("class", "bar_chart") + .attr("width", @plot_width + @margin.left + @margin.right) + .attr("height", @plot_height + @margin.top + @margin.bottom) + .append("g") + .attr("transform", "translate(" + @margin.left + "," + @margin.top + ")") + + return svg + + create_scales: () -> + @x_scale = d3.scale.ordinal() + .domain(@sample_names) + .rangeBands([0, @plot_width], .1) + + @y_scale = d3.scale.linear() + .domain([@y_min * 0.75, @y_max]) + .range([@plot_height, @y_buffer]) + + create_graph: () -> + + #@add_border() + @add_x_axis(@x_scale) + @add_y_axis() + + @add_bars() + + add_x_axis: (scale) -> + xAxis = d3.svg.axis() + .scale(scale) + .orient("bottom"); + + @svg.append("g") + .attr("class", "x axis") + .attr("transform", "translate(0," + @plot_height + ")") + .call(xAxis) + .selectAll("text") + .style("text-anchor", "end") + .style("font-size", "12px") + .attr("dx", "-.8em") + .attr("dy", "-.3em") + .attr("transform", (d) => + return "rotate(-90)" + ) + + add_y_axis: () -> + yAxis = d3.svg.axis() + .scale(@y_scale) + .orient("left") + .ticks(5) + + @svg.append("g") + .attr("class", "y axis") + .call(yAxis) + .append("text") + .attr("transform", "rotate(-90)") + .attr("y", 6) + .attr("dy", ".71em") + .style("text-anchor", "end") + + add_bars: () -> + @svg.selectAll(".bar") + .data(@samples) + .enter().append("rect") + .style("fill", "steelblue") + .attr("class", "bar") + .attr("x", (d) => + return @x_scale(d[0]) + ) + .attr("width", @x_scale.rangeBand()) + .attr("y", (d) => + return @y_scale(d[1]) + ) + .attr("height", (d) => + return @plot_height - @y_scale(d[1]) + ) + .append("svg:title") + .text((d) => + return d[1] + ) + + sorted_samples: () -> + #if @sample_attr_vals.length > 0 + sample_list = _.zip(@sample_names, @sample_vals, @sample_attr_vals) + #else + # sample_list = _.zip(@sample_names, @sample_vals) + sorted = _.sortBy(sample_list, (sample) => + return sample[1] + ) + console.log("sorted:", sorted) + return sorted + + add_legend: (attribute, distinct_vals) -> + legend = @svg.append("g") + .attr("class", "legend") + .attr("height", 100) + .attr("width", 100) + .attr('transform', 'translate(-20,50)') + + legend_rect = legend.selectAll('rect') + .data(distinct_vals) + .enter() + .append("rect") + .attr("x", @plot_width - 65) + .attr("width", 10) + .attr("height", 10) + .attr("y", (d, i) => + return i * 20 + ) + .style("fill", (d) => + console.log("TEST:", @attr_color_dict[attribute][d]) + return @attr_color_dict[attribute][d] + ) + + legend_text = legend.selectAll('text') + .data(distinct_vals) + .enter() + .append("text") + .attr("x", @plot_width - 52) + .attr("y", (d, i) => + return i*20 + 9 + ) + .text((d) => + return d + ) + + color_by_trait: () -> + $('#collections_holder').load('/collections/list #collections_list', => + $.colorbox( + inline: true + href: "#collections_holder" + ) + ) + + class Box_Plot + constructor: (@sample_list, @sample_group) -> + @get_samples() + + @margin = {top: 10, right: 50, bottom: 20, left: 50} + @plot_width = 200 - @margin.left - @margin.right + @plot_height = 500 - @margin.top - @margin.bottom + + @min = d3.min(@sample_vals) + @max = d3.max(@sample_vals) + + @svg = @create_svg() + @enter_data() + + + get_samples: () -> + @sample_vals = (sample.value for sample in @sample_list when sample.value != null) + + create_svg: () -> + svg = d3.box() + .whiskers(@inter_quartile_range(1.5)) + .width(@plot_width) + .height(@plot_height) + .domain([@min, @max]) + return svg + + enter_data: () -> + d3.select("#box_plot").selectAll("svg") + .data([@sample_vals]) + .enter().append("svg:svg") + .attr("class", "box") + .attr("width", @plot_width) + .attr("height", @plot_height) + .append("svg:g") + .call(@svg) + + inter_quartile_range: (k) -> + return (d, i) => + console.log("iqr d:", d) + q1 = d.quartiles[0] + q3 = d.quartiles[2] + inter_quartile_range = (q3 - q1) * k + console.log("iqr:", inter_quartile_range) + i = 0 + j = d.length + console.log("d[-1]:", d[1]) + console.log("q1 - iqr:", q1 - inter_quartile_range) + i++ while (d[i] < q1 - inter_quartile_range) + j-- while (d[j] > q3 + inter_quartile_range) + #while (d[++i] < q1 - inter_quartile_range + #while d[--j] > q3 + inter_quartile_range + console.log("[i, j]", [i, j]) + return [i, j] + sample_lists = js_data.sample_lists - attribute_names = js_data.attribute_names sample_group_types = js_data.sample_group_types - new Bar_Chart(sample_lists[0], attribute_names) + new Bar_Chart(sample_lists[0]) + new Box_Plot(sample_lists[0]) - $('.stats_samples_group').change -> + + $('.bar_chart_samples_group').change -> $('#bar_chart').remove() $('#bar_chart_container').append('<div id="bar_chart"></div>') group = $(this).val() - console.log("group:", group) if group == "samples_primary" new Bar_Chart(sample_lists[0]) else if group == "samples_other" new Bar_Chart(sample_lists[1]) else if group == "samples_all" all_samples = sample_lists[0].concat sample_lists[1] - new HBar_Chart(all_samples) + new Bar_Chart(all_samples) + + $('.box_plot_samples_group').change -> + $('#box_plot').remove() + $('#box_plot_container').append('<div id="box_plot"></div>') + group = $(this).val() + if group == "samples_primary" + new Box_Plot(sample_lists[0]) + else if group == "samples_other" + new Box_Plot(sample_lists[1]) + else if group == "samples_all" + all_samples = sample_lists[0].concat sample_lists[1] + new Box_Plot(all_samples) + hide_tabs = (start) -> for x in [start..10] diff --git a/wqflask/wqflask/static/new/javascript/show_trait.js b/wqflask/wqflask/static/new/javascript/show_trait.js index c5a6cbd5..b562bfe2 100644 --- a/wqflask/wqflask/static/new/javascript/show_trait.js +++ b/wqflask/wqflask/static/new/javascript/show_trait.js @@ -2,6 +2,7 @@ (function() { var Stat_Table_Rows, is_number, __hasProp = {}.hasOwnProperty, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, __slice = [].slice; console.log("start_b"); @@ -56,24 +57,437 @@ ]; $(function() { - var attribute_names, block_by_attribute_value, block_by_index, block_outliers, change_stats_value, create_value_dropdown, edit_data_change, export_sample_table_data, get_sample_table_data, hide_no_value, hide_tabs, make_table, on_corr_method_change, populate_sample_attributes_values_dropdown, process_id, reset_samples_table, sample_group_types, sample_lists, show_hide_outliers, stats_mdp_change, update_stat_values; + var Bar_Chart, Box_Plot, block_by_attribute_value, block_by_index, block_outliers, change_stats_value, create_value_dropdown, edit_data_change, export_sample_table_data, get_sample_table_data, hide_no_value, hide_tabs, make_table, on_corr_method_change, populate_sample_attributes_values_dropdown, process_id, reset_samples_table, sample_group_types, sample_lists, show_hide_outliers, stats_mdp_change, update_stat_values; + Bar_Chart = (function() { + + function Bar_Chart(sample_list, sample_group) { + var longest_sample_name, sample, + _this = this; + this.sample_list = sample_list; + this.sample_group = sample_group; + this.get_samples(); + console.log("sample names:", this.sample_names); + if (this.sample_attr_vals.length > 0) { + this.get_distinct_attr_vals(); + this.get_attr_color_dict(); + } + longest_sample_name = d3.max((function() { + var _i, _len, _ref, _results; + _ref = this.sample_names; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + sample = _ref[_i]; + _results.push(sample.length); + } + return _results; + }).call(this)); + this.margin = { + top: 20, + right: 20, + bottom: longest_sample_name * 7, + left: 40 + }; + this.plot_width = this.sample_vals.length * 15 - this.margin.left - this.margin.right; + this.plot_height = 500 - this.margin.top - this.margin.bottom; + this.x_buffer = this.plot_width / 20; + this.y_buffer = this.plot_height / 20; + this.y_min = d3.min(this.sample_vals); + this.y_max = d3.max(this.sample_vals) * 1.1; + this.svg = this.create_svg(); + this.plot_height -= this.y_buffer; + this.create_scales(); + this.create_graph(); + d3.select("#color_attribute").on("change", function() { + var attribute; + attribute = $("#color_attribute").val(); + if ($("#update_bar_chart").html() === 'Sort By Name') { + _this.svg.selectAll(".bar").data(_this.sorted_samples()).transition().duration(1000).style("fill", function(d) { + if (attribute === "None") { + return "steelblue"; + } else { + return _this.attr_color_dict[attribute][d[2][attribute]]; + } + }).select("title").text(function(d) { + return d[1]; + }); + } else { + _this.svg.selectAll(".bar").data(_this.samples).transition().duration(1000).style("fill", function(d) { + if (attribute === "None") { + return "steelblue"; + } else { + return _this.attr_color_dict[attribute][d[2][attribute]]; + } + }); + } + return _this.add_legend(attribute, _this.distinct_attr_vals[attribute]); + }); + d3.select("#update_bar_chart").on("click", function() { + var attribute, sortItems, sorted_sample_names, x_scale; + if (_this.attributes.length > 0) { + attribute = $("#color_attribute").val(); + } + if ($("#update_bar_chart").html() === 'Sort By Value') { + $("#update_bar_chart").html('Sort By Name'); + sortItems = function(a, b) { + return a[1] - b[1]; + }; + _this.svg.selectAll(".bar").data(_this.sorted_samples()).transition().duration(1000).attr("y", function(d) { + return _this.y_scale(d[1]); + }).attr("height", function(d) { + return _this.plot_height - _this.y_scale(d[1]); + }).style("fill", function(d) { + if (_this.attributes.length > 0) { + return _this.attr_color_dict[attribute][d[2][attribute]]; + } else { + return "steelblue"; + } + }).select("title").text(function(d) { + return d[1]; + }); + sorted_sample_names = (function() { + var _i, _len, _ref, _results; + _ref = this.sorted_samples(); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + sample = _ref[_i]; + _results.push(sample[0]); + } + return _results; + }).call(_this); + x_scale = d3.scale.ordinal().domain(sorted_sample_names).rangeBands([0, _this.plot_width], .1); + $('.x.axis').remove(); + return _this.add_x_axis(x_scale); + } else { + $("#update_bar_chart").html('Sort By Value'); + _this.svg.selectAll(".bar").data(_this.samples).transition().duration(1000).attr("y", function(d) { + return _this.y_scale(d[1]); + }).attr("height", function(d) { + return _this.plot_height - _this.y_scale(d[1]); + }).style("fill", function(d) { + if (_this.attributes.length > 0) { + return _this.attr_color_dict[attribute][d[2][attribute]]; + } else { + return "steelblue"; + } + }).select("title").text(function(d) { + return d[1]; + }); + x_scale = d3.scale.ordinal().domain(_this.sample_names).rangeBands([0, _this.plot_width], .1); + $('.x.axis').remove(); + return _this.add_x_axis(x_scale); + } + }); + d3.select("#color_by_trait").on("click", function() { + return _this.color_by_trait(); + }); + } + + Bar_Chart.prototype.get_attr_color_dict = function() { + var color, color_range, distinct_vals, i, key, this_color_dict, value, _i, _j, _len, _len1, _ref, _results, + _this = this; + this.attr_color_dict = {}; + console.log("distinct_attr_vals:", this.distinct_attr_vals); + _ref = this.distinct_attr_vals; + _results = []; + for (key in _ref) { + if (!__hasProp.call(_ref, key)) continue; + distinct_vals = _ref[key]; + this_color_dict = {}; + if (distinct_vals.length < 10) { + color = d3.scale.category10(); + for (i = _i = 0, _len = distinct_vals.length; _i < _len; i = ++_i) { + value = distinct_vals[i]; + this_color_dict[value] = color(i); + } + } else { + console.log("distinct_values:", distinct_vals); + if (_.every(distinct_vals, function(d) { + if (isNaN(d)) { + return false; + } else { + return true; + } + })) { + color_range = d3.scale.linear().domain([d3.min(distinct_vals), d3.max(distinct_vals)]).range([0, 4]); + for (i = _j = 0, _len1 = distinct_vals.length; _j < _len1; i = ++_j) { + value = distinct_vals[i]; + console.log("color_range(value):", color_range(parseInt(value))); + this_color_dict[value] = d3.rgb("lightblue").darker(color_range(parseInt(value))); + } + } + } + _results.push(this.attr_color_dict[key] = this_color_dict); + } + return _results; + }; + + Bar_Chart.prototype.get_samples = function() { + var attr_vals, attribute, key, sample, _i, _j, _len, _len1, _ref, _ref1; + this.sample_names = (function() { + var _i, _len, _ref, _results; + _ref = this.sample_list; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + sample = _ref[_i]; + if (sample.value !== null) { + _results.push(sample.name); + } + } + return _results; + }).call(this); + this.sample_vals = (function() { + var _i, _len, _ref, _results; + _ref = this.sample_list; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + sample = _ref[_i]; + if (sample.value !== null) { + _results.push(sample.value); + } + } + return _results; + }).call(this); + this.attributes = (function() { + var _results; + _results = []; + for (key in this.sample_list[0]["extra_attributes"]) { + _results.push(key); + } + return _results; + }).call(this); + console.log("attributes:", this.attributes); + this.sample_attr_vals = []; + if (this.attributes.length > 0) { + _ref = this.sample_list; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + sample = _ref[_i]; + attr_vals = {}; + _ref1 = this.attributes; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + attribute = _ref1[_j]; + attr_vals[attribute] = sample["extra_attributes"][attribute]; + } + this.sample_attr_vals.push(attr_vals); + } + } + return this.samples = _.zip(this.sample_names, this.sample_vals, this.sample_attr_vals); + }; + + Bar_Chart.prototype.get_distinct_attr_vals = function() { + var attribute, sample, _i, _len, _ref, _results; + this.distinct_attr_vals = {}; + _ref = this.sample_attr_vals; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + sample = _ref[_i]; + _results.push((function() { + var _ref1, _results1; + _results1 = []; + for (attribute in sample) { + if (!this.distinct_attr_vals[attribute]) { + this.distinct_attr_vals[attribute] = []; + } + if (_ref1 = sample[attribute], __indexOf.call(this.distinct_attr_vals[attribute], _ref1) < 0) { + _results1.push(this.distinct_attr_vals[attribute].push(sample[attribute])); + } else { + _results1.push(void 0); + } + } + return _results1; + }).call(this)); + } + return _results; + }; + + Bar_Chart.prototype.create_svg = function() { + var svg; + svg = d3.select("#bar_chart").append("svg").attr("class", "bar_chart").attr("width", this.plot_width + this.margin.left + this.margin.right).attr("height", this.plot_height + this.margin.top + this.margin.bottom).append("g").attr("transform", "translate(" + this.margin.left + "," + this.margin.top + ")"); + return svg; + }; + + Bar_Chart.prototype.create_scales = function() { + this.x_scale = d3.scale.ordinal().domain(this.sample_names).rangeBands([0, this.plot_width], .1); + return this.y_scale = d3.scale.linear().domain([this.y_min * 0.75, this.y_max]).range([this.plot_height, this.y_buffer]); + }; + + Bar_Chart.prototype.create_graph = function() { + this.add_x_axis(this.x_scale); + this.add_y_axis(); + return this.add_bars(); + }; + + Bar_Chart.prototype.add_x_axis = function(scale) { + var xAxis, + _this = this; + xAxis = d3.svg.axis().scale(scale).orient("bottom"); + return this.svg.append("g").attr("class", "x axis").attr("transform", "translate(0," + this.plot_height + ")").call(xAxis).selectAll("text").style("text-anchor", "end").style("font-size", "12px").attr("dx", "-.8em").attr("dy", "-.3em").attr("transform", function(d) { + return "rotate(-90)"; + }); + }; + + Bar_Chart.prototype.add_y_axis = function() { + var yAxis; + yAxis = d3.svg.axis().scale(this.y_scale).orient("left").ticks(5); + return this.svg.append("g").attr("class", "y axis").call(yAxis).append("text").attr("transform", "rotate(-90)").attr("y", 6).attr("dy", ".71em").style("text-anchor", "end"); + }; + + Bar_Chart.prototype.add_bars = function() { + var _this = this; + return this.svg.selectAll(".bar").data(this.samples).enter().append("rect").style("fill", "steelblue").attr("class", "bar").attr("x", function(d) { + return _this.x_scale(d[0]); + }).attr("width", this.x_scale.rangeBand()).attr("y", function(d) { + return _this.y_scale(d[1]); + }).attr("height", function(d) { + return _this.plot_height - _this.y_scale(d[1]); + }).append("svg:title").text(function(d) { + return d[1]; + }); + }; + + Bar_Chart.prototype.sorted_samples = function() { + var sample_list, sorted, + _this = this; + sample_list = _.zip(this.sample_names, this.sample_vals, this.sample_attr_vals); + sorted = _.sortBy(sample_list, function(sample) { + return sample[1]; + }); + console.log("sorted:", sorted); + return sorted; + }; + + Bar_Chart.prototype.add_legend = function(attribute, distinct_vals) { + var legend, legend_rect, legend_text, + _this = this; + legend = this.svg.append("g").attr("class", "legend").attr("height", 100).attr("width", 100).attr('transform', 'translate(-20,50)'); + legend_rect = legend.selectAll('rect').data(distinct_vals).enter().append("rect").attr("x", this.plot_width - 65).attr("width", 10).attr("height", 10).attr("y", function(d, i) { + return i * 20; + }).style("fill", function(d) { + console.log("TEST:", _this.attr_color_dict[attribute][d]); + return _this.attr_color_dict[attribute][d]; + }); + return legend_text = legend.selectAll('text').data(distinct_vals).enter().append("text").attr("x", this.plot_width - 52).attr("y", function(d, i) { + return i * 20 + 9; + }).text(function(d) { + return d; + }); + }; + + Bar_Chart.prototype.color_by_trait = function() { + var _this = this; + return $('#collections_holder').load('/collections/list #collections_list', function() { + return $.colorbox({ + inline: true, + href: "#collections_holder" + }); + }); + }; + + return Bar_Chart; + + })(); + Box_Plot = (function() { + + function Box_Plot(sample_list, sample_group) { + this.sample_list = sample_list; + this.sample_group = sample_group; + this.get_samples(); + this.margin = { + top: 10, + right: 50, + bottom: 20, + left: 50 + }; + this.plot_width = 200 - this.margin.left - this.margin.right; + this.plot_height = 500 - this.margin.top - this.margin.bottom; + this.min = d3.min(this.sample_vals); + this.max = d3.max(this.sample_vals); + this.svg = this.create_svg(); + this.enter_data(); + } + + Box_Plot.prototype.get_samples = function() { + var sample; + return this.sample_vals = (function() { + var _i, _len, _ref, _results; + _ref = this.sample_list; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + sample = _ref[_i]; + if (sample.value !== null) { + _results.push(sample.value); + } + } + return _results; + }).call(this); + }; + + Box_Plot.prototype.create_svg = function() { + var svg; + svg = d3.box().whiskers(this.inter_quartile_range(1.5)).width(this.plot_width).height(this.plot_height).domain([this.min, this.max]); + return svg; + }; + + Box_Plot.prototype.enter_data = function() { + return d3.select("#box_plot").selectAll("svg").data([this.sample_vals]).enter().append("svg:svg").attr("class", "box").attr("width", this.plot_width).attr("height", this.plot_height).append("svg:g").call(this.svg); + }; + + Box_Plot.prototype.inter_quartile_range = function(k) { + var _this = this; + return function(d, i) { + var inter_quartile_range, j, q1, q3; + console.log("iqr d:", d); + q1 = d.quartiles[0]; + q3 = d.quartiles[2]; + inter_quartile_range = (q3 - q1) * k; + console.log("iqr:", inter_quartile_range); + i = 0; + j = d.length; + console.log("d[-1]:", d[1]); + console.log("q1 - iqr:", q1 - inter_quartile_range); + while (d[i] < q1 - inter_quartile_range) { + i++; + } + while (d[j] > q3 + inter_quartile_range) { + j--; + } + console.log("[i, j]", [i, j]); + return [i, j]; + }; + }; + + return Box_Plot; + + })(); sample_lists = js_data.sample_lists; - attribute_names = js_data.attribute_names; sample_group_types = js_data.sample_group_types; - new Bar_Chart(sample_lists[0], attribute_names); - $('.stats_samples_group').change(function() { + new Bar_Chart(sample_lists[0]); + new Box_Plot(sample_lists[0]); + $('.bar_chart_samples_group').change(function() { var all_samples, group; $('#bar_chart').remove(); $('#bar_chart_container').append('<div id="bar_chart"></div>'); group = $(this).val(); - console.log("group:", group); if (group === "samples_primary") { return new Bar_Chart(sample_lists[0]); } else if (group === "samples_other") { return new Bar_Chart(sample_lists[1]); } else if (group === "samples_all") { all_samples = sample_lists[0].concat(sample_lists[1]); - return new HBar_Chart(all_samples); + return new Bar_Chart(all_samples); + } + }); + $('.box_plot_samples_group').change(function() { + var all_samples, group; + $('#box_plot').remove(); + $('#box_plot_container').append('<div id="box_plot"></div>'); + group = $(this).val(); + if (group === "samples_primary") { + return new Box_Plot(sample_lists[0]); + } else if (group === "samples_other") { + return new Box_Plot(sample_lists[1]); + } else if (group === "samples_all") { + all_samples = sample_lists[0].concat(sample_lists[1]); + return new Box_Plot(all_samples); } }); hide_tabs = function(start) { diff --git a/wqflask/wqflask/templates/show_trait.html b/wqflask/wqflask/templates/show_trait.html index 36a62327..8a19e07b 100644 --- a/wqflask/wqflask/templates/show_trait.html +++ b/wqflask/wqflask/templates/show_trait.html @@ -3,6 +3,7 @@ {% block css %} <link rel="stylesheet" type="text/css" href="/static/new/css/marker_regression.css" /> <link rel="stylesheet" type="text/css" href="/static/new/css/bar_chart.css" /> + <link rel="stylesheet" type="text/css" href="/static/new/css/box_plot.css" /> <link rel="stylesheet" type="text/css" href="/static/new/packages/DataTables/css/jquery.dataTables.css" /> <link rel="stylesheet" type="text/css" href="/static/packages/DT_bootstrap/DT_bootstrap.css" /> {% endblock %} @@ -53,6 +54,7 @@ <script type="text/javascript" src="/static/new/packages/ValidationPlugin/dist/jquery.validate.min.js"></script> <script type="text/javascript" src="/static/new/javascript/stats.js"></script> + <script type="text/javascript" src="/static/new/javascript/box.js"></script> <script type="text/javascript" src="/static/new/javascript/bar_chart.js"></script> <script type="text/javascript" src="/static/new/javascript/show_trait.js"></script> <script type="text/javascript" src="/static/new/javascript/show_trait_mapping_tools.js"></script> diff --git a/wqflask/wqflask/templates/show_trait_statistics_new.html b/wqflask/wqflask/templates/show_trait_statistics_new.html index 6c64989f..6385089b 100644 --- a/wqflask/wqflask/templates/show_trait_statistics_new.html +++ b/wqflask/wqflask/templates/show_trait_statistics_new.html @@ -2,30 +2,58 @@ <br> <h2>Charts and Figures</h2> <div class="well form-horizontal"> - {% if sample_groups|length > 1 %} - <select class="stats_samples_group"> - {% for group, pretty_group in sample_group_types.items() %} - <option value="{{ group }}">{{ pretty_group }}</option> - {% endfor %} - </select> - {% endif %} - {% if sample_groups[0].attributes %} - <div class="input-append"> - <select id="color_attribute" size=1> - <option value="None">None</option> - {% for attribute in sample_groups[0].attributes %} - <option value="{{ sample_groups[0].attributes[attribute].name.replace(' ', '_') }}"> - {{ sample_groups[0].attributes[attribute].name }}</option> - {% endfor %} - </select> + <div class="tabbable"> <!-- Only required for left/right tabs --> + <ul class="nav nav-pills"> + <li class="active"> + <a href="#bar_chart_tab" data-toggle="tab">Bar Chart</a> + </li> + <li> + <a href="#box_plot_tab" data-toggle="tab">Box Plot</a> + </li> + </ul> + <div class="tab-content"> + <div class="tab-pane active" id="bar_chart_tab"> + {% if sample_groups|length > 1 %} + <select class="bar_chart_samples_group"> + {% for group, pretty_group in sample_group_types.items() %} + <option value="{{ group }}">{{ pretty_group }}</option> + {% endfor %} + </select> + {% endif %} + {% if sample_groups[0].attributes %} + <div class="input-append"> + <select id="color_attribute" size=1> + <option value="None">None</option> + {% for attribute in sample_groups[0].attributes %} + <option value="{{ sample_groups[0].attributes[attribute].name.replace(' ', '_') }}"> + {{ sample_groups[0].attributes[attribute].name }}</option> + {% endfor %} + </select> + </div> + {% endif %} + <button type="button" id="update_bar_chart">Sort By Value</button> + <button type="button" id="color_by_trait">Color by Trait</button> + <div id="bar_chart_container"> + <div id="bar_chart"></div> + </div> + </div> + <div class="tab-pane active" id="box_plot_tab"> + {% if sample_groups|length > 1 %} + <select class="box_plot_samples_group"> + {% for group, pretty_group in sample_group_types.items() %} + <option value="{{ group }}">{{ pretty_group }}</option> + {% endfor %} + </select> + <br><br> + {% endif %} + <div id="box_plot_container"> + <div id="box_plot"></div> + </div> + </div> + </div> </div> - {% endif %} - <button type="button" id="update_bar_chart">Sort By Value</button> - <button type="button" id="color_by_trait">Color by Trait</button> - <div id="bar_chart_container"> - <div id="bar_chart"></div> - </div> - </div> - <div id="collections_holder"></div> + <div id="collections_holder_wrapper" style="display:none;"> + <div id="collections_holder"></div> + </div> </div>
\ No newline at end of file |