changeset 5:a9213a30d0f9 draft

Uploaded new version with set code and moved throbber. Hopefully works.
author adam-novak
date Wed, 16 Oct 2013 18:48:28 -0400
parents 6b6c1a0a452e
children 740c9df2ffe8
files hexagram/hexagram.css hexagram/hexagram.html hexagram/hexagram.js hexagram/hexagram.py hexagram/hexagram.xml hexagram/inflate.svg hexagram/save.svg hexagram/set.svg hexagram/statistics.js hexagram/tools.js hexagram/tsv.pyc
diffstat 11 files changed, 2339 insertions(+), 308 deletions(-) [+]
line wrap: on
line diff
--- a/hexagram/hexagram.css	Wed Jun 19 15:04:17 2013 -0400
+++ b/hexagram/hexagram.css	Wed Oct 16 18:48:28 2013 -0400
@@ -170,20 +170,103 @@
 
 #browse-holder {
     margin-left: 0.5em;
+	width: 500px;
 }
-
 #search {
-    width: 20em;
+    width: 322px;
 }
 
 #recalculate-statistics {
     padding: 0.2em;
+	margin-left: 10px;
+}
+
+#calculate-set-operation {
+    padding: 0.2em;
+}
+
+#inflate{
 }
 
 .recalculate-throbber {
     display: none;
 }
 
+/* Set Operation Menu */
+
+#set-operation {
+    padding: 0.2em;
+}
+
+.set-operation-col {
+	visibility:hidden;
+    width: 25em;
+    overflow: visible;
+}
+
+.set-operation-panel-holder {
+	visibility:hidden;
+	margin-left:21em;
+	padding-top: 2em;
+    overflow: hidden;
+    top: 4em;
+    width: 25em;
+    z-index: 100;
+}
+
+.set-operation-panel {
+	text-align: center;
+	visibility:hidden;
+	height: 160px;
+    position: relative;
+    top: 0;
+    border-radius: 10px;
+    border: 1px solid gray;
+    background: white;
+    z-index: 100;
+}
+
+.set-operation-panel-title {
+	visibility:hidden;
+	text-align: center;
+}
+
+.set-operation-panel-contents {
+	visibility:hidden;
+    overflow-y: auto;
+    overflow-x: hidden;
+    top: 1em;
+}
+
+#set-operations-list {
+}
+
+.set-operation-entry {
+	text-align: left;
+    position: relative;
+    height: auto;
+    width: auto;
+    padding: 5px;
+}
+
+.set-operation-value {
+	visibility: hidden;
+    width: 15em;
+	margin-bottom: 10px;
+}
+
+.set-operation-layer-value {
+	visibility: hidden;
+	width: 8em;
+	margin-left: 50px;
+} 
+
+.compute-button {
+	visibility: hidden;
+	text-align: center;
+	width: 190px;
+	margin-left: 25%;
+}
 /* Do some custom styling of browse results */
 .layer-entry {
     padding-right: 20px;
@@ -201,11 +284,11 @@
 
 /* Make the browse dropdown tall */
 .results-dropdown.select2-container .select2-results {
-    max-height: 20em;
+    max-height: 30em;
 }
 
 .results-dropdown .select2-results {
-    max-height: 20em;
+    max-height: 30em;
 }
 
 .layer-metadata {
@@ -231,6 +314,29 @@
     top: 4em;
 }
 
+/* Map Layout Selection Stuff */
+
+#layout-holder{
+	margin-left: 0.5em;
+}
+
+#layout-search {
+    width: 22em;
+}
+
+.layout-entry {
+    padding-right: 20px;
+}
+
+layout-name {
+    /* Force silly underscore names into shape */
+    word-wrap: break-word;
+}
+#current-layout {
+	padding-top: 2.5em;
+	width: 700px;
+}
+
 /* Shortlist UI stuff */
 
 .shortlist-controls {
@@ -311,13 +417,158 @@
     margin-top: 0.5em;
 }
 
+/*Shortlist holders*/
+#left-columns {
+	width: 33%;
+}
+#center-columns {
+	margin-left: 33%;	
+}
+#right-columns {
+	margin-left: 66%
+}
+
 /* Filtering stuff */
+
 .filter {
     line-height: 1em;
     vertical-align: center;
 }
+.filter-threshold, .filter-value {
+    display: none;
+    width: 5em;
+}
+.filter-holder {
+	float: left;
+	text-align: left;
+	width: 120px;
+}
 
-.filter-threshold, .filter-value {
+.save-filter {
+	display: none;
+}
+
+/* Intersection */
+.intersection {
+	line-height: 1em;
+    vertical-align: center;
+}
+.intersection-text {
+	width: 15px;
+	float: left;
+	text-align: center;
+}
+.intersection-checkbox {
+	float: left;
+	text-align: center;
+	margin-left: 2px;
+}
+.intersection-holder {
+	float: left;
+	text-align: center;
+}
+.intersection-threshold, .intersection-value {
+    display: none;
+    width: 5em;
+}
+
+/*Union*/
+.union {
+        line-height: 1em;
+    	vertical-align: center;
+}
+.union-text{
+        width: 15px;
+        float: left;
+        text-align: center;
+}
+.union-checkbox {
+		float: left;
+		text-align: center;
+		margin-left: 2px;
+}
+.union-holder {
+		float: left;
+		text-align: center;
+		margin-left: 10px;
+}
+.union-threshold, .union-value {
+    display: none;
+    width: 5em;
+}
+
+/*Set Difference*/
+.set-difference {
+        line-height: 1em;
+    	vertical-align: center;
+}
+.set-difference-text{
+        width: 15px;
+        float: left;
+        text-align: center;
+}
+.set-difference-checkbox {
+		float: left;
+		text-align: center;
+		margin-left: 2px;
+}
+.set-difference-holder {
+		float: left;
+		text-align: center;
+		margin-left: 10px;
+}
+.set-difference-threshold, .set-difference-value {
+    display: none;
+    width: 5em;
+}
+
+/*Symmetric Difference*/
+.symmetric-difference {
+        line-height: 1em;
+    	vertical-align: center;
+}
+.symmetric-difference-text{
+        width: 15px;
+        float: left;
+        text-align: center;
+}
+.symmetric-difference-checkbox {
+		float: left;
+		text-align: center;
+		margin-left: 2px;
+}
+.symmetric-difference-holder {
+		float: left;
+		text-align: center;
+		margin-left: 10px;
+}
+.symmetric-difference-threshold, .symmetric-difference-value {
+    display: none;
+    width: 5em;
+}
+
+/*Absolute Complement*/
+.absolute-complement {
+     	line-height: 1em;
+    	vertical-align: center;
+}
+.absolute-complement-text{
+      	width: 40px;
+        float: left;
+        text-align: center;
+}
+.absolute-complement-checkbox {
+		float: left;
+		text-align: center;
+		margin-left: 2px;
+}
+.absolute-complement-holder {
+	width: 65px;
+	float: left;
+	text-align: center;
+	margin-left: 10px
+}
+.absolute-complement-threshold, .absolute-complement-value {
     display: none;
     width: 5em;
 }
@@ -439,3 +690,5 @@
     */
     font-size: 0.5em;
 }
+
+
--- a/hexagram/hexagram.html	Wed Jun 19 15:04:17 2013 -0400
+++ b/hexagram/hexagram.html	Wed Oct 16 18:48:28 2013 -0400
@@ -32,11 +32,34 @@
                 <div class="vertical-cell">
                     <div id="browse-holder">
                         <input id="search" type="hidden"/>
-                        <img src="statistics.svg" id="recalculate-statistics" title="Recalculate Statistics"/>
-                        <img src="throbber.svg" class="recalculate-throbber" title="Recalculating..." />
+                        <img src="statistics.svg" id="recalculate-statistics" title="Enrich Attributes"/>
+						<img src="throbber.svg" class="recalculate-throbber" title="Recalculating..." />
+						<img src="set.svg" id="set-operation" title="Calculate Set Operation"/>
+						<img src="inflate.svg" id="inflate" title="Inflate Map"/>
                     </div>
-                </div>
+					<div id="layout-holder">
+						<input id="layout-search" type="hidden"/>
+					</div>
+				</div>
+				<div id="current-layout">Current Layout:</div> 	
             </div>
+			<div class="set-operation-col">
+				<div class="set-operation-panel-holder">
+					<div class="set-operation-panel">
+						<div class="set-operation-panel-title">Set Operation Paramaters:</div>
+						<select id="set-operations-list" onchange="update_set_operation_drop_down()">
+  								<option value = "0" selected = 'selected'>Select Set Operation:</option>
+  								<option value = "1">∩ - Intersection</option>
+  								<option value = "2">U - Union</option>  
+ 								<option value = "3">\ - Set Difference</option>
+  								<option value = "4">∆ - Symmetric Difference</option>
+  								<option value = "5">Not:</option>
+							</select>
+						<div id="set-operations" class="set-operation-panel-contents">
+						</div>
+					</div>
+				</div>
+			</div>
             <div class="shortlist col">
                 <div id="shortlist-holder" class="panel-holder">
                     <div id="shortlist-panel" class="panel">
--- a/hexagram/hexagram.js	Wed Jun 19 15:04:17 2013 -0400
+++ b/hexagram/hexagram.js	Wed Oct 16 18:48:28 2013 -0400
@@ -23,6 +23,9 @@
 // This is a list of layer names maintained in sorted order.
 var layer_names_sorted = [];
 
+// This is a list of the map-layour names mantained in order of entry
+var layout_names = [];
+
 // This holds an array of layer names that the user has added to the "shortlist"
 // They can be quickly selected for display.
 var shortlist = [];
@@ -31,6 +34,52 @@
 // elements, so we can efficiently tell if e.g. one is selected.
 var shortlist_ui = {};
 
+// This is a list of layer names whose intersection checkbox has been selected.
+var shortlist_intersection = [];
+
+//This is the number of intersection checkboxes that have been selected.
+var shortlist_intersection_num = 0;
+
+// This is a list of layer names whose union checkbox has been selected.
+var shortlist_union = [];
+
+//This is the number of union checkboxes that have been selected.
+var shortlist_union_num = 0;
+
+//This is a list of layer names whose set difference checkbox has been selected.
+var shortlist_set_difference = [];
+
+// This is the number of set difference checkboxes that have been selected.
+var shortlist_set_difference_num = 0;
+
+// This is a list of the layer names whose symmetric difference checkbox
+// has been selected.
+var shortlist_symmetric_difference = [];
+
+// This is the number of symmetric difference checkboxes that have been
+// selected.
+var shortlist_symmetric_difference_num = 0;
+
+// This is an array containing the layer whose absolute complement checkbox
+// has been selected.
+var shortlist_absolute_complement = [];
+
+// This is the number of absolute complement checkboxes that have been selected.
+var shortlist_absolute_complement_num = 0;
+
+// Records number of set-operation clicks
+var set_operation_clicks = 0;
+
+// Boolean stating whether this is the first time the set operation popup
+// has been created so that "Select Layer" Default is added only once
+var first_opening = true;
+
+// Boolean for Creating Layer from Filter
+var created = false;
+
+// Stores the Name of Current Layer Displayed
+var current_layout_name;
+
 // This holds colormaps (objects from layer values to category objects with a 
 // name and color). They are stored under the name of the layer they apply to.
 var colormaps = {}
@@ -118,6 +167,10 @@
     "mousemove"
 ];
 
