From a224594125a88b75dcebc125e5e4b2394acedebb Mon Sep 17 00:00:00 2001 From: zsloan Date: Tue, 15 Sep 2020 12:42:30 -0500 Subject: Added scroller to trait page and changed sample tables to use it * wqflask/wqflask/templates/show_trait.html - Imported scroller (from the Google cdn temporarily for testing) and activated it for the sample tables, as well as disabled options that conflicted with it (like paging: false) --- wqflask/wqflask/templates/show_trait.html | 35 +++++++++++++++---------------- 1 file changed, 17 insertions(+), 18 deletions(-) (limited to 'wqflask') diff --git a/wqflask/wqflask/templates/show_trait.html b/wqflask/wqflask/templates/show_trait.html index 56df2049..fc65c5b1 100644 --- a/wqflask/wqflask/templates/show_trait.html +++ b/wqflask/wqflask/templates/show_trait.html @@ -150,6 +150,7 @@ + @@ -352,16 +353,15 @@ 'order': [[1, "asc"]], 'sDom': "Ztr", 'autoWidth': true, - 'deferRender': true, - 'paging': false, 'orderClasses': true, - 'scrollY': "600px", - 'scrollCollapse': false, - 'processing': true, - 'language': { - 'loadingRecords': ' ', - 'processing': 'Loading...' - } + "scrollY": "50vh", + 'scroller': true, + 'scrollCollapse': true + // 'processing': true, + // 'language': { + // 'loadingRecords': ' ', + // 'processing': 'Loading...' + // } } ); primary_table.on( 'order.dt search.dt draw.dt', function () { @@ -502,16 +502,15 @@ 'order': [[1, "asc"]], 'sDom': "Ztr", 'autoWidth': true, - 'deferRender': true, - 'paging': false, 'orderClasses': true, - 'scrollY': "600px", - 'scrollCollapse': false, - 'processing': true, - 'language': { - 'loadingRecords': ' ', - 'processing': 'Loading...' - } + "scrollY": "50vh", + 'scroller': true, + 'scrollCollapse': true + // 'processing': true, + // 'language': { + // 'loadingRecords': ' ', + // 'processing': 'Loading...' + // } } ); $('#other_searchbox').on( 'keyup', function () { -- cgit v1.2.3 From 07959c86e235072eaa46974ada5ea9c0432f49e7 Mon Sep 17 00:00:00 2001 From: zsloan Date: Wed, 16 Sep 2020 13:54:11 -0500 Subject: Applied PEP8 and removed commented out code --- wqflask/wqflask/show_trait/SampleList.py | 67 +++++--------------------------- 1 file changed, 10 insertions(+), 57 deletions(-) (limited to 'wqflask') diff --git a/wqflask/wqflask/show_trait/SampleList.py b/wqflask/wqflask/show_trait/SampleList.py index ad78ebcc..10157558 100644 --- a/wqflask/wqflask/show_trait/SampleList.py +++ b/wqflask/wqflask/show_trait/SampleList.py @@ -1,21 +1,20 @@ from __future__ import absolute_import, print_function, division -from flask import Flask, g - -from base import webqtlCaseData -from utility import webqtlUtil, Plot, Bunch -from base.trait import GeneralTrait +import itertools import numpy as np -from scipy import stats +from flask import Flask, g from pprint import pformat as pf +from scipy import stats -import simplejson as json - -import itertools +from base import webqtlCaseData +from base.trait import GeneralTrait +from utility import logger +from utility import webqtlUtil +from utility import Plot +from utility import Bunch -import utility.logger -logger = utility.logger.getLogger(__name__ ) +logger = logger.getLogger(__name__ ) class SampleList(object): def __init__(self, @@ -35,8 +34,6 @@ class SampleList(object): self.get_attributes() - #self.sample_qnorm = get_transform_vals(self.dataset, this_trait) - if self.this_trait and self.dataset: self.get_extra_attribute_values() @@ -70,8 +67,6 @@ class SampleList(object): self.sample_list.append(sample) - #logger.debug("attribute vals are", pf(self.sample_attribute_values)) - self.do_outliers() def __repr__(self): @@ -156,48 +151,6 @@ class SampleList(object): return any(sample.variance for sample in self.sample_list) -# def get_transform_vals(dataset, trait): -# es = get_elasticsearch_connection(for_user=False) - -# logger.info("DATASET NAME:", dataset.name) - -# query = '{"bool": {"must": [{"match": {"name": "%s"}}, {"match": {"dataset": "%s"}}]}}' % (trait.name, dataset.name) - -# es_body = { -# "query": { -# "bool": { -# "must": [ -# { -# "match": { -# "name": "%s" % (trait.name) -# } -# }, -# { -# "match": { -# "dataset": "%s" % (dataset.name) -# } -# } -# ] -# } -# } -# } - -# response = es.search( index = "traits", doc_type = "trait", body = es_body ) -# logger.info("THE RESPONSE:", response) -# results = response['hits']['hits'] - -# if len(results) > 0: -# samples = results[0]['_source']['samples'] - -# sample_dict = {} -# for sample in samples: -# sample_dict[sample['name']] = sample['qnorm'] - -# #logger.info("SAMPLE DICT:", sample_dict) -# return sample_dict -# else: -# return None - def natural_sort_key(x): """Get expected results when using as a key for sort - ints or strings are sorted properly""" -- cgit v1.2.3 From 64675d43272625464ef49e657dd9f61d8459e074 Mon Sep 17 00:00:00 2001 From: zsloan Date: Wed, 16 Sep 2020 14:09:46 -0500 Subject: Changed se_exists to a property so the SampleList instance can include that when converted to a dict (which is needed to use it in the javascript) * wqflask/wqflask/show_trait/SampleList.py - Directly set se_exists as a property of SampleList instead of requiring a method be called; I could have set self.se_exists by calling the se_exists method, but that would have resulted in the convoluted line "self.se_exists = self.se_exists()" and the se_exists method only consisted of one line anyways --- wqflask/wqflask/show_trait/SampleList.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'wqflask') diff --git a/wqflask/wqflask/show_trait/SampleList.py b/wqflask/wqflask/show_trait/SampleList.py index 10157558..9e5be0e8 100644 --- a/wqflask/wqflask/show_trait/SampleList.py +++ b/wqflask/wqflask/show_trait/SampleList.py @@ -67,6 +67,7 @@ class SampleList(object): self.sample_list.append(sample) + self.se_exists = any(sample.variance for sample in self.sample_list) self.do_outliers() def __repr__(self): @@ -146,11 +147,6 @@ class SampleList(object): attribute_values[self.attributes[item.Id].name] = attribute_value self.sample_attribute_values[sample_name] = attribute_values - def se_exists(self): - """Returns true if SE values exist for any samples, otherwise false""" - - return any(sample.variance for sample in self.sample_list) - def natural_sort_key(x): """Get expected results when using as a key for sort - ints or strings are sorted properly""" -- cgit v1.2.3 From 870ddf6075f38c1ce5e7bf8f90742f06fe7d4805 Mon Sep 17 00:00:00 2001 From: zsloan Date: Wed, 16 Sep 2020 14:15:46 -0500 Subject: Changed references to se_exists to just get it as a property of SampleList instead of calling the method * wqflask/wqflask/show_trait/show_trait.py - see above * wqflask/wqflask/templates/show_trait.html - see above + removed some commented out code --- wqflask/wqflask/show_trait/show_trait.py | 2 +- wqflask/wqflask/templates/show_trait.html | 20 +++++--------------- 2 files changed, 6 insertions(+), 16 deletions(-) (limited to 'wqflask') diff --git a/wqflask/wqflask/show_trait/show_trait.py b/wqflask/wqflask/show_trait/show_trait.py index f188fd9d..bc24098a 100644 --- a/wqflask/wqflask/show_trait/show_trait.py +++ b/wqflask/wqflask/show_trait/show_trait.py @@ -545,7 +545,7 @@ def get_table_widths(sample_groups, has_num_cases=False): stats_table_width = 450 trait_table_width = 380 - if sample_groups[0].se_exists(): + if sample_groups[0].se_exists: trait_table_width += 80 if has_num_cases: trait_table_width += 80 diff --git a/wqflask/wqflask/templates/show_trait.html b/wqflask/wqflask/templates/show_trait.html index fc65c5b1..b7bffd79 100644 --- a/wqflask/wqflask/templates/show_trait.html +++ b/wqflask/wqflask/templates/show_trait.html @@ -211,7 +211,7 @@ //ZS: This variable is just created to get the column position of the first case attribute, since it's needed to set the row classes in createdRow for the DataTable {% if sample_groups[0].attributes|length > 0 %} - {% if sample_groups[0].se_exists() %} + {% if sample_groups[0].se_exists %} {% if has_num_cases %} attribute_start_pos = 6 {% else %} @@ -246,7 +246,7 @@ $('td', row).eq(2).addClass("column_name-Sample") $('td', row).eq(3).addClass("column_name-Value") $('td', row).eq(3).attr("style", "text-align: right; padding-top: 2px; padding-bottom: 0px;"); - {% if sample_groups[0].se_exists() %} + {% if sample_groups[0].se_exists %} $('td', row).eq(4).attr("align", "center"); $('td', row).eq(4).attr("style", "padding-left: 2px; padding-right: 2px;"); $('td', row).eq(5).addClass("column_name-SE") @@ -301,7 +301,7 @@ return '' } } - }{% if sample_groups[0].se_exists() %}, + }{% if sample_groups[0].se_exists %}, { 'bSortable': false, 'type': "natural", @@ -357,11 +357,6 @@ "scrollY": "50vh", 'scroller': true, 'scrollCollapse': true - // 'processing': true, - // 'language': { - // 'loadingRecords': ' ', - // 'processing': 'Loading...' - // } } ); primary_table.on( 'order.dt search.dt draw.dt', function () { @@ -395,7 +390,7 @@ $('td', row).eq(2).addClass("column_name-Sample") $('td', row).eq(3).addClass("column_name-Value") $('td', row).eq(3).attr("style", "text-align: right; padding-top: 2px; padding-bottom: 0px;"); - {% if sample_groups[1].se_exists() %} + {% if sample_groups[1].se_exists %} $('td', row).eq(4).attr("align", "center"); $('td', row).eq(4).attr("style", "padding-left: 2px; padding-right: 2px;"); $('td', row).eq(5).addClass("column_name-SE") @@ -450,7 +445,7 @@ return '' } } - }{% if sample_groups[1].se_exists() %}, + }{% if sample_groups[1].se_exists %}, { 'bSortable': false, 'type': "natural", @@ -506,11 +501,6 @@ "scrollY": "50vh", 'scroller': true, 'scrollCollapse': true - // 'processing': true, - // 'language': { - // 'loadingRecords': ' ', - // 'processing': 'Loading...' - // } } ); $('#other_searchbox').on( 'keyup', function () { -- cgit v1.2.3 From f376eaca55643972943fc6d313a3ca00b32d66ae Mon Sep 17 00:00:00 2001 From: zsloan Date: Fri, 18 Sep 2020 14:40:41 -0500 Subject: Made a bunch of changes to move trait page DataTables initialization to a separate file (initialize_show_trait_tables.js). The biggest complication was getting the order of attributes in the rows to sync with the order of atribute namees in the column headers. Previously this logic was all in the template. * wqflask/base/webqtlCaseData.py - added attribute first_attr_col as a very awkward solution to passing the column position into the column render function in situations where there are case attribute columns (which can be variable in number) * wqflask/wqflask/show_trait/show_trait.py - Replace "attribute_names" in js_data with "attributes" (which allows the JS access to more information) and also pass new se_exists and has_num_cases variables with js_data, so the javascript has access to whether or not those columns exist in the table * wqflask/wqflask/static/new/javascript/show_trait.js - Change case attribute-related logic to use js_data.attributes instead of js_data.attribute_names * wqflask/wqflask/templates/show_trait.html - Removed table initialization from template * wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js - new file that initializes tables and reproduces what the template logic used to do with JS logic --- wqflask/base/webqtlCaseData.py | 11 + wqflask/wqflask/show_trait/show_trait.py | 16 +- .../new/javascript/initialize_show_trait_tables.js | 222 ++++++++++++++++ .../wqflask/static/new/javascript/show_trait.js | 24 +- wqflask/wqflask/templates/show_trait.html | 284 +-------------------- 5 files changed, 261 insertions(+), 296 deletions(-) create mode 100644 wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js (limited to 'wqflask') diff --git a/wqflask/base/webqtlCaseData.py b/wqflask/base/webqtlCaseData.py index 2844cedd..3cf2d80d 100644 --- a/wqflask/base/webqtlCaseData.py +++ b/wqflask/base/webqtlCaseData.py @@ -41,6 +41,8 @@ class webqtlCaseData: self.this_id = None # Set a sane default (can't be just "id" cause that's a reserved word) self.outlier = None # Not set to True/False until later + self.first_attr_col = self.get_first_attr_col() + def __repr__(self): case_data_string = " " if self.value is not None: @@ -79,3 +81,12 @@ class webqtlCaseData: if self.num_cases is not None: return "%s" % self.num_cases return "x" + + def get_first_attr_col(self): + col_num = 4 + if self.variance is not None: + col_num += 2 + if self.num_cases is not None: + col_num += 1 + + return col_num \ No newline at end of file diff --git a/wqflask/wqflask/show_trait/show_trait.py b/wqflask/wqflask/show_trait/show_trait.py index bc24098a..f1bd6f27 100644 --- a/wqflask/wqflask/show_trait/show_trait.py +++ b/wqflask/wqflask/show_trait/show_trait.py @@ -275,7 +275,9 @@ class ShowTrait(object): data_scale = self.dataset.data_scale, sample_group_types = self.sample_group_types, sample_lists = sample_lists, - attribute_names = self.sample_groups[0].attributes, + se_exists = self.sample_groups[0].se_exists, + has_num_cases = self.has_num_cases, + attributes = self.sample_groups[0].attributes, categorical_vars = ",".join(categorical_var_list), num_values = self.num_values, qnorm_values = self.qnorm_vals, @@ -454,6 +456,7 @@ class ShowTrait(object): self.primary_sample_names = primary_sample_names self.dataset.group.allsamples = all_samples_ordered + def quantile_normalize_vals(sample_groups): def normf(trait_vals): ranked_vals = ss.rankdata(trait_vals) @@ -492,6 +495,7 @@ def quantile_normalize_vals(sample_groups): return qnorm_by_group + def get_z_scores(sample_groups): zscore_by_group = [] for sample_type in sample_groups: @@ -516,6 +520,7 @@ def get_z_scores(sample_groups): return zscore_by_group + def get_nearest_marker(this_trait, this_db): this_chr = this_trait.locus_chr logger.debug("this_chr:", this_chr) @@ -539,6 +544,7 @@ def get_nearest_marker(this_trait, this_db): else: return result[0][0] + def get_table_widths(sample_groups, has_num_cases=False): stats_table_width = 250 if len(sample_groups) > 1: @@ -555,6 +561,7 @@ def get_table_widths(sample_groups, has_num_cases=False): return stats_table_width, trait_table_width + def has_num_cases(this_trait): has_n = False if this_trait.dataset.type != "ProbeSet" and this_trait.dataset.type != "Geno": @@ -565,6 +572,7 @@ def has_num_cases(this_trait): return has_n + def get_trait_units(this_trait): unit_type = "" inside_brackets = False @@ -584,6 +592,7 @@ def get_trait_units(this_trait): return unit_type + def check_if_attr_exists(the_trait, id_type): if hasattr(the_trait, id_type): if getattr(the_trait, id_type) == None or getattr(the_trait, id_type) == "": @@ -593,6 +602,7 @@ def check_if_attr_exists(the_trait, id_type): else: return False + def get_ncbi_summary(this_trait): if check_if_attr_exists(this_trait, 'geneid'): #ZS: Need to switch this try/except to something that checks the output later @@ -605,6 +615,7 @@ def get_ncbi_summary(this_trait): else: return None + def get_categorical_variables(this_trait, sample_list): categorical_var_list = [] @@ -623,6 +634,7 @@ def get_categorical_variables(this_trait, sample_list): return categorical_var_list + def get_genotype_scales(genofiles): geno_scales = {} if type(genofiles) is list: @@ -634,6 +646,7 @@ def get_genotype_scales(genofiles): return geno_scales + def get_scales_from_genofile(file_location): geno_path = locate_ignore_error(file_location, 'genotype') @@ -686,6 +699,7 @@ def get_scales_from_genofile(file_location): if i > first_marker_line + 10: break + #ZS: This assumes that both won't be all zero, since if that's the case mapping shouldn't be an option to begin with if mb_all_zero: return [["morgan", "cM"]] diff --git a/wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js b/wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js new file mode 100644 index 00000000..41ddc088 --- /dev/null +++ b/wqflask/wqflask/static/new/javascript/initialize_show_trait_tables.js @@ -0,0 +1,222 @@ +// ZS: This file initializes the tables for the show_trait page + +// ZS: This variable is just created to get the column position of the first case attribute (if case attributes exist), since it's needed to set the row classes in createdRow for the DataTable +attribute_start_pos = 3 +if (js_data.se_exists === "true") { + attribute_start_pos += 2 +} +if (js_data.has_num_cases === "true") { + attribute_start_post += 1 +} + +build_columns = function() { + let column_list = [ + { + 'data': null, + 'orderDataType': "dom-checkbox", + 'searchable' : false, + 'render': function(data, type, row, meta) { + return '' + } + }, + { + 'title': "ID", + 'type': "natural", + 'searchable' : false, + 'data': "this_id" + }, + { + 'title': "Sample", + 'type': "natural", + 'data': null, + 'render': function(data, type, row, meta) { + return '' + data.name + '' + } + }, + { + 'title': "
Value
", + 'orderDataType': "dom-input", + 'type': "cust-txt", + 'data': null, + 'render': function(data, type, row, meta) { + if (data.value == null) { + return '' + } else { + return '' + } + } + } + ]; + + if (js_data.se_exists === "true") { + column_list.push( + { + 'bSortable': false, + 'type': "natural", + 'data': null, + 'searchable' : false, + 'render': function(data, type, row, meta) { + return '±' + } + }, + { + 'title': "
SE
", + 'orderDataType': "dom-input", + 'type': "cust-txt", + 'data': null, + 'render': function(data, type, row, meta) { + if (data.variance == null) { + return '' + } else { + return '' + } + } + } + ); + } + + if (js_data.has_num_cases === "true") { + column_list.push( + { + 'title': "
N
", + 'orderDataType': "dom-input", + 'type': "cust-txt", + 'data': null, + 'render': function(data, type, row, meta) { + if (data.num_cases == null || data.num_cases == undefined) { + return '' + } else { + return '' + } + } + } + ); + } + + attr_keys = Object.keys(js_data.attributes).sort((a, b) => (js_data.attributes[a].name > js_data.attributes[b].name) ? 1 : -1) + for (i = 0; i < attr_keys.length; i++){ + column_list.push( + { + 'title': "
" + js_data.attributes[attr_keys[i]].name + "
", + 'type': "natural", + 'data': null, + 'render': function(data, type, row, meta) { + attr_name = Object.keys(data.extra_attributes).sort((a, b) => (a > b) ? 1 : -1)[meta.col - data.first_attr_col] + if (attr_name != null && attr_name != undefined){ + return data.extra_attributes[attr_name] + } else { + return "" + } + } + } + ) + } + + return column_list +} + +var primary_table = $('#samples_primary').DataTable( { + 'initComplete': function(settings, json) { + $('.edit_sample_value').change(function() { + edit_data_change(); + }); + }, + 'createdRow': function ( row, data, index ) { + $(row).attr('id', "Primary_" + data.this_id) + $(row).addClass("value_se"); + if (data.outlier) { + $(row).addClass("outlier"); + } + $('td', row).eq(1).addClass("column_name-Index") + $('td', row).eq(2).addClass("column_name-Sample") + $('td', row).eq(3).addClass("column_name-Value") + if (js_data.se_exists === "true") { + $('td', row).eq(5).addClass("column_name-SE") + if (js_data.has_num_cases === "true") { + $('td', row).eq(6).addClass("column_name-num_cases") + } else { + if (js_data.has_num_cases === "true") { + $('td', row).eq(4).addClass("column_name-num_cases") + } + } + } else { + if (js_data.has_num_cases === "true") { + $('td', row).eq(4).addClass("column_name-num_cases") + } + } + + sorted_key_list = Object.keys(js_data.attributes).sort() + for (i=0; i < sorted_key_list.length; i++) { + $('td', row).eq(attribute_start_pos + i).addClass("column_name-" + js_data.attributes[sorted_key_list[i]].name) + $('td', row).eq(attribute_start_pos + i).attr("style", "text-align: " + js_data.attributes[sorted_key_list[i]].alignment + "; padding-top: 2px; padding-bottom: 0px;") + } + }, + 'data': js_data['sample_lists'][0], + 'columns': build_columns(), + 'order': [[1, "asc"]], + 'sDom': "Ztr", + 'autoWidth': true, + 'orderClasses': true, + "scrollY": "50vh", + 'scroller': true, + 'scrollCollapse': true +} ); + +primary_table.on( 'order.dt search.dt draw.dt', function () { + primary_table.column(1, {search:'applied', order:'applied'}).nodes().each( function (cell, i) { + cell.innerHTML = i+1; + } ); +} ).draw(); + +$('#primary_searchbox').on( 'keyup', function () { + primary_table.search($(this).val()).draw(); +} ); + +if (js_data.sample_lists.length > 1){ + var other_table = $('#samples_other').DataTable( { + 'initComplete': function(settings, json) { + $('.edit_sample_value').change(function() { + edit_data_change(); + }); + }, + 'createdRow': function ( row, data, index ) { + $(row).attr('id', "Primary_" + data.this_id) + $(row).addClass("value_se"); + if (data.outlier) { + $(row).addClass("outlier"); + } + $('td', row).eq(1).addClass("column_name-Index") + $('td', row).eq(2).addClass("column_name-Sample") + $('td', row).eq(3).addClass("column_name-Value") + if (js_data.se_exists === "true") { + $('td', row).eq(5).addClass("column_name-SE") + if (js_data.has_num_cases === "true") { + $('td', row).eq(6).addClass("column_name-num_cases") + } else { + if (js_data.has_num_cases === "true") { + $('td', row).eq(4).addClass("column_name-num_cases") + } + } + } else { + if (js_data.has_num_cases === "true") { + $('td', row).eq(4).addClass("column_name-num_cases") + } + } + + sorted_key_list = Object.keys(js_data.attributes).sort() + for (i=0; i < sorted_key_list.length; i++) { + $('td', row).eq(attribute_start_pos + i).addClass("column_name-" + js_data.attributes[sorted_key_list[i]].name) + $('td', row).eq(attribute_start_pos + i).attr("style", "text-align: " + js_data.attributes[sorted_key_list[i]].alignment + "; padding-top: 2px; padding-bottom: 0px;") + } + }, + 'data': js_data['sample_lists'][1], + 'columns': build_columns(), + 'order': [[1, "asc"]], + 'sDom': "Ztr", + 'autoWidth': true, + 'orderClasses': true, + "scrollY": "50vh", + 'scroller': true, + 'scrollCollapse': true + } ); +} \ No newline at end of file diff --git a/wqflask/wqflask/static/new/javascript/show_trait.js b/wqflask/wqflask/static/new/javascript/show_trait.js index c0784073..0b5ae6f9 100644 --- a/wqflask/wqflask/static/new/javascript/show_trait.js +++ b/wqflask/wqflask/static/new/javascript/show_trait.js @@ -538,10 +538,9 @@ populate_sample_attributes_values_dropdown = function() { var attribute_info, key, sample_attributes, selected_attribute, value, _i, _len, _ref, _ref1, _results; $('#attribute_values').empty(); sample_attributes = {}; - _ref = js_data.attribute_names; - for (key in _ref) { - if (!__hasProp.call(_ref, key)) continue; - attribute_info = _ref[key]; + attr_keys = Object.keys(js_data.attributes).sort(); + for (i=0; i < attr_keys.length; i++) { + attribute_info = js_data.attributes[attr_keys[i]]; sample_attributes[attribute_info.name] = attribute_info.distinct_values; } selected_attribute = $('#exclude_menu').val().replace("_", " "); @@ -549,13 +548,15 @@ populate_sample_attributes_values_dropdown = function() { _results = []; for (_i = 0, _len = _ref1.length; _i < _len; _i++) { value = _ref1[_i]; - _results.push($(create_value_dropdown(value)).appendTo($('#attribute_values'))); + if (value != ""){ + _results.push($(create_value_dropdown(value)).appendTo($('#attribute_values'))); + } } return _results; }; -if (Object.keys(js_data.attribute_names).length > 0) { - populate_sample_attributes_values_dropdown(); -} + +populate_sample_attributes_values_dropdown(); + $('#exclude_menu').change(populate_sample_attributes_values_dropdown); block_by_attribute_value = function() { var attribute_name, cell_class, exclude_by_value; @@ -859,10 +860,9 @@ get_sample_table_data = function(table_name) { if ($(element).find('.edit_sample_num_cases').length > 0) { row_data.num_cases = $(element).find('.edit_sample_num_cases').val(); } - _ref = js_data.attribute_names; - for (key in _ref) { - if (!__hasProp.call(_ref, key)) continue; - attribute_info = _ref[key]; + attr_keys = Object.keys(js_data.attributes).sort() + for (i=0; i < attr_keys.length; i++) { + attribute_info = js_data.attributes[attr_keys[i]]; row_data[attribute_info.name] = $.trim($(element).find('.column_name-' + attribute_info.name.replace(" ", "_").replace("/", "\\/")).text()); } return samples.push(row_data); diff --git a/wqflask/wqflask/templates/show_trait.html b/wqflask/wqflask/templates/show_trait.html index b7bffd79..0a79ad48 100644 --- a/wqflask/wqflask/templates/show_trait.html +++ b/wqflask/wqflask/templates/show_trait.html @@ -153,6 +153,7 @@ + - - - - + + + + +