about summary refs log tree commit diff
diff options
context:
space:
mode:
authorZachary Sloan2012-10-02 17:24:09 -0500
committerZachary Sloan2012-10-02 17:24:09 -0500
commitfe9082941a9c3a7815fb986a4717144f3ae7c021 (patch)
treece0196b4567d5a5c7ef639f5360870884ba962af
parente5ba48c06a76ac1d4d4725cf633de1cf3abfde2d (diff)
downloadgenenetwork2-fe9082941a9c3a7815fb986a4717144f3ae7c021.tar.gz
Finished getting the dropdowns for the black samples by attribute value function working
-rw-r--r--wqflask/wqflask/show_trait/SampleList.py4
-rwxr-xr-xwqflask/wqflask/show_trait/show_trait.py103
-rw-r--r--wqflask/wqflask/static/new/javascript/show_trait.coffee28
-rw-r--r--wqflask/wqflask/static/new/javascript/show_trait.js236
-rw-r--r--wqflask/wqflask/templates/show_trait.html16
-rw-r--r--wqflask/wqflask/views.py43
6 files changed, 361 insertions, 69 deletions
diff --git a/wqflask/wqflask/show_trait/SampleList.py b/wqflask/wqflask/show_trait/SampleList.py
index 62bc63c3..d39559d3 100644
--- a/wqflask/wqflask/show_trait/SampleList.py
+++ b/wqflask/wqflask/show_trait/SampleList.py
@@ -24,7 +24,7 @@ class SampleList(object):
 
         self.sample_list = [] # The actual list
         
-        self.calc_attributes()
+        self.get_attributes()
         
         print("camera: attributes are:", pf(self.attributes))
 
@@ -85,7 +85,7 @@ class SampleList(object):
                     sample.outlier = False
                     
                     
-    def calc_attributes(self):
+    def get_attributes(self):
         """Finds which extra attributes apply to this dataset"""
         
         #ZS: Id and name values for this trait's extra attributes  
diff --git a/wqflask/wqflask/show_trait/show_trait.py b/wqflask/wqflask/show_trait/show_trait.py
index 743e4ad6..9bad6154 100755
--- a/wqflask/wqflask/show_trait/show_trait.py
+++ b/wqflask/wqflask/show_trait/show_trait.py
@@ -161,7 +161,10 @@ class ShowTrait(templatePage):
         self.sample_group_types['primary_only'] = fd.RISet + " Only"
         self.sample_group_types['other_only'] = "Non-" + fd.RISet
         self.sample_group_types['all_cases'] = "All Cases"
-        self.js_data = dict(sample_groups = self.sample_group_types)
+        js_data = dict(sample_groups = self.sample_group_types,
+                        attribute_names = self.sample_groups[0].attributes)
+        print("js_data:", pf(js_data))
+        self.js_data = js_data
 
 
     def get_this_trait(self):
@@ -989,55 +992,55 @@ class ShowTrait(templatePage):
                 except:
                     plotTitle = str(this_trait.name)
 
