about summary refs log tree commit diff
path: root/wqflask
diff options
context:
space:
mode:
authorLei Yan2013-11-20 20:26:49 +0000
committerLei Yan2013-11-20 20:26:49 +0000
commit8d1187e8aa1ff1ec151aa95742c2c660d74447e8 (patch)
treee5351eec484e4133749a971827ae23111ea3d9f0 /wqflask
parent47856e327c4367b1aa7e953a53e87c347eee5068 (diff)
parent36cd8acc08477038664fc3532016036f3696f734 (diff)
downloadgenenetwork2-8d1187e8aa1ff1ec151aa95742c2c660d74447e8.tar.gz
Merge /home/zas1024/gene
Diffstat (limited to 'wqflask')
-rw-r--r--wqflask/wqflask/static/new/css/box_plot.css20
-rw-r--r--wqflask/wqflask/static/new/javascript/bar_chart.coffee100
-rw-r--r--wqflask/wqflask/static/new/javascript/bar_chart.js108
-rw-r--r--wqflask/wqflask/static/new/javascript/box.js307
-rw-r--r--wqflask/wqflask/static/new/javascript/box_plot.coffee50
-rw-r--r--wqflask/wqflask/static/new/javascript/show_trait.coffee389
-rw-r--r--wqflask/wqflask/static/new/javascript/show_trait.js426
-rw-r--r--wqflask/wqflask/templates/show_trait.html2
-rw-r--r--wqflask/wqflask/templates/show_trait_statistics_new.html76
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