From 744c247c4de7a49b565e7deead5176efff2b55a2 Mon Sep 17 00:00:00 2001 From: Artem Tarasov Date: Mon, 18 May 2015 14:12:19 +0300 Subject: fix attribute coloring also I found out that there are two legends shown simultaneously, but one is suitable only for discrete values, and the other for continuous; now only the suitable one is shown --- wqflask/runserver.py | 3 +- .../wqflask/static/new/javascript/bar_chart.coffee | 117 +++++++------- wqflask/wqflask/static/new/javascript/bar_chart.js | 169 +++++++++++++-------- 3 files changed, 164 insertions(+), 125 deletions(-) diff --git a/wqflask/runserver.py b/wqflask/runserver.py index 5a76d1e2..59ebf0d4 100755 --- a/wqflask/runserver.py +++ b/wqflask/runserver.py @@ -30,6 +30,7 @@ logging_tree.printout() app.run(host='0.0.0.0', port=app.config['SERVER_PORT'], - use_debugger=False, + debug=True, + use_debugger=True, threaded=True, use_reloader=True) diff --git a/wqflask/wqflask/static/new/javascript/bar_chart.coffee b/wqflask/wqflask/static/new/javascript/bar_chart.coffee index acc4ac46..8c958e7d 100755 --- a/wqflask/wqflask/static/new/javascript/bar_chart.coffee +++ b/wqflask/wqflask/static/new/javascript/bar_chart.coffee @@ -26,41 +26,36 @@ class Bar_Chart @svg = @create_svg() @plot_height -= @y_buffer - @create_scales() + @create_scales(@sample_names) @create_graph() d3.select("#color_attribute").on("change", => @attribute = $("#color_attribute").val() + console.log("attr_color_dict:", @attr_color_dict) - #if $("#update_bar_chart").html() == 'Sort By Name' - if @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] - ) + + @svg.selectAll(".bar") + .data(if @sort_by == "name" then @samples else @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] + ) + + $(".legend").remove() + if @attribute == "None" or @is_discrete[@attribute] + $("#legend-left,#legend-right,#legend-colors").empty() + if @attribute != "None" + @add_legend(@attribute, @distinct_attr_vals[@attribute]) 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]] - ) - @draw_legend() - @add_legend(@attribute, @distinct_attr_vals[@attribute]) + @draw_legend() ) $(".sort_by_value").on("click", => @@ -136,23 +131,31 @@ class Bar_Chart @open_trait_selection() ) + extra: (sample) -> + attr_vals = {} + for attribute in @attributes + attr_vals[attribute] = sample["extra_attributes"][attribute] + attr_vals + # takes a dict: name -> value and rebuilds the graph redraw: (samples_dict) -> - updated_samples = [] - for [name, val, attr] in @full_sample_list - if name of samples_dict - updated_samples.push [name, samples_dict[name], attr] - - @samples = updated_samples - # TODO: update underscore.js and replace the below with an _.unzip call - @sample_names = (x[0] for x in @samples) - @sample_vals = (x[1] for x in @samples) - @sample_attr_vals = (x[2] for x in @samples) + curr = (x for x in @sample_list when\ + x.name of samples_dict and samples_dict[x.name] != null) + @sample_names = (x.name for x in curr) + @sample_vals = (samples_dict[x.name] for x in curr) + @sample_attr_vals = (@extra(x) for x in curr) + @samples = _.zip(@sample_names, @sample_vals, @sample_attr_vals) @rebuild_bar_graph(if @sort_by == 'name' then @samples else @sorted_samples()) rebuild_bar_graph: (samples) -> console.log("samples:", samples) + @attribute = $("#color_attribute").val() + + vals = (x[1] for x in samples) + @y_min = d3.min(vals) + @y_max = d3.max(vals) * 1.1 + @svg.selectAll(".bar") .data(samples) .transition() @@ -185,7 +188,8 @@ class Bar_Chart # return @trait_color_dict[d[0]] # #return @attr_color_dict["collection_trait"][trimmed_samples[d[0]]] #) - @create_scales() + names = (x[0] for x in samples) + @create_scales(names) $('.bar_chart').find('.x.axis').remove() $('.bar_chart').find('.y.axis').remove() @add_x_axis() @@ -193,12 +197,16 @@ class Bar_Chart get_attr_color_dict: (vals) -> @attr_color_dict = {} + @is_discrete = {} + @minimum_values = {} + @maximum_values = {} console.log("vals:", vals) for own key, distinct_vals of vals @min_val = d3.min(distinct_vals) @max_val = d3.max(distinct_vals) this_color_dict = {} - if distinct_vals.length < 10 + discrete = distinct_vals.length < 10 + if discrete color = d3.scale.category10() for value, i in distinct_vals this_color_dict[value] = color(i) @@ -213,8 +221,7 @@ class Bar_Chart return true ) color_range = d3.scale.linear() - .domain([min_val, - max_val]) + .domain([@min_val, @max_val]) .range([0,255]) for value, i in distinct_vals console.log("color_range(value):", parseInt(color_range(value))) @@ -222,12 +229,15 @@ class Bar_Chart #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 + @is_discrete[key] = discrete + @minimum_values[key] = @min_val + @maximum_values[key] = @max_val draw_legend: () -> - $('#legend-left').html(@min_val) - $('#legend-right').html(@max_val) + $('#legend-left').html(@minimum_values[@attribute]) + $('#legend-right').html(@maximum_values[@attribute]) svg_html = ' \ \ \ @@ -285,19 +295,11 @@ class Bar_Chart @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 = [] - # WTF??? how can they be zipped later??? - # TODO find something with extra_attributes for testing - 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) + @sample_attr_vals = (@extra(sample) for sample in @sample_list when sample.value != null) @samples = _.zip(@sample_names, @sample_vals, @sample_attr_vals) - @full_sample_list = @samples.slice() # keeps attributes across redraws get_distinct_attr_vals: () -> + # FIXME: this has quadratic behaviour, may cause issues with many samples and continuous attributes @distinct_attr_vals = {} for sample in @sample_attr_vals for attribute of sample @@ -318,9 +320,9 @@ class Bar_Chart return svg - create_scales: () -> + create_scales: (sample_names) -> @x_scale = d3.scale.ordinal() - .domain(@sample_names) + .domain(sample_names) .rangeRoundBands([0, @range], 0.1, 0) @y_scale = d3.scale.linear() @@ -401,6 +403,7 @@ class Bar_Chart console.log("sorted:", sorted) return sorted + # FIXME: better positioning of the legend add_legend: (attribute, distinct_vals) -> legend = @svg.append("g") .attr("class", "legend") diff --git a/wqflask/wqflask/static/new/javascript/bar_chart.js b/wqflask/wqflask/static/new/javascript/bar_chart.js index 4dba3793..c392acc8 100755 --- a/wqflask/wqflask/static/new/javascript/bar_chart.js +++ b/wqflask/wqflask/static/new/javascript/bar_chart.js @@ -42,33 +42,30 @@ 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_scales(this.sample_names); this.create_graph(); d3.select("#color_attribute").on("change", (function(_this) { return function() { _this.attribute = $("#color_attribute").val(); console.log("attr_color_dict:", _this.attr_color_dict); - if (_this.sort_by = "name") { - _this.svg.selectAll(".bar").data(_this.sorted_samples()).transition().duration(1000).style("fill", function(d) { - if (_this.attribute === "None") { - return "steelblue"; - } else { - return _this.attr_color_dict[_this.attribute][d[2][_this.attribute]]; - } - }).select("title").text(function(d) { - return d[1]; - }); + _this.svg.selectAll(".bar").data(_this.sort_by === "name" ? _this.samples : _this.sorted_samples()).transition().duration(1000).style("fill", function(d) { + if (_this.attribute === "None") { + return "steelblue"; + } else { + return _this.attr_color_dict[_this.attribute][d[2][_this.attribute]]; + } + }).select("title").text(function(d) { + return d[1]; + }); + $(".legend").remove(); + if (_this.attribute === "None" || _this.is_discrete[_this.attribute]) { + $("#legend-left,#legend-right,#legend-colors").empty(); + if (_this.attribute !== "None") { + return _this.add_legend(_this.attribute, _this.distinct_attr_vals[_this.attribute]); + } } else { - _this.svg.selectAll(".bar").data(_this.samples).transition().duration(1000).style("fill", function(d) { - if (_this.attribute === "None") { - return "steelblue"; - } else { - return _this.attr_color_dict[_this.attribute][d[2][_this.attribute]]; - } - }); + return _this.draw_legend(); } - _this.draw_legend(); - return _this.add_legend(_this.attribute, _this.distinct_attr_vals[_this.attribute]); }; })(this)); $(".sort_by_value").on("click", (function(_this) { @@ -98,52 +95,77 @@ })(this)); } - Bar_Chart.prototype.redraw = function(samples_dict) { - var attr, j, len, name, ref, ref1, updated_samples, val, x; - updated_samples = []; - ref = this.full_sample_list; + Bar_Chart.prototype.extra = function(sample) { + var attr_vals, attribute, j, len, ref; + attr_vals = {}; + ref = this.attributes; for (j = 0, len = ref.length; j < len; j++) { - ref1 = ref[j], name = ref1[0], val = ref1[1], attr = ref1[2]; - if (name in samples_dict) { - updated_samples.push([name, samples_dict[name], attr]); - } + attribute = ref[j]; + attr_vals[attribute] = sample["extra_attributes"][attribute]; } - this.samples = updated_samples; - this.sample_names = (function() { - var k, len1, ref2, results; - ref2 = this.samples; + return attr_vals; + }; + + Bar_Chart.prototype.redraw = function(samples_dict) { + var curr, x; + curr = (function() { + var j, len, ref, results; + ref = this.sample_list; results = []; - for (k = 0, len1 = ref2.length; k < len1; k++) { - x = ref2[k]; - results.push(x[0]); + for (j = 0, len = ref.length; j < len; j++) { + x = ref[j]; + if (x.name in samples_dict && samples_dict[x.name] !== null) { + results.push(x); + } } return results; }).call(this); + this.sample_names = (function() { + var j, len, results; + results = []; + for (j = 0, len = curr.length; j < len; j++) { + x = curr[j]; + results.push(x.name); + } + return results; + })(); this.sample_vals = (function() { - var k, len1, ref2, results; - ref2 = this.samples; + var j, len, results; results = []; - for (k = 0, len1 = ref2.length; k < len1; k++) { - x = ref2[k]; - results.push(x[1]); + for (j = 0, len = curr.length; j < len; j++) { + x = curr[j]; + results.push(samples_dict[x.name]); } return results; - }).call(this); + })(); this.sample_attr_vals = (function() { - var k, len1, ref2, results; - ref2 = this.samples; + var j, len, results; results = []; - for (k = 0, len1 = ref2.length; k < len1; k++) { - x = ref2[k]; - results.push(x[2]); + for (j = 0, len = curr.length; j < len; j++) { + x = curr[j]; + results.push(this.extra(x)); } return results; }).call(this); + this.samples = _.zip(this.sample_names, this.sample_vals, this.sample_attr_vals); return this.rebuild_bar_graph(this.sort_by === 'name' ? this.samples : this.sorted_samples()); }; Bar_Chart.prototype.rebuild_bar_graph = function(samples) { + var names, vals, x; console.log("samples:", samples); + this.attribute = $("#color_attribute").val(); + vals = (function() { + var j, len, results; + results = []; + for (j = 0, len = samples.length; j < len; j++) { + x = samples[j]; + results.push(x[1]); + } + return results; + })(); + this.y_min = d3.min(vals); + this.y_max = d3.max(vals) * 1.1; this.svg.selectAll(".bar").data(samples).transition().duration(1000).style("fill", (function(_this) { return function(d) { if (_this.attributes.length === 0 && (_this.trait_color_dict != null)) { @@ -172,7 +194,16 @@ return d[1]; }; })(this)); - this.create_scales(); + names = (function() { + var j, len, results; + results = []; + for (j = 0, len = samples.length; j < len; j++) { + x = samples[j]; + results.push(x[0]); + } + return results; + })(); + this.create_scales(names); $('.bar_chart').find('.x.axis').remove(); $('.bar_chart').find('.y.axis').remove(); this.add_x_axis(); @@ -180,8 +211,11 @@ }; Bar_Chart.prototype.get_attr_color_dict = function(vals) { - var color, color_range, distinct_vals, i, j, k, key, len, len1, results, this_color_dict, value; + var color, color_range, discrete, distinct_vals, i, j, k, key, len, len1, results, this_color_dict, value; this.attr_color_dict = {}; + this.is_discrete = {}; + this.minimum_values = {}; + this.maximum_values = {}; console.log("vals:", vals); results = []; for (key in vals) { @@ -190,7 +224,8 @@ this.min_val = d3.min(distinct_vals); this.max_val = d3.max(distinct_vals); this_color_dict = {}; - if (distinct_vals.length < 10) { + discrete = distinct_vals.length < 10; + if (discrete) { color = d3.scale.category10(); for (i = j = 0, len = distinct_vals.length; j < len; i = ++j) { value = distinct_vals[i]; @@ -207,7 +242,7 @@ } }; })(this))) { - color_range = d3.scale.linear().domain([min_val, max_val]).range([0, 255]); + color_range = d3.scale.linear().domain([this.min_val, this.max_val]).range([0, 255]); for (i = k = 0, len1 = distinct_vals.length; k < len1; i = ++k) { value = distinct_vals[i]; console.log("color_range(value):", parseInt(color_range(value))); @@ -215,15 +250,18 @@ } } } - results.push(this.attr_color_dict[key] = this_color_dict); + this.attr_color_dict[key] = this_color_dict; + this.is_discrete[key] = discrete; + this.minimum_values[key] = this.min_val; + results.push(this.maximum_values[key] = this.max_val); } return results; }; Bar_Chart.prototype.draw_legend = function() { var svg_html; - $('#legend-left').html(this.min_val); - $('#legend-right').html(this.max_val); + $('#legend-left').html(this.minimum_values[this.attribute]); + $('#legend-right').html(this.maximum_values[this.attribute]); svg_html = ' '; console.log("svg_html:", svg_html); return $('#legend-colors').html(svg_html); @@ -287,7 +325,7 @@ }; Bar_Chart.prototype.get_samples = function() { - var attr_vals, attribute, j, k, key, len, len1, ref, ref1, sample; + var key, sample; this.sample_names = (function() { var j, len, ref, results; ref = this.sample_list; @@ -321,22 +359,19 @@ return results; }).call(this); console.log("attributes:", this.attributes); - this.sample_attr_vals = []; - if (this.attributes.length > 0) { + this.sample_attr_vals = (function() { + var j, len, ref, results; ref = this.sample_list; + results = []; for (j = 0, len = ref.length; j < len; j++) { sample = ref[j]; - attr_vals = {}; - ref1 = this.attributes; - for (k = 0, len1 = ref1.length; k < len1; k++) { - attribute = ref1[k]; - attr_vals[attribute] = sample["extra_attributes"][attribute]; + if (sample.value !== null) { + results.push(this.extra(sample)); } - this.sample_attr_vals.push(attr_vals); } - } - this.samples = _.zip(this.sample_names, this.sample_vals, this.sample_attr_vals); - return this.full_sample_list = this.samples.slice(); + return results; + }).call(this); + return this.samples = _.zip(this.sample_names, this.sample_vals, this.sample_attr_vals); }; Bar_Chart.prototype.get_distinct_attr_vals = function() { @@ -371,8 +406,8 @@ return svg; }; - Bar_Chart.prototype.create_scales = function() { - this.x_scale = d3.scale.ordinal().domain(this.sample_names).rangeRoundBands([0, this.range], 0.1, 0); + Bar_Chart.prototype.create_scales = function(sample_names) { + this.x_scale = d3.scale.ordinal().domain(sample_names).rangeRoundBands([0, this.range], 0.1, 0); return this.y_scale = d3.scale.linear().domain([this.y_min * 0.75, this.y_max]).range([this.plot_height, this.y_buffer]); }; -- cgit v1.2.3