Mercurial > repos > iuc > meme_fimo
view test-data/dreme2.html @ 12:02f6ad791bbf draft
planemo upload for repository https://github.com/galaxyproject/tools-iuc/tree/master/tools/meme commit 42fa6e319cf1a97330818dc8c869871a32f0e7aa
author | iuc |
---|---|
date | Wed, 25 Apr 2018 12:12:47 -0400 |
parents | |
children |
line wrap: on
line source
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>DREME</title> <script> // @JSON_VAR data var data = { "program": "dreme", "version": "4.12.0", "release": "Tue Jun 27 16:22:50 2017 -0700", "cmd": [ "dreme", "-oc", "dreme_out_adv", "-rna", "-norc", "-p", "dreme_test_sites.fa", "-e", "0.00001", "-mink", "4", "-maxk", "10" ], "options": { "revcomp": false, "ngen": 100, "add_pv_thresh": 0.01, "seed": 1, "stop": { "evalue": "1e-05" } }, "alphabet": { "name": "RNA", "like": "rna", "ncore": 4, "symbols": [ { "symbol": "A", "name": "Adenine", "colour": "CC0000" }, { "symbol": "C", "name": "Cytosine", "colour": "0000CC" }, { "symbol": "G", "name": "Guanine", "colour": "FFB300" }, { "symbol": "U", "aliases": "T", "name": "Uracil", "colour": "008000" }, { "symbol": "N", "aliases": "X.", "name": "Any base", "equals": "ACGU" }, { "symbol": "V", "name": "Not U", "equals": "ACG" }, { "symbol": "H", "name": "Not G", "equals": "ACU" }, { "symbol": "D", "name": "Not C", "equals": "AGU" }, { "symbol": "B", "name": "Not A", "equals": "CGU" }, { "symbol": "M", "name": "Amino", "equals": "AC" }, { "symbol": "R", "name": "Purine", "equals": "AG" }, { "symbol": "W", "name": "Weak", "equals": "AU" }, { "symbol": "S", "name": "Strong", "equals": "CG" }, { "symbol": "Y", "name": "Pyrimidine", "equals": "CU" }, { "symbol": "K", "name": "Keto", "equals": "GU" } ] }, "background": { "freqs": [0.221, 0.245, 0.221, 0.312] }, "sequence_db": { "name": "dreme test sites", "file": "dreme_test_sites.fa", "lmod": "Thu Apr 19 19:09:45 CEST 2018", "count": 1000 }, "control_db": { "name": "shuffled positive sequences", "from": "shuffled", "count": 1000, "freqs": [0.221, 0.245, 0.221, 0.312] }, "motifs": [ { "db": 0, "id": "UUYUCY", "alt": "DREME-1", "len": 6, "nsites": 459, "evalue": "3.3e-013", "p": 387, "n": 210, "pvalue": "2.6e-018", "unerased_evalue": "3.3e-013", "pwm": [ [0.000000, 0.000000, 0.000000, 1.000000], [0.000000, 0.000000, 0.000000, 1.000000], [0.000000, 0.294118, 0.000000, 0.705882], [0.000000, 0.000000, 0.000000, 1.000000], [0.000000, 1.000000, 0.000000, 0.000000], [0.000000, 0.474946, 0.000000, 0.525054] ], "matches": [ { "seq": "UUUUCC", "p": 147, "n": 75, "pvalue": "1.8e-007", "evalue": "2.2e-002" }, { "seq": "UUUUCU", "p": 155, "n": 94, "pvalue": "2.2e-005", "evalue": "2.8e+000" }, { "seq": "UUCUCU", "p": 94, "n": 51, "pvalue": "1.3e-004", "evalue": "1.7e+001" }, { "seq": "UUCUCC", "p": 75, "n": 42, "pvalue": "1.1e-003", "evalue": "1.4e+002" } ] }, { "db": 0, "id": "YAGG", "alt": "DREME-2", "len": 4, "nsites": 793, "evalue": "1.4e-011", "p": 600, "n": 416, "pvalue": "1.1e-016", "unerased_evalue": "6.3e-012", "pwm": [ [0.000000, 0.692308, 0.000000, 0.307692], [1.000000, 0.000000, 0.000000, 0.000000], [0.000000, 0.000000, 1.000000, 0.000000], [0.000000, 0.000000, 1.000000, 0.000000] ], "matches": [ { "seq": "CAGG", "p": 441, "n": 304, "pvalue": "1.5e-010", "evalue": "1.8e-005" }, { "seq": "UAGG", "p": 232, "n": 165, "pvalue": "1.1e-004", "evalue": "1.3e+001" } ] } ], "runtime": { "host": "ThinkPad-T450s", "when": "Tue Apr 24 18:44:36 CEST 2018", "cpu": 18.17, "real": 18.17, "stop": "evalue" } }; </script> <script> var site_url = "http://meme-suite.org"; </script> <script> /* * $ * * Shorthand function for getElementById */ function $(el) { return document.getElementById(el); } /* * See http://stackoverflow.com/a/5450113/66387 * Does string multiplication like the perl x operator. */ function string_mult(pattern, count) { if (count < 1) return ''; var result = ''; while (count > 1) { if (count & 1) result += pattern; count >>= 1, pattern += pattern; } return result + pattern; } /* * See http://stackoverflow.com/questions/814613/how-to-read-get-data-from-a-url-using-javascript * Slightly modified with information from * https://developer.mozilla.org/en/DOM/window.location */ function parse_params() { "use strict"; var search, queryStart, queryEnd, query, params, nvPairs, i, nv, n, v; search = window.location.search; queryStart = search.indexOf("?") + 1; queryEnd = search.indexOf("#") + 1 || search.length + 1; query = search.slice(queryStart, queryEnd - 1); if (query === search || query === "") return {}; params = {}; nvPairs = query.replace(/\+/g, " ").split("&"); for (i = 0; i < nvPairs.length; i++) { nv = nvPairs[i].split("="); n = decodeURIComponent(nv[0]); v = decodeURIComponent(nv[1]); // allow a name to be used multiple times // storing each value in the array if (!(n in params)) { params[n] = []; } params[n].push(nv.length === 2 ? v : null); } return params; } /* * coords * * Calculates the x and y offset of an element. * From http://www.quirksmode.org/js/findpos.html * with alterations to take into account scrolling regions */ function coords(elem) { var myX = myY = 0; if (elem.getBoundingClientRect) { var rect; rect = elem.getBoundingClientRect(); myX = rect.left + ((typeof window.pageXOffset !== "undefined") ? window.pageXOffset : document.body.scrollLeft); myY = rect.top + ((typeof window.pageYOffset !== "undefined") ? window.pageYOffset : document.body.scrollTop); } else { // this fall back doesn't properly handle absolutely positioned elements // inside a scrollable box var node; if (elem.offsetParent) { // subtract all scrolling node = elem; do { myX -= node.scrollLeft ? node.scrollLeft : 0; myY -= node.scrollTop ? node.scrollTop : 0; } while (node = node.parentNode); // this will include the page scrolling (which is unwanted) so add it back on myX += (typeof window.pageXOffset !== "undefined") ? window.pageXOffset : document.body.scrollLeft; myY += (typeof window.pageYOffset !== "undefined") ? window.pageYOffset : document.body.scrollTop; // sum up offsets node = elem; do { myX += node.offsetLeft; myY += node.offsetTop; } while (node = node.offsetParent); } } return [myX, myY]; } /* * position_popup * * Positions a popup relative to an anchor element. * * The avaliable positions are: * 0 - Centered below the anchor. */ function position_popup(anchor, popup, position) { "use strict"; var a_x, a_y, a_w, a_h, p_x, p_y, p_w, p_h; var a_xy, spacer, margin, scrollbar, page_w; // define constants spacer = 5; margin = 15; scrollbar = 15; // define the positions and widths a_xy = coords(anchor); a_x = a_xy[0]; a_y = a_xy[1]; a_w = anchor.offsetWidth; a_h = anchor.offsetHeight; p_w = popup.offsetWidth; p_h = popup.offsetHeight; page_w = null; if (window.innerWidth) { page_w = window.innerWidth; } else if (document.body) { page_w = document.body.clientWidth; } // check the position type is defined if (typeof position !== "number") { position = 0; } // calculate the popup position switch (position) { case 1: p_x = a_x + a_w + spacer; p_y = a_y + (a_h / 2) - (p_h / 2); break; case 0: default: p_x = a_x + (a_w / 2) - (p_w / 2); p_y = a_y + a_h + spacer; break; } // constrain the popup position if (p_x < margin) { p_x = margin; } else if (page_w != null && (p_x + p_w) > (page_w - margin - scrollbar)) { p_x = page_w - margin - scrollbar - p_w; } if (p_y < margin) { p_y = margin; } // position the popup popup.style.left = p_x + "px"; popup.style.top = p_y + "px"; } function lookup_help_popup(popup_id) { var _body, pop, info; pop = document.getElementById(popup_id); if (pop == null) { _body = document.getElementsByTagName("body")[0]; pop = document.createElement("div"); pop.className = "pop_content"; pop.id = popup_id; pop.style.backgroundColor = "#FFC"; pop.style.borderColor = "black"; info = document.createElement("p"); info.style.fontWeight = "bold"; info.appendChild(document.createTextNode("Error: No popup for topic \"" + popup_id + "\".")); pop.appendChild(info); // this might cause problems with the menu, but as this only happens // when something is already wrong I don't think that's too much of a problem _body.insertBefore(pop, _body.firstChild); } if (document.getElementsByTagName('body')[0].hasAttribute("data-autobtns")) { if (!/\bauto_buttons\b/.test(pop.className)) { pop.className += " auto_buttons"; var back_btn_sec = document.createElement("div"); back_btn_sec.className = "nested_only pop_back_sec"; var back_btn = document.createElement("span"); back_btn.className = "pop_back"; back_btn.appendChild(document.createTextNode("<< back")); back_btn.addEventListener("click", function(e) { help_return(); }, false); back_btn_sec.appendChild(back_btn); pop.insertBefore(back_btn_sec, pop.firstChild); var close_btn_sec = document.createElement("div"); close_btn_sec.className = "pop_close_sec"; var close_btn = document.createElement("span"); close_btn.className = "pop_close"; close_btn.appendChild(document.createTextNode("close")); close_btn.addEventListener("click", function(e) { help_popup(); }, false); close_btn_sec.appendChild(close_btn); pop.appendChild(close_btn_sec); } } return pop; } /* * help_popup * * Moves around help pop-ups so they appear * below an activator. */ function help_popup(activator, popup_id) { "use strict"; var pop; // set default values if (typeof help_popup.popup === "undefined") { help_popup.popup = []; } if (typeof help_popup.activator === "undefined") { help_popup.activator = null; } var last_pop = (help_popup.popup.length > 0 ? help_popup.popup[help_popup.popup.length - 1] : null); if (typeof(activator) == "undefined") { // no activator so hide if (last_pop != null) { last_pop.style.display = 'none'; help_popup.popup = []; } return; } pop = lookup_help_popup(popup_id); if (pop == last_pop) { if (activator == help_popup.activator) { //hide popup (as we've already shown it for the current help button) last_pop.style.display = 'none'; help_popup.popup = []; return; // toggling complete! } } else if (last_pop != null) { //activating different popup so hide current one last_pop.style.display = 'none'; } help_popup.popup = [pop]; help_popup.activator = activator; toggle_class(pop, "nested", false); //must make the popup visible to measure it or it has zero width pop.style.display = 'block'; position_popup(activator, pop); } /* * help_refine * * Intended for links within a help popup. Stores a stack of state so * you can go back. */ function help_refine(popup_id) { if (help_popup.popup == null || help_popup.popup.length == 0 || help_popup.activator == null) { throw new Error("Can not refine a help popup when one is not shown!"); } var pop = lookup_help_popup(popup_id); var last_pop = help_popup.popup[help_popup.popup.length - 1]; if (pop == last_pop) return; // slightly odd, but no real cause for alarm help_popup.popup.push(pop); toggle_class(pop, "nested", true); last_pop.style.display = "none"; //must make the popup visible to measure it or it has zero width pop.style.display = "block"; position_popup(help_popup.activator, pop); } /* * help_return * * Intended for links within a help popup. Stores a stack of state so * you can go back. */ function help_return() { if (help_popup.popup == null || help_popup.popup.length == 0 || help_popup.activator == null) { throw new Error("Can not return to a earlier help popup when one is not shown!"); } var last_pop = help_popup.popup.pop(); last_pop.style.display = "none"; var pop = (help_popup.popup.length > 0 ? help_popup.popup[help_popup.popup.length - 1] : null); if (pop != null) { toggle_class(pop, "nested", help_popup.popup.length > 1); pop.style.display = "block"; position_popup(help_popup.activator, pop); } else { help_popup.activator = null; } } /* * update_scroll_pad * * Creates padding at the bottom of the page to allow * scrolling of anything into view. */ function update_scroll_pad() { var page, pad; page = (document.compatMode === "CSS1Compat") ? document.documentElement : document.body; pad = $("scrollpad"); if (pad === null) { pad = document.createElement("div"); pad.id = 'scrollpad'; document.getElementsByTagName('body')[0].appendChild(pad); } pad.style.height = Math.abs(page.clientHeight - 100) + "px"; } function substitute_classes(node, remove, add) { "use strict"; var list, all, i, cls, classes; list = node.className.split(/\s+/); all = {}; for (i = 0; i < list.length; i++) { if (list[i].length > 0) all[list[i]] = true; } for (i = 0; i < remove.length; i++) { if (all.hasOwnProperty(remove[i])) { delete all[remove[i]]; } } for (i = 0; i < add.length; i++) { all[add[i]] = true; } classes = ""; for (cls in all) { classes += cls + " "; } node.className = classes; } /* * toggle_class * * Adds or removes a class from the node. If the parameter 'enabled' is not * passed then the existence of the class will be toggled, otherwise it will be * included if enabled is true. */ function toggle_class(node, cls, enabled) { var classes = node.className; var list = classes.replace(/^\s+/, '').replace(/\s+$/, '').split(/\s+/); var found = false; for (var i = 0; i < list.length; i++) { if (list[i] == cls) { list.splice(i, 1); i--; found = true; } } if (typeof enabled == "undefined") { if (!found) list.push(cls); } else { if (enabled) list.push(cls); } node.className = list.join(" "); } /* * find_child * * Searches child nodes in depth first order and returns the first it finds * with the className specified. * TODO replace with querySelector */ function find_child(node, className) { var pattern; if (node == null || typeof node !== "object") { return null; } if (typeof className === "string") { pattern = new RegExp("\\b" + className + "\\b"); } else { pattern = className; } if (node.nodeType == Node.ELEMENT_NODE && pattern.test(node.className)) { return node; } else { var result = null; for (var i = 0; i < node.childNodes.length; i++) { result = find_child(node.childNodes[i], pattern); if (result != null) break; } return result; } } /* * find_parent * * Searches parent nodes outwards from the node and returns the first it finds * with the className specified. */ function find_parent(node, className) { var pattern; pattern = new RegExp("\\b" + className + "\\b"); do { if (node.nodeType == Node.ELEMENT_NODE && pattern.test(node.className)) { return node; } } while (node = node.parentNode); return null; } /* * find_parent_tag * * Searches parent nodes outwards from the node and returns the first it finds * with the tag name specified. HTML tags should be specified in upper case. */ function find_parent_tag(node, tag_name) { do { if (node.nodeType == Node.ELEMENT_NODE && node.tagName == tag_name) { return node; } } while (node = node.parentNode); return null; } /* * __toggle_help * * Uses the 'topic' property of the this object to * toggle display of a help topic. * * This function is not intended to be called directly. */ function __toggle_help(e) { if (!e) e = window.event; if (e.type === "keydown") { if (e.keyCode !== 13 && e.keyCode !== 32) { return; } // stop a submit or something like that e.preventDefault(); } help_popup(this, this.getAttribute("data-topic")); } function setup_help_button(button) { "use strict"; var topic; if (button.hasAttribute("data-topic")) { topic = button.getAttribute("data-topic"); if (document.getElementById(topic) != null) { button.tabIndex = "0"; // make keyboard selectable button.addEventListener("click", function() { help_popup(button, topic); }, false); button.addEventListener("keydown", function(e) { // toggle only on Enter or Spacebar, let other keys do their thing if (e.keyCode !== 13 && e.keyCode !== 32) return; // stop a submit or something like that e.preventDefault(); help_popup(button, topic); }, false); } else { button.style.visibility = "hidden"; } } button.className += " active"; } /* * help_button * * Makes a help button for the passed topic. */ function help_button(topic) { var btn = document.createElement("div"); btn.className = "help"; btn.setAttribute("data-topic", topic); setup_help_button(btn); return btn; } /* * prepare_download * * Sets the attributes of a link to setup a file download using the given content. * If no link is provided then create one and click it. */ function prepare_download(content, mimetype, filename, link) { "use strict"; // if no link is provided then create one and click it var click_link = false; if (!link) { link = document.createElement("a"); click_link = true; } try { // Use a BLOB to convert the text into a data URL. // We could do this manually with a base 64 conversion. // This will only be supported on modern browsers, // hence the try block. var blob = new Blob([content], {type: mimetype}); var reader = new FileReader(); reader.onloadend = function() { // If we're lucky the browser will also support the download // attribute which will let us suggest a file name to save the link. // Otherwise it is likely that the filename will be unintelligible. link.setAttribute("download", filename); link.href = reader.result; if (click_link) { // must add the link to click it document.body.appendChild(link); link.click(); document.body.removeChild(link); } } reader.readAsDataURL(blob); } catch (error) { if (console && console.log) console.log(error); // probably an old browser link.href = ""; link.visible = false; } } /* * add_cell * * Add a cell to the table row. */ function add_cell(row, node, cls, click_action) { var cell = row.insertCell(row.cells.length); if (node) cell.appendChild(node); if (cls && cls !== "") cell.className = cls; if (click_action) cell.addEventListener("click", click_action, false); } /* * add_header_cell * * Add a header cell to the table row. */ function add_header_cell(row, node, help_topic, cls, colspan) { var th = document.createElement("th"); if (node) th.appendChild(node); if (help_topic && help_topic !== "") th.appendChild(help_button(help_topic)); if (cls && cls !== "") th.className = cls; if (typeof colspan == "number" && colspan > 1) th.colSpan = colspan; row.appendChild(th); } /* * add_text_cell * * Add a text cell to the table row. */ function add_text_cell(row, text, cls, action) { var node = null; if (typeof(text) != 'undefined') node = document.createTextNode(text); add_cell(row, node, cls, action); } /* * add_text_header_cell * * Add a text header cell to the table row. */ function add_text_header_cell(row, text, help_topic, cls, action, colspan) { var node = null; if (typeof(text) != 'undefined') { var nbsp = (help_topic ? "\u00A0" : ""); var str = "" + text; var parts = str.split(/\n/); if (parts.length === 1) { if (action) { node = document.createElement("span"); node.appendChild(document.createTextNode(str + nbsp)); } else { node = document.createTextNode(str + nbsp); } } else { node = document.createElement("span"); for (var i = 0; i < parts.length; i++) { if (i !== 0) { node.appendChild(document.createElement("br")); } node.appendChild(document.createTextNode(parts[i])); } } if (action) { node.addEventListener("click", action, false); node.style.cursor = "pointer"; } } add_header_cell(row, node, help_topic, cls, colspan); } function setup_help() { "use strict"; var help_buttons, i; help_buttons = document.querySelectorAll(".help:not(.active)"); for (i = 0; i < help_buttons.length; i++) { setup_help_button(help_buttons[i]); } } function setup_scrollpad() { "use strict"; if (document.getElementsByTagName('body')[0].hasAttribute("data-scrollpad") && document.getElementById("scrollpad") == null) { window.addEventListener("resize", update_scroll_pad, false); update_scroll_pad(); } } // anon function to avoid polluting global scope (function() { "use strict"; window.addEventListener("load", function load(evt) { window.removeEventListener("load", load, false); setup_help(); setup_scrollpad(); }, false); })(); /* * make_link * * Creates a text node and if a URL is specified it surrounds it with a link. * If the URL doesn't begin with "http://" it automatically adds it, as * relative links don't make much sense in this context. */ function make_link(text, url) { var textNode = null; var link = null; if (typeof text !== "undefined" && text !== null) textNode = document.createTextNode(text); if (typeof url === "string") { if (url.indexOf("//") == -1) { url = "http://" + url; } link = document.createElement('a'); link.href = url; if (textNode) link.appendChild(textNode); return link; } return textNode; } </script> <script> function motif_logo_template(inputs) { function _input(name) { if (typeof inputs[name] === "undefined") { throw new Error("Missing template variable: " + name); } return inputs[name]; } return ( "%!PS-Adobe-3.0 EPSF-3.0\n" + "%%Title: Sequence Logo : " + _input("TITLE") + "\n" + "%%Creator: " + _input("CREATOR") + "\n" + "%%CreationDate: " + _input("CREATIONDATE") + "\n" + "%%BoundingBox: 0 0 " + _input("BOUNDINGWIDTH") + " " + _input("BOUNDINGHEIGHT") + " \n" + "%%Pages: 0\n" + "%%DocumentFonts: \n" + "%%EndComments\n" + "\n" + "% ---- CONSTANTS ----\n" + "\/cmfactor 72 2.54 div def % defines points -> cm conversion\n" + "\/cm {cmfactor mul} bind def % defines centimeters\n" + "\n" + "% ---- VARIABLES ----\n" + "\n" + "% NA = Nucleic Acid, AA = Amino Acid\n" + "\/logoType (" + _input("LOGOTYPE") + ") def \n" + "\n" + "\/logoTitle (" + _input("TITLE") + ") def\n" + "\n" + "% Dimensions in cm\n" + "\/logoWidth " + _input("LOGOWIDTH") + " cm def\n" + "\/logoHeight " + _input("LOGOLINEHEIGHT") + " cm def\n" + "\/totalHeight " + _input("LOGOHEIGHT") + " cm def\n" + "\n" + "\/yaxis " + _input("YAXIS") + " def\n" + "\/yaxisLabel (" + _input("YAXISLABEL") + ") def\n" + "\/yaxisBits " + _input("BARBITS") + " def % bits\n" + "\/yaxisTicBits " + _input("TICBITS") + " def\n" + "\n" + "\/xaxis " + _input("NUMBERING") + " def\n" + "\/xaxisLabel (" + _input("XAXISLABEL") + ") def\n" + "\/showEnds (" + _input("SHOWENDS") + ") def \n" + "\n" + "\/showFineprint true def\n" + "\/fineprint (" + _input("FINEPRINT") + ") def\n" + "\n" + "\/charsPerLine " + _input("CHARSPERLINE") + " def\n" + "\n" + "\/showingBox " + _input("SHOWINGBOX") + " def \n" + "\/shrinking false def % true falses\n" + "\/shrink 1.0 def\n" + "\/outline " + _input("OUTLINE") + " def\n" + "\n" + "\/IbeamFraction " + _input("ERRORBARFRACTION") + " def\n" + "\/IbeamGray 0.50 def\n" + "\/IbeamLineWidth 0.5 def\n" + "\n" + "\/fontsize " + _input("FONTSIZE") + " def\n" + "\/titleFontsize " + _input("TITLEFONTSIZE") + " def\n" + "\/smallFontsize " + _input("SMALLFONTSIZE") + " def\n" + "\n" + "\/topMargin " + _input("TOPMARGIN") + " cm def\n" + "\/bottomMargin " + _input("BOTTOMMARGIN") + " cm def\n" + "\n" + "\/defaultColor [0 0 0] def \n" + "\n" + _input("COLORDICT") + "\n" + "\n" + "\/colorDict fullColourDict def\n" + "\n" + "% ---- DERIVED PARAMETERS ----\n" + "\n" + "\/leftMargin\n" + " fontsize 3.5 mul\n" + "\n" + "def \n" + "\n" + "\/rightMargin \n" + " %Add extra room if showing ends\n" + " showEnds (false) eq { fontsize}{fontsize 1.5 mul} ifelse\n" + "def\n" + "\n" + "\/yaxisHeight \n" + " logoHeight \n" + " bottomMargin sub \n" + " topMargin sub\n" + "def\n" + "\n" + "\/ticWidth fontsize 2 div def\n" + "\n" + "\/pointsPerBit yaxisHeight yaxisBits div def\n" + "\n" + "\/stackMargin 1 def\n" + "\n" + "% Do not add space aroung characters if characters are boxed\n" + "\/charRightMargin \n" + " showingBox { 0.0 } {stackMargin} ifelse\n" + "def\n" + "\n" + "\/charTopMargin \n" + " showingBox { 0.0 } {stackMargin} ifelse\n" + "def\n" + "\n" + "\/charWidth\n" + " logoWidth\n" + " leftMargin sub\n" + " rightMargin sub\n" + " charsPerLine div\n" + " charRightMargin sub\n" + "def\n" + "\n" + "\/charWidth4 charWidth 4 div def\n" + "\/charWidth2 charWidth 2 div def\n" + "\n" + "\/stackWidth \n" + " charWidth charRightMargin add\n" + "def\n" + " \n" + "\/numberFontsize \n" + " fontsize charWidth lt {fontsize}{charWidth} ifelse\n" + "def\n" + "\n" + "% movements to place 5'\/N and 3'\/C symbols\n" + "\/leftEndDeltaX fontsize neg def\n" + "\/leftEndDeltaY fontsize 1.5 mul neg def\n" + "\/rightEndDeltaX fontsize 0.25 mul def\n" + "\/rightEndDeltaY leftEndDeltaY def\n" + "\n" + "% Outline width is proporional to charWidth, \n" + "% but no less that 1 point\n" + "\/outlinewidth \n" + " charWidth 32 div dup 1 gt {}{pop 1} ifelse\n" + "def\n" + "\n" + "\n" + "% ---- PROCEDURES ----\n" + "\n" + "\/StartLogo { \n" + " % Save state\n" + " save \n" + " gsave \n" + "\n" + " % Print Logo Title, top center \n" + " gsave \n" + " SetStringFont\n" + "\n" + " logoWidth 2 div\n" + " logoTitle\n" + " stringwidth pop 2 div sub\n" + " totalHeight\n" + " titleFontsize sub\n" + " moveto\n" + "\n" + " logoTitle\n" + " show\n" + " grestore\n" + "\n" + " % Print X-axis label, bottom center\n" + " gsave\n" + " SetStringFont\n" + "\n" + " logoWidth 2 div\n" + " xaxisLabel\n" + " stringwidth pop 2 div sub\n" + " 0\n" + " titleFontsize 3 div\n" + " add\n" + " moveto\n" + "\n" + " xaxisLabel\n" + " show\n" + " grestore\n" + "\n" + " % Show Fine Print\n" + " showFineprint {\n" + " gsave\n" + " SetSmallFont\n" + " logoWidth\n" + " fineprint stringwidth pop sub\n" + " smallFontsize sub\n" + " smallFontsize 3 div\n" + " moveto\n" + " \n" + " fineprint show\n" + " grestore\n" + " } if\n" + "\n" + " % Move to lower left corner of last line, first stack\n" + " leftMargin bottomMargin translate\n" + "\n" + " % Move above first line ready for StartLine \n" + " 0 totalHeight translate\n" + "\n" + " SetLogoFont\n" + "} bind def\n" + "\n" + "\/EndLogo { \n" + " grestore \n" + " showpage \n" + " restore \n" + "} bind def\n" + "\n" + "\n" + "\/StartLine { \n" + " % move down to the bottom of the line:\n" + " 0 logoHeight neg translate\n" + " \n" + " gsave \n" + " yaxis { MakeYaxis } if\n" + " xaxis { showEnds (true) eq {ShowLeftEnd} if } if\n" + "} bind def\n" + "\n" + "\/EndLine{ \n" + " xaxis { showEnds (true) eq {ShowRightEnd} if } if\n" + " grestore \n" + "} bind def\n" + "\n" + "\n" + "\/MakeYaxis {\n" + " gsave \n" + " stackMargin neg 0 translate\n" + " ShowYaxisBar\n" + " ShowYaxisLabel\n" + " grestore\n" + "} bind def\n" + "\n" + "\n" + "\/ShowYaxisBar { \n" + " gsave \n" + " SetStringFont\n" + "\n" + " \/str 10 string def % string to hold number \n" + " \/smallgap stackMargin 2 div def\n" + "\n" + " % Draw first tic and bar\n" + " gsave \n" + " ticWidth neg 0 moveto \n" + " ticWidth 0 rlineto \n" + " 0 yaxisHeight rlineto\n" + " stroke\n" + " grestore\n" + "\n" + " \n" + " % Draw the tics\n" + " % initial increment limit proc for\n" + " 0 yaxisTicBits yaxisBits abs %cvi\n" + " {\/loopnumber exch def\n" + "\n" + " % convert the number coming from the loop to a string\n" + " % and find its width\n" + " loopnumber 10 str cvrs\n" + " \/stringnumber exch def % string representing the number\n" + "\n" + " stringnumber stringwidth pop\n" + " \/numberwidth exch def % width of number to show\n" + "\n" + " \/halfnumberheight\n" + " stringnumber CharBoxHeight 2 div\n" + " def\n" + "\n" + " numberwidth % move back width of number\n" + " neg loopnumber pointsPerBit mul % shift on y axis\n" + " halfnumberheight sub % down half the digit\n" + "\n" + " moveto % move back the width of the string\n" + "\n" + " ticWidth neg smallgap sub % Move back a bit more \n" + " 0 rmoveto % move back the width of the tic \n" + "\n" + " stringnumber show\n" + " smallgap 0 rmoveto % Make a small gap \n" + "\n" + " % now show the tic mark\n" + " 0 halfnumberheight rmoveto % shift up again\n" + " ticWidth 0 rlineto\n" + " stroke\n" + " } for\n" + " grestore\n" + "} bind def\n" + "\n" + "\/ShowYaxisLabel {\n" + " gsave\n" + " SetStringFont\n" + "\n" + " % How far we move left depends on the size of\n" + " % the tic labels.\n" + " \/str 10 string def % string to hold number \n" + " yaxisBits yaxisTicBits div cvi yaxisTicBits mul \n" + " str cvs stringwidth pop\n" + " ticWidth 1.5 mul add neg \n" + "\n" + "\n" + " yaxisHeight\n" + " yaxisLabel stringwidth pop\n" + " sub 2 div\n" + "\n" + " translate\n" + " 90 rotate\n" + " 0 0 moveto\n" + " yaxisLabel show\n" + " grestore\n" + "} bind def\n" + "\n" + "\n" + "\/StartStack { % <stackNumber> startstack\n" + " xaxis {MakeNumber}{pop} ifelse\n" + " gsave\n" + "} bind def\n" + "\n" + "\/EndStack {\n" + " grestore\n" + " stackWidth 0 translate\n" + "} bind def\n" + "\n" + "\n" + "% Draw a character whose height is proportional to symbol bits\n" + "\/MakeSymbol{ % charbits character MakeSymbol\n" + " gsave\n" + " \/char exch def\n" + " \/bits exch def\n" + "\n" + " \/bitsHeight \n" + " bits pointsPerBit mul \n" + " def\n" + "\n" + " \/charHeight \n" + " bitsHeight charTopMargin sub\n" + " dup \n" + " 0.0 gt {}{pop 0.0} ifelse % if neg replace with zero \n" + " def \n" + " \n" + " charHeight 0.0 gt {\n" + " char SetColor\n" + " charWidth charHeight char ShowChar\n" + "\n" + " showingBox { % Unfilled box\n" + " 0 0 charWidth charHeight false ShowBox\n" + " } if\n" + "\n" + "\n" + " } if\n" + "\n" + " grestore\n" + "\n" + " 0 bitsHeight translate \n" + "} bind def\n" + "\n" + "\n" + "\/ShowChar { % <width> <height> <char> ShowChar\n" + " gsave\n" + " \/tc exch def % The character\n" + " \/ysize exch def % the y size of the character\n" + " \/xsize exch def % the x size of the character\n" + "\n" + " \/xmulfactor 1 def \n" + " \/ymulfactor 1 def\n" + " \/limmulfactor 0.01 def\n" + " \/drawable true def\n" + "\n" + " \n" + " % if ysize is negative, make everything upside down!\n" + " ysize 0 lt {\n" + " % put ysize normal in this orientation\n" + " \/ysize ysize abs def\n" + " xsize ysize translate\n" + " 180 rotate\n" + " } if\n" + "\n" + " shrinking {\n" + " xsize 1 shrink sub 2 div mul\n" + " ysize 1 shrink sub 2 div mul translate \n" + "\n" + " shrink shrink scale\n" + " } if\n" + "\n" + " % Calculate the font scaling factors\n" + " % Loop twice to catch small correction due to first scaling\n" + " 2 {\n" + " gsave\n" + " xmulfactor ymulfactor scale\n" + " \n" + " ysize % desired size of character in points\n" + " tc CharBoxHeight \n" + " dup 0.0 ne {\n" + " div % factor by which to scale up the character\n" + " \/ymulfactor exch def\n" + " } % end if\n" + " {pop pop}\n" + " ifelse\n" + "\n" + " xsize % desired size of character in points\n" + " tc CharBoxWidth \n" + " dup 0.0 ne {\n" + " div % factor by which to scale up the character\n" + " \/xmulfactor exch def\n" + " } % end if\n" + " {pop pop}\n" + " ifelse\n" + " grestore\n" + " % if the multiplication factors get too small we need to avoid a crash\n" + " xmulfactor limmulfactor lt {\n" + " \/xmulfactor 1 def\n" + " \/drawable false def\n" + " } if\n" + " ymulfactor limmulfactor lt {\n" + " \/ymulfactor 1 def\n" + " \/drawable false def\n" + " } if\n" + " } repeat\n" + "\n" + " % Adjust horizontal position if the symbol is an I\n" + " tc (I) eq {\n" + " charWidth 2 div % half of requested character width\n" + " tc CharBoxWidth 2 div % half of the actual character\n" + " sub 0 translate\n" + " % Avoid x scaling for I \n" + " \/xmulfactor 1 def \n" + " } if\n" + "\n" + "\n" + " % ---- Finally, draw the character\n" + " drawable { \n" + " newpath\n" + " xmulfactor ymulfactor scale\n" + "\n" + " % Move lower left corner of character to start point\n" + " tc CharBox pop pop % llx lly : Lower left corner\n" + " exch neg exch neg\n" + " moveto\n" + "\n" + " outline { % outline characters:\n" + " outlinewidth setlinewidth\n" + " tc true charpath\n" + " gsave 1 setgray fill grestore\n" + " clip stroke\n" + " } { % regular characters\n" + " tc show\n" + " } ifelse\n" + " } if\n" + "\n" + " grestore\n" + "} bind def\n" + "\n" + "\n" + "\/ShowBox { % x1 y1 x2 y2 filled ShowBox\n" + " gsave\n" + " \/filled exch def \n" + " \/y2 exch def\n" + " \/x2 exch def\n" + " \/y1 exch def\n" + " \/x1 exch def\n" + " newpath\n" + " x1 y1 moveto\n" + " x2 y1 lineto\n" + " x2 y2 lineto\n" + " x1 y2 lineto\n" + " closepath\n" + "\n" + " clip\n" + " \n" + " filled {\n" + " fill\n" + " }{ \n" + " 0 setgray stroke \n" + " } ifelse\n" + "\n" + " grestore\n" + "} bind def\n" + "\n" + "\n" + "\/MakeNumber { % number MakeNumber\n" + " gsave\n" + " SetNumberFont\n" + " stackWidth 0 translate\n" + " 90 rotate % rotate so the number fits\n" + " dup stringwidth pop % find the length of the number\n" + " neg % prepare for move\n" + " stackMargin sub % Move back a bit\n" + " charWidth (0) CharBoxHeight % height of numbers\n" + " sub 2 div %\n" + " moveto % move back to provide space\n" + " show\n" + " grestore\n" + "} bind def\n" + "\n" + "\n" + "\/Ibeam{ % heightInBits Ibeam\n" + " gsave\n" + " % Make an Ibeam of twice the given height in bits\n" + " \/height exch pointsPerBit mul def \n" + " \/heightDRAW height IbeamFraction mul def\n" + "\n" + " IbeamLineWidth setlinewidth\n" + " IbeamGray setgray \n" + "\n" + " charWidth2 height neg translate\n" + " ShowIbar\n" + " newpath\n" + " 0 0 moveto\n" + " 0 heightDRAW rlineto\n" + " stroke\n" + " newpath\n" + " 0 height moveto\n" + " 0 height rmoveto\n" + " currentpoint translate\n" + " ShowIbar\n" + " newpath\n" + " 0 0 moveto\n" + " 0 heightDRAW neg rlineto\n" + " currentpoint translate\n" + " stroke\n" + " grestore\n" + "} bind def\n" + "\n" + "\n" + "\/ShowIbar { % make a horizontal bar\n" + " gsave\n" + " newpath\n" + " charWidth4 neg 0 moveto\n" + " charWidth4 0 lineto\n" + " stroke\n" + " grestore\n" + "} bind def\n" + "\n" + "\n" + "\/ShowLeftEnd {\n" + " gsave\n" + " SetStringFont\n" + " leftEndDeltaX leftEndDeltaY moveto\n" + " logoType (NA) eq {(5) show ShowPrime} if\n" + " logoType (AA) eq {(N) show} if\n" + " grestore\n" + "} bind def\n" + "\n" + "\n" + "\/ShowRightEnd { \n" + " gsave\n" + " SetStringFont\n" + " rightEndDeltaX rightEndDeltaY moveto\n" + " logoType (NA) eq {(3) show ShowPrime} if\n" + " logoType (AA) eq {(C) show} if\n" + " grestore\n" + "} bind def\n" + "\n" + "\n" + "\/ShowPrime {\n" + " gsave\n" + " SetPrimeFont\n" + " (\\242) show \n" + " grestore\n" + "} bind def\n" + "\n" + " \n" + "\/SetColor{ % <char> SetColor\n" + " dup colorDict exch known {\n" + " colorDict exch get aload pop setrgbcolor\n" + " } {\n" + " pop\n" + " defaultColor aload pop setrgbcolor\n" + " } ifelse \n" + "} bind def\n" + "\n" + "% define fonts\n" + "\/SetTitleFont {\/Times-Bold findfont titleFontsize scalefont setfont} bind def\n" + "\/SetLogoFont {\/Helvetica-Bold findfont charWidth scalefont setfont} bind def\n" + "\/SetStringFont{\/Helvetica-Bold findfont fontsize scalefont setfont} bind def\n" + "\/SetPrimeFont {\/Symbol findfont fontsize scalefont setfont} bind def\n" + "\/SetSmallFont {\/Helvetica findfont smallFontsize scalefont setfont} bind def\n" + "\n" + "\/SetNumberFont {\n" + " \/Helvetica-Bold findfont \n" + " numberFontsize\n" + " scalefont\n" + " setfont\n" + "} bind def\n" + "\n" + "%Take a single character and return the bounding box\n" + "\/CharBox { % <char> CharBox <lx> <ly> <ux> <uy>\n" + " gsave\n" + " newpath\n" + " 0 0 moveto\n" + " % take the character off the stack and use it here:\n" + " true charpath \n" + " flattenpath \n" + " pathbbox % compute bounding box of 1 pt. char => lx ly ux uy\n" + " % the path is here, but toss it away ...\n" + " grestore\n" + "} bind def\n" + "\n" + "\n" + "% The height of a characters bounding box\n" + "\/CharBoxHeight { % <char> CharBoxHeight <num>\n" + " CharBox\n" + " exch pop sub neg exch pop\n" + "} bind def\n" + "\n" + "\n" + "% The width of a characters bounding box\n" + "\/CharBoxWidth { % <char> CharBoxHeight <num>\n" + " CharBox\n" + " pop exch pop sub neg \n" + "} bind def\n" + "\n" + "% Set the colour scheme to be faded to indicate trimming\n" + "\/MuteColour {\n" + " \/colorDict mutedColourDict def\n" + "} def\n" + "\n" + "% Restore the colour scheme to the normal colours\n" + "\/RestoreColour {\n" + " \/colorDict fullColourDict def\n" + "} def\n" + "\n" + "% Draw the background for a trimmed section\n" + "% takes the number of columns as a parameter\n" + "\/DrawTrimBg { % <num> DrawTrimBox\n" + " \/col exch def\n" + " \n" + " \/boxwidth \n" + " col stackWidth mul \n" + " def\n" + " \n" + " gsave\n" + " 0.97 setgray\n" + "\n" + " newpath\n" + " 0 0 moveto\n" + " boxwidth 0 rlineto\n" + " 0 yaxisHeight rlineto\n" + " 0 yaxisHeight lineto\n" + " closepath\n" + " \n" + " fill\n" + " grestore\n" + "} def\n" + "\n" + "\/DrawTrimEdge {\n" + " gsave\n" + " 0.2 setgray\n" + " [2] 0 setdash\n" + "\n" + " newpath\n" + " 0 0 moveto\n" + " 0 yaxisHeight lineto\n" + " \n" + " stroke\n" + "\n" + "} def\n" + "\n" + "\n" + "% Deprecated names\n" + "\/startstack {StartStack} bind def\n" + "\/endstack {EndStack} bind def\n" + "\/makenumber {MakeNumber} bind def\n" + "\/numchar { MakeSymbol } bind def\n" + "\n" + "%%EndProlog\n" + "\n" + "%%Page: 1 1\n" + "StartLogo\n" + "\n" + _input("DATA") + "\n" + "\n" + "EndLogo\n" + "\n" + "%%EOF\n" ); }</script> <script> //====================================================================== // start Alphabet object //====================================================================== var Alphabet = function(alphabet, background) { "use strict"; var i, j, sym, aliases, complement, comp_e_sym, ambigs, generate_background; generate_background = (background == null); if (generate_background) { background = []; for (i = 0; i < alphabet.ncore; i++) background[i] = 1.0 / alphabet.ncore; } else if (alphabet.ncore != background.length) { throw new Error("The background length does not match the alphabet length."); } this.name = alphabet.name; this.like = (alphabet.like != null ? alphabet.like.toUpperCase() : null); this.ncore = alphabet.ncore; this.symbols = alphabet.symbols; this.background = background; this.genbg = generate_background; this.encode = {}; this.encode2core = {}; this.complement = {}; // check if all symbols are same case var seen_uc = false; var seen_lc = false; var check_case = function (syms) { var s, sym; if (typeof syms === "string") { for (s = 0; s < syms.length; s++) { sym = syms.charAt(s); if (sym >= 'a' && sym <= 'z') seen_lc = true; else if (sym >= 'A' && sym <= 'Z') seen_uc = true; } } }; for (i = 0; i < this.symbols.length; i++) { check_case(this.symbols[i].symbol); check_case(this.symbols[i].aliases); } // now map symbols to indexes var update_array = function(array, syms, index) { var s, sym; if (typeof syms === "string") { for (s = 0; s < syms.length; s++) { sym = syms.charAt(s); array[sym] = index; // when only a single case is used, then encode as case insensitive if (seen_uc != seen_lc) { if (sym >= 'a' && sym <= 'z') { array[sym.toUpperCase()] = index; } else if (sym >= 'A' && sym <= 'Z') { array[sym.toLowerCase()] = index; } } } } } // map core symbols to index for (i = 0; i < this.ncore; i++) { update_array(this.encode2core, this.symbols[i].symbol, i); update_array(this.encode, this.symbols[i].symbol, i); update_array(this.encode2core, this.symbols[i].aliases, i); update_array(this.encode, this.symbols[i].aliases, i); } // map ambigous symbols to index ambigs = {}; for (i = this.ncore; i < this.symbols.length; i++) { update_array(this.encode, this.symbols[i].symbol, i); update_array(this.encode, this.symbols[i].aliases, i); ambigs[this.symbols[i].equals] = i; } // determine complements for (i = 0; i < this.ncore; i++) { complement = this.symbols[i].complement; if (typeof complement === "string") { this.complement[i] = this.encode2core[complement]; } } next_symbol: for (i = this.ncore; i < this.symbols.length; i++) { complement = ""; for (j = 0; j < this.symbols[i].equals.length; j++) { comp_e_sym = this.complement[this.encode2core[this.symbols[i].equals.charAt(j)]]; if (typeof comp_e_sym !== "number") continue next_symbol; complement += this.symbols[comp_e_sym].symbol; } complement = complement.split("").sort().join(""); if (typeof ambigs[complement] === "number") { this.complement[i] = ambigs[complement]; } } // determine case insensitivity this.case_insensitive = true; if (seen_uc == seen_lc) { // when there is a mixture of cases it probably won't // be case insensitive but we still need to check loop: for (i = 0; i < this.symbols.length; i++) { sym = this.symbols[i].symbol; if (sym >= 'A' && sym <= 'Z') { if (this.encode[sym.toLowerCase()] != i) { this.case_insensitive = false; break loop; } } else if (sym >= 'a' && sym <= 'z') { if (this.encode[sym.toUpperCase()] != i) { this.case_insensitive = false; break loop; } } aliases = this.symbols[i].aliases; if (aliases != null) { for (j = 0; j < aliases.length; j++) { sym = aliases.charAt(j); if (sym >= 'A' && sym <= 'Z') { if (this.encode[sym.toLowerCase()] != i) { this.case_insensitive = false; break loop; } } else if (sym >= 'a' && sym <= 'z') { if (this.encode[sym.toUpperCase()] != i) { this.case_insensitive = false; break loop; } } } } } } // normalise aliases to remove the prime symbol and eliminate // the alternate cases when the alphabet is case insensitive var seen, out; for (i = 0; i < this.symbols.length; i++) { sym = this.symbols[i].symbol; aliases = this.symbols[i].aliases; if (typeof aliases != "string") aliases = ""; seen = {}; out = []; if (this.case_insensitive) { sym = sym.toUpperCase(); aliases = aliases.toUpperCase(); } seen[sym] = true; for (j = 0; j < aliases.length; j++) { if (!seen[aliases.charAt(j)]) { seen[aliases.charAt(j)] = true; out.push(aliases.charAt(j)); } } this.symbols[i].aliases = out.sort().join(""); } }; // return the name of the alphabet Alphabet.prototype.get_alphabet_name = function() { return this.name; }; // return if the alphabet can be complemented Alphabet.prototype.has_complement = function() { return (typeof this.symbols[0].complement === "string"); }; // return true if an uppercase letter has the same meaning as the lowercase form Alphabet.prototype.is_case_insensitive = function() { return this.case_insensitive; }; // return the information content of an alphabet letter Alphabet.prototype.get_ic = function() { return Math.log(this.ncore) / Math.LN2; }; // return the count of the core alphabet symbols Alphabet.prototype.get_size_core = function() { return this.ncore; }; // return the count of all alphabet symbols Alphabet.prototype.get_size_full = function() { return this.symbols.length; }; // return the symbol for the given alphabet index Alphabet.prototype.get_symbol = function(alph_index) { "use strict"; if (alph_index < 0 || alph_index >= this.symbols.length) { throw new Error("Alphabet index out of bounds"); } return this.symbols[alph_index].symbol; }; // return the aliases for the given alphabet index Alphabet.prototype.get_aliases = function(alph_index) { "use strict"; if (alph_index < 0 || alph_index >= this.symbols.length) { throw new Error("Alphabet index out of bounds"); } var sym_obj = this.symbols[alph_index]; return (sym_obj.aliases != null ? sym_obj.aliases : ""); }; // return the name for the given alphabet index Alphabet.prototype.get_name = function(alph_index) { "use strict"; var sym; if (alph_index < 0 || alph_index >= this.symbols.length) { throw new Error("Alphabet index out of bounds"); } sym = this.symbols[alph_index]; return (typeof sym.name === "string" ? sym.name : sym.symbol); }; // return the alphabet it is like or null Alphabet.prototype.get_like = function() { "use strict"; return this.like; }; // return the index of the complement for the given alphabet index Alphabet.prototype.get_complement = function(alph_index) { var comp_e_sym = this.complement[alph_index]; if (typeof comp_e_sym === "number") { return comp_e_sym; } else { return -1; } }; // return a string containing the core symbols Alphabet.prototype.get_symbols = function() { "use strict"; var i, core_symbols; core_symbols = ""; for (i = 0; i < this.ncore; i++) { core_symbols += this.symbols[i].symbol; } return core_symbols; }; // return if the background was not a uniform generated background Alphabet.prototype.has_bg = function() { "use strict"; return !this.genbg; }; // get the background frequency for the index Alphabet.prototype.get_bg_freq = function(alph_index) { "use strict"; var freq, i, symbols; if (alph_index >= 0) { if (alph_index < this.ncore) { return this.background[alph_index]; } else if (alph_index < this.symbols.length) { freq = 0; symbols = this.symbols[alph_index].equals; for (i = 0; i < symbols.length; i++) { freq += this.background[this.encode2core[symbols.charAt(i)]]; } return freq; } } throw new Error("The alphabet index is out of range."); }; // get the colour of the index Alphabet.prototype.get_colour = function(alph_index) { "use strict"; if (alph_index < 0 || alph_index >= this.symbols.length) { throw new Error("BAD_ALPHABET_INDEX"); } if (typeof this.symbols[alph_index].colour != "string") { return "black"; } return "#" + this.symbols[alph_index].colour; }; // get the rgb componets of the colour at the index Alphabet.prototype.get_rgb = function(alph_index) { "use strict"; if (alph_index < 0 || alph_index >= this.symbols.length) { throw new Error("BAD_ALPHABET_INDEX"); } if (typeof this.symbols[alph_index].colour != "string") { return {"red": 0, "green": 0, "blue": 0}; } var colour = this.symbols[alph_index].colour; var red = parseInt(colour.substr(0, 2), 16) / 255; var green = parseInt(colour.substr(2, 2), 16) / 255; var blue = parseInt(colour.substr(4, 2), 16) / 255; return {"red": red, "green": green, "blue": blue}; }; // convert a symbol into the index Alphabet.prototype.get_index = function(letter) { "use strict"; var alph_index; alph_index = this.encode[letter]; if (typeof alph_index === "undefined") { return -1; } return alph_index; }; // convert a symbol into the list of core indexes that it equals Alphabet.prototype.get_indexes = function(letter) { "use strict"; var alph_index, comprise_str, i, comprise_list; alph_index = this.encode[letter]; if (typeof alph_index === "undefined") { throw new Error("Unknown letter"); } comprise_str = this.symbols[alph_index].equals; comprise_list = []; if (typeof comprise_str == "string") { for (i = 0; i < comprise_str.length; i++) { comprise_list.push(this.encode2core[comprise_str.charAt(i)]); } } else { comprise_list.push(alph_index); } return comprise_list; }; // check if a symbol is the primary way of representing the symbol in the alphabet Alphabet.prototype.is_prime_symbol = function(letter) { var alph_index; alph_index = this.encode[letter]; if (alph_index == null) return false; if (this.is_case_insensitive()) { return (this.symbols[alph_index].symbol.toUpperCase() == letter.toUpperCase()); } else { return (this.symbols[alph_index].symbol == letter); } }; // compare 2 alphabets Alphabet.prototype.equals = function(other) { "use strict"; var i, sym1, sym2; // first check that it's actually an alphabet object if (!(typeof other === "object" && other != null && other instanceof Alphabet)) { return false; } // second shortcircuit if it's the same object if (this === other) return true; // compare if (this.name !== other.name) return false; if (this.ncore !== other.ncore) return false; if (this.symbols.length !== other.symbols.length) return false; for (i = 0; i < this.symbols.length; i++) { sym1 = this.symbols[i]; sym2 = other.symbols[i]; if (sym1.symbol !== sym2.symbol) return false; if (sym1.aliases !== sym2.aliases) return false; if (sym1.name !== sym2.name) return false; if (typeof sym1.colour !== typeof sym2.colour || (typeof sym1.colour === "string" && typeof sym2.colour === "string" && parseInt(sym1.colour, 16) != parseInt(sym2.colour, 16))) { return false; } if (sym1.complement !== sym2.complement) return false; if (sym1.equals !== sym2.equals) return false; } return true; }; Alphabet.prototype.check_core_subset = function(super_alph) { var complement_same = true; var seen_set = {}; var sub_i, sub_symbol, super_i, super_symbol; for (sub_i = 0; sub_i < this.ncore; sub_i++) { sub_symbol = this.symbols[sub_i]; super_i = super_alph.encode[sub_symbol.symbol]; if (super_i == null) return 0; super_symbol = super_alph.symbols[super_i]; if (seen_set[super_i]) return 0; seen_set[super_i] = true; // check complement if (sub_symbol.complement != null && super_symbol.complement != null) { if (super_alph.encode[sub_symbol.complement] != super_alph.encode[super_symbol.complement]) { complement_same = false; } } else if (sub_symbol.complement != null || super_symbol.complement != null) { complement_same = false; } } return (complement_same ? 1 : -1); }; // convert a sequence to its reverse complement Alphabet.prototype.invcomp_seq = function(seq) { "use strict"; var syms, i, e_sym, comp_e_sym; if (!this.has_complement()) throw new Error("Alphabet must be complementable"); syms = seq.split(""); for (i = 0; i < syms.length; i++) { e_sym = this.encode[syms[i]]; if (typeof e_sym === "undefined") { e_sym = this.ncore; // wildcard } comp_e_sym = this.complement[e_sym]; if (typeof comp_e_sym === "undefined") { comp_e_sym = e_sym; // not complementable } syms[i] = this.symbols[comp_e_sym].symbol; } return syms.reverse().join(""); }; // convert the alphabet to the text version Alphabet.prototype.as_text = function() { "use strict"; function name_as_text(name) { var i, c, out; out = "\""; for (i = 0; i < name.length; i++) { c = name.charAt(i); if (c == "\"") { out += "\\\""; } else if (c == "/") { out += "\\/"; } else if (c == "\\") { out += "\\\\"; } else { out += c; } } out += "\""; return out; } function symbol_as_text(sym) { var out; out = sym.symbol; if (typeof sym.name === "string" && sym.name != sym.symbol) { out += " " + name_as_text(sym.name); } if (typeof sym.colour === "string") { out += " " + sym.colour; } return out; } var out, i, j, c, sym; out = ""; // output core symbols with 2 way complements for (i = 0; i < this.ncore; i++) { c = this.complement[i]; if (typeof c === "number" && i < c && this.complement[c] === i) { out += symbol_as_text(this.symbols[i]) + " ~ " + symbol_as_text(this.symbols[c]) + "\n"; } } // output core symbols with no complement for (i = 0; i < this.ncore; i++) { if (typeof this.complement[i] === "undefined") { out += symbol_as_text(this.symbols[i]) + "\n"; } } // output ambiguous symbols that have comprising characters for (i = this.ncore; i < this.symbols.length; i++) { if (this.symbols[i].equals.length == 0) break; out += symbol_as_text(this.symbols[i]) + " = " + this.symbols[i].equals + "\n"; if (typeof this.symbols[i].aliases === "string") { for (j = 0; j < this.symbols[i].aliases.length; j++) { if (this.symbols[i].aliases.charAt(j) == this.symbols[i].symbol) continue; out += this.symbols[i].aliases.charAt(j) + " = " + this.symbols[i].equals + "\n"; } } } // output aliases of core symbols for (i = 0; i < this.ncore; i++) { if (typeof this.symbols[i].aliases === "string") { for (j = 0; j < this.symbols[i].aliases.length; j++) { if (this.symbols[i].aliases.charAt(j) == this.symbols[i].symbol) continue; out += this.symbols[i].aliases.charAt(j) + " = " + this.symbols[i].symbol + "\n"; } } } // output gap symbols i = this.symbols.length - 1; if (this.symbols[i].equals.length == 0) { out += symbol_as_text(this.symbols[i]) + " =\n"; if (typeof this.symbols[i].aliases === "string") { for (j = 0; j < this.symbols[i].aliases.length; j++) { if (this.symbols[i].aliases.charAt(j) == this.symbols[i].symbol) continue; out += this.symbols[i].aliases.charAt(j) + " =\n"; } } } return out; }; // output the alphabet as it appears in minimal MEME format Alphabet.prototype.as_meme = function() { "use strict"; function name_as_text(name) { var i, c, out; out = "\""; for (i = 0; i < name.length; i++) { c = name.charAt(i); if (c == "\"") { out += "\\\""; } else if (c == "/") { out += "\\/"; } else if (c == "\\") { out += "\\\\"; } else { out += c; } } out += "\""; return out; } if (this.equals(AlphStd.DNA)) { return "ALPHABET= ACGT\n"; } else if (this.equals(AlphStd.PROTEIN)) { return "ALPHABET= ACDEFGHIKLMNPQRSTVWY\n"; } else { return "ALPHABET" + (this.name != null ? " " + name_as_text(this.name) : "") + (this.like != null ? " " + this.like + "-LIKE" : "") + "\n" + this.as_text() + "END ALPHABET\n"; } }; // Returns a table showing all the letters in the alphabet Alphabet.prototype.as_table = function() { "use strict"; var i, j, row, th, td, aliases, equals, sym; var table = document.createElement("table"); // create the core symbol header row = table.insertRow(table.rows.length); th = document.createElement("th"); th.appendChild(document.createTextNode("Symbol(s)")); row.appendChild(th); th = document.createElement("th"); th.appendChild(document.createTextNode("Name")); row.appendChild(th); th = document.createElement("th"); if (this.has_complement()) { th.appendChild(document.createTextNode("Complement")); } row.appendChild(th); // list the core symbols for (i = 0; i < this.ncore; i++) { row = table.insertRow(table.rows.length); td = document.createElement("td"); if (this.symbols[i].colour != null) { td.style.color = '#' + this.symbols[i].colour; } td.appendChild(document.createTextNode(this.symbols[i].symbol)); aliases = this.get_aliases(i); if (aliases.length > 0) { td.appendChild(document.createTextNode(' ' + aliases.split('').join(' '))); } row.appendChild(td); td = document.createElement("td"); if (this.symbols[i].name != null) { td.appendChild(document.createTextNode(this.symbols[i].name)); } row.appendChild(td); td = document.createElement("td"); if (this.symbols[i].complement != null) { td.style.color = this.get_colour(this.get_index(this.symbols[i].complement)); td.appendChild(document.createTextNode(this.symbols[i].complement)); } row.appendChild(td); } // create the ambiguous symbol header row = table.insertRow(table.rows.length); th = document.createElement("th"); th.appendChild(document.createTextNode("Symbol(s)")); row.appendChild(th); th = document.createElement("th"); th.appendChild(document.createTextNode("Name")); row.appendChild(th); th = document.createElement("th"); th.appendChild(document.createTextNode("Matches")); row.appendChild(th); // list the ambiguous symbols for (i = this.ncore; i < this.symbols.length; i++) { row = table.insertRow(table.rows.length); td = document.createElement("td"); if (this.symbols[i].colour != null) { td.style.color = '#' + this.symbols[i].colour; } td.appendChild(document.createTextNode(this.symbols[i].symbol)); aliases = this.get_aliases(i); if (aliases.length > 0) { td.appendChild(document.createTextNode(' ' + aliases.split('').join(' '))); } row.appendChild(td); td = document.createElement("td"); if (this.symbols[i].name != null) { td.appendChild(document.createTextNode(this.symbols[i].name)); } row.appendChild(td); td = document.createElement("td"); equals = this.symbols[i].equals.split(''); for (j = 0; j < equals.length; j++) { if (j != 0) td.appendChild(document.createTextNode(' ')); sym = document.createElement("span"); sym.style.color = this.get_colour(this.get_index(equals[j])); sym.appendChild(document.createTextNode(equals[j])); td.appendChild(sym); } row.appendChild(td); } return table; }; // returns a dictionary of the colours for EPS Alphabet.prototype._as_eps_dict = function() { "use strict"; var i, sym, rgb; var out = "/fullColourDict <<\n"; for (i = 0; i < this.ncore; i++) { sym = this.get_symbol(i); sym = sym.replace(/\\/g, "\\\\"); sym = sym.replace(/\(/g, "\\("); sym = sym.replace(/\)/g, "\\)"); rgb = this.get_rgb(i); out += " (" + sym + ") [" + rgb.red.toFixed(4) + " " + rgb.green.toFixed(4) + " " + rgb.blue.toFixed(4) + "]\n"; } out += ">> def\n"; out += "/mutedColourDict <<\n"; for (i = 0; i < this.ncore; i++) { sym = this.get_symbol(i); sym = sym.replace(/\\/g, "\\\\"); sym = sym.replace(/\(/g, "\\("); sym = sym.replace(/\)/g, "\\)"); rgb = Alphabet.lighten_colour(this.get_rgb(i)); out += " (" + sym + ") [" + rgb.red.toFixed(4) + " " + rgb.green.toFixed(4) + " " + rgb.blue.toFixed(4) + "]\n"; } out += ">> def\n"; return out; }; // return the alphabet name or a list of primary symbols Alphabet.prototype.toString = function() { "use strict"; if (this.name != null) { return this.name; } else { return this.get_symbols(); } }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Helper functions //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Convert a colour specified in RGB colourspace values into LAB colourspace Alphabet.rgb2lab = function(rgb) { "use strict"; var xyzHelper, labHelper; // XYZ helper xyzHelper = function(value) { if (value > 0.0445) { value = (value + 0.055) / 1.055; value = Math.pow(value, 2.4); } else { value /= 12.92; } value *= 100; return value; }; // lab helper labHelper = function(value) { if (value > 0.008856) { value = Math.pow(value, 1.0 / 3.0); } else { value = (7.787 * value) + (16.0 / 116.0); } return value; }; // convert into XYZ colourspace var c1, c2, c3; if (typeof rgb == "number") { c1 = xyzHelper(((rgb >> 16) & 0xFF) / 255.0); c2 = xyzHelper(((rgb >> 8) & 0xFF) / 255.0); c3 = xyzHelper((rgb & 0xFF) / 255.0); } else { c1 = xyzHelper(rgb.red); c2 = xyzHelper(rgb.green); c3 = xyzHelper(rgb.blue); } var x = (c1 * 0.4124) + (c2 * 0.3576) + (c3 * 0.1805); var y = (c1 * 0.2126) + (c2 * 0.7152) + (c3 * 0.0722); var z = (c1 * 0.0193) + (c2 * 0.1192) + (c3 * 0.9505); // convert into Lab colourspace c1 = labHelper(x / 95.047); c2 = labHelper(y / 100.0); c3 = labHelper(z / 108.883); var l = (116.0 * c2) - 16; var a = 500.0 * (c1 - c2); var b = 200.0 * (c2 - c3); return {"l": l, "a": a, "b": b}; }; // Convert a colour specified in HSV colourspace into RGB colourspace Alphabet.hsv2rgb = function(hue, sat, value, output_object) { // achromatic (grey) var r = value; var g = value; var b = value; if (sat != 0) { var h = hue / 60.0; var i = Math.floor(h); var f = h - i; var p = value * (1.0 - sat); var q = value * (1.0 - (sat * f)); var t = value * (1.0 - (sat * (1.0 - f))); if (i == 0) { r = value; g = t; b = p; } else if (i == 1) { r = q; g = value; b = p; } else if (i == 2) { r = p; g = value; b = t; } else if (i == 3) { r = p; g = q; b = value; } else if (i == 4) { r = t; g = p; b = value; } else { r = value; g = p; b = q; } } if (output_object) { return {"red": r, "green": g, "blue": b}; } else { return (Math.floor(r * 255) << 15) | (Math.floor(g * 255) << 8) | (Math.floor(b * 255)); } }; // Calculate a distance score between two colours in LAB colourspace Alphabet.lab_dist = function(lab1, lab2) { var c1 = Math.sqrt((lab1.l * lab1.l) + (lab1.a * lab1.a)); var c2 = Math.sqrt((lab2.l * lab2.l) + (lab2.a * lab2.a)); var dc = c1 - c2; var dl = lab1.l - lab2.l; var da = lab1.a - lab2.a; var db = lab1.b - lab2.b; // we don't want NaN due to rounding errors so fudge things a bit... var dh = 0; var dh_squared = (da * da) + (db * db) - (dc * dc); if (dh_squared > 0) { dh = Math.sqrt(dh_squared); } var first = dl; var second = dc / (1.0 + (0.045 * c1)); var third = dh / (1.0 + (0.015 * c1)); return Math.sqrt((first * first) + (second * second) + (third * third)); }; // convert an RGB value into a HSL value Alphabet.rgb2hsl = function(rgb) { "use strict"; var min, max, delta, h, s, l, r, g, b; if (typeof rgb == "number") { r = ((rgb >> 16) & 0xFF) / 255.0; g = ((rgb >> 8) & 0xFF) / 255.0; b = (rgb & 0xFF) / 255.0; } else { r = rgb.red; g = rgb.green; b = rgb.blue; } min = Math.min(r, g, b); max = Math.max(r, g, b); delta = max - min; l = min + (delta / 2); if (max == min) { h = 0; // achromatic (grayscale) s = 0; } else { if (l > 0.5) { s = delta / (2 - max - min); } else { s = delta / (max + min); } if (max == r) { h = (g - b) / delta; if (g < b) h += 6; } else if (max == g) { h = ((b - r) / delta) + 2; } else { h = ((r - g) / delta) + 4; } h /= 6; } return {"h": h, "s": s, "l": l}; }; // convert a HSL value into an RGB value Alphabet.hsl2rgb = function(hsl, output_object) { "use strict"; function _hue(p, q, t) { "use strict"; if (t < 0) t += 1; else if (t > 1) t -= 1; if (t < (1.0 / 6.0)) { return p + ((q - p) * 6.0 * t); } else if (t < 0.5) { return q; } else if (t < (2.0 / 3.0)) { return p + ((q - p) * ((2.0 / 3.0) - t) * 6.0); } else { return p; } } var r, g, b, p, q; if (hsl.s == 0) { // achromatic (grayscale) r = hsl.l; g = hsl.l; b = hsl.l; } else { if (hsl.l < 0.5) { q = hsl.l * (1 + hsl.s); } else { q = hsl.l + hsl.s - (hsl.l * hsl.s); } p = (2 * hsl.l) - q; r = _hue(p, q, hsl.h + (1.0 / 3.0)); g = _hue(p, q, hsl.h); b = _hue(p, q, hsl.h - (1.0 / 3.0)); } if (output_object) { return {"red": r, "green": g, "blue": b}; } else { return (Math.floor(r * 255) << 15) | (Math.floor(g * 255) << 8) | (Math.floor(b * 255)); } }; Alphabet.lighten_colour = function(rgb) { "use strict"; var hsl = Alphabet.rgb2hsl(rgb); hsl.l += (1.0 - hsl.l) * 2 / 3; return Alphabet.hsl2rgb(hsl, typeof rgb != "number"); }; //====================================================================== // end Alphabet object //====================================================================== //====================================================================== // start StandardAlphabet object //====================================================================== // an extension of the alphabet object to support some additional fields // only present in standard alphabets. var StandardAlphabet = function(enum_code, enum_name, alphabet_data) { Alphabet.apply(this, [alphabet_data]); this.enum_code = enum_code; this.enum_name = enum_name; }; StandardAlphabet.prototype = Alphabet.prototype; StandardAlphabet.prototype.constructor = StandardAlphabet; // A unique code for this standard alphabet. // This code will be a power of 2 to enable creation of bitsets for // a selection of standard alphabets. StandardAlphabet.prototype.get_code = function() { return this.enum_code; }; // A unique name for this standard alphabet. // this name will be all upper case and the same as the property that // refers to this alphabet in the AlphStd collection. StandardAlphabet.prototype.get_enum = function() { return this.enum_name; }; //====================================================================== // end StandardAlphabet object //====================================================================== // A collection of standard alphabets. var AlphStd = { RNA: new StandardAlphabet(1, "RNA", { "name": "RNA", "like": "RNA", "ncore": 4, "symbols": [ {"symbol": "A", "name": "Adenine", "colour": "CC0000"}, {"symbol": "C", "name": "Cytosine", "colour": "0000CC"}, {"symbol": "G", "name": "Guanine", "colour": "FFB300"}, {"symbol": "U", "name": "Uracil", "colour": "008000", "aliases": "T"}, {"symbol": "N", "name": "Any base", "equals": "ACGU", "aliases": "X."}, {"symbol": "V", "name": "Not U", "equals": "ACG"}, {"symbol": "H", "name": "Not G", "equals": "ACU"}, {"symbol": "D", "name": "Not C", "equals": "AGU"}, {"symbol": "B", "name": "Not A", "equals": "CGU"}, {"symbol": "M", "name": "Amino", "equals": "AC"}, {"symbol": "R", "name": "Purine", "equals": "AG"}, {"symbol": "W", "name": "Weak", "equals": "AU"}, {"symbol": "S", "name": "Strong", "equals": "CG"}, {"symbol": "Y", "name": "Pyrimidine", "equals": "CU"}, {"symbol": "K", "name": "Keto", "equals": "GU"} ] }), DNA: new StandardAlphabet(2, "DNA", { "name": "DNA", "like": "DNA", "ncore": 4, "symbols": [ {"symbol": "A", "name": "Adenine", "colour": "CC0000", "complement": "T"}, {"symbol": "C", "name": "Cytosine", "colour": "0000CC", "complement": "G"}, {"symbol": "G", "name": "Guanine", "colour": "FFB300", "complement": "C"}, {"symbol": "T", "name": "Thymine", "colour": "008000", "complement": "A", "aliases": "U"}, {"symbol": "N", "name": "Any base", "equals": "ACGT", "aliases": "X."}, {"symbol": "V", "name": "Not T", "equals": "ACG"}, {"symbol": "H", "name": "Not G", "equals": "ACT"}, {"symbol": "D", "name": "Not C", "equals": "AGT"}, {"symbol": "B", "name": "Not A", "equals": "CGT"}, {"symbol": "M", "name": "Amino", "equals": "AC"}, {"symbol": "R", "name": "Purine", "equals": "AG"}, {"symbol": "W", "name": "Weak", "equals": "AT"}, {"symbol": "S", "name": "Strong", "equals": "CG"}, {"symbol": "Y", "name": "Pyrimidine", "equals": "CT"}, {"symbol": "K", "name": "Keto", "equals": "GT"} ] }), PROTEIN: new StandardAlphabet(4, "PROTEIN", { "name": "Protein", "like": "PROTEIN", "ncore": 20, "symbols": [ {"symbol": "A", "name": "Alanine", "colour": "0000CC"}, {"symbol": "C", "name": "Cysteine", "colour": "0000CC"}, {"symbol": "D", "name": "Aspartic acid", "colour": "FF00FF"}, {"symbol": "E", "name": "Glutamic acid", "colour": "FF00FF"}, {"symbol": "F", "name": "Phenylalanine", "colour": "0000CC"}, {"symbol": "G", "name": "Glycine", "colour": "FFB300"}, {"symbol": "H", "name": "Histidine", "colour": "FFCCCC"}, {"symbol": "I", "name": "Isoleucine", "colour": "0000CC"}, {"symbol": "K", "name": "Lysine", "colour": "CC0000"}, {"symbol": "L", "name": "Leucine", "colour": "0000CC"}, {"symbol": "M", "name": "Methionine", "colour": "0000CC"}, {"symbol": "N", "name": "Asparagine", "colour": "008000"}, {"symbol": "P", "name": "Proline", "colour": "FFFF00"}, {"symbol": "Q", "name": "Glutamine", "colour": "008000"}, {"symbol": "R", "name": "Arginine", "colour": "CC0000"}, {"symbol": "S", "name": "Serine", "colour": "008000"}, {"symbol": "T", "name": "Threonine", "colour": "008000"}, {"symbol": "V", "name": "Valine", "colour": "0000CC"}, {"symbol": "W", "name": "Tryptophan", "colour": "0000CC"}, {"symbol": "Y", "name": "Tyrosine", "colour": "33E6CC"}, {"symbol": "X", "name": "Any amino acid", "equals": "ACDEFGHIKLMNPQRSTVWY", "aliases": "*."}, {"symbol": "B", "name": "Asparagine or Aspartic acid", "equals": "DN"}, {"symbol": "Z", "name": "Glutamine or Glutamic acid", "equals": "EQ"}, {"symbol": "J", "name": "Leucine or Isoleucine", "equals": "IL"} ] }) }; //====================================================================== // start Symbol object //====================================================================== var Symbol = function(alph_index, scale, alphabet) { "use strict"; //variable prototype this.symbol = alphabet.get_symbol(alph_index); this.scale = scale; this.colour = alphabet.get_colour(alph_index); }; Symbol.prototype.get_symbol = function() { "use strict"; return this.symbol; }; Symbol.prototype.get_scale = function() { "use strict"; return this.scale; }; Symbol.prototype.get_colour = function() { "use strict"; return this.colour; }; Symbol.prototype.toString = function() { "use strict"; return this.symbol + " " + (Math.round(this.scale*1000)/10) + "%"; }; function compare_symbol(sym1, sym2) { "use strict"; if (sym1.get_scale() < sym2.get_scale()) { return -1; } else if (sym1.get_scale() > sym2.get_scale()) { return 1; } else { return 0; } } //====================================================================== // end Symbol object //====================================================================== //====================================================================== // start Pspm object //====================================================================== var Pspm = function(matrix, name, ltrim, rtrim, nsites, evalue, pssm, alt) { "use strict"; var row, col, data, row_sum, delta, evalue_re; if (typeof name !== "string") { name = ""; } this.name = name; //construct if (matrix instanceof Pspm) { // copy constructor this.alph_length = matrix.alph_length; this.motif_length = matrix.motif_length; this.name = matrix.name; this.alt = matrix.alt; this.nsites = matrix.nsites; this.evalue = matrix.evalue; this.ltrim = matrix.ltrim; this.rtrim = matrix.rtrim; this.pspm = []; for (row = 0; row < matrix.motif_length; row++) { this.pspm[row] = []; for (col = 0; col < matrix.alph_length; col++) { this.pspm[row][col] = matrix.pspm[row][col]; } } if (matrix.pssm != null) { this.pssm = []; for (row = 0; row < matrix.motif_length; row++) { this.pspm[row] = []; for (col = 0; col < matrix.alph_length; col++) { this.pssm[row][col] = matrix.pssm[row][col]; } } } } else { // check parameters if (ltrim == null) { ltrim = 0; } else if (typeof ltrim !== "number" || ltrim % 1 !== 0 || ltrim < 0) { throw new Error("ltrim must be a non-negative integer, got: " + ltrim); } if (rtrim == null) { rtrim = 0; } else if (typeof rtrim !== "number" || rtrim % 1 !== 0 || rtrim < 0) { throw new Error("rtrim must be a non-negative integer, got: " + rtrim); } if (nsites != null) { if (typeof nsites !== "number" || nsites < 0) { throw new Error("nsites must be a positive number, got: " + nsites); } else if (nsites == 0) { nsites = null; } } if (evalue != null) { if (typeof evalue === "number") { if (evalue < 0) { throw new Error("evalue must be a non-negative number, got: " + evalue); } } else if (typeof evalue === "string") { evalue_re = /^((?:[+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?)|inf)$/; if (!evalue_re.test(evalue)) { throw new Error("evalue must be a non-negative number, got: " + evalue); } } else { throw new Error("evalue must be a non-negative number, got: " + evalue); } } // set properties this.name = name; this.alt = alt; this.nsites = nsites; this.evalue = evalue; this.ltrim = ltrim; this.rtrim = rtrim; if (typeof matrix === "string") { // string constructor data = parse_pspm_string(matrix); this.alph_length = data["alph_length"]; this.motif_length = data["motif_length"]; this.pspm = data["pspm"]; if (this.evalue == null) { if (data["evalue"] != null) { this.evalue = data["evalue"]; } else { this.evalue = 0; } } if (this.nsites == null) { if (typeof data["nsites"] === "number") { this.nsites = data["nsites"]; } else { this.nsites = 20; } } } else { // assume pspm is a nested array this.motif_length = matrix.length; this.alph_length = (matrix.length > 0 ? matrix[0].length : 0); if (this.nsites == null) { this.nsites = 20; } if (this.evalue == null) { this.evalue = 0; } this.pspm = []; // copy pspm and check for (row = 0; row < this.motif_length; row++) { if (this.alph_length != matrix[row].length) { throw new Error("COLUMN_MISMATCH"); } this.pspm[row] = []; row_sum = 0; for (col = 0; col < this.alph_length; col++) { this.pspm[row][col] = matrix[row][col]; row_sum += this.pspm[row][col]; } delta = 0.1; if (isNaN(row_sum) || (row_sum > 1 && (row_sum - 1) > delta) || (row_sum < 1 && (1 - row_sum) > delta)) { throw new Error("INVALID_SUM"); } } // copy pssm if (pssm != null) { this.pssm = []; for (row = 0; row < this.motif_length; row++) { this.pssm[row] = []; for (col = 0; col < this.alph_length; col++) { this.pssm[row][col] = pssm[row][col]; } } } } } }; Pspm.prototype.copy = function() { "use strict"; return new Pspm(this); }; Pspm.prototype.reverse = function() { "use strict"; var x, y, temp, temp_trim; //reverse x = 0; y = this.motif_length-1; while (x < y) { temp = this.pspm[x]; this.pspm[x] = this.pspm[y]; this.pspm[y] = temp; x++; y--; } // reverse pssm (if defined) if (typeof this.pssm !== "undefined") { //reverse x = 0; y = this.motif_length-1; while (x < y) { temp = this.pssm[x]; this.pspm[x] = this.pssm[y]; this.pssm[y] = temp; x++; y--; } } //swap triming temp_trim = this.ltrim; this.ltrim = this.rtrim; this.rtrim = temp_trim; return this; //allow function chaining... }; Pspm.prototype.reverse_complement = function(alphabet) { "use strict"; var x, y, temp, i, row, c, temp_trim; if (this.alph_length != alphabet.get_size_core()) { throw new Error("The alphabet size does not match the size of the pspm."); } if (!alphabet.has_complement()) { throw new Error("The specified alphabet can not be complemented."); } // reverse motif this.reverse(); //complement for (x = 0; x < this.motif_length; x++) { row = this.pspm[x]; for (i = 0; i < row.length; i++) { c = alphabet.get_complement(i); if (c < i) continue; temp = row[i]; row[i] = row[c]; row[c] = temp; } } // complement pssm (if defined) if (typeof this.pssm !== "undefined") { //complement for (x = 0; x < this.motif_length; x++) { row = this.pssm[x]; for (i = 0; i < row.length; i++) { c = alphabet.get_complement(i); if (c < i) continue; temp = row[i]; row[i] = row[c]; row[c] = temp; } } } return this; //allow function chaining... }; Pspm.prototype.get_stack = function(position, alphabet, ssc) { "use strict"; var row, stack_ic, alphabet_ic, stack, i, sym; if (this.alph_length != alphabet.get_size_core()) { throw new Error("The alphabet size does not match the size of the pspm."); } row = this.pspm[position]; stack_ic = this.get_stack_ic(position, alphabet); if (ssc) stack_ic -= this.get_error(alphabet); alphabet_ic = alphabet.get_ic(); stack = []; for (i = 0; i < this.alph_length; i++) { sym = new Symbol(i, row[i]*stack_ic/alphabet_ic, alphabet); if (sym.get_scale() <= 0) { continue; } stack.push(sym); } stack.sort(compare_symbol); return stack; }; Pspm.prototype.get_stack_ic = function(position, alphabet) { "use strict"; var row, H, i; if (this.alph_length != alphabet.get_size_core()) { throw new Error("The alphabet size does not match the size fo the pspm."); } row = this.pspm[position]; H = 0; for (i = 0; i < this.alph_length; i++) { if (row[i] === 0) { continue; } H -= (row[i] * (Math.log(row[i]) / Math.LN2)); } return alphabet.get_ic() - H; }; Pspm.prototype.get_error = function(alphabet) { "use strict"; if (this.nsites === 0) { return 0; } return (alphabet.get_size_core()-1) / (2 * Math.LN2 * this.nsites); }; Pspm.prototype.get_motif_length = function() { "use strict"; return this.motif_length; }; Pspm.prototype.get_alph_length = function() { "use strict"; return this.alph_length; }; Pspm.prototype.get_left_trim = function() { "use strict"; return this.ltrim; }; Pspm.prototype.get_right_trim = function() { "use strict"; return this.rtrim; }; Pspm.prototype.as_best_match = function(alphabet) { "use strict"; var match, odds, best_odds, best_index; var i, j; match = ""; for (i = 0; i < this.motif_length; i++) { best_index = 0; best_odds = this.pspm[i][0] / alphabet.get_bg_freq(0); for (j = 1; j < this.alph_length; j++) { odds = this.pspm[i][j] / alphabet.get_bg_freq(j); if (odds > best_odds) { best_odds = odds; best_index = j; } } match += alphabet.get_symbol(best_index); } return match; }; Pspm.prototype.as_count_matrix = function() { "use strict"; var count, count_text, text; var i, j; text = ""; for (i = 0; i < this.motif_length; i++) { if (i !== 0) { text += "\n"; } for (j = 0; j < this.alph_length; j++) { if (j !== 0) { text += " "; } count = Math.round(this.nsites * this.pspm[i][j]); count_text = "" + count; // pad up to length of 4 if (count_text.length < 4) { text += (new Array(5 - count_text.length)).join(" ") + count_text; } else { text += count_text; } } } return text; }; Pspm.prototype.as_probability_matrix = function() { "use strict"; var text; var i, j; text = ""; for (i = 0; i < this.motif_length; i++) { if (i !== 0) { text += "\n"; } for (j = 0; j < this.alph_length; j++) { if (j !== 0) { text += " "; } text += this.pspm[i][j].toFixed(6); } } return text; }; Pspm.prototype.as_score_matrix = function(alphabet, pseudo) { "use strict"; var me, score, out, row, col, score_text; me = this; if (typeof this.pssm === "undefined") { if (!(typeof alphabet === "object" && alphabet != null && alphabet instanceof Alphabet)) { throw new Error("The alphabet is required to generate the pssm."); } if (typeof pseudo === "undefined") { pseudo = 0.01; } else if (typeof pseudo !== "number" || pseudo < 0) { throw new Error("Expected positive number for pseudocount"); } score = function(row, col) { "use strict"; var p, bg, p2; p = me.pspm[row][col]; bg = alphabet.get_bg_freq(col); p2 = (p * me.nsites + bg * pseudo) / (me.nsites + pseudo); return (p2 > 0 ? Math.round((Math.log(p2 / bg) / Math.LN2) * 100) : -10000); }; } else { score = function(row, col) { "use strict"; return me.pssm[row][col]; }; } out = ""; for (row = 0; row < this.motif_length; row++) { for (col = 0; col < this.alph_length; col++) { if (col !== 0) { out += " "; } score_text = "" + score(row, col); // pad out to 6 characters if (score_text.length < 6) { out += (new Array(7 - score_text.length)).join(" ") + score_text; } else { out += score_text; } } out += "\n"; } return out; } Pspm.prototype.as_pspm = function() { "use strict"; return "letter-probability matrix: alength= " + this.alph_length + " w= " + this.motif_length + " nsites= " + this.nsites + " E= " + (typeof this.evalue === "number" ? this.evalue.toExponential() : this.evalue) + "\n" + this.as_probability_matrix(); }; Pspm.prototype.as_pssm = function(alphabet, pseudo) { "use strict"; return "log-odds matrix: alength= " + this.alph_length + " w= " + this.motif_length + " E= " + (typeof this.evalue == "number" ? this.evalue.toExponential() : this.evalue) + "\n" + this.as_score_matrix(alphabet, pseudo); }; Pspm.prototype.as_meme = function(options) { var with_header, with_pspm, with_pssm, version, alphabet, bg_source, pseudocount, strands; var out, alen, i; // get the options if (typeof options !== "object" || options === null) { options = {}; } with_header = (typeof options["with_header"] === "boolean" ? options["with_header"] : false); with_pspm = (typeof options["with_pspm"] === "boolean" ? options["with_pspm"] : false); with_pssm = (typeof options["with_pssm"] === "boolean" ? options["with_pssm"] : false); if (!with_pspm && !with_pssm) with_pspm = true; if (with_header) { if (typeof options["version"] === "string" && /^\d+(?:\.\d+){0,2}$/.test(options["version"])) { version = options["version"]; } else if (typeof options["version"] === "number") { version = options["version"].toFixed(0); } else { version = "4"; } if (typeof options["strands"] === "number" && options["strands"] === 1) { strands = 1; } else { strands = 2; } if (typeof options["bg_source"] === "string") { bg_source = options["bg_source"]; } else { bg_source = "unknown source"; } if (typeof options["alphabet"] === "object" && options["alphabet"] != null && options["alphabet"] instanceof Alphabet) { alphabet = options["alphabet"]; } else { throw new Error("The alphabet is required to generate the header."); } } // now create the output out = ""; if (with_header) { out = "MEME version " + version + "\n\n"; out += alphabet.as_meme() + "\n"; if (alphabet.has_complement()) { // assume DNA has both strands unless otherwise specified out += "strands: " + (strands === 1 ? "+" : "+ -") + "\n\n"; } out += "Background letter frequencies (from " + bg_source + "):\n"; alen = alphabet.get_size_core(); for (i = 0; i < alen; i++) { if (i !== 0) { if (i % 9 === 0) { // maximum of nine entries per line out += "\n"; } else { out += " "; } } out += alphabet.get_symbol(i) + " " + alphabet.get_bg_freq(i).toFixed(3); } } out += "\n\n"; out += "MOTIF " + this.name + (this.alt == null ? "" : " " + this.alt); if (with_pssm) { out += "\n\n"; out += this.as_pssm(options["alphabet"], options["pseudocount"]); } if (with_pspm) { out += "\n\n"; out += this.as_pspm(); } return out; } Pspm.prototype.toString = function() { "use strict"; var str, i, row; str = ""; for (i = 0; i < this.pspm.length; i++) { row = this.pspm[i]; str += row.join("\t") + "\n"; } return str; }; function parse_pspm_properties(str) { "use strict"; var parts, i, eqpos, before, after, properties, prop, num, num_re; num_re = /^((?:[+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?)|inf)$/; parts = trim(str).split(/\s+/); // split up words containing = for (i = 0; i < parts.length;) { eqpos = parts[i].indexOf("="); if (eqpos != -1) { before = parts[i].substr(0, eqpos); after = parts[i].substr(eqpos+1); if (before.length > 0 && after.length > 0) { parts.splice(i, 1, before, "=", after); i += 3; } else if (before.length > 0) { parts.splice(i, 1, before, "="); i += 2; } else if (after.length > 0) { parts.splice(i, 1, "=", after); i += 2; } else { parts.splice(i, 1, "="); i++; } } else { i++; } } properties = {}; for (i = 0; i < parts.length; i += 3) { if (parts.length - i < 3) { throw new Error("Expected PSPM property was incomplete. "+ "Remaing parts are: " + parts.slice(i).join(" ")); } if (parts[i+1] !== "=") { throw new Error("Expected '=' in PSPM property between key and " + "value but got " + parts[i+1]); } prop = parts[i].toLowerCase(); num = parts[i+2]; if (!num_re.test(num)) { throw new Error("Expected numeric value for PSPM property '" + prop + "' but got '" + num + "'"); } properties[prop] = num; } return properties; } function parse_pspm_string(pspm_string) { "use strict"; var header_re, lines, first_line, line_num, col_num, alph_length, motif_length, nsites, evalue, pspm, i, line, match, props, parts, j, prob; header_re = /^letter-probability\s+matrix:(.*)$/i; lines = pspm_string.split(/\n/); first_line = true; line_num = 0; col_num = 0; alph_length; motif_length; nsites; evalue; pspm = []; for (i = 0; i < lines.length; i++) { line = trim(lines[i]); if (line.length === 0) { continue; } // check the first line for a header though allow matrices without it if (first_line) { first_line = false; match = header_re.exec(line); if (match !== null) { props = parse_pspm_properties(match[1]); if (props.hasOwnProperty("alength")) { alph_length = parseFloat(props["alength"]); if (alph_length != 4 && alph_length != 20) { throw new Error("PSPM property alength should be 4 or 20" + " but got " + alph_length); } } if (props.hasOwnProperty("w")) { motif_length = parseFloat(props["w"]); if (motif_length % 1 !== 0 || motif_length < 1) { throw new Error("PSPM property w should be an integer larger " + "than zero but got " + motif_length); } } if (props.hasOwnProperty("nsites")) { nsites = parseFloat(props["nsites"]); if (nsites <= 0) { throw new Error("PSPM property nsites should be larger than " + "zero but got " + nsites); } } if (props.hasOwnProperty("e")) { evalue = props["e"]; if (evalue < 0) { throw new Error("PSPM property evalue should be " + "non-negative but got " + evalue); } } continue; } } pspm[line_num] = []; col_num = 0; parts = line.split(/\s+/); for (j = 0; j < parts.length; j++) { prob = parseFloat(parts[j]); if (prob != parts[j] || prob < 0 || prob > 1) { throw new Error("Expected probability but got '" + parts[j] + "'"); } pspm[line_num][col_num] = prob; col_num++; } line_num++; } if (typeof motif_length === "number") { if (pspm.length != motif_length) { throw new Error("Expected PSPM to have a motif length of " + motif_length + " but it was actually " + pspm.length); } } else { motif_length = pspm.length; } if (typeof alph_length !== "number") { alph_length = pspm[0].length; if (alph_length != 4 && alph_length != 20) { throw new Error("Expected length of first row in the PSPM to be " + "either 4 or 20 but got " + alph_length); } } for (i = 0; i < pspm.length; i++) { if (pspm[i].length != alph_length) { throw new Error("Expected PSPM row " + i + " to have a length of " + alph_length + " but the length was " + pspm[i].length); } } return {"pspm": pspm, "motif_length": motif_length, "alph_length": alph_length, "nsites": nsites, "evalue": evalue}; } //====================================================================== // end Pspm object //====================================================================== //====================================================================== // start Logo object //====================================================================== var Logo = function(alphabet, options) { "use strict"; this.alphabet = alphabet; this.fine_text = ""; this.x_axis = 1; this.y_axis = true; this.xlate_nsyms = 1; this.xlate_start = null; this.xlate_end = null; this.pspm_list = []; this.pspm_column = []; this.rows = 0; this.columns = 0; if (typeof options === "string") { // the old method signature had fine_text here so we support that this.fine_text = options; } else if (typeof options === "object" && options != null) { this.fine_text = (typeof options.fine_text === "string" ? options.fine_text : ""); this.x_axis = (typeof options.x_axis === "boolean" ? (options.x_axis ? 1 : 0) : 1); if (options.x_axis_hidden != null && options.x_axis_hidden) this.x_axis = -1; this.y_axis = (typeof options.y_axis === "boolean" ? options.y_axis : true); this.xlate_nsyms = (typeof options.xlate_nsyms === "number" ? options.xlate_nsyms : this.xlate_nsyms); this.xlate_start = (typeof options.xlate_start === "number" ? options.xlate_start : this.xlate_start); this.xlate_end = (typeof options.xlate_end === "number" ? options.xlate_end : this.xlate_end); } }; Logo.prototype.add_pspm = function(pspm, column) { "use strict"; var col; if (typeof column === "undefined") { column = 0; } else if (column < 0) { throw new Error("Column index out of bounds."); } this.pspm_list[this.rows] = pspm; this.pspm_column[this.rows] = column; this.rows++; col = column + pspm.get_motif_length(); if (col > this.columns) { this.columns = col; } }; Logo.prototype.get_columns = function() { "use strict"; return this.columns; }; Logo.prototype.get_xlate_nsyms = function() { "use strict"; return this.xlate_nsyms; }; Logo.prototype.get_xlate_start = function() { "use strict"; return (this.xlate_start != null ? this.xlate_start : 0); }; Logo.prototype.get_xlate_end = function() { "use strict"; return (this.xlate_end != null ? this.xlate_end : this.columns * this.xlate_nsyms); }; Logo.prototype.get_xlate_columns = function() { "use strict"; return this.get_xlate_end() - this.get_xlate_start(); }; Logo.prototype.get_rows = function() { "use strict"; return this.rows; }; Logo.prototype.get_pspm = function(row_index) { "use strict"; if (row_index < 0 || row_index >= this.rows) { throw new Error("INDEX_OUT_OF_BOUNDS"); } return this.pspm_list[row_index]; }; Logo.prototype.get_offset = function(row_index) { "use strict"; if (row_index < 0 || row_index >= this.rows) { throw new Error("INDEX_OUT_OF_BOUNDS"); } return this.pspm_column[row_index]; }; Logo.prototype._as_eps_data = function(ssc, errbars) { var i, j, pos, stack_pos, pspm, stack, sym, out; out = ""; for (i = 0; i < this.rows; i++) { out += "\nStartLine\n"; // Indent for (j = 0; j < this.pspm_column[i]; j++) { out += "() startstack\nendstack\n\n"; } pspm = this.pspm_list[i]; if (pspm.get_left_trim() > 0) { out += "MuteColour\nDrawTrimEdge\n" + pspm.get_left_trim() + " DrawTrimBg\n"; } for (pos = 0; pos < pspm.get_motif_length(); pos++) { if (pos != 0 && pos == pspm.get_left_trim()) { // enable full colour out += "DrawTrimEdge\nRestoreColour\n"; } else if (pos == (pspm.get_motif_length() - pspm.get_right_trim())) { out += "MuteColour\n" + pspm.get_right_trim() + " DrawTrimBg\n"; } out += "(" + (pos + 1) + ") startstack\n"; stack = pspm.get_stack(pos, this.alphabet, ssc); for (stack_pos = 0; stack_pos < stack.length; stack_pos++) { sym = stack[stack_pos]; out += " " + (sym.get_scale() * this.alphabet.get_ic()) + " (" + sym.get_symbol() + ") numchar\n"; } if (errbars) { out += " " + pspm.get_error(this.alphabet) + " Ibeam\n"; } out += "endstack\n\n"; } if (pspm.get_right_trim() > 0 || pspm.get_left_trim() == pspm.get_motif_length()) { out += "RestoreColour\n"; } out += "EndLine\n"; } return out; }; Logo.prototype.as_eps = function(options) { "use strict"; if (this.xlate_nsyms != 1) throw new Error("Unsupported setting xlate_nsyms for EPS"); if (this.xlate_start != null) throw new Error("Unsupported setting xlate_start for EPS"); if (this.xlate_end != null) throw new Error("Unsupported setting xlate_end for EPS"); var LOGOHEIGHT = 7.5; // default height of line in cm var cm2pts, height, width, now, ssc, errbars; if (typeof options === "undefined") { options = {}; } cm2pts = 72 / 2.54; if (typeof options.logo_height == "number") { height = options.logo_height; } else { height = LOGOHEIGHT * this.rows; } if (typeof options.logo_width == "number") { width = options.logo_width; } else { width = this.columns + 2; } now = new Date(); ssc = (typeof options.ssc == "boolean" ? options.ssc : false); errbars = (typeof options.show_error_bar == "boolean" ? options.show_error_bar : ssc); var values = { "LOGOHEIGHT": height, "LOGOWIDTH": width, "BOUNDINGHEIGHT": Math.round(height * cm2pts), "BOUNDINGWIDTH": Math.round(width * cm2pts), "LOGOLINEHEIGHT": (height / this.rows), "CHARSPERLINE": this.columns, "BARBITS": this.alphabet.get_ic(), "LOGOTYPE": (this.alphabet.has_complement() ? "NA" : "AA"), "CREATIONDATE": now.getDate() + "." + (now.getMonth() + 1) + "." + now.getFullYear() + " " + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds(), "ERRORBARFRACTION": (typeof options.error_bar_fraction == "number" ? options.error_bar_fraction : 1.0), "TICBITS": (typeof options.ticbits == "number" ? options.ticbits : 1.0), "TITLE": (typeof options.title == "string" ? options.title : ""), "FINEPRINT": (typeof options.fineprint == "string" ? options.fineprint : this.fine_text), "XAXISLABEL": (typeof options.xaxislabel == "string" ? options.xaxislabel : ""), "YAXISLABEL": (typeof options.yaxislabel == "string" ? options.yaxislabel : "bits"), "SSC": ssc, "YAXIS": (typeof options.show_y_axis == "boolean" ? options.show_y_axis : this.y_axis), "SHOWENDS": (typeof options.show_ends == "boolean" ? options.show_ends : false), "ERRBAR": errbars, "OUTLINE": (typeof options.show_outline == "boolean" ? options.show_outline : false), "NUMBERING": (typeof options.show_numbering == "boolean" ? options.show_numbering : this.x_axis != 0), "SHOWINGBOX": (typeof options.show_box == "boolean" ? options.show_box : false), "CREATOR": (typeof options.creator == "string" ? options.creator : "motif_logo.js"), "FONTSIZE": (typeof options.label_font_size == "number" ? options.label_font_size : 12), "TITLEFONTSIZE": (typeof options.title_font_size == "number" ? options.title_font_size : 12), "SMALLFONTSIZE": (typeof options.small_font_size == "number" ? options.small_font_size : 6), "TOPMARGIN" : (typeof options.top_margin == "number" ? options.top_margin : 0.9), "BOTTOMMARGIN": (typeof options.bottom_margin == "number" ? options.bottom_margin : 0.9), "COLORDICT": this.alphabet._as_eps_dict(), "DATA": this._as_eps_data(ssc, errbars) }; // now this requires that the script containing the template has been imported! return motif_logo_template(values); }; //====================================================================== // end Logo object //====================================================================== // calculate the exact size (in pixels) of an object drawn on the // canvas assuming that the background of the canvas is transparent. function canvas_bounds(ctx, cwidth, cheight) { "use strict"; var data, r, c, top_line, bottom_line, left_line, right_line, txt_width, txt_height; // extract the image data data = ctx.getImageData(0, 0, cwidth, cheight).data; // set initial values top_line = -1; bottom_line = -1; left_line = -1; right_line = -1; txt_width = 0; txt_height = 0; // Find the top-most line with a non-transparent pixel for (r = 0; r < cheight; r++) { for (c = 0; c < cwidth; c++) { if (data[r * cwidth * 4 + c * 4 + 3]) { top_line = r; break; } } if (top_line != -1) { break; } } // Only bother looking if we found at least one set pixel... if (top_line != -1) { //find the last line with a non-transparent pixel for (r = cheight-1; r >= top_line; r--) { for(c = 0; c < cwidth; c++) { if(data[r * cwidth * 4 + c * 4 + 3]) { bottom_line = r; break; } } if (bottom_line != -1) { break; } } // calculate height txt_height = bottom_line - top_line + 1; // Find the left-most line with a non-transparent pixel for (c = 0; c < cwidth; c++) { for (r = top_line; r <= bottom_line; r++) { if (data[r * cwidth * 4 + c * 4 + 3]) { left_line = c; break; } } if (left_line != -1) { break; } } //find the right most line with a non-transparent pixel for (c = cwidth-1; c >= left_line; c--) { for(r = top_line; r <= bottom_line; r++) { if(data[r * cwidth * 4 + c * 4 + 3]) { right_line = c; break; } } if (right_line != -1) { break; } } txt_width = right_line - left_line + 1; } //return the bounds return {bound_top: top_line, bound_bottom: bottom_line, bound_left: left_line, bound_right: right_line, width: txt_width, height: txt_height}; } //====================================================================== // start RasterizedAlphabet //====================================================================== // Rasterize Alphabet // 1) Measure width of text at default font for all symbols in alphabet // 2) sort in width ascending // 3) Drop the top and bottom 10% (designed to ignore outliers like 'W' and 'I') // 4) Calculate the average as the maximum scaling factor (designed to stop I becoming a rectangular blob). // 5) Assume scale of zero would result in width of zero, interpolate scale required to make perfect width font // 6) Draw text onto temp canvas at calculated scale // 7) Find bounds of drawn text // 8) Paint on to another canvas at the desired height (but only scaling width to fit if larger). var RasterizedAlphabet = function(alphabet, logo_scale, font, width) { "use strict"; var default_size, safety_pad, canvas, ctx, middle, baseline, widths, sizes, i, sym, size, tenpercent, avg_width, scale, target_width, target_height; //variable prototypes this.alphabet = alphabet; this.scale = logo_scale; this.sym_cache = {}; this.stack_num_cache = []; this.scale_num_cache = []; // size of canvas default_size = 60; // size of measuring canvas safety_pad = 20; // pixels to pad around so we don't miss the edges // create a canvas to do our measuring canvas = document.createElement("canvas"); if (!canvas.getContext) throw new Error("No canvas support"); canvas.width = default_size + 2 * safety_pad; canvas.height = default_size + 2 * safety_pad; middle = Math.round(canvas.width / 2); baseline = Math.round(canvas.height - safety_pad); ctx = canvas.getContext('2d'); if (!supports_text(ctx)) throw new Error("Canvas does not support text"); ctx.font = font; ctx.textAlign = "center"; ctx.translate(middle, baseline); // list of widths widths = []; sizes = []; //now measure each letter in the alphabet for (i = 0; i < alphabet.get_size_core(); ++i) { // reset the canvas ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = alphabet.get_colour(i); // draw the test text ctx.fillText(alphabet.get_symbol(i), 0, 0); //measure size = canvas_bounds(ctx, canvas.width, canvas.height); if (size.width === 0) throw new Error("Invisible symbol!"); widths.push(size.width); sizes[i] = size; } //sort the widths widths.sort(function(a,b) {return a - b;}); //drop 10% of the items off each end tenpercent = Math.floor(widths.length / 10); for (i = 0; i < tenpercent; ++i) { widths.pop(); widths.shift(); } //calculate average width avg_width = 0; for (i = 0; i < widths.length; ++i) { avg_width += widths[i]; } avg_width /= widths.length; // calculate the target width target_width = width * this.scale * 2; // calculate scales for (i = 0; i < alphabet.get_size_core(); ++i) { sym = alphabet.get_symbol(i); size = sizes[i]; // calculate scale scale = target_width / Math.max(avg_width, size.width); // estimate scaled height target_height = size.height * scale; // create an appropriately sized canvas canvas = document.createElement("canvas"); canvas.width = target_width; canvas.height = target_height + safety_pad * 2; // calculate the middle middle = Math.round(canvas.width / 2); // calculate the baseline baseline = Math.round(canvas.height - safety_pad); // get the context and prepare to draw the rasterized text ctx = canvas.getContext('2d'); ctx.font = font; ctx.fillStyle = alphabet.get_colour(i); ctx.textAlign = "center"; ctx.translate(middle, baseline); ctx.save(); ctx.scale(scale, scale); // draw the text ctx.fillText(sym, 0, 0); ctx.restore(); this.sym_cache[sym] = {"image": canvas, "size": canvas_bounds(ctx, canvas.width, canvas.height)}; } }; RasterizedAlphabet.prototype.get_alphabet = function() { return this.alphabet; }; RasterizedAlphabet.prototype.get_scale = function() { return this.scale; }; RasterizedAlphabet.prototype.draw_stack_sym = function(ctx, letter, dx, dy, dWidth, dHeight) { "use strict"; var entry, image, size; entry = this.sym_cache[letter]; image = entry.image; size = entry.size; ctx.drawImage(image, 0, size.bound_top -1, image.width, size.height+1, dx, dy, dWidth, dHeight); }; RasterizedAlphabet.prototype.draw_stack_num = function(ctx, font, stack_width, index) { var image, image_ctx, text_length; if (index >= this.stack_num_cache.length) { image = document.createElement("canvas"); // measure the text image_ctx = image.getContext('2d'); image_ctx.save(); image_ctx.font = font; text_length = image_ctx.measureText("" + (index + 1)).width; image_ctx.restore(); // resize the canvas to fit image.width = Math.ceil(stack_width); image.height = Math.ceil(text_length); // draw the text image_ctx = image.getContext('2d'); image_ctx.translate(Math.round(stack_width / 2), 0); image_ctx.font = font; image_ctx.textBaseline = "middle"; image_ctx.textAlign = "right"; image_ctx.rotate(-(Math.PI / 2)); image_ctx.fillText("" + (index + 1), 0, 0); this.stack_num_cache[index] = image; } else { image = this.stack_num_cache[index]; } ctx.drawImage(image, 0, 0); } RasterizedAlphabet.prototype.draw_scale_num = function(ctx, font, num) { var image, image_ctx, text_size, m_length; if (num >= this.scale_num_cache.length) { image = document.createElement("canvas"); // measure the text image_ctx = image.getContext('2d'); image_ctx.font = font; text_size = image_ctx.measureText("" + num); if (text_size.actualBoundingBoxAscent && text_size.actualBoundingBoxDesent) { // resize the canvas to fit image.width = Math.ceil(text_size.width); image.height = Math.ceil(text_size.actualBoundingBoxAscent + text_size.actualBoundingBoxDesent); // draw the text image_ctx = image.getContext('2d'); image_ctx.font = font; image_ctx.textAlign = "right"; image_ctx.fillText("" + num, image.width, text_size.actualBoundingBoxAscent); } else { // measure width of 'm' to approximate height, we double it later anyway m_length = image_ctx.measureText("m").width; // resize the canvas to fit image.width = Math.ceil(text_size.width); image.height = Math.ceil(2 * m_length); // draw the text image_ctx = image.getContext('2d'); image_ctx.font = font; image_ctx.textAlign = "right"; image_ctx.textBaseline = "middle"; image_ctx.fillText("" + num, image.width, m_length); } this.scale_num_cache[num] = image; } else { image = this.scale_num_cache[num]; } ctx.drawImage(image, -image.width, -Math.round(image.height / 2)) } //====================================================================== // end RasterizedAlphabet //====================================================================== //====================================================================== // start LogoMetrics object //====================================================================== var LogoMetrics = function(ctx, logo_columns, logo_rows, has_names, has_finetext, x_axis, y_axis) { "use strict"; var i, row_height; //variable prototypes this.pad_top = (has_names ? 5 : 0); this.pad_left = (y_axis ? 10 : 0); this.pad_right = (has_finetext ? 15 : 0); this.pad_bottom = 0; this.pad_middle = 20; this.name_height = 14; this.name_font = "bold " + this.name_height + "px Times, sans-serif"; this.name_spacer = 0; this.y_axis = y_axis; this.y_label = "bits"; this.y_label_height = 12; this.y_label_font = "bold " + this.y_label_height + "px Helvetica, sans-serif"; this.y_label_spacer = 3; this.y_num_height = 12; this.y_num_width = 0; this.y_num_font = "bold " + this.y_num_height + "px Helvetica, sans-serif"; this.y_tic_width = 5; this.stack_pad_left = 0; this.stack_font = "bold 25px Helvetica, sans-serif"; this.stack_height = 90; this.stack_width = 26; this.stacks_pad_right = 5; this.x_axis = x_axis; this.x_num_above = 2; this.x_num_height = 12; this.x_num_width = 0; this.x_num_font = "bold " + this.x_num_height + "px Helvetica, sans-serif"; this.fine_txt_height = 6; this.fine_txt_above = 2; this.fine_txt_font = "normal " + this.fine_txt_height + "px Helvetica, sans-serif"; this.letter_metrics = new Array(); this.summed_width = 0; this.summed_height = 0; //calculate the width of the y axis numbers ctx.font = this.y_num_font; for (i = 0; i <= 2; i++) { this.y_num_width = Math.max(this.y_num_width, ctx.measureText("" + i).width); } //calculate the width of the x axis numbers (but they are rotated so it becomes height) if (x_axis == 1) { ctx.font = this.x_num_font; for (i = 1; i <= logo_columns; i++) { this.x_num_width = Math.max(this.x_num_width, ctx.measureText("" + i).width); } } else if (x_axis == 0) { this.x_num_height = 4; this.x_num_width = 4; } else { this.x_num_height = 0; this.x_num_width = 0; } //calculate how much vertical space we want to draw this //first we add the padding at the top and bottom since that's always there this.summed_height += this.pad_top + this.pad_bottom; //all except the last row have the same amount of space allocated to them if (logo_rows > 1) { row_height = this.stack_height + this.pad_middle; if (has_names) { row_height += this.name_height; //the label is allowed to overlap into the spacer row_height += Math.max(this.y_num_height/2, this.name_spacer); //the label is allowed to overlap the space used by the other label row_height += Math.max(this.y_num_height/2, this.x_num_height + this.x_num_above); } else { row_height += this.y_num_height/2; //the label is allowed to overlap the space used by the other label row_height += Math.max(this.y_num_height/2, this.x_num_height + this.x_num_above); } this.summed_height += row_height * (logo_rows - 1); } //the last row has the name and fine text below it but no padding this.summed_height += this.stack_height + (this.y_axis ? this.y_num_height/2 : 0); var fine_txt_total = (has_finetext ? this.fine_txt_height + this.fine_txt_above : 0); if (has_names) { this.summed_height += fine_txt_total + this.name_height; this.summed_height += Math.max((this.y_axis ? this.y_num_height/2 : 0), this.x_num_height + this.x_num_above + this.name_spacer); } else { this.summed_height += Math.max((this.y_axis ? this.y_num_height/2 : 0), this.x_num_height + this.x_num_above + fine_txt_total); } //calculate how much horizontal space we want to draw this //first add the padding at the left and right since that's always there this.summed_width += this.pad_left + this.pad_right; if (this.y_axis) { //add on the space for the y-axis label this.summed_width += this.y_label_height + this.y_label_spacer; //add on the space for the y-axis this.summed_width += this.y_num_width + this.y_tic_width; } //add on the space for the stacks this.summed_width += (this.stack_pad_left + this.stack_width) * logo_columns; //add on the padding after the stacks (an offset from the fine text) this.summed_width += this.stacks_pad_right; }; //====================================================================== // end LogoMetrics object //====================================================================== //found this trick at http://talideon.com/weblog/2005/02/detecting-broken-images-js.cfm function image_ok(img) { "use strict"; // During the onload event, IE correctly identifies any images that // weren't downloaded as not complete. Others should too. Gecko-based // browsers act like NS4 in that they report this incorrectly. if (!img.complete) { return false; } // However, they do have two very useful properties: naturalWidth and // naturalHeight. These give the true size of the image. If it failed // to load, either of these should be zero. if (typeof img.naturalWidth !== "undefined" && img.naturalWidth === 0) { return false; } // No other way of checking: assume it's ok. return true; } function supports_text(ctx) { "use strict"; if (!ctx.fillText) { return false; } if (!ctx.measureText) { return false; } return true; } //draws the scale, returns the width function draw_scale(ctx, metrics, alphabet_ic, raster) { "use strict"; var tic_height, i; tic_height = metrics.stack_height / alphabet_ic; ctx.save(); ctx.translate(metrics.y_label_height, metrics.y_num_height/2); //draw the axis label ctx.save(); ctx.font = metrics.y_label_font; ctx.translate(0, metrics.stack_height/2); ctx.rotate(-(Math.PI / 2)); ctx.textAlign = "center"; ctx.fillText("bits", 0, 0); ctx.restore(); ctx.translate(metrics.y_label_spacer + metrics.y_num_width, 0); //draw the axis tics ctx.save(); ctx.translate(0, metrics.stack_height); for (i = 0; i <= alphabet_ic; i++) { //draw the number ctx.save(); ctx.translate(-1, 0); raster.draw_scale_num(ctx, metrics.y_num_font, i); ctx.restore(); //draw the tic ctx.fillRect(0, -1, metrics.y_tic_width, 2); //prepare for next tic ctx.translate(0, -tic_height); } ctx.restore(); ctx.fillRect(metrics.y_tic_width - 2, 0, 2, metrics.stack_height) ctx.restore(); } function draw_stack_num(ctx, metrics, row_index, raster) { "use strict"; ctx.save(); ctx.translate(0, Math.round(metrics.stack_height + metrics.x_num_above)); if (metrics.x_axis == 1) { raster.draw_stack_num(ctx, metrics.x_num_font, metrics.stack_width, row_index); } else if (metrics.x_axis == 0) { // draw dots instead of the numbers (good for small logos) ctx.beginPath(); var radius = Math.round(metrics.x_num_height / 2); ctx.arc(Math.round(metrics.stack_width / 2), radius, radius, 0, 2 * Math.PI, false); ctx.fill(); } ctx.restore(); } function draw_stack(ctx, metrics, symbols, raster) { "use strict"; var preferred_pad, sym_min, i, sym, sym_height, pad; preferred_pad = 0; sym_min = 5; ctx.save();//1 ctx.translate(0, metrics.stack_height); for (i = 0; i < symbols.length; i++) { sym = symbols[i]; sym_height = metrics.stack_height * sym.get_scale(); pad = preferred_pad; if (sym_height - pad < sym_min) { pad = Math.min(pad, Math.max(0, sym_height - sym_min)); } sym_height -= pad; //translate to the correct position ctx.translate(0, -(pad/2 + sym_height)); //draw raster.draw_stack_sym(ctx, sym.get_symbol(), 0, 0, metrics.stack_width, sym_height); //translate past the padding ctx.translate(0, -(pad/2)); } ctx.restore();//1 } function draw_dashed_line(ctx, pattern, start, x1, y1, x2, y2) { "use strict"; var x, y, len, i, dx, dy, tlen, theta, mulx, muly, lx, ly; dx = x2 - x1; dy = y2 - y1; tlen = Math.pow(dx*dx + dy*dy, 0.5); theta = Math.atan2(dy,dx); mulx = Math.cos(theta); muly = Math.sin(theta); lx = []; ly = []; for (i = 0; i < pattern; ++i) { lx.push(pattern[i] * mulx); ly.push(pattern[i] * muly); } i = start; x = x1; y = y1; len = 0; ctx.beginPath(); while (len + pattern[i] < tlen) { ctx.moveTo(x, y); x += lx[i]; y += ly[i]; ctx.lineTo(x, y); len += pattern[i]; i = (i + 1) % pattern.length; x += lx[i]; y += ly[i]; len += pattern[i]; i = (i + 1) % pattern.length; } if (len < tlen) { ctx.moveTo(x, y); x += mulx * (tlen - len); y += muly * (tlen - len); ctx.lineTo(x, y); } ctx.stroke(); } function draw_trim_background(ctx, metrics, left_start, left_end, left_divider, right_start, right_end, right_divider) { "use strict"; var left_size = left_end - left_start; var right_size = right_end - right_start; var line_x; ctx.save();//s8 ctx.fillStyle = "rgb(240, 240, 240)"; if (left_size > 0) { ctx.fillRect(left_start * metrics.stack_width, 0, left_size * metrics.stack_width, metrics.stack_height); } if (right_size > 0) { ctx.fillRect(right_start * metrics.stack_width, 0, right_size * metrics.stack_width, metrics.stack_height); } ctx.fillStyle = "rgb(51, 51, 51)"; if (left_size > 0 && left_divider) { line_x = (left_end * metrics.stack_width) - 0.5; draw_dashed_line(ctx, [3], 0, line_x, 0, line_x, metrics.stack_height); } if (right_size > 0 && right_divider) { line_x = (right_start * metrics.stack_width) + 0.5; draw_dashed_line(ctx, [3], 0, line_x, 0, line_x, metrics.stack_height); } ctx.restore();//s8 } function size_logo_on_canvas(logo, canvas, show_names, scale) { "use strict"; var draw_name, draw_finetext, metrics; draw_name = (typeof show_names === "boolean" ? show_names : (logo.get_rows() > 1)); draw_finetext = (logo.fine_text.length > 0); if (canvas.width !== 0 && canvas.height !== 0) { return; } metrics = new LogoMetrics(canvas.getContext('2d'), logo.get_xlate_columns(), logo.get_rows(), draw_name, draw_finetext, logo.x_axis, logo.y_axis); if (typeof scale == "number") { //resize the canvas to fit the scaled logo canvas.width = metrics.summed_width * scale; canvas.height = metrics.summed_height * scale; } else { if (canvas.width === 0 && canvas.height === 0) { canvas.width = metrics.summed_width; canvas.height = metrics.summed_height; } else if (canvas.width === 0) { canvas.width = metrics.summed_width * (canvas.height / metrics.summed_height); } else if (canvas.height === 0) { canvas.height = metrics.summed_height * (canvas.width / metrics.summed_width); } } } function draw_logo_on_canvas(logo, canvas, show_names, scale) { "use strict"; var i, draw_name, draw_finetext, ctx, metrics, raster, pspm_i, pspm, offset, col_index, motif_position, ssc; ssc = false; draw_name = (typeof show_names === "boolean" ? show_names : (logo.get_rows() > 1)); draw_finetext = (logo.fine_text.length > 0); ctx = canvas.getContext('2d'); //assume that the user wants the canvas scaled equally so calculate what the best width for this image should be metrics = new LogoMetrics(ctx, logo.get_xlate_columns(), logo.get_rows(), draw_name, draw_finetext, logo.x_axis, logo.y_axis); if (typeof scale == "number") { //resize the canvas to fit the scaled logo canvas.width = metrics.summed_width * scale; canvas.height = metrics.summed_height * scale; } else { if (canvas.width === 0 && canvas.height === 0) { scale = 1; canvas.width = metrics.summed_width; canvas.height = metrics.summed_height; } else if (canvas.width === 0) { scale = canvas.height / metrics.summed_height; canvas.width = metrics.summed_width * scale; } else if (canvas.height === 0) { scale = canvas.width / metrics.summed_width; canvas.height = metrics.summed_height * scale; } else { scale = Math.min(canvas.width / metrics.summed_width, canvas.height / metrics.summed_height); } } // cache the raster based on the assumption that we will be drawing a lot // of logos the same size and alphabet if (typeof draw_logo_on_canvas.raster_cache === "undefined") { draw_logo_on_canvas.raster_cache = []; } for (i = 0; i < draw_logo_on_canvas.raster_cache.length; i++) { raster = draw_logo_on_canvas.raster_cache[i]; if (raster.get_alphabet().equals(logo.alphabet) && Math.abs(raster.get_scale() - scale) < 0.1) break; raster = null; } if (raster == null) { raster = new RasterizedAlphabet(logo.alphabet, scale, metrics.stack_font, metrics.stack_width); draw_logo_on_canvas.raster_cache.push(raster); } ctx = canvas.getContext('2d'); ctx.save();//s1 ctx.scale(scale, scale); ctx.save();//s2 ctx.save();//s7 //create margin ctx.translate(Math.round(metrics.pad_left), Math.round(metrics.pad_top)); for (pspm_i = 0; pspm_i < logo.get_rows(); ++pspm_i) { pspm = logo.get_pspm(pspm_i); offset = logo.get_offset(pspm_i); //optionally draw name if this isn't the last row or is the only row if (draw_name && (logo.get_rows() == 1 || pspm_i != (logo.get_rows()-1))) { ctx.save();//s4 ctx.translate(Math.round(metrics.summed_width/2), Math.round(metrics.name_height)); ctx.font = metrics.name_font; ctx.textAlign = "center"; ctx.fillText(pspm.name, 0, 0); ctx.restore();//s4 ctx.translate(0, Math.round(metrics.name_height + Math.min(0, metrics.name_spacer - metrics.y_num_height/2))); } //draw scale if (logo.y_axis) draw_scale(ctx, metrics, logo.alphabet.get_ic(), raster); ctx.save();//s5 //translate across past the scale if (logo.y_axis) { ctx.translate(Math.round(metrics.y_label_height + metrics.y_label_spacer + metrics.y_num_width + metrics.y_tic_width), Math.round(metrics.y_num_height / 2)); } //draw the trimming background if (pspm.get_left_trim() > 0 || pspm.get_right_trim() > 0) { var left_start = offset * logo.get_xlate_nsyms(); var left_end = (offset + pspm.get_left_trim()) * logo.get_xlate_nsyms(); var left_divider = true; if (left_end < logo.get_xlate_start() || left_start > logo.get_xlate_end()) { // no overlap left_start = 0; left_end = 0; left_divider = false; } else { if (left_start < logo.get_xlate_start()) { left_start = logo.get_xlate_start(); } if (left_end > logo.get_xlate_end()) { left_end = logo.get_xlate_end(); left_divider = false; } left_start -= logo.get_xlate_start(); left_end -= logo.get_xlate_start(); if (left_end < left_start) { left_start = 0; left_end = 0; left_divider = false; } } var right_end = (offset + pspm.get_motif_length()) * logo.get_xlate_nsyms(); //var right_start = right_end - (pspm.get_left_trim() * logo.get_xlate_nsyms()); var right_start = right_end - (pspm.get_right_trim() * logo.get_xlate_nsyms()); var right_divider = true; if (right_end < logo.get_xlate_start() || right_start > logo.get_xlate_end()) { // no overlap right_start = 0; right_end = 0; right_divider = false; } else { if (right_start < logo.get_xlate_start()) { right_start = logo.get_xlate_start(); right_divider = false; } if (right_end > logo.get_xlate_end()) { right_end = logo.get_xlate_end(); } right_start -= logo.get_xlate_start(); right_end -= logo.get_xlate_start(); if (right_end < right_start) { right_start = 0; right_end = 0; right_divider = false; } } draw_trim_background(ctx, metrics, left_start, left_end, left_divider, right_start, right_end, right_divider); } //draw letters var xlate_col; for (xlate_col = logo.get_xlate_start(); xlate_col < logo.get_xlate_end(); xlate_col++) { ctx.translate(metrics.stack_pad_left,0); col_index = Math.floor(xlate_col / logo.get_xlate_nsyms()); if (xlate_col % logo.get_xlate_nsyms() == 0) { if (col_index >= offset && col_index < (offset + pspm.get_motif_length())) { motif_position = col_index - offset; draw_stack_num(ctx, metrics, motif_position, raster); draw_stack(ctx, metrics, pspm.get_stack(motif_position, logo.alphabet, ssc), raster); } } else { if (col_index >= offset && col_index < (offset + pspm.get_motif_length())) { ctx.save();// s5.1 ctx.translate(0, Math.round(metrics.stack_height)); // TODO draw a dot or dash or something to indicate continuity of the motif ctx.restore(); //s5.1 } } ctx.translate(Math.round(metrics.stack_width), 0); } ctx.restore();//s5 ////optionally draw name if this is the last row but isn't the only row if (draw_name && (logo.get_rows() != 1 && pspm_i == (logo.get_rows()-1))) { //translate vertically past the stack and axis's ctx.translate(0, metrics.y_num_height/2 + metrics.stack_height + Math.max(metrics.y_num_height/2, metrics.x_num_above + metrics.x_num_width + metrics.name_spacer)); ctx.save();//s6 ctx.translate(metrics.summed_width/2, metrics.name_height); ctx.font = metrics.name_font; ctx.textAlign = "center"; ctx.fillText(pspm.name, 0, 0); ctx.restore();//s6 ctx.translate(0, metrics.name_height); } else { //translate vertically past the stack and axis's ctx.translate(0, metrics.y_num_height/2 + metrics.stack_height + Math.max(metrics.y_num_height/2, metrics.x_num_above + metrics.x_num_width)); } //if not the last row then add middle padding if (pspm_i != (logo.get_rows() -1)) { ctx.translate(0, metrics.pad_middle); } } ctx.restore();//s7 if (logo.fine_text.length > 0) { ctx.translate(metrics.summed_width - metrics.pad_right, metrics.summed_height - metrics.pad_bottom); ctx.font = metrics.fine_txt_font; ctx.textAlign = "right"; ctx.fillText(logo.fine_text, 0,0); } ctx.restore();//s2 ctx.restore();//s1 } function create_canvas(c_width, c_height, c_id, c_title, c_display) { "use strict"; var canvas = document.createElement("canvas"); //check for canvas support before attempting anything if (!canvas.getContext) { return null; } var ctx = canvas.getContext('2d'); //check for html5 text drawing support if (!supports_text(ctx)) { return null; } //size the canvas canvas.width = c_width; canvas.height = c_height; canvas.id = c_id; canvas.title = c_title; canvas.style.display = c_display; return canvas; } function logo_1(alphabet, fine_text, pspm) { "use strict"; var logo = new Logo(alphabet, fine_text); logo.add_pspm(pspm); return logo; } function logo_2(alphabet, fine_text, target, query, query_offset) { "use strict"; var logo = new Logo(alphabet, fine_text); if (query_offset < 0) { logo.add_pspm(target, -query_offset); logo.add_pspm(query); } else { logo.add_pspm(target); logo.add_pspm(query, query_offset); } return logo; } /* * Specifies an alternate source for an image. * If the image with the image_id specified has * not loaded then a generated logo will be used * to replace it. * * Note that the image must either have dimensions * or a scale must be set. */ function alternate_logo(logo, image_id, scale) { "use strict"; var image = document.getElementById(image_id); if (!image) { alert("Can't find specified image id (" + image_id + ")"); return; } //if the image has loaded then there is no reason to use the canvas if (image_ok(image)) { return; } //the image has failed to load so replace it with a canvas if we can. var canvas = create_canvas(image.width, image.height, image_id, image.title, image.style.display); if (canvas === null) { return; } //draw the logo on the canvas draw_logo_on_canvas(logo, canvas, null, scale); //replace the image with the canvas image.parentNode.replaceChild(canvas, image); } /* * Specifes that the element with the specified id * should be replaced with a generated logo. */ function replace_logo(logo, replace_id, scale, title_txt, display_style) { "use strict"; var element = document.getElementById(replace_id); if (!replace_id) { alert("Can't find specified id (" + replace_id + ")"); return; } //found the element! var canvas = create_canvas(50, 120, replace_id, title_txt, display_style); if (canvas === null) { return; } //draw the logo on the canvas draw_logo_on_canvas(logo, canvas, null, scale); //replace the element with the canvas element.parentNode.replaceChild(canvas, element); } /* * Fast string trimming implementation found at * http://blog.stevenlevithan.com/archives/faster-trim-javascript * * Note that regex is good at removing leading space but * bad at removing trailing space as it has to first go through * the whole string. */ function trim (str) { "use strict"; var ws, i; str = str.replace(/^\s\s*/, ''); ws = /\s/; i = str.length; while (ws.test(str.charAt(--i))); return str.slice(0, i + 1); } </script> <script> var current_motif = 0; var dreme_alphabet = new Alphabet(data.alphabet, data.control_db.freqs); /* * Create a pspm for the given motif data */ function motif_pspm(m) { return new Pspm(m.pwm, m.id, 0, 0, m.nsites, m.evalue); } /* * Create a count matrix from the given motif data */ function motif_count_matrix(motif) { return motif_pspm(motif).as_count_matrix(); } /* * Create a probablity matrix from the given motif data */ function motif_prob_matrix(motif) { return motif_pspm(motif).as_probability_matrix(); } /* * Create a minimal meme format motif from the given motif data */ function motif_minimal_meme(motif) { return motif_pspm(motif).as_meme({ "with_header": true, "with_pspm": true, "with_pssm": false, "version": data["version"], "alphabet": dreme_alphabet, "strands": (data.options.revcomp ? 2 : 1) }); } /* * Fill in a template variable */ function set_tvar(template, tvar, value) { var node; node = find_child(template, tvar); if (node === null) { throw new Error("Template does not contain variable " + tvar); } node.innerHTML = ""; if (typeof value !== "object") { node.appendChild(document.createTextNode(value)); } else { node.appendChild(value); } } /* * Make a canvas with the motif logo drawn on it. */ function make_logo(motif, height, rc) { var pspm = new Pspm(motif["pwm"]); if (rc) pspm = pspm.copy().reverse_complement(dreme_alphabet); var logo = new Logo(dreme_alphabet); logo.add_pspm(pspm, 0); var canvas = document.createElement('canvas'); canvas.height = height; canvas.width = 0; draw_logo_on_canvas(logo, canvas, false); return canvas; } /* * Create a button designed to contain a single symbol */ function make_sym_btn(symbol, title, action) { var box, sbox; box = document.createElement("div"); box.tabIndex = 0; box.className = "sym_btn"; sbox = document.createElement("span"); if (typeof symbol == "string") { sbox.appendChild(document.createTextNode(symbol)); } else { sbox.appendChild(symbol); } box.appendChild(sbox); box.title = title; box.addEventListener('click', action, false); box.addEventListener('keydown', action, false); return box; } /* * Create a pair of text spans with different classes. * This is useful when using CSS to only display one of them. */ function text_pair(txt1, cls1, txt2, cls2) { var container, part1, part2; container = document.createElement("span"); part1 = document.createElement("span"); part1.appendChild(document.createTextNode(txt1)); part1.className = cls1; container.appendChild(part1); part2 = document.createElement("span"); part2.appendChild(document.createTextNode(txt2)); part2.className = cls2; container.appendChild(part2); return container; } /* * Make a colourised sequence. */ function make_seq(seq) { var i, j, letter, lbox, sbox; sbox = document.createElement("span"); for (i = 0; i < seq.length; i = j) { letter = seq.charAt(i); for (j = i+1; j < seq.length; j++) { if (seq.charAt(j) !== letter) { break; } } lbox = document.createElement("span"); lbox.style.color = dreme_alphabet.get_colour(dreme_alphabet.get_index(letter)); lbox.appendChild(document.createTextNode(seq.substring(i, j))); sbox.appendChild(lbox); } return sbox; } /* * Create a description element taking into account the newlines in the source text. */ function make_description(text) { var i, j, lines, p; var container = document.createElement("div"); var paragraphs = text.split(/\n\n+/); for (i = 0; i < paragraphs.length; i++) { lines = paragraphs[i].split(/\n/); p = document.createElement("p"); p.appendChild(document.createTextNode(lines[0])); for (j = 1; j < lines.length; j++) { p.appendChild(document.createElement("br")); p.appendChild(document.createTextNode(lines[j])); } container.appendChild(p); } return container; } /* * Make the table header for the discovered motifs. */ function make_motif_header() { var row = document.createElement("tr"); add_text_header_cell(row, "", "", "motif_ordinal"); add_text_header_cell(row, "Motif", "pop_motifs_word", "motif_word"); add_text_header_cell(row, "Logo", "pop_motifs_logo", "motif_logo"); if (data.options.revcomp) { add_text_header_cell(row, "RC Logo", "pop_motifs_rc_logo", "motif_logo"); } add_text_header_cell(row, "E-value", "pop_motifs_evalue", "motif_evalue"); add_text_header_cell(row, "Unerased E-value", "pop_motifs_uevalue", "motif_evalue"); add_text_header_cell(row, "More", "pop_more", "motif_more"); add_text_header_cell(row, "Submit/Download", "pop_submit_dl", "motif_submit"); row.className = "more"; return row; } /* * Make a compact motif summary row for the discovered motifs. */ function make_motif_row(tbody, ordinal, motif) { var row = document.createElement("tr"); add_text_cell(row, "" + ordinal + ".", "motif_ordinal"); add_text_cell(row, motif["id"], "motif_word"); add_cell(row, make_logo(motif, 50, false), "motif_logo"); if (data.options.revcomp) { add_cell(row, make_logo(motif, 50, true), "motif_logo"); } add_text_cell(row, motif["evalue"], "motif_evalue"); add_text_cell(row, motif["unerased_evalue"], "motif_evalue"); add_cell(row, make_sym_btn(text_pair("\u21A7", "less", "\u21A5", "more"), "Show more information.", function(e) { toggle_class(tbody, "collapsed"); }, "\u21A5", ""), "motif_more"); add_cell(row, make_sym_btn("\u21E2", "Submit the motif to another MEME Suite program or download it.", function(e) { action_show_outpop(e, ordinal); }), "motif_submit"); return row; } /* * Make a sortable table of enriched matching rows. */ function make_motif_words(motif) { var row, i, match; var table = document.createElement("table"); var thead = document.createElement("thead"); row = document.createElement("tr"); add_text_header_cell(row, "Word", "pop_match_word", "match_word", function(e) {sort_table(this, compare_words);}); add_text_header_cell(row, "Positives", "pop_match_pos", "match_count", function(e) {sort_table(this, compare_counts);}); add_text_header_cell(row, "Negatives", "pop_match_neg", "match_count", function(e) {sort_table(this, compare_counts);}); add_text_header_cell(row, "P-value", "pop_match_pval", "match_evalue", function(e) {sort_table(this, compare_evalues);}); add_text_header_cell(row, "E-value", "pop_match_eval", "match_evalue", function(e) {sort_table(this, compare_evalues);}); thead.appendChild(row); table.appendChild(thead); var tbody = document.createElement("tbody"); for (i = 0; i < motif.matches.length; i++) { match = motif.matches[i]; row = document.createElement("tr"); add_cell(row, make_seq(match.seq), "match_word"); add_text_cell(row, match.p + " / " + data.sequence_db.count, "match_count"); add_text_cell(row, match.n + " / " + data.control_db.count, "match_count"); add_text_cell(row, match.pvalue, "match_evalue"); add_text_cell(row, match.evalue, "match_evalue"); tbody.appendChild(row); } table.appendChild(tbody); return table; } /* * Make an expanded view of a discovered motif. */ function make_motif_exp(tbody, ordinal, motif) { "use strict"; var box, pspm, logo_box; box = $("tmpl_motif_expanded").cloneNode(true); toggle_class(box, "template", false); box.id = ""; find_child(box, "tvar_logo").appendChild(make_logo(motif, 150, false)); if (data.options.revcomp) { find_child(box, "tvar_rclogo").appendChild(make_logo(motif, 150, true)); } set_tvar(box, "tvar_p", motif["p"]); set_tvar(box, "tvar_p_total", data.sequence_db.count); set_tvar(box, "tvar_n", motif["n"]); set_tvar(box, "tvar_n_total", data.control_db.count); set_tvar(box, "tvar_pvalue", motif["pvalue"]); set_tvar(box, "tvar_evalue", motif["evalue"]); set_tvar(box, "tvar_uevalue", motif["unerased_evalue"]); set_tvar(box, "tvar_words", make_motif_words(motif)); var cell = document.createElement("td"); cell.colSpan = 8; cell.appendChild(box); var row = document.createElement("tr"); row.className = "more"; row.appendChild(cell); return row; } /* * Convert a string containing a scientific number into the log of that number * without having an intermediate representation of the number. * This is intended to avoid underflow problems with the tiny evalues that * MEME and DREME can create. */ function sci2log(scinum) { "use strict"; var ev_re, match, sig, exp; ev_re = /^(.*)e(.*)$/; if (match = ev_re.exec(scinum)) { sig = parseFloat(match[1]); exp = parseInt(match[2]); return Math.log(sig) + (exp * Math.log(10)); } return 0; } /* * Create a table of discovered motifs. A fresh table body is used for each * motif to make hiding/showing rows with css easier. */ function make_motifs() { "use strict"; var i, row, tbody, motif, ordinal; // make the motifs table var container = $("motifs"); container.innerHTML = ""; // clear content var table = document.createElement("table"); // add a header that is always shown var thead = document.createElement("thead"); thead.appendChild(make_motif_header()); table.appendChild(thead); for (i = 0; i < data.motifs.length; i++) { ordinal = i + 1; motif = data.motifs[i]; tbody = document.createElement("tbody"); tbody.className = "collapsed"; tbody.appendChild(make_motif_row(tbody, ordinal, motif)); tbody.appendChild(make_motif_exp(tbody, ordinal, motif)); // create a following header for every row except the last one if ((i + 1) < data.motifs.length) tbody.appendChild(make_motif_header()); table.appendChild(tbody); } container.appendChild(table); } /* * Create a table showing all the alphabet symbols, their names and frequencies. */ function make_alpha_bg(alph, freqs) { function colour_symbol(index) { var span = document.createElement("span"); span.appendChild(document.createTextNode(alph.get_symbol(index))); span.style.color = alph.get_colour(index); span.className = "alpha_symbol"; return span; } var table, thead, tbody, row, th, span, i; // create table table = document.createElement("table"); table.className = "inputs"; // create header thead = document.createElement("thead"); table.appendChild(thead); row = thead.insertRow(thead.rows.length); if (alph.has_complement()) { add_text_header_cell(row, "Name", "pop_alph_name"); add_text_header_cell(row, "Bg.", "pop_alph_control"); add_text_header_cell(row, ""); add_text_header_cell(row, ""); add_text_header_cell(row, ""); add_text_header_cell(row, "Bg.", "pop_alph_control"); add_text_header_cell(row, "Name", "pop_alph_name"); } else { add_text_header_cell(row, ""); add_text_header_cell(row, "Name", "pop_alph_name"); add_text_header_cell(row, "Bg.", "pop_alph_control"); } // add alphabet entries tbody = document.createElement("tbody"); table.appendChild(tbody); if (alph.has_complement()) { for (i = 0; i < alph.get_size_core(); i++) { var c = alph.get_complement(i); if (i > c) continue; row = tbody.insertRow(tbody.rows.length); add_text_cell(row, alph.get_name(i)); add_text_cell(row, "" + freqs[i].toFixed(3)); add_cell(row, colour_symbol(i)); add_text_cell(row, "~"); add_cell(row, colour_symbol(c)); add_text_cell(row, "" + freqs[c].toFixed(3)); add_text_cell(row, alph.get_name(c)); } } else { for (i = 0; i < alph.get_size_core(); i++) { row = tbody.insertRow(tbody.rows.length); add_cell(row, colour_symbol(i)); add_text_cell(row, alph.get_name(i)); add_text_cell(row, "" + freqs[i].toFixed(3)); } } return table; } /* * Updates the format download text in the popup. * This is called when either the format or current motif changes. */ function update_outpop_format(index) { var motif = data.motifs[index]; var fn = [motif_count_matrix, motif_prob_matrix, motif_minimal_meme]; var suffix = ["_counts.txt", "_freqs.txt", ".meme"]; var format = parseInt($("text_format").value); var text = fn[format](motif); prepare_download(text, "text/plain", motif.id + suffix[format], $("outpop_text_dl")); $("outpop_text").value = text; } /* * Updates the motif logos and format download text in the popup. * This is called whenever the current motif changes. */ function update_outpop_motif(index) { "use strict"; var motifs, motif, pspm, logo, canvas, num; motifs = data["motifs"]; if (index < 0 || index >= motifs.length) {return;} current_motif = index; motif = motifs[index]; pspm = new Pspm(motif["pwm"]); logo = new Logo(dreme_alphabet, ""); logo.add_pspm(pspm, 0); canvas = $("outpop_logo"); canvas.width = canvas.width; // clear canvas draw_logo_on_canvas(logo, canvas, false); canvas = $("outpop_logo_rc"); canvas.width = canvas.width; // clear rc canvas if (data.options.revcomp) { pspm.reverse_complement(dreme_alphabet); logo = new Logo(dreme_alphabet, ""); logo.add_pspm(pspm, 0); draw_logo_on_canvas(logo, canvas, false); } num = $("outpop_num"); num.innerHTML = ""; num.appendChild(document.createTextNode("" + (index + 1))); update_outpop_format(index); } /* * Initialise and display the download popup. */ function action_show_outpop(e, ordinal) { "use strict"; function init() { "use strict"; var close_btn, next_btn, prev_btn, cancel_btn, do_btn; var tab1, tab2, tab3; var pnl1, pnl2, pnl3; var format_list; var tbl_submit, inputs, i, default_prog; close_btn = $("outpop_close"); close_btn.addEventListener("click", action_hide_outpop, false); close_btn.addEventListener("keydown", action_hide_outpop, false); next_btn = $("outpop_next"); next_btn.addEventListener("click", action_outpop_next, false); next_btn.addEventListener("keydown", action_outpop_next, false); prev_btn = $("outpop_prev"); prev_btn.addEventListener("click", action_outpop_prev, false); prev_btn.addEventListener("keydown", action_outpop_prev, false); cancel_btn = $("outpop_cancel"); cancel_btn.addEventListener("click", action_hide_outpop, false); do_btn = $("outpop_do"); do_btn.addEventListener("click", action_outpop_submit, false); tab1 = $("outpop_tab_1"); tab1.tabIndex = 0; tab1.addEventListener("click", action_outpop_tab, false); tab1.addEventListener("keydown", action_outpop_tab, false); tab2 = $("outpop_tab_2"); tab2.tabIndex = 0; tab2.addEventListener("click", action_outpop_tab, false); tab2.addEventListener("keydown", action_outpop_tab, false); tab3 = $("outpop_tab_3"); tab3.tabIndex = 0; tab3.addEventListener("click", action_outpop_tab, false); tab3.addEventListener("keydown", action_outpop_tab, false); pnl1 = $("outpop_pnl_1"); pnl2 = $("outpop_pnl_2"); pnl3 = $("outpop_pnl_3"); toggle_class(tab1, "activeTab", true); toggle_class(tab2, "activeTab", false); toggle_class(tab3, "activeTab", false); pnl1.style.display = "block"; pnl2.style.display = "none"; pnl3.style.display = "none"; format_list = $("text_format"); format_list.addEventListener("change", action_outpop_format, false); // setup program selection tbl_submit = $("programs"); // when not dna, hide the inputs for programs that require dna motifs toggle_class(tbl_submit, "alphabet_dna", dreme_alphabet.has_complement());//TODO FIXME alphabet_dna is a bad name for a field when allowing custom alphabets // add a click listener for the radio buttons inputs = tbl_submit.querySelectorAll("input[type='radio']"); for (i = 0; i < inputs.length; i++) { inputs[i].addEventListener("click", action_outpop_program, false); } // ensure that a default program option is selected for DNA and Protein default_prog = document.getElementById(dreme_alphabet.has_complement() ? "submit_tomtom" : "submit_fimo"); default_prog.checked = true; action_outpop_program.call(default_prog); // disable reverse-complement when not DNA $("logo_rc_option").disabled = !dreme_alphabet.has_complement(); // set errorbars on when ssc is on $("logo_ssc").addEventListener("change", action_outpop_ssc, false); } // store the focused element action_hide_outpop.last_active = document.activeElement; if (!e) e = window.event; if (e.type === "keydown") { if (e.keyCode !== 13 && e.keyCode !== 32) { return; } // stop a submit or something like that e.preventDefault(); } // hide the help popup help_popup(); // on first load initilize the popup if (!action_show_outpop.ready) { init(); action_show_outpop.ready = true; } update_outpop_motif(ordinal - 1); // display the download popup $("grey_out_page").style.display = "block"; $("download").style.display = "block"; $("outpop_close").focus(); } /* * Hide the download popup. */ function action_hide_outpop(e) { if (!e) e = window.event; if (e.type === "keydown") { if (e.keyCode !== 13 && e.keyCode !== 32) { return; } // stop a submit or something like that e.preventDefault(); } $("download").style.display = "none"; $("grey_out_page").style.display = "none"; if (typeof action_hide_outpop.last_active !== "undefined") { action_hide_outpop.last_active.focus(); } } /* * Show the next motif in the download popup. */ function action_outpop_next(e) { if (!e) e = window.event; if (e.type === "keydown") { if (e.keyCode !== 13 && e.keyCode !== 32) { return; } // stop a submit or something like that e.preventDefault(); } update_outpop_motif(current_motif + 1); } /* * Show the previous motif in the download popup. */ function action_outpop_prev(e) { if (!e) e = window.event; if (e.type === "keydown") { if (e.keyCode !== 13 && e.keyCode !== 32) { return; } // stop a submit or something like that e.preventDefault(); } update_outpop_motif(current_motif - 1); } /* * Highlight the selected row in the program list. */ function action_outpop_program() { "use strict"; var table, tr, rows, i; tr = find_parent_tag(this, "TR"); table = find_parent_tag(tr, "TABLE"); rows = table.querySelectorAll("tr"); for (i = 0; i < rows.length; i++) { toggle_class(rows[i], "selected", rows[i] === tr); } } /* * Enable error bars when small sample correction is enabled. */ function action_outpop_ssc() { "use strict"; $("logo_err").value = $("logo_ssc").value; } /* * Submit the motif to the selected program. */ function action_outpop_submit(e) { "use strict"; var form, input, program, motifs; // find out which program is selected var radios, i; radios = document.getElementsByName("program"); program = "fimo"; // default to fimo, since it works with all alphabet types for (i = 0; i < radios.length; i++) { if (radios[i].checked) program = radios[i].value; } motifs = motif_minimal_meme(data.motifs[current_motif]); form = document.createElement("form"); form.setAttribute("method", "post"); form.setAttribute("action", site_url + "/tools/" + program); input = document.createElement("input"); input.setAttribute("type", "hidden"); input.setAttribute("name", "motifs_embed"); input.setAttribute("value", motifs); form.appendChild(input); document.body.appendChild(form); form.submit(); document.body.removeChild(form); } /* * Download the format text. * Wire the link containing the data URI text to a download button so it looks * the same as the server submit stuff. */ function action_outpop_download_motif(e) { $("outpop_text_dl").click(); } /* * Download the motif logo. * The EPS format can be calculated locally in Javascript */ function action_outpop_download_logo(e) { "use strict"; var pspm, logo, eps; var logo_rc, logo_ssc, logo_width, logo_height; var motif = data.motifs[current_motif]; if ($("logo_format").value == "0") { // EPS logo_rc = ($("logo_rc").value == "1"); logo_ssc = ($("logo_ssc").value == "1"); logo_width = parseFloat($("logo_width").value); if (isNaN(logo_width) || !isFinite(logo_width) || logo_width <= 0) logo_width = null; logo_height = parseFloat($("logo_height").value); if (isNaN(logo_height) || !isFinite(logo_height) || logo_height <= 0) logo_height = null; // create a PSPM from the motif pspm = motif_pspm(motif); if (logo_rc) pspm.reverse_complement(dreme_alphabet); logo = new Logo(dreme_alphabet); logo.add_pspm(pspm, 0); eps = logo.as_eps({"ssc": logo_ssc, "logo_width": logo_width, "logo_height": logo_height}); prepare_download(eps, "application/postscript", motif.id + ".eps"); } else { $("logo_motifs").value = motif_minimal_meme(motif); $("logo_form").submit(); } } /* * Change the selected tab in the download popup. */ function action_outpop_tab(e) { "use strict"; var tab1, tab2, tab3, pnl1, pnl2, pnl3, do_btn; if (!e) e = window.event; if (e.type === "keydown") { if (e.keyCode !== 13 && e.keyCode !== 32) { return; } // stop a submit or something like that e.preventDefault(); } tab1 = $("outpop_tab_1"); tab2 = $("outpop_tab_2"); tab3 = $("outpop_tab_3"); pnl1 = $("outpop_pnl_1"); pnl2 = $("outpop_pnl_2"); pnl3 = $("outpop_pnl_3"); do_btn = $("outpop_do"); toggle_class(tab1, "activeTab", (this === tab1)); toggle_class(tab2, "activeTab", (this === tab2)); toggle_class(tab3, "activeTab", (this === tab3)); pnl1.style.display = ((this === tab1) ? "block" : "none"); pnl2.style.display = ((this === tab2) ? "block" : "none"); pnl3.style.display = ((this === tab3) ? "block" : "none"); do_btn.value = ((this === tab1) ? "Submit" : "Download"); do_btn.removeEventListener("click", action_outpop_submit, false); do_btn.removeEventListener("click", action_outpop_download_logo, false); do_btn.removeEventListener("click", action_outpop_download_motif, false); if (this === tab1) { do_btn.addEventListener("click", action_outpop_submit, false); } else if (this === tab2) { do_btn.addEventListener("click", action_outpop_download_motif, false); } else { do_btn.addEventListener("click", action_outpop_download_logo, false); } } /* * Update the text in the download format popup. */ function action_outpop_format() { update_outpop_format(current_motif); } /* * Find all text nodes in the given container. */ function text_nodes(container) { var textNodes = []; var stack = [container]; // depth first search to maintain ordering when flattened while (stack.length > 0) { var node = stack.pop(); if (node.nodeType == Node.TEXT_NODE) { textNodes.push(node); } else { for (var i = node.childNodes.length-1; i >= 0; i--) { stack.push(node.childNodes[i]); } } } return textNodes; } /* * Get the text out of a specific text node. */ function node_text(node) { if (node === undefined) { return ''; } else if (node.textContent) { return node.textContent; } else if (node.innerText) { return node.innerText; } else { return ''; } } /* * Get the text contained within the element. */ function elem_text(elem, separator) { if (separator === undefined) separator = ''; return text_nodes(elem).map(node_text).join(separator); } /* * Sort all rows in the first table body based on the column of the given element and the comparison function. * The sort is not very fast and is intended for small tables only. */ function sort_table(colEle, compare_function) { //find the parent of colEle that is either a td or th var i, j; var cell = colEle; while (true) { if (cell == null) return; if (cell.nodeType == Node.ELEMENT_NODE && (cell.tagName.toLowerCase() == "td" || cell.tagName.toLowerCase() == "th")) { break; } cell = cell.parentNode; } //find the parent of cell that is a tr var row = cell; while (true) { if (row == null) return; if (row.nodeType == Node.ELEMENT_NODE && row.tagName.toLowerCase() == "tr") { break; } row = row.parentNode; } //find the parent of row that is a table var table = row; while (true) { if (table == null) return; if (table.nodeType == Node.ELEMENT_NODE && table.tagName.toLowerCase() == "table") { break; } table = table.parentNode; } var column_index = cell.cellIndex; // do a bubble sort, because the tables are so small it doesn't matter var change; var trs = table.tBodies[0].getElementsByTagName('tr'); var already_sorted = true; var reverse = false; while (true) { do { change = false; for (i = 0; i < trs.length -1; i++) { var v1 = elem_text(trs[i].cells[column_index]); var v2 = elem_text(trs[i+1].cells[column_index]); if (reverse) { var tmp = v1; v1 = v2; v2 = tmp; } if (compare_function(v1, v2) > 0) { exchange(trs[i], trs[i+1], table); change = true; already_sorted = false; trs = table.tBodies[0].getElementsByTagName('tr'); } } } while (change); if (reverse) break;// we've sorted twice so exit if (!already_sorted) break;// sort did something so exit // when it's sorted one way already then sort the opposite way reverse = true; } // put arrows on the headers var headers = table.tHead.getElementsByTagName('tr'); for (i = 0; i < headers.length; i++) { for (j = 0; j < headers[i].cells.length; j++) { var cell = headers[i].cells[j]; var arrows = cell.getElementsByClassName("sort_arrow"); var arrow; if (arrows.length == 0) { arrow = document.createElement("span"); arrow.className = "sort_arrow"; cell.insertBefore(arrow, cell.firstChild); } else { arrow = arrows[0]; } arrow.innerHTML = ""; if (j == column_index) { arrow.appendChild(document.createTextNode(reverse ? "\u25B2" : "\u25BC")); } } } } /* * Swap two rows in a table. */ function exchange(oRowI, oRowJ, oTable) { var i = oRowI.rowIndex; var j = oRowJ.rowIndex; if (i == j+1) { oTable.tBodies[0].insertBefore(oRowI, oRowJ); } if (j == i+1) { oTable.tBodies[0].insertBefore(oRowJ, oRowI); } else { var tmpNode = oTable.tBodies[0].replaceChild(oRowI, oRowJ); if(typeof(oRowI) != "undefined") { oTable.tBodies[0].insertBefore(tmpNode, oRowI); } else { oTable.appendChild(tmpNode); } } } /* * Compare two E-values which may be very small. */ function compare_evalues(v1, v2) { var e1 = sci2log(v1); var e2 = sci2log(v2); if (e1 < e2) return -1; else if (e1 > e2) return 1; return 0; } /* * Compare two counts. */ function compare_counts(v1, v2) { var re = /(\d+)\s*\/\s*\d+/; var m1 = re.exec(v1); var m2 = re.exec(v2); if (m1 == null && m2 == null) return 0; if (m1 == null) return -1; if (m2 == null) return 1; return parseInt(m2[1]) - parseInt(m1[1]); } /* * Compare two sequence words. */ function compare_words(v1, v2) { return v1.localeCompare(v2); } </script> <style> /* The following is the content of meme.css */ body { background-color:white; font-size: 12px; font-family: Verdana, Arial, Helvetica, sans-serif;} div.help { display: inline-block; margin: 0px; padding: 0px; width: 12px; height: 13px; cursor: pointer; background-image: url(data:image/gif;base64,R0lGODlhDAANAIABANR0AP///yH5BAEAAAEALAAAAAAMAA0AAAIdhI8Xy22MIFgv1DttrrJ7mlGNNo4c+aFg6SQuUAAAOw==); } div.help:hover { background-image: url(data:image/gif;base64,R0lGODlhDAANAKEAANR0AP///9R0ANR0ACH+EUNyZWF0ZWQgd2l0aCBHSU1QACH5BAEAAAIALAAAAAAMAA0AAAIdDGynCe3PgoxONntvwqz2/z2K2ImjR0KhmSIZUgAAOw==); } p.spaced { line-height: 1.8em;} span.citation { font-family: "Book Antiqua", "Palatino Linotype", serif; color: #004a4d;} p.pad { padding-left: 30px; padding-top: 5px; padding-bottom: 10px;} td.jump { font-size: 13px; color: #ffffff; background-color: #00666a; font-family: Georgia, "Times New Roman", Times, serif;} a.jump { margin: 15px 0 0; font-style: normal; font-variant: small-caps; font-weight: bolder; font-family: Georgia, "Times New Roman", Times, serif;} h2.mainh {font-size: 1.5em; font-style: normal; margin: 15px 0 0; font-variant: small-caps; font-family: Georgia, "Times New Roman", Times, serif;} h2.line {border-bottom: 1px solid #CCCCCC; font-size: 1.5em; font-style: normal; margin: 15px 0 0; padding-bottom: 3px; font-variant: small-caps; font-family: Georgia, "Times New Roman", Times, serif;} h4 {border-bottom: 1px solid #CCCCCC; font-size: 1.2em; font-style: normal; margin: 10px 0 0; padding-bottom: 3px; font-family: Georgia, "Times New Roman", Times, serif;} h5 {margin: 0px} a.help { font-size: 9px; font-style: normal; text-transform: uppercase; font-family: Georgia, "Times New Roman", Times, serif;} div.pad { padding-left: 30px; padding-top: 5px; padding-bottom: 10px;} div.pad1 { margin: 10px 5px;} div.pad2 { margin: 25px 5px 5px;} h2.pad2 { padding: 25px 5px 5px;} div.pad3 { padding: 5px 0px 10px 30px;} div.box { border: 2px solid #CCCCCC; padding:10px; overflow: hidden;} div.bar { border-left: 7px solid #00666a; padding:5px; margin-top:25px; } div.subsection {margin:25px 0px;} img {border:0px none;} th.majorth {text-align:left;} th.minorth {font-weight:normal; text-align:left; width:8em; padding: 3px 0px;} th.actionth {font-weight:normal; text-align:left;} .explain h5 {font-size:1em; margin-left: 1em;} div.doc {margin-left: 2em; margin-bottom: 3em;} th.trainingset { border-bottom: thin dashed black; font-weight:normal; padding:0px 10px; } div.pop_content { position:absolute; z-index:50; width:300px; padding: 5px; background: #E4ECEC; font-size: 12px; font-family: Arial; border-style: double; border-width: 3px; border-color: #AA2244; display:none; } div.pop_content > *:first-child { margin-top: 0px; } div.pop_content h1, div.pop_content h2, div.pop_content h3, div.pop_content h4, div.pop_content h5, div.pop_content h6, div.pop_content p { margin: 0px; } div.pop_content p + h1, div.pop_content p + h2, div.pop_content p + h3, div.pop_content p + h4, div.pop_content p + h5, div.pop_content p + h6 { margin-top: 5px; } div.pop_content p + p { margin-top: 5px; } div.pop_content > *:last-child { margin-bottom: 0px; } div.pop_content div.pop_close { /* old definition */ float:right; bottom: 0; } div.pop_content span.pop_close, div.pop_content span.pop_back { display: inline-block; border: 2px outset #661429; background-color: #CCC; padding-left: 1px; padding-right: 1px; padding-top: 0px; padding-bottom: 0px; cursor: pointer; color: #AA2244; /*#661429;*/ font-weight: bold; } div.pop_content span.pop_close:active, div.pop_content span.pop_back:active { border-style: inset; } div.pop_content span.pop_close { float:right; /*border: 2px outset #AA002B;*/ /*color: #AA2244;*/ } div.pop_content:not(.nested) .nested_only { display: none; } div.pop_back_sec { margin-bottom: 5px; } div.pop_close_sec { margin-top: 5px; } table.hide_advanced tr.advanced { display: none; } span.show_more { display: none; } table.hide_advanced span.show_more { display: inline; } table.hide_advanced span.show_less { display: none; } /***************************************************************************** * Program logo styling ****************************************************************************/ div.prog_logo { border-bottom: 0.25em solid #0f5f60; height: 4.5em; width: 24em; display:inline-block; } div.prog_logo img { float:left; width: 4em; border-style: none; margin-right: 0.2em; } div.prog_logo h1, div.prog_logo h1:hover, div.prog_logo h1:active, div.prog_logo h1:visited { margin:0; padding:0; font-family: Arial, Helvetica, sans-serif; font-size: 3.2em; line-height: 1em; vertical-align: top; display: block; color: #026666; letter-spacing: -0.06em; text-shadow: 0.04em 0.06em 0.05em #666; } div.prog_logo h2, div.prog_logo h2:hover, div.prog_logo h2:active, div.prog_logo h2:visited { display: block; margin:0; padding:0; font-family: Helvetica, sans-serif; font-size: 0.9em; line-height: 1em; letter-spacing: -0.06em; color: black; } div.big.prog_logo { font-size: 18px; } </style> <style> /* dreme output specific css */ div.header { position: relative; overflow: hidden; margin-top: 15px; margin-bottom: 5px; margin-right: 3px; margin-left: 3px; } div.header > h2 { font-size: 1.5em; font-style: normal; margin: 0; font-variant: small-caps; font-family: Georgia, "Times New Roman", Times, serif; } div.header > span { position: absolute; right: 0; bottom: 0; } div.template { position: absolute; z-index: 1; left: 0; top: 0; visibility: hidden; } div.sym_btn { display:inline-block; text-decoration: underline; cursor: pointer; font-size: 20px; line-height:20px; text-align: center; width: 20px; height: 20px; color: blue; } div.sym_btn:hover { color: white; background-color: blue; } div.sym_btn.positioned { position: absolute; top: 0px; } div.box + div.box { margin-top: 5px; } th.motif_ordinal { } td.motif_ordinal { text-align: right; padding-right: 10px; font-weight: bold; font-size: large; } th.motif_word { padding-right: 10px; } td.motif_word { font-size:15px; font-family: 'Courier New', Courier, monospace; padding-right: 10px; } th.motif_logo { padding-right: 10px; } td.motif_logo { padding-right: 10px; } th.motif_evalue { text-align:right; padding-right: 10px; } td.motif_evalue { text-align: right; white-space: nowrap; padding-right: 20px; } th.motif_more { padding: 0 5px; } td.motif_more { text-align: center; padding: 0 5px; } th.motif_submit { padding: 0 5px; } td.motif_submit { text-align: center; padding: 0 5px; } th.match_word { padding-right: 10px; } td.match_word { padding-right: 10px; font-weight: bold; font-size: large; font-family: 'Courier New', Courier, monospace; } th.match_evalue, th.match_count { text-align: right; padding-right: 10px; } td.match_evalue, td.match_count { text-align: right; white-space: nowrap; padding-right: 20px; } div.tabArea { font-size: 80%; font-weight: bold; } .norc div.tabArea { display: none; } span.tab, span.tab:visited { cursor: pointer; color: #888; background-color: #ddd; border: 2px solid #ccc; padding: 2px 1em; text-decoration: none; } span.tab.middle { border-left-width: 0px; } div.tabArea.base span.tab { border-top-width: 0px; } div.tabArea.top span.tab { border-bottom-width: 0px; } span.tab:hover { background-color: #bbb; border-color: #bbb; color: #666; } span.tab.activeTab, span.tab.activeTab:hover, span.tab.activeTab:visited { background-color: white; color: black; cursor: default; } div.tabMain { border: 2px solid #ccc; background-color: white; padding: 10px; } div.tabMain.base { margin-top: 5px; display: inline-block; max-width: 98%; } div.tabMain.top { margin-bottom: 5px; } div.grey_background { position:fixed; z-index: 8; background-color: #000; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; opacity: 0.5; left: 0; top: 0; width: 100%; height: 100%; } div.popup_wrapper { position:fixed; z-index:9; width:100%; height:0; top:50%; left:0; } div.popup { width: 600px; z-index:9; margin-left: auto; margin-right: auto; padding: 5px; background-color: #FFF; border-style: double; border-width: 5px; border-color: #00666a; position:relative; } div.close { cursor: pointer; border: 1px solid black; width:15px; height:15px; line-height:15px; /* this causes vertical centering */ text-align:center; background-color:#FFF; color:#000; font-size:15px; font-family:monospace; } div.close:hover { color:#FFF; background-color:#000; } div.navnum { width:100%; height:20px; line-height:20px; text-align:center; font-size:medium; } div.navarrow { font-size: 30px; text-decoration:none; cursor: pointer; -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; } div.navarrow > span.inactive { display: inline; } div.navarrow > span.active { display: none; } div.navarrow:hover > span.active { display: inline; } div.navarrow:hover > span.inactive { display: none; } table.programs { width: 100%; } table.programs tr { background-color: #EFE; } table.programs tr.selected { background-color: #262; color: #FFF; } table.programs tr.dna_only { display: none; } table.programs.alphabet_dna tr.dna_only { display: table-row; } table.inputs { margin-top: 20px; border-collapse:collapse; } table.inputs * td, table.inputs * th { padding-left: 15px; padding-right: 15px; padding-top: 1px; padding-bottom: 1px; } /* program settings */ span.strand_none, span.strand_given, span.strand_both { display: none; } td.none span.strand_none, td.given span.strand_given, td.both span.strand_both { display: inline; } /* show the expanded motif only when the collapsed one is hidden */ tbody *.less, tbody.collapsed *.more { display: none; } tbody.collapsed *.less { display: inline; } </style> </head> <body data-scrollpad="true"> <!-- --> <div id="grey_out_page" class="grey_background" style="display:none;"> </div> <!-- Help popups --> <div class="pop_content" id="pop_"> <p>Help poup.</p> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_motifs_word"> <p> The name of the motif uses the IUPAC codes for nucleotides which has a different letter to represent each of the 15 possible combinations. </p> <p> The name is itself a representation of the motif though the position weight matrix is not directly equalivant as it is generated from the sites found that matched the letters given in the name. </p> <p> <a id="doc_alphabets_url" href="#"> Read more about the MEME suite's use of the IUPAC alphabets. </a> <script>$("doc_alphabets_url").href = site_url + "/doc/alphabets.html";</script> </p> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_motifs_logo"> <p>The logo of the motif.</p> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_motifs_rc_logo"> <p>The logo of the reverse complement motif.</p> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_motifs_evalue"> <p>The E-value is the enrichment p-value times the number of candidate motifs tested.</p> <p>The enrichment p-value is calculated using Fisher's Exact Test for enrichment of the motif in the positive sequences.</p> <p>Note that the counts used in Fisher's Exact Test are made after erasing sites that match previously found motifs.</p> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_motifs_uevalue"> <p>The E-value of the motif calculated without erasing the sites of previously found motifs.</p> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_more"> <p>Show more information on the motif.</p> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_submit_dl"> <p>Submit your motif to another MEME Suite program or download your motif.</p> <h5>Supported Programs</h5> <dl> <dt>Tomtom</dt> <dd>Tomtom is a tool for searching for similar known motifs. </dd> <dt>MAST</dt> <dd>MAST is a tool for searching biological sequence databases for sequences that contain one or more of a group of known motifs. </dd> <dt>FIMO</dt> <dd>FIMO is a tool for searching biological sequence databases for sequences that contain one or more known motifs. </dd> <dt>GOMO</dt> <dd>GOMO is a tool for identifying possible roles (Gene Ontology terms) for DNA binding motifs. </dd> <dt>SpaMo</dt> <dd>SpaMo is a tool for inferring possible transcription factor complexes by finding motifs with enriched spacings. </dd> </dl> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_motif_positives"> <p># positive sequences matching the motif / # positive sequences.</p> <p>Note these counts are made after erasing sites that match previously found motifs.</p> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_motif_negatives"> <p># negative sequences matching the motif / # negative sequences.</p> <p>Note these counts are made after erasing sites that match previously found motifs.</p> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_motif_pvalue"> <p>The p-value of Fisher's Exact Test for enrichment of the motif in the positive sequences.</p> <p>Note that the counts used in Fisher's Exact Test are made after erasing sites that match previously found motifs.</p> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_motif_evalue"> <p>The E-value is the motif p-value times the number of candidate motifs tested.</p> <p>Note that the p-value was calculated with counts made after erasing sites that match previously found motifs.</p> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_motif_uevalue"> <p>The E-value of the motif calculated without erasing the sites of previously found motifs.</p> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_match_word"> <p>All words matching the motif whose uncorrected p-value is less than <span id="help_add_pv_thresh"></span>.</p> <script>$("help_add_pv_thresh").innerHTML = data.options.add_pv_thresh;</script> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_match_pos"> <p># positive sequences with matches to the word / # positive sequences.</p> <p>Note these counts are made after erasing sites that match previously found motifs.</p> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_match_neg"> <p># negative sequences with matches to the word / # negative sequences.</p> <p>Note these counts are made after erasing sites that match previously found motifs.</p> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_match_pval"> <p>The p-value of Fisher's Exact Test for enrichment of the word in the positive sequences.</p> <p>Note that the counts used in Fisher's Exact Test are made after erasing sites that match previously found motifs.</p> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_match_eval"> <p>The word p-value times the number of candidates tested.</p> <p>Note that the p-value was calculated with counts made after erasing sites that match previously found motifs.</p> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_seq_source"> <p>The sequence file used by DREME to find the motifs.</p> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_seq_alph"> <p>The alphabet of the sequences.</p> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_seq_count"> <p>The count of the sequences.</p> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_alph_name"> <p>The name of the alphabet symbol.</p> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_alph_control"> <p>The frequency of the alphabet symbol in the control dataset.</p> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <!-- templates --> <div class="template box expanded_motif" id="tmpl_motif_expanded"> <div> <span class="tvar_logo"></span> <span class="tvar_rclogo"></span> </div> <h4>Details</h4> <table class="details"> <thead> <tr> <th class="match_count">Positives <div class="help" data-topic="pop_motif_positives"></div></th> <th class="match_count">Negatives <div class="help" data-topic="pop_motif_negatives"></div></th> <th class="match_evalue">P-value <div class="help" data-topic="pop_motif_pvalue"></div></th> <th class="match_evalue">E-value <div class="help" data-topic="pop_motif_evalue"></div></th> <th class="match_evalue">Unerased E-value <div class="help" data-topic="pop_motif_uevalue"></div></th> </tr> </thead> <tbody> <tr> <td class="match_count"> <span class="tvar_p"></span> / <span class="tvar_p_total"></span> </td> <td class="match_count"> <span class="tvar_n"></span> / <span class="tvar_n_total"></span> </td> <td class="tvar_pvalue match_evalue"></td> <td class="tvar_evalue match_evalue"></td> <td class="tvar_uevalue match_evalue"></td> </tr> </tbody> </table> <h4>Enriched Matching Words</h4> <div class="tvar_words"></div> </div> <div class="popup_wrapper"> <div class="popup" style="display:none; top: -150px;" id="download"> <div> <div style="float:right; "> <div id="outpop_close" class="close" tabindex="0">x</div> </div> <h2 class="mainh" style="margin:0; padding:0;">Submit or Download</h2> <div style="clear:both"></div> </div> <div style="height:100px"> <div style="float:right; width: 30px;"> <div id="outpop_prev" class="navarrow" tabindex="0"> <span class="inactive">⇧</span><span class="active">⬆</span> </div> <div id="outpop_num" class="navnum"></div> <div id="outpop_next" class="navarrow" tabindex="0"> <span class="inactive">⇩</span><span class="active">⬇</span> </div> </div> <div id="logo_box" style="height: 100px; margin-right: 40px;"> <canvas id="outpop_logo" height="100" width="250"></canvas> <canvas id="outpop_logo_rc" height="100" width="250"></canvas> </div> </div> <div> <!-- tabs start --> <div class="tabArea top"> <span id="outpop_tab_1" class="tab">Submit Motif</span><span id="outpop_tab_2" class="tab middle">Download Motif</span><span id="outpop_tab_3" class="tab middle">Download Logo</span> </div> <div class="tabMain top"> <!-- Submit to another program --> <div id="outpop_pnl_1"> <h4 class="compact">Submit to program</h4> <table id="programs" class="programs"> <tr class="dna_only"> <td><input type="radio" name="program" value="tomtom" id="submit_tomtom"></td> <td><label for="submit_tomtom">Tomtom</label></td> <td><label for="submit_tomtom">Find similar motifs in published libraries or a library you supply.</label></td> </tr> <tr> <td><input type="radio" name="program" value="fimo" id="submit_fimo"></td> <td><label for="submit_fimo">FIMO</label></td> <td><label for="submit_fimo">Find motif occurrences in sequence data.</label></td> </tr> <tr> <td><input type="radio" name="program" value="mast" id="submit_mast"></td> <td><label for="submit_mast">MAST</label></td> <td><label for="submit_mast">Rank sequences by affinity to groups of motifs.</label></td> </tr> <tr class="dna_only"> <td><input type="radio" name="program" value="gomo" id="submit_gomo"></td> <td><label for="submit_gomo">GOMo</label></td> <td><label for="submit_gomo">Identify possible roles (Gene Ontology terms) for motifs.</label></td> </tr> <tr class="dna_only"> <td><input type="radio" name="program" value="spamo" id="submit_spamo"></td> <td><label for="submit_spamo">SpaMo</label></td> <td><label for="submit_spamo">Find other motifs that are enriched at specific close spacings which might imply the existance of a complex.</label></td> </tr> </table> </div> <!-- download text format --> <div id="outpop_pnl_2"> <div> <label for="text_format">Format:</label> <select id="text_format"> <option value="0">Count Matrix</option> <option value="1">Probability Matrix</option> <option value="2">Minimal MEME</option> </select> </div> <textarea id="outpop_text" name="content" style="width:99%; white-space: pre; word-wrap: normal; overflow-x: scroll;" rows="8" readonly="readonly" wrap="off"></textarea> <a id="outpop_text_dl" download="meme.txt" href=""></a> </div> <!-- download logo format --> <div id="outpop_pnl_3"> <form id="logo_form" method="post" action=""> <script>$("logo_form").action = site_url + "/utilities/generate_logo";</script> <input type="hidden" name="program" value="DREME"/> <input type="hidden" id="logo_motifs" name="motifs" value=""/> <table> <tr> <td><label for="logo_format">Format:</label></td> <td> <select id="logo_format" name="png"> <option value="1">PNG (for web)</option> <option value="0">EPS (for publication)</option> </select> </td> </tr> <tr> <td><label for="logo_rc">Orientation:</label></td> <td> <select id="logo_rc" name="rc1"> <option value="0">Normal</option> <option value="1" id="logo_rc_option">Reverse Complement</option> </select> </td> </tr> <tr> <td><label for="logo_ssc">Small Sample Correction:</label></td> <td> <input type="hidden" id="logo_err" name="errbars" value="0"/> <select id="logo_ssc" name="ssc"> <option value="0">Off</option> <option value="1">On</option> </select> </td> </tr> <tr> <td><label for="logo_width">Width:</label></td> <td> <input type="text" id="logo_width" size="4" placeholder="default" name="width"/> cm </td> </tr> <tr> <td><label for="logo_height">Height:</label></td> <td> <input type="text" id="logo_height" size="4" placeholder="default" name="height"/> cm </td> </tr> </table> </form> </div> <!-- Buttons --> <div> <div style="float:left;"> <input type="button" id="outpop_do" value="Submit" /> </div> <div style="float:right;"> <input id="outpop_cancel" type="button" value="Cancel" /> </div> <div style="clear:both;"></div> </div> </div> </div> </div> </div> <!-- Page starts here --> <div id="top" class="pad1"> <div class="prog_logo big"> <img src="data:image/png;base64,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" alt="DREME Logo"/> <h1>DREME</h1> <h2>Discriminative Regular Expression Motif Elicitation</h2> </div> <p class="spaced"> For further information on how to interpret these results or to get a copy of the MEME software please access <a href="http://meme.nbcr.net/">http://meme.nbcr.net</a>. </p> <p> If you use DREME in your research please cite the following paper:<br /> <span class="citation"> Timothy L. Bailey, "DREME: Motif discovery in transcription factor ChIP-seq data", <i>Bioinformatics</i>, <b>27</b>(12):1653-1659, 2011. <a href="http://bioinformatics.oxfordjournals.org/content/27/12/1653">[full text]</a> </span> </p> </div> <!-- navigation --> <div class="pad2"> <a class="jump" href="#motifs_sec">Discovered Motifs</a> | <a class="jump" href="#inputs_sec">Inputs & Settings</a> | <a class="jump" href="#info_sec">Program information</a> </div> <!-- alert the user when their browser is not up to the task --> <noscript><h1 style="color:red">Javascript is required to view these results!</h1></noscript> <h1 id="html5_warning" style="color:red; display:none;">Your browser does not support canvas!</h1> <script> if (!window.HTMLCanvasElement) $("html5_warning").style.display = "block"; </script> <!-- description --> <div id="description_section" style="display:none"> <div id="description" class="header"> <h2>Description</h2> </div> <div id="description_text" class="box"> </div> </div> <script> if (data.description) { $("description_text").innerHTML = ""; $("description_text").appendChild(make_description(data.description)); $("description_section").style.display = "block"; } </script> <!-- motifs --> <div id="motifs_sec" class="header"> <h2>Discovered Motifs</h2> <span><a href="#inputs_sec">Next</a> <a href="#">Top</a></span> </div> <div id="motifs" class="box"> <p>No motifs were discovered!</p> </div> <script>make_motifs();</script> <!-- inputs and settings --> <div id="inputs_sec" class="header"> <h2>Inputs & Settings</h2> <span><a href="#motifs_sec">Previous</a> <a href="#info_sec">Next</a> <a href="#">Top</a></span> </div> <div class="box"> <h4>Sequences</h4> <table id="seq_info" class="inputs"> <tr><th>Source <div class="help" data-topic="pop_seq_source"></div></th> <th>Alphabet <div class="help" data-topic="pop_seq_alph"></div></th> <th>Sequence Count <div class="help" data-topic="pop_seq_count"></div></th> </tr> <tr> <td id="ins_seq_source"></td> <td id="ins_seq_alphabet"></td> <td id="ins_seq_count"></td> </tr> </table> <script> { var db = data.sequence_db; $("ins_seq_source").innerHTML = db.file; $("ins_seq_alphabet").innerHTML = dreme_alphabet.get_alphabet_name(); $("ins_seq_count").innerHTML = db.count; } </script> <h4>Control Sequences</h4> <table id="seq_info" class="inputs"> <tr><th>Source <div class="help" data-topic="pop_seq_source"></div></th> <th>Sequence Count <div class="help" data-topic="pop_seq_count"></div></th> </tr> <tr> <td id="ins_cseq_source"></td> <td id="ins_cseq_count"></td> </tr> </table> <script> { var db = data.control_db; if (db.from == "shuffled") { $("ins_cseq_source").innerHTML = "Shuffled Sequences"; } else { $("ins_cseq_source").innerHTML = db.file; } $("ins_cseq_count").innerHTML = db.count; } </script> <h4>Background</h4> <span id="alpha_bg"></span> <script> { $("alpha_bg").appendChild(make_alpha_bg(dreme_alphabet, data.control_db.freqs)); } </script> <h4>Other Settings</h4> <table id="tbl_settings" class="inputs hide_advanced"> <tr> <th>Strand Handling</th> <td id="opt_strand"> <span class="strand_none">This alphabet only has one strand</span> <span class="strand_given">Only the given strand is processed</span> <span class="strand_both">Both the given and reverse complement strands are processed</span> </td> </tr> <tr><th># REs to Generalize</th><td id="opt_ngen"></td></tr> <tr><th>Shuffle Seed</th><td id="opt_seed"></td></tr> <tr><th>E-value Threshold</th><td id="opt_stop_evalue"></td></tr> <tr><th>Max Motif Count</th><td id="opt_stop_count"></td></tr> <tr><th>Max Run Time</th><td id="opt_stop_time"></td></tr> </table> <script> { $("opt_strand").className = (dreme_alphabet.has_complement() ? (data.options.revcomp ? "both" : "given") : "none"); $("opt_ngen").innerHTML = data.options.ngen; $("opt_seed").innerHTML = data.options.seed; $("opt_stop_evalue").innerHTML = data.options.stop.evalue; $("opt_stop_count").innerHTML = (typeof data.options.stop.count == "number" ? data.options.stop.count : "No maximum motif count."); $("opt_stop_time").innerHTML = (typeof data.options.stop.time == "number" ? data.options.stop.time + " seconds." : "No maximum running time."); } </script> </div> <!-- list information on this program --> <div id="info_sec" class="bar" style="position:relative"> <div style="position: absolute; right: 0;"><a href="#inputs_sec">Previous</a> <a href="#">Top</a></div> <div class="subsection"> <h5 id="version">DREME version</h5> <span id="ins_version"></span> (Release date: <span id="ins_release"></span>)<br> </div> <script> $("ins_version").innerHTML = data["version"]; $("ins_release").innerHTML = data["release"]; </script> <div class="subsection"> <h5 id="reference">Reference</h5> <span class="citation"> Timothy L. Bailey, "DREME: Motif discovery in transcription factor ChIP-seq data", <i>Bioinformatics</i>, <b>27</b>(12):1653-1659, 2011. <a href="http://bioinformatics.oxfordjournals.org/content/27/12/1653">[full text]</a> </span> </div> <div class="subsection"> <h5 id="command">Command line</h5> <textarea id="cmd" rows="3" style="width:100%;" readonly="readonly"> </textarea> <script>$("cmd").value = data["cmd"].join(" ");</script> </div> </div> </body> </html>