aboutsummaryrefslogtreecommitdiff
path: root/wqflask
diff options
context:
space:
mode:
Diffstat (limited to 'wqflask')
-rwxr-xr-xwqflask/base/data_set.py13
-rw-r--r--wqflask/wqflask/my_pylmm/data/genofile_parser.py4
-rw-r--r--wqflask/wqflask/static/new/css/bar_chart.css1
-rw-r--r--wqflask/wqflask/static/new/javascript/bar_chart.coffee43
-rw-r--r--wqflask/wqflask/static/new/javascript/bar_chart.js27
-rw-r--r--wqflask/wqflask/static/new/javascript/histogram.coffee149
-rw-r--r--wqflask/wqflask/static/new/javascript/histogram.js140
-rw-r--r--wqflask/wqflask/static/new/javascript/show_trait.coffee17
-rw-r--r--wqflask/wqflask/static/new/javascript/show_trait.js7
-rw-r--r--wqflask/wqflask/templates/show_trait.html1
-rw-r--r--wqflask/wqflask/templates/show_trait_statistics_new.html16
11 files changed, 367 insertions, 51 deletions
diff --git a/wqflask/base/data_set.py b/wqflask/base/data_set.py
index fbe78d5d..d421f21e 100755
--- a/wqflask/base/data_set.py
+++ b/wqflask/base/data_set.py
@@ -168,13 +168,14 @@ class Markers(object):
for marker, p_value in itertools.izip(self.markers, p_values):
marker['p_value'] = p_value
- if math.isnan(marker['p_value']):
+ if math.isnan(marker['p_value']) or marker['p_value'] <= 0:
print("p_value is:", marker['p_value'])
- marker['lod_score'] = -math.log10(marker['p_value'])
- #Using -log(p) for the LRS; need to ask Rob how he wants to get LRS from p-values
- marker['lrs_value'] = -math.log10(marker['p_value']) * 4.61
-
-
+ marker['lod_score'] = 0
+ marker['lrs_value'] = 0
+ else:
+ marker['lod_score'] = -math.log10(marker['p_value'])
+ #Using -log(p) for the LRS; need to ask Rob how he wants to get LRS from p-values
+ marker['lrs_value'] = -math.log10(marker['p_value']) * 4.61
class HumanMarkers(Markers):
diff --git a/wqflask/wqflask/my_pylmm/data/genofile_parser.py b/wqflask/wqflask/my_pylmm/data/genofile_parser.py
index af855fb4..c8c0929f 100644
--- a/wqflask/wqflask/my_pylmm/data/genofile_parser.py
+++ b/wqflask/wqflask/my_pylmm/data/genofile_parser.py
@@ -106,8 +106,8 @@ class ConvertGenoFile(object):
this_marker.genotypes.append("NA")
#print("this_marker is:", pf(this_marker.__dict__))
-
- self.markers.append(this_marker.__dict__)
+ if this_marker.chr == "5":
+ self.markers.append(this_marker.__dict__)
with open(self.output_file, 'w') as fh:
json.dump(self.markers, fh, indent=" ", sort_keys=True)
diff --git a/wqflask/wqflask/static/new/css/bar_chart.css b/wqflask/wqflask/static/new/css/bar_chart.css
index ba14fe4e..c8e081f9 100644
--- a/wqflask/wqflask/static/new/css/bar_chart.css
+++ b/wqflask/wqflask/static/new/css/bar_chart.css
@@ -7,6 +7,7 @@
.bar {
fill: steelblue;
+ shape-rendering: crispEdges;
}
.x.axis path {
diff --git a/wqflask/wqflask/static/new/javascript/bar_chart.coffee b/wqflask/wqflask/static/new/javascript/bar_chart.coffee
index 27a8d284..3f12d956 100644
--- a/wqflask/wqflask/static/new/javascript/bar_chart.coffee
+++ b/wqflask/wqflask/static/new/javascript/bar_chart.coffee
@@ -132,7 +132,6 @@ class Bar_Chart
d3.select("#color_by_trait").on("click", =>
@open_trait_selection()
-
)
rebuild_bar_graph: (samples) ->
@@ -141,20 +140,11 @@ class Bar_Chart
.data(samples)
.transition()
.duration(1000)
- .attr("y", (d) =>
- return @y_scale(d[1])
- )
- .attr("height", (d) =>
- return @plot_height - @y_scale(d[1])
- )
- .select("title")
- .text((d) =>
- return d[1]
- )
.style("fill", (d) =>
- if @attributes.length == 0
+ if @attributes.length == 0 and @trait_color_dict?
console.log("SAMPLE:", d[0])
console.log("CHECKING:", @trait_color_dict[d[0]])
+ #return "steelblue"
return @trait_color_dict[d[0]]
else if @attributes.length > 0 and @attribute != "None"
console.log("@attribute:", @attribute)
@@ -164,6 +154,16 @@ class Bar_Chart
else
return "steelblue"
)
+ .attr("y", (d) =>
+ return @y_scale(d[1])
+ )
+ .attr("height", (d) =>
+ return @plot_height - @y_scale(d[1])
+ )
+ .select("title")
+ .text((d) =>
+ return d[1]
+ )
#.style("fill", (d) =>
# return @trait_color_dict[d[0]]
# #return @attr_color_dict["collection_trait"][trimmed_samples[d[0]]]
@@ -419,29 +419,34 @@ class Bar_Chart
#@get_attr_color_dict(distinct_values)
@get_trait_color_dict(trimmed_samples, distinct_values)
console.log("TRAIT_COLOR_DICT:", @trait_color_dict)
- if $("#update_bar_chart").html() == 'Sort By Name'
+ console.log("SAMPLES:", @samples)
+ if @sort_by = "value"
@svg.selectAll(".bar")
- .data(@sorted_samples())
+ .data(@samples)
.transition()
.duration(1000)
.style("fill", (d) =>
+ console.log("this color:", @trait_color_dict[d[0]])
return @trait_color_dict[d[0]]
- #return @attr_color_dict["collection_trait"][trimmed_samples[d[0]]]
)
.select("title")
.text((d) =>
return d[1]
- )
+ )
+
else
@svg.selectAll(".bar")
- .data(@samples)
+ .data(@sorted_samples())
.transition()
.duration(1000)
.style("fill", (d) =>
+ console.log("this color:", @trait_color_dict[d[0]])
return @trait_color_dict[d[0]]
- #return @attr_color_dict["collection_trait"][trimmed_samples[d[0]]]
)
-
+ .select("title")
+ .text((d) =>
+ return d[1]
+ )
trim_values: (trait_sample_data) ->
trimmed_samples = {}
diff --git a/wqflask/wqflask/static/new/javascript/bar_chart.js b/wqflask/wqflask/static/new/javascript/bar_chart.js
index faf66cd4..c0b056f8 100644
--- a/wqflask/wqflask/static/new/javascript/bar_chart.js
+++ b/wqflask/wqflask/static/new/javascript/bar_chart.js
@@ -95,14 +95,8 @@
var sample, sample_names, x_scale,
_this = this;
console.log("samples:", samples);
- this.svg.selectAll(".bar").data(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]);
- }).select("title").text(function(d) {
- return d[1];
- }).style("fill", function(d) {
- if (_this.attributes.length === 0) {
+ this.svg.selectAll(".bar").data(samples).transition().duration(1000).style("fill", function(d) {
+ if (_this.attributes.length === 0 && (_this.trait_color_dict != null)) {
console.log("SAMPLE:", d[0]);
console.log("CHECKING:", _this.trait_color_dict[d[0]]);
return _this.trait_color_dict[d[0]];
@@ -114,6 +108,12 @@
} else {
return "steelblue";
}
+ }).attr("y", function(d) {
+ return _this.y_scale(d[1]);
+ }).attr("height", function(d) {
+ return _this.plot_height - _this.y_scale(d[1]);
+ }).select("title").text(function(d) {
+ return d[1];
});
sample_names = (function() {
var _i, _len, _results;
@@ -394,15 +394,20 @@
distinct_values["collection_trait"] = this.get_distinct_values(trimmed_samples);
this.get_trait_color_dict(trimmed_samples, distinct_values);
console.log("TRAIT_COLOR_DICT:", this.trait_color_dict);
- if ($("#update_bar_chart").html() === 'Sort By Name') {
- return this.svg.selectAll(".bar").data(this.sorted_samples()).transition().duration(1000).style("fill", function(d) {
+ console.log("SAMPLES:", this.samples);
+ if (this.sort_by = "value") {
+ return this.svg.selectAll(".bar").data(this.samples).transition().duration(1000).style("fill", function(d) {
+ console.log("this color:", _this.trait_color_dict[d[0]]);
return _this.trait_color_dict[d[0]];
}).select("title").text(function(d) {
return d[1];
});
} else {
- return this.svg.selectAll(".bar").data(this.samples).transition().duration(1000).style("fill", function(d) {
+ return this.svg.selectAll(".bar").data(this.sorted_samples()).transition().duration(1000).style("fill", function(d) {
+ console.log("this color:", _this.trait_color_dict[d[0]]);
return _this.trait_color_dict[d[0]];
+ }).select("title").text(function(d) {
+ return d[1];
});
}
};
diff --git a/wqflask/wqflask/static/new/javascript/histogram.coffee b/wqflask/wqflask/static/new/javascript/histogram.coffee
new file mode 100644
index 00000000..03332835
--- /dev/null
+++ b/wqflask/wqflask/static/new/javascript/histogram.coffee
@@ -0,0 +1,149 @@
+root = exports ? this
+
+class Histogram
+ constructor: (@sample_list, @sample_group) ->
+ @sort_by = "name"
+ @format_count = d3.format(",.0f") #a formatter for counts
+ @get_samples()
+ #if @sample_attr_vals.length > 0
+ # @get_distinct_attr_vals()
+ # @get_attr_color_dict(@distinct_attr_vals)
+
+ @margin = {top: 10, right: 30, bottom: 30, left: 30}
+ @plot_width = 960 - @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
+
+ @plot_height -= @y_buffer
+ @create_x_scale()
+ @get_histogram_data()
+ @create_y_scale()
+
+ @svg = @create_svg()
+
+ @create_graph()
+
+ 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)
+
+ create_svg: () ->
+ svg = d3.select("#histogram")
+ .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_x_scale: () ->
+ @x_scale = d3.scale.linear()
+ .domain([d3.min(@sample_vals), d3.max(@sample_vals)])
+ .range([0, @plot_width])
+
+ get_histogram_data: () ->
+ console.log("sample_vals:", @sample_vals)
+ @histogram_data = d3.layout.histogram()
+ .bins(@x_scale.ticks(10))(@sample_vals)
+ console.log("histogram_data:", @histogram_data[0])
+
+ create_y_scale: () ->
+ @y_scale = d3.scale.linear()
+ .domain([0, d3.max(@histogram_data, (d) => return d.y )])
+ .range([@plot_height, 0])
+
+ create_graph: () ->
+
+ @add_x_axis()
+ #@add_y_axis()
+
+ @add_bars()
+
+ add_x_axis: () ->
+ x_axis = d3.svg.axis()
+ .scale(@x_scale)
+ .orient("bottom");
+
+ @svg.append("g")
+ .attr("class", "x axis")
+ .attr("transform", "translate(0," + @plot_height + ")")
+ .call(x_axis)
+ #.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: () ->
+ # y_axis = d3.svg.axis()
+ # .scale(@y_scale)
+ # .orient("left")
+ # .ticks(5)
+ #
+ # @svg.append("g")
+ # .attr("class", "y axis")
+ # .call(y_axis)
+ # .append("text")
+ # .attr("transform", "rotate(-90)")
+ # .attr("y", 6)
+ # .attr("dy", ".71em")
+ # .style("text-anchor", "end")
+
+ add_bars: () ->
+ @svg.selectAll(".bar")
+ .data(@histogram_data)
+ .enter().append("g")
+ .attr("class", "bar")
+ .attr("transform", (d) =>
+ return "translate(" + @margin.left + "," + @margin.top + ")")
+ .append("rect")
+ .attr("x", 1)
+ .attr("width", @x_scale(@histogram_data[0].dx) - 1)
+ .attr("height", (d) =>
+ return @plot_height - @y_scale(d.y)
+ )
+ .append("text")
+ .attr("dy", ".75em")
+ .attr("y", 6)
+ .attr("x", @x_scale(@histogram_data[0].dx) / 2)
+ .attr("text-anchor", "middle")
+ .text((d) =>
+ return @format_count(d.y)
+ )
+
+ #open_trait_selection: () ->
+ # $('#collections_holder').load('/collections/list?color_by_trait #collections_list', =>
+ # $.colorbox(
+ # inline: true
+ # href: "#collections_holder"
+ # )
+ # #Removes the links from the collection names, because clicking them would leave the page
+ # #instead of loading the list of traits in the colorbox
+ # $('a.collection_name').attr( 'onClick', 'return false' )
+ # #$('.collection_name').each (index, element) =>
+ # # console.log("contents:", $(element).contents())
+ # # $(element).contents().unwrap()
+ # )
+
+root.Histogram = Histogram \ No newline at end of file
diff --git a/wqflask/wqflask/static/new/javascript/histogram.js b/wqflask/wqflask/static/new/javascript/histogram.js
new file mode 100644
index 00000000..e7926ab1
--- /dev/null
+++ b/wqflask/wqflask/static/new/javascript/histogram.js
@@ -0,0 +1,140 @@
+// Generated by CoffeeScript 1.6.1
+(function() {
+ var Histogram, root;
+
+ root = typeof exports !== "undefined" && exports !== null ? exports : this;
+
+ Histogram = (function() {
+
+ function Histogram(sample_list, sample_group) {
+ this.sample_list = sample_list;
+ this.sample_group = sample_group;
+ this.sort_by = "name";
+ this.format_count = d3.format(",.0f");
+ this.get_samples();
+ this.margin = {
+ top: 10,
+ right: 30,
+ bottom: 30,
+ left: 30
+ };
+ this.plot_width = 960 - 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.plot_height -= this.y_buffer;
+ this.create_x_scale();
+ this.get_histogram_data();
+ this.create_y_scale();
+ this.svg = this.create_svg();
+ this.create_graph();
+ }
+
+ Histogram.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);
+ };
+
+ Histogram.prototype.create_svg = function() {
+ var svg;
+ svg = d3.select("#histogram").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;
+ };
+
+ Histogram.prototype.create_x_scale = function() {
+ return this.x_scale = d3.scale.linear().domain([d3.min(this.sample_vals), d3.max(this.sample_vals)]).range([0, this.plot_width]);
+ };
+
+ Histogram.prototype.get_histogram_data = function() {
+ console.log("sample_vals:", this.sample_vals);
+ this.histogram_data = d3.layout.histogram().bins(this.x_scale.ticks(10))(this.sample_vals);
+ return console.log("histogram_data:", this.histogram_data[0]);
+ };
+
+ Histogram.prototype.create_y_scale = function() {
+ var _this = this;
+ return this.y_scale = d3.scale.linear().domain([
+ 0, d3.max(this.histogram_data, function(d) {
+ return d.y;
+ })
+ ]).range([this.plot_height, 0]);
+ };
+
+ Histogram.prototype.create_graph = function() {
+ this.add_x_axis();
+ return this.add_bars();
+ };
+
+ Histogram.prototype.add_x_axis = function() {
+ var x_axis;
+ x_axis = d3.svg.axis().scale(this.x_scale).orient("bottom");
+ return this.svg.append("g").attr("class", "x axis").attr("transform", "translate(0," + this.plot_height + ")").call(x_axis);
+ };
+
+ Histogram.prototype.add_bars = function() {
+ var _this = this;
+ return this.svg.selectAll(".bar").data(this.histogram_data).enter().append("g").attr("class", "bar").attr("transform", function(d) {
+ return "translate(" + _this.margin.left + "," + _this.margin.top + ")";
+ }).append("rect").attr("x", 1).attr("width", this.x_scale(this.histogram_data[0].dx) - 1).attr("height", function(d) {
+ return _this.plot_height - _this.y_scale(d.y);
+ }).append("text").attr("dy", ".75em").attr("y", 6).attr("x", this.x_scale(this.histogram_data[0].dx) / 2).attr("text-anchor", "middle").text(function(d) {
+ return _this.format_count(d.y);
+ });
+ };
+
+ return Histogram;
+
+ })();
+
+ root.Histogram = Histogram;
+
+}).call(this);
diff --git a/wqflask/wqflask/static/new/javascript/show_trait.coffee b/wqflask/wqflask/static/new/javascript/show_trait.coffee
index 1df033d6..e42a7d82 100644
--- a/wqflask/wqflask/static/new/javascript/show_trait.coffee
+++ b/wqflask/wqflask/static/new/javascript/show_trait.coffee
@@ -66,6 +66,7 @@ $ ->
$("#update_bar_chart.btn-group").button()
root.bar_chart = new Bar_Chart(sample_lists[0])
+ root.histogram = new Histogram(sample_lists[0])
new Box_Plot(sample_lists[0])
$('.bar_chart_samples_group').change ->
@@ -73,13 +74,12 @@ $ ->
$('#bar_chart_container').append('<div id="bar_chart"></div>')
group = $(this).val()
if group == "samples_primary"
- new Bar_Chart(sample_lists[0])
+ root.bar_chart = new Bar_Chart(sample_lists[0])
else if group == "samples_other"
- new Bar_Chart(sample_lists[1])
+ root.bar_chart = new Bar_Chart(sample_lists[1])
else if group == "samples_all"
all_samples = sample_lists[0].concat sample_lists[1]
- new Bar_Chart(all_samples)
- #$(".btn-group").button()
+ root.bar_chart = new Bar_Chart(all_samples)
$('.box_plot_samples_group').change ->
$('#box_plot').remove()
@@ -93,18 +93,18 @@ $ ->
all_samples = sample_lists[0].concat sample_lists[1]
new Box_Plot(all_samples)
-
+
hide_tabs = (start) ->
for x in [start..10]
$("#stats_tabs" + x).hide()
+
# Changes stats table between all, bxd only and non-bxd, etc.
stats_mdp_change = ->
selected = $(this).val()
hide_tabs(0)
$("#stats_tabs" + selected).show()
- #$(".stats_mdp").change(stats_mdp_change)
change_stats_value = (sample_sets, category, value_type, decimal_places)->
id = "#" + process_id(category, value_type)
@@ -130,12 +130,9 @@ $ ->
if title_value
$(id).attr('title', title_value)
+
update_stat_values = (sample_sets)->
for category in ['samples_primary', 'samples_other', 'samples_all']
- #change_stats_value(sample_sets, category, "n_of_samples", 0)
-
- #for stat in ["mean", "median", "std_dev", "std_error", "min", "max"]
- #for stat in (row.vn for row in Stat_Table_Rows)
for row in Stat_Table_Rows
console.log("Calling change_stats_value")
change_stats_value(sample_sets, category, row.vn, row.digits)
diff --git a/wqflask/wqflask/static/new/javascript/show_trait.js b/wqflask/wqflask/static/new/javascript/show_trait.js
index 90fa8228..d3a34166 100644
--- a/wqflask/wqflask/static/new/javascript/show_trait.js
+++ b/wqflask/wqflask/static/new/javascript/show_trait.js
@@ -63,6 +63,7 @@
sample_group_types = js_data.sample_group_types;
$("#update_bar_chart.btn-group").button();
root.bar_chart = new Bar_Chart(sample_lists[0]);
+ root.histogram = new Histogram(sample_lists[0]);
new Box_Plot(sample_lists[0]);
$('.bar_chart_samples_group').change(function() {
var all_samples, group;
@@ -70,12 +71,12 @@
$('#bar_chart_container').append('<div id="bar_chart"></div>');
group = $(this).val();
if (group === "samples_primary") {
- return new Bar_Chart(sample_lists[0]);
+ return root.bar_chart = new Bar_Chart(sample_lists[0]);
} else if (group === "samples_other") {
- return new Bar_Chart(sample_lists[1]);
+ return root.bar_chart = new Bar_Chart(sample_lists[1]);
} else if (group === "samples_all") {
all_samples = sample_lists[0].concat(sample_lists[1]);
- return new Bar_Chart(all_samples);
+ return root.bar_chart = new Bar_Chart(all_samples);
}
});
$('.box_plot_samples_group').change(function() {
diff --git a/wqflask/wqflask/templates/show_trait.html b/wqflask/wqflask/templates/show_trait.html
index 86891bb0..26f21f08 100644
--- a/wqflask/wqflask/templates/show_trait.html
+++ b/wqflask/wqflask/templates/show_trait.html
@@ -58,6 +58,7 @@
<script type="text/javascript" src="/static/new/javascript/box.js"></script>
<script type="text/javascript" src="/static/new/javascript/get_traits_from_collection.js"></script>
<script type="text/javascript" src="/static/new/javascript/bar_chart.js"></script>
+ <script type="text/javascript" src="/static/new/javascript/histogram.js"></script>
<script type="text/javascript" src="/static/new/javascript/box_plot.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 9393e9bd..28f7e0c7 100644
--- a/wqflask/wqflask/templates/show_trait_statistics_new.html
+++ b/wqflask/wqflask/templates/show_trait_statistics_new.html
@@ -8,6 +8,9 @@
<a href="#bar_chart_tab" data-toggle="tab">Bar Chart</a>
</li>
<li>
+ <a href="#histogram_tab" data-toggle="tab">Histogram</a>
+ </li>
+ <li>
<a href="#box_plot_tab" data-toggle="tab">Box Plot</a>
</li>
</ul>
@@ -51,6 +54,19 @@
<div id="bar_chart"></div>
</div>
</div>
+ <div class="tab-pane" id="histogram_tab">
+ {% if sample_groups|length > 1 %}
+ <select class="histogram_samples_group">
+ {% for group, pretty_group in sample_group_types.items() %}
+ <option value="{{ group }}">{{ pretty_group }}</option>
+ {% endfor %}
+ </select>
+ <br><br>
+ {% endif %}
+ <div id="histogram_container">
+ <div id="histogram"></div>
+ </div>
+ </div>
<div class="tab-pane" id="box_plot_tab">
{% if sample_groups|length > 1 %}
<select class="box_plot_samples_group">