about summary refs log tree commit diff
path: root/gn2/wqflask/static/new/javascript/show_trait.js
diff options
context:
space:
mode:
Diffstat (limited to 'gn2/wqflask/static/new/javascript/show_trait.js')
-rw-r--r--gn2/wqflask/static/new/javascript/show_trait.js1677
1 files changed, 1677 insertions, 0 deletions
diff --git a/gn2/wqflask/static/new/javascript/show_trait.js b/gn2/wqflask/static/new/javascript/show_trait.js
new file mode 100644
index 00000000..c5214947
--- /dev/null
+++ b/gn2/wqflask/static/new/javascript/show_trait.js
@@ -0,0 +1,1677 @@
+var statTableRows, isNumber,
+  __hasProp = {}.hasOwnProperty,
+  __slice = [].slice;
+
+isNumber = function(o) {
+  return !isNaN((o - 0) && o !== null);
+};
+
+statTableRows = [
+  {
+    vn: "n_of_samples",
+    pretty: "N of Samples",
+    digits: 0
+  }, {
+    vn: "mean",
+    pretty: "Mean",
+    digits: 3
+  }, {
+    vn: "median",
+    pretty: "Median",
+    digits: 3
+  }, {
+    vn: "std_error",
+    pretty: "Standard Error (SE)",
+    digits: 3
+  }, {
+    vn: "std_dev",
+    pretty: "Standard Deviation (SD)",
+    digits: 3
+  }, {
+    vn: "min",
+    pretty: "Minimum",
+    digits: 3
+  }, {
+    vn: "max",
+    pretty: "Maximum",
+    digits: 3
+  }
+]
+
+if (js_data.dataset_type == "ProbeSet"){
+  if (js_data.data_scale == "linear_positive" || js_data.data_scale == "log2") {
+    statTableRows.push({
+                           vn: "range",
+                           pretty: "Range (log2)",
+                           digits: 3
+                         })
+  } else {
+    statTableRows.push({
+                           vn: "range",
+                           pretty: "Range",
+                           digits: 3
+                         })
+  }
+} else {
+  statTableRows.push({
+                       vn: "range",
+                       pretty: "Range",
+                       digits: 3
+                     })
+}
+
+statTableRows.push(
+  {
+    vn: "range_fold",
+    pretty: "Range (fold)",
+    digits: 3
+  }, {
+    vn: "interquartile",
+    pretty: "<font color='black'>Interquartile Range</font>",
+    url: "http://www.genenetwork.org/glossary.html#Interquartile",
+    digits: 3
+  }, {
+    vn: "skewness",
+    pretty: "Skewness",
+    url: "https://en.wikipedia.org/wiki/Skewness",
+    digits: 3
+  }, {
+    vn: "kurtosis",
+    pretty: "Excess Kurtosis",
+    url: "https://en.wikipedia.org/wiki/Kurtosis",
+    digits: 3
+  }
+);
+
+toggleDescription = function() {
+  if ($('.truncDesc').is(':visible')) {
+    $('.truncDesc').hide();
+    $('.fullDesc').show();
+  } else {
+    $('.truncDesc').show();
+    $('.fullDesc').hide();
+  }
+}
+
+add = function() {
+  var trait;
+  trait = $("input[name=trait_hmac]").val();
+  return $.colorbox({
+    href: "/collections/add",
+    data: {
+      "traits": trait
+    }
+  });
+};
+$('#add_to_collection').click(add);
+
+sampleLists = js_data.sample_lists;
+sampleGroupTypes = js_data.sample_group_types;
+
+$(".select_covariates").click(function () {
+  openCovariateSelection();
+});
+
+$(".remove_covariates").click(function () {
+  $(".selected-covariates option:selected").each(function() {
+    this_val = $(this).val();
+    $(".selected-covariates option").each(function(){
+      if ($(this).val() == this_val){
+        $(this).remove();
+      }
+    })
+    cofactor_count = $(".selected-covariates:first option").length
+    if (cofactor_count > 2 && cofactor_count < 11){
+      $(".selected-covariates").each(function() {
+        $(this).attr("size", $(".selected-covariates:first option").length)
+      });
+    } else if (cofactor_count > 10) {
+      $(".selected-covariates").each(function() {
+        $(this).attr("size", 10)
+      });
+    } else {
+      $(".selected-covariates").each(function() {
+        $(this).attr("size", 2)
+      });
+    }
+    if (cofactor_count == 0){
+      $(".selected-covariates").each(function() {
+        $(this).append($("<option/>", {
+          value: "",
+          text: "No covariates selected"
+        }))
+      })
+    }
+  });
+
+  covariates_list = [];
+  $(".selected-covariates:first option").each(function() {
+    covariates_list.push($(this).val());
+  })
+  $("input[name=covariates]").val(covariates_list.join(","))
+});
+
+$(".remove_all_covariates").click(function() {
+  $(".selected-covariates option").each(function() {
+    $(this).remove();
+  });
+  $(".selected-covariates").attr("size", 2)
+  $("input[name=covariates]").val("");
+})
+
+openTraitSelection = function() {
+  return $('#collections_holder').load('/collections/list?color_by_trait #collections_list', (function(_this) {
+    return function() {
+      $.colorbox({
+        inline: true,
+        href: "#collections_holder",
+        onComplete: function(){
+            $.getScript("/static/new/javascript/get_traits_from_collection.js");
+        }
+      });
+      return $('a.collection_name').attr('onClick', 'return false');
+    };
+  })(this));
+};
+openCovariateSelection = function() {
+  return $('#collections_holder').load('/collections/list #collections_list', (function(_this) {
+    return function() {
+      $.colorbox({
+        inline: true,
+        href: "#collections_holder",
+        width: "1000px",
+        height: "700px",
+        onComplete: function(){
+            $.getScript("/static/new/javascript/get_covariates_from_collection.js");
+        }
+      });
+      return $('a.collection_name').attr('onClick', 'return false');
+    };
+  })(this));
+};
+hideTabs = function(start) {
+  var x, _i, _results;
+  _results = [];
+  for (x = _i = start; start <= 10 ? _i <= 10 : _i >= 10; x = start <= 10 ? ++_i : --_i) {
+    _results.push($("#stats_tabs" + x).hide());
+  }
+  return _results;
+};
+statsMdpChange = function() {
+  var selected;
+  selected = $(this).val();
+  hideTabs(0);
+  return $("#stats_tabs" + selected).show();
+};
+changeStatsValue = function(sample_sets, category, value_type, decimal_places, effects) {
+  var current_value, id, in_box, the_value, title_value;
+  id = "#" + processId(category, value_type);
+  in_box = $(id).html;
+  current_value = parseFloat($(in_box)).toFixed(decimal_places);
+  the_value = sample_sets[category][value_type]();
+  if (decimal_places > 0) {
+    title_value = the_value.toFixed(decimal_places * 2);
+    the_value = the_value.toFixed(decimal_places);
+  } else {
+    title_value = null;
+  }
+  if (the_value !== current_value) {
+    if (effects) {
+      $(id).html(the_value).effect("highlight");
+    } else {
+      $(id).html(the_value);
+    }
+  }
+  if (title_value) {
+    return $(id).attr('title', title_value);
+  }
+};
+updateStatValues = function(sample_sets) {
+  var category, row, show_effects, _i, _len, _ref, _results;
+  show_effects = $(".tab-pane.active").attr("id") === "stats_tab";
+  _ref = ['samples_primary', 'samples_other', 'samples_all'];
+  _results = [];
+  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+    category = _ref[_i];
+    _results.push((function() {
+      var _j, _len1, _results1;
+      _results1 = [];
+      for (_j = 0, _len1 = statTableRows.length; _j < _len1; _j++) {
+        row = statTableRows[_j];
+        _results1.push(changeStatsValue(sample_sets, category, row.vn, row.digits, show_effects));
+      }
+      return _results1;
+    })());
+  }
+  return _results;
+};
+
+updateHistogram_width = function() {
+  num_bins = $('#histogram').find('g.trace.bars').find('g.point').length
+
+  if (num_bins < 10) {
+    width_update = {
+      width: 400
+    }
+
+    Plotly.relayout('histogram', width_update)
+  }
+}
+
+updateHistogram = function() {
+  var x;
+  var _i, _len, _ref, data;
+  _ref = _.values(root.selected_samples[root.stats_group]);
+  var trait_vals = [];
+  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+    x = _ref[_i];
+    trait_vals.push(x.value);
+  }
+  root.histogram_data[0]['x'] = trait_vals
+
+  if ($('input[name="transform"]').val() != ""){
+    root.histogram_layout['xaxis']['title'] = "<b>" + js_data.unit_type +  " (" + $('input[name="transform"]').val() + ")</b>"
+  } else {
+    root.histogram_layout['xaxis']['title'] = "<b>" + js_data.unit_type + "</b>"
+  }
+
+  Plotly.newPlot('histogram', root.histogram_data, root.histogram_layout, root.modebar_options);
+  updateHistogram_width()
+};
+
+updateBarChart = function() {
+  var x;
+  var _i, _len, _ref, data;
+  _ref = _.values(root.selected_samples[root.stats_group]);
+  names_and_values = []
+  for (i = 0; i < _ref.length; i++){
+      _ref[i]["name"] = Object.keys(root.selected_samples[root.stats_group])[i]
+  }
+  trait_vals = [];
+  trait_vars = [];
+  trait_samples = [];
+
+  function sortFunction(a, b) {
+    if (a.value === b.value) {
+      return 0;
+    }
+    else {
+      return (a.value < b.value) ? -1 : 1;
+    }
+  }
+
+  if (root.bar_sort == "value") {
+    _ref.sort(sortFunction)
+  }
+
+  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+    x = _ref[_i];
+    trait_samples.push(x.name)
+    trait_vals.push(x.value);
+    if (x["variance"] != undefined) {
+      trait_vars.push(x.variance);
+    } else{
+      trait_vars.push(null)
+    }
+  }
+
+  new_chart_range = getBarRange(trait_vals, trait_vars)
+
+  root.bar_layout['yaxis']['range'] = new_chart_range
+
+  if ($('input[name="transform"]').val() != ""){
+    root.bar_layout['yaxis']['title'] = "<b>" + js_data.unit_type +  " (" + $('input[name="transform"]').val() + ")</b>"
+  } else {
+    root.bar_layout['yaxis']['title'] = "<b>" + js_data.unit_type + "</b>"
+  }
+
+  root.bar_data[0]['y'] = trait_vals
+  root.bar_data[0]['error_y'] = {
+    type: 'data',
+    array: trait_vars,
+    visible: root.errors_exist
+  }
+  root.bar_data[0]['x'] = trait_samples
+
+  if (trait_vals.length < 256) {
+    Plotly.newPlot('bar_chart', root.bar_data, root.bar_layout, root.modebar_options);
+  }
+};
+
+updateViolinPlot = function() {
+  var y_value_list = []
+  if (sampleLists.length > 1) {
+    i = 0;
+    for (var sample_group in root.selected_samples){
+      var trait_sample_data = _.values(root.selected_samples[sample_group])
+      var trait_vals = [];
+      for (j = 0, len = trait_sample_data.length; j < len; j++) {
+        this_sample_data = trait_sample_data[j];
+        trait_vals.push(this_sample_data.value);
+      }
+      root.violin_data[i]['y'] = trait_vals
+      i++;
+    }
+  } else {
+    var trait_sample_data = _.values(root.selected_samples['samples_all'])
+    var trait_vals = [];
+    for (j = 0, len = trait_sample_data.length; j < len; j++) {
+      this_sample_data = trait_sample_data[j];
+      trait_vals.push(this_sample_data.value);
+    }
+    root.violin_data[0]['y'] = trait_vals
+  }
+
+  if ($('input[name="transform"]').val() != ""){
+    root.violin_layout['yaxis']['title'] = "<b>" + js_data.unit_type +  " (" + $('input[name="transform"]').val() + ")</b>"
+  } else {
+    root.violin_layout['yaxis']['title'] = "<b>" + js_data.unit_type + "</b>"
+  }
+
+  Plotly.newPlot('violin_plot', root.violin_data, root.violin_layout, root.modebar_options)
+}
+
+
+updateProbPlot = function() {
+  return root.redraw_prob_plot_impl(root.selected_samples, root.prob_plot_group);
+};
+
+makeTable = function() {
+  var header, key, row, row_line, table, the_id, the_rows, value, _i, _len, _ref, _ref1;
+  if (js_data.trait_symbol != null) {
+    header = "<thead><tr><th style=\"color: white; background-color: #369; text-align: center;\" colspan=\"100%\">Trait " + js_data.trait_id + " - " + js_data.trait_symbol + "</th></tr><tr><th style=\"text-align: right; padding-left: 5px;\">Statistic</th>";
+  } else if (js_data.dataset_type == "Geno"){
+    header = "<thead><tr><th style=\"color: white; background-color: #369; text-align: center;\" colspan=\"100%\">Marker " + js_data.trait_id + "</th></tr><tr><th style=\"text-align: right; padding-left: 5px;\">Statistic</th>";
+  } else {
+    header = "<thead><tr><th style=\"color: white; background-color: #369; text-align: center;\" colspan=\"100%\">Trait " + js_data.trait_id + ": " + js_data.short_description + "</th></tr><tr><th style=\"text-align: right; padding-left: 5px;\">Statistic</th>";
+  }
+  _ref = js_data.sample_group_types;
+  for (key in _ref) {
+    if (!__hasProp.call(_ref, key)) continue;
+    value = _ref[key];
+    the_id = processId("column", key);
+    if (Object.keys(_ref).length > 1) {
+        header += "<th id=\"" + the_id + "\" style=\"text-align: right; padding-left: 5px;\">" + value + "</th>";
+    } else {
+        header += "<th id=\"" + the_id + "\" style=\"text-align: right; padding-left: 5px;\">Value</th>";
+    }
+  }
+
+  header += "</thead>";
+  the_rows = "<tbody>";
+  for (_i = 0, _len = statTableRows.length; _i < _len; _i++) {
+    row = statTableRows[_i];
+    if ((row.vn == "range_fold") && js_data.dataset_type == "Publish"){
+        continue;
+    }
+    row_line = "<tr>";
+    if (row.url != null) {
+      row_line += "<td id=\"" + row.vn + "\" align=\"right\"><a href=\"" + row.url + "\" style=\"color: #0000EE;\">" + row.pretty + "</a></td>";
+    } else {
+      row_line += "<td id=\"" + row.vn + "\" align=\"right\">" + row.pretty + "</td>";
+    }
+    _ref1 = js_data.sample_group_types;
+    for (key in _ref1) {
+      if (!__hasProp.call(_ref1, key)) continue;
+      value = _ref1[key];
+      the_id = processId(key, row.vn);
+      row_line += "<td id=\"" + the_id + "\" align=\"right\">N/A</td>";
+    }
+    row_line += "</tr>";
+    the_rows += row_line;
+  }
+  the_rows += "</tbody>";
+  table = header + the_rows;
+  return $("#stats_table").append(table);
+};
+processId = function() {
+  var processed, value, values, _i, _len;
+  values = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
+
+  /* Make an id or a class valid javascript by, for example, eliminating spaces */
+  processed = "";
+  for (_i = 0, _len = values.length; _i < _len; _i++) {
+    value = values[_i];
+    value = value.replace(" ", "_");
+    if (processed.length) {
+      processed += "-";
+    }
+    processed += value;
+  }
+  return processed;
+};
+
+fetchSampleValues = function() {
+  // This is meant to fetch all sample values using DataTables API, since they can't all be submitted with the form when using Scroller (and this should also be faster)
+  sample_val_dict = {};
+
+  table = 'samples_primary';
+  if ($('#' + table).length){
+    tableApi = $('#' + table).DataTable();
+    val_nodes = tableApi.column(3).nodes().to$();
+    for (_j = 0; _j < val_nodes.length; _j++){
+      sample_name = val_nodes[_j].childNodes[0].name.split(":")[1]
+      sample_val = val_nodes[_j].childNodes[0].value
+      sample_val_dict[sample_name] = sample_val
+    }
+  }
+
+  return sample_val_dict;
+}
+
+editDataChange = function() {
+  var already_seen, sample_sets, table, tables, _i, _j, _len;
+  already_seen = {};
+  sample_sets = {
+    samples_primary: new Stats([]),
+    samples_other: new Stats([]),
+    samples_all: new Stats([])
+  };
+  root.selected_samples = {
+    samples_primary: {},
+    samples_other: {},
+    samples_all: {}
+  };
+
+  tables = ['samples_primary', 'samples_other'];
+  for (_i = 0, _len = tables.length; _i < _len; _i++) {
+    table = tables[_i];
+    if ($('#' + table).length){
+      tableApi = $('#' + table).DataTable();
+      sample_vals = [];
+      name_nodes = tableApi.column(2).nodes().to$();
+      val_nodes = tableApi.column(3).nodes().to$();
+      var_nodes = tableApi.column(5).nodes().to$();
+      for (_j = 0; _j < val_nodes.length; _j++){
+        sample_val = val_nodes[_j].childNodes[0].value
+        sample_name = $.trim(name_nodes[_j].childNodes[0].textContent)
+        if (isNumber(sample_val) && sample_val !== "") {
+          sample_val = parseFloat(sample_val);
+          sample_sets[table].add_value(sample_val);
+          try {
+            sample_var = var_nodes[_j].childNodes[0].value
+            if (isNumber(sample_var)) {
+              sample_var = parseFloat(sample_var)
+            } else {
+              sample_var = null;
+            }
+          } catch {
+            sample_var = null;
+          }
+          sample_dict = {
+            value: sample_val,
+            variance: sample_var
+          }
+          root.selected_samples[table][sample_name] = sample_dict;
+          if (!(sample_name in already_seen)) {
+            sample_sets['samples_all'].add_value(sample_val);
+            root.selected_samples['samples_all'][sample_name] = sample_dict;
+            already_seen[sample_name] = true;
+          }
+        }
+      }
+    }
+
+  }
+
+  updateStatValues(sample_sets);
+
+  if ($('#histogram').hasClass('js-plotly-plot')){
+    updateHistogram();
+  }
+  if ($('#bar_chart').hasClass('js-plotly-plot')){
+    updateBarChart();
+  }
+  if ($('#violin_plot').hasClass('js-plotly-plot')){
+    updateViolinPlot();
+  }
+  if ($('#prob_plot_div').hasClass('js-plotly-plot')){
+    return updateProbPlot();
+  }
+};
+
+showHideOutliers = function() {
+  var label;
+  label = $('#showHideOutliers').val();
+  if (label === "Hide Outliers") {
+    return $('#showHideOutliers').val("Show Outliers");
+  } else if (label === "Show Outliers") {
+    $('#showHideOutliers').val("Hide Outliers");
+    return console.log("Should be now Hide Outliers");
+  }
+};
+
+onCorrMethodChange = function() {
+  var corr_method;
+  corr_method = $('select[name=corr_type]').val();
+  $('.correlation_desc').hide();
+  $('#' + corr_method + "_r_desc").show().effect("highlight");
+  if (corr_method === "lit") {
+    return $("#corr_sample_method").hide();
+  } else {
+    return $("#corr_sample_method").show();
+  }
+};
+$('select[name=corr_type]').change(onCorrMethodChange);
+
+on_dataset_change = function() {
+  let dataset_type = $('select[name=corr_dataset] option:selected').data('type');
+  let location_type = $('select[name=location_type] option:selected').val();
+
+  if (dataset_type == "mrna_assay"){
+    $('#min_expr_filter').show();
+    $('select[name=location_type] option:disabled').prop('disabled', false)
+  }
+  else if (dataset_type == "pheno"){
+    $('#min_expr_filter').show();
+    $('select[name=location_type]>option:eq(0)').prop('disabled', true).attr('selected', false);
+    $('select[name=location_type]>option:eq(1)').prop('disabled', false).attr('selected', true);
+  }
+  else {
+    $('#min_expr_filter').hide();
+    $('select[name=location_type]>option:eq(0)').prop('disabled', false).attr('selected', true);
+    $('select[name=location_type]>option:eq(1)').prop('disabled', true).attr('selected', false);
+  }
+}
+
+$('select[name=corr_dataset]').change(on_dataset_change);
+$('select[name=location_type]').change(on_dataset_change);
+
+submit_special = function(url) {
+  $("input[name=sample_vals]").val(JSON.stringify(fetchSampleValues()))
+  $("#trait_data_form").attr("action", url);
+
+  $("#trait_data_form").submit();
+};
+
+var corrInputList = ['sample_vals', 'corr_type', 'primary_samples', 'trait_id', 'dataset', 'group', 'tool_used', 'form_url', 'corr_sample_method', 'corr_samples_group', 'corr_dataset', 'min_expr',
+                        'corr_return_results', 'location_type', 'loc_chr', 'min_loc_mb', 'max_loc_mb', 'p_range_lower', 'p_range_upper',"use_cache"]
+
+$(".test_corr_compute").on("click", (function(_this) {
+  return function() {
+    $('input[name=tool_used]').val("Correlation");
+    $('input[name=form_url]').val("/test_corr_compute");
+    $('input[name=wanted_inputs]').val(corrInputList.join(","));
+    
+
+    url = "/loading";
+    return submit_special(url);
+  };
+})(this));
+
+$(".corr_compute").on("click", (function(_this) {
+
+    return function() {
+
+
+    $('input[name=tool_used]').val("Correlation");
+    $('input[name=form_url]').val("/corr_compute");
+    $('input[name=wanted_inputs]').val(corrInputList.join(","));
+
+
+    $('input[name=use_cache]').val($('#use_cache').is(":checked") ? "true": "false");
+
+    url = "/loading";
+    return submit_special(url);
+  };
+})(this));
+
+createValueDropdown = function(value) {
+  return "<option val=" + value + ">" + value + "</option>";
+};
+
+populateSampleAttributesValuesDropdown = function() {
+  var attribute_info, key, sample_attributes, selected_attribute, value, _i, _len, _ref, _ref1, _results;
+  $('#attribute_values').empty();
+  sample_attributes = [];
+
+  var attributesAsList = Object.keys(js_data.attributes).map(function(key) {
+    return [key, js_data.attributes[key].id];
+  });
+
+  attributesAsList.sort(function(first, second) {
+    if (second[1] > first[1]){
+      return -1
+    }
+    if (first[1] > second[1]){
+      return 1
+    }
+    return 0
+  });
+
+  for (i=0; i < attributesAsList.length; i++) {
+    attribute_info = js_data.attributes[attributesAsList[i][1]]
+    sample_attributes.push(attribute_info.distinct_values);
+  }
+
+  selected_attribute = $('#exclude_column').val()
+  _ref1 = sample_attributes[selected_attribute - 1];
+  _results = [];
+  for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
+    value = _ref1[_i];
+    if (value != ""){
+      _results.push($(createValueDropdown(value)).appendTo($('#attribute_values')));
+    }
+  }
+  return _results;
+};
+
+if (js_data.categorical_attr_exists == "true"){
+  populateSampleAttributesValuesDropdown();
+}
+
+$('#exclude_column').change(populateSampleAttributesValuesDropdown);
+blockByAttributeValue = function() {
+  var attribute_name, cell_class, exclude_by_value;
+
+  let exclude_group = $('#exclude_by_attr_group').val();
+  let exclude_column = $('#exclude_column').val();
+
+  if (exclude_group === "other") {
+    var tableApi = $('#samples_other').DataTable();
+  } else {
+    var tableApi = $('#samples_primary').DataTable();
+  }
+
+  exclude_by_value = $('#attribute_values').val();
+
+  let val_nodes = tableApi.column(3).nodes().to$();
+  let exclude_val_nodes = tableApi.column(attributeStartPos + parseInt(exclude_column)).nodes().to$();
+
+  for (i = 0; i < exclude_val_nodes.length; i++) {
+    if (exclude_val_nodes[i].hasChildNodes()) {
+      let this_col_value = exclude_val_nodes[i].childNodes[0].data;
+      let this_val_node = val_nodes[i].childNodes[0];
+
+      if (this_col_value == exclude_by_value){
+        this_val_node.value = "x";
+      }
+    }
+  }
+
+  editDataChange();
+};
+$('#exclude_by_attr').click(blockByAttributeValue);
+
+blockByIndex = function() {
+  var end_index, error, index, index_list, index_set, index_string, start_index, _i, _j, _k, _len, _len1, _ref;
+  index_string = $('#remove_samples_field').val();
+  index_list = [];
+  _ref = index_string.split(",");
+  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+    index_set = _ref[_i];
+    if (index_set.indexOf('-') !== -1) {
+      try {
+        start_index = parseInt(index_set.split("-")[0]);
+        end_index = parseInt(index_set.split("-")[1]);
+        for (index = _j = start_index; start_index <= end_index ? _j <= end_index : _j >= end_index; index = start_index <= end_index ? ++_j : --_j) {
+          index_list.push(index);
+        }
+      } catch (_error) {
+        error = _error;
+        alert("Syntax error");
+      }
+    } else {
+      index = parseInt(index_set);
+      index_list.push(index);
+    }
+  }
+
+  let block_group = $('#block_group').val();
+  if (block_group === "other") {
+    tableApi = $('#samples_other').DataTable();
+  } else {
+    tableApi = $('#samples_primary').DataTable();
+  }
+  val_nodes = tableApi.column(3).nodes().to$();
+  for (_k = 0, _len1 = index_list.length; _k < _len1; _k++) {
+    index = index_list[_k];
+    val_nodes[index - 1].childNodes[0].value = "x";
+  }
+};
+
+filter_by_study = function() {
+  let this_study = $('#filter_study').val();
+
+  let study_sample_data = JSON.parse($('input[name=study_samplelists]').val())
+  let filter_samples = study_sample_data[parseInt(this_study)]['samples']
+
+  if ($('#filter_study_group').length){
+    let block_group = $('#filter_study_group').val();
+    if (block_group === "other") {
+      tableApi = $('#samples_other').DataTable();
+    } else {
+      tableApi = $('#samples_primary').DataTable();
+    }
+  }
+
+  let sample_nodes = tableApi.column(2).nodes().to$();
+  let val_nodes = tableApi.column(3).nodes().to$();
+  for (i = 0; i < sample_nodes.length; i++) {
+    this_sample = sample_nodes[i].childNodes[0].innerText;
+    if (!filter_samples.includes(this_sample)){
+      val_nodes[i].childNodes[0].value = "x";
+    }
+  }
+}
+
+filter_by_value = function() {
+  let filter_logic = $('#filter_logic').val();
+  let filter_column = $('#filter_column').val();
+  let filter_value = $('#filter_value').val();
+  let block_group = $('#filter_group').val();
+
+  if (block_group === "other") {
+    var tableApi = $('#samples_other').DataTable();
+  } else {
+    var tableApi = $('#samples_primary').DataTable();
+  }
+
+  let val_nodes = tableApi.column(3).nodes().to$();
+  if (filter_column == "value"){
+    var filter_val_nodes = tableApi.column(3).nodes().to$();
+  }
+  else if (filter_column == "stderr"){
+    var filter_val_nodes = tableApi.column(5).nodes().to$();
+  }
+  else if (!isNaN(filter_column)){
+    var filter_val_nodes = tableApi.column(attributeStartPos + parseInt(filter_column)).nodes().to$();
+  }
+  else {
+    return false
+  }
+
+  for (i = 0; i < filter_val_nodes.length; i++) {
+    if (filter_column == "value" || filter_column == "stderr"){
+      var this_col_value = filter_val_nodes[i].childNodes[0].value;
+    } else {
+      if (filter_val_nodes[i].childNodes[0] !== undefined){
+        var this_col_value = filter_val_nodes[i].innerText;
+      } else {
+        continue
+      }
+    }
+    let this_val_node = val_nodes[i].childNodes[0];
+
+    if(!isNaN(this_col_value) && !isNaN(filter_value)) {
+      if (filter_logic == "greater_than"){
+        if (parseFloat(this_col_value) <= parseFloat(filter_value)){
+          this_val_node.value = "x";
+        }
+      }
+      else if (filter_logic == "less_than"){
+        if (parseFloat(this_col_value) >= parseFloat(filter_value)){
+          this_val_node.value = "x";
+        }
+      }
+      else if (filter_logic == "greater_or_equal"){
+        if (parseFloat(this_col_value) < parseFloat(filter_value)){
+          this_val_node.value = "x";
+        }
+      }
+      else if (filter_logic == "less_or_equal"){
+        if (parseFloat(this_col_value) > parseFloat(filter_value)){
+          this_val_node.value = "x";
+        }
+      }
+    }
+  }
+};
+
+hideNoValue_filter = function( settings, data, dataIndex ) {
+  this_value = tableApi.column(3).nodes().to$()[dataIndex].childNodes[0].value;
+  if (this_value == "x"){
+    return false
+  } else {
+    return true
+  }
+}
+
+hideNoValue = function() {
+  tables = ['samples_primary', 'samples_other'];
+  filter_active = $(this).data("active");
+  for (_i = 0, _len = tables.length; _i < _len; _i++) {
+    table = tables[_i];
+    if ($('#' + table).length) {
+      tableApi = $('#' + table).DataTable();
+      if (filter_active == "true"){
+        $(this).val("Hide No Value")
+        tableApi.draw();
+        $(this).data("active", "false");
+      } else {
+        $(this).val("Show No Value")
+        $.fn.dataTable.ext.search.push(hideNoValue_filter);
+        tableApi.search();
+        tableApi.draw();
+        $.fn.dataTable.ext.search.splice($.fn.dataTable.ext.search.indexOf(hideNoValue_filter, 1));
+        $(this).data("active", "true");
+      }
+    }
+  }
+};
+$('#hideNoValue').click(hideNoValue);
+
+blockOutliers = function() {
+  return $('.outlier').each((function(_this) {
+    return function(_index, element) {
+      return $(element).find('.trait-value-input').val('x');
+    };
+  })(this));
+};
+$('#blockOutliers').click(blockOutliers);
+
+resetSamplesTable = function() {
+  $('input[name="transform"]').val("");
+  $('span[name="transform_text"]').text("")
+  $('#hideNoValue').val("Hide No Value")
+  tables = ['samples_primary', 'samples_other'];
+  for (_i = 0, _len = tables.length; _i < _len; _i++) {
+    table = tables[_i];
+    if ($('#' + table).length) {
+      tableApi = $('#' + table).DataTable();
+      val_nodes = tableApi.column(3).nodes().to$();
+      for (i = 0; i < val_nodes.length; i++) {
+        this_node = val_nodes[i].childNodes[0];
+        this_node.value = this_node.attributes["data-value"].value;
+      }
+      if (js_data.se_exists){
+        se_nodes = tableApi.column(5).nodes().to$();
+        for (i = 0; i < val_nodes.length; i++) {
+          this_node = val_nodes[i].childNodes[0];
+          this_node.value = this_node.attributes["data-value"].value;
+        }
+      }
+      tableApi.draw();
+    }
+  }
+};
+$('.reset').click(function() {
+  $('.selected').each(function() {
+    $(this).removeClass('selected');
+    $(this).find('.edit_sample_checkbox').prop("checked", false);
+  })
+  resetSamplesTable();
+  $('input[name="transform"]').val("");
+  editDataChange();
+});
+
+checkForZeroToOneVals = function() {
+  tables = ['samples_primary', 'samples_other'];
+  for (_i = 0, _len = tables.length; _i < _len; _i++) {
+    table = tables[_i];
+    if ($('#' + table).length) {
+      tableApi = $('#' + table).DataTable();
+      val_nodes = tableApi.column(3).nodes().to$();
+      for (i = 0; i < val_nodes.length; i++) {
+        this_node = val_nodes[i].childNodes[0];
+        if(!isNaN(this_node.value)) {
+          if (0 <= this_node.value && this_node.value < 1){
+            return true
+          }
+        }
+      }
+    }
+  }
+  return false
+}
+
+log2Data = function(this_node) {
+  current_value = this_node.value;
+  original_value = this_node.attributes['data-value'].value;
+  if(!isNaN(current_value) && !isNaN(original_value)) {
+    if (zeroToOneValsExist){
+      original_value = parseFloat(original_value) + 1;
+    }
+    this_node.value = Math.log2(original_value).toFixed(3);
+  }
+};
+
+log10Data = function() {
+  current_value = this_node.value;
+  original_value = this_node.attributes['data-value'].value;
+  if(!isNaN(current_value) && !isNaN(original_value)) {
+    if (zeroToOneValsExist){
+      original_value = parseFloat(original_value) + 1;
+    }
+    this_node.value = Math.log10(original_value).toFixed(3);
+  }
+};
+
+sqrtData = function() {
+  current_value = this_node.value;
+  original_value = this_node.attributes['data-value'].value;
+  if(!isNaN(current_value) && !isNaN(original_value)) {
+    if (zeroToOneValsExist){
+      original_value = parseFloat(original_value) + 1;
+    }
+    this_node.value = Math.sqrt(original_value).toFixed(3);
+  }
+};
+
+invertData = function() {
+  current_value = this_node.value;
+  if(!isNaN(current_value)) {
+    this_node.value = parseFloat(-(current_value)).toFixed(3);
+  }
+};
+
+qnormData = function() {
+  current_value = this_node.value;
+  qnorm_value = this_node.attributes['data-qnorm'].value;
+  if(!isNaN(current_value)) {
+    this_node.value = qnorm_value;
+  }
+};
+
+zScoreData = function() {
+  current_value = this_node.value;
+  zscore_value = this_node.attributes['data-zscore'].value;
+  if(!isNaN(current_value)) {
+    this_node.value = zscore_value;
+  }
+};
+
+doTransform = function(transform_type) {
+  tables = ['samples_primary', 'samples_other'];
+  for (_i = 0, _len = tables.length; _i < _len; _i++) {
+    table = tables[_i];
+    if ($('#' + table).length) {
+      tableApi = $('#' + table).DataTable();
+      val_nodes = tableApi.column(3).nodes().to$();
+      for (i = 0; i < val_nodes.length; i++) {
+        this_node = val_nodes[i].childNodes[0]
+        if (transform_type == "log2"){
+          log2Data(this_node)
+        }
+        if (transform_type == "log10"){
+          log10Data(this_node)
+        }
+        if (transform_type == "sqrt"){
+          sqrtData(this_node)
+        }
+        if (transform_type == "invert"){
+          invertData(this_node)
+        }
+        if (transform_type == "qnorm"){
+          qnormData(this_node)
+        }
+        if (transform_type == "zscore"){
+          zScoreData(this_node)
+        }
+      }
+    }
+  }
+}
+
+normalizeData = function() {
+  if ($('#norm_method option:selected').val() == 'log2' || $('#norm_method option:selected').val() == 'log10'){
+    if ($('input[name="transform"]').val() != "log2" && $('#norm_method option:selected').val() == 'log2') {
+      doTransform("log2")
+      $('input[name="transform"]').val("log2")
+      $('span[name="transform_text"]').text(" - log2 Transformed")
+    } else {
+      if ($('input[name="transform"]').val() != "log10" && $('#norm_method option:selected').val() == 'log10'){
+        doTransform("log10")
+        $('input[name="transform"]').val("log10")
+        $('span[name="transform_text"]').text(" - log10 Transformed")
+      }
+    }
+  }
+  else if ($('#norm_method option:selected').val() == 'sqrt'){
+    if ($('input[name="transform"]').val() != "sqrt") {
+      doTransform("sqrt")
+      $('input[name="transform"]').val("sqrt")
+      $('span[name="transform_text"]').text(" - Square Root Transformed")
+    }
+  }
+  else if ($('#norm_method option:selected').val() == 'invert'){
+    doTransform("invert")
+    $('input[name="transform"]').val("inverted")
+    if ($('span[name="transform_text"]:eq(0)').text() != ""){
+      current_text = $('span[name="transform_text"]:eq(0)').text();
+      $('span[name="transform_text"]').text(current_text + " and Inverted");
+    } else {
+      $('span[name="transform_text"]').text(" - Inverted")
+    }
+  }
+  else if ($('#norm_method option:selected').val() == 'qnorm'){
+    if ($('input[name="transform"]').val() != "qnorm") {
+      doTransform("qnorm")
+      $('input[name="transform"]').val("qnorm")
+      $('span[name="transform_text"]').text(" - Quantile Normalized")
+    }
+  }
+  else if ($('#norm_method option:selected').val() == 'zscore'){
+    if ($('input[name="transform"]').val() != "zscore") {
+      doTransform("zscore")
+      $('input[name="transform"]').val("zscore")
+      $('span[name="transform_text"]').text(" - Z-Scores")
+    }
+  }
+}
+
+zeroToOneValsExist = checkForZeroToOneVals();
+
+showTransformWarning = function() {
+  transform_type = $('#norm_method option:selected').val()
+  if (transform_type == "log2" || transform_type == "log10"){
+    if (zeroToOneValsExist){
+      $('#transform_alert').css("display", "block")
+    }
+  } else {
+    $('#transform_alert').css("display", "none")
+  }
+}
+
+$('#norm_method').change(function(){
+  showTransformWarning()
+});
+$('#normalize').hover(function(){
+  showTransformWarning()
+});
+
+$('#normalize').click(normalizeData)
+
+switchQNormData = function() {
+  return $('.trait-value-input').each((function(_this) {
+    return function(_index, element) {
+      transform_val = $(element).data('transform')
+      if (transform_val != "") {
+          $(element).val(transform_val.toFixed(3));
+      }
+      return transform_val
+    };
+  })(this));
+};
+$('#qnorm').click(switchQNormData);
+
+getSampleTableData = function(tableName, attributesAsList, includeNAs=false) {
+  var samples = [];
+
+  if ($('#' + tableName).length){
+    tableApi = $('#' + tableName).DataTable();
+    attrCol = 4
+
+    nameNodes = tableApi.column(2).nodes().to$();
+    valNodes = tableApi.column(3).nodes().to$();
+    if (js_data.se_exists){
+      varNodes = tableApi.column(5).nodes().to$();
+      attrCol = 6
+      if (js_data.has_num_cases) {
+        nNodes = tableApi.column(6).nodes().to$();
+        attrCol = 7
+      }
+    } else {
+      if (js_data.has_num_cases){
+        nNodes = tableApi.column(4).nodes().to$();
+        attrCol = 5
+      }
+    }
+
+    attributeNodes = []
+    for (_i = 0; _i < attributesAsList.length; _i++){
+      attributeNodes.push(tableApi.column(attrCol + _i).nodes().to$())
+    }
+
+    checkedRows = getCheckedRows(tableName)
+
+    for (_j = 0; _j < valNodes.length; _j++){
+      if (!checkedRows.includes(_j) && checkedRows.length > 0) {
+        continue
+      }
+      sampleVal = valNodes[_j].childNodes[0].value
+      sampleName = $.trim(nameNodes[_j].childNodes[0].textContent)
+      if (isNumber(sampleVal) && sampleVal !== "") {
+        sampleVal = parseFloat(sampleVal);
+      } else {
+        sampleVal = 'x'
+      }
+      if (typeof varNodes == 'undefined'){
+        sampleVar = null;
+      } else {
+        sampleVar = varNodes[_j].childNodes[0].value;
+        if (isNumber(sampleVar)) {
+          sampleVar = parseFloat(sampleVar);
+        } else {
+          sampleVar = 'x';
+        }
+      }
+      if (typeof nNodes == 'undefined'){
+        sampleN = null;
+      } else {
+        sampleN = nNodes[_j].childNodes[0].value;
+        if (isNumber(sampleN)) {
+          sampleN = parseInt(sampleN);
+        } else {
+          sampleN = 'x';
+        }
+      }
+
+      rowDict = {
+        name: sampleName,
+        value: sampleVal,
+        se: sampleVar,
+        num_cases: sampleN
+      }
+
+      for (_k = 0; _k < attributeNodes.length; _k++){
+        rowDict[attributesAsList[_k]] = attributeNodes[_k][_j].textContent;
+      }
+      if (includeNAs || sampleVal != 'x') {
+        samples.push(rowDict)
+      }
+    }
+  }
+
+  return samples;
+};
+exportSampleTableData = function() {
+  var format, json_sample_data, sample_data;
+
+  var attributesAsList = Object.keys(js_data.attributes).map(function(key) {
+    return js_data.attributes[key].name;
+  });
+
+  sample_data = {};
+  sample_data.primary_samples = getSampleTableData('samples_primary', attributesAsList, true);
+  sample_data.other_samples = getSampleTableData('samples_other', attributesAsList, true);
+  sample_data.attributes = attributesAsList;
+  json_sample_data = JSON.stringify(sample_data);
+  $('input[name=export_data]').val(json_sample_data);
+  format = $('input[name=export_format]').val();
+  if (format === "excel") {
+    $('#trait_data_form').attr('action', '/export_trait_excel');
+  } else {
+    $('#trait_data_form').attr('action', '/export_trait_csv');
+  }
+  return $('#trait_data_form').submit();
+};
+
+$('.export_format').change(function() {
+  if (this.value  == "csv"){
+    $('#export_code').css("display", "block")
+  } else{
+    $('#export_code').css("display", "none")
+  }
+  $('input[name=export_format]').val( this.value );
+  $('.export_format').val( this.value );
+});
+
+$('.export').click(exportSampleTableData);
+$('#blockOutliers').click(blockOutliers);
+_.mixin(_.str.exports());
+
+getSampleVals = function(sample_list) {
+  var sample;
+  return this.sample_vals = (function() {
+    var i, len, results;
+    results = [];
+    for (i = 0, len = sample_list.length; i < len; i++) {
+      sample = sample_list[i];
+      if (sample.value !== null) {
+        results.push(sample.value);
+      }
+    }
+    return results;
+  })();
+};
+
+getSampleErrors = function(sample_list) {
+  var sample;
+  return this.sample_vals = (function() {
+    var i, len, results;
+    variance_exists = false;
+    results = [];
+    for (i = 0, len = sample_list.length; i < len; i++) {
+      sample = sample_list[i];
+      if (sample.variance !== null) {
+        results.push(sample.variance);
+        variance_exists = true;
+      }
+    }
+    return [results, variance_exists];
+  })();
+};
+
+getSampleNames = function(sample_list) {
+  var sample;
+  return this.sampleNames = (function() {
+    var i, len, results;
+    results = [];
+    for (i = 0, len = sample_list.length; i < len; i++) {
+      sample = sample_list[i];
+      if (sample.value !== null) {
+        results.push(sample.name);
+      }
+    }
+    return results;
+  })();
+};
+
+getBarBottomMargin = function(sample_list){
+  bottomMargin = 80
+  maxLength = 0
+  sampleNames = getSampleNames(sample_list)
+  for (i=0; i < sampleNames.length; i++){
+    if (sampleNames[i].length > maxLength) {
+      maxLength = sampleNames[i].length
+    }
+  }
+
+  if (maxLength > 6){
+    bottomMargin += 11*(maxLength - 6)
+  }
+
+  return bottomMargin;
+}
+
+root.stats_group = 'samples_primary';
+
+if (Object.keys(js_data.sample_group_types).length > 1) {
+    fullSampleLists = [sampleLists[0], sampleLists[1], sampleLists[0].concat(sampleLists[1])]
+    sampleGroupList = [js_data.sample_group_types['samples_primary'], js_data.sample_group_types['samples_other'], js_data.sample_group_types['samples_all']]
+} else {
+    fullSampleLists = [sampleLists[0]]
+    sampleGroupList = [js_data.sample_group_types['samples_primary']]
+}
+
+// Define Plotly Options (for the options bar at the top of each figure)
+
+root.modebar_options = {
+  displayModeBar: true,
+  modeBarButtonsToAdd:[{
+    name: 'Export as SVG',
+    icon: Plotly.Icons.disk,
+    click: function(gd) {
+      Plotly.downloadImage(gd, {format: 'svg'})
+    }
+  },
+  {
+    name: 'Export as JPEG',
+    icon: Plotly.Icons.camera,
+    click: function(gd) {
+      Plotly.downloadImage(gd, {format: 'jpeg'})
+    }
+  }],
+  showEditInChartStudio: true,
+  plotlyServerURL: "https://chart-studio.plotly.com",
+  modeBarButtonsToRemove:['zoom2d', 'pan2d', 'toImage', 'hoverClosest', 'hoverCompare', 'hoverClosestCartesian', 'hoverCompareCartesian', 'lasso2d', 'toggleSpikelines', 'resetScale2d'],
+  displaylogo: false
+  //modeBarButtons:['toImage2', 'zoom2d', 'pan2d', 'select2d', 'zoomIn2d', 'zoomOut2d', 'autoScale2d', 'resetScale2d'],
+}
+
+// Bar Chart
+
+root.errors_exist = getSampleErrors(sampleLists[0])[1]
+var barTrace = {
+    x: getSampleNames(sampleLists[0]),
+    y: getSampleVals(sampleLists[0]),
+    error_y: {
+        type: 'data',
+        array: getSampleErrors(sampleLists[0])[0],
+        visible: root.errors_exist
+    },
+    type: 'bar'
+}
+
+root.bar_data = [barTrace]
+
+getBarRange = function(sample_vals, sampleErrors = null){
+  positiveErrorVals = []
+  negativeErrorVals = []
+  for (i = 0;i < sample_vals.length; i++){
+    if (sampleErrors[i] != undefined) {
+        positiveErrorVals.push(sample_vals[i] + sampleErrors[i])
+        negativeErrorVals.push(sample_vals[i] - sampleErrors[i])
+    } else {
+        positiveErrorVals.push(sample_vals[i])
+        negativeErrorVals.push(sample_vals[i])
+    }
+  }
+
+  minYVal = Math.min(...negativeErrorVals)
+  maxYVal = Math.max(...positiveErrorVals)
+
+  if (minYVal == 0) {
+    rangeTop = maxYVal + Math.abs(maxYVal)*0.1
+    rangeBottom = 0;
+  } else {
+    rangeTop = maxYVal + Math.abs(maxYVal)*0.1
+    rangeBottom = minYVal - Math.abs(minYVal)*0.1
+    if (minYVal > 0) {
+        rangeBottom = minYVal - 0.1*Math.abs(minYVal)
+    } else if (minYVal < 0) {
+        rangeBottom = minYVal + 0.1*minYVal
+    } else {
+        rangeBottom = 0
+    }
+  }
+
+  return [rangeBottom, rangeTop]
+}
+
+root.chart_range = getBarRange(getSampleVals(sampleLists[0]), getSampleErrors(sampleLists[0])[0])
+valRange = root.chart_range[1] - root.chart_range[0]
+
+if (valRange < 0.05){
+  tickDigits = '.3f'
+  leftMargin = 80
+} else if (valRange < 0.5) {
+  tickDigits = '.2f'
+  leftMargin = 70
+} else if (valRange < 5){
+  tickDigits = '.1f'
+  leftMargin = 60
+} else {
+  tickDigits = 'f'
+  leftMargin = 55
+}
+
+if (js_data.num_values < 256) {
+  barChartWidth = 25 * getSampleVals(sampleLists[0]).length
+
+  // Set bottom margin dependent on longest sample name length, since those can get long
+  bottomMargin = getBarBottomMargin(sampleLists[0])
+
+  root.bar_layout = {
+    title: {
+      x: 0,
+      y: 10,
+      xanchor: 'left',
+      text: "<b>Trait " + js_data.trait_id + ": " + js_data.short_description + "</b>",
+    },
+    xaxis: {
+        type: 'category',
+        titlefont: {
+          size: 16
+        },
+        showline: true,
+        ticklen: 4,
+        tickfont: {
+          size: 16
+        },
+    },
+    yaxis: {
+        title: "<b>" + js_data.unit_type + "</b>",
+        range: root.chart_range,
+        titlefont: {
+          size: 16
+        },
+        showline: true,
+        ticklen: 4,
+        tickfont: {
+          size: 16
+        },
+        tickformat: tickDigits,
+        fixedrange: true
+    },
+    width: barChartWidth,
+    height: 600,
+    margin: {
+        l: leftMargin,
+        r: 30,
+        t: 100,
+        b: bottomMargin
+    },
+    dragmode: false
+  };
+
+  $('.bar_chart_tab').click(function() {
+    updateBarChart();
+  });
+}
+
+total_sample_count = 0
+for (i = 0, i < sampleLists.length; i++;) {
+  total_sample_count += getSampleVals(sampleLists[i]).length
+}
+
+// Histogram
+var hist_trace = {
+    x: getSampleVals(sampleLists[0]),
+    type: 'histogram'
+};
+root.histogram_data = [hist_trace];
+root.histogram_layout = {
+  bargap: 0.05,
+  title: {
+    x: 0,
+    y: 10,
+    xanchor: 'left',
+    text: "<b> Trait " + js_data.trait_id + ": " + js_data.short_description + "</b>",
+  },
+  xaxis: {
+           autorange: true,
+           title: js_data.unit_type,
+           titlefont: {
+             family: "arial",
+             size: 16
+           },
+           ticklen: 4,
+           tickfont: {
+             size: 16
+           }
+         },
+  yaxis: {
+           autorange: true,
+           title: "<b>count</b>",
+           titlefont: {
+             family: "arial",
+             size: 16
+           },
+           showline: true,
+           ticklen: 4,
+           tickfont: {
+             size: 16
+           },
+           automargin: true,
+           fixedrange: true
+         },
+  width: 500,
+  height: 600,
+  margin: {
+      l: 100,
+      r: 30,
+      t: 100,
+      b: 50
+  }
+};
+
+$('.histogram_tab').click(function() {
+  updateHistogram();
+  updateHistogram_width();
+});
+
+$('.histogram_samples_group').val(root.stats_group);
+$('.histogram_samples_group').change(function() {
+  root.stats_group = $(this).val();
+  return updateHistogram();
+});
+
+// Violin Plot
+
+root.violin_layout = {
+  title: "<b>Trait " + js_data.trait_id + ": " + js_data.short_description + "</b>",
+  xaxis: {
+      showline: true,
+      titlefont: {
+        family: "arial",
+        size: 16
+      },
+      tickfont: {
+        family: "arial",
+        size: 16
+      }
+  },
+  yaxis: {
+      title: {
+        text: "<b>"+js_data.unit_type+"</b>"
+      },
+      titlefont: {
+        family: "arial",
+        size: 16
+      },
+      autorange: true,
+      showline: true,
+      ticklen: 4,
+      tickfont: {
+        size: 16
+      },
+      tickformat: tickDigits,
+      zeroline: false,
+      automargin: true
+  },
+  margin: {
+        l: 100,
+        r: 30,
+        t: 100,
+        b: 80
+  },
+  dragmode: false,
+  showlegend: false
+};
+
+if (fullSampleLists.length > 1) {
+    root.violin_layout['width'] = 600;
+    root.violin_layout['height'] = 500;
+    var trace1 = {
+        y: getSampleVals(fullSampleLists[2]),
+        type: 'violin',
+        points: 'none',
+        box: {
+          visible: true
+        },
+        line: {
+          color: 'blue',
+        },
+        meanline: {
+          visible: true
+        },
+        name: "<b>" + sampleGroupList[2] + "</b>",
+        x0: "<b>" + sampleGroupList[2] + "</b>"
+    }
+    var trace2 = {
+        y: getSampleVals(fullSampleLists[1]),
+        type: 'violin',
+        points: 'none',
+        box: {
+          visible: true
+        },
+        line: {
+          color: 'red',
+        },
+        meanline: {
+          visible: true
+        },
+        name: "<b>" + sampleGroupList[1] + "</b>",
+        x0: "<b>" + sampleGroupList[1] + "</b>"
+    }
+    var trace3 = {
+        y: getSampleVals(fullSampleLists[0]),
+        type: 'violin',
+        points: 'none',
+        box: {
+          visible: true
+        },
+        line: {
+          color: 'green',
+        },
+        meanline: {
+          visible: true
+        },
+        name: "<b>" + sampleGroupList[0] + "</b>",
+        x0: "<b>" + sampleGroupList[0] + "</b>"
+    }
+    root.violin_data = [trace1, trace2, trace3]
+} else {
+    root.violin_layout['width'] = 320;
+    root.violin_layout['height'] = 400;
+    root.violin_data = [
+      {
+        y: getSampleVals(fullSampleLists[0]),
+        type: 'violin',
+        points: 'none',
+        box: {
+          visible: true
+        },
+        meanline: {
+          visible: true
+        },
+        name: "<b>Trait " + js_data.trait_id + "</b>",
+        x0: "<b>density</b>"
+      }
+    ]
+}
+
+$('.violin_plot_tab').click(function() {
+  updateViolinPlot();
+});
+
+if (getSampleVals(sampleLists[0]).length < 256) {
+  $('.bar_chart_samples_group').change(function() {
+    root.stats_group = $(this).val();
+    return updateBarChart();
+  });
+  root.bar_sort = "name"
+}
+$('.sort_by_name').click(function() {
+  root.bar_sort = "name"
+  return updateBarChart();
+});
+$('.sort_by_value').click(function() {
+  root.bar_sort = "value"
+  return updateBarChart();
+});
+
+root.prob_plot_group = 'samples_primary';
+$('.prob_plot_samples_group').val(root.prob_plot_group);
+$('.prob_plot_tab').click(function() {
+  return updateProbPlot();
+});
+$('.prob_plot_samples_group').change(function() {
+  root.prob_plot_group = $(this).val();
+  return updateProbPlot();
+});
+
+function isEmpty( el ){
+  return !$.trim(el.html())
+}
+
+$('.stats_panel').click(function() {
+  if (isEmpty($('#stats_table'))){
+    makeTable();
+    editDataChange();
+  } else {
+    editDataChange();
+  }
+});
+
+$('#block_by_index').click(function(){
+  blockByIndex();
+  editDataChange();
+});
+
+$('#filter_by_study').click(function(){
+  filter_by_study();
+  editDataChange();
+})
+
+$('#filter_by_value').click(function(){
+  filter_by_value();
+  editDataChange();
+})
+
+$('.edit_sample_value').change(function() {
+  editDataChange();
+});
+
+$('#exclude_group').click(editDataChange);
+$('#blockOutliers').click(editDataChange);
+$('#reset').click(editDataChange);
+$('#qnorm').click(editDataChange);
+$('#normalize').click(editDataChange);
+
+Number.prototype.countDecimals = function () {
+  if(Math.floor(this.valueOf()) === this.valueOf()) return 0;
+    return this.toString().split(".")[1].length || 0;
+}