-                #normalplot_img = BasicStatisticsFunctions.plotNormalProbability(vals=vals, RISet=fd.RISet, title=plotTitle, specialStrains=specialStrains)
-                #normalplot.append(HT.TR(HT.TD(normalplot_img)))
-                #normalplot.append(HT.TR(HT.TD(HT.BR(),HT.BR(),"This plot evaluates whether data are \
-                #normally distributed. Different symbols represent different groups.",HT.BR(),HT.BR(),
-                #"More about ", HT.Href(url="http://en.wikipedia.org/wiki/Normal_probability_plot",
-                #                 target="_blank", text="Normal Probability Plots"), " and more about interpreting these plots from the ", HT.Href(url="/glossary.html#normal_probability", target="_blank", text="glossary"))))
-                #normalplot_container.append(normalplot)
-                #normalplot_div.append(normalplot_container)
-                #stats_container.append(normalplot_div)
-
-                #boxplot_div = HT.Div(id="statstabs-2")
-                #boxplot_container = HT.Paragraph()
-                #boxplot = HT.TableLite(cellspacing=0, cellpadding=0, width="100%")
-                #boxplot_img, boxplot_link = BasicStatisticsFunctions.plotBoxPlot(vals)
-                #boxplot.append(HT.TR(HT.TD(boxplot_img, HT.P(), boxplot_link, align="left")))
-                #boxplot_container.append(boxplot)
-                #boxplot_div.append(boxplot_container)
-                #stats_container.append(boxplot_div)
-
-
-                #barName_div = HT.Div(id="statstabs-3")
-                #barName_container = HT.Paragraph()
-                #barName = HT.TableLite(cellspacing=0, cellpadding=0, width="100%")
-                #barName_img = BasicStatisticsFunctions.plotBarGraph(identification=fd.identification, RISet=fd.RISet, vals=vals, type="name")
-                #barName.append(HT.TR(HT.TD(barName_img)))
-                #barName_container.append(barName)
-                #barName_div.append(barName_container)
-                #stats_container.append(barName_div)
-                #
-                #barRank_div = HT.Div(id="statstabs-4")
-                #barRank_container = HT.Paragraph()
-                #barRank = HT.TableLite(cellspacing=0, cellpadding=0, width="100%")
-                #barRank_img = BasicStatisticsFunctions.plotBarGraph(identification=fd.identification, RISet=fd.RISet, vals=vals, type="rank")
-                #barRank.append(HT.TR(HT.TD(barRank_img)))
-                #barRank_container.append(barRank)
-                #barRank_div.append(barRank_container)
-                #stats_container.append(barRank_div)
-
-        #    stats_cell.append(stats_container)
-        #
-        #stats_script.append(stats_script_text)
-        #
-        #submitTable = HT.TableLite(cellspacing=0, cellpadding=0, width="100%", Class="target2")
-        #stats_row.append(stats_cell)
-
-        #submitTable.append(stats_row)
-        #submitTable.append(stats_script)
-
-        #title2Body.append(submitTable)
+                    #normalplot_img = BasicStatisticsFunctions.plotNormalProbability(vals=vals, RISet=fd.RISet, title=plotTitle, specialStrains=specialStrains)
+                    #normalplot.append(HT.TR(HT.TD(normalplot_img)))
+                    #normalplot.append(HT.TR(HT.TD(HT.BR(),HT.BR(),"This plot evaluates whether data are \
+                    #normally distributed. Different symbols represent different groups.",HT.BR(),HT.BR(),
+                    #"More about ", HT.Href(url="http://en.wikipedia.org/wiki/Normal_probability_plot",
+                    #                 target="_blank", text="Normal Probability Plots"), " and more about interpreting these plots from the ", HT.Href(url="/glossary.html#normal_probability", target="_blank", text="glossary"))))
+                    #normalplot_container.append(normalplot)
+                    #normalplot_div.append(normalplot_container)
+                    #stats_container.append(normalplot_div)
+    
+                    #boxplot_div = HT.Div(id="statstabs-2")
+                    #boxplot_container = HT.Paragraph()
+                    #boxplot = HT.TableLite(cellspacing=0, cellpadding=0, width="100%")
+                    #boxplot_img, boxplot_link = BasicStatisticsFunctions.plotBoxPlot(vals)
+                    #boxplot.append(HT.TR(HT.TD(boxplot_img, HT.P(), boxplot_link, align="left")))
+                    #boxplot_container.append(boxplot)
+                    #boxplot_div.append(boxplot_container)
+                    #stats_container.append(boxplot_div)
+    
+    
+                    #barName_div = HT.Div(id="statstabs-3")
+                    #barName_container = HT.Paragraph()
+                    #barName = HT.TableLite(cellspacing=0, cellpadding=0, width="100%")
+                    #barName_img = BasicStatisticsFunctions.plotBarGraph(identification=fd.identification, RISet=fd.RISet, vals=vals, type="name")
+                    #barName.append(HT.TR(HT.TD(barName_img)))
+                    #barName_container.append(barName)
+                    #barName_div.append(barName_container)
+                    #stats_container.append(barName_div)
+                    #
+                    #barRank_div = HT.Div(id="statstabs-4")
+                    #barRank_container = HT.Paragraph()
+                    #barRank = HT.TableLite(cellspacing=0, cellpadding=0, width="100%")
+                    #barRank_img = BasicStatisticsFunctions.plotBarGraph(identification=fd.identification, RISet=fd.RISet, vals=vals, type="rank")
+                    #barRank.append(HT.TR(HT.TD(barRank_img)))
+                    #barRank_container.append(barRank)
+                    #barRank_div.append(barRank_container)
+                    #stats_container.append(barRank_div)
+    
+            #    stats_cell.append(stats_container)
+            #
+            #stats_script.append(stats_script_text)
+            #
+            #submitTable = HT.TableLite(cellspacing=0, cellpadding=0, width="100%", Class="target2")
+            #stats_row.append(stats_cell)
+    
+            #submitTable.append(stats_row)
+            #submitTable.append(stats_script)
+    
+            #title2Body.append(submitTable)
 
 
     def build_correlation_tools(self, fd, this_trait):