+// This is a global variable that keeps track of the current Goolge Map zoom
+// This is needed to keep viewing consistent across layouts
+var global_zoom = 0;
+
 function print(text) {
     // Print some logging text to the browser console
         
@@ -130,7 +183,7 @@
 function complain(text) {
     // Display a temporary error message to the user.
     $("#error-notification").text(text);
-    $(".error").show().delay(1000).fadeOut(400);
+    $(".error").show().delay(1250).fadeOut(1000);
     
     if(console && console.error) {
         // Inform the browser console of this problem.as
@@ -400,7 +453,9 @@
         data: data,
         magnitude: undefined
     };
-    
+	
+	var check_layer_exists = layers[layer_name];    
+
     for(var name in attributes) {
         // Copy over each specified attribute
         layers[layer_name][name] = attributes[name];
@@ -422,6 +477,7 @@
     // First get what we have stored for the layer
     var layer = layers[layer_name];
     
+	var data_val = layer.data;
     if(layer.data == undefined) {
         // We need to download the layer.
         print("Downloading \"" + layer.url + "\"");
@@ -571,6 +627,7 @@
     // Return a jQuery element representing the layer with the given name in the
     // shortlist UI.
     
+
     // This holds the root element for this shortlist UI entry
     var root = $("<div/>").addClass("shortlist-entry");
     root.data("layer", layer_name);
@@ -610,14 +667,15 @@
     fill_layer_metadata(metadata_holder, layer_name);
     
     contents.append(metadata_holder);
-    
-    // Add a div to hold the filtering stuff so it wraps together.
+
+	// Add a div to hold the filtering stuff so it wraps together.
     var filter_holder = $("<div/>").addClass("filter-holder");
     
     // Add an image label for the filter control.
-    // TODO: put this in a label
-    var filter_image = $("<img/>").attr("src", "filter.svg")
+    // TODO: put this in a label    
+	var filter_image = $("<img/>").attr("src", "filter.svg");
     filter_image.addClass("control-icon");
+	filter_image.addClass("filter-image");
     filter_image.attr("title", "Filter on Layer");
     filter_image.addClass("filter");
     
@@ -636,9 +694,16 @@
     
     // Add a select input to pick from a discrete list of values to filter on
     var filter_value = $("<select/>").addClass("filter-value");
-    filter_holder.append(filter_value);
-    
-    contents.append(filter_holder);
+	filter_holder.append(filter_value);
+
+	// Add a image for the save function
+	var save_filter = $("<img/>").attr("src", "save.svg");
+	save_filter.addClass("save-filter");
+	save_filter.attr("title", "Save Filter as Layer");
+
+	contents.append(filter_holder);
+	contents.append(save_filter);
+
     if(layers[layer_name].selection) {
         // We can do statistics on this layer.
         
@@ -738,17 +803,18 @@
         
         // Remove this from the DOM
         root.remove();
-        
+
         // Make the UI match the list.
         update_shortlist_ui();
-        
+
         if(checkbox.is(":checked") || filter_control.is(":checked")) {
             // Re-draw the view since we were selected (as coloring or filter) 
             // before removal.
             refresh();
         }
+
     });
-    
+
     // Functionality for turning filtering on and off
     filter_control.change(function() {
         if(filter_control.is(":checked")) {
@@ -793,14 +859,43 @@
                     filter_threshold.show();
                 }
                 
-                // Now that the right controls are there, assume they have 
+				save_filter.show ();
+						
+				save_filter.button().click(function() {
+				// Configure Save Filter Buttons
+
+					// Get selected value
+					var selected = filter_value.prop("selectedIndex");
+					var value = filter_value.val();
+
+					var signatures = [];
+
+					// Gather Tumor-ID Signatures with value and push to "signatures"
+					for (hex in polygons){
+						if (layer.data[hex] == value){
+								signatures.push(hex);
+						}		
+					}
+
+					// Create Layer
+					if (created == false) {
+						select_list (signatures, "user selection");	
+						created = true;
+					}
+					created = false;			
+				}); 	
+			    
+	
+				// Now that the right controls are there, assume they have 
                 refresh();
+
             });
         } else {
+			created = false;
             // Hide the filtering settings
             filter_value.hide();
             filter_threshold.hide();
-            
+            save_filter.hide();
             // Draw view since we're no longer filtering on this layer.
             refresh();
         }
@@ -845,6 +940,331 @@
     return root;
 }
 
+// ____________________________________________________________________________
+// Replacement Set Operation Code
+// ____________________________________________________________________________
+function get_set_operation_selection () {
+	// For the new dop-down GUI for set operation selection
+	// we neeed a function to determine which set operation is selected.
+	// This way we can display the appropriate divs.	
+	
+	// Drop Down List & Index for Selected Element
+	var drop_down = document.getElementById("set-operations-list");
+	var index = drop_down.selectedIndex;
+	var selection = drop_down.options[index];
+	
+	return selection;	
+}
+
+function show_set_operation_drop_down () {
+	// Show Set Operation Drop Down Menu
+	document.getElementsByClassName("set-operation-col")[0].style.visibility="visible";
+	document.getElementsByClassName("set-operation-panel-holder")[0].style.visibility="visible";
+	document.getElementsByClassName("set-operation-panel")[0].style.visibility="visible";
+	document.getElementById("set-operations").style.visibility="visible";
+	document.getElementsByClassName("set-operation-panel-title")[0].style.visibility="visible";
+	document.getElementsByClassName("set-operation-panel-contents")[0].style.visibility="visible";
+
+}
+
+function hide_set_operation_drop_down () {
+	// Hide Set Operation Drop Down Menu
+	document.getElementsByClassName("set-operation-col")[0].style.visibility="hidden";
+	document.getElementsByClassName("set-operation-panel-holder")[0].style.visibility="hidden";
+	document.getElementsByClassName("set-operation-panel")[0].style.visibility="hidden";
+	document.getElementById("set-operations").style.visibility="hidden";
+	document.getElementsByClassName("set-operation-panel-title")[0].style.visibility="hidden";
+	document.getElementsByClassName("set-operation-panel-contents")[0].style.visibility="hidden";
+
+	// Hide the Data Values for the Selected Layers
+	var drop_downs_layer_values = document.getElementsByClassName("set-operation-layer-value");
+	for (var i = 0; i < drop_downs_layer_values.length; i++) {
+				drop_downs_layer_values[i].style.visibility="hidden";
+	}
+
+	// Hide the Compute Button
+	var compute_button = document.getElementsByClassName("compute-button");
+	compute_button[0].style.visibility = "hidden";
+
+	// Set the "Select Layer" drop down to the default value
+	var list = document.getElementById("set-operations-list");
+	list.selectedIndex = 0;
+	
+	var list_value = document.getElementsByClassName("set-operation-value");
+	list_value[0].selectedIndex = 0;
+	list_value[1].selectedIndex = 0;
+
+	// Remove all elements from drop downs holding the data values for the 
+	// selected layers. This way there are no values presented when the user
+	// clicks on the set operation button to open it again.
+	var set_operation_layer_values = document.getElementsByClassName("set-operation-layer-value");
+	var length = set_operation_layer_values[0].options.length;
+	do{
+		set_operation_layer_values[0].remove(0);
+		length--;		
+	}
+	while (length > 0);
+
+	var length = set_operation_layer_values[1].options.length;
+	do{
+		set_operation_layer_values[1].remove(0);
+		length--;		
+	}
+	while (length > 0);
+	
+}
+
+function create_set_operation_ui () {
+	// Returns a Jquery element that is then prepended to the existing 
+	// set theory drop-down menu	
+
+    // This holds the root element for this set operation UI 
+    var root = $("<div/>").addClass("set-operation-entry");
+	
+	// Add Drop Downs to hold the selected layers and and selected data values 
+    var set_theory_value1 = $("<select/>").addClass("set-operation-value");
+	var set_theory_layer_value1 = $("<select/>").addClass("set-operation-layer-value");
+	var set_theory_value2 = $("<select/>").addClass("set-operation-value");	
+	var set_theory_layer_value2 = $("<select/>").addClass("set-operation-layer-value");
+
+	var compute_button = $("<input/>").attr("type", "button");
+	compute_button.addClass ("compute-button");
+
+	// Append to Root
+	root.append (set_theory_value1);
+	root.append (set_theory_layer_value1);
+	root.append (set_theory_value2);
+	root.append (set_theory_layer_value2);
+	root.append (compute_button);
+
+	return root;
+}
+
+function update_set_operation_drop_down () {
+	// This is the onchange command for the drop down displaying the 
+	// different set operation functions. It is called whenever the user changes
+	// the selected set operation.
+
+	// Get the value of the set operation selection made by the user.
+	var selection = get_set_operation_selection();
+	var value = selection.value;	
+	// Check if the selectin value is that of one of set operation functions
+	if (selection.value == 1 || selection.value == 2 
+		|| selection.value == 3 || selection.value == 4
+		|| selection.value == 5){
+			// Make the drop downs that hold layer names and data values visible
+			var drop_downs = document.getElementsByClassName("set-operation-value");
+			var drop_downs_layer_values = document.getElementsByClassName("set-operation-layer-value");
+
+			for (var i = 0; i < drop_downs.length; i++) {
+				drop_downs[i].style.visibility="visible";
+			}
+			
+			for (var i = 0; i < drop_downs_layer_values.length; i++) {
+				drop_downs_layer_values[i].style.visibility="visible";
+			}
+
+			var compute_button = document.getElementsByClassName("compute-button");
+			compute_button[0].style.visibility = "visible";
+			compute_button[0].value = "Compute Set Operation";
+
+			if (first_opening == true) {
+				// Set the default value for the drop down, holding the selected layers
+				var default_value = document.createElement("option");
+				default_value.text = "Select Layer 1";
+				default_value.value = 0;
+				drop_downs[0].add(default_value);
+
+				var default_value2 = document.createElement("option");
+				default_value2.text = "Select Layer 2";
+				default_value2.value = 0;
+				drop_downs[1].add(default_value2);
+				
+				// Prevent from adding the default value again
+				first_opening = false;
+			}
+
+			// Hide the second set of drop downs if "Not:" is selected
+			if (selection.value == 5) {
+				drop_downs[1].style.visibility="hidden";
+				drop_downs_layer_values[1].style.visibility="hidden";
+			}
+	}	
+	else {
+		// If the user has the default value selected, hide all drop downs
+		var drop_downs = document.getElementsByClassName("set-operation-value");
+		for (var i = 0; i < drop_downs.length; i++) {
+			drop_downs[i].style.visibility="hidden";
+		}
+		var drop_downs_layer_values = document.getElementsByClassName("set-operation-layer-value");
+		for (var i = 0; i < drop_downs_layer_values.length; i++) {
+				drop_downs_layer_values[i].style.visibility="hidden";
+		}
+		var compute_button = document.getElementsByClassName("compute-button");
+			compute_button[0].style.visibility = "hidden";
+	}
+}
+
+function update_set_operation_selections () {
+	// This function is called when the shorlist is changed.
+	// It appropriately updates the drop down containing the list of layers
+	// to match the layers found in the shortlist.
+
+	// Get the list of all layers
+	var layers = [];
+	$("#shortlist").children().each(function(index, element) {
+	 	// Get the layer name
+        var layer_name = $(element).data("layer");
+		layers.push(layer_name);
+	});
+
+	// Get a list of all drop downs that contain layer names
+	var drop_downs = document.getElementsByClassName("set-operation-value");
+
+	// Remove all existing layer names from both dropdowns
+	var length = drop_downs[0].options.length;
+	do{
+		drop_downs[0].remove(0);
+		length--;		
+	}
+	while (length > 0);
+	var length = drop_downs[1].options.length;
+	do{
+		drop_downs[1].remove(0);
+		length--;		
+	}
+	while (length > 0);
+
+	// Add the default values that were stripped in the last step.
+	var default_value = document.createElement("option");
+	default_value.text = "Select Layer 1";
+	default_value.value = 0;
+	drop_downs[0].add(default_value);
+
+	var default_value2 = document.createElement("option");
+	default_value2.text = "Select Layer 2";
+	default_value2.value = 0;
+	drop_downs[1].add(default_value2);
+	
+	first_opening = false;
+	
+	// Add the layer names from the shortlist to the drop downs that store
+	// layer names.		
+	for (var i = 0; i < drop_downs.length; i++){
+		for (var j = 0; j < layers.length; j++) {
+			var option = document.createElement("option");
+			option.text = layers[j];
+			option.value = j+1;
+			drop_downs[i].add(option);
+		}
+	}
+
+	// Remove all elements from drop downs holding the data values for the 
+	// selected layers. This way there are no values presented when the user
+	// clicks on the set operation button to open it again.
+	var set_operation_layer_values = document.getElementsByClassName("set-operation-layer-value");
+	var length = set_operation_layer_values[0].options.length;
+	do{
+		set_operation_layer_values[0].remove(0);
+		length--;		
+	}
+	while (length > 0);
+
+	var length = set_operation_layer_values[1].options.length;
+	do{
+		set_operation_layer_values[1].remove(0);
+		length--;		
+	}
+	while (length > 0);
+
+	// Call the function containing onchange commands for these dropdowns.
+	// This way the data values are updated according the the selected layer.
+	update_set_operation_data_values ();
+}
+
+function update_set_operation_data_values () {
+	// Define the onchange commands for the drop downs that hold layer names.
+	// This way the data values are updated according the the selected layer.
+
+	// Get all drop down elements
+	var selected_function = document.getElementById ("set-operations-list");
+	var drop_downs = document.getElementsByClassName("set-operation-value");
+	var set_operation_layer_values = document.getElementsByClassName("set-operation-layer-value");
+
+	// The "Select Layer1" Dropdown onchange function
+	drop_downs[0].onchange = function(){
+		// Strip current values of the data value dropdown
+		var length = set_operation_layer_values[0].options.length;
+		do{
+			set_operation_layer_values[0].remove(0);
+			length--;		
+		}
+		while (length > 0);
+	
+		// Add the data values depending on the selected layer
+		var selectedIndex = drop_downs[0].selectedIndex;
+		var layer_name = drop_downs[0].options[selectedIndex].text;
+		var set_operation_data_value_select = set_operation_layer_values[0];
+		create_set_operation_pick_list(set_operation_data_value_select, layer_name);
+	};
+
+	// The "Select Layer2" Dropdown onchange function
+	drop_downs[1].onchange = function(){
+		// Strip current values of the data value dropdown
+		var length = set_operation_layer_values[1].options.length;
+		do{
+			set_operation_layer_values[1].remove(0);
+			length--;		
+		}
+		while (length > 0);
+
+		// Add the data values depending on the selected layer
+		var selectedIndex = drop_downs[1].selectedIndex;
+		var layer_name = drop_downs[1].options[selectedIndex].text;
+		var set_operation_data_value_select = set_operation_layer_values[1];
+		create_set_operation_pick_list(set_operation_data_value_select, layer_name);
+	};
+
+}
+
+function create_set_operation_pick_list(value,layer_object) {
+
+	// We must create a drop down containing the data values for the selected
+	// layer.
+
+	// The Javascript "select" element that contains the data values
+	// is passed as "value" and the selected layer is passed as "layer_object". 
+
+	// First, figure out what kind of filter settings we take based on 
+	// what kind of layer we are.
+	with_layer(layer_object, function(layer) {
+                    
+             // No options available. We have to add them.
+             for(var i = 0; i < layer.magnitude + 1; i++) {
+             	// Make an option for each value;
+				var option = document.createElement("option");
+				option.value = i;
+                            
+                if(colormaps[layer_object].hasOwnProperty(i)) {
+                	// We have a real name for this value
+                    option.text = (colormaps[layer_object][i].name);
+                 } else {
+                     // No name. Use the number.
+                     option.text = i;
+                     }  
+                 value.add(option);
+     
+                 // Select the last option, so that 1 on 0/1 layers will 
+                 // be selected by default.
+				 var last_index = value.options.length - 1;
+                 value.selectedIndex = last_index;   
+                }                
+            // Now that the right controls are there, assume they have 
+            refresh();
+     });
+}
+
+
 function update_shortlist_ui() {
     // Go through the shortlist and make sure each layer there has an entry in 
     // the shortlist UI, and that each UI element has an entry in the shortlist.
@@ -896,9 +1316,207 @@
         // Sort by the part with the lines icon, so we can still select text.
         handle: ".shortlist-controls" 
     });
