Mercurial > repos > adam-novak > hexagram
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; + + }); +}); +