diff --git a/wqflask/wqflask/static/new/javascript/show_trait.coffee b/wqflask/wqflask/static/new/javascript/show_trait.coffee
index 803045d5..a91e9681 100644
--- a/wqflask/wqflask/static/new/javascript/show_trait.coffee
+++ b/wqflask/wqflask/static/new/javascript/show_trait.coffee
@@ -69,7 +69,7 @@ $ ->
     make_table = ->
         header = "<thead><tr><th>&nbsp;</th>"
         console.log("js_data.sample_groups:", js_data.sample_groups)
-        for key, value of js_data.sample_groups
+        for own key, value of js_data.sample_groups
             console.log("aa key:", key)
             console.log("aa value:", value)
             the_id = process_id("column", key)
@@ -108,7 +108,7 @@ $ ->
             row_line = """<tr>"""
             row_line += """<td id="#{ row.vn  }">#{ row.pretty }</td>"""
             console.log("box - js_data.sample_groups:", js_data.sample_groups)
-            for key, value of js_data.sample_groups
+            for own key, value of js_data.sample_groups
                 console.log("apple key:", key)
                 the_id = process_id(key, row.vn)
                 console.log("the_id:", the_id)
@@ -166,6 +166,30 @@ $ ->
     
     #End Calculate Correlations Code
     
+    #Populate Samples Attribute Values Code
+    
+    create_value_dropdown = (value) ->
+        return """<option val=#{value}>#{value}</option>"""
+    
+    populate_sample_attributes_values_dropdown = ->
+        console.log("in beginning of psavd")
+        $('#attribute_values').empty()
+        sample_attributes = {}
+        for own key, attribute_info of js_data.attribute_names
+            sample_attributes[attribute_info.name] = attribute_info.distinct_values
+        console.log("[visa] attributes is:", sample_attributes)
+        selected_attribute = $('#exclude_menu').val()
+        for value in sample_attributes[selected_attribute]
+            $(create_value_dropdown(value))
+                .appendTo($('#attribute_values'))
+
+    # Must run once at beginning
+    populate_sample_attributes_values_dropdown()
+    $('#exclude_menu').change(populate_sample_attributes_values_dropdown)
+    
+    
+    
+    #End Populate Samples Attribute Values Code
 
     console.log("before registering show_hide_outliers")
     $('#show_hide_outliers').click(show_hide_outliers)