-    
+
+	update_set_operation_selections ();   
+}
+
+function uncheck_checkbox (checkbox_class) {
+	// Unchecks chekboxes after the function has been completed.
+	var checkboxArray = new Array ();
+	checkboxArray = document.getElementsByClassName(checkbox_class);
+	for (var i = 0; i < checkboxArray.length; i++)
+	{
+		checkboxArray[i].checked = false;
+	}
+}	
+
+function hide_values (set_theory_function) {
+	// Hides pick lists for set theory functions after function has been 
+	// completed.
+	var value_type = set_theory_function + '-value';
+
+	var values = new Array ();
+
+	values = document.getElementsByClassName(value_type);
+	
+	var length = values.length;
+
+	for (var i = 0; i < length; i++)
+	{
+		values[i].style.display = 'none';
+	}
+	refresh();
+}	
+
+function compute_intersection (values, intersection_layer_names, text) {
+	// A function that will take a list of layer names
+	// that have been selected for the intersection utility.
+	// Fetches the respective layers and list of tumor ids.
+	// Then compares data elements of the same tumor id
+	// between both layers. Adds these hexes to a new layer
+	// for visualization
+	
+	//Array of signatures that intersect 
+	var intersection_signatures = [];
+
+	with_layers (intersection_layer_names, function (intersection_layers) {
+	
+		// Gather Tumor-ID Signatures.
+		for (hex in polygons)
+		{
+			if (intersection_layers[0].data[hex] == values[0] && intersection_layers[1].data[hex] == values[1]){
+				intersection_signatures.push(hex);
+			}		
+		}
+	});
+
+	for (var i = 0; i < intersection_layer_names.length; i++){
+		intersection_layer_names[i] = intersection_layer_names[i] + " [" + text[i] + "]";
+	}
+	var intersection_function = "intersection";
+	select_list (intersection_signatures, intersection_function, intersection_layer_names);
+	uncheck_checkbox ('intersection-checkbox');
+	hide_values('intersection');
+}
+
+function compute_union (values, union_layer_names, text) {
+	// A function that will take a list of layer names
+	// that have been selected for the union utility.
+	// Fetches the respective layers and list of tumor ids.
+	// Then compares data elements of the same tumor id
+	// between both layers. Adds these hexes to a new layer
+	// for visualization
+	
+	//Array of signatures 
+	var union_signatures = [];
+
+	with_layers (union_layer_names, function (union_layers) {
+	
+		// Gather Tumor-ID Signatures.
+		for (hex in polygons)
+		{
+			// Union Function
+			if (union_layers[0].data[hex] == values[0] || union_layers[1].data[hex] == values[1]){
+				union_signatures.push(hex);
+			}		
+		}
+	});
+	
+	for (var i = 0; i < union_layer_names.length; i++){
+		union_layer_names[i] = union_layer_names[i] + " [" + text[i] + "]";
+	}
+
+	var union_function = "union";
+	select_list (union_signatures, union_function, union_layer_names);
+	uncheck_checkbox ('union-checkbox');
+	hide_values('union');
 }
 
+function compute_set_difference (values, set_difference_layer_names, text) {
+	// A function that will take a list of layer names
+	// that have been selected for the set difference utility.
+	// Fetches the respective layers and list of tumor ids.
+	// Then compares data elements of the same tumor id
+	// between both layers. Adds these hexes to a new layer
+	// for visualization
+	
+	//Array of signatures  
+	var set_difference_signatures = [];
+
+	with_layers (set_difference_layer_names, function (set_difference_layers) {
+	
+		// Gather Tumor-ID Signatures.
+		for (hex in polygons)
+		{
+			// Set Difference Function
+			if (set_difference_layers[0].data[hex] == values[0] && 
+				set_difference_layers[1].data[hex] != values[1]){
+				set_difference_signatures.push(hex);
+			}
+		}
+	});
+	
+	for (var i = 0; i < set_difference_layer_names.length; i++){
+		set_difference_layer_names[i] = set_difference_layer_names[i] + " [" + text[i] + "]";
+	}
+
+	var set_difference_function = "set difference";
+	select_list (set_difference_signatures, set_difference_function, set_difference_layer_names);
+	uncheck_checkbox ('set-difference-checkbox');
+	hide_values('set-difference');
+}
+
+function compute_symmetric_difference (values, symmetric_difference_layer_names, text) {
+	// A function that will take a list of layer names
+	// that have been selected for the set difference utility.
+	// Fetches the respective layers and list of tumor ids.
+	// Then compares data elements of the same tumor id
+	// between both layers. Adds these hexes to a new layer
+	// for visualization
+	
+	//Array of signatures 
+	var symmetric_difference_signatures = [];
+
+	with_layers (symmetric_difference_layer_names, function (symmetric_difference_layers) {
+	
+		// Gather Tumor-ID Signatures.
+		for (hex in polygons)
+		{
+			// Symmetric Difference Function
+			if (symmetric_difference_layers[0].data[hex] == values[0] && 
+				symmetric_difference_layers[1].data[hex] != values[1]){
+				symmetric_difference_signatures.push(hex);
+			}
+			if (symmetric_difference_layers[0].data[hex] != values[0] &&
+				symmetric_difference_layers[1].data[hex] == values[1]){
+				symmetric_difference_signatures.push(hex);
+			}
+		}
+	});
+	
+	for (var i = 0; i < symmetric_difference_layer_names.length; i++){
+		symmetric_difference_layer_names[i] = symmetric_difference_layer_names[i] + " [" + text[i] + "]";
+	}
+
+	var symmetric_difference_function = "symmetric difference";
+	select_list (symmetric_difference_signatures, symmetric_difference_function, symmetric_difference_layer_names);
+	uncheck_checkbox ('symmetric-difference-checkbox');
+	hide_values('symmetric-difference');
+}
+
+function compute_absolute_complement (values, absolute_complement_layer_names, text) {
+	// A function that will take a list of layer names
+	// that have been selected for the set difference utility.
+	// Fetches the respective layers and list of tumor ids.
+	// Then compares data elements of the same tumor id
+	// between both layers. Adds these hexes to a new layer
+	// for visualization
+	
+	//Array of signatures 
+	var absolute_complement_signatures = [];
+
+	with_layers (absolute_complement_layer_names, function (absolute_complement_layers) {
+	
+		// Gather Tumor-ID Signatures.
+		for (hex in polygons)
+		{
+			// Absolute Complement Function
+			if (absolute_complement_layers[0].data[hex] != values[0]) {
+				absolute_complement_signatures.push(hex);
+			}
+		}
+	});
+	
+	for (var i = 0; i < absolute_complement_layer_names.length; i++){
+		absolute_complement_layer_names[i] = absolute_complement_layer_names[i] + " [" + text[i] + "]";
+	}
+	var absolute_complement_function = "absolute complement";
+	select_list (absolute_complement_signatures, absolute_complement_function, absolute_complement_layer_names);
+	uncheck_checkbox ('absolute-complement-checkbox');
+	hide_values('absolute-complement');
+}
+
+
 function layer_sort_order(a, b) {
     // A sort function defined on layer names.
     // Return <0 if a belongs before b, >0 if a belongs after
@@ -1010,7 +1628,7 @@
     }
     
     // We couldn't find a difference in selection status, p-value, or clumpiness
-    // score, or the binary layer minor value frequency, or whether eqach layer
+    // score, or the binary layer minor value frequency, or whether each layer
     // *had* a binary layer minor value frequency, so use lexicographic ordering
     // on the name.
     return a.localeCompare(b);
@@ -1072,7 +1690,9 @@
         // Do some transformations to make the displayed labels make more sense
         lookup = {
             n: "Number of non-empty values",
-            positives: "Number of ones"
+            positives: "Number of ones",
+            inside_yes: "Ones in A",
+            outside_yes: "Ones in background"
         }
         
         if(lookup[attribute]) {
@@ -1089,6 +1709,21 @@
     }
 }
 
+function make_toggle_layout_ui(layout_name) {
+    // Returns a jQuery element to represent the layer layout the given name in 
+    // the toggle layout panel.
+    
+    // This holds a jQuery element that's the root of the structure we're
+    // building.
+    var root = $("<div/>").addClass("layout-entry");
+    root.data("layout-name", layout_name);
+    
+    // Put in the layer name in a div that makes it wrap.
+    root.append($("<div/>").addClass("layout-name").text(layout_name));
+ 
+    return root;
+}
+
 function make_browse_ui(layer_name) {
     // Returns a jQuery element to represent the layer with the given name in 
     // the browse panel.
@@ -1270,6 +1905,134 @@
     return current_filters;
 }
 
+function get_current_layers() {
+    // Returns an array of the string names of the layers that are currently
+    // supposed to be displayed, according to the shortlist UI.
+    // Not responsible for enforcing maximum selected layers limit.
+    
+    // This holds a list of the string names of the currently selected layers,
+    // in order.
+    var current_layers = [];
+    
+    $("#shortlist").children().each(function(index, element) {
+        // This holds the checkbox that determines if we use this layer
+        var checkbox = $(element).find(".layer-on");
+        if(checkbox.is(":checked")) {
+            // Put the layer in if its checkbox is checked.
+            current_layers.push($(element).data("layer"));
+        }
+    });
+    
+    // Return things in reverse order relative to the UI.
+    // Thus, layer-added layers will be "secondary", and e.g. selecting 
+    // something with only tissue up behaves as you might expect, highlighting 
+    // those things.
+    current_layers.reverse();
+    
+    return current_layers;
+}
+
+function get_current_set_theory_layers(function_type) {
+    // Returns an array of layer names that have been selected.
+	// This function only looks at the layers that are listed on the shortlist.
+
+    var current_set_theory_layers = [];
+
+	// Initialize global variables that hold the number of checkboxes selected
+	// for set theory functions to zero so that the new number is calculated
+	// each time this function is called.
+	
+	if (function_type == "intersection"){
+	shortlist_intersection_num = 0;
+	}
+
+	if (function_type == "union"){
+	shortlist_union_num = 0;
+	}
+
+	if (function_type == "set difference"){
+	shortlist_set_difference_num = 0;
+	}
+
+	if (function_type == "symmetric difference"){
+	shortlist_symmetric_difference_num = 0;
+	}
+
+	if (function_type == "absolute complement"){
+	shortlist_absolute_complement_num = 0;
+	}
+	
+    $("#shortlist").children().each(function(index, element) {
+        // Go through all the shortlist entries.
+
+        // This holds the checkbox that determines if we use this layer
+		// The class name depends on the function_type.   
+
+		// If intersection function look for intersection-checkbox.
+		if (function_type == "intersection"){  
+		var checkbox = $(element).find(".intersection-checkbox");
+		}
+
+		// If union function look for union-checkbox.
+		if (function_type == "union"){  
+		var checkbox = $(element).find(".union-checkbox");
+		}
+
+		// If set difference function look for set-difference-checkbox.
+		if (function_type == "set difference"){  
+		var checkbox = $(element).find(".set-difference-checkbox");
+		}
+
+		// If symmetric difference function look for 
+		// symmetric-difference-checkbox.
+		if (function_type == "symmetric difference"){  
+		var checkbox = $(element).find(".symmetric-difference-checkbox");
+		}
+
+		if (function_type == "absolute complement"){  
+		var checkbox = $(element).find(".absolute-complement-checkbox");
+		}
+
+        if(checkbox.is(":checked")) {
+            // Put the layer in if its checkbox is checked.
+            
+		
+            // Get the layer name
+            var layer_name = $(element).data("layer");
+           
+            // Add the layer_name to the list of current_set_theory_layers.
+            current_set_theory_layers.push(layer_name);
+
+			// Add to the global "num" variables to keep track of the number
+			// of selected checkboxes.
+
+			if (function_type == "intersection"){
+				shortlist_intersection_num++;
+			}
+				
+			if (function_type == "union"){
+				shortlist_union_num++;
+			}
+
+			if (function_type == "set difference"){  
+				shortlist_set_difference_num++;
+			}
+
+			if (function_type == "symmetric difference"){  
+				shortlist_symmetric_difference_num++;
+			}
+
+			if (function_type == "absolute complement"){  
+				shortlist_absolute_complement_num++;
+			}
+
+        }
+    });
+    
+    return current_set_theory_layers;
+}
+
+
 function with_filtered_signatures(filters, callback) {
     // Takes an array of filters, as produced by get_current_filters. Signatures 
     // pass a filter if the filter's layer has a value >0 for that signature. 
@@ -1322,10 +2085,18 @@
     });
 }
 
