Mercurial > repos > iuc > meme_psp_gen
view test-data/meme_output_test2.html @ 8:8436beac5eed draft default tip
planemo upload for repository https://github.com/galaxyproject/tools-iuc/tree/master/tools/meme commit 89ee0af6e955ff964b7984d77ad536e0a9154278
author | iuc |
---|---|
date | Mon, 14 Jul 2025 21:32:53 +0000 |
parents | 5f95d385a33c |
children |
line wrap: on
line source
* 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 available 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("Cannot refine a help popup when one is not shown!"); var pop = lookup_help_popup(popup_id); var act_id = popup_id + '_act'; var activator = document.getElementById(act_id); help_popup(activator, popup_id); } 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, is_new) { var th = document.createElement("th"); if (node) th.appendChild(node); if (help_topic && help_topic !== "") th.appendChild(help_button(help_topic)); if (is_new && is_new !== "") { var br = document.createElement("span"); br.innerHTML = "<br>"; th.appendChild(br); var new_icon = document.createElement("img"); new_icon.src = new_icon_src; new_icon.alt = "NEW"; th.appendChild(new_icon); } 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, is_new) { 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, is_new); } 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; } // // Function to create an HTML paragraph describing the // MEME Suite background model source. // function make_background_source(title, source, text) { var paraNode = document.createElement("P"); var titleNode = document.createElement("B"); var textNode1 = document.createTextNode("\u00A0\u00A0\u00A0\u00A0" + title + ": "); titleNode.appendChild(textNode1); var source_text = ((source == "--motif--") ? "the (first) motif file" : (source == "--nrdb--") ? "an old version of the NCBI non-redundant database" : (source == "--uniform--") ? "the uniform model" : (source == "--query--") ? "the query file" : (source == "--sequences--") ? "built from the (primary) sequences" : (source == "--control--") ? "built from the control (negative) sequences" : ((source == "--negatives--") ? "built from the negative (control) sequences" : "the file '" + source + "'")); if (text) { return source_text; } var textNode2 = document.createTextNode(source_text); paraNode.appendChild(titleNode); paraNode.appendChild(textNode2); return paraNode; } // Function to create a help button function make_help_button(container, help_topic) { container.appendChild(help_button(help_topic)); } // Function to toggle display. function change_display(id) { var element=document.getElementById(id); element.style.display=(element.style.display=='none') ? element.style.display='inline' : element.style.display='none'; } </script> <script> // // return true if any part of the passed element is visible in the viewport // function element_in_viewport(elem) { var rect; try { rect = elem.getBoundingClientRect(); } catch (e) { return false; } return ( rect.top < (window.innerHeight || document.body.clientHeight) && rect.bottom > 0 && rect.left < (window.innerWidth || document.body.clientWidth) && rect.right > 0 ); } // // Functions to delay a drawing task until it is required or it would not lag the display to do so // // a list of items still to be drawn var drawable_list = []; // the delay between drawing objects that are not currently visible var draw_delay = 1; // the delay after a user interaction var user_delay = 300; // the delay after a user has stopped scrolling and is viewing the stuff drawn on the current page var stop_delay = 300; // the timer handle; allows resetting of the timer after user interactions var draw_timer = null; // // Drawable // // elem - a page element which defines the position on the page that drawing is to be done // task - an object with the method run which takes care of painting the object // var Drawable = function(elem, task) { this.elem = elem; this.task = task; } // // Drawable.is_visible // // Determines if the element is visible in the viewport // Drawable.prototype.is_visible = function() { return element_in_viewport(this.elem); } // // Drawable.run // // Run the task held by the drawable Drawable.prototype.run = function() { if (this.task) this.task.run(); this.task = null; } // // Drawable.run // // Run the task iff visible // returns true if the task ran or has already run Drawable.prototype.run_visible = function() { if (this.task) { if (element_in_viewport(this.elem)) { this.task.run(); this.task = null; return true; } return false; } else { return true; } } // // draw_on_screen // // Checks each drawable object and draws those on screen. // function draw_on_screen() { var found = false; for (var i = 0; i < drawable_list.length; i++) { if (drawable_list[i].run_visible()) { drawable_list.splice(i--, 1); found = true; } } return found; } // // process_draw_tasks // // Called on a delay to process the next available // draw task. // function process_draw_tasks() { var delay = draw_delay; draw_timer = null; if (drawable_list.length == 0) return; //no more tasks if (draw_on_screen()) { delay = stop_delay; //give the user a chance to scroll } else { //get next task var drawable = drawable_list.shift(); drawable.task.run(); } //allow UI updates between tasks draw_timer = window.setTimeout("process_draw_tasks()", delay); } // // delayed_process_draw_tasks // // Call process_draw_tasks after a short delay. // The delay serves to group multiple redundant events. // Should be set as event handler for onscroll and onresize. // function delayed_process_draw_tasks() { //reset the timer if (drawable_list.length > 0) { if (draw_timer != null) clearTimeout(draw_timer); draw_timer = window.setTimeout("process_draw_tasks()", user_delay); } } // // add_draw_task // // Add a drawing task to be called immediately if it is // visible, or to be called on a delay to reduce stuttering // effect on the web browser. function add_draw_task(elem, task) { drawable = new Drawable(elem, task); if (drawable.is_visible()) { task.run(); } else { drawable_list.push(drawable); //reset timer if (draw_timer != null) clearTimeout(draw_timer); draw_timer = window.setTimeout("process_draw_tasks()", user_delay); } } </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 ambiguous 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 components 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, pgm) { "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 = []; this.pgm = matrix.pgm; 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; this.pgm = pgm; 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 + (this.pgm === "STREME" ? " P= " : " 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); } /* * Specifies 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); } // // Delay drawing a logo // var DelayLogoTask = function(logo, canvas) { "use strict"; canvas.width = canvas.width; // clear canvas this.logo = logo; this.canvas = canvas; }; DelayLogoTask.prototype.run = function () { "use strict"; this.canvas.width = this.canvas.width; // clear canvas draw_logo_on_canvas(this.logo, this.canvas, false); }; /* * Make a canvas with the motif logo drawn on it. */ function make_logo(alphabet, pspm, height, rc, offset, className) { if (rc) pspm = pspm.copy().reverse_complement(alphabet); var logo = new Logo(alphabet); logo.add_pspm(pspm, offset); var canvas = document.createElement('canvas'); var sizeit = (height < 0); canvas.height = (sizeit ? -height : height); canvas.width = 0; canvas.className = className; if (sizeit) size_logo_on_canvas(logo, canvas, false); add_draw_task(canvas, new DelayLogoTask(logo, canvas)); return canvas; } </script> <script> // PRIVATE GLOBAL (uhoh) var _block_colour_lookup = {}; function block_colour(index) { function hsl2rgb(hue, saturation, lightness) { "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; } } function _pad_hex(value) { var hex = Math.round(value * 255).toString(16); if (hex.length < 2) hex = "0" + hex; return hex; } var r, g, b, p, q; if (saturation == 0) { // achromatic (grayscale) r = lightness; g = lightness; b = lightness; } else { if (lightness < 0.5) { q = lightness * (1 + saturation); } else { q = lightness + saturation - (lightness * saturation); } p = (2 * lightness) - q; r = _hue(p, q, hue + (1.0 / 3.0)); g = _hue(p, q, hue); b = _hue(p, q, hue - (1.0 / 3.0)); } return "#" + _pad_hex(r) + _pad_hex(g) + _pad_hex(b); } if (typeof index !== "number" || index % 1 !== 0 || index < 0) return "#000000"; // check for override if (_block_colour_lookup[index] == null) { var start = 0; //red var sat = 100; var light = 50; var divisions = 1 << Math.ceil(Math.log(index + 1) / Math.LN2); hue = start + (360 / divisions) * ((index - (divisions >> 1)) * 2 + 1); // colour input fields only support values in the form #RRGGBB _block_colour_lookup[index] = hsl2rgb(hue / 360, sat / 100, light / 100); } return _block_colour_lookup[index]; } function set_block_colour(index, new_colour) { _block_colour_lookup[index] = new_colour; var blocks = document.querySelectorAll("div.block_motif[data-colour-index=\"" + index + "\"]"); var i; for (i = 0; i < blocks.length; i++) { blocks[i].style.backgroundColor = new_colour; } var swatches = document.querySelectorAll("div.legend_swatch[data-colour-index=\"" + index + "\"]"); var picker; for (i = 0; i < swatches.length; i++) { swatches[i].style.backgroundColor = new_colour; picker = swatches[i].querySelector("input[type=\"color\"]"); if (picker != null) picker.value = new_colour; } } function make_block_legend_entry(motif_name, motif_colour_index) { if (typeof make_block_legend_entry.has_colour_picker !== "boolean") { // test if colour picker is supported, based off Modernizer // see http://stackoverflow.com/a/7787648/66387 make_block_legend_entry.has_colour_picker = (function() { var doc_ele = document.documentElement; // We first check to see if the type we give it sticks.. var input_ele = document.createElement('input'); input_ele.setAttribute('type', 'color'); var value_ok = input_ele.type !== 'text'; if (value_ok) { // If the type does, we feed it a textual value, which shouldn't be valid. // If the value doesn't stick, we know there's input sanitization which infers a custom UI var smile = ':)'; input_ele.value = smile; input_ele.style.cssText = 'position:absolute;visibility:hidden;'; // chuck into DOM and force reflow for Opera bug in 11.00 // github.com/Modernizr/Modernizr/issues#issue/159 doc_ele.appendChild(input_ele); doc_ele.offsetWidth; value_ok = input_ele.value != smile; doc_ele.removeChild(input_ele); } return value_ok; })(); } var entry = document.createElement("div"); entry.className = "legend_entry"; var swatch; swatch = document.createElement("div"); swatch.className = "legend_swatch"; swatch.setAttribute("data-colour-index", motif_colour_index); swatch.style.backgroundColor = block_colour(motif_colour_index); if (make_block_legend_entry.has_colour_picker) { var picker = document.createElement("input"); picker.type = "color"; picker.value = block_colour(motif_colour_index); picker.addEventListener("change", function(e) { set_block_colour(motif_colour_index, picker.value); }, false); swatch.addEventListener("click", function(e) { picker.click(); }, false); swatch.appendChild(picker); } entry.appendChild(swatch); var name = document.createElement("div"); name.className = "legend_text"; name.appendChild(document.createTextNode(motif_name)); entry.appendChild(name); return entry; } function make_block_ruler(max_len) { var container = document.createElement("div"); container.className = "block_container"; var step; if (max_len < 50) { step = 1; } else if (max_len < 100) { step = 2; } else if (max_len < 200) { step = 4; } else if (max_len < 500) { step = 10; } else if (max_len < 1000) { step = 20; } else if (max_len < 2000) { step = 40; } else if (max_len < 5000) { step = 100; } else if (max_len < 10000) { step = 200; } else if (max_len < 20000) { step = 400; } else { step = Math.floor(max_len / 20000) * 400; } var peroid; if (max_len < 10) { peroid = 1; } else if (max_len < 20) { peroid = 2; } else { peroid = 5; } var i, cycle, offset, tic, label; for (i = 0, cycle = 0; i < max_len; i += step, cycle = (cycle + 1) % peroid) { offset = "" + ((i / max_len) * 100) + "%"; tic = document.createElement("div"); tic.style.left = offset; tic.className = (cycle == 0 ? "tic_major" : "tic_minor"); container.appendChild(tic); if (cycle == 0) { label = document.createElement("div"); label.className = "tic_label"; label.style.left = offset; label.appendChild(document.createTextNode(i)); container.appendChild(label); } } return container; } function _calculate_block_needle_drag_pos(e, data) { var mouse; e = e || window.event; if (e.pageX || ev.pageY) { mouse = {"x": e.pageX, "y": e.pageY}; } else { mouse = { x:e.clientX + document.body.scrollLeft - document.body.clientLeft, y:e.clientY + document.body.scrollTop - document.body.clientTop }; } var cont = data.container; var dragable_length = cont.clientWidth - (cont.style.paddingLeft ? cont.style.paddingLeft : 0) - (cont.style.paddingRight ? cont.style.paddingRight : 0); //I believe that the offset parent is the body //otherwise I would need to make this recursive //maybe clientLeft would work, but the explanation of //it is hard to understand and it apparently doesn't work //in firefox 2. var diff = mouse.x - cont.offsetLeft; if (diff < 0) diff = 0; if (diff > dragable_length) diff = dragable_length; var pos = Math.round(diff / dragable_length * data.max); if (pos > data.len) pos = data.len; return pos; } function _update_block_needle_drag(e, data, done) { "use strict"; var pos = _calculate_block_needle_drag_pos(e, data); // read the needle positions var left = parseInt(data.llabel.textContent, 10) - data.off - 1; var right = parseInt(data.rlabel.textContent, 10) - data.off; // validate needle positions if (left >= data.len) left = data.len - 1; if (left < 0) left = 0; if (right > data.len) right = data.len; if (right <= left) right = left + 1; // calculate the new needle positions if (data.moveboth) { var size = right - left; if (data.isleft) { if ((pos + size) > data.len) pos = data.len - size; left = pos; right = pos + size; } else { if ((pos - size) < 0) pos = size; left = pos - size; right = pos; } } else { if (data.isleft) { if (pos >= right) pos = right - 1; left = pos; } else { if (pos <= left) pos = left + 1; right = pos; } } // update the needle positions data.lneedle.style.left = "" + (left / data.max * 100) + "%"; data.llabel.textContent = "" + (left + data.off + 1); data.rneedle.style.left = "" + (right / data.max * 100) + "%"; data.rlabel.textContent = "" + (right + data.off); data.handler(left, right, done); } function _make_block_needle_drag_start_handler(isleft, data) { return function (e) { data.isleft = isleft; data.moveboth = !(e.shiftKey); document.addEventListener("mousemove", data.drag_during, false); document.addEventListener("mouseup", data.drag_end, false); }; } function _make_block_needle_drag_end_handler(data) { return function (e) { document.removeEventListener("mousemove", data.drag_during, false); document.removeEventListener("mouseup", data.drag_end, false); _update_block_needle_drag(e, data, true); }; } function _make_block_needle_drag_during_handler(data) { return function (e) { _update_block_needle_drag(e, data, false); }; } // private function used by make_block_container function _make_block_needle(isleft, value, data) { var vbar = document.createElement('div'); vbar.className = "block_needle " + (isleft ? "left" : "right"); vbar.style.left = "" + (value / data.max * 100)+ "%"; var label = document.createElement('div'); label.className = "block_handle " + (isleft ? "left" : "right"); // The needles sit between the sequence positions, so the left one sits at the // start and the right at the end. This is why 1 is added to the displayed // value for a left handle as the user doesn't need to know about this detail label.textContent = "" + (isleft ? value + data.off + 1 : value + data.off); label.unselectable = "on"; // so IE and Opera don't select the text, others are done in css label.title = "Drag to move the displayed range. Hold shift and drag to change " + (isleft ? "lower" : "upper") + " bound of the range."; vbar.appendChild(label); if (isleft) { data.lneedle = vbar; data.llabel = label; } else { data.rneedle = vbar; data.rlabel = label; } label.addEventListener("mousedown", _make_block_needle_drag_start_handler(isleft, data), false); return vbar; } function make_block_container(is_stranded, has_both_strands, max_len, show_len, offset, range_handler) { offset = (offset != null ? offset : 0); // make the container for the block diagram var container = document.createElement("div"); container.className = "block_container"; container.setAttribute("data-max", max_len); container.setAttribute("data-off", offset); if (is_stranded) { var plus = document.createElement("div"); plus.appendChild(document.createTextNode("+")); plus.className = "block_plus_sym"; container.appendChild(plus); if (has_both_strands) { var minus = document.createElement("div"); minus.appendChild(document.createTextNode("-")); minus.className = "block_minus_sym"; container.appendChild(minus); } } var rule = document.createElement("div"); rule.className = "block_rule"; rule.style.width = ((show_len / max_len) * 100) + "%"; container.appendChild(rule); if (range_handler != null) { var range_data = { "max": max_len, "len": show_len, "off": offset, "handler": range_handler, "container": container, "lneedle": null, "llabel": null, "rneedle": null, "rlabel": null, "isleft": false, "moveboth" : false }; range_data.drag_during = _make_block_needle_drag_during_handler(range_data); range_data.drag_end = _make_block_needle_drag_end_handler(range_data); container.appendChild(_make_block_needle(false, 1, range_data)); // add right first so z-index works container.appendChild(_make_block_needle(true, 0, range_data)); } return container; } function make_block_label(container, max_len, pos, length, message) { "use strict"; var label = document.createElement("div"); label.className = "block_label"; label.style.left = (((pos + (length / 2)) / max_len) * 100) + "%"; label.appendChild(document.createTextNode(message)); container.appendChild(label); } function make_block(container, max_len, site_pos, site_len, site_pvalue, site_rc, site_colour_index, site_secondary) { "use strict"; var block_height, block, block_region1, block_region2; var max_block_height = 12; var max_pvalue = 1e-10; // calculate the height of the block block_height = (site_pvalue < max_pvalue ? max_block_height : (Math.log(site_pvalue) / Math.log(max_pvalue)) * max_block_height); if (block_height < 1) block_height = 1; // create a block to represent the motif block = document.createElement("div"); block.className = "block_motif" + (site_secondary ? " scanned_site" : "") + (site_rc ? " bottom" : " top"); block.style.left = ((site_pos / max_len) * 100) + "%"; block.style.top = (!site_rc ? max_block_height - block_height : max_block_height + 1) + "px"; block.style.width = ((site_len / max_len) * 100) + "%"; block.style.height = block_height + "px"; block.style.backgroundColor = block_colour(site_colour_index); block.setAttribute("data-colour-index", site_colour_index); // add to container container.appendChild(block); var activator = function (e) { toggle_class(block, "active", true); var new_e = new e.constructor(e.type, e); block.dispatchEvent(new_e); }; var deactivator = function (e) { toggle_class(block, "active", false); var new_e = new e.constructor(e.type, e); block.dispatchEvent(new_e); } // create a larger region to detect mouseover for the block block_region1 = document.createElement("div"); block_region1.className = "block_region top" + (site_secondary ? " scanned_site" : "") + (site_rc ? "" : " main"); block_region1.style.left = block.style.left; block_region1.style.width = block.style.width; block_region1.addEventListener('mouseover', activator, false); block_region1.addEventListener('mouseout', deactivator, false); container.appendChild(block_region1); block_region2 = document.createElement("div"); block_region2.className = "block_region bottom" + (site_secondary ? " scanned_site" : "") + (site_rc ? " main" : ""); block_region2.style.left = block.style.left; block_region2.style.width = block.style.width; block_region2.addEventListener('mouseover', activator, false); block_region2.addEventListener('mouseout', deactivator, false); container.appendChild(block_region2); return block; } function set_block_needle_positions(containingNode, start, end) { var container, lneedle, llabel, rneedle, rlabel, max, off, left, right; container = (/\bblock_container\b/.test(containingNode.className) ? containingNode : containingNode.querySelector(".block_container")); max = parseInt(container.getAttribute("data-max"), 10); off = parseInt(container.getAttribute("data-off"), 10); left = start - off; right = end - off; lneedle = containingNode.querySelector(".block_needle.left"); llabel = lneedle.querySelector(".block_handle.left"); rneedle = containingNode.querySelector(".block_needle.right"); rlabel = rneedle.querySelector(".block_handle.right"); // update the needle positions lneedle.style.left = "" + (left / max * 100) + "%"; llabel.textContent = "" + (left + off + 1); rneedle.style.left = "" + (right / max * 100) + "%"; rlabel.textContent = "" + (right + off); } function get_block_needle_positions(containingNode) { var container, llabel, rlabel, max, off, left, right; container = (/\bblock_container\b/.test(containingNode.className) ? containingNode : containingNode.querySelector(".block_container")); max = parseInt(container.getAttribute("data-max"), 10); off = parseInt(container.getAttribute("data-off"), 10); llabel = containingNode.querySelector(".block_needle.left > .block_handle.left"); rlabel = containingNode.querySelector(".block_needle.right > .block_handle.right"); left = parseInt(llabel.textContent, 10) - off - 1; right = parseInt(rlabel.textContent, 10) - off; return {"start": left + off, "end": right + off}; } </script> <script> function make_alpha_bg_table(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 = "alpha_bg_table"; // 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"); if (freqs != null) add_text_header_cell(row, "Freq.", "pop_alph_freq"); if (alph.has_bg()) add_text_header_cell(row, "Bg.", "pop_alph_bg"); add_text_header_cell(row, ""); add_text_header_cell(row, ""); add_text_header_cell(row, ""); if (alph.has_bg()) add_text_header_cell(row, "Bg.", "pop_alph_bg"); if (freqs != null) add_text_header_cell(row, "Freq.", "pop_alph_freq"); add_text_header_cell(row, "Name", "pop_alph_name"); } else { add_text_header_cell(row, ""); add_text_header_cell(row, "Name", "pop_alph_name"); if (freqs != null) add_text_header_cell(row, "Freq.", "pop_alph_freq"); if (alph.has_bg()) add_text_header_cell(row, "Bg.", "pop_alph_bg"); } // 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)); if (freqs != null) add_text_cell(row, "" + freqs[i]); if (alph.has_bg()) add_text_cell(row, "" + alph.get_bg_freq(i)); add_cell(row, colour_symbol(i)); add_text_cell(row, "~"); add_cell(row, colour_symbol(c)); if (alph.has_bg()) add_text_cell(row, "" + alph.get_bg_freq(c)); if (freqs != null) add_text_cell(row, "" + freqs[c]); 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)); if (freqs != null) add_text_cell(row, "" + freqs[i]); if (alph.has_bg()) add_text_cell(row, "" + alph.get_bg_freq(i)); } } return table; } </script> <script> // // simple-shared-doc.js // // // Function to redirect to appropriate doc file. // function get_doc_text(pgm, doc_type, extra, extra2) { switch (pgm) { case 'shared': return(get_shared_doc_text(doc_type, extra, extra2)); case 'ame': return(get_ame_doc_text(doc_type, extra, extra2)); case 'centrimo': return(get_centrimo_doc_text(doc_type, extra, extra2)); case 'discovery': return(get_discovery_doc_text(doc_type, extra, extra2)); case 'fimo': return(get_fimo_doc_text(doc_type, extra, extra2)); case 'gomo': return(get_gomo_doc_text(doc_type, extra, extra2)); case 'mcast': return(get_mcast_doc_text(doc_type, extra, extra2)); case 'meme-chip': return(get_meme_chip_doc_text(doc_type, extra, extra2)); case 'momo': return(get_momo_doc_text(doc_type, extra, extra2)); case 'sea': return(get_sea_doc_text(doc_type, extra, extra2)); case 'spamo': return(get_spamo_doc_text(doc_type, extra, extra2)); case 'streme': return(get_streme_doc_text(doc_type, extra, extra2)); case 'tgene': return(get_tgene_doc_text(doc_type, extra, extra2)); case 'tomtom': return(get_tomtom_doc_text(doc_type, extra, extra2)); case 'xstreme': return(get_xstreme_doc_text(doc_type, extra, extra2)); default: return("<b>Unknown program type: <font color=red>" + pgm + "</font></b>"); } } // get_doc_text // // Function to replace the innerHTML of element "id" with the HTML indicated by "doc_type". // Easier to read and update than the more flexible approach in shared-doc.js. // function print_doc(id, pgm, doc_type, extra) { document.getElementById(id).insertAdjacentHTML('beforeend', get_doc_text(pgm, doc_type, extra)); } // print_doc // // Function to replace the innerHTML of element "id" with an HTML paragraph // containing the text for 'pgm' and 'doc_type'. // This function can be used in help pop-ups. // function print_doc_para(id, pgm, doc_type, extra, extra2) { html = "<p>" + get_doc_text(pgm, doc_type, extra, extra2) + "</p>"; document.getElementById(id).insertAdjacentHTML('beforeend', html); } // print_doc_para // // Function to return the Shared HTML text of a given type. // This function can be used directly to document the output format (xx-output-format.html) // and indirectly via print_doc_para for help pop-ups in the actual output HTML, // to prevent duplication of documentation. // function get_shared_doc_text(doc_type, extra, extra2) { if (extra == undefined) {extra = ""}; if (extra2 == undefined) {extra2 = ""}; switch (doc_type) { case 'fasta-coordinates-name': return(` The sequence IDs in the FASTA header lines are used as the source of sequence names. The sequence ID is the string following the initial '>' up to the first white space character. If the sequence ID is in an accepted <a href="` + site_url + `/doc/fasta-coordinates-format.html">FASTA Coordinates Format</a> (e.g., UCSC or Galaxy format), and you did NOT specify the <code>` + extra + `-no-pgc</code> option, then the coordinates are removed from the sequence ID to create the sequence name. `); case 'fasta-coordinates-brief': return(` The sequence IDs in the FASTA header lines are used as the source of sequence names. The sequence ID is the string following the initial '>' up to the first white space character. If the sequence ID is in an accepted <a href="` + site_url + `/doc/fasta-coordinates-format.html">FASTA Coordinates Format</a> (e.g., UCSC or Galaxy format), and you did NOT specify the <code>` + extra + `-no-pgc</code> option, then the coordinates are removed from the sequence ID to create the sequence name, and the starting coordinate given in the sequence ID will be used as the coordinate of the first position of the sequence. Otherwise, the coordinate of the first position of the sequence is taken as 1 and the entire sequence ID is used as the sequence name. `); case 'fasta-coordinates': return(` For sequence coordinates embedded in FASTA sequence headers to be parsed correctly by MEME Suite programs, the sequence ID in the FASTA header should have one of the two following formats: <h4>UCSC Format</h4> <div style='margin: 5px 0'> ><span class='pdat'>sequence name</span>:<span class='pdat' >starting position</span>-<span class='pdat'>ending position</span> </div> where <ul style='margin-top: 0; margin-bottom: 5px'> <li><span class='pdat'>sequence name</span> is the name of the genomic sequence,</li> <li><span class='pdat'>starting position</span> is the genomic position of the first base and</li> <li><span class='pdat'>ending position</span> is the genomic position of the final base.</li> </ul> <b>Example:</b> <span class="pdata">chr1:156887119-156887619</span> <h4>Galaxy Format</h4> <div style='margin: 5px 0'> ><span class='pdat'>assembly name</span>_<span class='pdat' >sequence name</span>_<span class='pdat' >starting position</span>_<span class='pdat' >ending position</span>_<span class='pdat' >strand</span> </div> where <ul style='margin-top: 0; margin-bottom: 5px'> <li><span class='pdat'>assembly name</span> is the name of the genomic assembly,</li> <li><span class='pdat'>sequence name</span> is the name of the genomic sequence,</li> <li><span class='pdat'>starting position</span> is the genomic position of the first base and</li> <li><span class='pdat'>ending position</span> is the genomic position of the final base.</li> </ul> <b>Example:</b> <span class="pdata">>mm9_chr18_75759530_7575972_-</span> <p> For both formats, the following rules also apply: <ul> <li>The the coordinates are 1-start, fully-closed. This means that the first base of the chromosome is position "1", and the bases at the first and last positions of the given range are included.</li> <li>The <span class='pdat'>sequence name</span> may not contain any white space.</li> <li>The <span class='pdat'>assembly name</span> is not optional.</li> <li>The <span class='pdat'>strand</span> is ignored.</li> <li>When no valid genomic coordinates are found in a FASTA sequence header, the starting position of the sequence is taken to be position 1.</li> </ul> </p> `); case 'motif-db': return(` The name of ` + extra2 + ` a file of motifs ("motif database file") that contains ` + extra + ` `); case 'motif-id': return(` The name of the ` + extra + ` motif, which is unique ` + extra2 + ` in the motif database file. `); case 'motif-alt-id': return(` An alternate name for the ` + extra + ` motif that may be provided ` + extra2 + ` in the motif database file. `); case 'motif-width': return(` The width of the motif. No gaps are allowed in motifs supplied to ` + extra + ` as it only works for motifs of a fixed width. `); case 'motif-cons': return(` A consensus sequence computed from the ` + extra + ` motif (as described <a href="#consensus_doc">below</a>). `); case 'motif-match-score': return(` ` + extra2 + ` The motif match score of a position in a sequence is computed by summing the appropriate entry from each column of the position-dependent scoring matrix that represents the motif. ` + extra + ` `); case 'motif-match-p-value': return(` The <i>p</i>-value of a motif match is the probability of a single random subsequence of the length of the motif <a href="javascript:help_refine('pop_motif_match_score')">scoring</a> at least as well as the observed match. `); case 'bh-q-value': if (extra2 == "") extra2 = "match"; return(` The q-value is the minimum False Discovery Rate (FDR) required to consider this ` + extra2 + ` significant.</br>` + get_shared_doc_text('bh-q-value-method', extra, extra2) + ` `); case 'bh-q-value-method': return(` <br>` + extra + ` estimates q-values from all the ` + extra2 + ` <i>p</i>-values using the method proposed by Benjamini & Hochberg (<i>Journal of the Royal Statistical Society B</i>, 57:289-300, 1995). See also Storey JD, Tibshirani R. Statistical significance for genome-wide studies, <i>Proc. Natl. Acad. Sci. USA</i> (2003) <b>100</b>:9440–9445. `); case 'sdb-name': return(` The name of the (FASTA) sequence database file. `); case 'sdb-psp': return(` The name of the position specific priors (PSP) file. `); case 'sdb-dist': return(` The name of the binned distribution of priors file. `); case 'sdb-count': return(` The number of sequences in the database. `); case 'sdb-letters': return(` The number of letters in the sequence database. `); case 'lastmod': return(` The date of the last modification to the ` + extra + ` database. `); case 'sequence-id': return(` The identifier of the sequence (from the FASTA sequence header line)` + extra + ` `); case 'sequence-desc': return(` The description appearing after the identifier of the sequence in the FASTA header line. `); case 'alph-name': return(` The name of the alphabet symbol. `); case 'alph-bg': return(` The frequency of the alphabet symbol as defined by the background model. `); case 'match-start': return(` The start position of the ` + extra + `. `); case 'match-stop': return(` The end position of the ` + extra + `. `); case 'match-start-seq': return(` The start position of the ` + extra + `; 1-based sequence coordinates. `); case 'match-stop-seq': return(` The end position of the ` + extra + `; 1-based sequence coordinates. `); case 'match-start-genomic': return(` The start position of the ` + extra + `; genomic coordinates. `); case 'match-stop-genomic': return(` The end position of the ` + extra + `; genomic coordinates. `); case 'motif-consensus': return(` <p id="consensus_doc"> A <b>consensus sequence</b> is constructed from each column in a motif's frequency matrix using the <b>"50% rule"</b> as follows: </p> <ol> <li>The letter frequencies in the column are sorted in decreasing order.</li> <li>Letters with frequency less 50% of the maximum are discarded.</li> <li>The letter used in this position in the consensus sequence is determined by the first rule below that applies:</li> <ul> <li>If there is only one letter left, or if the remaining letters exactly match an ambiguous symbol in the alphabet, the <b>letter</b> or <b>ambiguous symbol</b>, respectively, is used.</li> <li>Otherwise, if the remaining set contains at least 50% of the core symbols in the alphabet, the alphabet's <b>wildcard</b> (e.g., "N" for DNA or RNA, and "X" for protein) is used.</li> <li>Otherwise, the letter with the <b>maximum frequency</b> is used.</li> </ul> </ol> `); default: return("Error--Unrecognized shared doc_type: " + doc_type); } } // get_shared_doc_text </script> <script> // // discovery_doc.js // Documentation common to motif discovery tools. // // // Function to return the HTML text of a given type. // This function can be used directly to document the output format (xx-output-format.html) // and indirectly via print_doc_para for help pop-ups in the actual output HTML, // to prevent duplication of documentation. // function get_discovery_doc_text(doc_type, extra, extra2) { if (extra == undefined) {extra = ""}; if (extra2 == undefined) {extra2 = ""}; switch (doc_type) { case 'motif_logo': return(` The sequence logo of the motif. The rules for construction logos are given in the <i>Description</i> section of the documentation for the MEME Suite utility <a href="` + extra + `/doc/ceqlogo.html#description">ceqlogo</a>. `); case 'motif_rc_logo': return(` The sequence logo of the reverse complement motif. The rules for construction logos are given in the <i>Description</i> section of the documentation for the MEME Suite utility <a href="` + extra + `/doc/ceqlogo.html#description">ceqlogo</a>. `); case 'more': return(` Click on the blue symbol below to reveal detailed information about the motif. `); case 'submit_dl': return(` Click on the blue symbol below to reveal options allowing you to submit this motif to another MEME Suite motif analysis program, to download this motif in various text formats, or to download a sequence "logo" of this motif PNG or EPS format.</p> <h5>Supported Programs</h5> <dl> <dt>Tomtom</dt> <dd>Tomtom is a tool for searching for similar known motifs. [<a href="` + extra + `/doc/tomtom.html?man_type=web">manual</a>]</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. [<a href="` + extra + `/doc/mast.html?man_type=web">manual</a>]</dd> <dt>FIMO</dt> <dd>FIMO is a tool for searching biological sequence databases for sequences that contain one or more known motifs. [<a href="` + extra + `/doc/fimo.html?man_type=web">manual</a>]</dd> <dt>GOMo</dt> <dd>GOMo is a tool for identifying possible roles (Gene Ontology terms) for DNA binding motifs. [<a href="` + extra + `/doc/gomo.html?man_type=web">manual</a>]</dd> <dt>SpaMo</dt> <dd>SpaMo is a tool for inferring possible transcription factor complexes by finding motifs with enriched spacings. [<a href="` + extra + `/doc/spamo.html?man_type=web">manual</a>]</dd> </dl> `); case 'site_distr': return(` This plot shows the positional distribution of the best match to the motif in the ` + extra + ` sequences. Only matches with scores at least the ` + extra2 + ` score threshold are considered. The plot is smoothed with a triangular function whose width is 5% of the maximum ` + extra + ` sequence length. The position of the dotted vertical line indicates whether the sequences were aligned on their left ends, centers, or right ends, respectively. `); case 'site_hist': return(` This histogram shows the distribution of the <b>number</b> of matches to the motif in the ` + extra + ` sequences with at least one match. Only matches with scores at least the ` + extra2 + ` score threshold are considered. `); default: return("Error--Unrecognized discovery doc_type: " + doc_type); } } // get_discovery_doc_text </script> <script> // // submit_or_download_motif.js // function make_submit_or_download_motif_form(id, site_url, program) { var html = ` <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> <!-- 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> <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 existence 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> ` + (program == "MEME" ? ` <option value="3">FASTA</option> <option value="4">Raw</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=""> <input type="hidden" name="program" value=" ` + program + `"/> <input type="hidden" id="logo_motifs" name="motifs" value=""/> <input type="hidden" id="logo_id1" name="id1" 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> `; document.getElementById(id).insertAdjacentHTML('beforeend', html); $("logo_form").action = site_url + "/utilities/generate_logo"; } // make_submit_or_download_motif_form // // Functions to update the submit_or_download_motif form. // // // 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", current_alphabet.has_complement());//TODO 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(current_alphabet.has_complement() ? "submit_tomtom" : "submit_fimo"); //TODO Tomtom might require a more strict definition of DNA default_prog.checked = true; action_outpop_program.call(default_prog); // disable reverse-complement when not DNA $("logo_rc_option").disabled = !current_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(); } // action_show_output // // Hide the submit or 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(); } } // action_hide_outpop /* * 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); } // action_outpop_next /* * 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); } // action_outpop_prev /* * 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); } } // action_outpop_program /* * 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); var current_file = location.pathname.substring(location.pathname.lastIndexOf('/')+1); input = document.createElement("input"); input.setAttribute("type", "hidden"); input.setAttribute("name", "motifs_name"); input.setAttribute("value", "motif number " + (current_motif+1) + " from " + current_file); form.appendChild(input); document.body.appendChild(form); form.submit(); document.body.removeChild(form); } // action_outpop_submit(e) /* * Enable error bars when small sample correction is enabled. */ function action_outpop_ssc() { "use strict"; $("logo_err").value = $("logo_ssc").value; } // action_outpop_ssc // // Update 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(current_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.strands === "both" || data.options.revcomp) { pspm.reverse_complement(current_alphabet); logo = new Logo(current_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); } // action_outpop_motif // // Create the download menu. // function update_outpop_format(index) { var motif = data.motifs[index]; var fn = [motif_count_matrix, motif_prob_matrix, motif_minimal_meme, motif_fasta, motif_raw]; var suffix = ["_counts.txt", "_freqs.txt", ".meme", "_fasta.txt", "_raw.txt"]; 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; } // update_outpop_format /* * Update the text in the download format popup. */ function action_outpop_format() { update_outpop_format(current_motif); } // action_outpop_format /* * 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(); } // action_outpop_download_motif /* * Download the motif logo. * The EPS format can be calculated locally in Javascript */ function action_outpop_download_logo(e) { "use strict"; var motif = data.motifs[current_motif]; if ($("logo_format").value === "0") { // EPS var pspm, logo, eps; var logo_rc, logo_ssc, logo_width, logo_height; 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(current_alphabet); logo = new Logo(current_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 + (logo_rc ? "_rc" : "") + ".eps"); } else { $("logo_motifs").value = motif_minimal_meme(motif); $("logo_id1").value = motif.id; $("logo_form").submit(); } } // action_outpop_download_logo /* * 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); } } // action_outpop_tab function motif_fasta(motif) { "use strict"; var sites, site, seq, sequences, sequence, i, num, counter, out; counter = {}; sequences = data["sequence_db"]["sequences"]; sites = motif["sites"]; out = ""; for (i = 0; i < sites.length; i++) { site = sites[i]; seq = site["seq"]; sequence = sequences[seq]; counter[seq] = (num = counter[seq]) ? (++num) : (num = 1); // inc counter if (i !== 0) {out += "\n";} out += ">" + sequence["name"] + "_site_" + num + " offset= " + site["pos"] + (site["rc"] ? " RC\n" : "\n"); out += site["match"]; } return out; } // motif_fasta function motif_raw(motif) { "use strict"; var sites, i, out; sites = motif["sites"]; out = ""; for (i = 0; i < sites.length; i++) { if (i !== 0) {out += "\n";} out += sites[i]["match"]; } return out; } // motif_raw /* * Create a pspm for the given motif data */ function motif_pspm(motif) { var pwm = motif.pwm; var name = motif.id; var ltrim = 0; var rtrim = 0; var nsites = motif.nsites; var sig = (current_program === "STREME" ? motif.test_pvalue : motif.evalue); return new Pspm(pwm, name, ltrim, rtrim, nsites, sig, null, motif.alt, current_program); } // motif_pspm /* * Create a count matrix from the given motif data */ function motif_count_matrix(motif) { return motif_pspm(motif).as_count_matrix(); } // motif_count_matrix /* * Create a probablity matrix from the given motif data */ function motif_prob_matrix(motif) { return motif_pspm(motif).as_probability_matrix(); } // motif_prob_matrix function motif_minimal_meme(motif) { var strands; if (current_program === "STREME") { strands = (data.options.strands === "both" ? 2 : 1); } else { strands = (data.options.revcomp ? 2 : 1); } return motif_pspm(motif).as_meme({ "with_header": true, "with_pspm": true, "with_pssm": (current_program === "MEME" ? true : false), "version": data["version"], "alphabet": current_alphabet, "strands": strands }); } </script> <script> var current_program = "MEME"; var current_alphabet = new Alphabet(data.alphabet, data.background.freqs); var current_motif = 0; //var new_icon_src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAQCAMAAAAyEe/dAAAACVBMVEX//wAAAAD////s2cV/AAAAdUlEQVQYlXVRBxLAIAhL+P+jC2HZhXcBZEWEldDsZcLIcAhHWWnK8SDcWQhMFUHdAQ1CqQ5+CWPmlHojl+nCJNRtzu4qRc3IUzmTVpXYK0nox0z0PI1stgchdK7lEv7ekhvalw8WW547Gyzedt/2/gLx8WXjXF/1AYFriNAWAAAAAElFTkSuQmCC"; var DelayLogoTask = function(logo, canvas) { this.logo = logo; this.canvas = canvas; }; DelayLogoTask.prototype.run = function () { draw_logo_on_canvas(this.logo, this.canvas, false); }; function clone_template(template) { "use strict"; var node, help_btns, i, button; node = $(template).cloneNode(true); toggle_class(node, "template", false); node.id = ""; help_btns = node.querySelectorAll(".help"); for (i = 0; i < help_btns.length; i++) { button = help_btns[i]; if (button.hasAttribute("data-topic")) { button.tabIndex = "0"; button.addEventListener("click", __toggle_help, false); button.addEventListener("keydown", __toggle_help, false); } } return node; } function make_small_logo(alphabet, pspm, options) { if (typeof options === "undefined") options = {}; if (options.rc) pspm = pspm.copy().reverse_complement(alphabet); var logo = new Logo(alphabet, {x_axis: false, y_axis: false}); logo.add_pspm(pspm, (typeof options.offset === "number" ? options.offset : 0)); var canvas = document.createElement('canvas'); if (typeof options.className === "string") canvas.className = options.className; if (typeof options.width === "number" && options.width > 0) { canvas.height = 0; canvas.width = options.width; draw_logo_on_canvas(logo, canvas, false); } else { draw_logo_on_canvas(logo, canvas, false, 1/3); } return canvas; } function make_large_logo(alphabet, pspm, rc, offset, className) { if (rc) pspm = pspm.copy().reverse_complement(alphabet); var logo = new Logo(alphabet, ""); logo.add_pspm(pspm, offset); var canvas = document.createElement('canvas'); canvas.height = 200; canvas.width = 0; canvas.className = className; size_logo_on_canvas(logo, canvas, false); add_draw_task(canvas, new DelayLogoTask(logo, canvas)); return canvas; } function make_sym_btn(symbol, title, action) { var box; box = document.createElement("div"); box.tabIndex = 0; box.className = "sym_btn"; box.appendChild(document.createTextNode(symbol)); box.title = title; box.addEventListener('click', action, false); box.addEventListener('keydown', action, false); return box; } function make_seq(alphabet, 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 = alphabet.get_colour(alphabet.get_index(letter)); lbox.appendChild(document.createTextNode(seq.substring(i, j))); sbox.appendChild(lbox); } return sbox; } // // make_pv_text // // Returns the string p-value, with the p italicised. /// function make_pv_text() { var pv_text = document.createElement("span"); var pv_italic_text = document.createElement("span"); pv_italic_text.appendChild(document.createTextNode("p")); pv_italic_text.style.fontStyle = "italic"; pv_text.appendChild(pv_italic_text); pv_text.appendChild(document.createTextNode("-value")); return pv_text; } function append_site_entries(tbody, motif, site_index, count) { "use strict"; var i, end; var sites, site, sequences, sequence; var rbody; if (typeof count !== "number") { count = 20; } sequences = data["sequence_db"]["sequences"]; sites = motif["sites"]; end = Math.min(site_index + count, sites.length); for (i = site_index; i < end; i++) { site = sites[i]; sequence = sequences[site["seq"]]; rbody = tbody.insertRow(tbody.rows.length); add_text_cell(rbody, "" + (site["seq"] + 1) + ".", "site_num"); add_text_cell(rbody, sequence["name"], "site_name"); add_text_cell(rbody, site["rc"] ? "-" : "+", "site_strand"); add_text_cell(rbody, site["pos"] + 1, "site_start"); add_text_cell(rbody, site["pvalue"].toExponential(2), "site_pvalue"); add_text_cell(rbody, site["lflank"], "site lflank"); add_cell(rbody, make_seq(current_alphabet, site["match"]), "site match"); add_text_cell(rbody, site["rflank"], "site rflank"); } return i; } function make_site_entries() { "use strict"; var region; region = this; if (region.data_site_index >= region.data_motif["sites"].length) { // all sites created region.removeEventListener('scroll', make_site_entries, false); return; } // if there's still 100 pixels to scroll than don't do anything yet if (region.scrollHeight - (region.scrollTop + region.offsetHeight) > 100) { return; } region.data_site_index = append_site_entries( find_child(region, "sites_tbl").tBodies[0], region.data_motif, region.data_site_index, 20 ); } function make_sites(motif) { "use strict"; function add_site_header(row, title, nopad, help_topic, tag_class) { var div, divcp, th; th = document.createElement("th"); div = document.createElement("div"); div.className = "sites_th_inner"; if (typeof title !== "object") { title = document.createTextNode("" + title); } div.appendChild(title); if (help_topic) { div.appendChild(document.createTextNode("\xA0")); div.appendChild(help_button(help_topic)); } divcp = div.cloneNode(true); divcp.className = "sites_th_hidden"; th.appendChild(div); th.appendChild(divcp); if (nopad) { th.className = "nopad"; } if (tag_class) { th.className += " " + tag_class; } row.appendChild(th); } var outer_tbl, inner_tbl, tbl, thead, tbody, rhead; outer_tbl = document.createElement("div"); outer_tbl.className = "sites_outer"; inner_tbl = document.createElement("div"); inner_tbl.className = "sites_inner"; outer_tbl.appendChild(inner_tbl); tbl = document.createElement("table"); tbl.className = "sites_tbl"; inner_tbl.appendChild(tbl); thead = document.createElement("thead"); tbl.appendChild(thead); tbody = document.createElement("tbody"); tbl.appendChild(tbody); rhead = thead.insertRow(thead.rows.length); add_site_header(rhead, "", true); add_site_header(rhead, "Name", false, "pop_seq_name"); add_site_header(rhead, "Strand", false, "pop_site_strand", "site_strand_title"); add_site_header(rhead, "Start", false, "pop_site_start"); add_site_header(rhead, make_pv_text(), false, "pop_site_pvalue"); add_site_header(rhead, "", false); add_site_header(rhead, "Sites", true, "pop_site_match"); add_site_header(rhead, "", false); inner_tbl.data_motif = motif; inner_tbl.data_site_index = append_site_entries(tbody, motif, 0, 20); if (inner_tbl.data_site_index < motif["sites"].length) { inner_tbl.addEventListener('scroll', make_site_entries, false); } return outer_tbl; } function make_motif_table_entry(row, alphabet, ordinal, motif, colw) { "use strict"; function ev_sig(evalue_str) { "use strict"; var ev_re, match, sig, exp, num; ev_re = /^(.*)e(.*)$/; if (match = ev_re.exec(evalue_str)) { sig = parseFloat(match[1]); exp = parseInt(match[2]); if (exp >= 0) { return false; } else if (exp <= -3) { return true; } else { return sig * Math.pow(10, exp) <= 0.05; } } return true; } function make_preview(alphabet, motif) { "use strict"; var pspm, preview, preview_rc; var box, btn_box, logo_box, btn_plus, btn_minus; if (motif["preview_logo"]) { preview = motif["preview_logo"]; preview_rc = motif["preview_logo_rc"]; } else { pspm = new Pspm(motif["pwm"]); preview = make_logo(alphabet, pspm, 50, false, 0); motif["preview_logo"] = preview; if (alphabet.has_complement()) { preview_rc = make_logo(alphabet, pspm, 50, true, 0, "logo_rc"); motif["preview_logo_rc"] = preview_rc; } } if (preview_rc) { btn_plus = document.createElement("div"); btn_plus.appendChild(document.createTextNode("+")); btn_plus.className = "preview_btn plus"; btn_plus.tabIndex = "0"; btn_plus.addEventListener("click", action_btn_rc, false); btn_plus.addEventListener("keydown", action_btn_rc, false); btn_minus = document.createElement("div"); btn_minus.appendChild(document.createTextNode("-")); btn_minus.className = "preview_btn minus"; btn_minus.tabIndex = "0"; btn_minus.addEventListener("click", action_btn_rc, false); btn_minus.addEventListener("keydown", action_btn_rc, false); btn_box = document.createElement("div"); btn_box.className = "preview_btn_box"; btn_box.appendChild(btn_plus); btn_box.appendChild(btn_minus); } logo_box = document.createElement("div"); logo_box.className = "preview_logo_box"; logo_box.appendChild(preview); if (preview_rc) logo_box.appendChild(preview_rc); box = document.createElement("div"); box.className = "preview_box"; if (preview_rc) box.appendChild(btn_box); box.appendChild(logo_box); if (preview_rc) { if (motif["rc"]) { btn_minus.className += " active"; logo_box.className += " show_rc_logo"; } else { btn_plus.className += " active"; } } return box; } var pspm, preview, preview_rc, c; row.data_motif = motif; row.id = motif["alt"]; row.data_ordinal = ordinal; if (!ev_sig(motif["evalue"])) { row.style.opacity = 0.4; } add_text_cell(row, "" + ordinal + ".", "motif_ordinal"); add_cell(row, make_preview(alphabet, motif), "motif_logo"); add_text_cell(row, motif["evalue"], "motif_evalue"); add_text_cell(row, motif["nsites"], "motif_nsites"); add_text_cell(row, motif["len"], "motif_width"); add_cell(row, make_sym_btn("\u21A7", "Show more information.", action_show_more), "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"); if (colw) { for (c = 0; c < row.cells.length; c++) { row.cells[c].style.minWidth = colw[c] + "px"; } } } function make_motifs_table(alphabet, start_ordinal, motifs, colw, stop_reason) { var i, j; var tbl, thead, tbody, tfoot, row, preview; var motif, pspm; tbl = document.createElement("table"); thead = document.createElement("thead"); tbl.appendChild(thead); tbody = document.createElement("tbody"); tbl.appendChild(tbody); tfoot = document.createElement("tfoot"); tbl.appendChild(tfoot); row = thead.insertRow(thead.rows.length); add_text_header_cell(row, "", "", "motif_ordinal"); add_text_header_cell(row, "Logo", "pop_logo", "motif_logo"); add_text_header_cell(row, "E-value", "pop_ev", "motif_evalue"); add_text_header_cell(row, "Sites", "pop_sites", "motif_nsites"); add_text_header_cell(row, "Width", "pop_width", "motif_width"); add_text_header_cell(row, "More", "pop_more", "motif_more"); add_text_header_cell(row, "Submit/Download", "pop_submit_dl", "motif_submit"); for (i = 0; i < motifs.length; i++) { row = tbody.insertRow(tbody.rows.length); make_motif_table_entry(row, alphabet, start_ordinal + i, motifs[i], colw); } row = tfoot.insertRow(tfoot.rows.length); add_text_header_cell(row, stop_reason, "", "stop_reason", "", 6); return tbl; } function make_expanded_motif(alphabet, ordinal, motif, less_x, submit_x) { "use strict"; var box, pspm, logo_box, large_logo, large_logo_rc, tab_logo, tab_logo_rc; var btn, offset, norc; box = clone_template("tmpl_motif_expanded"); box.data_motif = motif; box.data_ordinal = ordinal; pspm = new Pspm(motif["pwm"]); if (typeof motif["rc"] !== "boolean") { motif["rc"] = false; } if (motif["large_logo"]) { large_logo = motif["large_logo"]; large_logo_rc = motif["large_logo_rc"]; } else { large_logo = make_large_logo(alphabet, pspm, false, 0); motif["large_logo"] = large_logo; if (alphabet.has_complement()) { large_logo_rc = make_large_logo(alphabet, pspm, true, 0, "logo_rc"); motif["large_logo_rc"] = large_logo_rc; } } norc = (large_logo_rc == null); toggle_class(box, "norc", norc); logo_box = find_child(box, "tvar_logo"); logo_box.appendChild(large_logo); if (large_logo_rc) logo_box.appendChild(large_logo_rc); toggle_class(logo_box, "show_rc_logo", motif["rc"]); tab_logo = find_child(box, "tvar_tab"); tab_logo_rc = find_child(box, "tvar_tab_rc"); toggle_class(tab_logo, "activeTab", !motif["rc"]); toggle_class(tab_logo_rc, "activeTab", motif["rc"]); tab_logo.addEventListener('click', action_rc_tab, false); tab_logo.addEventListener('keydown', action_rc_tab, false); tab_logo_rc.addEventListener('click', action_rc_tab, false); tab_logo_rc.addEventListener('keydown', action_rc_tab, false); set_tvar(box, "tvar_ordinal", ordinal); set_tvar(box, "tvar_evalue", motif["evalue"]); set_tvar(box, "tvar_width", motif["len"]); set_tvar(box, "tvar_site_count", motif["nsites"]); set_tvar(box, "tvar_llr", motif["llr"]); set_tvar(box, "tvar_ic", motif["ic"]); set_tvar(box, "tvar_re", motif["re"]); set_tvar(box, "tvar_bt", motif["bt"]); if (data.sequence_db.primary_count > data.options.brief) { if (data.options.brief == 1000) { set_tvar(box, "tvar_sites", "Output of sites suppressed because there were more than 1000 (primary) sequences."); } else { set_tvar(box, "tvar_sites", "Output of sites suppressed by -brief option."); } } else { set_tvar(box, "tvar_sites", make_sites(motif)); } offset = 32; // 1* 5px padding + 2 * 10px padding + 2 * 2px border + 3px ?? btn = find_child(box, "tvar_less"); btn.style.left = (less_x - offset) + "px"; btn.addEventListener('click', action_show_less, false); btn.addEventListener('keydown', action_show_less, false); btn = find_child(box, "tvar_submit"); btn.style.left = (submit_x - offset) + "px"; btn.addEventListener('click', action_show_outpop, false); btn.addEventListener('keydown', action_show_outpop, false); return box; } // // // function make_motifs() { "use strict"; function pixel_value(str_in) { "use strict"; var px_re, match; px_re = /^(\d+)px$/; if (match = px_re.exec(str_in)) { return parseInt(match[1], 10); } return 0; } var container, tbl; var colw, r, row, c, cell, cell_style, pad_left, pad_right; // make the motifs table container = $("motifs"); container.innerHTML = ""; // clear content tbl = make_motifs_table(current_alphabet, 1, data["motifs"], colw, data["stop_reason"]); container.appendChild(tbl); // measure table column widths colw = []; row = tbl.tBodies[0].rows[0]; for (c = 0; c < row.cells.length; c++) { var padLeft, padRight; cell = row.cells[c]; cell_style = window.getComputedStyle(cell, null); pad_left = pixel_value(cell_style.getPropertyValue("padding-left")); pad_right = pixel_value(cell_style.getPropertyValue("padding-right")); colw[c] = cell.clientWidth - pad_left - pad_right; if (typeof colw[c] !== "number" || colw[c] < 0) { colw[c] = 1; } } // set minimum table column widths on each row so later when we remove rows it still aligns for (r = 0; r < tbl.tBodies[0].rows.length; r++) { row = tbl.tBodies[0].rows[r]; for (c = 0; c < row.cells.length; c++) { row.cells[c].style.minWidth = colw[c] + "px"; } } // store the table column widths so we can create rows latter with the same minimums container.data_colw = colw; // calculate the x offset for the buttons row = tbl.tBodies[0].rows[0]; container.data_more_x = coords(find_child(find_child(row, "motif_more"), "sym_btn"))[0]; container.data_submit_x = coords(find_child(find_child(row, "motif_submit"), "sym_btn"))[0]; draw_on_screen(); } function make_meme_block(container, max_seq_len, is_scan, site) { "use strict"; var motif = data.motifs[site.motif]; var block = make_block(container, max_seq_len, site.pos, motif.len, site.pvalue, site.rc, site.motif, is_scan); var handler = (is_scan ? make_scan_popup(site, motif, block) : make_block_popup(site, motif, block)); block.addEventListener("mouseover", handler, false); block.addEventListener("mouseout", handler, false); } function append_blocks_entries(tbody, seq_index, count) { "use strict"; var i, end, j; var max_pvalue, max_block_height, max_seq_len, sequences; var sequence, sites, scans, scan; var container, plus, minus, rule, row; // define some constants max_seq_len = data.sequence_db.max_length; // determine how many to load end = Math.min(seq_index + count, data.sequence_db.sequences.length); for (i = seq_index; i < end; i++) { // get the sequence sequence = data.sequence_db.sequences[i]; // make the containers for the block diagram container = make_block_container(current_alphabet.has_complement(), data.options.revcomp, max_seq_len, sequence.length); // create blocks for the motif sites sites = sequence["sites"]; for (j = 0; j < sites.length; j++) make_meme_block(container, max_seq_len, false, sites[j]); // create blocks for the scanned sites scan = data.scan[i]; for (j = 0; j < scan.sites.length; j++) make_meme_block(container, max_seq_len, true, scan.sites[j]); // create a row for the sequence row = tbody.insertRow(tbody.rows.length); toggle_class(row, "empty_seq", sites.length == 0 && scan.sites.length == 0); toggle_class(row, "only_scan", sites.length == 0 && scan.sites.length > 0); add_text_cell(row, (i + 1) + ".", "blockdiag_num"); add_text_cell(row, sequence["name"], "blockdiag_name"); add_text_cell(row, scan["pvalue"].toExponential(2), "blockdiag_pvalue"); add_cell(row, container, "block_td"); } return end; } function make_blocks_entries() { "use strict"; var region; region = this; if (region.data_blocks_index >= data["sequence_db"]["sequences"].length) { // all sites created region.removeEventListener('scroll', make_blocks_entries, false); return; } // if there's still 100 pixels to scroll then don't do anything yet if (region.scrollHeight - (region.scrollTop + region.offsetHeight) > 100) { return; } region.data_blocks_index = append_blocks_entries( find_child(region, "blocks_tbl").tBodies[0], region.data_blocks_index, 20 ); } // Apply opacity alpha to color rgb with backrgound bkg. function RGBAtoRGB(rgb, bkg, opacity) { var i; var rgb_new = []; for (i=0; i<3; i++) { rgb_new[i] = Math.round(((1-opacity) * bkg[i]) + (opacity * rgb[i])); } return rgb_new; } // Function to measure the size of text on a canvas. var MeasureText = function(font, text) { var image = document.createElement("canvas"); var image_ctx = image.getContext('2d'); image_ctx.save(); image_ctx.font = font; var text_length = image_ctx.measureText(text).width; image.remove(); return text_length; } // MeasureText // Functions to download the motif block diagram as a PDF or SVG file. function download_PDF_block_diagram() { downloadBlockDiagram(true, 'bitbucket'); } function download_SVG_block_diagram() { downloadBlockDiagram(false, 'bitbucket'); } // Helper function to create a script element for downloading javascript. function createScriptElement(url, file, integrity) { console.log('Downloading ' + file + ' from ' + url + '.'); const script = document.createElement('script'); script.setAttribute('src', url + '/' + file); if (integrity) script.setAttribute('integrity', integrity); script.setAttribute('crossorigin', 'anonymous'); script.setAttribute('async', ''); document.head.appendChild(script); } // Helper function to download the motif block diagram as a PDF or SVG file. var downloadBlockDiagram = function( make_pdf, next_source ) { var script_file, integrity_key; // Check if necessary javascript has been loaded. if ( (make_pdf && typeof jsPDF === 'undefined') || (!make_pdf && typeof d3 === 'undefined') ) { if (next_source === 'bitbucket') { if (make_pdf) { script_file = 'jspdf.min.js'; } else { script_file = 'd3.v5.min.js'; } createScriptElement('https://memesuite.bitbucket.io/javascript', script_file); // Wait 3 seconds and then try to create the diagram. setTimeout(downloadBlockDiagram, 3000, make_pdf, 'cloudflare'); } else if (next_source === 'cloudflare') { if (make_pdf) { script_file = 'jspdf/1.5.3/jspdf.min.js'; integrity_key = 'sha512-ToRWKKOvhBSS8EtqSflysM/S7v9bB9V0X3B1+E7xo7XZBEZCPL3VX5SFIp8zxY19r7Sz0svqQVbAOx+QcLQSAQ==' } else { script_file = 'd3/5.16.0/d3.min.js'; integrity_key = 'sha512-FHsFVKQ/T1KWJDGSbrUhTJyS1ph3eRrxI228ND0EGaEp6v4a/vGwPWd3Dtd/+9cI7ccofZvl/wulICEurHN1pg=='; } createScriptElement('https://cdnjs.cloudflare.com/ajax/libs', script_file, integrity_key); // Wait 3 seconds and then try to create the diagram. setTimeout(downloadBlockDiagram, 3000, make_pdf, 'none'); } else { // No more sources for javascript. Call so error message will be shown. downloadBlockDiagramMain(make_pdf); } } else { // Create the diagram. downloadBlockDiagramMain(make_pdf); } } // Main function to download the motif block diagram as a PDF or SVG file. var downloadBlockDiagramMain= function( make_pdf ) { // Check that necessary javascript was downloaded. if ( (make_pdf && typeof jsPDF === 'undefined') || (!make_pdf && typeof d3 === 'undefined') ) { var id = make_pdf ? $("pdfButton") : $("svgButton"); help_popup(id, "pop_offline"); return; } // Determine which lines are visible in the HTML inner scroll window. var inner_tbl = $("blocks_scroll"); var pix_per_sequence = 27; // (vertical) pixels per sequence diagram line var first = Math.round(inner_tbl.scrollTop / pix_per_sequence) + 1; var last = first + Math.round(inner_tbl.offsetHeight / pix_per_sequence) - 1; // Get the contents of the HTML inner scroll window while saving the sequences to be printed. var numbers = document.getElementsByClassName("blockdiag_num"); var bars = {}; var visible_motifs = {}; var seq_index = 0; var rgb; for (var i=0; i<numbers.length && seq_index < last; i++) { var row_node = numbers[i].parentNode; // Check if the sequence is displayed in the outer scrolling window. var seq_name = numbers[i].nextSibling.innerHTML; if ( ($("rdo_sites_only").checked && row_node.getAttribute("class").includes("only_scan")) || (! $("rdo_all_seqs").checked && row_node.getAttribute("class").includes("empty_seq")) ) { continue; } seq_index++; if (seq_index < first) { continue; } // sequence not in HTML inner scrolling window var pvalue = numbers[i].nextSibling.nextSibling.innerHTML; var far = numbers[i].nextSibling.nextSibling.nextSibling.children[0].children; var seq_length = data.sequence_db.sequences[i].length; var seqObj = []; seqObj["length"] = seq_length; seqObj["pvalue"] = pvalue; seqObj["pn"] = []; seqObj["width"] = []; seqObj["left"] = []; seqObj["height"] = []; seqObj["color"] = []; seqObj["opacity"] = []; for (var x = 0; x < far.length; x++) { if ((far[x].getAttribute("style") != null) && ( ( $("rdo_sites_only").checked && ! far[x].getAttribute("class").includes("scanned")) || ( $("rdo_sites_and_scan").checked || $("rdo_all_seqs").checked ) ) ) { if (far[x].getAttribute("style").includes("rgb")) { var compStyles = far[x].style; // Make scanned sites get displayed first so they will not "cover" regular sites. var site_pn = far[x].getAttribute("class").includes("top") ? "+" : "-"; var site_width = parseFloat(compStyles.width.slice(0, -1)); var site_left = parseFloat(compStyles.left.slice(0, -1)); var site_height = parseFloat(compStyles.height.slice(0, -2)); var site_color = compStyles.backgroundColor.slice(4, -1).replace(/ /g, ""); if (far[x].getAttribute("class").includes("scanned")) { seqObj["pn"].unshift(site_pn); seqObj["width"].unshift(site_width); seqObj["left"].unshift(site_left); seqObj["height"].unshift(site_height); seqObj["color"].unshift(site_color); seqObj["opacity"].unshift(0.3); } else { seqObj["pn"].push(site_pn); seqObj["width"].push(site_width); seqObj["left"].push(site_left); seqObj["height"].push(site_height); seqObj["color"].push(site_color); seqObj["opacity"].push(1); } visible_motifs[far[x].getAttribute("data-colour-index")] = site_color; } } } // Save the sequence data if it has motifs (or rdo_all_seqs is checked) if ($("rdo_all_seqs").checked || seqObj["width"].length > 0) { bars[seq_name] = seqObj; } } // jsPDF coordinates are always in points. var font_size = 13; var nbars = Object.keys(bars).length; var legend_font_size = 0.8 * font_size; // Initialize field widths in points by measuring header text. var font = "bold " + font_size + "pt Helvetica, sans-serif"; var max_name_width = MeasureText(font, "Name"); var max_pvalue_width = MeasureText(font, "p-value"); var max_seq_length = 0; // in characters var has_complement = current_alphabet.has_complement(); var revcomp = data.options["revcomp"]; // Measure text of numbers, names and p-values, convert to points and save the max. font = font_size + "pt Helvetica, sans-serif"; var seq_name; for (seq_name in bars) { var seq_name_width = MeasureText(font, seq_name); var pvalue_width = MeasureText(font, pvalue); var seq_length = bars[seq_name]["length"]; if (seq_length > max_seq_length) { max_seq_length = seq_length; } if (seq_name_width > max_name_width) { max_name_width = seq_name_width; } if (pvalue_width > max_pvalue_width) { max_pvalue_width = pvalue_width; } } // Get the length in characters of the longest visible motif. var max_motif_length = 0; var motif_index, motif_length; for (motif_index in visible_motifs) { motif_length = data.motifs[motif_index].len; if (motif_length > max_motif_length) { max_motif_length = motif_length; } } // Sort the motif indices. var motif_indices = []; var sorted_motif_indices = []; for (motif_index in visible_motifs) { motif_indices.push(Number(motif_index)); } sorted_motif_indices = motif_indices.sort(function(a, b){return a-b;}); // Set up values for main section. var height = (nbars+1) * (2.6*font_size); var nmotifs = Object.keys(visible_motifs).length; var name_field_width = max_name_width + font_size; var pvalue_field_width = max_pvalue_width + font_size; var plus_minus_field_width = has_complement ? 2*font_size : font_size; var non_diagram_width = name_field_width + pvalue_field_width + plus_minus_field_width; var diagram_width = 47 * font_size; var pix_per_char = diagram_width/max_seq_length; var x_scale_factor = data.sequence_db.max_length/100; // Scale factor comes from function make_block(). var diagram_line_height = (height-2*font_size)/nbars; var doc_width = diagram_width + non_diagram_width + 2*font_size; var doc_height = height + 0.5*font_size; // Set up values for the legend. var tmp_font = legend_font_size + "pt Courier, normal"; var courier_width = MeasureText(tmp_font, "A"); var legend_line_height = 1.2 * legend_font_size; var index_field_width = 3 * legend_font_size; var symbol_field_width = 5 * legend_font_size; var legend_non_consensus_width = index_field_width + symbol_field_width + 3*legend_font_size; var legend_hdr_font = legend_font_size + "pt Helvetica, sans-serif"; var consensus_hdr_width = MeasureText(legend_hdr_font, "Motif Consensus"); var consensus_field_width = doc_width - legend_non_consensus_width - legend_font_size; // Get number of characters that will fit in legend consensus field. var legend_split_length = Math.floor(consensus_field_width/courier_width); // Get number of lines in legend. var n_legend_lines = 0; for (motif_index in visible_motifs) { motif_length = data.motifs[motif_index].len; n_legend_lines += Math.ceil(motif_length/legend_split_length); } if (n_legend_lines > 0) { n_legend_lines += 3; } // header line + 2*space var legend_width = legend_non_consensus_width + Math.min(legend_split_length, max_motif_length)*courier_width; var legend_height = n_legend_lines * legend_line_height; doc_height += legend_height + 1*font_size; if (make_pdf) { // Now create the PDF document. // This next line is necessary because jsPDF silently swaps width and height. var orient = doc_width > doc_height ? 'landscape' : 'portrait'; doc = new jsPDF( { orientation: orient, unit: 'pt', format: [doc_width, doc_height] } ); // Set the font size for the PDF. doc.setFontSize(1.33*font_size); // Create the header. var offset = font_size; var liney = 1.5*font_size; // .. Name hdr .. doc.setFont("Helvetica", "bold"); doc.text("Name", offset, liney); offset += name_field_width; // p-value hdr doc.setFont("Helvetica", "bolditalic"); doc.text("p", offset + font_size, liney); doc.setFont("Helvetica", "bold"); doc.text("-value", offset + 2*font_size, liney); offset += pvalue_field_width + plus_minus_field_width; // Motif Location hdr doc.text("Motif Locations", offset, liney); // Generate the data object for the PDF. liney -= 0.5*font_size; var dy = font_size/3.5; for (var seq_name in bars) { liney += diagram_line_height; offset = font_size; // // Generate the text fields. // doc.setFont("Helvetica", "normal"); // Sequence name text doc.text(seq_name, offset, liney + dy); offset += name_field_width; // p-value text doc.text(bars[seq_name]["pvalue"], offset + pvalue_field_width, liney + dy, {align: "right"}); offset += pvalue_field_width; // +/- text (optional) if (has_complement) { doc.text("+", offset+font_size, liney + dy - font_size/2); if (revcomp) { doc.text("-", offset+1.15*font_size, liney + dy + font_size/2); } } offset += plus_minus_field_width; // Generate the base line. doc.setLineWidth(0.35); doc.line(offset, liney, offset + (bars[seq_name]["length"] * pix_per_char), liney); // Generate the blocks. for (var i = 0; i < bars[seq_name]["width"].length; i++) { if (bars[seq_name]["pn"][i] == undefined) { continue; } rgb = bars[seq_name]["color"][i].split(",").map(Number); var opacity = bars[seq_name]["opacity"][i]; if (opacity != 1) { rgb = RGBAtoRGB(rgb, [255,255,255], opacity); } var bar_x = offset + (bars[seq_name]["left"][i] * x_scale_factor * pix_per_char); var bar_y = (bars[seq_name]["pn"][i] == "+") ? (liney - 0.1*font_size*bars[seq_name]["height"][i]) : liney; doc.setFillColor(rgb[0], rgb[1], rgb[2]); doc.rect(bar_x, bar_y, bars[seq_name]["width"][i] * x_scale_factor * pix_per_char, 0.1*font_size*bars[seq_name]["height"][i], 'FD'); } } // // Generate the legend. // if (n_legend_lines > 0) { doc.setFontSize(1.33*legend_font_size); dy = 0.8 * legend_font_size; // The legend header. var legend_top = liney + 2*legend_font_size; liney += 4.5*legend_font_size; offset = legend_font_size; doc.setFont("Helvetica", "bold"); doc.text("Motif", offset, liney); offset += index_field_width + legend_font_size; doc.text("Symbol", offset, liney); offset += symbol_field_width + legend_font_size; doc.text("Motif Consensus", offset, liney); liney -= 0.5*legend_font_size; liney += legend_line_height; for (var i=0; i<motif_indices.length; i++) { motif_index = sorted_motif_indices[i]; offset = legend_font_size; // Motif Name doc.setFont("Helvetica", "normal"); var motif_index_string = (motif_index+1).toString(); motif_index_string = motif_index_string + "."; var dx = 3 * legend_font_size; doc.text(motif_index_string, offset+dx, liney+dy, {align: "right"}); offset += index_field_width + legend_font_size; // Motif Symbol motif_length = data.motifs[motif_index].len; rgb = visible_motifs[motif_index].split(",").map(Number); var bar_x = offset; var bar_y = liney; doc.setFillColor(rgb[0], rgb[1], rgb[2]); doc.rect(bar_x, bar_y, symbol_field_width*(motif_length/max_motif_length), legend_font_size, 'FD'); offset += symbol_field_width + legend_font_size; // Motif Consensus Sequence doc.setFont("Courier", "normal"); var motif_consensus = data.motifs[motif_index].id; doc.text(motif_consensus, offset, liney+dy, {maxWidth: legend_split_length*courier_width}); liney += Math.ceil(motif_length/legend_split_length) * legend_line_height; } // Draw box around legend. doc.rect( 0.5*legend_font_size, legend_top + 0.5*legend_font_size, Math.max(legend_width, legend_non_consensus_width + consensus_hdr_width + courier_width), legend_height ); } // legend doc.save('motif_locations.pdf'); } else { // Download an SVG document. var body = d3.select("#blocks").append("svg") .attr("width", (diagram_width + non_diagram_width) + "pt") .attr("height", (doc_height+legend_font_size).toString()) .attr("background-color", "lightgrey") .attr("id", "memeSVG") .attr("xmlns", "http://www.w3.org/2000/svg"); // Create the header. var x = 0; var offset = font_size; var liney = 1.5*font_size; // .. Name hdr .. body.append("text") .attr("x", offset) .attr("y", liney) .attr("font-family", "Helvetica, sans-serif") .attr("font-size", font_size+"pt") .attr("font-weight", "bold") .text("Name"); offset += name_field_width; // p-value hdr body.append("text") .attr("x", offset + 2*font_size) .attr("y", liney) .attr("font-family", "Helvetica, sans-serif") .attr("font-size", font_size+"pt") .attr("font-weight", "bold") .attr("font-style", "italic") .text("p"); body.append("text") .attr("x", offset + 3*font_size) .attr("y", liney) .attr("font-family", "Helvetica, sans-serif") .attr("font-size", font_size+"pt") .attr("font-weight", "bold") .text("-value"); offset += pvalue_field_width + plus_minus_field_width + font_size; // Motif Location hdr body.append("text") .attr("x", offset) .attr("y", liney) .attr("font-family", "Helvetica, sans-serif") .attr("font-size", font_size+"pt") .attr("font-weight", "bold") .text("Motif Locations"); // Generate the data for the SVG. liney -= 0.5*font_size; var dy = font_size/3.5; for (var seq_name in bars) { liney += diagram_line_height; offset = font_size; // // Generate the text fields. // // Sequence name text body.append("text") .attr("x", offset) .attr("y", liney + dy) .attr("font-family", "Helvetica, sans-serif") .attr("font-size", font_size+"pt") .text(seq_name); offset += name_field_width; // p-value text body.append("text") .attr("x", offset + font_size+ pvalue_field_width) .attr("y", liney + dy) .attr("font-family", "Helvetica, sans-serif") .attr("font-size", font_size+"pt") .attr("text-anchor", "end") .text(bars[seq_name]["pvalue"]); offset += pvalue_field_width + font_size; // +/- text (optional) if (has_complement) { body.append("text") .attr("x", offset+font_size) .attr("y", liney + dy - font_size/2) .attr("font-family", "Helvetica, sans-serif") .attr("font-size", font_size+"pt") .text("+"); if (revcomp) { body.append("text") .attr("x", offset+1.15*font_size) .attr("y", liney + dy + font_size/2) .attr("font-family", "Helvetica, sans-serif") .attr("font-size", font_size+"pt") .text("-"); } } offset += plus_minus_field_width; // Generate the base line. body.append("line") .attr("x1", offset) .attr("x2", offset + (bars[seq_name]["length"] * pix_per_char)) .attr("y1", liney) .attr("y2", liney) .attr("stroke-width", 0.5) .attr("stroke","black"); // Generate the blocks. for (var i = 0; i < bars[seq_name]["width"].length; i++) { if (bars[seq_name]["pn"][i] == undefined) { continue; } body.append("rect") .attr("x", offset + (bars[seq_name]["left"][i] * x_scale_factor * pix_per_char) ) .attr("y", (bars[seq_name]["pn"][i] == "+") ? (liney - 0.1*font_size*bars[seq_name]["height"][i]) : liney) .attr("width", bars[seq_name]["width"][i] * x_scale_factor * pix_per_char) .attr("height", 0.1*font_size*bars[seq_name]["height"][i]) .attr("fill", "rgb("+bars[seq_name]["color"][i] + ")") .attr("fill-opacity", bars[seq_name]["opacity"][i]) .attr("stroke-width", 0.5) .attr("stroke","black"); } } // // Generate the legend. // if (n_legend_lines > 0) { dy = 0.8 * legend_font_size; // The legend header. var legend_top = liney + 2*legend_font_size; liney += 4.5*legend_font_size; offset = legend_font_size; body.append("text") .attr("x", offset) .attr("y", liney) .attr("font-family", "Helvetica, sans-serif") .attr("font-size", legend_font_size+"pt") .attr("font-weight", "bold") .text("Motif"); offset += index_field_width + legend_font_size; body.append("text") .attr("x", offset) .attr("y", liney) .attr("font-family", "Helvetica, sans-serif") .attr("font-size", legend_font_size+"pt") .attr("font-weight", "bold") .text("Symbol"); offset += symbol_field_width + legend_font_size; body.append("text") .attr("x", offset) .attr("y", liney) .attr("font-family", "Helvetica, sans-serif") .attr("font-size", legend_font_size+"pt") .attr("font-weight", "bold") .text("Motif Consensus"); liney -= 0.5*legend_font_size; liney += legend_line_height; for (var i=0; i<motif_indices.length; i++) { motif_index = sorted_motif_indices[i]; offset = legend_font_size; // Motif Name var motif_index_string = (motif_index+1).toString(); motif_index_string = motif_index_string + "."; var dx = 3.3 * legend_font_size; body.append("text") .attr("x", offset+dx) .attr("y", liney+dy) .attr("font-family", "Helvetica, sans-serif") .attr("font-size", legend_font_size+"pt") .attr("text-anchor", "end") .text(motif_index_string); offset += index_field_width + legend_font_size; // Motif Symbol motif_length = data.motifs[motif_index].len; var bar_x = offset; var bar_y = liney; body.append("rect") .attr("x", bar_x ) .attr("y", liney) .attr("width", symbol_field_width*(motif_length/max_motif_length)) .attr("height", legend_font_size) .attr("fill", "rgb("+ visible_motifs[motif_index] + ")") .attr("stroke-width", 0.5) .attr("stroke","black"); offset += symbol_field_width + legend_font_size; // Motif Consensus Sequence var motif_consensus = data.motifs[motif_index].id; var cons_length = motif_consensus.length; var start_index = 0; while (start_index < cons_length) { body.append("text") .attr("x", offset) .attr("y", liney+dy) .attr("font-family", "Courier") .attr("font-size", legend_font_size+"pt") .text(motif_consensus.slice(start_index, Math.min(cons_length, start_index+legend_split_length))) liney += legend_line_height; start_index += legend_split_length; } } // Draw box around legend. body.append("rect") .attr("x", 0.5*legend_font_size) .attr("y", legend_top + 0.5*legend_font_size) .attr("width", Math.max(legend_width, legend_non_consensus_width + consensus_hdr_width + courier_width)) .attr("height", legend_height) .attr("fill", "none") .attr("stroke-width", 1) .attr("stroke", "black"); } // legend var svg = document.getElementsByTagName("svg")[0].outerHTML; var svgBlob = new Blob([svg], {type:"image/svg+xml;charset=utf-8"}); var svgUrl = URL.createObjectURL(svgBlob); var downloadLink = document.createElement("a"); downloadLink.href = svgUrl; downloadLink.download = "meme-motif-locations.svg"; document.getElementById("sites_sec").appendChild(downloadLink); downloadLink.click(); downloadLink.remove(); document.getElementById("memeSVG").remove(); } // SVG }; function make_blocks() { "use strict"; function add_seqs_filter(container, id, checked, label_text, help_topic) { "use strict"; var label, radio; radio = document.createElement("input"); radio.type = "radio"; radio.name = "seqs_display"; radio.id = id; radio.checked = checked; radio.addEventListener('click', action_seqs_filter, false); label = document.createElement("label"); label.appendChild(document.createTextNode(label_text)); label.htmlFor = id; container.appendChild(radio); container.appendChild(label); if (help_topic) { container.appendChild(document.createTextNode("\xA0")); container.appendChild(help_button(help_topic)); } } function add_block_diagram_button(container, id, buttonText, help_topic) { var button, label; button = document.createElement("button"); button.id = id; label = document.createTextNode(buttonText); button.appendChild(label); button.onclick = (id === "pdfButton") ? download_PDF_block_diagram : download_SVG_block_diagram; container.appendChild(document.createTextNode(" ")); container.appendChild(button); if (help_topic) { container.appendChild(document.createTextNode("\xA0")); container.appendChild(help_button(help_topic)); } //var new_icon = document.createElement("img"); //new_icon.src = new_icon_src; //new_icon.alt = "NEW"; //container.appendChild(document.createTextNode(" ")); //container.appendChild(new_icon); } function add_blocks_header(row, title, nopad, help_topic) { "use strict"; var div, divcp, th; th = document.createElement("th"); div = document.createElement("div"); div.className = "blocks_th_inner"; if (typeof title !== "object") { title = document.createTextNode("" + title); } div.appendChild(title); if (help_topic) { div.appendChild(document.createTextNode("\xA0")); div.appendChild(help_button(help_topic)); } divcp = div.cloneNode(true); divcp.className = "blocks_th_hidden"; th.appendChild(div); th.appendChild(divcp); if (nopad) { th.className = "nopad"; } row.appendChild(th); } var container; var page, view_height, outer_tbl, inner_tbl, tbl, thead, tbody, rhead; var in_view, i, seq_count; page = (document.compatMode === "CSS1Compat") ? document.documentElement : document.body; view_height = Math.max(page.clientHeight - 300, 300); container = $("blocks"); toggle_class(container, "hide_empty_seqs", true); toggle_class(container, "hide_only_scan", true); container.innerHTML = ""; add_seqs_filter(container, "rdo_sites_only", true, "Only Motif Sites", "pop_motif_sites"); add_seqs_filter(container, "rdo_sites_and_scan", false, "Motif Sites+Scanned Sites", "pop_scanned_sites"); add_seqs_filter(container, "rdo_all_seqs", false, "All Sequences", "pop_all_sequences"); add_block_diagram_button(container, "pdfButton", "Download PDF", "pop_download_pdf_motif_locations"); add_block_diagram_button(container, "svgButton", "Download SVG", "pop_download_svg_motif_locations"); outer_tbl = document.createElement("div"); outer_tbl.className = "blocks_outer"; inner_tbl = document.createElement("div"); inner_tbl.id = "blocks_scroll"; inner_tbl.className = "blocks_inner"; inner_tbl.style.maxHeight = view_height + "px"; outer_tbl.appendChild(inner_tbl); tbl = document.createElement("table"); tbl.className = "blocks_tbl"; inner_tbl.appendChild(tbl); thead = document.createElement("thead"); tbl.appendChild(thead); tbody = document.createElement("tbody"); tbl.appendChild(tbody); rhead = thead.insertRow(thead.rows.length); add_blocks_header(rhead, "", true); add_blocks_header(rhead, "Name", false, "pop_seq_name"); add_blocks_header(rhead, make_pv_text(), false, "pop_seq_pvalue"); add_blocks_header(rhead, "Motif Locations", false, "pop_motif_location"); container.appendChild(outer_tbl); seq_count = data["sequence_db"]["sequences"].length; in_view = Math.max(Math.ceil(view_height / 25), 1); i = append_blocks_entries(tbody, 0, in_view); while (i < seq_count && inner_tbl.scrollHeight - (inner_tbl.scrollTop + inner_tbl.offsetHeight) < 400) { i = append_blocks_entries(tbody, i, 20); } inner_tbl.data_blocks_index = i; if (i < seq_count) { inner_tbl.addEventListener('scroll', make_blocks_entries, false); } } function make_scan_popup(site, motif) { return function (e) { "use strict"; var pop, xy, padding, edge_padding, pop_left, pop_top, page_width; var lflank, match, rflank, pspm; if (!e) var e = window.event; pop = make_scan_popup.pop; if (e.type === "mouseover") { if (pop) return; pop = clone_template("tmpl_scan_info"); pspm = new Pspm(motif.pwm); if (site.rc) pspm.reverse_complement(current_alphabet); set_tvar(pop, "tvar_logo", make_small_logo(current_alphabet, pspm, {"className": "scan_logo"})); set_tvar(pop, "tvar_motif", motif.id); set_tvar(pop, "tvar_pvalue", site.pvalue.toExponential(2)); set_tvar(pop, "tvar_start", site.pos + 1); set_tvar(pop, "tvar_end", site.pos + motif.len); document.body.appendChild(pop); position_popup(this, pop); make_scan_popup.pop = pop; } else if (e.type === "mouseout") { if (pop) { pop.parentNode.removeChild(pop); make_scan_popup.pop = null; } } }; } function make_block_popup(site, motif, block) { return function (e) { "use strict"; var pop; var lflank, match, rflank, pspm, ruler, match_seq, match_width; if (!e) var e = window.event; pop = make_block_popup.pop; if (e.type === "mouseover") { if (pop) return; pop = clone_template("tmpl_block_info"); pspm = new Pspm(motif.pwm); if (site.rc) { // must be dna pspm.reverse_complement(current_alphabet); lflank = current_alphabet.invcomp_seq(site.rflank); match = current_alphabet.invcomp_seq(site.match); rflank = current_alphabet.invcomp_seq(site.lflank); } else { lflank = site.lflank; match = site.match; rflank = site.rflank; } ruler = document.getElementById("measure_match"); match_seq = make_seq(current_alphabet, match); ruler.innerHTML = ""; ruler.appendChild(match_seq); match_width = ruler.clientWidth; ruler.removeChild(match_seq); set_tvar(pop, "tvar_lflank", lflank); set_tvar(pop, "tvar_match", match_seq); set_tvar(pop, "tvar_rflank", rflank); set_tvar(pop, "tvar_logo_pad", lflank); set_tvar(pop, "tvar_logo", make_small_logo(current_alphabet, pspm, {"width": match_width})); set_tvar(pop, "tvar_motif", motif.id); set_tvar(pop, "tvar_pvalue", site.pvalue.toExponential(2)); set_tvar(pop, "tvar_start", site.pos + 1); set_tvar(pop, "tvar_end", site.pos + motif.len); document.body.appendChild(pop); position_popup(block, pop); make_block_popup.pop = pop; } else if (e.type === "mouseout") { if (pop) { pop.parentNode.removeChild(pop); make_block_popup.pop = null; } } }; } // // action_show_more // // Show more information on the motif. /// function action_show_more(e) { var node, tr, tbody, table, container, motif, ordinal; var expanded_motif; 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(); } // find the row that contains the cell node = this; do { if (node.tagName === "TR") break; } while (node = node.parentNode); if (!node) throw new Error("Expected to find row!?"); tr = node; // get info motif = tr.data_motif; ordinal = tr.data_ordinal; // find tbody do { if (node.tagName === "TBODY") break; } while (node = node.parentNode); if (!node) throw new Error("Expected to find tbody!?"); tbody = node; // find table do { if (node.tagName === "TABLE") break; } while (node = node.parentNode); if (!node) throw new Error("Expected to find table!?"); table = node; // find container container = node.parentNode; // make a expanded motif motif["expanded"] = true; expanded_motif = make_expanded_motif(current_alphabet, ordinal, motif, container.data_more_x, container.data_submit_x); // now determine how to place it if (tbody.rows.length === 1) { // only us in the table so the table can be replaced container.replaceChild(expanded_motif, table); } else if (tbody.rows[0] === tr) { // first row, so remove and insert an expanded motif before table.deleteRow(tr.rowIndex); container.insertBefore(expanded_motif, table); } else if (tbody.rows[tbody.rows.length - 1] === tr) { // last row, so remove and insert an expanded motif after table.deleteRow(tr.rowIndex); container.insertBefore(expanded_motif, table.nextSibling); } else { var table2, tbody2; table2 = table.cloneNode(false); table2.appendChild(table.tHead.cloneNode(true)); tbody2 = table.tBodies[0].cloneNode(false); table2.appendChild(tbody2); container.insertBefore(table2, table.nextSibling); for (i = tbody.rows.length - 1; i >= 0; i--) { row = tbody.rows[i]; row.parentNode.removeChild(row); if (row === tr) { break; } tbody2.insertBefore(row, tbody2.rows[0]); } container.insertBefore(expanded_motif, table2); } find_child(expanded_motif, "tvar_less").focus(); } // // action_show_less // // Show less information on the motif. /// function action_show_less(e) { var btn; var expanded_motif, container, motif, ordinal, colw, focus_target; var table, tbody, tbody2, row, table_before, table_after; 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(); } btn = this; // find expanded motif expanded_motif = find_parent(btn, "expanded_motif"); if (!expanded_motif) throw new Error("Expected expanded motif."); // find the container container = expanded_motif.parentNode; // get data motif = expanded_motif.data_motif; ordinal = expanded_motif.data_ordinal; colw = container.data_colw; // get the table before table_before = expanded_motif.previousSibling; if (table_before && table_before.tagName !== "TABLE") { table_before = null; } // get the table after table_after = expanded_motif.nextSibling; if (table_after && table_after.tagName !== "TABLE") { table_after = null; } // see if there is a table below or above that we can put this in. // if there is a table both below and above then add this motif and // all ones below to the above table motif["expanded"] = false; if (table_before && table_after) { tbody = table_before.tBodies[0]; row = tbody.insertRow(tbody.rows.length); make_motif_table_entry(row, current_alphabet, ordinal, motif, colw); focus_target = find_child(row.cells[5], "sym_btn"); container.removeChild(expanded_motif); tbody2 = table_after.tBodies[0]; while (tbody2.rows.length > 0) { row = tbody2.rows[0]; row.parentNode.removeChild(row); tbody.appendChild(row); } container.removeChild(table_after); } else if (table_before) { tbody = table_before.tBodies[0]; row = tbody.insertRow(tbody.rows.length); make_motif_table_entry(row, current_alphabet, ordinal, motif, colw); focus_target = find_child(row.cells[5], "sym_btn"); container.removeChild(expanded_motif); } else if (table_after) { tbody = table_after.tBodies[0]; row = tbody.insertRow(0); make_motif_table_entry(row, current_alphabet, ordinal, motif, colw); focus_target = find_child(row.cells[5], "sym_btn"); container.removeChild(expanded_motif); } else { //no table above or below! // make a new table table = make_motifs_table(current_alphabet, ordinal, [motif], colw, data["stop_reason"]); focus_target = find_child(table.tBodies[0].rows[0].cells[5], "sym_btn"); container.replaceChild(table, expanded_motif); } focus_target.focus(); } //TODO -- can we delete this junk? //function action_show_outpop(e) { function fred_action_show_outpop(e) { "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", current_alphabet.has_complement());//TODO 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(current_alphabet.has_complement() ? "submit_tomtom" : "submit_fimo"); //TODO Tomtom might require a more strict definition of DNA default_prog.checked = true; action_outpop_program.call(default_prog); // disable reverse-complement when not DNA $("logo_rc_option").disabled = !current_alphabet.has_complement(); // set errorbars on when ssc is on $("logo_ssc").addEventListener("change", action_outpop_ssc, false); } var node; // 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; } // load the motif logo node = this; do { if (/\bexpanded_motif\b/.test(node.className) || node.tagName === "TR") break; } while (node = node.parentNode); if (node === null) throw new Error("Expected node!"); update_outpop_motif(node.data_ordinal - 1); // display the download popup $("grey_out_page").style.display = "block"; $("download").style.display = "block"; $("outpop_close").focus(); } // fred_action_show_outpop function action_btn_rc(e) { "use strict"; var node, tr, motif, box, logo_box, tab_st, tab_rc, rc; 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(); } node = this; do { if (node.tagName === "TR") break; } while (node = node.parentNode); if (!node) throw new Error("Expected to find row!?"); tr = node; // get info motif = tr.data_motif; box = find_parent(this, "preview_box"); logo_box = find_child(box, "preview_logo_box"); tab_st = find_child(box, "plus"); tab_rc = find_child(box, "minus"); rc = (this === tab_rc); motif["rc"] = rc; toggle_class(logo_box, "show_rc_logo", rc); toggle_class(tab_st, "active", !rc); toggle_class(tab_rc, "active", rc); } function action_rc_tab(e) { "use strict"; var box, logo_box, tab_st, tab_rc, rc; 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(); } box = find_parent(this, "expanded_motif"); logo_box = find_child(box, "tvar_logo"); tab_st = find_child(box, "tvar_tab"); tab_rc = find_child(box, "tvar_tab_rc"); rc = (this === tab_rc); box.data_motif["rc"] = rc; toggle_class(logo_box, "show_rc_logo", rc); toggle_class(tab_st, "activeTab", !rc); toggle_class(tab_rc, "activeTab", rc); } function action_seqs_filter() { "use strict"; var block_container; block_container = $("blocks"); if ($("rdo_all_seqs").checked) { toggle_class(block_container, "hide_empty_seqs", false); toggle_class(block_container, "hide_only_scan", false); } else if ($("rdo_sites_and_scan").checked) { toggle_class(block_container, "hide_empty_seqs", true); toggle_class(block_container, "hide_only_scan", false); } else if ($("rdo_sites_only").checked) { toggle_class(block_container, "hide_empty_seqs", true); toggle_class(block_container, "hide_only_scan", true); } } // // page_loaded // // Called when the page has loaded for the first time. /// function page_loaded() { post_load_setup(); } // // page_loaded // // Called when a cached page is reshown. /// function page_shown(e) { if (e.persisted) post_load_setup(); } // // page_loaded // // Called when the page is resized /// function page_resized() { var page, blocks_scroll; update_scroll_pad(); page = (document.compatMode === "CSS1Compat") ? document.documentElement : document.body; blocks_scroll = $("blocks_scroll"); if (blocks_scroll) { blocks_scroll.style.maxHeight = Math.max(page.clientHeight - 300, 300) + "px"; } } // // pre_load_setup // // Run before the page is displayed /// function pre_load_setup() { var start, hue, sat, light, divisions; var i, j, motifs, motif, sites, site, sequences, sequence; var max_seq_len; motifs = data["motifs"]; sequences = data["sequence_db"]["sequences"]; max_seq_len = 1; if (sequences) { // no sequences if -brief for (i = 0; i < sequences.length; i++) { sequence = sequences[i]; sequence["sites"] = []; if (sequence["length"] > max_seq_len) { max_seq_len = sequence["length"]; } } } data["sequence_db"]["max_length"] = max_seq_len; // use hsl colours start = 0; //red sat = 100; light = 50; for (i = 0; i < motifs.length; i++) { motif = motifs[i]; // give the motif a colour divisions = 1 << Math.ceil(Math.log(i + 1) / Math.LN2); hue = start + (360 / divisions) * ((i - (divisions >> 1)) * 2 + 1); motif["colour"] = "hsl(" + hue + ", " + sat + "%, " + light + "%)"; // associate sites with sequences as well // to make generating the block diagram easier sites = motif["sites"]; for (j = 0; j < sites.length; j++) { site = sites[j]; sequence = sequences[site["seq"]]; // record the motif index site["motif"] = i; // add the site to the sequence sequence["sites"].push(site); } } } // // post_load_setup // // Run when the page has loaded, or been reloaded. // function post_load_setup() { update_scroll_pad(); if (data["motifs"].length > 0) { make_motifs(); if (data.sequence_db.primary_count > data.options.brief) { if (data.options.brief == 1000) { $("blocks").innerHTML = "<p>Output of sites suppressed because there were more than 1000 (primary) sequences.</p>"; } else { $("blocks").innerHTML = "<p>Output of motif locations suppressed by -brief option.</p>"; } } else { make_blocks(); } } else { $("motifs").innerHTML = "<p>No significant motifs found!</p>"; // clear content $("motifs").innerHTML += "<p><b>" + data["stop_reason"] + "</b></p>"; $("blocks").innerHTML = "<p>No significant motifs found!</p>"; } } pre_load_setup(); </script> <script> // // template.js // /* * 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); } } // set_tvar /* * 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); } /* * 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 ''; } } /* * 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; } /* * 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; } </script> <script> // // citation.js // function get_citation_text(doc_type, extra) { var html; switch (doc_type) { case 'AMA': return(get_citation_text("GOMo", extra)); case 'AME': return(extra + ` <span class="citation"> Robert C. McLeay and Timothy L. Bailey, "Motif Enrichment Analysis: a unified framework and an evaluation on ChIP data", <i>BMC Bioinformatics</i>, <b>11</b>:165, 2010. <a href="http://www.biomedcentral.com/1471-2105/11/165">[full text]</a> </span> `); case 'CentriMo': return(extra + ` <span class="citation"> Timothy L. Bailey and Philip Machanick, "Inferring direct DNA binding from ChIP-seq", <i>Nucleic Acids Research</i>, <b>40</b>:e128, 2012. <a href="http://nar.oxfordjournals.org/content/40/17/e128">[Full Text]</a> </span> `); case 'DREME': return(extra + ` <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> `); case 'FIMO': return(extra + ` <span class="citation"> Charles E. Grant, Timothy L. Bailey and William Stafford Noble, "FIMO: Scanning for occurrences of a given motif", <i>Bioinformatics</i> <b>27</b>(7):1017-1018, 2011. <a href="http://bioinformatics.oxfordjournals.org/content/27/7/1017">[full text]</a> </span> `); case 'GLAM2': case 'GLAM2SCAN': return(extra + ` <span class="citation"> Martin C. Frith, Neil F. W. Saunders, Bostjan Kobe and Timothy L. Bailey, "Discovering sequence motifs with arbitrary insertions and deletions", <i>PLoS Computational Biology</i>, <b>4</b>(5):e1000071, 2008. <a href="https://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1000071">[full text]</a> </span> `); case 'GOMo': return(extra + ` <span class="citation"> Fabian A. Buske, Mikael Bodén, Denis C. Bauer and Timothy L. Bailey, "Assigning roles to DNA regulatory motifs using comparative genomics", <i>Bioinformatics</i>, <b>26</b>(7), 860-866, 2010. <a href="http://bioinformatics.oxfordjournals.org/cgi/content/full/26/7/860">[full text]</a> </span> `); case 'MAST': return(extra + ` <span class="citation"> Timothy L. Bailey and Michael Gribskov, "Combining evidence using p-values: application to sequence homology searches", <i>Bioinformatics</i>, <b>14</b>(1):48-54, 1998. <a href="http://bioinformatics.oxfordjournals.org/content/14/1/48">[full text]</a> </span> `); case 'MCAST': return(extra + ` <span class="citation"> Timothy Bailey and William Stafford Noble, "Searching for statistically significant regulatory modules", <i>Bioinformatics (Proceedings of the European Conference on Computational Biology)</i>, <b>19</b>(Suppl. 2):ii16-ii25, 2003. <a href="http://bioinformatics.oxfordjournals.org/cgi/content/abstract/19/suppl_2/ii16">[full text]</a> </span> `); case 'Meta-MEME': return(extra + ` <span class="citation"> William N. Grundy, Timothy L. Bailey, Charles P. Elkan and Michael E. Baker. "Meta-MEME: Motif-based Hidden Markov Models of Protein Families" <i>Computer Applications in the Biological Sciences (CABIOS)</i>, <b>13</b>(4):397-406, 1997. <a href="http://bioinformatics.oxfordjournals.org/content/13/4/397">[full text]</a> </span> `); case 'MEME': return(extra + ` <span class="citation"> Timothy L. Bailey and Charles Elkan, "Fitting a mixture model by expectation maximization to discover motifs in biopolymers", <em>Proceedings of the Second International Conference on Intelligent Systems for Molecular Biology</em>, pp. 28-36, AAAI Press, Menlo Park, California, 1994. <a href="http://www.aaai.org/Papers/ISMB/1994/ISMB94-004.pdf">[full text]</a> </span> `); case 'MEME-ChIP': return(extra + ` <span class="citation"> Philip Machanick and Timothy L. Bailey, "MEME-ChIP: motif analysis of large DNA datasets", <i>Bioinformatics</i> <b>27</b>(12):1696-1697, 2011. <a href="http://bioinformatics.oxfordjournals.org/content/27/12/1696.full">[full text]</a> </span> `); case 'MEME_SUITE': return(extra + ` <span class="citation"> Timothy L. Bailey, James Johnson, Charles E. Grant, William S. Noble, "The MEME Suite", <i>Nucleic Acids Research</i>, <b>43</b>(W1):W39-W49, 2015. <a href="https://academic.oup.com/nar/article/43/W1/W39/2467905">[full text]</a> </span> `); case 'MoMo': return(extra + ` <span class="citation"> Alice Cheng, Charles Grant, Timothy L. Bailey and William Noble, "MoMo: Discovery of statistically significant post-translational modification motifs", <i>Bioinformatics</i>, <b>35</b>(16):2774-2782, 2018. <a href="https://doi.org/10.1093/bioinformatics/bty1058">[full text]</a> </span> `); case 'PSPs': return(extra + ` <span class="citation"> Timothy L. Bailey, Mikael Bodén, Tom Whitington and Philip Machanick, "The value of position-specific priors in motif discovery using MEME", <i>BMC Bioinformatics</i>, <b>11</b>(1):179, 2010. <a href="http://www.biomedcentral.com/1471-2105/11/179">[full text]</a> </span> `); case 'SEA': return(extra + ` <span class="citation"> Timothy L. Bailey and Charles E. Grant, "SEA: Simple Enrichment Analysis of motifs", <i>BioRxiv</i>, August 24, 2021. <a href="https://www.biorxiv.org/content/10.1101/2021.08.23.457422v1">[full text]</a> </span> `); case 'SpaMo': return(extra + ` <span class="citation"> Tom Whitington, Martin C. Frith, James Johnson and Timothy L. Bailey "Inferring transcription factor complexes from ChIP-seq data", <i>Nucleic Acids Res.</i> <b>39</b>(15):e98, 2011. <a href="http://nar.oxfordjournals.org/content/39/15/e98">[full text]</a> </span> `); case 'STREME': return(extra + ` <span class="citation"> Timothy L. Bailey, "STREME: accurate and versatile sequence motif discovery", <i>Bioinformatics</i>, Mar. 24, 2021. <a href="https://academic.oup.com/bioinformatics/advance-article-abstract/doi/10.1093/bioinformatics/btab203/6184861" >[full text]</a> </span> `); case 'Tomtom': return(extra + ` <span class="citation"> Shobhit Gupta, JA Stamatoyannopolous, Timothy Bailey and William Stafford Noble, "Quantifying similarity between motifs", <i>Genome Biology</i>, <b>8</b>(2):R24, 2007. <a href="http://genomebiology.com/2007/8/2/R24">[full text]</a> </span> `); case 'T-Gene': return(extra + ` <span class="citation"> Timothy O'Connor, Charles E. Grant, Mikael Bodén, Timothy L. Bailey, "T-Gene: Improved target gene prediction", <i>Bioinformatics</i>, <b>36</b>(12):3902-3904, 2020. <a href="https://academic.oup.com/bioinformatics/article/36/12/3902/5815978?guestAccessKey=aa625a49-a2aa-4d7a-858e-8bc82867a534">[Full Text]</a> </span> `); case 'XSTREME': return(extra + ` <span class="citation"> Charles E. Grant and Timothy L. Bailey, "XSTREME: comprehensive motif analysis of biological sequence datasets", <i>BioRxiv</i>, September 3, 2021. <a href="https://www.biorxiv.org/content/10.1101/2021.09.02.458722v1">[full text]</a> </span> `); default: return("Unknown program: " + doc_type); } } // get_citation_text // // Function to replace the innerHTML of element "id" with an HTML paragraph // containing the text for 'program', which is known to function get_citation_text. // If "id" is either "citation" or "reference" some extra text is printed. // function print_citation(id, program) { var extra; switch (id) { case 'citation': extra = "If you use " + program + " in your research, please cite the following paper:<br>"; break; case 'reference': extra = "<h5>Reference</h5>"; break; default: extra = ""; break; }; var html = get_citation_text(program, extra); document.getElementById(id).insertAdjacentHTML('beforeend', html); } // print_citation // // Function to convert a citation for a program to a C #define statement. // function print_citation_define(lang, pgm) { var citation = get_citation_text(pgm, ''); citation = citation.replace(/<[^>]*>/g, ''); citation = citation.replace(/\[.*\]/g, ''); citation = citation.replace(/\n\s*/g, '\\n'); citation = citation.replace(/"/g, '\\"'); citation = citation.replace(/é/g, 'e'); citation = citation.replace(/^\\n/, ''); pgm = pgm.replace(/-/, ''); citation = "If you use this program in your research, please cite:\\n\\n" + citation; if (lang == "C") { citation = "#define " + pgm + '_CITE "' + citation + '"'; } else if (lang == "perl") { citation = '"' + pgm + '" => "' + citation + '",'; } return(citation); } // print_citation_define // // Main program (for use with nodejs "node" javascript engine) // to create citation.js.h and citation.pm from citation.js. // The command line: // node citation.js C > citation.js.h // will output the C #define statements for each of the // programs listed below, defining macros <program>_CITE. // The command line: // node citation.js perl > citation.js.pm // will output perl hash <program> => text // // if (typeof process !== 'undefined') { var lang = process.argv[2]; var programs = ['AMA', 'AME', 'CentriMo', 'DREME', 'FIMO', 'GLAM2', 'GLAM2SCAN', 'GOMo', 'MAST', 'MCAST', 'Meta-MEME', 'MEME', 'MEME-ChIP', 'MEME_SUITE', 'MoMo', 'PSPs', 'SEA', 'SpaMo', 'STREME', 'Tomtom', 'T-Gene', 'XSTREME']; if (lang == "C") { console.log("// Do not edit this file. It is created from etc/citation.js."); console.log("#ifndef citation_js_h\n#define citation_js_h\n"); for (var i=0; i<programs.length; i++) { console.log(print_citation_define(lang, programs[i])); } console.log("\n#endif"); } else if (lang == "perl") { console.log("# Do not edit this file. It is created from etc/citation.js."); console.log("package Citation;"); console.log("sub cite {\n my ($pgm) = @_;\n return $citation{$pgm};\n}"); console.log("%citation = ("); for (var i=0; i<programs.length; i++) { console.log(print_citation_define(lang, programs[i])); } console.log(");"); } } </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_wide { position:absolute; z-index:1; width:700px; 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: 25em; 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.prog_logo h3, div.prog_logo h3:hover, div.prog_logo h3:active, div.prog_logo h3:visited { display: block; margin:0; padding:0; font-family: Helvetica, sans-serif; font-size: 0.9em; line-height: 1.5em; letter-spacing: -0.06em; color: black; } div.big.prog_logo { font-size: 18px; } /* These are for centered columns in tables */ td.ctr { text-align: center; } /* These are for the navigation bars at the top of outputs. */ table.navigation { margin-top: 0px; border-collapse:collapse; } table.navigation * td { padding-left: 0px; padding-right: 10px; padding-top: 0px; padding-bottom: 0px; } </style> <style> .block_td { height:25px; } .block_container { position:relative; box-sizing: border-box; height: 25px; padding: 0px; margin: 0px; margin-left: 1em; } .block_label { position: absolute; display: inline-block; padding: 3px; z-index: 4; top: 6px; height: 12px; line-height: 12px; font-size: 12px; background-color: white; border: 1px solid black; -moz-border-radius: 12px; -webkit-border-radius: 12px; border-radius: 12px; transform: translateX(-50%); } .block_motif { position: absolute; z-index: 3; top: 0px; box-sizing: border-box; border: 1px solid black; height: 12px; background-color: cyan; } .block_motif.top { border-bottom-width: 0; } .block_motif.bottom { border-top-width: 0; } .block_motif.scanned_site { opacity: 0.3; } .block_motif.scanned_site.active { opacity: 0.9; } .block_region { position:absolute; z-index:6; height:25px; top:0px; } .block_region.main { z-index:8; } .block_region.scanned_site { z-index:5; } .block_region.scanned_site.main { z-index:7; } .block_region.top { height:13px; } .block_region.bottom { height:13px; top:12px; } .block_rule { position:absolute; z-index:2; width:100%; height:1px; top:12px; left:0px; background-color:gray; } .block_plus_sym { position:absolute; z-index:4; line-height:12px; top:0px; left:-1em; } .block_minus_sym { position:absolute; z-index:4; line-height:12px; top:13px; left:-1em; } .tic_major { position:absolute; top:0em; height:0.5em; width: 2px; margin-left: -1px; background-color: blue; } .tic_minor { position:absolute; top:0em; height:0.2em; width: 1px; margin-left: -0.5px; background-color: blue; } .tic_label { position:absolute; display: inline-block; top:0.5em; height: 1em; color: blue; transform: translateX(-50%); } .block_needle { position:absolute; z-index:4; height:30px; width:1px; top:-2px; background-color:gray; } .block_needle.right { height: 60px; } .block_handle { position: absolute; display: inline-block; z-index: 5; top: 27px; min-width: 3ex; text-align: center; font-size: 12px; line-height: 12px; transform: translateX(-50%); background-color: LightGrey; border:3px outset grey; cursor: pointer; -webkit-user-select: none; /* Chrome/Safari */ -moz-user-select: none; /* Firefox */ -ms-user-select: none; /* IE10+ */ /* Rules below not implemented in browsers yet */ -o-user-select: none; user-select: none; } .block_handle.right { top: 47px; } .legend_container { text-align: right; } .legend_entry { display: inline-block; padding: 5px; } div.legend_swatch { box-sizing: border-box; width: 15px; height: 15px; border: 1px solid black; background-color: cyan; float: left; } div.legend_swatch input { display: none; } .legend_text { line-height: 15px; margin-left: 20px; } </style> <style> /* meme output specific css */ div.pop_block { position:absolute; z-index:5; padding: 5px; border: 1px solid black; display: inline-block; background-color: white; } #measure_match { position: absolute; visibility: hidden; height: auto; width: auto; white-space: nowrap; } div.template { position: absolute; z-index: 1; left: 0; top: 0; visibility: hidden; } table.block_information { margin-left: auto; margin-right: auto; } table.block_information * th { text-align: right; } *.hide_empty_seqs * tr.empty_seq { display: none; } *.hide_only_scan * tr.only_scan { display: none; } *.hide_only_scan * div.scanned_site { display: none; } td.symaction { text-align: center; text-decoration: underline; font-size: 20px; cursor: pointer; } 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.actionbutton { display:inline-block; cursor: pointer; font-size: 18px; line-height:20px; padding: 5px; margin: 10px 0; border: 1px solid black; } div.actionbutton:hover { color:#FFF; background-color:#000; } div.param_box { display: inline-block; margin-right: 20px; } span.param { font-weight: bold; } div.box + div.box { margin-top: 5px; } div.sites_outer { position: relative; padding-top: 20px; /* height of header */ display: inline-block; } div.sites_inner { overflow-x: hidden; overflow-y: auto; max-height: 200px; } table.sites_tbl { border-collapse: collapse; } div.sites_th_inner { position: absolute; top: 0; line-height: 20px; /* height of header */ text-align: left; padding-left: 5px; } th.nopad div.sites_th_inner { padding-left: 0; } div.sites_th_hidden { visibility: hidden; height: 0; padding: 0 10px; } th.nopad div.sites_th_hidden { padding: 0; } div.sites_inner * th { height: 0; } table.sites_tbl { overflow-x: hidden; overflow-y: auto; } .site_num { text-align: right; } .site_name { padding:0px 5px; text-align:left; } .site_strand { padding:0px 5px; text-align:center; } .norc .site_strand, .norc .site_strand_title { display: none; } .site_start { padding:0px 15px; text-align: right; } .site_pvalue { text-align:center; padding:0px 15px; text-align:right; white-space: nowrap; } .lflank, .rflank, .match, .alpha_symbol { font-weight:bold; font-size:15px; font-family: 'Courier New', Courier, monospace; color:gray; } .site.lflank { text-align:right; padding-right:5px; color:gray; } .site.match { text-align:center; } .site.rflank { text-align:left; padding-left:5px; padding-right: 20px; } th.stop_reason { text-align: left; padding-right: 10px; } th.motif_ordinal { } td.motif_ordinal { text-align: right; 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_nsites { text-align: right; padding-right: 10px; } td.motif_nsites { text-align: right; padding-right: 20px; } th.motif_width { text-align: right; padding-right: 5px; } td.motif_width { text-align: right; padding-right: 15px; } 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.motif_download { padding-left: 5px; } td.motif_download { text-align: center; padding-left: 5px; } 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.tabCenter { max-width: 100%; overflow-x: auto; height: 200px; overflow-y: hidden; } canvas.logo_rc { display:none; } .show_rc_logo > canvas { display: none; } .show_rc_logo > canvas.logo_rc { display: block; } canvas.scan_logo { margin-left: 10px; } div.blocks_outer { position: relative; padding-top: 20px; /* height of header */ } div.blocks_inner { overflow-x: hidden; overflow-y: auto; max-height: 200px; } table.blocks_tbl { border-collapse: collapse; width: 100%; } table.blocks_tbl .blockdiag_name { white-space: nowrap } div.blocks_th_inner { position: absolute; top: 0; line-height: 20px; /* height of header */ text-align: left; padding-left: 5px; } th.nopad div.blocks_th_inner { padding-left: 0; } div.blocks_th_hidden { visibility: hidden; height: 0; padding: 0 10px; } th.nopad div.blocks_th_hidden { padding: 0; } div.blocks_inner * th { height: 0; } table.blocks_tbl { overflow-x: hidden; overflow-y: auto; } td.block_td { width: 99%; } *.blockdiag_num { text-align: right; } td.blockdiag_name { text-align: left; padding:0px 10px; } td.blockdiag_pvalue { padding:0px 10px; text-align:right; white-space: nowrap; } div.preview_btn { border: 2px solid white; height: 16px; width: 16px; font-size: 12px; line-height: 16px; text-align: center; cursor: pointer; } div.preview_btn + div.preview_btn { margin-top: 3px; } div.preview_btn.active { border: 2px solid black; cursor: default; } div.preview_btn:hover { background-color: black; color: white; border-color: black; } div.preview_btn.active:hover { background-color: white; color: black; border-color: black; } div.preview_btn_box { position: absolute; left: 0px; top: 0px; padding: 3px; } div.preview_logo_box { height: 50px; overflow-y: hidden; } div.preview_btn_box + div.preview_logo_box { margin-left: 25px; } div.preview_box { position: relative; } 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; } div.programs_scroll { width: 100%; height: 90px; overflow-y: auto; overflow-x: hidden; margin: 0 auto; } table.inputs, table.alpha_bg_table { margin-top: 20px; border-collapse:collapse; } table.inputs * td, table.inputs * th, table.alpha_bg_table * td, table.alpha_bg_table * th { padding-left: 15px; padding-right: 15px; padding-top: 1px; padding-bottom: 1px; } table.hide_psp td.col_psp, table.hide_psp th.col_psp { display: none; } table.hide_control td.col_control, table.hide_control th.col_control { display: none; } /* program settings */ span.mod_oops, span.mod_zoops, span.mod_anr { display: none; } td.oops span.mod_oops,td.zoops span.mod_zoops, td.anr span.mod_anr { display: inline; } 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; } span.spmap_uni, span.spmap_pam { display: none; } td.uni span.spmap_uni, td.pam span.spmap_pam { display: inline; } span.prior_dirichlet, span.prior_dmix, span.prior_mega, span.prior_megap, span.prior_addone { display: none; } td.dirichlet span.prior_dirichlet, td.dmix span.prior_dmix, td.mega span.prior_mega, td.megap span.prior_megap, td.addone span.prior_addone { display: inline; } span.noendgaps_on, span.noendgaps_off { display: none; } td.on span.noendgaps_on, td.off span.noendgaps_off { display: inline; } span.substring_on, span.substring_off { display: none; } td.on span.substring_on, td.off span.substring_off { display: inline; } </style> </head> <body onload="page_loaded()" onpageshow="page_shown(event)" onresize="page_resized()"> <!-- --> <div id="grey_out_page" class="grey_background" style="display:none;"> </div> <!-- Help popups --> <div class="pop_content" id="pop_results_txt"> <p>MEME results in plain text format.</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_results_xml"> <p>MEME results in XML format.</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_"> <p>Help poup.</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_logo"> <script>print_doc_para("pop_logo", "discovery", "motif_logo", site_url);</script> Click on the "+" or "-" buttons to the left of the motif to see the forward or reverse complement of the motif if available. <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_ev"> <p>The statistical significance of the motif. MEME usually finds the most statistically significant (low E-value) motifs first. It is unusual to consider a motif with an E-value larger than 0.05 significant so, as an additional indicator, MEME displays these greyed out.</p> <p>The E-value of a motif is based on its log likelihood ratio, width, sites, the background letter frequencies (given in the command line summary), and the size of the training set.</p> <p>The E-value is an estimate of the expected number of motifs with the given log likelihood ratio (or higher), and with the same width and site count, that one would find in a similarly sized set of random sequences (sequences where each position is independent and letters are chosen according to the background letter frequencies).</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_sites"> <p>The number of sites contributing to the construction of the motif.</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_width"> <p>The width of the motif. Each motif describes a pattern of a fixed width, as no gaps are allowed in MEME motifs.</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_more"> <script>print_doc_para("pop_more", "discovery", "more");</script> <div class="pop_close">[<a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_submit_dl"> <script>print_doc_para("pop_submit_dl", "discovery", "submit_dl", "https://meme-suite.org/meme");</script> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_llr"> <p>The log likelihood ratio of the motif. The log likelihood ratio is the logarithm of the ratio of the probability of the occurrences of the motif given the motif model (likelihood given the motif) versus their probability given the background model (likelihood given the null model). (Normally the background model is a 0-order Markov model using the background letter frequencies, but higher order Markov models may be specified via the -bfile option to MEME.).</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_ic"> <p>The information content of the motif in bits. It is equal to the sum of the uncorrected information content, R(), in the columns of the motif. This is equal relative entropy of the motif relative to a uniform background frequency model.</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_re"> <p>The relative entropy of the motif.</p> <p style="font-family: monospace;">re = llr / (sites * ln(2))</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_bt"> <p>The Bayes Threshold.</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_site_strand"> <p>The strand used for the motif site.</p> <dl> <dt>+</dt> <dd>The motif site was found in the sequence as it was supplied.</dd> <dt>-</dt> <dd>The motif site was found in the reverse complement of the supplied sequence.</dd> </dl> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_site_start"> <p>The position in the sequence where the motif site starts. If a motif started right at the beginning of a sequence it would be described as starting at position 1.</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_site_pvalue"> <p>The probability that an equal or better site would be found in a random sequence of the same length conforming to the background letter frequencies.</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_site_match"> <p>A motif site with the 10 flanking letters on either side.</p> <p>When the site is not on the given strand then the site and both flanks are reverse complemented so they align.</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_seq_name"> <p>The name of the sequences as given in the FASTA file.</p> <p>The number to the left of the sequence name is the position of the sequence in the input sequence file.</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_motif_sites"> <p>These are the motif sites predicted by MEME and used to build the motif.</p> <p>These sites are shown in solid color and hovering the cursor over a site will reveal details about the site. Only sequences that contain a motif site are shown.</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_scanned_sites"> <p>These are the motif sites predicted by MEME plus any additional sites detected using a motif scanning algorithm.</p> <p>These MEME sites are shown in solid color and additional scanned sites are shown greyed out. Hovering the cursor over a site will reveal details about the site. Only sequences containing a predicted or scanned motif site are shown.</p> <p>The scanned sites are predicted using a log-odds scoring matrix constructed from the MEME sites. Only scanned sites with position <i>p</i>-values less than 0.0001 are shown.</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_all_sequences"> <p>These are the same sites as shown by selecting the "Motif Sites + Scanned Sites" button except that all sequences, including those with no sites, are included in the diagram.</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_seq_pvalue"> <p>This is the combined match <i>p</i>-value.</p> <p>The combined match <i>p</i>-value is defined as the probability that a random sequence (with the same length and conforming to the background) would have position <i>p</i>-values such that the product is smaller or equal to the value calculated for the sequence under test.</p> <p>The position <i>p</i>-value is defined as the probability that a random sequence (with the same length and conforming to the background) would have a match to the motif under test with a score greater or equal to the largest found in the sequence under test.</p> <p>Hovering your mouse over a motif site in the motif location block diagram will show its position <i>p</i>-value and other information about the site.</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_download_pdf_motif_locations"> <p>Use this button to download the "Motif Locations" block diagrams as a PDF image suitable for publication. </p> <p> Only the block diagrams currently visible in the inner scrolling window (below) will be included in the image, and the numbers to the left of each sequence name will not be included in the image. You can change the size of the inner scrolling by moving the bottom of the main document window up and down. You can display more diagrams by making your browser's font size smaller. </p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_download_svg_motif_locations"> <p>Use this button to download the "Motif Locations" block diagrams as a SVG image use in HTML documents. </p> <p> Only the block diagrams currently visible in the inner scrolling window (below) will be included in the image, and the numbers to the left of each sequence name will not be included in the image. You can change the size of the inner scrolling by moving the bottom of the main document window up and down. You can display more diagrams by making your browser's font size smaller. </p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_offline"> <p> This button will only function if your browser was connected to the internet when you loaded this page. </p> <p> To use this button, make sure your browser is connected to the internet and then reload this page. (You may need to do a "hard refresh" to clear the cache. On Mac, hold down the Shift key and click the Reload button. On Windows/Linux, hold down Ctrl and press F5.) </p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_motif_location"> <p>This diagram shows the location of motif sites.</p> <p>Each block shows the position and strength of a motif site. The height of a block gives an indication of the significance of the site as taller blocks are more significant. The height is calculated to be proportional to the negative logarithm of the <i>p</i>-value of the site, truncated at the height for a <i>p</i>-value of 1e-10.</p> <p>For complementable alphabets (like DNA), sites on the positive strand are shown above the line, sites on the negative strand are shown below.</p> <p>Placing the cursor over a motif site will reveal more information about the site including its position <i>p</i>-value. (See the help for the <i>p</i>-value column for an explanation of position <i>p</i>-values.)</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_seq_source"> <p>The name of the file(s) of sequences input to MEME.</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_psp_source"> <p>The position specific priors file used by MEME to find the motifs.</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_seq_alph"> <p>The alphabet used by the sequences.</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_seq_count"> <p>The number of FASTA sequences provided in this input file.</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_num_positions"> <p>The number of characters in the sequences provided in this FASTA input file.</p> <div style="float:right; bottom:0px;">[ <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 style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_alph_freq"> <p>The frequency of the alphabet symbol in the dataset.</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <div class="pop_content" id="pop_alph_bg"> <p>The frequency of the alphabet symbol as defined by the background model.</p> <div style="float:right; bottom:0px;">[ <a href="javascript:help_popup()">close</a> ]</div> </div> <!-- templates --> <div id="measure_match" class="match"></div> <div class="template pop_block" id="tmpl_block_info"> <div> <span class="tvar_logo_pad lflank" style="visibility:hidden;"></span> <span class="tvar_logo"></span> </div> <div class="block_sequence_fragment"> <span class="tvar_lflank lflank"></span> <span class="tvar_match match"></span> <span class="tvar_rflank rflank"></span> </div> <table class="block_information"> <tr><th>Motif</th><td class="tvar_motif">1</td></tr> <tr><th><i>p</i>-value</th><td class="tvar_pvalue">8.23e-7</td></tr> <tr><th>Start</th><td class="tvar_start">23</td></tr> <tr><th>End</th><td class="tvar_end">33</td></tr> </table> </div> <div class="template pop_block" id="tmpl_scan_info"> <h5>Scanned Site</h5> <div class="tvar_logo"></div> <table class="block_information"> <tr><th>Motif</th><td class="tvar_motif">1</td></tr> <tr><th><i>p</i>-value</th><td class="tvar_pvalue">8.23e-7</td></tr> <tr><th>Start</th><td class="tvar_start">23</td></tr> <tr><th>End</th><td class="tvar_end">33</td></tr> </table> </div> <div class="template box expanded_motif" id="tmpl_motif_expanded"> <div style="position: relative; min-height: 20px"> <div class="param_box"> <span class="param"><span class="tvar_ordinal"></span>.</span> </div> <div class="sym_btn positioned tvar_less" tabindex="0" title="Show less information.">↥</div> <div class="sym_btn positioned tvar_submit" tabindex="0" title="Submit the motif to another MEME Suite program or download it.">⇢</div> </div> <div> <div class="param_box"> <span class="param"><i>E</i>-value:</span> <span class="tvar_evalue"></span> <div class="help" data-topic="pop_ev"></div> </div> <div class="param_box"> <span class="param">Site Count:</span> <span class="tvar_site_count"></span> <div class="help" data-topic="pop_sites"></div> </div> <div class="param_box"> <span class="param">Width:</span> <span class="tvar_width"></span> <div class="help" data-topic="pop_width"></div> </div> </div> <div class="tabMain base"> <div class="tabCenter tvar_logo"></div> </div> <div class="tabArea base"> <span class="tvar_tab tab" tabindex="0">Standard</span><span class="tvar_tab_rc tab middle" tabindex="0">Reverse Complement</span> </div> <div style="padding: 10px 0"> <div class="param_box"> <span class="param">Log Likelihood Ratio:</span> <span class="tvar_llr"></span> <div class="help" data-topic="pop_llr"></div> </div> <div class="param_box"> <span class="param">Information Content:</span> <span class="tvar_ic"></span> <div class="help" data-topic="pop_ic"></div> </div> <div class="param_box"> <span class="param">Relative Entropy:</span> <span class="tvar_re"></span> <div class="help" data-topic="pop_re"></div> </div> <div class="param_box"> <span class="param">Bayes Threshold:</span> <span class="tvar_bt"></span> <div class="help" data-topic="pop_bt"></div> </div> </div> <div class="tvar_sites"></div> </div> <div id="tab_submit_or_download_motif"></div> <script> make_submit_or_download_motif_form("tab_submit_or_download_motif", site_url, "MEME"); </script> <!-- Page starts here --> <div id="top" class="pad1"> <div class="prog_logo big"> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABGCAYAAACUsCfoAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9wLHAInL7an9JAAAA8eSURBVHja7ZpZbxv3ucZ/s3AZ7qQkypZELZS3WHKiRJbTFnHqOjZcGzCQBf0A7cUB8glOb89dz30vChRp7xK0aZo4TYq6dtKqSew6iuJWpmPJlrVFFCmKI+7LLJw5F81MFZyec5rTILJaP8AAnAty+Pzf933ebeAhHuIhHuIhHmJPo6TpaeGLfimTydhLS0sUCgWazSbVahXDMOh0Ong8HiKRCAMDAxw+fJhHH31UeFDJ/91/bHp62r558ya6rmOaJuvr6+TzeYrFIoZhAOD1epFlmWAwSDqdZnR0lCNHjjA+Ps7+/fuFPUU8k8nYV69epVKpEA6HuXPnDrOzs7RaLbxeL93d3fj9foLBIB6Ph0ajQaVSAUBRFNLpNI888ggHDhzg3Llzwp4g/vbbb9szMzPE43FyuRwffPAB2WyWnp4ehoaGiMVi2LZNvV6n3W7j8/mIRqN4vV4ajQa1Wo2trS0OHTqEaZo89dRTfO973xMeaOKvvfaaffv2bcLhMCsrK/z+979HVVWOHz/O0NAQxWIRVVVRVRW/348oihiGgSiKxGIxurq6CAQCBINB3n//fcbGxiiXyxw7dowXX3yx1Nvbm3igiBcKhY9u3rw5OTMzQzgc5vbt23zwwQfIsszExAS2bZPP55EkiVAoRCQSIRwOI8sy5XKZ7e1tWq0WnU6HTqfD4OAggUAAVVXpdDo0m01GRkb44Q9/KDxQxH/729/as7Oz+Hw+Pv30U37zm9/g9Xrp6emht7eXYDCI3+/H6/UiCALtdhvLsuh0OkiSRCAQQJZl6vU65XKZ1dVV+vv7SSQS5PN5vF4vhUKBgwcP8qMf/WjXyIs7b+7cuWMvLi4iCAL1ep133nkHXdcZHh4mlUoRDofp7+8nHo9jGAaCIBCPx+nr6yOdTtPX14fH40HTNGRZpqenh76+PrLZLMVikYGBARRFwTRN5ubm+PGPf2zvFnF5583c3BzlchlZlrl16xa1Wo2xsTGi0SiDg4OutUzTJBKJIIoiXq+XQCBAIpEgFAphmiaqqlIoFKjVaoyOjhKJRFhfXycajRKNRunp6WFhYYG33nqLQqHwUTKZPP5VE5ecD5cvX7bv37+Poijkcjl++ctfMjo6ytDQEMlkEo/HQ7lcpt1u4/F4kGUZQRDw+Xz09fVx4MABRkZGSKVSdHV10el0KJVK1Ot14vE4kiRRKpVQFIV4PI5t23z66ad0Op2+K1eu/MeuWVxVVUzTRNd17t27RzKZJJFIEI1GEUWRdruNaZqIoogkSYiiiCiK+P1+AoEA0WiUQ4cOCQCbm5vb5XI5Xi6XWVtbw7ZtZFnG7/e7D1YUhWAwSLVaJZvN2v39/cJXHuOLi4t2sVhEEAS2t7eZn59n//79JBIJwuEwlmXRbDbRdR1BEBAEAcuysCwL2/5LmIriX+Wit7c3EY/HSSQSeDweDMPA4/EQCoWwbRvbtgmFQoTDYUqlErlcbnfE7f79+64gbWxs0G63icViRCIRBEHANE0Mw0CSJLxer0vSUfVKpUKxWGRtbc12UmKr1cI0TQD3t4PBoHtwgUAAv99Ps9kkn8/vjrjlcjlkWabdbrO8vEx3dzfhcJhoNEq9XkfTNERRxOfz4fV6sW0bSZJcBS+VSqytrdFqtbh+/bq9sLBALpdje3sbXddd4jutLwh/8WzLslBVdXeI12o1RFFkc3PTLTFjsRixWAxVVbEsC1mWkSTJdVXnMgyDarWKrusUi0X8fj+WZVGtVimXyxiGgW3bblh4PB78fj/tdhvbthFF0a3tv3Liuq4jiiKFQgFZlolEInR3d6MoConEXytLp1Bx0Ol0sG0bXdfRdZ1arYYgCNi2jaZptFot1zOcQ3LSnxMGzsHvCnHH/RqNBtFoFEmSCIfDAAwNDWFZFu12m0ajgaZpWJbl/oDH4/ncoTii5xBz1N+2bTqdDrIs4/P53MxgWRaapu2exQOBgHsAnU6HdrvN5uYmgUCASCRCJBIhkUhgmibNZpNarUaj0XAt71jfET1RFN1YliTJfUa73SaZTLK1tUWtVkPTNKampnaHuFNGyrKM1+t141bTNGq1GrVazS1EIpEI8XjcLWJqtdrnYthNF58pv23beL1eJEly1VzXder1Oq1Wi2AwiK7ru0PcSSs73bBYLBIMBpEkCdM0qVQq6LpOq9UiHA673Vmn08E0TfdyRM85CNM08Xq9bkoMhULugRqGgd/v3z1Xl2X5c24aDodRVZV4PO7W406/raoqtVqNYDCIz+dDURQ3vp3LuXeEz4nlTqdDOBxG13U3TBRF2b0mJRAI0Gg0EAQBTdPw+/2Uy2VXoJzRkkPEifNWq0UgEHCLEsedLcty1X1nzIdCIRRFoVQqUSqVsCyLYDBIPB7fncotlUq5JaWu6xiGgWmabG1tuanINE0EQXAPwSlk6vU6zWaTdruNpmnud3eWsk6fnkwmMU2Tzc1NVFVFURSi0SjpdHp3iB89ehRRFOnt7XWHCNFolFwu58ar08AYhuEWNH6/H4/H8zlL71R4J5XJskwgECAWi5HP51lZWaHVajE8PEw8Hufw4cO7Q3zfvn0C4E5MNU2jq6uLarVKPp//nPA5hYgzcYlEIoRCIfcQHLd3SDvEPR4PHo+HfD5PPp9HEARGRkYIhUIMDQ0Ju0Ic4NixY3g8Hnp7e8lms8RiMcLhMNlsFk3TXHW3bZtgMOjmfScEvF6vW8s7qczxgGazSSAQ4M9//jOqqlKpVHj88cfx+XyMjY3t7ujp1KlTQrlcdicupVKJkZER1tbWuHfvHqqqEolEiMVitNtt6vW6q+iNRoNms4kkSfh8PtfC0WgURVHo7+9nc3OTjY0N3n33XQYGBkilUiSTSU6ePCnsKnGA559/nkqlwtGjR8nn8/j9fh5//HEsy+LWrVvMz8+j6zqhUAifz4dhGG7z0mq1UFUVXdeJRCIEg0F32loqlbh37x53796lq6sLRVGIRCJMTEzs2pT1c8Qfe+wxYWpqyv1j2WyWVCpFIpGgUqkwNzfHnTt33JTnDCUlSaK7u5v+/n66u7vxeDxun16r1SgUCly/fp3bt29z+vRpBgcHqdVqRKPRB2uh8LOf/cyemZlhYWGBYDBIJBIBoFgs0mw2CYfDxONxfD4fg4ODros7vXWhUKDT6bg5/v3332dlZYWhoSHS6TSnTp1i3759VKtVzpw5w1c9dvpfNymvvPKKff36dbLZLIqiuBVWs9mk0WhgWZbbn4fDYURRRNM0AoEAvb29+Hw+Go0Gly9fZmNjg4mJCcbGxti/f787mJyfn6darTI5OcmJEyeEB4J4sVj8wfT09L/Pzs6SzWbdpWEikXBJGoZBs9kkGo0iyzKmabrLhtXVVTKZDJubm5w9e5YjR44wMDDAd7/7XWF2dtZeXFzkyJEj7pZm//79pFIpenp6vhIP+D8f8NZbb9nr6+ssLy+ztbXl1t5er9fdhxeLRSRJoquri0qlQiaTYXt7m0gkwpkzZ5BlmbGxMV544QX3eR9//LE9Pz/PsWPHuHHjBouLi0iSxMDAAMePH2dqakrYVeIAKysr9u3bt1leXnZn65qmoeu6W9AYhkGj0aBYLGKaJocOHeLRRx8lkUgwOTnpjp4d5HI5++OPP6ZcLjM+Ps61a9dYWFig2Wzi9Xp5/vnnOX36tLCrxHfi1q1b9tLSkuv+9XrdbTEVRSEWi5FMJhkdHWV4eJiDBw/+j8/Y2tr6+WuvvfYdwzBIpVJIkoSqqszPz1Ov17lw4QJf+9rXziYSiau7TvxvoVQqpUul0n2n2/oibz+899579k9/+lPC4TCnTp3i61//Orlcjp/85CdomsbTTz/NiRMn/pvH/CMotrQfyF/GD8Xj8aX/7yEePnx4dnx8fPJ3v/sdiqIwODjI5OSkcOPGDfvNN9/kypUr5PN5MpmMPT4+/qWQ71Z835fZZSSTyeMrKyt2vV7n7t27vPrqq1y7ds1+8sknhT/+8Y/2pUuXuHnzJs1mk6WlJTudTn8p5EUeAAwPDwvPPfccBw4cYHV1lc+KJ3t0dPTVixcvcvDgQebn53n55ZeZmZn5h1fLalv/twfqTaRMJmP/4he/YH19nSNHjnDhwgVisRj37t3jnXfeYWFhgQMHDnD+/HmeeuopYc9b3MH4+LjwrW99C0EQuHXrFtPT09RqNfr7+zlx4gTpdJqNjQ3efPNN3njjDbtYLP5gV1X9y8bly5ft119/nUqlwsmTJzl9+jQej4ePPvqITz75hLW1NYLBIJOTk5w7d46+vr4vzEN+EImfO3dOuHr1qv3666/z3nvvoWkaZ8+e5YknnnBXU5qmcfPmTQzDYG1tzR4cHBT2vMUdTE9P25cuXaJQKDA5OcmFCxfQdZ3Z2VkWFhbY2NhAURRSqRTPPvssY2Njwp62uINvfvObwp/+9Cf7V7/6FTdu3KDT6XD+/HmmpqbcoaaqqszOzmIYxhfK9Q80cYCJiQlhbm7OFgSBubk5vF4vzzzzDBMTE+7CMRgMsrCwwEsvvcS1a9fsb3zjG8KedvWd+OSTT+y3336bubk5JicnOXnyJJZl8eGHH7K2tkahUKDRaLBv3z4uXrzI2bNnhT1tcQdHjx4VMpmM3el0WFxcJBQKMTU1xbFjx6hWqwC0221WVlb49a9/zY0bN+wnn3xS2BN5/O/J88899xzDw8NkMhnm5uaIx+M8/fTT9PT0YFkWg4ODrK6u8sorrzA/P2/veVffidXVVfvdd99lenqa8+fPMzo6iqZp/OEPf2BhYYFWq4Usy4yMjHDx4kX+luXlvUh8aGhImJmZsS3L4vr165imSSqVYt++fbTbbWq1GtVqlWq1yt27d7l//749Ojoq7HniAFNTU8LS0pJdLpe5e/cu6+vrRCIRhoeHqVarrK6uous66+vrZLNZSqVS+rP2eW8TB0in00I2m3XVHqCvr49YLEYikXBfRiqXy+Ryufs7Q1tkj6O/v1/49re/zTPPPIMgCMzPz7sraJ/Ph9/vd/d3pVIp/U9hcQdOnX7p0iU7k8kgiqK76lIUxX19dKerC/wTYXt7+8zm5uaV5eVlNjY2iMfj+P1+hoeH6enpmd35evg/FXEHm1uF7ZXltXgg6EcSPSR7u/+zO9H1ff6VsFWq/pyHeIiHeIh/FfwXjVDdIW9O2PAAAAAASUVORK5CYII=" alt="MEME Logo"> <h1>MEME</h1> <h2>Multiple Em for Motif Elicitation</h2> </div> <p> For further information on how to interpret these results please access <a href="https://meme-suite.org/meme/doc/meme.html">https://meme-suite.org/meme/doc/meme.html</a>. <br /> To get a copy of the MEME software please access <a href="https://meme-suite.org">https://meme-suite.org</a>. </p> <p id="citation"> <script>print_citation("citation", "MEME");</script></p> </div> <!-- navigation --> <div class="pad2"> <a class="jump" href="#motifs_sec">Discovered Motifs</a> | <a class="jump" href="#sites_sec">Motif Locations</a> | <a class="jump" href="#inputs_sec">Inputs & Settings</a> | <a class="jump" href="#info_sec">Program Information</a> | <a class="jump" href="meme.txt">Results in Text Format</a> <span id="results_txt_help"></span> | <a class="jump" href="meme.xml">Results in XML Format</a> <span id="results_xml_help"></span> <script> make_help_button($("results_txt_help"), "pop_results_txt"); make_help_button($("results_xml_help"), "pop_results_xml"); </script> </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> <h2 class="mainh pad2" id="motifs_sec">Discovered Motifs</h2> <div id="motifs" class="box"> <p>Please wait... Loading...</p> <p>If the page has fully loaded and this message does not disappear then an error may have occurred.</p> </div> <h2 class="mainh pad2" id="sites_sec">Motif Locations</h2> <div id="blocks" class="box"> <p>Please wait... Loading...</p> <p>If the page has fully loaded and this message does not disappear then an error may have occurred.</p> </div> <h2 class="mainh pad2" id="inputs_sec">Inputs & Settings</h2> <div class="box"> <h4>Sequences</h4> <table id="seq_info" class="inputs"> <tr> <th>Role <div class="help" data-topic="pop_seq_role"></div></th> <th>Source <div class="help" data-topic="pop_seq_source"></div></th> <th class="col_psp">PSP Source <div class="help" data-topic="pop_psp_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> <th>Total Size <div class="help" data-topic="pop_num_positions"></div></th> </tr> <tr> <td>Primary Sequences</td> <td id="ins_seq_source"></td> <td id="ins_seq_psp" class="col_psp"></td> <td id="ins_seq_alphabet"></td> <td id="ins_seq_count"></td> <td id="ins_num_positions"></td> </tr> <tr class="col_control"> <td class="col_control">Control Sequences</td> <td id="ins_control_source" class="col_control"></td> <td id="ins_control_psp" class="col_control col_psp"></td> <td id="ins_control_alphabet" class="col_control"></td> <td id="ins_control_count" class="col_control"></td> <td id="ins_control_positions" class="col_control"></td> </tr> </table> <script> { var db = data.sequence_db; $("ins_seq_source").innerHTML = db.primary_source; $("ins_seq_alphabet").innerHTML = current_alphabet.get_alphabet_name(); $("ins_seq_count").innerHTML = db.primary_count; $("ins_num_positions").innerHTML = db.primary_positions; $("ins_control_source").innerHTML = db.control_source; $("ins_control_alphabet").innerHTML = current_alphabet.get_alphabet_name(); $("ins_control_count").innerHTML = db.control_count; $("ins_control_positions").innerHTML = db.control_positions; if (db.psp_source) { $("ins_seq_psp").innerHTML = db.psp_source; } toggle_class($("seq_info"), "hide_psp", !(db.psp_source)); toggle_class($("seq_info"), "hide_control", (db.control_source == "--none--")); } </script> <h4>Background Model</h4> <span id="bg_source"></span> <span id="bg_order"></span> <span id="alpha_bg"></span> <script> { $("bg_source").appendChild(make_background_source("Source", data.background.source, false)); $("bg_order").innerHTML = " <b>Order:</b> " + data.background.order + (data.background.order>0 ? " (only order-0 shown)" : ""); $("alpha_bg").appendChild(make_alpha_bg_table(current_alphabet, data.sequence_db.freqs)); } </script> <h4>Other Settings</h4> <table id="tbl_settings" class="inputs hide_advanced"> <tr> <th>Motif Site Distribution</th> <td id="opt_mod"> <span class="mod_zoops">ZOOPS: Zero or one site per sequence</span> <span class="mod_oops">OOPS: Exactly one site per sequence</span> <span class="mod_anr">ANR: Any number of sites per sequence</span> </td> </tr> <tr> <th>Objective Function</th> <td id=opt_objfun></td> </tr> <tr> <th>Starting Point Function</th> <td id=opt_spfun></td> </tr> <tr> <th>Site Strand Handling</th> <td id="opt_strand"> <span class="strand_none">This alphabet only has one strand</span> <span class="strand_given">Sites must be on the given strand</span> <span class="strand_both">Sites may be on either strand</span> </td> </tr> <tr> <th>Maximum Number of Motifs</th> <td id="opt_nmotifs"></td> </tr> <tr> <th>Motif E-value Threshold</th> <td id="opt_evt"></td> </tr> <tr> <th>Minimum Motif Width</th> <td id="opt_minw"></td> </tr> <tr> <th>Maximum Motif Width</th> <td id="opt_maxw"></td> </tr> <tr> <th>Minimum Sites per Motif</th> <td id="opt_minsites"></td> </tr> <tr> <th>Maximum Sites per Motif</th> <td id="opt_maxsites"></td> </tr> <tr class="advanced"> <th>Bias on Number of Sites</th> <td id="opt_wnsites"></td> </tr> <tr class="advanced"> <th>Sequence Prior</th> <td id="opt_prior"> <span class="prior_dirichlet">Simple Dirichlet</span> <span class="prior_dmix">Dirichlet Mixture</span> <span class="prior_mega">Mega-weight Dirichlet Mixture</span> <span class="prior_megap">Mega-weight Dirichlet Mixture Plus</span> <span class="prior_addone">Add One</span> </td> </tr> <tr class="advanced"> <th>Sequence Prior Source</th> <td id="opt_prior_source"></td> </tr> <tr class="advanced"> <th>Sequence Prior Strength</th> <td id="opt_b"></td> </tr> <tr class="advanced"> <th>EM Starting Point Source</th> <td id="opt_substring"> <span class="substring_on">From substrings in input sequences</span> <span class="substring_off">From strings on command line (-cons)</span> </td> </tr> <tr class="advanced"> <th>EM Starting Point Map Type</th> <td id="opt_spmap"> <span class="spmap_uni">Uniform</span> <span class="spmap_pam">Point Accepted Mutation</span> </td> </tr> <tr class="advanced"> <th>EM Starting Point Fuzz</th> <td id="opt_spfuzz"></td> </tr> <tr class="advanced"> <th>EM Maximum Iterations</th> <td id="opt_maxiter"></td> </tr> <tr class="advanced"> <th>EM Improvement Threshold</th> <td id="opt_distance"></td> </tr> <tr class="advanced"> <th>Maximum Search Size</th> <td id="opt_searchsize"></td> </tr> <tr class="advanced"> <th>Maximum Number of Sites for E-values</th> <td id="opt_csites"></td> </tr> <tr class="advanced"> <th>Trim Gap Open Cost</th> <td id="opt_wg"></td> </tr> <tr class="advanced"> <th>Trim Gap Extend Cost</th> <td id="opt_ws"></td> </tr> <tr class="advanced"> <th>End Gap Treatment</th> <td id="opt_noendgaps"> <span class="noendgaps_on">No cost</span> <span class="noendgaps_off">Same cost as other gaps</span> </td> </tr> <tr> <td colspan="2" style="text-align: center"> <a href="javascript:toggle_class(document.getElementById('tbl_settings'), 'hide_advanced')"> <span class="show_more">Show Advanced Settings</span> <span class="show_less">Hide Advanced Settings</span> </a> </td> </tr> </table> <script> { $("opt_mod").className = data.options.mod; $("opt_objfun").textContent = data.options.objfun; $("opt_spfun").textContent = data.options.spfun; $("opt_strand").className = (current_alphabet.has_complement() ? (data.options.revcomp ? "both" : "given") : "none"); $("opt_nmotifs").textContent = data.options.nmotifs; $("opt_evt").textContent = (typeof data.options.evt === "number" ? data.options.evt : "no limit"); $("opt_minw").textContent = data.options.minw; $("opt_maxw").textContent = data.options.maxw; $("opt_minsites").textContent = data.options.minsites; $("opt_maxsites").textContent = data.options.maxsites; $("opt_wnsites").textContent = data.options.wnsites; $("opt_spmap").className = data.options.spmap; $("opt_spfuzz").textContent = data.options.spfuzz; $("opt_prior").className = data.options.prior; if (data.options.prior == "dirichlet") { $("opt_prior_source").textContent = make_background_source("Source", data.background.source, true); } else { $("opt_prior_source").textContent = (data.options.prior == "addone") ? "motif observed frequencies" : data.options.priors_source; } $("opt_b").textContent = (data.options.b < 0) ? "not applicable" : (data.options.b == 0) ? "intrinsic strength" : data.options.b; $("opt_maxiter").textContent = data.options.maxiter; $("opt_distance").textContent = data.options.distance; $("opt_searchsize").textContent = data.options.searchsize; if (typeof data.options.csites != "undefined") { $("opt_csites").textContent = data.options.csites; } else { $("opt_csites").parentElement.style.display = "none" } if (typeof data.options.wg != "undefined") { $("opt_wg").textContent = data.options.wg; } else { $("opt_wg").parentElement.style.display = "none" } if (typeof data.options.ws != "undefined") { $("opt_ws").textContent = data.options.ws; } else { $("opt_ws").parentElement.style.display = "none" } if (typeof data.options.noendgaps != "undefined") { $("opt_noendgaps").className = (data.options.noendgaps ? "on" : "off"); } else { $("opt_noendgaps").parentElement.style.display = "none" } $("opt_substring").className = (data.options.substring ? "on" : "off"); } </script> </div> <!-- list information on this program --> <div id="info_sec" class="bar"> <div class="subsection"> <h5 id="version">MEME 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" id="reference"> <script>print_citation("reference", "MEME");</script></div> <div class="subsection"> <h5 id="command">Command line</h5> <textarea id="cmd" rows="5" style="width:100%;" readonly="readonly"> </textarea> <script>$("cmd").value = data["cmd"].join(" ");</script> </div> </div> </body> </html>