diff --git a/wqflask/wqflask/static/new/javascript/show_trait.js b/wqflask/wqflask/static/new/javascript/show_trait.js
new file mode 100644
index 00000000..039a5e04
--- /dev/null
+++ b/wqflask/wqflask/static/new/javascript/show_trait.js
@@ -0,0 +1,236 @@
+// Generated by CoffeeScript 1.3.3
+(function() {
+  var is_number,
+    __hasProp = {}.hasOwnProperty,
+    __slice = [].slice;
+
+  console.log("start_b");
+
+  is_number = function(o) {
+    return !isNaN((o - 0) && o !== null);
+  };
+
+  $(function() {
+    var change_stats_value, create_value_dropdown, edit_data_change, hide_tabs, make_table, on_corr_method_change, populate_sample_attributes_values_dropdown, process_id, show_hide_outliers, stats_mdp_change, update_stat_values;
+    hide_tabs = 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;
+    };
+    hide_tabs(1);
+    stats_mdp_change = function() {
+      var selected;
+      selected = $(this).val();
+      hide_tabs(0);
+      return $("#stats_tabs" + selected).show();
+    };
+    $(".stats_mdp").change(stats_mdp_change);
+    change_stats_value = function(sample_sets, category, value_type, decimal_places) {
+      var current_value, id, in_box, the_value;
+      id = "#" + process_id(category, value_type);
+      console.log("the_id:", id);
+      in_box = $(id).html;
+      current_value = parseFloat($(in_box)).toFixed(decimal_places);
+      the_value = sample_sets[category][value_type]();
+      if (decimal_places > 0) {
+        the_value = the_value.toFixed(decimal_places);
+      }
+      if (the_value !== current_value) {
+        return $(id).html(the_value).effect("highlight");
+      }
+    };
+    update_stat_values = function(sample_sets) {
+      var category, stat, _i, _len, _ref, _results;
+      _ref = ['primary_only', 'other_only', 'all_cases'];
+      _results = [];
+      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+        category = _ref[_i];
+        change_stats_value(sample_sets, category, "n_of_samples", 0);
+        _results.push((function() {
+          var _j, _len1, _ref1, _results1;
+          _ref1 = ["mean", "median", "std_dev", "std_error"];
+          _results1 = [];
+          for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
+            stat = _ref1[_j];
+            _results1.push(change_stats_value(sample_sets, category, stat, 2));
+          }
+          return _results1;
+        })());
+      }
+      return _results;
+    };
+    edit_data_change = function() {
+      var category, checkbox, checked, real_value, row, sample_sets, value, values, _i, _len;
+      sample_sets = {
+        primary_only: new Stats([]),
+        other_only: new Stats([]),
+        all_cases: new Stats([])
+      };
+      console.log("at beginning:", sample_sets);
+      values = $('#value_table').find(".edit_sample_value");
+      for (_i = 0, _len = values.length; _i < _len; _i++) {
+        value = values[_i];
+        real_value = $(value).val();
+        row = $(value).closest("tr");
+        category = row[0].id;
+        checkbox = $(row).find(".edit_sample_checkbox");
+        checked = $(checkbox).attr('checked');
+        if (checked && is_number(real_value) && real_value !== "") {
+          real_value = parseFloat(real_value);
+          if (_(category).startsWith("Primary")) {
+            sample_sets.primary_only.add_value(real_value);
+          } else if (_(category).startsWith("Other")) {
+            sample_sets.other_only.add_value(real_value);
+          }
+          sample_sets.all_cases.add_value(real_value);
+        }
+      }
+      console.log("towards end:", sample_sets);
+      return update_stat_values(sample_sets);
+    };
+    make_table = function() {
+      var header, key, row, row_line, rows, table, the_id, the_rows, value, _i, _len, _ref, _ref1;
+      header = "<thead><tr><th>&nbsp;</th>";
+      console.log("js_data.sample_groups:", js_data.sample_groups);
+      _ref = js_data.sample_groups;
+      for (key in _ref) {
+        if (!__hasProp.call(_ref, key)) continue;
+        value = _ref[key];
+        console.log("aa key:", key);
+        console.log("aa value:", value);
+        the_id = process_id("column", key);
+        header += "<th id=\"" + the_id + "\">" + value + "</th>";
+      }
+      header += "</thead>";
+      console.log("windex header is:", header);
+      rows = [
+        {
+          vn: "n_of_samples",
+          pretty: "N of Samples"
+        }, {
+          vn: "mean",
+          pretty: "Mean"
+        }, {
+          vn: "median",
+          pretty: "Median"
+        }, {
+          vn: "std_error",
+          pretty: "Standard Error (SE)"
+        }, {
+          vn: "std_dev",
+          pretty: "Standard Deviation (SD)"
+        }
+      ];
+      console.log("rows are:", rows);
+      the_rows = "<tbody>";
+      console.log("length of rows:", rows.length);
+      for (_i = 0, _len = rows.length; _i < _len; _i++) {
+        row = rows[_i];
+        console.log("rowing");
+        row_line = "<tr>";
+        row_line += "<td id=\"" + row.vn + "\">" + row.pretty + "</td>";
+        console.log("box - js_data.sample_groups:", js_data.sample_groups);
+        _ref1 = js_data.sample_groups;
+        for (key in _ref1) {
+          if (!__hasProp.call(_ref1, key)) continue;
+          value = _ref1[key];
+          console.log("apple key:", key);
+          the_id = process_id(key, row.vn);
+          console.log("the_id:", the_id);
+          row_line += "<td id=\"" + the_id + "\">foo</td>";
+        }
+        row_line += "</tr>";
+        console.log("row line:", row_line);
+        the_rows += row_line;
+      }
+      the_rows += "</tbody>";
+      table = header + the_rows;
+      console.log("table is:", table);
+      return $("#stats_table").append(table);
+    };
+    process_id = 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];
+        console.log("value:", value);
+        value = value.replace(" ", "_");
+        if (processed.length) {
+          processed += "-";
+        }
+        processed += value;
+      }
+      return processed;
+    };
+    show_hide_outliers = function() {
+      var label;
+      console.log("FOOBAR in beginning of show_hide_outliers");
+      label = $('#show_hide_outliers').val();
+      console.log("lable is:", label);
+      if (label === "Hide Outliers") {
+        return $('#show_hide_outliers').val("Show Outliers");
+      } else if (label === "Show Outliers") {
+        console.log("Found Show Outliers");
+        $('#show_hide_outliers').val("Hide Outliers");
+        return console.log("Should be now Hide Outliers");
+      }
+    };
+    on_corr_method_change = function() {
+      var corr_method;
+      console.log("in beginning of on_corr_method_change");
+      corr_method = $('select[name=corr_method]').val();
+      console.log("corr_method is:", corr_method);
+      $('.correlation_desc').hide();
+      $('#' + corr_method + "_r_desc").show().effect("highlight");
+      if (corr_method === "lit") {
+        return $("#corr_sample_method_options").hide();
+      } else {
+        return $("#corr_sample_method_options").show();
+      }
+    };
+    $('select[name=corr_method]').change(on_corr_method_change);
+    create_value_dropdown = function(value) {
+      return "<option val=" + value + ">" + value + "</option>";
+    };
+    populate_sample_attributes_values_dropdown = function() {
+      var attribute_info, key, sample_attributes, selected_attribute, value, _i, _len, _ref, _ref1, _results;
+      console.log("in beginning of psavd");
+      $('#attribute_values').empty();
+      sample_attributes = {};
+      _ref = js_data.attribute_names;
+      for (key in _ref) {
+        if (!__hasProp.call(_ref, key)) continue;
+        attribute_info = _ref[key];
+        sample_attributes[attribute_info.name] = attribute_info.distinct_values;
+      }
+      console.log("[visa] attributes is:", sample_attributes);
+      selected_attribute = $('#exclude_menu').val();
+      _ref1 = sample_attributes[selected_attribute];
+      _results = [];
+      for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
+        value = _ref1[_i];
+        _results.push($(create_value_dropdown(value)).appendTo($('#attribute_values')));
+      }
+      return _results;
+    };
+    populate_sample_attributes_values_dropdown();
+    $('#exclude_menu').change(populate_sample_attributes_values_dropdown);
+    console.log("before registering show_hide_outliers");
+    $('#show_hide_outliers').click(show_hide_outliers);
+    console.log("after registering show_hide_outliers");
+    _.mixin(_.str.exports());
+    $('#value_table').change(edit_data_change);
+    console.log("loaded");
+    make_table();
+    edit_data_change();
+    return console.log("end");
+  });
+
+}).call(this);
diff --git a/wqflask/wqflask/templates/show_trait.html b/wqflask/wqflask/templates/show_trait.html
index 7d0e671f..3d24e738 100644
--- a/wqflask/wqflask/templates/show_trait.html
+++ b/wqflask/wqflask/templates/show_trait.html
@@ -1227,6 +1227,20 @@
                           </select></span> &nbsp;&nbsp;&nbsp;
                           <input type="button" name="blockSamples" class="button" value=" Block ">
                           <br>