-function select_list(to_select) {
+function select_list(to_select, function_type, layer_names) {
     // Given an array of signature names, add a new selection layer containing
     // just those hexes. Only looks at hexes that are not filtered out by the
     // currently selected filters.
+	
+	// function_type is an optional parameter. If no variable is passed for the 
+	// function_type undefined then the value will be undefined and the
+	// default "selection + #" title will be assigned to the shortlist element.
+	// If layer_names is undefined, the "selection + #" will also apply as a
+	// default. However, if a value i.e. "intersection" is passed 
+	// for function_type, the layer_names will be used along with the 
+	// function_type to assign the correct title. 
     
     // Make the requested signature list into an object for quick membership
     // checking. This holds true if a signature was requested, undefined
@@ -1365,10 +2136,57 @@
             }
         }
         
-        // Make up a name for the layer
-        var layer_name = "Selection " + selection_next_id;
-        selection_next_id++;
+		// Make up a name for the layer
+		var layer_name;
+
+		// Default Values for Optional Parameters
+		if (function_type == undefined && layer_names == undefined){		
+        	layer_name = "Selection " + selection_next_id;
+        	selection_next_id++;
+		}
+
+		if (function_type == "user selection"){
+			 var text = prompt("Please provide a label for your selection",
+			 "Selection Label Text");
+			 if (text != null){
+			 	layer_name = text;
+			 }
+			 if (!text)
+			 {
+				return;
+			 }			
+		}
+		
+		// intersection for layer name
+		if (function_type == "intersection"){
+			layer_name = "(" + layer_names[0] + " ∩ " + layer_names[1] + ")";
+		}
+
+		// union for layer name
+		if (function_type == "union"){
+			layer_name = "(" + layer_names[0] + " U " + layer_names[1] + ")";
+		}
+
+		// set difference for layer name
+		if (function_type == "set difference"){
+			layer_name = "(" + layer_names[0] + " \\ " + layer_names[1] + ")";
+		}
+
+		// symmetric difference for layer name
+		if (function_type == "symmetric difference"){
+			layer_name = "(" + layer_names[0] + " ∆ " + layer_names[1] + ")";
+		}
         
+		// absolute complement for layer name
+		if (function_type == "absolute complement"){
+			layer_name = "Not: " + "(" + layer_names[0] + ")";
+		}
+
+		// saved filter for layer name
+		if (function_type == "save"){
+			layer_name =  "(" + layer_names[0] + ")";
+		}
+		
         // Add the layer. Say it is a selection
         add_layer_data(layer_name, data, {
             selection: true,
@@ -1434,7 +2252,8 @@
     // Now we have an array of the signatures that ought to be in the selection
     // (if they pass filters). Hand it off to select_list.
     
-    select_list(in_box);
+	var select_function_type = "user selection";
+    select_list(in_box, select_function_type);
     
 }
 
@@ -1551,8 +2370,14 @@
     
     // This holds a callback for setting the layer's p_value to the result of
     // the statistics.
-    var callback = function(result) {
-        layers[layer_name].p_value = result;
+    var callback = function(results) {
+        
+        // The statistics code really sends back a dict of updated metadata for
+        // each layer. Copy it over.
+        for(var metadata in results) {
+            layers[layer_name][metadata] = results[metadata];
+        }
+        
         if(jobs_running == 0) {
             // All statistics are done!
             // TODO: Unify this code with similar callback below.
@@ -1592,8 +2417,11 @@
         
         // The return value is p values by layer name
         for(var layer_name in result) {
-            // Copy over p values
-            layers[layer_name].p_value = result[layer_name];
+            // The statistics code really sends back a dict of updated metadata
+            // for each layer. Copy it over.
+            for(var metadata in result[layer_name]) {
+                layers[layer_name][metadata] = result[layer_name][metadata];
+            }
         }
         
         if(jobs_running == 0) {
@@ -1705,7 +2533,7 @@
         " column " + error.column);
 }
 
-function initialize_view() {
+function initialize_view(initial_zoom) {
     // Initialize the global Google Map.
     
     // Configure a Google map
@@ -1713,7 +2541,7 @@
         // Look at the center of the map
         center: get_LatLng(128, 128),
         // Zoom all the way out
-        zoom: 0,
+        zoom: initial_zoom,
         mapTypeId: "blank",
         // Don't show a map type picker.
         mapTypeControlOptions: {
@@ -2408,13 +3236,196 @@
         new google.maps.Point(x, y));
 }
 
+function clearMap() {
+
+}
+
+function drl_values(layout_index) {
+
+	// Download the DrL position data, and make it into a layer
+    $.get("drl"+ layout_index +".tab", function(tsv_data) {
+        // This is an array of rows, which are arrays of values:
+        // id, x, y
+        // Only this time X and Y are Cartesian coordinates.
+        var parsed = $.tsv.parseRows(tsv_data);
+        
+        // Compute two layers: one for x position, and one for y position.
+        var layer_x = {};
+        var layer_y = {};
+        
+        for(var i = 0; i < parsed.length; i++) {
+            // Pull out the parts of the TSV entry
+            var label = parsed[i][0];
+            
+            if(label == "") {
+                // DrL ends its output with a blank line, which we skip 
+                // here.
+                continue;
+            }
+            
+            var x = parseFloat(parsed[i][1]);
+            // Invert the Y coordinate since we do that in the hex grid
+            var y = -parseFloat(parsed[i][2]);
+            
+            // Add x and y to the appropriate layers
+            layer_x[label] = x;
+            layer_y[label] = y;
+        }
+        
+        // Register the layers with no priorities. By default they are not 
+        // selections.
+        add_layer_data("DrL X Position", layer_x);
+        add_layer_data("DrL Y Position", layer_y);
+        
+        // Make sure the layer browser has the up-to-date layer list
+        update_browse_ui();
+        
+    }, "text");
+}
+
+function assignment_values (layout_index, spacing) {
+	// Download the signature assignments to hexagons and fill in the global 
+    // hexagon assignment grid.
+    $.get("assignments" + layout_index +".tab", function(tsv_data) {        
+        // This is an array of rows, which are arrays of values:
+        // id, x, y
+        var parsed = $.tsv.parseRows(tsv_data);
+
+        // This holds the maximum observed x
+        var max_x = 0;
+        // And y
+        var max_y = 0;
+        
+        // Fill in the global signature grid and ploygon grid arrays.
+        for(var i = 0; i < parsed.length; i++) {
+            // Get the label
+            var label = parsed[i][0];
+            
+            if(label == "") {
+                // Blank line
+                continue;
+            }
+            
+            // Get the x coord
+            var x = parseInt(parsed[i][1]);
+            // And the y coord
+            var y = parseInt(parsed[i][2]);
+
+			x = x * spacing;
+			y = y * spacing;			
+
+
+            // Update maxes
+            max_x = Math.max(x, max_x);
+            max_y = Math.max(y, max_y);
+           
+
+            // Make sure we have a row
+            if(signature_grid[y] == null) {
+                signature_grid[y] = [];
+                // Pre-emptively add a row to the polygon grid.
+                polygon_grid[y] = [];
+            }
+            
+            // Store the label in the global signature grid.
+            signature_grid[y][x] = label;
+        }
+        
+        // We need to fit this whole thing into a 256x256 grid.
+        // How big can we make each hexagon?
+        // TODO: Do the algrbra to make this exact. Right now we just make a 
+        // grid that we know to be small enough.
+        // Divide the space into one column per column, and calculate 
+        // side length from column width. Add an extra column for dangling
+        // corners.
+        var side_length_x = (256)/ (max_x + 2) * (2.0 / 3.0);
+        
+        print("Max hexagon side length horizontally is " + side_length_x);
+        
+        // Divide the space into rows and calculate the side length
+        // from hex height. Remember to add an extra row for wggle.
+        var side_length_y = ((256)/(max_y + 2)) / Math.sqrt(3);
+        
+        print("Max hexagon side length vertically is " + side_length_y);
+        
+        // How long is a hexagon side in world coords?
+        // Shrink it from the biggest we can have so that we don't wrap off the 
+        // edges of the map.
+        var hexagon_side_length = Math.min(side_length_x, side_length_y) / 2.0;
+
+        // Store this in the global hex_size, so we can later calculate the hex
+        // size in pixels and make borders go away if we are too zoomed out.
+        hex_size = hexagon_side_length;
+
+        // How far in should we move the whole grid from the top left corner of 
+        // the earth?
+        // Let's try leaving a 1/4 Earth gap at least, to stop wrapping in 
+        // longitude that we can't turn off.
+        // Since we already shrunk the map to half max size, this would put it 
+        // 1/4 of the 256 unit width and height away from the top left corner.
+        grid_offset = (256) / 4;
+        
+        // Loop through again and draw the polygons, now that we know how big 
+        // they have to be
+        for(var i = 0; i < parsed.length; i++) {
+            // TODO: don't re-parse this info
+            // Get the label
+            var label = parsed[i][0];
+            
+            if(label == "") {
+                // Blank line
+                continue;
+            }
+            
+            // Get the x coord
+            var x = parseInt(parsed[i][1]);
+            // And the y coord
+            var y = parseInt(parsed[i][2]);
+
+			x = x * spacing;
+			y = y * spacing;			
+
+            // Make a hexagon on the Google map and store that.
+            var hexagon = make_hexagon(y, x, hexagon_side_length, grid_offset);
+            // Store by x, y in grid
+            polygon_grid[y][x] = hexagon;
+            // Store by label
+            polygons[label] = hexagon;
+            
+            // Set the polygon's signature so we can look stuff up for it when 
+            // it's clicked.
+            set_hexagon_signature(hexagon, label);     
+            
+        }
+        
+        // Now that the ploygons exist, do the initial redraw to set all their 
+        // colors corectly. In case someone has messed with the controls.
+        // TODO: can someone yet have messed with the controlls?
+        refresh();
+        
+
+    }, "text");
+}
+
+// Function to create a new map based upon the the layout_name argument
+// Find the index of the layout_name and pass it as the index to the 
+// drl_values and assignment_values functions as these files are indexed
+// according to the appropriate layout
+function recreate_map(layout_name, spacing) {
+
+	var layout_index = layout_names.indexOf(layout_name);
+	drl_values(layout_index);
+	assignment_values(layout_index, spacing);
+
+}
+
 $(function() {
 
     // Set up the RPC system for background statistics
     rpc_initialize();
 
     // Set up the Google Map
-    initialize_view();
+    initialize_view(0);
     
     // Set up the layer search
     $("#search").select2({
@@ -2474,7 +3485,7 @@
         // We want our dropdown to be big enough to browse.
         dropdownCssClass: "results-dropdown"
     });
-    
+
     // Handle result selection
     $("#search").on("select2-selecting", function(event) {
         // The select2 id of the thing clicked (the layer's name) is event.val
@@ -2521,164 +3532,84 @@
             // Find everything passing the filters and run the statistics.
             recalculate_statistics(signatures);
         });
-    });
-
-    // Download the signature assignments to hexagons and fill in the global 
-    // hexagon assignment grid.
-    $.get("assignments.tab", function(tsv_data) {        
-        // This is an array of rows, which are arrays of values:
-        // id, x, y
-        var parsed = $.tsv.parseRows(tsv_data);
-
-        // This holds the maximum observed x
-        var max_x = 0;
-        // And y
-        var max_y = 0;
-        
-        // Fill in the global signature grid and ploygon grid arrays.
-        for(var i = 0; i < parsed.length; i++) {
-            // Get the label
-            var label = parsed[i][0];
-            
-            if(label == "") {
-                // Blank line
-                continue;
-            }
-            
-            // Get the x coord
-            var x = parseInt(parsed[i][1]);
-            // And the y coord
-            var y = parseInt(parsed[i][2]);
-
-
-            // Update maxes
-            max_x = Math.max(x, max_x);
-            max_y = Math.max(y, max_y);
-            
-
-            // Make sure we have a row
-            if(signature_grid[y] == null) {
-                signature_grid[y] = [];
-                // Pre-emptively add a row to the polygon grid.
-                polygon_grid[y] = [];
-            }
-            
-            // Store the label in the global signature grid.
-            signature_grid[y][x] = label;
-        }
-        
-        // We need to fit this whole thing into a 256x256 grid.
-        // How big can we make each hexagon?
-        // TODO: Do the algrbra to make this exact. Right now we just make a 
-        // grid that we know to be small enough.
-        // Divide the space into one column per column, and calculate 
-        // side length from column width. Add an extra column for dangling
-        // corners.
-        var side_length_x = 256 / (max_x + 2) * (2.0 / 3.0);
-        
-        print("Max hexagon side length horizontally is " + side_length_x);
-        
-        // Divide the space into rows and calculate the side length
-        // from hex height. Remember to add an extra row for wggle.
-        var side_length_y = (256 / (max_y + 2)) / Math.sqrt(3);
-        
-        print("Max hexagon side length vertically is " + side_length_y);
-        
-        // How long is a hexagon side in world coords?
-        // Shrink it from the biggest we can have so that we don't wrap off the 
-        // edges of the map.
-        var hexagon_side_length = Math.min(side_length_x, side_length_y) / 2.0;
-
-        // Store this in the global hex_size, so we can later calculate the hex
-        // size in pixels and make borders go away if we are too zoomed out.
-        hex_size = hexagon_side_length;
-
-        // How far in should we move the whole grid from the top left corner of 
-        // the earth?
-        // Let's try leaving a 1/4 Earth gap at least, to stop wrapping in 
-        // longitude that we can't turn off.
-        // Since we already shrunk the map to half max size, this would put it 
-        // 1/4 of the 256 unit width and height away from the top left corner.
-        grid_offset = 256 / 4;
-        
-        // Loop through again and draw the polygons, now that we know how big 
-        // they have to be
-        for(var i = 0; i < parsed.length; i++) {
-            // TODO: don't re-parse this info
-            // Get the label
-            var label = parsed[i][0];
-            
-            if(label == "") {
-                // Blank line
-                continue;
-            }
-            
-            // Get the x coord
-            var x = parseInt(parsed[i][1]);
-            // And the y coord
-            var y = parseInt(parsed[i][2]);
-
-            // Make a hexagon on the Google map and store that.
-            var hexagon = make_hexagon(y, x, hexagon_side_length, grid_offset);
-            // Store by x, y in grid
-            polygon_grid[y][x] = hexagon;
-            // Store by label
-            polygons[label] = hexagon;
-            
-            // Set the polygon's signature so we can look stuff up for it when 
-            // it's clicked.
-            set_hexagon_signature(hexagon, label);     
-            
-        }
-        
-        // Now that the ploygons exist, do the initial redraw to set all their 
-        // colors corectly. In case someone has messed with the controls.
-        // TODO: can someone yet have messed with the controlls?
-        refresh();
-        
-
-    }, "text");
-    
-    // Download the DrL position data, and make it into a layer
-    $.get("drl.tab", function(tsv_data) {
-        // This is an array of rows, which are arrays of values:
-        // id, x, y
-        // Only this time X and Y are Cartesian coordinates.
-        var parsed = $.tsv.parseRows(tsv_data);
-        
-        // Compute two layers: one for x position, and one for y position.
-        var layer_x = {};
-        var layer_y = {};
-        
-        for(var i = 0; i < parsed.length; i++) {
-            // Pull out the parts of the TSV entry
-            var label = parsed[i][0];
-            
-            if(label == "") {
-                // DrL ends its output with a blank line, which we skip 
-                // here.
-                continue;
-            }
-            
-            var x = parseFloat(parsed[i][1]);
-            // Invert the Y coordinate since we do that in the hex grid
-            var y = -parseFloat(parsed[i][2]);
-            
-            // Add x and y to the appropriate layers
-            layer_x[label] = x;
-            layer_y[label] = y;
-        }
-        
-        // Register the layers with no priorities. By default they are not 
-        // selections.
-        add_layer_data("DrL X Position", layer_x);
-        add_layer_data("DrL Y Position", layer_y);
-        
-        // Make sure the layer browser has the up-to-date layer list
-        update_browse_ui();
-        
-    }, "text");
-    
+	});
+
+	// Temporary Inflate Button
+	$("#inflate").button().click(function() {
+		initialize_view (0);
+        recreate_map(current_layout_name, 2);
+		refresh ();
+	});
+
+	// Create Pop-Up UI for Set Operations
+	$("#set-operations").prepend(create_set_operation_ui ());
+
+	// Action handler for display of set operation pop-up
+	$("#set-operation").button().click(function() {
+		set_operation_clicks++;
+		if (set_operation_clicks % 2 != 0){
+			show_set_operation_drop_down ();
+			}
+		else {
+			hide_set_operation_drop_down ();
+			var drop_downs = document.getElementsByClassName("set-operation-value");
+				for (var i = 0; i < drop_downs.length; i++) {
+					drop_downs[i].style.visibility="hidden";
+				}
+		}		
+	
+	});
+	
+	// Coputation of Set Operations
+	var compute_button = document.getElementsByClassName ("compute-button");
+	compute_button[0].onclick = function () {
+		var layer_names = [];
+		var layer_values = [];
+		var layer_values_text = [];
+
+		var drop_down_layers = document.getElementsByClassName("set-operation-value");
+		var drop_down_data_values = document.getElementsByClassName("set-operation-layer-value");
+
+		var function_type = document.getElementById("set-operations-list");
+		var selected_function = function_type.selectedIndex;
+
+		var selected_index = drop_down_layers[0].selectedIndex;
+		layer_names.push(drop_down_layers[0].options[selected_index].text);	
+
+		var selected_index = drop_down_data_values[0].selectedIndex;
+		layer_values.push(drop_down_data_values[0].options[selected_index].value);	
+		layer_values_text.push(drop_down_data_values[0].options[selected_index].text);
+
+		if (selected_function != 5) {
+			var selected_index = drop_down_data_values[1].selectedIndex;
+			layer_values.push(drop_down_data_values[1].options[selected_index].value);	
+			layer_values_text.push(drop_down_data_values[1].options[selected_index].text);
+			var selected_index = drop_down_layers[1].selectedIndex;
+			layer_names.push(drop_down_layers[1].options[selected_index].text);
+		}
+		
+
+		switch (selected_function) {
+			case 1:
+				compute_intersection(layer_values, layer_names, layer_values_text);
+				break;
+			case 2:
+				compute_union(layer_values, layer_names, layer_values_text);
+				break;
+			case 3:
+				compute_set_difference(layer_values, layer_names, layer_values_text);
+				break;
+			case 4:
+				compute_symmetric_difference(layer_values, layer_names, layer_values_text);
+				break;
+			case 5:
+				compute_absolute_complement(layer_values, layer_names, layer_values_text);
+				break
+			default:
+				complain ("Set Theory Error");
+		}
+	};
+	   
     // Download the layer index
     $.get("layers.tab", function(tsv_data) {
         // Layer index is <name>\t<filename>\t<clumpiness>
@@ -2796,5 +3727,106 @@
         refresh();
             
     }, "text");
+
+// Download the Matrix Names and pass it to the layout_names array
+	$.get("matrixnames.tab", function(tsv_data) {
+        // This is an array of rows, which are strings of matrix names
+        var parsed = $.tsv.parseRows(tsv_data);
+        
+        for(var i = 0; i < parsed.length; i++) {
+            // Pull out the parts of the TSV entry
+            var label = parsed[i][0];
+
+			if(label == "") {
+                // Skip any blank lines
+                continue;
+            }
+            // Add layout names to global array of names
+            layout_names.push(label);
+        }     
+    }, "text");
+
+	$("#layout-search").select2({
+        placeholder: "Select a Layout...",
+        query: function(query) {
+            // Given a select2 query object, call query.callback with an object
+            // with a "results" array.
+            
+            // This is the array of result objects we will be sending back.
+            var results = [];
+        
+            // Get where we should start in the layer list, from select2's
+            // infinite scrolling.
+            var start_position = 0;
+            if(query.context != undefined) {
+                start_position = query.context;
+            }
+        
+            for(var i = start_position; i < layout_names.length; i++) {
+                // For each possible result
+                if(layout_names[i].toLowerCase().indexOf(
+                    query.term.toLowerCase()) != -1) {
+                    
+                    // Query search term is in this layer's name. Add a select2
+                    // record to our results. Don't specify text: our custom
+                    // formatter looks up by ID and makes UI elements
+                    // dynamically.
+                    results.push({
+                        id: layout_names[i]
+                    });
+                    
+                    if(results.length >= SEARCH_PAGE_SIZE) {
+                        // Page is full. Send it on.
+                        break;
+                    }
+                    
+                }
+            }
+            
+            // Give the results back to select2 as the results parameter.
+            query.callback({
+                results: results,
+                // Say there's more if we broke out of the loop.
+                more: i < layout_names.length,
+                // If there are more results, start after where we left off.
+                context: i + 1
+            });
+        },
+        formatResult: function(result, container, query) {
+            // Given a select2 result record, the element that our results go
+            // in, and the query used to get the result, return a jQuery element
+            // that goes in the container to represent the result.
+            
+            // Get the layer name, and make the browse UI for it.
+            return make_toggle_layout_ui(result.id);
+        },
+        // We want our dropdown to be big enough to browse.
+        dropdownCssClass: "results-dropdown"
+    });
+
+	// Handle result selection
+    $("#layout-search").on("select2-selecting", function(event) {
+        // The select2 id of the thing clicked (the layout's name) is event.val
+        var layout_name = event.val;		
+
+		var current_layout = "Current Layout: " + layout_name;         
+	 
+		document.getElementById('current-layout').innerHTML=current_layout;
+		initialize_view (0);
+        recreate_map(layout_name, 1);
+		refresh ();
+        // Don't actually change the selection.
+        // This keeps the dropdown open when we click.
+        event.preventDefault();
+
+		current_layout_name = layout_name;
+    });
+
+	drl_values(layout_names[0]);
+	assignment_values (layout_names[0], 1);
+	current_layout_name = layout_names[0];
+
 });
 
