diff options
-rwxr-xr-x | wqflask/base/data_set.py | 13 | ||||
-rw-r--r-- | wqflask/wqflask/my_pylmm/data/genofile_parser.py | 4 | ||||
-rw-r--r-- | wqflask/wqflask/static/new/css/bar_chart.css | 1 | ||||
-rw-r--r-- | wqflask/wqflask/static/new/javascript/bar_chart.coffee | 43 | ||||
-rw-r--r-- | wqflask/wqflask/static/new/javascript/bar_chart.js | 27 | ||||
-rw-r--r-- | wqflask/wqflask/static/new/javascript/histogram.coffee | 149 | ||||
-rw-r--r-- | wqflask/wqflask/static/new/javascript/histogram.js | 140 | ||||
-rw-r--r-- | wqflask/wqflask/static/new/javascript/show_trait.coffee | 17 | ||||
-rw-r--r-- | wqflask/wqflask/static/new/javascript/show_trait.js | 7 | ||||
-rw-r--r-- | wqflask/wqflask/templates/show_trait.html | 1 | ||||
-rw-r--r-- | wqflask/wqflask/templates/show_trait_statistics_new.html | 16 |
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"> |