+
+                          {% if sample_groups[0].attributes %}
+                          <strong>&nbsp;&nbsp;Block samples by index:&nbsp;&nbsp;&nbsp;&nbsp;</strong>
+                          <select id="exclude_menu" size=1>
+                            {% for attribute in sample_groups[0].attributes %}
+                            <option value="{{ sample_groups[0].attributes[attribute].name }}">{{ sample_groups[0].attributes[attribute].name }}</option>
+                            {% endfor %}
+                          </select>
+                          <select id="attribute_values" size=1>
+                          </select>                         
+                          {% endif %}
+                          <input type="button" name="exclude_group" class="button" value=" Block ">
+                          <br>
+
                           <strong>&nbsp;&nbsp;Options:</strong>
                           &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                           <input type="button" id="show_hide_no_value" class="button" value="Hide No Value">
@@ -1335,7 +1349,7 @@
     <script type="text/javascript" src="/static/new/js_external/underscore.string.min.js"></script>
     
     <script type="text/javascript" src="/static/new/javascript/stats.js"></script>
-    <script type="text/javascript" src="/static/new/javascript/trait_data_and_analysis.js"></script>
+    <script type="text/javascript" src="/static/new/javascript/show_trait.js"></script>
     
 
     <!-- End of body -->
diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py
index 4da1082f..c38ecb47 100644
--- a/wqflask/wqflask/views.py
+++ b/wqflask/wqflask/views.py
@@ -1,6 +1,6 @@
 from __future__ import absolute_import, division, print_function
 