+
+
--- a/hexagram/hexagram.py	Wed Jun 19 15:04:17 2013 -0400
+++ b/hexagram/hexagram.py	Wed Oct 16 18:48:28 2013 -0400
@@ -7,7 +7,7 @@
 layer/score data. It produces an HTML file (and several support files) that
 provide an interactive visualization of the items clustered on a hexagonal grid.
 
-This script depends on the DrL graph alyout package, binaries for which must be
+This script depends on the DrL graph layout package, binaries for which must be
 present in your PATH.
 
 Re-uses sample code and documentation from 
@@ -15,10 +15,15 @@
 """
 
 import argparse, sys, os, itertools, math, numpy, subprocess, shutil, tempfile
-import collections, scipy.stats, multiprocessing, traceback, numpy.ma
+import collections, multiprocessing, traceback, numpy
+import scipy.stats, scipy.linalg
 import os.path
 import tsv
 
+# Global variable to hold opened matrices files
+matrices = [];
+
+
 def parse_args(args):
     """
     Takes in the command-line arguments list (args), and returns a nice argparse
@@ -42,8 +47,10 @@
     
     # Now add all the options to it
     # Options match the ctdHeatmap tool options as much as possible.
-    parser.add_argument("similarities", type=argparse.FileType("r"), 
-        help="the TSV file with the similarities for signatures we're using")
+    parser.add_argument("similarity", type=str, nargs='+',
+        help="the unopened files of similarity matrices")
+    parser.add_argument("--names", type=str, action="append", default=[],
+        help="the unopened files of similarity matrices")
     parser.add_argument("--scores", type=str,
         action="append", default=[],
         help="a TSV to read scores for each signature from")
@@ -80,7 +87,7 @@
     scale is a float specifying hexagon side length.
     
     The origin in coordinate space is defined as the upper left corner of the 
-    bounding box of the hexagon wityh indices x=0 and y=0.
+    bounding box of the hexagon with indices x=0 and y=0.
     
     Returns a tuple of floats.
     """
@@ -640,124 +647,164 @@
     except:
         # Put all exception text into an exception and raise that
         raise Exception(traceback.format_exc())
-                
-def main(args):
-    """
-    Parses command line arguments, and makes visualization.
-    "args" specifies the program arguments, with args[0] being the executable
-    name. The return value should be used as the program's exit code.
+
+def open_matrices(names):
+	"""
+	The argument parser now take multiple similarity matrices as input and 
+	saves their file name as strings. We want to store the names of these
+	strings for display later in hexagram.js in order to allow the user to 
+	navigate and know what type of visualization map they are looking at -
+	gene expression, copy number, etc. 
+
+	Since, the parser no longer opens the files automatically we must, do it
+	in this function.
+	"""
+
+	# For each file name, open the file and add it to the matrices list
+	# 'r' is the argument stating that the file will be read-only
+	for similarity_filename in  names:
+		print "Opening Matrices..."
+		matrix_file = tsv.TsvReader(open(similarity_filename, "r")) 
+		matrices.append(matrix_file)
+
+def compute_beta (coords, matrix, axis, index, options):
+    """ 
+    Compute and return a beta matrix from coords * matrix.
+    Then print the matrix to a file to be read on clientside.
     """
-    
-    options = parse_args(args) # This holds the nicely-parsed options object
-    
-    # Test our picking
-    x, y = hexagon_center(0, 0)
-    if hexagon_pick(x, y) != (0, 0):
-        raise Exception("Picking is broken!")
-    
-    # First bit of stdout becomes annotation in Galaxy
-    
-    # Make sure our output directory exists.
-    if not os.path.exists(options.directory):
-        # makedirs is the right thing to use here: recursive
-        os.makedirs(options.directory)
-    
-    # Work in a temporary directory
-    drl_directory = tempfile.mkdtemp()
+    beta = coords * matrix
+    return beta
+    # Must add writing function
+
+def drl_similarity_functions(matrix, index, options):
+	"""
+	Performs all the functions needed to format a similarity matrix into a 
+	tsv format whereby the DrL can take the values. Then all of the DrL
+	functions are performed on the similarity matrix.
+
+	Options is passed to access options.singletons and other required apsects
+    of the parsed args.
+	"""
+	
+	# Work in a temporary directory
+	# If not available, create the directory.
+	drl_directory = tempfile.mkdtemp()
     
     # This is the base name for all the files that DrL uses to do the layout
     # We're going to put it in a temporary directory.
-    drl_basename = os.path.join(drl_directory, "layout")
-    
-    # We can just pass our similarity matrix to DrL's truncate
+	# index added to extension in order to keep track of
+	# respective layouts
+	drl_basename = os.path.join(drl_directory, "layout" + str(index))
+
+	# We can just pass our similarity matrix to DrL's truncate
     # But we want to run it through our tsv parser to strip comments and ensure
     # it's valid
     
     # This holds a reader for the similarity matrix
-    sim_reader = tsv.TsvReader(options.similarities)
+	sim_reader = matrix
     
     # This holds a writer for the sim file
-    sim_writer = tsv.TsvWriter(open(drl_basename + ".sim", "w"))
+	sim_writer = tsv.TsvWriter(open(drl_basename + ".sim", "w"))
     
-    print "Regularizing similarity matrix..."
-    sys.stdout.flush()
+	print "Regularizing similarity matrix..."
+	sys.stdout.flush()
     
     # This holds a list of all unique signature names in the similarity matrix.
     # We can use it to add edges to keep singletons.
-    signatures = set()
-    
-    for parts in sim_reader:
+	signatures = set()
+
+	print "Reach for parts in sim_reader"
+	for parts in sim_reader:
         # Keep the signature names used
-        signatures.add(parts[0])
-        signatures.add(parts[1])
+		signatures.add(parts[0])
+		signatures.add(parts[1])
         
         # Save the line to the regularized file
-        sim_writer.list_line(parts)
+		sim_writer.list_line(parts)
     
-    if options.singletons:    
+	if options.singletons:    
         # Now add a self-edge on every node, so we don't drop nodes with no
         # other strictly positive edges
-        for signature in signatures:
-            sim_writer.line(signature, signature, 1)
+		for signature in signatures:
+			sim_writer.line(signature, signature, 1)
         
-    sim_reader.close()
-    sim_writer.close()
+	sim_reader.close()
+	sim_writer.close()
     
     # Now our input for DrL is prepared!
     
     # Do DrL truncate.
     # TODO: pass a truncation level
-    print "DrL: Truncating..."
-    sys.stdout.flush()
-    subprocess.check_call(["truncate", "-t", str(options.truncation_edges), 
+	print "DrL: Truncating..."
+	sys.stdout.flush()
+	subprocess.check_call(["truncate", "-t", str(options.truncation_edges), 
         drl_basename]) 
         
     # Run the DrL layout engine.
-    print "DrL: Doing layout..."
-    sys.stdout.flush()
-    subprocess.check_call(["layout", drl_basename]) 
+	print "DrL: Doing layout..."
+	sys.stdout.flush()
+	subprocess.check_call(["layout", drl_basename]) 
     
     # Put the string names back
-    print "DrL: Restoring names..."
-    sys.stdout.flush()
-    subprocess.check_call(["recoord", drl_basename]) 
+	print "DrL: Restoring names..."
+	sys.stdout.flush()
+	subprocess.check_call(["recoord", drl_basename]) 
         
     # Now DrL has saved its coordinates as <signature name>\t<x>\t<y> rows in 
     # <basename>.coord
     
     # We want to read that.
     # This holds a reader for the DrL output
-    coord_reader = tsv.TsvReader(open(drl_basename + ".coord", "r"))
+	coord_reader = tsv.TsvReader(open(drl_basename + ".coord", "r"))
     
     # This holds a dict from signature name string to (x, y) float tuple. It is
     # also our official collection of node names that made it through DrL, and
     # therefore need their score data sent to the client.
-    nodes = {}
-    
-    print "Reading DrL output..."
-    sys.stdout.flush()
-    for parts in coord_reader:
-        nodes[parts[0]] = (float(parts[1]), float(parts[2])) 
-            
-    coord_reader.close()
+	nodes = {}
+
+	print "Reading DrL output..."
+	sys.stdout.flush()
+	for parts in coord_reader:
+		nodes[parts[0]] = (float(parts[1]), float(parts[2])) 
+
+	coord_reader.close()
     
     # Save the DrL coordinates in our bundle, to be displayed client-side for 
     # debugging.
-    coord_writer = tsv.TsvWriter(open(
-        os.path.join(options.directory, "drl.tab"), "w"))
+
+	# index added to drl.tab extension in order to keep track of
+	# respective drl.tabs
+	coord_writer = tsv.TsvWriter(open(
+		os.path.join(options.directory, "drl" + str(index) + ".tab"), "w"))
         
-    for signature_name, (x, y) in nodes.iteritems():
+	for signature_name, (x, y) in nodes.iteritems():
         # Write a tsv with names instead of numbers, like what DrL recoord would
         # have written. This is what the Javascript on the client side wants.
-        coord_writer.line(signature_name, x, y)
+		coord_writer.line(signature_name, x, y)
         
-    coord_writer.close()
-    
+	coord_writer.close()
+	
+    # Delete our temporary directory.
+	shutil.rmtree(drl_directory)
+
+	# Return nodes dict back to main method for further processes
+	return nodes
+
+def compute_hexagram_assignments (nodes, index, options):
+    """
+    Now that we are taking multiple similarity matrices as inputs, we must
+    compute hexagram assignments for each similarity matrix. These assignments 
+    are based up on the nodes ouput provided by the DrL function. 
+
+    Index relates each matrix name with its drl output, nodes, assignments, etc.
+    Options contains the parsed arguments that are present in the main method.
+    """
     # Do the hexagon layout
     # We do the squiggly rows setup, so express everything as integer x, y
     
     # This is a defaultdict from (x, y) integer tuple to id that goes there, or
     # None if it's free.
+    global hexagons
     hexagons = collections.defaultdict(lambda: None)
     
     # This holds the side length that we use
@@ -790,13 +837,13 @@
     # The hexagons have been assigned. Make hexagons be a dict instead of a 
     # defaultdict, so it pickles.
     # TODO: I should change it so I don't need to do this.
-    hexagons = dict(hexagons)  
-   
+    hexagons = dict(hexagons) 
+
     # Now dump the hexagon assignments as an id, x, y tsv. This will be read by
     # the JavaScript on the static page and be used to produce the 
     # visualization.        
     hexagon_writer = tsv.TsvWriter(open(os.path.join(options.directory, 
-        "assignments.tab"), "w"))
+        "assignments"+ str(index) + ".tab"), "w"))
 
     # First find the x and y offsets needed to make all hexagon positions 
     # positive
@@ -807,7 +854,79 @@
         # Write this hexagon assignment, converted to all-positive coordinates.
         hexagon_writer.line(name, coords[0] - min_x, coords[1] - min_y)    
     hexagon_writer.close()
+
+    # Hand placement_badness dict to main method so that it can be used else
+    # where.
+    return placement_badnesses
+                
+def write_matrix_names (options):
+    """
+    Write the names of the similarity matrices so that hexagram.js can
+    process the names and create the toggle layout GUI.
+    We pass options to access the parsed args and thus the matrix names.
+    """
+    name_writer = tsv.TsvWriter(open(os.path.join(options.directory, 
+        "matrixnames.tab"), "w"))
+    for i in options.names:
+        name_writer.line(i)
+
+    name_writer.close()
+
+def main(args):
+    """
+    Parses command line arguments, and makes visualization.
+    "args" specifies the program arguments, with args[0] being the executable
+    name. The return value should be used as the program's exit code.
+    """
     
+    options = parse_args(args) # This holds the nicely-parsed options object
+	
+    print "Created Options"
+    
+    # Test our picking
+    x, y = hexagon_center(0, 0)
+    if hexagon_pick(x, y) != (0, 0):
+        raise Exception("Picking is broken!")
+    
+    # First bit of stdout becomes annotation in Galaxy 
+    # Make sure our output directory exists.
+    if not os.path.exists(options.directory):
+        # makedirs is the right thing to use here: recursive
+        os.makedirs(options.directory)
+	
+    print "Writing matrix names..."
+    # We must write the file names for hexagram.js to access.
+    write_matrix_names(options)
+
+    print "About to open matrices..."
+
+	# We have file names stored in options.similarities
+	# We must open the files and store them in matrices list for access
+    open_matrices(options.similarity)
+
+    print "Opened matrices..."
+
+	# The nodes list stores the list of nodes for each matrix
+	# We must keep track of each set of nodes
+    nodes_multiple = []
+
+    print "Created nodes_multiple list..."
+
+	# Index for drl.tab and drl.layout file naming. With indexes we can match
+	# file names, to matrices, to drl output files.
+    for index, i in enumerate (matrices):
+        nodes_multiple.append (drl_similarity_functions(i, index, options))
+    
+    # Compute Hexagam Assignments for each similarity matrix's drl output,
+    # which is found in nodes_multiple.
+
+    # placement_badnesses_multiple list is required to store the placement
+    # badness dicts that are returned by the compute_hexagram_assignments
+    # function.
+    placement_badnesses_multiple = []
+    for index, i in enumerate (nodes_multiple):
+        placement_badnesses_multiple.append (compute_hexagram_assignments (i, index, options))
+
     # Now that we have hex assignments, compute layers.
     
     # In addition to making per-layer files, we're going to copy all the score
@@ -863,7 +982,7 @@
                 # This is the signature that this line is about
                 signature_name = parts[0]
                 
-                if signature_name not in nodes:
+                if signature_name not in nodes_multiple[0]:
                     # This signature wasn't in our DrL output. Don't bother
                     # putting its layer data in our visualization. This saves
                     # space and makes the client-side layer counts accurate for
@@ -903,7 +1022,7 @@
     
     # Stick our placement badness layer on the end
     layer_names.append("Placement Badness")
-    layers["Placement Badness"] = placement_badnesses
+    layers["Placement Badness"] = placement_badnesses_multiple[0]
        
     # Now we need to write layer files.
         
@@ -995,11 +1114,16 @@
         
     index_writer.close()
     
+    # Sahil will implement linear regression code here
+   
+    # We must create a m * n matrix of samples * genes
+    # In order to create this matrix we first must know the number of hexes
+    # and mantain them in a certain order. The order is important so that
+    # we populate the matrix with the data values in the proper row (sample).
+
     # Copy over the user-specified colormaps file, or make an empty TSV if it's
     # not specified.
     
-    
-    
     # This holds a writer for the sim file. Creating it creates the file.
     colormaps_writer = tsv.TsvWriter(open(os.path.join(options.directory, 
         "colormaps.tab"), "w"))
@@ -1035,6 +1159,9 @@
         "filter.svg",
         "statistics.svg",
         "right.svg",
+		"set.svg",
+		"save.svg",
+        "inflate.svg",
         "throbber.svg",
         
         # jQuery itself is pulled from a CDN.
@@ -1074,12 +1201,9 @@
     # Copy the HTML file to our output file. It automatically knows to read
     # assignments.tab, and does its own TSV parsing
     shutil.copy2(os.path.join(tool_root, "hexagram.html"), options.html)
-    
-    # Delete our temporary directory.
-    shutil.rmtree(drl_directory)
-    
+     
     print "Visualization generation complete!"
-        
+       
     return 0
 
 if __name__ == "__main__" :
--- a/hexagram/hexagram.xml	Wed Jun 19 15:04:17 2013 -0400
+++ b/hexagram/hexagram.xml	Wed Oct 16 18:48:28 2013 -0400
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<tool id="hexagram" name="Hexagram Visualization" version="0.1">
+<tool id="hexagram" name="Hexagram Visualization" version="0.2">
     <description>Interactive hex grid clustering visualization</description>
     <requirements>
         <!--
@@ -18,7 +18,13 @@
         We do fancy iteration over multiple score matrices (see
         ../plotting/xy_plot.xml).
     -->
-    <command interpreter="python">hexagram.py "$similarity"
+    <command interpreter="python">hexagram.py 
+		#for $i, $s in enumerate( $similarity )
+			"${s.similarity_matrix.file_name}"
+		#end for
+		 #for $i, $s in enumerate ($similarity)
+            --names "${s.similarity_matrix.name}"
+        #end for
         #for $i, $s in enumerate( $scores )
             --scores "${s.score_matrix.file_name}"
         #end for
@@ -39,8 +45,10 @@
         #end if
     </command>
     <inputs>
-        <param name="similarity" type="data" format="tabular" 
-            label="Similarity matrix of signatures to visualize"/>
+		<repeat name="similarity" title="Similarity Matrices">
+        	<param name="similarity_matrix" type="data" format="tabular" 
+            	label="Similarity matrix of signatures to visualize"/>
+		</repeat>
         <repeat name="scores" title="Scores">
             <param name="score_matrix" type="data" format="tabular" 
                 label="Score matrix for signatures to visualize"/>
@@ -58,7 +66,7 @@
             label="Skip calculation of heatmap clumpiness statistics"/>
     </inputs>
     <outputs>
-        <data name="output" label="Hexagram Visualization of $similarity.name ($edges edges)" 
+        <data name="output" label="Hexagram Visualization($edges edges)" 
             format="html" hidden="false"/>
     </outputs>
     <stdio>
@@ -84,10 +92,10 @@
 
 The tool takes three types of input files:
 
-Similarity Matrix
-+++++++++++++++++
+Similarity Matrices
++++++++++++++++++++
 
-The only required input file is a *similarity matrix*, which contains similarity information over a set of "samples" or "signatures". This file is a sparse matrix represented as three tab-delimited columns; the first two columns of each row contain the names of two signatures, and the last column contains a nonzero, non-negative floating-point "similarity" between them. No headers are used. Self-edges are permitted, and self-edges with a similarity of 1 will be added to every node if "Keep unconnected singleton signatures" is checked. The input similarity matrix need not describe a similarity graph that is connected, and similarity need not be transitive in any way.
+The only required input file is at least one *similarity matrix*, which contains similarity information over a set of "samples" or "signatures". This file is a sparse matrix represented as three tab-delimited columns; the first two columns of each row contain the names of two signatures, and the last column contains a nonzero, non-negative floating-point "similarity" between them. No headers are used. Self-edges are permitted, and self-edges with a similarity of 1 will be added to every node if "Keep unconnected singleton signatures" is checked. The input similarity matrix need not describe a similarity graph that is connected, and similarity need not be transitive in any way.
 
 Score Matrices
 ++++++++++++++