-import json
+import simplejson as json
 import yaml
 
 import flask
@@ -10,7 +10,7 @@ from wqflask import app
 from flask import render_template, request
 
 from wqflask import search_results
-from wqflask.show_trait import DataEditingPage
+from wqflask.show_trait import show_trait
 from wqflask.correlation import CorrelationPage
 
 from wqflask.dataSharing import SharingInfo, SharingInfoPage
@@ -19,8 +19,6 @@ from base import webqtlFormData
 
 from pprint import pformat as pf
 
-print("latest blue")
-
 
 @app.route("/")
 def index_page():
@@ -29,7 +27,7 @@ def index_page():
 
 
 @app.route("/data_sharing")
-def data_sharing():
+def data_sharing_page():
     print("In data_sharing")
     fd = webqtlFormData.webqtlFormData(request.args)
     print("1Have fd")
@@ -45,7 +43,7 @@ def data_sharing():
 
 
 @app.route("/search")
-def search():
+def search_page():
     if 'info_database' in request.args:
         print("Going to sharing_info_page")
         template_vars = sharing_info_page()
@@ -60,7 +58,7 @@ def search():
 
 
 @app.route("/whats_new")
-def whats_new():
+def whats_new_page():
     #variables = whats_new.whats_new()
     with open("/home/sam/gene/wqflask/wqflask/yaml_data/whats_new.yaml") as fh:
         contents = fh.read()
@@ -72,19 +70,20 @@ def whats_new():
 
 
 @app.route("/show_trait")
-def show_trait():
+def show_trait_page():
     # Here it's currently too complicated not to use an fd that is a webqtlFormData
     fd = webqtlFormData.webqtlFormData(request.args)
-    #template_vars = show_trait_page.ShowTraitPage(fd)
-    template_vars = show_trait.show_trait(fd)
-    template_vars.js_data = json.dumps(template_vars.js_data)
-    
+    template_vars = show_trait.ShowTrait(fd)
+    template_vars.js_data = json.dumps(template_vars.js_data,
+                                       default=json_default_handler,
+                                       indent="   ",
+                                       sort_keys=True)
     print("show_trait template_vars:", pf(template_vars.__dict__))
-    return render_template("trait_data_and_analysis.html", **template_vars.__dict__)
+    return render_template("show_trait.html", **template_vars.__dict__)
 
 
 @app.route("/corr_compute", methods=('POST',))
-def corr_compute():
+def corr_compute_page():
     #print("In corr_compute, request.args is:", pf(request.form))
     fd = webqtlFormData.webqtlFormData(request.form)
     print("Have fd")
@@ -101,3 +100,19 @@ def sharing_info_page():
     template_vars = SharingInfoPage.SharingInfoPage(fd)
     print("2 Made it to rendering")
     return template_vars
+
+
+def json_default_handler(obj):
+    '''Based on http://stackoverflow.com/a/2680060/1175849'''
+    # Handle datestamps
+    if hasattr(obj, 'isoformat'):
+        return obj.isoformat()
+    # Handle integer keys for dictionaries
+    elif isinstance(obj, int):
+        return str(int)
+    # Handle custom objects
+    if hasattr(obj, '__dict__'):
+        return obj.__dict__
+    else:
+        raise TypeError, 'Object of type %s with value of %s is not JSON serializable' % (
+            type(obj), repr(obj))