@@ -103,3 +111,4 @@
 
     </help>
 </tool>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hexagram/inflate.svg	Wed Oct 16 18:48:28 2013 -0400
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="29.851999"
+   height="32.582985"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="inflate.svg">
+  <defs
+     id="defs21">
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send"
+       style="overflow:visible">
+      <path
+         id="path3801"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-4"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3801-6"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-2"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3801-9"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Send-8"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path3801-3"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1301"
+     inkscape:window-height="704"
+     id="namedview19"
+     showgrid="false"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:zoom="2.5041624"
+     inkscape:cx="120.51589"
+     inkscape:cy="48.987443"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg2" />
+  <g
+     id="g4"
+     transform="matrix(0.03970783,0,0,0.03959906,7.8677399,8.123235)">
+    <title
+       id="title6">Layer 1</title>
+    <g
+       transform="translate(-1.26562,-1.26172)"
+       id="imagebot_119">
+      <path
+         id="imagebot_120"
+         d="m 187.07201,461.681 c 0,0 -9.594,-11.483 -9.594,-33.191 l -8.296,0 c 0,21.708 -9.596,33.191 -9.596,33.191"
+         inkscape:connector-curvature="0"
+         style="fill:#bed63a;stroke:#515c19;stroke-width:2.52600002" />
+      <path
+         id="imagebot_121"
+         d="m 345.39499,185.959 c 0,129.11999 -97.513,242.795 -172.065,242.795 -71.68901,0 -172.066,-103.295 -172.066,-242.795 C 1.263,83.955 71.325,1.263 173.33,1.263 c 102.00301,0 172.06499,82.692 172.06499,184.696 z"
+         inkscape:connector-curvature="0"
+         style="fill:#bed63a;stroke:#515c19;stroke-width:2.52600002" />
+      <ellipse
+         id="imagebot_122"
+         ry="3.8180001"
+         rx="13.743"
+         cy="461.681"
+         cx="173.32899"
+         d="m 187.07199,461.681 c 0,2.10862 -6.15295,3.818 -13.743,3.818 -7.59004,0 -13.743,-1.70938 -13.743,-3.818 0,-2.10862 6.15296,-3.818 13.743,-3.818 7.59005,0 13.743,1.70938 13.743,3.818 z"
+         sodipodi:cx="173.32899"
+         sodipodi:cy="461.681"
+         sodipodi:rx="13.743"
+         sodipodi:ry="3.8180001"
+         style="fill:#bed63a;stroke:#515c19;stroke-width:2.52600002" />
+    </g>
+  </g>
+  <g
+     id="g12"
+     transform="matrix(0.03970783,0,0,0.03959906,7.8677399,8.123235)">
+    <title
+       id="title14">Layer 2</title>
+    <path
+       id="imagebot_123"
+       d="m 179.307,28.2213 c 0,0 125.037,65.676 95.988,286.7007 0,0 63.527,-103.315 32.838,-188.187 C 274.6,33.9963 179.307,28.2213 179.307,28.2213 z"
+       inkscape:connector-curvature="0"
+       style="fill:#d6e584" />
+  </g>
+  <metadata
+     id="metadata17">image/svg+xmlOpen Clip Art LibraryBalloon2010-07-21T15:06:35Simple balloon illustration.http://openclipart.org/detail/74221/balloon-by-jgm104jgm104balloonchildcircusclip artclipartfloatingrubbertoy<rdf:RDF>
+  <cc:Work
+     rdf:about="">
+    <dc:format>image/svg+xml</dc:format>
+    <dc:type
+       rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+    <dc:title />
+  </cc:Work>
+</rdf:RDF>
+</metadata>
+  <path
+     style="fill:none;stroke:#000000;stroke-width:1.72656119;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)"
+     d="M 14.855292,9.3428471 14.51008,2.4575339"
+     id="path5690"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:1.72656119;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)"
+     d="m 20.47967,17.357859 6.912193,-0.09543"
+     id="path5690-7"
+     inkscape:connector-curvature="0"
+     inkscape:transform-center-x="-20.021171"
+     inkscape:transform-center-y="-1.9396242" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:1.72656119;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)"
+     d="m 14.67395,23.229042 0.05797,6.893672"
+     id="path5690-7-8"
+     inkscape:connector-curvature="0"
+     inkscape:transform-center-x="-1.8418242"
+     inkscape:transform-center-y="19.978895" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:1.72656119;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Send)"
+     d="M 9.3659788,17.191706 2.458586,17.465695"
+     id="path5690-7-88"
+     inkscape:connector-curvature="0"
+     inkscape:transform-center-x="19.96343"
+     inkscape:transform-center-y="2.4268093" />
+</svg>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hexagram/save.svg	Wed Oct 16 18:48:28 2013 -0400
@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   height="27.1875"
+   id="svg548"
+   sodipodi:docname="save.svg"
+   sodipodi:version="0.32"
+   width="27"
+   version="1.1"
+   inkscape:version="0.48.3.1 r9886">
+  <metadata
+     id="metadata3">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:title />
+        <dc:description />
+        <dc:subject>
+          <rdf:Bag>
+            <rdf:li>hash</rdf:li>
+            <rdf:li />
+            <rdf:li>computer</rdf:li>
+          </rdf:Bag>
+        </dc:subject>
+        <dc:publisher>
+          <cc:Agent
+             rdf:about="http://www.openclipart.org">
+            <dc:title>Nicu Buculei</dc:title>
+          </cc:Agent>
+        </dc:publisher>
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Nicu Buculei</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:rights>
+          <cc:Agent>
+            <dc:title>Nicu Buculei</dc:title>
+          </cc:Agent>
+        </dc:rights>
+        <dc:date />
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <cc:license
+           rdf:resource="http://web.resource.org/cc/PublicDomain" />
+        <dc:language>en</dc:language>
+      </cc:Work>
+      <cc:License
+         rdf:about="http://web.resource.org/cc/PublicDomain">
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Reproduction" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Distribution" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+      </cc:License>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs550" />
+  <sodipodi:namedview
+     id="base"
+     showgrid="true"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:zoom="2.6700352"
+     inkscape:cx="69.677527"
+     inkscape:cy="52.709901"
+     inkscape:window-width="1301"
+     inkscape:window-height="704"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg548" />
+  <path
+     d="m 0.13698097,0.1343605 24.24897403,0 2.494464,2.4364954 L 26.764453,27.051871 0.19499143,26.935837 0.13698347,0.1343605 z"
+     id="path551"
+     style="fill:#00007b;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.25656179;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-dasharray:none"
+     inkscape:connector-curvature="0" />
+  <path
+     d="m 21.949439,0.2592358 0,7.2212882 c 0,0 -0.174051,1.069755 -1.102258,1.404103 C 19.919044,8.951417 7.2724631,8.951497 7.2724631,8.951497 7.2144471,9.018367 6.4602916,8.41654 6.4022745,8.015401 6.3442585,7.614184 6.2862402,7.480524 6.2862402,7.480524 c 0,0 0.1160343,-7.2881498 0.058016,-7.2881498 -0.058016,0 15.6631988,0.066862 15.6051818,0.066862 z"
+     id="path552"
+     sodipodi:nodetypes="cccccccc"
+     style="fill:#a3a6a6;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.17104124;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-dasharray:none"
+     inkscape:connector-curvature="0" />
+  <rect
+     height="12.704596"
+     id="rect553"
+     style="font-size:12px;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke-width:1pt"
+     width="21.98649"
+     x="2.689502"
+     y="13.535099" />
+  <rect
+     height="7.7837553"
+     id="rect554"
+     style="font-size:12px;fill:#808080;fill-rule:evenodd;stroke-width:1pt"
+     width="0"
+     x="300.18646"
+     y="157.24586" />
+  <path
+     d="m 19.454906,1.6426701 c -0.05802,0 -3.596723,0 -3.596723,0 l 0,6.0912619 3.596723,0 0,-6.0912619 z"
+     id="path555"
+     style="fill:#00007b;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.17104119;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-dasharray:none"
+     inkscape:connector-curvature="0" />
+  <rect
+     height="3.7707691"
+     id="rect556"
+     style="font-size:12px;fill:#dd8080;fill-opacity:1;fill-rule:evenodd;stroke-width:1pt"
+     width="21.986492"
+     x="2.689502"
+     y="13.535099" />
+  <rect
+     height="0.46409538"
+     id="rect557"
+     style="font-size:12px;fill:#dd8080;fill-opacity:1;fill-rule:evenodd;stroke-width:1pt"
+     width="19.666018"
+     x="3.7337143"
+     y="19.394289" />
+  <rect
+     height="0.4060829"
+     id="rect558"
+     style="font-size:12px;fill:#dd8080;fill-opacity:1;fill-rule:evenodd;stroke-width:1pt"
+     width="19.666018"
+     x="3.6757019"
+     y="21.830795" />
+  <rect
+     height="0.4060829"
+     id="rect559"
+     style="font-size:12px;fill:#df8080;fill-opacity:1;fill-rule:evenodd;stroke-width:1pt"
+     width="19.608006"
+     x="3.7337143"
+     y="24.267286" />
+  <rect
+     height="0.34806943"
+     id="rect567"
+     style="font-size:12px;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke-width:1pt"
+     width="5.3951015"
+     x="7.4464741"
+     y="1.5846567" />
+  <rect
+     height="0.34807205"
+     id="rect568"
+     style="font-size:12px;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke-width:1pt"
+     width="4.0028186"
+     x="7.5624957"
+     y="2.4548321" />
+  <rect
+     height="0.34806943"
+     id="rect569"
+     style="font-size:12px;fill:#180003;fill-opacity:1;fill-rule:evenodd;stroke-width:1pt"
+     width="5.221067"
+     x="7.5624957"
+     y="3.3250132" />
+  <rect
+     height="0.40608501"
+     id="rect570"
+     style="font-size:12px;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke-width:1pt"
+     width="7.8315992"
+     x="3.7917266"
+     y="14.34726" />
+  <rect
+     height="0.34807047"
+     id="rect571"
+     style="font-size:12px;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke-width:1pt"
+     width="3.0166156"
+     x="3.8497388"
+     y="15.44949" />
+  <rect
+     height="0.34806964"
+     id="rect572"
+     style="font-size:12px;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke-width:1pt"
+     width="2.3204749"
+     x="8.7227325"
+     y="15.44949" />
+  <path
+     d="M 6.824404,7.265759 C 6.9326388,6.940986 6.7161008,0.7705103 7.1491084,0.7705103 c 0.4330076,0 9.4181436,-0.1082481 9.4181436,-0.1082481 C 12.453574,1.0952764 7.7986548,0.9870216 6.824404,7.265759 z"
+     id="path566"
+     sodipodi:nodetypes="cccc"
+     style="fill:#ffffff;fill-opacity:0.5;fill-rule:evenodd;stroke:none"
+     inkscape:connector-curvature="0" />
+</svg>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hexagram/set.svg	Wed Oct 16 18:48:28 2013 -0400
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="24.647392"
+   height="23.09375"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="set.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="11.2"
+     inkscape:cx="37.729826"
+     inkscape:cy="19.396497"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1301"
+     inkscape:window-height="704"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     showborder="true" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(3.8022401,-1030.1184)">
+    <path
+       transform="matrix(1.2211561,0,0,1.2211561,-71.653905,1020.2289)"
+       sodipodi:type="arc"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="path4140-5"
+       sodipodi:cx="61.619305"
+       sodipodi:cy="14.154314"
+       sodipodi:rx="5.5558391"
+       sodipodi:ry="5.5558391"
+       d="m 67.175144,14.154314 c 0,3.068405 -2.487434,5.555839 -5.555839,5.555839 -3.068406,0 -5.555839,-2.487434 -5.555839,-5.555839 0,-3.068405 2.487433,-5.555839 5.555839,-5.555839 3.068405,0 5.555839,2.487434 5.555839,5.555839 z" />
+    <path
+       transform="matrix(1.2211561,0,0,1.2211561,-61.796763,1023.3539)"
+       sodipodi:type="arc"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="path4140-8"
+       sodipodi:cx="61.619305"
+       sodipodi:cy="14.154314"
+       sodipodi:rx="5.5558391"
+       sodipodi:ry="5.5558391"
+       d="m 67.175144,14.154314 c 0,3.068405 -2.487434,5.555839 -5.555839,5.555839 -3.068406,0 -5.555839,-2.487434 -5.555839,-5.555839 0,-3.068405 2.487433,-5.555839 5.555839,-5.555839 3.068405,0 5.555839,2.487434 5.555839,5.555839 z" />
+    <path
+       transform="matrix(1.2211561,0,0,1.2211561,-68.011048,1028.5324)"
+       sodipodi:type="arc"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="path4140-58"
+       sodipodi:cx="61.619305"
+       sodipodi:cy="14.154314"
+       sodipodi:rx="5.5558391"
+       sodipodi:ry="5.5558391"
+       d="m 67.175144,14.154314 c 0,3.068405 -2.487434,5.555839 -5.555839,5.555839 -3.068406,0 -5.555839,-2.487434 -5.555839,-5.555839 0,-3.068405 2.487433,-5.555839 5.555839,-5.555839 3.068405,0 5.555839,2.487434 5.555839,5.555839 z" />
+    <path
+       d="m 67.175144,14.154314 c 0,3.068405 -2.487434,5.555839 -5.555839,5.555839 -3.068406,0 -5.555839,-2.487434 -5.555839,-5.555839 0,-3.068405 2.487433,-5.555839 5.555839,-5.555839 3.068405,0 5.555839,2.487434 5.555839,5.555839 z"
+       sodipodi:ry="5.5558391"
+       sodipodi:rx="5.5558391"
+       sodipodi:cy="14.154314"
+       sodipodi:cx="61.619305"
+       id="path4207"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       sodipodi:type="arc"
+       transform="matrix(1.2211561,0,0,1.2211561,-71.653905,1020.2289)" />
+    <path
+       d="m 67.175144,14.154314 c 0,3.068405 -2.487434,5.555839 -5.555839,5.555839 -3.068406,0 -5.555839,-2.487434 -5.555839,-5.555839 0,-3.068405 2.487433,-5.555839 5.555839,-5.555839 3.068405,0 5.555839,2.487434 5.555839,5.555839 z"
+       sodipodi:ry="5.5558391"
+       sodipodi:rx="5.5558391"
+       sodipodi:cy="14.154314"
+       sodipodi:cx="61.619305"
+       id="path4209"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       sodipodi:type="arc"
+       transform="matrix(1.2211561,0,0,1.2211561,-61.796763,1023.3539)" />
+    <path
+       d="m 67.175144,14.154314 c 0,3.068405 -2.487434,5.555839 -5.555839,5.555839 -3.068406,0 -5.555839,-2.487434 -5.555839,-5.555839 0,-3.068405 2.487433,-5.555839 5.555839,-5.555839 3.068405,0 5.555839,2.487434 5.555839,5.555839 z"
+       sodipodi:ry="5.5558391"
+       sodipodi:rx="5.5558391"
+       sodipodi:cy="14.154314"
+       sodipodi:cx="61.619305"
+       id="path4211"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       sodipodi:type="arc"
+       transform="matrix(1.2211561,0,0,1.2211561,-68.011048,1028.5324)" />
+    <path
+       transform="matrix(1.2211561,0,0,1.2211561,-71.653905,1020.2289)"
+       sodipodi:type="arc"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="path4213"
+       sodipodi:cx="61.619305"
+       sodipodi:cy="14.154314"
+       sodipodi:rx="5.5558391"
+       sodipodi:ry="5.5558391"
+       d="m 67.175144,14.154314 c 0,3.068405 -2.487434,5.555839 -5.555839,5.555839 -3.068406,0 -5.555839,-2.487434 -5.555839,-5.555839 0,-3.068405 2.487433,-5.555839 5.555839,-5.555839 3.068405,0 5.555839,2.487434 5.555839,5.555839 z" />
+    <path
+       transform="matrix(1.2211561,0,0,1.2211561,-61.796763,1023.3539)"
+       sodipodi:type="arc"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="path4215"
+       sodipodi:cx="61.619305"
+       sodipodi:cy="14.154314"
+       sodipodi:rx="5.5558391"
+       sodipodi:ry="5.5558391"
+       d="m 67.175144,14.154314 c 0,3.068405 -2.487434,5.555839 -5.555839,5.555839 -3.068406,0 -5.555839,-2.487434 -5.555839,-5.555839 0,-3.068405 2.487433,-5.555839 5.555839,-5.555839 3.068405,0 5.555839,2.487434 5.555839,5.555839 z" />
+    <path
+       transform="matrix(1.2211561,0,0,1.2211561,-68.011048,1028.5324)"
+       sodipodi:type="arc"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="path4217"
+       sodipodi:cx="61.619305"
+       sodipodi:cy="14.154314"
+       sodipodi:rx="5.5558391"
+       sodipodi:ry="5.5558391"
+       d="m 67.175144,14.154314 c 0,3.068405 -2.487434,5.555839 -5.555839,5.555839 -3.068406,0 -5.555839,-2.487434 -5.555839,-5.555839 0,-3.068405 2.487433,-5.555839 5.555839,-5.555839 3.068405,0 5.555839,2.487434 5.555839,5.555839 z" />
+    <path
+       d="m 67.175144,14.154314 c 0,3.068405 -2.487434,5.555839 -5.555839,5.555839 -3.068406,0 -5.555839,-2.487434 -5.555839,-5.555839 0,-3.068405 2.487433,-5.555839 5.555839,-5.555839 3.068405,0 5.555839,2.487434 5.555839,5.555839 z"
+       sodipodi:ry="5.5558391"
+       sodipodi:rx="5.5558391"
+       sodipodi:cy="14.154314"
+       sodipodi:cx="61.619305"
+       id="path4219"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       sodipodi:type="arc"
+       transform="matrix(1.2211561,0,0,1.2211561,-71.653905,1020.2289)" />
+    <path
+       d="m 67.175144,14.154314 c 0,3.068405 -2.487434,5.555839 -5.555839,5.555839 -3.068406,0 -5.555839,-2.487434 -5.555839,-5.555839 0,-3.068405 2.487433,-5.555839 5.555839,-5.555839 3.068405,0 5.555839,2.487434 5.555839,5.555839 z"
+       sodipodi:ry="5.5558391"
+       sodipodi:rx="5.5558391"
+       sodipodi:cy="14.154314"
+       sodipodi:cx="61.619305"
+       id="path4221"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       sodipodi:type="arc"
+       transform="matrix(1.2211561,0,0,1.2211561,-61.796763,1023.3539)" />
+    <path
+       d="m 67.175144,14.154314 c 0,3.068405 -2.487434,5.555839 -5.555839,5.555839 -3.068406,0 -5.555839,-2.487434 -5.555839,-5.555839 0,-3.068405 2.487433,-5.555839 5.555839,-5.555839 3.068405,0 5.555839,2.487434 5.555839,5.555839 z"
+       sodipodi:ry="5.5558391"
+       sodipodi:rx="5.5558391"
+       sodipodi:cy="14.154314"
+       sodipodi:cx="61.619305"
+       id="path4223"
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       sodipodi:type="arc"
+       transform="matrix(1.2211561,0,0,1.2211561,-68.011048,1028.5324)" />
+    <path
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.22115612;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 7.2357427,1039.0448 c -3.0094933,0 -5.5495545,1.9435 -6.43749994,4.6562 0.85243504,0.386 1.78462804,0.5938 2.78124994,0.5938 3.0101183,0 5.5813115,-1.9427 6.4687503,-4.6563 -0.8541528,-0.3879 -1.8132998,-0.5937 -2.8125003,-0.5937 z"
+       id="path4225"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.22115612;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 9.8294927,1034.8885 c -1.9093309,1.2005 -3.15625,3.3281 -3.15625,5.75 0,0.9263 0.1951408,1.8206 0.53125,2.625 1.9093309,-1.2005 3.1875003,-3.3281 3.1875003,-5.75 0,-0.9267 -0.226159,-1.8203 -0.5625003,-2.625 z"
+       id="path4227"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.22115612;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 7.2357427,1039.0448 c -0.1279582,0 -0.2487893,0.024 -0.375,0.031 -0.1175521,0.5003 -0.1875,1.0264 -0.1875,1.5625 0,3.747 3.034248,6.7813 6.7812493,6.7813 0.127958,0 0.248789,-0.024 0.375,-0.031 0.121981,-0.509 0.1875,-1.0161 0.1875,-1.5625 0,-3.747 -3.034247,-6.7812 -6.7812493,-6.7812 z"
+       id="path4233"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:#008000;fill-opacity:1;stroke:#008000;stroke-width:1.22115612;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 7.2357427,1039.0448 c -0.1289522,0 -0.2478646,0.024 -0.375,0.031 -0.058776,0.2501 -0.092819,0.5202 -0.125,0.7813 -0.028269,0.2535 -0.0625,0.52 -0.0625,0.7812 0,0.4632 0.034201,0.9038 0.125,1.3438 0.00197,0.01 -0.00201,0.021 0,0.031 0.044283,0.2099 0.1248265,0.4229 0.1875,0.625 0.00287,0.01 -0.00291,0.022 0,0.031 0.060514,0.1922 0.1429028,0.3788 0.21875,0.5625 0.089436,-0.056 0.1946942,-0.096 0.28125,-0.1563 0.042386,-0.03 0.083322,-0.063 0.125,-0.094 0.096544,-0.071 0.1886771,-0.1435 0.28125,-0.2188 0.1773902,-0.1449 0.3380704,-0.3069 0.5,-0.4687 0.2204067,-0.2199 0.4366288,-0.4391 0.625,-0.6875 0.022654,-0.03 0.040328,-0.064 0.0625,-0.094 0.1981108,-0.2705 0.3747891,-0.5759 0.53125,-0.875 0.00632,-0.012 0.025005,-0.019 0.03125,-0.031 0.150422,-0.2921 0.268182,-0.5911 0.3750003,-0.9063 0.0045,-0.013 0.02682,-0.018 0.03125,-0.031 -0.063662,-0.029 -0.1227913,-0.066 -0.1875003,-0.094 -0.161782,-0.068 -0.3008294,-0.1316 -0.46875,-0.1875 -0.04079,-0.013 -0.083853,-0.019 -0.125,-0.031 -0.070794,-0.022 -0.1469806,-0.043 -0.21875,-0.063 -0.1464042,-0.039 -0.2873032,-0.095 -0.4375,-0.125 -0.4415675,-0.09 -0.9066248,-0.125 -1.375,-0.125 z"
+       id="path4241"
+       inkscape:connector-curvature="0" />
+  </g>
+</svg>
--- a/hexagram/statistics.js	Wed Jun 19 15:04:17 2013 -0400
+++ b/hexagram/statistics.js	Wed Oct 16 18:48:28 2013 -0400
@@ -251,9 +251,9 @@
     // Given the data of a continuous layer object (an object from signature
     // name to float (or undefined)), and arrays of the names of "in" and "out"
     // signatures, do a t test test for whether the in signatures differ from
-    // the out signatures. Returns the p value of the test (two-tailed), or NaN 
-    // if the test cannot be performed (due to, e.g. fewer than 2 samples in one
-    // category).
+    // the out signatures. Returns an object of metadata, with "p_value" set to
+    // either the p value of the test (two-tailed), or NaN if the test cannot be
+    // performed (due to, e.g. fewer than 2 samples in one category).
     
     // Go through the in list and calculate all the summary statistics
     // How many non-NaN values?
@@ -331,10 +331,11 @@
     var p_value = t_test(mean_in, unbiased_variance_in, number_in, mean_out, 
         unbiased_variance_out, number_out);
         
-    print("p=" + p_value);
-        
-    // And return it
-    return p_value;
+    // And return it in a dict with other metadata.
+    // We don't really have any other metadata.
+    return {
+        p_value: p_value
+    };
 }
 
 function t_test(mean_in, unbiased_variance_in, number_in, mean_out, 
@@ -347,11 +348,6 @@
     // https://en.wikipedia.org/wiki/Student%27s_t-test
     // Assumes we have enough samples to actually perform the test.
     
-    print("Running t test with mean " + mean_in + " and variance " + 
-        unbiased_variance_in + " at n=" + number_in + " versus mean " + 
-        mean_out + " and variance " + unbiased_variance_out + " at n=" + 
-        number_out);
-    
     // First, calculate the t statistic, which is where our observations fall on
     // the t distribution.
     var t_statistic = (mean_in - mean_out) / Math.sqrt((unbiased_variance_in /
@@ -365,8 +361,6 @@
         ((Math.pow(unbiased_variance_in / number_in, 2) / (number_in - 1)) + 
         (Math.pow(unbiased_variance_out / number_out, 2) / (number_out - 1)));
 
-    print("t = " + t_statistic + ", DoF = " + degrees_of_freedom); 
-
     // Now we have to compare the t statistic to the t test CDF available via
     // the totally undocumented jstat.pt = function(q, df, ncp, lower_tail, log)
     // where:
@@ -394,12 +388,13 @@
     // 0 or 1 (or undefined)), and arrays of the names of "in" and "out"
     // signatures, do a binomial test for whether the in signatures differ from
     // the out signatures. Uses a number of pseudocount trials as specified in
-    // the global constant BINOMIAL_PSEUDOCOUNTS Return the p value, or NaN if
-    // it cannot be calculated. all_list specifies the names of all signatures
-    // that figure into the analysis at all (i.e. those which the user hasn't
-    // filtered out), which we use when calculating how many of our pseudocounts
-    // should be successes. Signature names appearing in all_list but with no
-    // data in layer_data are not counted.
+    // the global constant BINOMIAL_PSEUDOCOUNTS Returns an object of metadata,
+    // with "p_value" set to either the p value of the test (two-tailed), or NaN
+    // if the test cannot be performed. all_list specifies the names of all
+    // signatures that figure into the analysis at all (i.e. those which the
+    // user hasn't filtered out), which we use when calculating how many of our
+    // pseudocounts should be successes. Signature names appearing in all_list
+    // but with no data in layer_data are not counted.
     
     
     // Work out the distribution from the out list
@@ -492,8 +487,14 @@
             outside_no) + " with " + pseudo_yes + " out of " + 
             BINOMIAL_PSEUDOCOUNTS + " pseudocounts.");
     }
-        
-    return p;
+     
+    // Return our p value as "p_value", and also how many non-pseudocount
+    // successes were in the in_list and the out_list.
+    return {
+        p_value: p,
+        inside_yes: inside_yes,
+        outside_yes: outside_yes
+    };
 }    
     
 function binomial_test(trials, successes, success_probability) {
--- a/hexagram/tools.js	Wed Jun 19 15:04:17 2013 -0400
+++ b/hexagram/tools.js	Wed Oct 16 18:48:28 2013 -0400
@@ -370,3 +370,20 @@
         });
     });
 });
+
+$(function() {
+    // Set up the link to this page control
+    add_tool("link-to-page", "Link to this Page...", function() {
+        
+        // We will provide the user with an alert box with the link to the
+		// hexagrap visualization map.
+
+		var link = (window.location.protocol + "//" + window.location.host 
+					+ "/" + window.location.pathname);
+		
+		alert(link);
+		selected_tool = undefined;
+     
+    });
+});
+
Binary file hexagram/tsv.pyc has changed