Mercurial > repos > iuc > meme_meme
comparison test-data/meme_output_test1.html @ 14:3f0dd362b755 draft
"planemo upload for repository https://github.com/galaxyproject/tools-iuc/tree/master/tools/meme commit 86a94f48321780dbe18ef5b099434c347ec2f4d0"
author | iuc |
---|---|
date | Wed, 11 Dec 2019 18:05:15 -0500 |
parents | 57e5d9382f36 |
children | 19237efe98d1 |
comparison
equal
deleted
inserted
replaced
13:57e5d9382f36 | 14:3f0dd362b755 |
---|---|
5 <title>MEME</title> | 5 <title>MEME</title> |
6 <script> | 6 <script> |
7 // @JSON_VAR data | 7 // @JSON_VAR data |
8 var data = { | 8 var data = { |
9 "program": "MEME", | 9 "program": "MEME", |
10 "version": "4.12.0", | 10 "version": "5.0.5", |
11 "release": "Tue Jun 27 16:22:50 2017 -0700", | 11 "release": "Mon Mar 18 20:12:19 2019 -0700", |
12 "stop_reason": "Stopped because requested number of motifs (1) found.", | 12 "stop_reason": "Stopped because requested number of motifs (1) found.", |
13 "cmd": [ | 13 "cmd": [ |
14 "meme", "meme_input_1.fasta", "-o", "meme_test1_out", "-nostatus", | 14 "meme", |
15 "-maxsize", "1000000" | 15 "-o", |
16 "-nostatus", "-maxsize", "1000000" | |
16 ], | 17 ], |
17 "options": { | 18 "options": { |
18 "mod": "zoops", | |
19 "revcomp": false, | |
20 "nmotifs": 1, | |
21 "minw": 8, | |
22 "maxw": 50, | |
23 "minsites": 2, | |
24 "maxsites": 30, | |
25 "wnsites": 0.8, | |
26 "spmap": "pam", | |
27 "spfuzz": 120, | |
28 "maxwords": -1, | |
29 "prior": "megap", | |
30 "b": 7500, | |
31 "maxiter": 50, | |
32 "distance": 1e-05, | |
33 "wg": 11, | |
34 "ws": 1, | |
35 "noendgaps": false, | |
36 "substring": true | |
37 }, | |
38 "alphabet": { | |
39 "name": "Protein", | |
40 "like": "protein", | |
41 "ncore": 20, | |
42 "symbols": [ | |
43 { | |
44 "symbol": "A", | |
45 "name": "Alanine", | |
46 "colour": "0000CC" | |
47 }, { | |
48 "symbol": "C", | |
49 "name": "Cysteine", | |
50 "colour": "0000CC" | |
51 }, { | |
52 "symbol": "D", | |
53 "name": "Aspartic acid", | |
54 "colour": "FF00FF" | |
55 }, { | |
56 "symbol": "E", | |
57 "name": "Glutamic acid", | |
58 "colour": "FF00FF" | |
59 }, { | |
60 "symbol": "F", | |
61 "name": "Phenylalanine", | |
62 "colour": "0000CC" | |
63 }, { | |
64 "symbol": "G", | |
65 "name": "Glycine", | |
66 "colour": "FFB300" | |
67 }, { | |
68 "symbol": "H", | |
69 "name": "Histidine", | |
70 "colour": "FFCCCC" | |
71 }, { | |
72 "symbol": "I", | |
73 "name": "Isoleucine", | |
74 "colour": "0000CC" | |
75 }, { | |
76 "symbol": "K", | |
77 "name": "Lysine", | |
78 "colour": "CC0000" | |
79 }, { | |
80 "symbol": "L", | |
81 "name": "Leucine", | |
82 "colour": "0000CC" | |
83 }, { | |
84 "symbol": "M", | |
85 "name": "Methionine", | |
86 "colour": "0000CC" | |
87 }, { | |
88 "symbol": "N", | |
89 "name": "Asparagine", | |
90 "colour": "008000" | |
91 }, { | |
92 "symbol": "P", | |
93 "name": "Proline", | |
94 "colour": "FFFF00" | |
95 }, { | |
96 "symbol": "Q", | |
97 "name": "Glutamine", | |
98 "colour": "008000" | |
99 }, { | |
100 "symbol": "R", | |
101 "name": "Arginine", | |
102 "colour": "CC0000" | |
103 }, { | |
104 "symbol": "S", | |
105 "name": "Serine", | |
106 "colour": "008000" | |
107 }, { | |
108 "symbol": "T", | |
109 "name": "Threonine", | |
110 "colour": "008000" | |
111 }, { | |
112 "symbol": "V", | |
113 "name": "Valine", | |
114 "colour": "0000CC" | |
115 }, { | |
116 "symbol": "W", | |
117 "name": "Tryptophan", | |
118 "colour": "0000CC" | |
119 }, { | |
120 "symbol": "Y", | |
121 "name": "Tyrosine", | |
122 "colour": "33E6CC" | |
123 }, { | |
124 "symbol": "X", | |
125 "aliases": "*.", | |
126 "name": "Any amino acid", | |
127 "equals": "ACDEFGHIKLMNPQRSTVWY" | |
128 }, { | |
129 "symbol": "B", | |
130 "name": "Asparagine or Aspartic acid", | |
131 "equals": "DN" | |
132 }, { | |
133 "symbol": "Z", | |
134 "name": "Glutamine or Glutamic acid", | |
135 "equals": "EQ" | |
136 }, { | |
137 "symbol": "J", | |
138 "name": "Leucine or Isoleucine", | |
139 "equals": "IL" | |
140 } | |
141 ] | |
142 }, | |
143 "background": { | |
144 "freqs": [ | |
145 0.291, 0.229, 0.001, 0.001, 0.001, 0.255, 0.001, 0.001, 0.001, | |
146 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.215, 0.001, | |
147 0.001, 0.001 | |
148 ] | |
149 }, | |
150 "sequence_db": { | |
151 "source": "meme_input_1.fasta", | |
152 "psp_source": "prior30.plib", | |
153 "freqs": [ | |
154 0.294, 0.231, 0.000, 0.000, 0.000, 0.257, 0.000, 0.000, 0.000, | |
155 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.217, 0.000, | |
156 0.000, 0.000 | |
157 ], | |
158 "sequences": [ | |
159 { | |
160 "name": "chr21_19617074_19617124_+", | |
161 "length": 50, | |
162 "weight": 1.000000 | |
163 }, { | |
164 "name": "chr21_26934381_26934431_+", | |
165 "length": 50, | |
166 "weight": 1.000000 | |
167 }, { | |
168 "name": "chr21_28217753_28217803_-", | |
169 "length": 50, | |
170 "weight": 1.000000 | |
171 }, { | |
172 "name": "chr21_31710037_31710087_-", | |
173 "length": 50, | |
174 "weight": 1.000000 | |
175 }, { | |
176 "name": "chr21_31744582_31744632_-", | |
177 "length": 50, | |
178 "weight": 1.000000 | |
179 }, { | |
180 "name": "chr21_31768316_31768366_+", | |
181 "length": 50, | |
182 "weight": 1.000000 | |
183 }, { | |
184 "name": "chr21_31914206_31914256_-", | |
185 "length": 50, | |
186 "weight": 1.000000 | |
187 }, { | |
188 "name": "chr21_31933633_31933683_-", | |
189 "length": 50, | |
190 "weight": 1.000000 | |
191 }, { | |
192 "name": "chr21_31962741_31962791_-", | |
193 "length": 50, | |
194 "weight": 1.000000 | |
195 }, { | |
196 "name": "chr21_31964683_31964733_+", | |
197 "length": 50, | |
198 "weight": 1.000000 | |
199 }, { | |
200 "name": "chr21_31973364_31973414_+", | |
201 "length": 50, | |
202 "weight": 1.000000 | |
203 }, { | |
204 "name": "chr21_31992870_31992920_+", | |
205 "length": 50, | |
206 "weight": 1.000000 | |
207 }, { | |
208 "name": "chr21_32185595_32185645_-", | |
209 "length": 50, | |
210 "weight": 1.000000 | |
211 }, { | |
212 "name": "chr21_32202076_32202126_-", | |
213 "length": 50, | |
214 "weight": 1.000000 | |
215 }, { | |
216 "name": "chr21_32253899_32253949_-", | |
217 "length": 50, | |
218 "weight": 1.000000 | |
219 }, { | |
220 "name": "chr21_32410820_32410870_-", | |
221 "length": 50, | |
222 "weight": 1.000000 | |
223 }, { | |
224 "name": "chr21_36411748_36411798_-", | |
225 "length": 50, | |
226 "weight": 1.000000 | |
227 }, { | |
228 "name": "chr21_37838750_37838800_-", | |
229 "length": 50, | |
230 "weight": 1.000000 | |
231 }, { | |
232 "name": "chr21_45705687_45705737_+", | |
233 "length": 50, | |
234 "weight": 1.000000 | |
235 }, { | |
236 "name": "chr21_45971413_45971463_-", | |
237 "length": 50, | |
238 "weight": 1.000000 | |
239 }, { | |
240 "name": "chr21_45978668_45978718_-", | |
241 "length": 50, | |
242 "weight": 1.000000 | |
243 }, { | |
244 "name": "chr21_45993530_45993580_+", | |
245 "length": 50, | |
246 "weight": 1.000000 | |
247 }, { | |
248 "name": "chr21_46020421_46020471_+", | |
249 "length": 50, | |
250 "weight": 1.000000 | |
251 }, { | |
252 "name": "chr21_46031920_46031970_+", | |
253 "length": 50, | |
254 "weight": 1.000000 | |
255 }, { | |
256 "name": "chr21_46046964_46047014_+", | |
257 "length": 50, | |
258 "weight": 1.000000 | |
259 }, { | |
260 "name": "chr21_46057197_46057247_+", | |
261 "length": 50, | |
262 "weight": 1.000000 | |
263 }, { | |
264 "name": "chr21_46086869_46086919_-", | |
265 "length": 50, | |
266 "weight": 1.000000 | |
267 }, { | |
268 "name": "chr21_46102103_46102153_-", | |
269 "length": 50, | |
270 "weight": 1.000000 | |
271 }, { | |
272 "name": "chr21_47517957_47518007_+", | |
273 "length": 50, | |
274 "weight": 1.000000 | |
275 }, { | |
276 "name": "chr21_47575506_47575556_-", | |
277 "length": 50, | |
278 "weight": 1.000000 | |
279 } | |
280 ] | |
281 }, | 19 }, |
282 "motifs": [ | 20 "motifs": [ |
283 { | |
284 "db": 0, | |
285 "id": "GGGGTATAAAA", | |
286 "alt": "MEME-1", | |
287 "len": 11, | |
288 "nsites": 25, | |
289 "evalue": "2.4e-011", | |
290 "ic": 40.0, | |
291 "re": 13.8, | |
292 "llr": 239, | |
293 "bt": 5.33554, | |
294 "time": 0.772000, | |
295 "psm": [ | |
296 [ | |
297 -32, -680, 91, 77, 7, 138, -20, 55, 64, 107, 11, 150, 142, 72, | |
298 87, 396, -148, 221, -140, -36 | |
299 ], [ | |
300 -11, -680, 89, 76, 7, 137, -21, 55, 63, 107, 10, 149, 141, 71, | |
301 87, 396, -239, 220, -140, -36 | |
302 ], [ | |
303 -79, 41, 4, 21, -7, 44, -62, 42, -5, 99, 0, 99, 138, 52, 42, | |
304 399, -46, 223, -173, -68 | |
305 ], [ | |
306 11, -677, 48, 47, -2, 127, -43, 46, 27, 101, 3, 124, 138, 60, | |
307 62, 397, -235, 220, -160, -55 | |
308 ], [ | |
309 -596, -820, 12, -21, -53, -267, -74, 37, 16, 44, -37, 98, 31, | |
310 9, 19, 319, 212, 127, -193, -95 | |
311 ], [ | |
312 165, -261, 70, 110, 77, -521, -4, 147, 95, 201, 90, 121, 124, | |
313 91, 107, 425, -527, 314, -95, 8 | |
314 ], [ | |
315 -838, -990, -89, -149, -151, -841, -161, -117, -113, -66, | |
316 -209, -68, -69, -129, -91, 111, 221, -55, -255, -173 | |
317 ], [ | |
318 176, -858, -79, -103, -115, -717, -148, -95, -108, -17, -162, | |
319 -61, -12, -95, -69, 193, -737, 52, -240, -153 | |
320 ], [ | |
321 134, -686, 0, 16, -12, -553, -68, 44, -8, 96, -9, 88, 124, 41, | |
322 36, 384, 11, 216, -177, -71 | |
323 ], [ | |
324 165, -261, 70, 110, 77, -521, -4, 147, 95, 201, 90, 121, 124, | |
325 91, 107, 425, -527, 314, -95, 8 | |
326 ], [ | |
327 147, -614, 89, 129, 93, -121, 12, 160, 113, 217, 108, 144, | |
328 144, 111, 125, 447, -241, 332, -81, 22 | |
329 ] | |
330 ], | |
331 "pwm": [ | |
332 [ | |
333 0.240000, 0.000000, 0.000000, 0.000000, 0.000000, 0.680000, | |
334 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
335 0.000000, 0.000000, 0.000000, 0.000000, 0.080000, 0.000000, | |
336 0.000000, 0.000000 | |
337 ], [ | |
338 0.280000, 0.000000, 0.000000, 0.000000, 0.000000, 0.680000, | |
339 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
340 0.000000, 0.000000, 0.000000, 0.000000, 0.040000, 0.000000, | |
341 0.000000, 0.000000 | |
342 ], [ | |
343 0.160000, 0.320000, 0.000000, 0.000000, 0.000000, 0.360000, | |
344 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
345 0.000000, 0.000000, 0.000000, 0.000000, 0.160000, 0.000000, | |
346 0.000000, 0.000000 | |
347 ], [ | |
348 0.320000, 0.000000, 0.000000, 0.000000, 0.000000, 0.640000, | |
349 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
350 0.000000, 0.000000, 0.000000, 0.000000, 0.040000, 0.000000, | |
351 0.000000, 0.000000 | |
352 ], [ | |
353 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.040000, | |
354 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
355 0.000000, 0.000000, 0.000000, 0.000000, 0.960000, 0.000000, | |
356 0.000000, 0.000000 | |
357 ], [ | |
358 0.960000, 0.040000, 0.000000, 0.000000, 0.000000, 0.000000, | |
359 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
360 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
361 0.000000, 0.000000 | |
362 ], [ | |
363 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
364 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
365 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, | |
366 0.000000, 0.000000 | |
367 ], [ | |
368 1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
369 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
370 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
371 0.000000, 0.000000 | |
372 ], [ | |
373 0.760000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
374 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
375 0.000000, 0.000000, 0.000000, 0.000000, 0.240000, 0.000000, | |
376 0.000000, 0.000000 | |
377 ], [ | |
378 0.960000, 0.040000, 0.000000, 0.000000, 0.000000, 0.000000, | |
379 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
380 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
381 0.000000, 0.000000 | |
382 ], [ | |
383 0.840000, 0.000000, 0.000000, 0.000000, 0.000000, 0.120000, | |
384 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
385 0.000000, 0.000000, 0.000000, 0.000000, 0.040000, 0.000000, | |
386 0.000000, 0.000000 | |
387 ] | |
388 ], | |
389 "sites": [ | |
390 { | |
391 "seq": 24, | |
392 "pos": 12, | |
393 "rc": false, | |
394 "pvalue": 1.06e-06, | |
395 "lflank": "AAGGCCAGGA", | |
396 "match": "GGGGTATAAAA", | |
397 "rflank": "GCCTGAGAGC" | |
398 }, { | |
399 "seq": 25, | |
400 "pos": 36, | |
401 "rc": false, | |
402 "pvalue": 3.41e-06, | |
403 "lflank": "ACAGGCCCTG", | |
404 "match": "GGCATATAAAA", | |
405 "rflank": "GCC" | |
406 }, { | |
407 "seq": 19, | |
408 "pos": 9, | |
409 "rc": false, | |
410 "pvalue": 3.41e-06, | |
411 "lflank": "CAGGCCCTG", | |
412 "match": "GGCATATAAAA", | |
413 "rflank": "GCCCCAGCAG" | |
414 }, { | |
415 "seq": 9, | |
416 "pos": 13, | |
417 "rc": false, | |
418 "pvalue": 3.41e-06, | |
419 "lflank": "GATTCACTGA", | |
420 "match": "GGCATATAAAA", | |
421 "rflank": "GGCCCTCTGC" | |
422 }, { | |
423 "seq": 21, | |
424 "pos": 7, | |
425 "rc": false, | |
426 "pvalue": 4.00e-06, | |
427 "lflank": "CCAAGGA", | |
428 "match": "GGAGTATAAAA", | |
429 "rflank": "GCCCCACAAA" | |
430 }, { | |
431 "seq": 13, | |
432 "pos": 13, | |
433 "rc": false, | |
434 "pvalue": 5.01e-06, | |
435 "lflank": "CCACCAGCTT", | |
436 "match": "GAGGTATAAAA", | |
437 "rflank": "AGCCCTGTAC" | |
438 }, { | |
439 "seq": 23, | |
440 "pos": 15, | |
441 "rc": false, | |
442 "pvalue": 6.06e-06, | |
443 "lflank": "ATACCCAGGG", | |
444 "match": "AGGGTATAAAA", | |
445 "rflank": "CCTCAGCAGC" | |
446 }, { | |
447 "seq": 15, | |
448 "pos": 21, | |
449 "rc": false, | |
450 "pvalue": 8.67e-06, | |
451 "lflank": "AATCACTGAG", | |
452 "match": "GATGTATAAAA", | |
453 "rflank": "GTCCCAGGGA" | |
454 }, { | |
455 "seq": 12, | |
456 "pos": 18, | |
457 "rc": false, | |
458 "pvalue": 8.67e-06, | |
459 "lflank": "CACCAGAGCT", | |
460 "match": "GGGATATATAA", | |
461 "rflank": "AGAAGGTTCT" | |
462 }, { | |
463 "seq": 11, | |
464 "pos": 16, | |
465 "rc": false, | |
466 "pvalue": 8.67e-06, | |
467 "lflank": "CACTATTGAA", | |
468 "match": "GATGTATAAAA", | |
469 "rflank": "TTTCATTTGC" | |
470 }, { | |
471 "seq": 22, | |
472 "pos": 2, | |
473 "rc": false, | |
474 "pvalue": 1.21e-05, | |
475 "lflank": "GA", | |
476 "match": "GACATATAAAA", | |
477 "rflank": "GCCAACATCC" | |
478 }, { | |
479 "seq": 28, | |
480 "pos": 32, | |
481 "rc": false, | |
482 "pvalue": 1.59e-05, | |
483 "lflank": "CCGGCGGGGC", | |
484 "match": "GGGGTATAAAG", | |
485 "rflank": "GGGGCGG" | |
486 }, { | |
487 "seq": 20, | |
488 "pos": 4, | |
489 "rc": false, | |
490 "pvalue": 1.59e-05, | |
491 "lflank": "CAGA", | |
492 "match": "GGGGTATAAAG", | |
493 "rflank": "GTTCCGACCA" | |
494 }, { | |
495 "seq": 6, | |
496 "pos": 15, | |
497 "rc": false, | |
498 "pvalue": 1.68e-05, | |
499 "lflank": "CCCACTACTT", | |
500 "match": "AGAGTATAAAA", | |
501 "rflank": "TCATTCTGAG" | |
502 }, { | |
503 "seq": 14, | |
504 "pos": 19, | |
505 "rc": false, | |
506 "pvalue": 2.03e-05, | |
507 "lflank": "CACCAGCAAG", | |
508 "match": "GATATATAAAA", | |
509 "rflank": "GCTCAGGAGT" | |
510 }, { | |
511 "seq": 4, | |
512 "pos": 12, | |
513 "rc": false, | |
514 "pvalue": 3.06e-05, | |
515 "lflank": "CAGGTCTAAG", | |
516 "match": "AGCATATATAA", | |
517 "rflank": "CTTGGAGTCC" | |
518 }, { | |
519 "seq": 0, | |
520 "pos": 39, | |
521 "rc": false, | |
522 "pvalue": 3.06e-05, | |
523 "lflank": "CCTCGGGACG", | |
524 "match": "TGGGTATATAA", | |
525 "rflank": "" | |
526 }, { | |
527 "seq": 18, | |
528 "pos": 37, | |
529 "rc": false, | |
530 "pvalue": 3.82e-05, | |
531 "lflank": "CGTGGTCGCG", | |
532 "match": "GGGGTATAACA", | |
533 "rflank": "GC" | |
534 }, { | |
535 "seq": 5, | |
536 "pos": 0, | |
537 "rc": false, | |
538 "pvalue": 3.82e-05, | |
539 "lflank": "", | |
540 "match": "AACGTATATAA", | |
541 "rflank": "ATGGTCCTGT" | |
542 }, { | |
543 "seq": 29, | |
544 "pos": 30, | |
545 "rc": false, | |
546 "pvalue": 4.02e-05, | |
547 "lflank": "GCTGCCGGTG", | |
548 "match": "AGCGTATAAAG", | |
549 "rflank": "GCCCTGGCG" | |
550 }, { | |
551 "seq": 1, | |
552 "pos": 27, | |
553 "rc": false, | |
554 "pvalue": 5.52e-05, | |
555 "lflank": "AGTCACAAGT", | |
556 "match": "GAGTTATAAAA", | |
557 "rflank": "GGGTCGCACG" | |
558 }, { | |
559 "seq": 3, | |
560 "pos": 14, | |
561 "rc": false, | |
562 "pvalue": 5.94e-05, | |
563 "lflank": "CCCAGGTTTC", | |
564 "match": "TGAGTATATAA", | |
565 "rflank": "TCGCCGCACC" | |
566 }, { | |
567 "seq": 16, | |
568 "pos": 22, | |
569 "rc": false, | |
570 "pvalue": 6.78e-05, | |
571 "lflank": "AGTTTCAGTT", | |
572 "match": "GGCATCTAAAA", | |
573 "rflank": "attatataac" | |
574 }, { | |
575 "seq": 7, | |
576 "pos": 2, | |
577 "rc": false, | |
578 "pvalue": 2.08e-04, | |
579 "lflank": "TC", | |
580 "match": "AGAGTATATAT", | |
581 "rflank": "AAATGTTCCT" | |
582 }, { | |
583 "seq": 8, | |
584 "pos": 13, | |
585 "rc": false, | |
586 "pvalue": 4.05e-04, | |
587 "lflank": "TATAACTCAG", | |
588 "match": "GTTGGATAAAA", | |
589 "rflank": "TAATTTGTAC" | |
590 } | |
591 ] | |
592 } | |
593 ], | |
594 "scan": [ | 21 "scan": [ |
595 { | |
596 "pvalue": 1.22e-03, | |
597 "sites": [ | |
598 { | |
599 "motif": 0, | |
600 "pos": 39, | |
601 "rc": false, | |
602 "pvalue": 3.06e-05 | |
603 } | |
604 ] | |
605 }, { | |
606 "pvalue": 2.21e-03, | |
607 "sites": [ | |
608 { | |
609 "motif": 0, | |
610 "pos": 27, | |
611 "rc": false, | |
612 "pvalue": 5.52e-05 | |
613 } | |
614 ] | |
615 }, { | |
616 "pvalue": 7.29e-01, | |
617 "sites": [] | |
618 }, { | |
619 "pvalue": 2.37e-03, | |
620 "sites": [ | |
621 { | |
622 "motif": 0, | |
623 "pos": 14, | |
624 "rc": false, | |
625 "pvalue": 5.94e-05 | |
626 } | |
627 ] | |
628 }, { | |
629 "pvalue": 1.22e-03, | |
630 "sites": [ | |
631 { | |
632 "motif": 0, | |
633 "pos": 12, | |
634 "rc": false, | |
635 "pvalue": 3.06e-05 | |
636 } | |
637 ] | |
638 }, { | |
639 "pvalue": 1.53e-03, | |
640 "sites": [ | |
641 { | |
642 "motif": 0, | |
643 "pos": 0, | |
644 "rc": false, | |
645 "pvalue": 3.82e-05 | |
646 } | |
647 ] | |
648 }, { | |
649 "pvalue": 6.70e-04, | |
650 "sites": [ | |
651 { | |
652 "motif": 0, | |
653 "pos": 15, | |
654 "rc": false, | |
655 "pvalue": 1.68e-05 | |
656 } | |
657 ] | |
658 }, { | |
659 "pvalue": 1.81e-03, | |
660 "sites": [ | |
661 { | |
662 "motif": 0, | |
663 "pos": 4, | |
664 "rc": false, | |
665 "pvalue": 4.54e-05 | |
666 } | |
667 ] | |
668 }, { | |
669 "pvalue": 1.61e-02, | |
670 "sites": [] | |
671 }, { | |
672 "pvalue": 1.36e-04, | |
673 "sites": [ | |
674 { | |
675 "motif": 0, | |
676 "pos": 13, | |
677 "rc": false, | |
678 "pvalue": 3.41e-06 | |
679 } | |
680 ] | |
681 }, { | |
682 "pvalue": 1.99e-01, | |
683 "sites": [] | |
684 }, { | |
685 "pvalue": 3.47e-04, | |
686 "sites": [ | |
687 { | |
688 "motif": 0, | |
689 "pos": 16, | |
690 "rc": false, | |
691 "pvalue": 8.67e-06 | |
692 } | |
693 ] | |
694 }, { | |
695 "pvalue": 3.47e-04, | |
696 "sites": [ | |
697 { | |
698 "motif": 0, | |
699 "pos": 18, | |
700 "rc": false, | |
701 "pvalue": 8.67e-06 | |
702 } | |
703 ] | |
704 }, { | |
705 "pvalue": 2.01e-04, | |
706 "sites": [ | |
707 { | |
708 "motif": 0, | |
709 "pos": 13, | |
710 "rc": false, | |
711 "pvalue": 5.01e-06 | |
712 } | |
713 ] | |
714 }, { | |
715 "pvalue": 8.11e-04, | |
716 "sites": [ | |
717 { | |
718 "motif": 0, | |
719 "pos": 19, | |
720 "rc": false, | |
721 "pvalue": 2.03e-05 | |
722 } | |
723 ] | |
724 }, { | |
725 "pvalue": 3.47e-04, | |
726 "sites": [ | |
727 { | |
728 "motif": 0, | |
729 "pos": 21, | |
730 "rc": false, | |
731 "pvalue": 8.67e-06 | |
732 } | |
733 ] | |
734 }, { | |
735 "pvalue": 2.71e-03, | |
736 "sites": [ | |
737 { | |
738 "motif": 0, | |
739 "pos": 22, | |
740 "rc": false, | |
741 "pvalue": 6.78e-05 | |
742 } | |
743 ] | |
744 }, { | |
745 "pvalue": 8.23e-02, | |
746 "sites": [] | |
747 }, { | |
748 "pvalue": 1.53e-03, | |
749 "sites": [ | |
750 { | |
751 "motif": 0, | |
752 "pos": 37, | |
753 "rc": false, | |
754 "pvalue": 3.82e-05 | |
755 } | |
756 ] | |
757 }, { | |
758 "pvalue": 1.36e-04, | |
759 "sites": [ | |
760 { | |
761 "motif": 0, | |
762 "pos": 9, | |
763 "rc": false, | |
764 "pvalue": 3.41e-06 | |
765 } | |
766 ] | |
767 }, { | |
768 "pvalue": 6.37e-04, | |
769 "sites": [ | |
770 { | |
771 "motif": 0, | |
772 "pos": 4, | |
773 "rc": false, | |
774 "pvalue": 1.59e-05 | |
775 } | |
776 ] | |
777 }, { | |
778 "pvalue": 1.60e-04, | |
779 "sites": [ | |
780 { | |
781 "motif": 0, | |
782 "pos": 7, | |
783 "rc": false, | |
784 "pvalue": 4.00e-06 | |
785 } | |
786 ] | |
787 }, { | |
788 "pvalue": 4.83e-04, | |
789 "sites": [ | |
790 { | |
791 "motif": 0, | |
792 "pos": 2, | |
793 "rc": false, | |
794 "pvalue": 1.21e-05 | |
795 } | |
796 ] | |
797 }, { | |
798 "pvalue": 2.43e-04, | |
799 "sites": [ | |
800 { | |
801 "motif": 0, | |
802 "pos": 15, | |
803 "rc": false, | |
804 "pvalue": 6.06e-06 | |
805 } | |
806 ] | |
807 }, { | |
808 "pvalue": 4.26e-05, | |
809 "sites": [ | |
810 { | |
811 "motif": 0, | |
812 "pos": 12, | |
813 "rc": false, | |
814 "pvalue": 1.06e-06 | |
815 } | |
816 ] | |
817 }, { | |
818 "pvalue": 1.36e-04, | |
819 "sites": [ | |
820 { | |
821 "motif": 0, | |
822 "pos": 36, | |
823 "rc": false, | |
824 "pvalue": 3.41e-06 | |
825 } | |
826 ] | |
827 }, { | |
828 "pvalue": 4.30e-02, | |
829 "sites": [] | |
830 }, { | |
831 "pvalue": 4.30e-02, | |
832 "sites": [] | |
833 }, { | |
834 "pvalue": 6.37e-04, | |
835 "sites": [ | |
836 { | |
837 "motif": 0, | |
838 "pos": 32, | |
839 "rc": false, | |
840 "pvalue": 1.59e-05 | |
841 } | |
842 ] | |
843 }, { | |
844 "pvalue": 1.61e-03, | |
845 "sites": [ | |
846 { | |
847 "motif": 0, | |
848 "pos": 30, | |
849 "rc": false, | |
850 "pvalue": 4.02e-05 | |
851 } | |
852 ] | |
853 } | |
854 ] | |
855 }; | |
856 </script> | 22 </script> |
857 <script> | |
858 var site_url = "http://meme-suite.org"; | 23 var site_url = "http://meme-suite.org"; |
859 </script> | |
860 <script> | |
861 | 24 |
862 /* | |
863 * $ | |
864 * | |
865 * Shorthand function for getElementById | |
866 */ | |
867 function $(el) { | |
868 return document.getElementById(el); | |
869 } | |
870 | |
871 | |
872 /* | |
873 * See http://stackoverflow.com/a/5450113/66387 | |
874 * Does string multiplication like the perl x operator. | |
875 */ | |
876 function string_mult(pattern, count) { | |
877 if (count < 1) return ''; | |
878 var result = ''; | |
879 while (count > 1) { | |
880 if (count & 1) result += pattern; | |
881 count >>= 1, pattern += pattern; | |
882 } | |
883 return result + pattern; | |
884 } | |
885 | |
886 /* | |
887 * See http://stackoverflow.com/questions/814613/how-to-read-get-data-from-a-url-using-javascript | |
888 * Slightly modified with information from | |
889 * https://developer.mozilla.org/en/DOM/window.location | |
890 */ | |
891 function parse_params() { | |
892 "use strict"; | |
893 var search, queryStart, queryEnd, query, params, nvPairs, i, nv, n, v; | |
894 search = window.location.search; | |
895 queryStart = search.indexOf("?") + 1; | |
896 queryEnd = search.indexOf("#") + 1 || search.length + 1; | |
897 query = search.slice(queryStart, queryEnd - 1); | |
898 | |
899 if (query === search || query === "") return {}; | |
900 | |
901 params = {}; | |
902 nvPairs = query.replace(/\+/g, " ").split("&"); | |
903 | |
904 for (i = 0; i < nvPairs.length; i++) { | |
905 nv = nvPairs[i].split("="); | |
906 n = decodeURIComponent(nv[0]); | |
907 v = decodeURIComponent(nv[1]); | |
908 // allow a name to be used multiple times | |
909 // storing each value in the array | |
910 if (!(n in params)) { | |
911 params[n] = []; | |
912 } | |
913 params[n].push(nv.length === 2 ? v : null); | |
914 } | |
915 return params; | |
916 } | |
917 | |
918 /* | |
919 * coords | |
920 * | |
921 * Calculates the x and y offset of an element. | |
922 * From http://www.quirksmode.org/js/findpos.html | |
923 * with alterations to take into account scrolling regions | |
924 */ | |
925 function coords(elem) { | |
926 var myX = myY = 0; | |
927 if (elem.getBoundingClientRect) { | |
928 var rect; | |
929 rect = elem.getBoundingClientRect(); | |
930 myX = rect.left + ((typeof window.pageXOffset !== "undefined") ? | |
931 window.pageXOffset : document.body.scrollLeft); | |
932 myY = rect.top + ((typeof window.pageYOffset !== "undefined") ? | |
933 window.pageYOffset : document.body.scrollTop); | |
934 } else { | |
935 // this fall back doesn't properly handle absolutely positioned elements | |
936 // inside a scrollable box | |
937 var node; | |
938 if (elem.offsetParent) { | |
939 // subtract all scrolling | |
940 node = elem; | |
941 do { | |
942 myX -= node.scrollLeft ? node.scrollLeft : 0; | |
943 myY -= node.scrollTop ? node.scrollTop : 0; | |
944 } while (node = node.parentNode); | |
945 // this will include the page scrolling (which is unwanted) so add it back on | |
946 myX += (typeof window.pageXOffset !== "undefined") ? window.pageXOffset : document.body.scrollLeft; | |
947 myY += (typeof window.pageYOffset !== "undefined") ? window.pageYOffset : document.body.scrollTop; | |
948 // sum up offsets | |
949 node = elem; | |
950 do { | |
951 myX += node.offsetLeft; | |
952 myY += node.offsetTop; | |
953 } while (node = node.offsetParent); | |
954 } | |
955 } | |
956 return [myX, myY]; | |
957 } | |
958 | |
959 /* | |
960 * position_popup | |
961 * | |
962 * Positions a popup relative to an anchor element. | |
963 * | |
964 * The avaliable positions are: | |
965 * 0 - Centered below the anchor. | |
966 */ | |
967 function position_popup(anchor, popup, position) { | |
968 "use strict"; | |
969 var a_x, a_y, a_w, a_h, p_x, p_y, p_w, p_h; | |
970 var a_xy, spacer, margin, scrollbar, page_w; | |
971 // define constants | |
972 spacer = 5; | |
973 margin = 15; | |
974 scrollbar = 15; | |
975 // define the positions and widths | |
976 a_xy = coords(anchor); | |
977 a_x = a_xy[0]; | |
978 a_y = a_xy[1]; | |
979 a_w = anchor.offsetWidth; | |
980 a_h = anchor.offsetHeight; | |
981 p_w = popup.offsetWidth; | |
982 p_h = popup.offsetHeight; | |
983 page_w = null; | |
984 if (window.innerWidth) { | |
985 page_w = window.innerWidth; | |
986 } else if (document.body) { | |
987 page_w = document.body.clientWidth; | |
988 } | |
989 // check the position type is defined | |
990 if (typeof position !== "number") { | |
991 position = 0; | |
992 } | |
993 // calculate the popup position | |
994 switch (position) { | |
995 case 1: | |
996 p_x = a_x + a_w + spacer; | |
997 p_y = a_y + (a_h / 2) - (p_h / 2); | |
998 break; | |
999 case 0: | |
1000 default: | |
1001 p_x = a_x + (a_w / 2) - (p_w / 2); | |
1002 p_y = a_y + a_h + spacer; | |
1003 break; | |
1004 } | |
1005 // constrain the popup position | |
1006 if (p_x < margin) { | |
1007 p_x = margin; | |
1008 } else if (page_w != null && (p_x + p_w) > (page_w - margin - scrollbar)) { | |
1009 p_x = page_w - margin - scrollbar - p_w; | |
1010 } | |
1011 if (p_y < margin) { | |
1012 p_y = margin; | |
1013 } | |
1014 // position the popup | |
1015 popup.style.left = p_x + "px"; | |
1016 popup.style.top = p_y + "px"; | |
1017 } | |
1018 | |
1019 function lookup_help_popup(popup_id) { | |
1020 var _body, pop, info; | |
1021 pop = document.getElementById(popup_id); | |
1022 if (pop == null) { | |
1023 _body = document.getElementsByTagName("body")[0]; | |
1024 pop = document.createElement("div"); | |
1025 pop.className = "pop_content"; | |
1026 pop.id = popup_id; | |
1027 pop.style.backgroundColor = "#FFC"; | |
1028 pop.style.borderColor = "black"; | |
1029 info = document.createElement("p"); | |
1030 info.style.fontWeight = "bold"; | |
1031 info.appendChild(document.createTextNode("Error: No popup for topic \"" + popup_id + "\".")); | |
1032 pop.appendChild(info); | |
1033 // this might cause problems with the menu, but as this only happens | |
1034 // when something is already wrong I don't think that's too much of a problem | |
1035 _body.insertBefore(pop, _body.firstChild); | |
1036 } | |
1037 if (document.getElementsByTagName('body')[0].hasAttribute("data-autobtns")) { | |
1038 if (!/\bauto_buttons\b/.test(pop.className)) { | |
1039 pop.className += " auto_buttons"; | |
1040 var back_btn_sec = document.createElement("div"); | |
1041 back_btn_sec.className = "nested_only pop_back_sec"; | |
1042 var back_btn = document.createElement("span"); | |
1043 back_btn.className = "pop_back"; | |
1044 back_btn.appendChild(document.createTextNode("<< back")); | |
1045 back_btn.addEventListener("click", function(e) { | |
1046 help_return(); | |
1047 }, false); | |
1048 back_btn_sec.appendChild(back_btn); | |
1049 pop.insertBefore(back_btn_sec, pop.firstChild); | |
1050 var close_btn_sec = document.createElement("div"); | |
1051 close_btn_sec.className = "pop_close_sec"; | |
1052 var close_btn = document.createElement("span"); | |
1053 close_btn.className = "pop_close"; | |
1054 close_btn.appendChild(document.createTextNode("close")); | |
1055 close_btn.addEventListener("click", function(e) { | |
1056 help_popup(); | |
1057 }, false); | |
1058 close_btn_sec.appendChild(close_btn); | |
1059 pop.appendChild(close_btn_sec); | |
1060 } | |
1061 } | |
1062 return pop; | |
1063 } | |
1064 | |
1065 /* | |
1066 * help_popup | |
1067 * | |
1068 * Moves around help pop-ups so they appear | |
1069 * below an activator. | |
1070 */ | |
1071 function help_popup(activator, popup_id) { | |
1072 "use strict"; | |
1073 var pop; | |
1074 // set default values | |
1075 if (typeof help_popup.popup === "undefined") { | |
1076 help_popup.popup = []; | |
1077 } | |
1078 if (typeof help_popup.activator === "undefined") { | |
1079 help_popup.activator = null; | |
1080 } | |
1081 var last_pop = (help_popup.popup.length > 0 ? help_popup.popup[help_popup.popup.length - 1] : null); | |
1082 if (typeof(activator) == "undefined") { // no activator so hide | |
1083 if (last_pop != null) { | |
1084 last_pop.style.display = 'none'; | |
1085 help_popup.popup = []; | |
1086 } | |
1087 return; | |
1088 } | |
1089 pop = lookup_help_popup(popup_id); | |
1090 if (pop == last_pop) { | |
1091 if (activator == help_popup.activator) { | |
1092 //hide popup (as we've already shown it for the current help button) | |
1093 last_pop.style.display = 'none'; | |
1094 help_popup.popup = []; | |
1095 return; // toggling complete! | |
1096 } | |
1097 } else if (last_pop != null) { | |
1098 //activating different popup so hide current one | |
1099 last_pop.style.display = 'none'; | |
1100 } | |
1101 help_popup.popup = [pop]; | |
1102 help_popup.activator = activator; | |
1103 toggle_class(pop, "nested", false); | |
1104 //must make the popup visible to measure it or it has zero width | |
1105 pop.style.display = 'block'; | |
1106 position_popup(activator, pop); | |
1107 } | |
1108 | |
1109 /* | |
1110 * help_refine | |
1111 * | |
1112 * Intended for links within a help popup. Stores a stack of state so | |
1113 * you can go back. | |
1114 */ | |
1115 function help_refine(popup_id) { | |
1116 if (help_popup.popup == null || help_popup.popup.length == 0 || help_popup.activator == null) { | |
1117 throw new Error("Can not refine a help popup when one is not shown!"); | |
1118 } | |
1119 var pop = lookup_help_popup(popup_id); | |
1120 var last_pop = help_popup.popup[help_popup.popup.length - 1]; | |
1121 if (pop == last_pop) return; // slightly odd, but no real cause for alarm | |
1122 help_popup.popup.push(pop); | |
1123 toggle_class(pop, "nested", true); | |
1124 last_pop.style.display = "none"; | |
1125 //must make the popup visible to measure it or it has zero width | |
1126 pop.style.display = "block"; | |
1127 position_popup(help_popup.activator, pop); | |
1128 } | |
1129 | |
1130 /* | |
1131 * help_return | |
1132 * | |
1133 * Intended for links within a help popup. Stores a stack of state so | |
1134 * you can go back. | |
1135 */ | |
1136 function help_return() { | |
1137 if (help_popup.popup == null || help_popup.popup.length == 0 || help_popup.activator == null) { | |
1138 throw new Error("Can not return to a earlier help popup when one is not shown!"); | |
1139 } | |
1140 var last_pop = help_popup.popup.pop(); | |
1141 last_pop.style.display = "none"; | |
1142 var pop = (help_popup.popup.length > 0 ? help_popup.popup[help_popup.popup.length - 1] : null); | |
1143 if (pop != null) { | |
1144 toggle_class(pop, "nested", help_popup.popup.length > 1); | |
1145 pop.style.display = "block"; | |
1146 position_popup(help_popup.activator, pop); | |
1147 } else { | |
1148 help_popup.activator = null; | |
1149 } | |
1150 } | |
1151 | |
1152 /* | |
1153 * update_scroll_pad | |
1154 * | |
1155 * Creates padding at the bottom of the page to allow | |
1156 * scrolling of anything into view. | |
1157 */ | |
1158 function update_scroll_pad() { | |
1159 var page, pad; | |
1160 page = (document.compatMode === "CSS1Compat") ? document.documentElement : document.body; | |
1161 pad = $("scrollpad"); | |
1162 if (pad === null) { | |
1163 pad = document.createElement("div"); | |
1164 pad.id = 'scrollpad'; | |
1165 document.getElementsByTagName('body')[0].appendChild(pad); | |
1166 } | |
1167 pad.style.height = Math.abs(page.clientHeight - 100) + "px"; | |
1168 } | |
1169 | |
1170 function substitute_classes(node, remove, add) { | |
1171 "use strict"; | |
1172 var list, all, i, cls, classes; | |
1173 list = node.className.split(/\s+/); | |
1174 all = {}; | |
1175 for (i = 0; i < list.length; i++) { | |
1176 if (list[i].length > 0) all[list[i]] = true; | |
1177 } | |
1178 for (i = 0; i < remove.length; i++) { | |
1179 if (all.hasOwnProperty(remove[i])) { | |
1180 delete all[remove[i]]; | |
1181 } | |
1182 } | |
1183 for (i = 0; i < add.length; i++) { | |
1184 all[add[i]] = true; | |
1185 } | |
1186 classes = ""; | |
1187 for (cls in all) { | |
1188 classes += cls + " "; | |
1189 } | |
1190 node.className = classes; | |
1191 } | |
1192 | |
1193 /* | |
1194 * toggle_class | |
1195 * | |
1196 * Adds or removes a class from the node. If the parameter 'enabled' is not | |
1197 * passed then the existence of the class will be toggled, otherwise it will be | |
1198 * included if enabled is true. | |
1199 */ | |
1200 function toggle_class(node, cls, enabled) { | |
1201 var classes = node.className; | |
1202 var list = classes.replace(/^\s+/, '').replace(/\s+$/, '').split(/\s+/); | |
1203 var found = false; | |
1204 for (var i = 0; i < list.length; i++) { | |
1205 if (list[i] == cls) { | |
1206 list.splice(i, 1); | |
1207 i--; | |
1208 found = true; | |
1209 } | |
1210 } | |
1211 if (typeof enabled == "undefined") { | |
1212 if (!found) list.push(cls); | |
1213 } else { | |
1214 if (enabled) list.push(cls); | |
1215 } | |
1216 node.className = list.join(" "); | |
1217 } | |
1218 | |
1219 /* | |
1220 * find_child | |
1221 * | |
1222 * Searches child nodes in depth first order and returns the first it finds | |
1223 * with the className specified. | |
1224 * TODO replace with querySelector | |
1225 */ | |
1226 function find_child(node, className) { | |
1227 var pattern; | |
1228 if (node == null || typeof node !== "object") { | |
1229 return null; | |
1230 } | |
1231 if (typeof className === "string") { | |
1232 pattern = new RegExp("\\b" + className + "\\b"); | |
1233 } else { | |
1234 pattern = className; | |
1235 } | |
1236 if (node.nodeType == Node.ELEMENT_NODE && | |
1237 pattern.test(node.className)) { | |
1238 return node; | |
1239 } else { | |
1240 var result = null; | |
1241 for (var i = 0; i < node.childNodes.length; i++) { | |
1242 result = find_child(node.childNodes[i], pattern); | |
1243 if (result != null) break; | |
1244 } | |
1245 return result; | |
1246 } | |
1247 } | |
1248 | |
1249 /* | |
1250 * find_parent | |
1251 * | |
1252 * Searches parent nodes outwards from the node and returns the first it finds | |
1253 * with the className specified. | |
1254 */ | |
1255 function find_parent(node, className) { | |
1256 var pattern; | |
1257 pattern = new RegExp("\\b" + className + "\\b"); | |
1258 do { | |
1259 if (node.nodeType == Node.ELEMENT_NODE && | |
1260 pattern.test(node.className)) { | |
1261 return node; | |
1262 } | |
1263 } while (node = node.parentNode); | |
1264 return null; | |
1265 } | |
1266 | |
1267 /* | |
1268 * find_parent_tag | |
1269 * | |
1270 * Searches parent nodes outwards from the node and returns the first it finds | |
1271 * with the tag name specified. HTML tags should be specified in upper case. | |
1272 */ | |
1273 function find_parent_tag(node, tag_name) { | |
1274 do { | |
1275 if (node.nodeType == Node.ELEMENT_NODE && node.tagName == tag_name) { | |
1276 return node; | |
1277 } | |
1278 } while (node = node.parentNode); | |
1279 return null; | |
1280 } | |
1281 | |
1282 /* | |
1283 * __toggle_help | |
1284 * | |
1285 * Uses the 'topic' property of the this object to | |
1286 * toggle display of a help topic. | |
1287 * | |
1288 * This function is not intended to be called directly. | |
1289 */ | |
1290 function __toggle_help(e) { | |
1291 if (!e) e = window.event; | |
1292 if (e.type === "keydown") { | |
1293 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
1294 return; | |
1295 } | |
1296 // stop a submit or something like that | |
1297 e.preventDefault(); | |
1298 } | |
1299 | |
1300 help_popup(this, this.getAttribute("data-topic")); | |
1301 } | |
1302 | |
1303 function setup_help_button(button) { | |
1304 "use strict"; | |
1305 var topic; | |
1306 if (button.hasAttribute("data-topic")) { | |
1307 topic = button.getAttribute("data-topic"); | |
1308 if (document.getElementById(topic) != null) { | |
1309 button.tabIndex = "0"; // make keyboard selectable | |
1310 button.addEventListener("click", function() { | |
1311 help_popup(button, topic); | |
1312 }, false); | |
1313 button.addEventListener("keydown", function(e) { | |
1314 // toggle only on Enter or Spacebar, let other keys do their thing | |
1315 if (e.keyCode !== 13 && e.keyCode !== 32) return; | |
1316 // stop a submit or something like that | |
1317 e.preventDefault(); | |
1318 help_popup(button, topic); | |
1319 }, false); | |
1320 } else { | |
1321 button.style.visibility = "hidden"; | |
1322 } | |
1323 } | |
1324 button.className += " active"; | |
1325 } | |
1326 | |
1327 /* | |
1328 * help_button | |
1329 * | |
1330 * Makes a help button for the passed topic. | |
1331 */ | |
1332 function help_button(topic) { | |
1333 var btn = document.createElement("div"); | |
1334 btn.className = "help"; | |
1335 btn.setAttribute("data-topic", topic); | |
1336 setup_help_button(btn); | |
1337 return btn; | |
1338 } | |
1339 | |
1340 /* | |
1341 * prepare_download | |
1342 * | |
1343 * Sets the attributes of a link to setup a file download using the given content. | |
1344 * If no link is provided then create one and click it. | |
1345 */ | |
1346 function prepare_download(content, mimetype, filename, link) { | |
1347 "use strict"; | |
1348 // if no link is provided then create one and click it | |
1349 var click_link = false; | |
1350 if (!link) { | |
1351 link = document.createElement("a"); | |
1352 click_link = true; | |
1353 } | |
1354 try { | |
1355 // Use a BLOB to convert the text into a data URL. | |
1356 // We could do this manually with a base 64 conversion. | |
1357 // This will only be supported on modern browsers, | |
1358 // hence the try block. | |
1359 var blob = new Blob([content], {type: mimetype}); | |
1360 var reader = new FileReader(); | |
1361 reader.onloadend = function() { | |
1362 // If we're lucky the browser will also support the download | |
1363 // attribute which will let us suggest a file name to save the link. | |
1364 // Otherwise it is likely that the filename will be unintelligible. | |
1365 link.setAttribute("download", filename); | |
1366 link.href = reader.result; | |
1367 if (click_link) { | |
1368 // must add the link to click it | |
1369 document.body.appendChild(link); | |
1370 link.click(); | |
1371 document.body.removeChild(link); | |
1372 } | |
1373 } | |
1374 reader.readAsDataURL(blob); | |
1375 } catch (error) { | |
1376 if (console && console.log) console.log(error); | |
1377 // probably an old browser | |
1378 link.href = ""; | |
1379 link.visible = false; | |
1380 } | |
1381 } | |
1382 | |
1383 /* | |
1384 * add_cell | |
1385 * | |
1386 * Add a cell to the table row. | |
1387 */ | |
1388 function add_cell(row, node, cls, click_action) { | |
1389 var cell = row.insertCell(row.cells.length); | |
1390 if (node) cell.appendChild(node); | |
1391 if (cls && cls !== "") cell.className = cls; | |
1392 if (click_action) cell.addEventListener("click", click_action, false); | |
1393 } | |
1394 | |
1395 /* | |
1396 * add_header_cell | |
1397 * | |
1398 * Add a header cell to the table row. | |
1399 */ | |
1400 function add_header_cell(row, node, help_topic, cls, colspan) { | |
1401 var th = document.createElement("th"); | |
1402 if (node) th.appendChild(node); | |
1403 if (help_topic && help_topic !== "") th.appendChild(help_button(help_topic)); | |
1404 if (cls && cls !== "") th.className = cls; | |
1405 if (typeof colspan == "number" && colspan > 1) th.colSpan = colspan; | |
1406 row.appendChild(th); | |
1407 } | |
1408 | |
1409 /* | |
1410 * add_text_cell | |
1411 * | |
1412 * Add a text cell to the table row. | |
1413 */ | |
1414 function add_text_cell(row, text, cls, action) { | |
1415 var node = null; | |
1416 if (typeof(text) != 'undefined') node = document.createTextNode(text); | |
1417 add_cell(row, node, cls, action); | |
1418 } | |
1419 | |
1420 /* | |
1421 * add_text_header_cell | |
1422 * | |
1423 * Add a text header cell to the table row. | |
1424 */ | |
1425 function add_text_header_cell(row, text, help_topic, cls, action, colspan) { | |
1426 var node = null; | |
1427 if (typeof(text) != 'undefined') { | |
1428 var nbsp = (help_topic ? "\u00A0" : ""); | |
1429 var str = "" + text; | |
1430 var parts = str.split(/\n/); | |
1431 if (parts.length === 1) { | |
1432 if (action) { | |
1433 node = document.createElement("span"); | |
1434 node.appendChild(document.createTextNode(str + nbsp)); | |
1435 } else { | |
1436 node = document.createTextNode(str + nbsp); | |
1437 } | |
1438 } else { | |
1439 node = document.createElement("span"); | |
1440 for (var i = 0; i < parts.length; i++) { | |
1441 if (i !== 0) { | |
1442 node.appendChild(document.createElement("br")); | |
1443 } | |
1444 node.appendChild(document.createTextNode(parts[i])); | |
1445 } | |
1446 } | |
1447 if (action) { | |
1448 node.addEventListener("click", action, false); | |
1449 node.style.cursor = "pointer"; | |
1450 } | |
1451 } | |
1452 add_header_cell(row, node, help_topic, cls, colspan); | |
1453 } | |
1454 | |
1455 function setup_help() { | |
1456 "use strict"; | |
1457 var help_buttons, i; | |
1458 help_buttons = document.querySelectorAll(".help:not(.active)"); | |
1459 for (i = 0; i < help_buttons.length; i++) { | |
1460 setup_help_button(help_buttons[i]); | |
1461 } | |
1462 } | |
1463 | |
1464 function setup_scrollpad() { | |
1465 "use strict"; | |
1466 if (document.getElementsByTagName('body')[0].hasAttribute("data-scrollpad") && document.getElementById("scrollpad") == null) { | |
1467 window.addEventListener("resize", update_scroll_pad, false); | |
1468 update_scroll_pad(); | |
1469 } | |
1470 } | |
1471 | |
1472 // anon function to avoid polluting global scope | |
1473 (function() { | |
1474 "use strict"; | |
1475 window.addEventListener("load", function load(evt) { | |
1476 window.removeEventListener("load", load, false); | |
1477 setup_help(); | |
1478 setup_scrollpad(); | |
1479 }, false); | |
1480 })(); | |
1481 | |
1482 /* | |
1483 * make_link | |
1484 * | |
1485 * Creates a text node and if a URL is specified it surrounds it with a link. | |
1486 * If the URL doesn't begin with "http://" it automatically adds it, as | |
1487 * relative links don't make much sense in this context. | |
1488 */ | |
1489 function make_link(text, url) { | |
1490 var textNode = null; | |
1491 var link = null; | |
1492 if (typeof text !== "undefined" && text !== null) textNode = document.createTextNode(text); | |
1493 if (typeof url === "string") { | |
1494 if (url.indexOf("//") == -1) { | |
1495 url = "http://" + url; | |
1496 } | |
1497 link = document.createElement('a'); | |
1498 link.href = url; | |
1499 if (textNode) link.appendChild(textNode); | |
1500 return link; | |
1501 } | |
1502 return textNode; | |
1503 } | |
1504 </script> | |
1505 <script> | |
1506 // | |
1507 // return true if any part of the passed element is visible in the viewport | |
1508 // | |
1509 function element_in_viewport(elem) { | |
1510 var rect; | |
1511 try { | |
1512 rect = elem.getBoundingClientRect(); | |
1513 } catch (e) { | |
1514 return false; | |
1515 } | |
1516 return ( | |
1517 rect.top < (window.innerHeight || document.body.clientHeight) && | |
1518 rect.bottom > 0 && | |
1519 rect.left < (window.innerWidth || document.body.clientWidth) && | |
1520 rect.right > 0 | |
1521 ); | |
1522 } | |
1523 | |
1524 // | |
1525 // Functions to delay a drawing task until it is required or it would not lag the display to do so | |
1526 // | |
1527 | |
1528 // a list of items still to be drawn | |
1529 var drawable_list = []; | |
1530 // the delay between drawing objects that are not currently visible | |
1531 var draw_delay = 1; | |
1532 // the delay after a user interaction | |
1533 var user_delay = 300; | |
1534 // the delay after a user has stopped scrolling and is viewing the stuff drawn on the current page | |
1535 var stop_delay = 300; | |
1536 // the timer handle; allows resetting of the timer after user interactions | |
1537 var draw_timer = null; | |
1538 | |
1539 // | |
1540 // Drawable | |
1541 // | |
1542 // elem - a page element which defines the position on the page that drawing is to be done | |
1543 // task - an object with the method run which takes care of painting the object | |
1544 // | |
1545 var Drawable = function(elem, task) { | |
1546 this.elem = elem; | |
1547 this.task = task; | |
1548 } | |
1549 | |
1550 // | |
1551 // Drawable.is_visible | |
1552 // | |
1553 // Determines if the element is visible in the viewport | |
1554 // | |
1555 Drawable.prototype.is_visible = function() { | |
1556 return element_in_viewport(this.elem); | |
1557 } | |
1558 | |
1559 // | |
1560 // Drawable.run | |
1561 // | |
1562 // Run the task held by the drawable | |
1563 Drawable.prototype.run = function() { | |
1564 if (this.task) this.task.run(); | |
1565 this.task = null; | |
1566 } | |
1567 | |
1568 // | |
1569 // Drawable.run | |
1570 // | |
1571 // Run the task iff visible | |
1572 // returns true if the task ran or has already run | |
1573 Drawable.prototype.run_visible = function() { | |
1574 if (this.task) { | |
1575 if (element_in_viewport(this.elem)) { | |
1576 this.task.run(); | |
1577 this.task = null; | |
1578 return true; | |
1579 } | |
1580 return false; | |
1581 } else { | |
1582 return true; | |
1583 } | |
1584 } | |
1585 | |
1586 // | |
1587 // draw_on_screen | |
1588 // | |
1589 // Checks each drawable object and draws those on screen. | |
1590 // | |
1591 function draw_on_screen() { | |
1592 var found = false; | |
1593 for (var i = 0; i < drawable_list.length; i++) { | |
1594 if (drawable_list[i].run_visible()) { | |
1595 drawable_list.splice(i--, 1); | |
1596 found = true; | |
1597 } | |
1598 } | |
1599 return found; | |
1600 } | |
1601 | |
1602 // | |
1603 // process_draw_tasks | |
1604 // | |
1605 // Called on a delay to process the next avaliable | |
1606 // draw task. | |
1607 // | |
1608 function process_draw_tasks() { | |
1609 var delay = draw_delay; | |
1610 draw_timer = null; | |
1611 if (drawable_list.length == 0) return; //no more tasks | |
1612 if (draw_on_screen()) { | |
1613 delay = stop_delay; //give the user a chance to scroll | |
1614 } else { | |
1615 //get next task | |
1616 var drawable = drawable_list.shift(); | |
1617 drawable.task.run(); | |
1618 } | |
1619 //allow UI updates between tasks | |
1620 draw_timer = window.setTimeout("process_draw_tasks()", delay); | |
1621 } | |
1622 | |
1623 // | |
1624 // delayed_process_draw_tasks | |
1625 // | |
1626 // Call process_draw_tasks after a short delay. | |
1627 // The delay serves to group multiple redundant events. | |
1628 // Should be set as event handler for onscroll and onresize. | |
1629 // | |
1630 function delayed_process_draw_tasks() { | |
1631 //reset the timer | |
1632 if (drawable_list.length > 0) { | |
1633 if (draw_timer != null) clearTimeout(draw_timer); | |
1634 draw_timer = window.setTimeout("process_draw_tasks()", user_delay); | |
1635 } | |
1636 } | |
1637 | |
1638 // | |
1639 // add_draw_task | |
1640 // | |
1641 // Add a drawing task to be called immediately if it is | |
1642 // visible, or to be called on a delay to reduce stuttering | |
1643 // effect on the web browser. | |
1644 function add_draw_task(elem, task) { | |
1645 drawable = new Drawable(elem, task); | |
1646 if (drawable.is_visible()) { | |
1647 task.run(); | |
1648 } else { | |
1649 drawable_list.push(drawable); | |
1650 //reset timer | |
1651 if (draw_timer != null) clearTimeout(draw_timer); | |
1652 draw_timer = window.setTimeout("process_draw_tasks()", user_delay); | |
1653 } | |
1654 } | |
1655 | |
1656 </script> | |
1657 <script> | |
1658 //====================================================================== | |
1659 // start Alphabet object | |
1660 //====================================================================== | |
1661 var Alphabet = function(alphabet, background) { | |
1662 "use strict"; | |
1663 var i, j, sym, aliases, complement, comp_e_sym, ambigs, generate_background; | |
1664 generate_background = (background == null); | |
1665 if (generate_background) { | |
1666 background = []; | |
1667 for (i = 0; i < alphabet.ncore; i++) background[i] = 1.0 / alphabet.ncore; | |
1668 } else if (alphabet.ncore != background.length) { | |
1669 throw new Error("The background length does not match the alphabet length."); | |
1670 } | |
1671 this.name = alphabet.name; | |
1672 this.like = (alphabet.like != null ? alphabet.like.toUpperCase() : null); | |
1673 this.ncore = alphabet.ncore; | |
1674 this.symbols = alphabet.symbols; | |
1675 this.background = background; | |
1676 this.genbg = generate_background; | |
1677 this.encode = {}; | |
1678 this.encode2core = {}; | |
1679 this.complement = {}; | |
1680 // check if all symbols are same case | |
1681 var seen_uc = false; | |
1682 var seen_lc = false; | |
1683 var check_case = function (syms) { | |
1684 var s, sym; | |
1685 if (typeof syms === "string") { | |
1686 for (s = 0; s < syms.length; s++) { | |
1687 sym = syms.charAt(s); | |
1688 if (sym >= 'a' && sym <= 'z') seen_lc = true; | |
1689 else if (sym >= 'A' && sym <= 'Z') seen_uc = true; | |
1690 } | |
1691 } | |
1692 }; | |
1693 for (i = 0; i < this.symbols.length; i++) { | |
1694 check_case(this.symbols[i].symbol); | |
1695 check_case(this.symbols[i].aliases); | |
1696 } | |
1697 // now map symbols to indexes | |
1698 var update_array = function(array, syms, index) { | |
1699 var s, sym; | |
1700 if (typeof syms === "string") { | |
1701 for (s = 0; s < syms.length; s++) { | |
1702 sym = syms.charAt(s); | |
1703 array[sym] = index; | |
1704 // when only a single case is used, then encode as case insensitive | |
1705 if (seen_uc != seen_lc) { | |
1706 if (sym >= 'a' && sym <= 'z') { | |
1707 array[sym.toUpperCase()] = index; | |
1708 } else if (sym >= 'A' && sym <= 'Z') { | |
1709 array[sym.toLowerCase()] = index; | |
1710 } | |
1711 } | |
1712 } | |
1713 } | |
1714 } | |
1715 // map core symbols to index | |
1716 for (i = 0; i < this.ncore; i++) { | |
1717 update_array(this.encode2core, this.symbols[i].symbol, i); | |
1718 update_array(this.encode, this.symbols[i].symbol, i); | |
1719 update_array(this.encode2core, this.symbols[i].aliases, i); | |
1720 update_array(this.encode, this.symbols[i].aliases, i); | |
1721 } | |
1722 // map ambigous symbols to index | |
1723 ambigs = {}; | |
1724 for (i = this.ncore; i < this.symbols.length; i++) { | |
1725 update_array(this.encode, this.symbols[i].symbol, i); | |
1726 update_array(this.encode, this.symbols[i].aliases, i); | |
1727 ambigs[this.symbols[i].equals] = i; | |
1728 } | |
1729 // determine complements | |
1730 for (i = 0; i < this.ncore; i++) { | |
1731 complement = this.symbols[i].complement; | |
1732 if (typeof complement === "string") { | |
1733 this.complement[i] = this.encode2core[complement]; | |
1734 } | |
1735 } | |
1736 next_symbol: | |
1737 for (i = this.ncore; i < this.symbols.length; i++) { | |
1738 complement = ""; | |
1739 for (j = 0; j < this.symbols[i].equals.length; j++) { | |
1740 comp_e_sym = this.complement[this.encode2core[this.symbols[i].equals.charAt(j)]]; | |
1741 if (typeof comp_e_sym !== "number") continue next_symbol; | |
1742 complement += this.symbols[comp_e_sym].symbol; | |
1743 } | |
1744 complement = complement.split("").sort().join(""); | |
1745 if (typeof ambigs[complement] === "number") { | |
1746 this.complement[i] = ambigs[complement]; | |
1747 } | |
1748 } | |
1749 // determine case insensitivity | |
1750 this.case_insensitive = true; | |
1751 if (seen_uc == seen_lc) { | |
1752 // when there is a mixture of cases it probably won't | |
1753 // be case insensitive but we still need to check | |
1754 loop: | |
1755 for (i = 0; i < this.symbols.length; i++) { | |
1756 sym = this.symbols[i].symbol; | |
1757 if (sym >= 'A' && sym <= 'Z') { | |
1758 if (this.encode[sym.toLowerCase()] != i) { | |
1759 this.case_insensitive = false; | |
1760 break loop; | |
1761 } | |
1762 } else if (sym >= 'a' && sym <= 'z') { | |
1763 if (this.encode[sym.toUpperCase()] != i) { | |
1764 this.case_insensitive = false; | |
1765 break loop; | |
1766 } | |
1767 } | |
1768 aliases = this.symbols[i].aliases; | |
1769 if (aliases != null) { | |
1770 for (j = 0; j < aliases.length; j++) { | |
1771 sym = aliases.charAt(j); | |
1772 if (sym >= 'A' && sym <= 'Z') { | |
1773 if (this.encode[sym.toLowerCase()] != i) { | |
1774 this.case_insensitive = false; | |
1775 break loop; | |
1776 } | |
1777 } else if (sym >= 'a' && sym <= 'z') { | |
1778 if (this.encode[sym.toUpperCase()] != i) { | |
1779 this.case_insensitive = false; | |
1780 break loop; | |
1781 } | |
1782 } | |
1783 } | |
1784 } | |
1785 } | |
1786 } | |
1787 // normalise aliases to remove the prime symbol and eliminate | |
1788 // the alternate cases when the alphabet is case insensitive | |
1789 var seen, out; | |
1790 for (i = 0; i < this.symbols.length; i++) { | |
1791 sym = this.symbols[i].symbol; | |
1792 aliases = this.symbols[i].aliases; | |
1793 if (typeof aliases != "string") aliases = ""; | |
1794 seen = {}; | |
1795 out = []; | |
1796 if (this.case_insensitive) { | |
1797 sym = sym.toUpperCase(); | |
1798 aliases = aliases.toUpperCase(); | |
1799 } | |
1800 seen[sym] = true; | |
1801 for (j = 0; j < aliases.length; j++) { | |
1802 if (!seen[aliases.charAt(j)]) { | |
1803 seen[aliases.charAt(j)] = true; | |
1804 out.push(aliases.charAt(j)); | |
1805 } | |
1806 } | |
1807 this.symbols[i].aliases = out.sort().join(""); | |
1808 } | |
1809 }; | |
1810 // return the name of the alphabet | |
1811 Alphabet.prototype.get_alphabet_name = function() { | |
1812 return this.name; | |
1813 }; | |
1814 // return if the alphabet can be complemented | |
1815 Alphabet.prototype.has_complement = function() { | |
1816 return (typeof this.symbols[0].complement === "string"); | |
1817 }; | |
1818 // return true if an uppercase letter has the same meaning as the lowercase form | |
1819 Alphabet.prototype.is_case_insensitive = function() { | |
1820 return this.case_insensitive; | |
1821 }; | |
1822 // return the information content of an alphabet letter | |
1823 Alphabet.prototype.get_ic = function() { | |
1824 return Math.log(this.ncore) / Math.LN2; | |
1825 }; | |
1826 // return the count of the core alphabet symbols | |
1827 Alphabet.prototype.get_size_core = function() { | |
1828 return this.ncore; | |
1829 }; | |
1830 // return the count of all alphabet symbols | |
1831 Alphabet.prototype.get_size_full = function() { | |
1832 return this.symbols.length; | |
1833 }; | |
1834 // return the symbol for the given alphabet index | |
1835 Alphabet.prototype.get_symbol = function(alph_index) { | |
1836 "use strict"; | |
1837 if (alph_index < 0 || alph_index >= this.symbols.length) { | |
1838 throw new Error("Alphabet index out of bounds"); | |
1839 } | |
1840 return this.symbols[alph_index].symbol; | |
1841 }; | |
1842 // return the aliases for the given alphabet index | |
1843 Alphabet.prototype.get_aliases = function(alph_index) { | |
1844 "use strict"; | |
1845 if (alph_index < 0 || alph_index >= this.symbols.length) { | |
1846 throw new Error("Alphabet index out of bounds"); | |
1847 } | |
1848 var sym_obj = this.symbols[alph_index]; | |
1849 return (sym_obj.aliases != null ? sym_obj.aliases : ""); | |
1850 }; | |
1851 // return the name for the given alphabet index | |
1852 Alphabet.prototype.get_name = function(alph_index) { | |
1853 "use strict"; | |
1854 var sym; | |
1855 if (alph_index < 0 || alph_index >= this.symbols.length) { | |
1856 throw new Error("Alphabet index out of bounds"); | |
1857 } | |
1858 sym = this.symbols[alph_index]; | |
1859 return (typeof sym.name === "string" ? sym.name : sym.symbol); | |
1860 }; | |
1861 // return the alphabet it is like or null | |
1862 Alphabet.prototype.get_like = function() { | |
1863 "use strict"; | |
1864 return this.like; | |
1865 }; | |
1866 // return the index of the complement for the given alphabet index | |
1867 Alphabet.prototype.get_complement = function(alph_index) { | |
1868 var comp_e_sym = this.complement[alph_index]; | |
1869 if (typeof comp_e_sym === "number") { | |
1870 return comp_e_sym; | |
1871 } else { | |
1872 return -1; | |
1873 } | |
1874 }; | |
1875 // return a string containing the core symbols | |
1876 Alphabet.prototype.get_symbols = function() { | |
1877 "use strict"; | |
1878 var i, core_symbols; | |
1879 core_symbols = ""; | |
1880 for (i = 0; i < this.ncore; i++) { | |
1881 core_symbols += this.symbols[i].symbol; | |
1882 } | |
1883 return core_symbols; | |
1884 }; | |
1885 // return if the background was not a uniform generated background | |
1886 Alphabet.prototype.has_bg = function() { | |
1887 "use strict"; | |
1888 return !this.genbg; | |
1889 }; | |
1890 // get the background frequency for the index | |
1891 Alphabet.prototype.get_bg_freq = function(alph_index) { | |
1892 "use strict"; | |
1893 var freq, i, symbols; | |
1894 if (alph_index >= 0) { | |
1895 if (alph_index < this.ncore) { | |
1896 return this.background[alph_index]; | |
1897 } else if (alph_index < this.symbols.length) { | |
1898 freq = 0; | |
1899 symbols = this.symbols[alph_index].equals; | |
1900 for (i = 0; i < symbols.length; i++) { | |
1901 freq += this.background[this.encode2core[symbols.charAt(i)]]; | |
1902 } | |
1903 return freq; | |
1904 } | |
1905 } | |
1906 throw new Error("The alphabet index is out of range."); | |
1907 }; | |
1908 // get the colour of the index | |
1909 Alphabet.prototype.get_colour = function(alph_index) { | |
1910 "use strict"; | |
1911 if (alph_index < 0 || alph_index >= this.symbols.length) { | |
1912 throw new Error("BAD_ALPHABET_INDEX"); | |
1913 } | |
1914 if (typeof this.symbols[alph_index].colour != "string") { | |
1915 return "black"; | |
1916 } | |
1917 return "#" + this.symbols[alph_index].colour; | |
1918 }; | |
1919 // get the rgb componets of the colour at the index | |
1920 Alphabet.prototype.get_rgb = function(alph_index) { | |
1921 "use strict"; | |
1922 if (alph_index < 0 || alph_index >= this.symbols.length) { | |
1923 throw new Error("BAD_ALPHABET_INDEX"); | |
1924 } | |
1925 if (typeof this.symbols[alph_index].colour != "string") { | |
1926 return {"red": 0, "green": 0, "blue": 0}; | |
1927 } | |
1928 var colour = this.symbols[alph_index].colour; | |
1929 var red = parseInt(colour.substr(0, 2), 16) / 255; | |
1930 var green = parseInt(colour.substr(2, 2), 16) / 255; | |
1931 var blue = parseInt(colour.substr(4, 2), 16) / 255; | |
1932 return {"red": red, "green": green, "blue": blue}; | |
1933 }; | |
1934 // convert a symbol into the index | |
1935 Alphabet.prototype.get_index = function(letter) { | |
1936 "use strict"; | |
1937 var alph_index; | |
1938 alph_index = this.encode[letter]; | |
1939 if (typeof alph_index === "undefined") { | |
1940 return -1; | |
1941 } | |
1942 return alph_index; | |
1943 }; | |
1944 // convert a symbol into the list of core indexes that it equals | |
1945 Alphabet.prototype.get_indexes = function(letter) { | |
1946 "use strict"; | |
1947 var alph_index, comprise_str, i, comprise_list; | |
1948 alph_index = this.encode[letter]; | |
1949 if (typeof alph_index === "undefined") { | |
1950 throw new Error("Unknown letter"); | |
1951 } | |
1952 comprise_str = this.symbols[alph_index].equals; | |
1953 comprise_list = []; | |
1954 if (typeof comprise_str == "string") { | |
1955 for (i = 0; i < comprise_str.length; i++) { | |
1956 comprise_list.push(this.encode2core[comprise_str.charAt(i)]); | |
1957 } | |
1958 } else { | |
1959 comprise_list.push(alph_index); | |
1960 } | |
1961 return comprise_list; | |
1962 }; | |
1963 // check if a symbol is the primary way of representing the symbol in the alphabet | |
1964 Alphabet.prototype.is_prime_symbol = function(letter) { | |
1965 var alph_index; | |
1966 alph_index = this.encode[letter]; | |
1967 if (alph_index == null) return false; | |
1968 if (this.is_case_insensitive()) { | |
1969 return (this.symbols[alph_index].symbol.toUpperCase() == letter.toUpperCase()); | |
1970 } else { | |
1971 return (this.symbols[alph_index].symbol == letter); | |
1972 } | |
1973 }; | |
1974 // compare 2 alphabets | |
1975 Alphabet.prototype.equals = function(other) { | |
1976 "use strict"; | |
1977 var i, sym1, sym2; | |
1978 // first check that it's actually an alphabet object | |
1979 if (!(typeof other === "object" && other != null && other instanceof Alphabet)) { | |
1980 return false; | |
1981 } | |
1982 // second shortcircuit if it's the same object | |
1983 if (this === other) return true; | |
1984 // compare | |
1985 if (this.name !== other.name) return false; | |
1986 if (this.ncore !== other.ncore) return false; | |
1987 if (this.symbols.length !== other.symbols.length) return false; | |
1988 for (i = 0; i < this.symbols.length; i++) { | |
1989 sym1 = this.symbols[i]; | |
1990 sym2 = other.symbols[i]; | |
1991 if (sym1.symbol !== sym2.symbol) return false; | |
1992 if (sym1.aliases !== sym2.aliases) return false; | |
1993 if (sym1.name !== sym2.name) return false; | |
1994 if (typeof sym1.colour !== typeof sym2.colour || | |
1995 (typeof sym1.colour === "string" && typeof sym2.colour === "string" && | |
1996 parseInt(sym1.colour, 16) != parseInt(sym2.colour, 16))) { | |
1997 return false; | |
1998 } | |
1999 if (sym1.complement !== sym2.complement) return false; | |
2000 if (sym1.equals !== sym2.equals) return false; | |
2001 } | |
2002 return true; | |
2003 }; | |
2004 Alphabet.prototype.check_core_subset = function(super_alph) { | |
2005 var complement_same = true; | |
2006 var seen_set = {}; | |
2007 var sub_i, sub_symbol, super_i, super_symbol; | |
2008 for (sub_i = 0; sub_i < this.ncore; sub_i++) { | |
2009 sub_symbol = this.symbols[sub_i]; | |
2010 super_i = super_alph.encode[sub_symbol.symbol]; | |
2011 if (super_i == null) return 0; | |
2012 super_symbol = super_alph.symbols[super_i]; | |
2013 if (seen_set[super_i]) return 0; | |
2014 seen_set[super_i] = true; | |
2015 // check complement | |
2016 if (sub_symbol.complement != null && super_symbol.complement != null) { | |
2017 if (super_alph.encode[sub_symbol.complement] != super_alph.encode[super_symbol.complement]) { | |
2018 complement_same = false; | |
2019 } | |
2020 } else if (sub_symbol.complement != null || super_symbol.complement != null) { | |
2021 complement_same = false; | |
2022 } | |
2023 } | |
2024 return (complement_same ? 1 : -1); | |
2025 }; | |
2026 // convert a sequence to its reverse complement | |
2027 Alphabet.prototype.invcomp_seq = function(seq) { | |
2028 "use strict"; | |
2029 var syms, i, e_sym, comp_e_sym; | |
2030 if (!this.has_complement()) throw new Error("Alphabet must be complementable"); | |
2031 syms = seq.split(""); | |
2032 for (i = 0; i < syms.length; i++) { | |
2033 e_sym = this.encode[syms[i]]; | |
2034 if (typeof e_sym === "undefined") { | |
2035 e_sym = this.ncore; // wildcard | |
2036 } | |
2037 comp_e_sym = this.complement[e_sym]; | |
2038 if (typeof comp_e_sym === "undefined") { | |
2039 comp_e_sym = e_sym; // not complementable | |
2040 } | |
2041 syms[i] = this.symbols[comp_e_sym].symbol; | |
2042 } | |
2043 return syms.reverse().join(""); | |
2044 }; | |
2045 // convert the alphabet to the text version | |
2046 Alphabet.prototype.as_text = function() { | |
2047 "use strict"; | |
2048 function name_as_text(name) { | |
2049 var i, c, out; | |
2050 out = "\""; | |
2051 for (i = 0; i < name.length; i++) { | |
2052 c = name.charAt(i); | |
2053 if (c == "\"") { | |
2054 out += "\\\""; | |
2055 } else if (c == "/") { | |
2056 out += "\\/"; | |
2057 } else if (c == "\\") { | |
2058 out += "\\\\"; | |
2059 } else { | |
2060 out += c; | |
2061 } | |
2062 } | |
2063 out += "\""; | |
2064 return out; | |
2065 } | |
2066 function symbol_as_text(sym) { | |
2067 var out; | |
2068 out = sym.symbol; | |
2069 if (typeof sym.name === "string" && sym.name != sym.symbol) { | |
2070 out += " " + name_as_text(sym.name); | |
2071 } | |
2072 if (typeof sym.colour === "string") { | |
2073 out += " " + sym.colour; | |
2074 } | |
2075 return out; | |
2076 } | |
2077 var out, i, j, c, sym; | |
2078 out = ""; | |
2079 // output core symbols with 2 way complements | |
2080 for (i = 0; i < this.ncore; i++) { | |
2081 c = this.complement[i]; | |
2082 if (typeof c === "number" && i < c && this.complement[c] === i) { | |
2083 out += symbol_as_text(this.symbols[i]) + " ~ " + symbol_as_text(this.symbols[c]) + "\n"; | |
2084 } | |
2085 } | |
2086 // output core symbols with no complement | |
2087 for (i = 0; i < this.ncore; i++) { | |
2088 if (typeof this.complement[i] === "undefined") { | |
2089 out += symbol_as_text(this.symbols[i]) + "\n"; | |
2090 } | |
2091 } | |
2092 // output ambiguous symbols that have comprising characters | |
2093 for (i = this.ncore; i < this.symbols.length; i++) { | |
2094 if (this.symbols[i].equals.length == 0) break; | |
2095 out += symbol_as_text(this.symbols[i]) + " = " + this.symbols[i].equals + "\n"; | |
2096 if (typeof this.symbols[i].aliases === "string") { | |
2097 for (j = 0; j < this.symbols[i].aliases.length; j++) { | |
2098 if (this.symbols[i].aliases.charAt(j) == this.symbols[i].symbol) continue; | |
2099 out += this.symbols[i].aliases.charAt(j) + " = " + this.symbols[i].equals + "\n"; | |
2100 } | |
2101 } | |
2102 } | |
2103 // output aliases of core symbols | |
2104 for (i = 0; i < this.ncore; i++) { | |
2105 if (typeof this.symbols[i].aliases === "string") { | |
2106 for (j = 0; j < this.symbols[i].aliases.length; j++) { | |
2107 if (this.symbols[i].aliases.charAt(j) == this.symbols[i].symbol) continue; | |
2108 out += this.symbols[i].aliases.charAt(j) + " = " + this.symbols[i].symbol + "\n"; | |
2109 } | |
2110 } | |
2111 } | |
2112 // output gap symbols | |
2113 i = this.symbols.length - 1; | |
2114 if (this.symbols[i].equals.length == 0) { | |
2115 out += symbol_as_text(this.symbols[i]) + " =\n"; | |
2116 if (typeof this.symbols[i].aliases === "string") { | |
2117 for (j = 0; j < this.symbols[i].aliases.length; j++) { | |
2118 if (this.symbols[i].aliases.charAt(j) == this.symbols[i].symbol) continue; | |
2119 out += this.symbols[i].aliases.charAt(j) + " =\n"; | |
2120 } | |
2121 } | |
2122 } | |
2123 return out; | |
2124 }; | |
2125 // output the alphabet as it appears in minimal MEME format | |
2126 Alphabet.prototype.as_meme = function() { | |
2127 "use strict"; | |
2128 function name_as_text(name) { | |
2129 var i, c, out; | |
2130 out = "\""; | |
2131 for (i = 0; i < name.length; i++) { | |
2132 c = name.charAt(i); | |
2133 if (c == "\"") { | |
2134 out += "\\\""; | |
2135 } else if (c == "/") { | |
2136 out += "\\/"; | |
2137 } else if (c == "\\") { | |
2138 out += "\\\\"; | |
2139 } else { | |
2140 out += c; | |
2141 } | |
2142 } | |
2143 out += "\""; | |
2144 return out; | |
2145 } | |
2146 if (this.equals(AlphStd.DNA)) { | |
2147 return "ALPHABET= ACGT\n"; | |
2148 } else if (this.equals(AlphStd.PROTEIN)) { | |
2149 return "ALPHABET= ACDEFGHIKLMNPQRSTVWY\n"; | |
2150 } else { | |
2151 return "ALPHABET" + | |
2152 (this.name != null ? " " + name_as_text(this.name) : "") + | |
2153 (this.like != null ? " " + this.like + "-LIKE" : "") + "\n" + | |
2154 this.as_text() + "END ALPHABET\n"; | |
2155 } | |
2156 }; | |
2157 | |
2158 // Returns a table showing all the letters in the alphabet | |
2159 Alphabet.prototype.as_table = function() { | |
2160 "use strict"; | |
2161 var i, j, row, th, td, aliases, equals, sym; | |
2162 var table = document.createElement("table"); | |
2163 // create the core symbol header | |
2164 row = table.insertRow(table.rows.length); | |
2165 th = document.createElement("th"); | |
2166 th.appendChild(document.createTextNode("Symbol(s)")); | |
2167 row.appendChild(th); | |
2168 th = document.createElement("th"); | |
2169 th.appendChild(document.createTextNode("Name")); | |
2170 row.appendChild(th); | |
2171 th = document.createElement("th"); | |
2172 if (this.has_complement()) { | |
2173 th.appendChild(document.createTextNode("Complement")); | |
2174 } | |
2175 row.appendChild(th); | |
2176 // list the core symbols | |
2177 for (i = 0; i < this.ncore; i++) { | |
2178 row = table.insertRow(table.rows.length); | |
2179 td = document.createElement("td"); | |
2180 if (this.symbols[i].colour != null) { | |
2181 td.style.color = '#' + this.symbols[i].colour; | |
2182 } | |
2183 td.appendChild(document.createTextNode(this.symbols[i].symbol)); | |
2184 aliases = this.get_aliases(i); | |
2185 if (aliases.length > 0) { | |
2186 td.appendChild(document.createTextNode(' ' + aliases.split('').join(' '))); | |
2187 } | |
2188 row.appendChild(td); | |
2189 td = document.createElement("td"); | |
2190 if (this.symbols[i].name != null) { | |
2191 td.appendChild(document.createTextNode(this.symbols[i].name)); | |
2192 } | |
2193 row.appendChild(td); | |
2194 td = document.createElement("td"); | |
2195 if (this.symbols[i].complement != null) { | |
2196 td.style.color = this.get_colour(this.get_index(this.symbols[i].complement)); | |
2197 td.appendChild(document.createTextNode(this.symbols[i].complement)); | |
2198 } | |
2199 row.appendChild(td); | |
2200 } | |
2201 // create the ambiguous symbol header | |
2202 row = table.insertRow(table.rows.length); | |
2203 th = document.createElement("th"); | |
2204 th.appendChild(document.createTextNode("Symbol(s)")); | |
2205 row.appendChild(th); | |
2206 th = document.createElement("th"); | |
2207 th.appendChild(document.createTextNode("Name")); | |
2208 row.appendChild(th); | |
2209 th = document.createElement("th"); | |
2210 th.appendChild(document.createTextNode("Matches")); | |
2211 row.appendChild(th); | |
2212 // list the ambiguous symbols | |
2213 for (i = this.ncore; i < this.symbols.length; i++) { | |
2214 row = table.insertRow(table.rows.length); | |
2215 td = document.createElement("td"); | |
2216 if (this.symbols[i].colour != null) { | |
2217 td.style.color = '#' + this.symbols[i].colour; | |
2218 } | |
2219 td.appendChild(document.createTextNode(this.symbols[i].symbol)); | |
2220 aliases = this.get_aliases(i); | |
2221 if (aliases.length > 0) { | |
2222 td.appendChild(document.createTextNode(' ' + aliases.split('').join(' '))); | |
2223 } | |
2224 row.appendChild(td); | |
2225 td = document.createElement("td"); | |
2226 if (this.symbols[i].name != null) { | |
2227 td.appendChild(document.createTextNode(this.symbols[i].name)); | |
2228 } | |
2229 row.appendChild(td); | |
2230 td = document.createElement("td"); | |
2231 equals = this.symbols[i].equals.split(''); | |
2232 for (j = 0; j < equals.length; j++) { | |
2233 if (j != 0) td.appendChild(document.createTextNode(' ')); | |
2234 sym = document.createElement("span"); | |
2235 sym.style.color = this.get_colour(this.get_index(equals[j])); | |
2236 sym.appendChild(document.createTextNode(equals[j])); | |
2237 td.appendChild(sym); | |
2238 } | |
2239 row.appendChild(td); | |
2240 } | |
2241 return table; | |
2242 }; | |
2243 | |
2244 // returns a dictionary of the colours for EPS | |
2245 Alphabet.prototype._as_eps_dict = function() { | |
2246 "use strict"; | |
2247 var i, sym, rgb; | |
2248 var out = "/fullColourDict <<\n"; | |
2249 for (i = 0; i < this.ncore; i++) { | |
2250 sym = this.get_symbol(i); | |
2251 sym = sym.replace(/\\/g, "\\\\"); | |
2252 sym = sym.replace(/\(/g, "\\("); | |
2253 sym = sym.replace(/\)/g, "\\)"); | |
2254 rgb = this.get_rgb(i); | |
2255 out += " (" + sym + ") [" + rgb.red.toFixed(4) + " " + rgb.green.toFixed(4) + " " + rgb.blue.toFixed(4) + "]\n"; | |
2256 } | |
2257 out += ">> def\n"; | |
2258 out += "/mutedColourDict <<\n"; | |
2259 for (i = 0; i < this.ncore; i++) { | |
2260 sym = this.get_symbol(i); | |
2261 sym = sym.replace(/\\/g, "\\\\"); | |
2262 sym = sym.replace(/\(/g, "\\("); | |
2263 sym = sym.replace(/\)/g, "\\)"); | |
2264 rgb = Alphabet.lighten_colour(this.get_rgb(i)); | |
2265 out += " (" + sym + ") [" + rgb.red.toFixed(4) + " " + rgb.green.toFixed(4) + " " + rgb.blue.toFixed(4) + "]\n"; | |
2266 } | |
2267 out += ">> def\n"; | |
2268 return out; | |
2269 }; | |
2270 | |
2271 // return the alphabet name or a list of primary symbols | |
2272 Alphabet.prototype.toString = function() { | |
2273 "use strict"; | |
2274 if (this.name != null) { | |
2275 return this.name; | |
2276 } else { | |
2277 return this.get_symbols(); | |
2278 } | |
2279 }; | |
2280 | |
2281 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
2282 // Helper functions | |
2283 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
2284 | |
2285 // Convert a colour specified in RGB colourspace values into LAB colourspace | |
2286 Alphabet.rgb2lab = function(rgb) { | |
2287 "use strict"; | |
2288 var xyzHelper, labHelper; | |
2289 // XYZ helper | |
2290 xyzHelper = function(value) { | |
2291 if (value > 0.0445) { | |
2292 value = (value + 0.055) / 1.055; | |
2293 value = Math.pow(value, 2.4); | |
2294 } else { | |
2295 value /= 12.92; | |
2296 } | |
2297 value *= 100; | |
2298 return value; | |
2299 }; | |
2300 // lab helper | |
2301 labHelper = function(value) { | |
2302 if (value > 0.008856) { | |
2303 value = Math.pow(value, 1.0 / 3.0); | |
2304 } else { | |
2305 value = (7.787 * value) + (16.0 / 116.0); | |
2306 } | |
2307 return value; | |
2308 }; | |
2309 // convert into XYZ colourspace | |
2310 var c1, c2, c3; | |
2311 if (typeof rgb == "number") { | |
2312 c1 = xyzHelper(((rgb >> 16) & 0xFF) / 255.0); | |
2313 c2 = xyzHelper(((rgb >> 8) & 0xFF) / 255.0); | |
2314 c3 = xyzHelper((rgb & 0xFF) / 255.0); | |
2315 } else { | |
2316 c1 = xyzHelper(rgb.red); | |
2317 c2 = xyzHelper(rgb.green); | |
2318 c3 = xyzHelper(rgb.blue); | |
2319 } | |
2320 var x = (c1 * 0.4124) + (c2 * 0.3576) + (c3 * 0.1805); | |
2321 var y = (c1 * 0.2126) + (c2 * 0.7152) + (c3 * 0.0722); | |
2322 var z = (c1 * 0.0193) + (c2 * 0.1192) + (c3 * 0.9505); | |
2323 // convert into Lab colourspace | |
2324 c1 = labHelper(x / 95.047); | |
2325 c2 = labHelper(y / 100.0); | |
2326 c3 = labHelper(z / 108.883); | |
2327 var l = (116.0 * c2) - 16; | |
2328 var a = 500.0 * (c1 - c2); | |
2329 var b = 200.0 * (c2 - c3); | |
2330 return {"l": l, "a": a, "b": b}; | |
2331 }; | |
2332 | |
2333 // Convert a colour specified in HSV colourspace into RGB colourspace | |
2334 Alphabet.hsv2rgb = function(hue, sat, value, output_object) { | |
2335 // achromatic (grey) | |
2336 var r = value; | |
2337 var g = value; | |
2338 var b = value; | |
2339 if (sat != 0) { | |
2340 var h = hue / 60.0; | |
2341 var i = Math.floor(h); | |
2342 var f = h - i; | |
2343 var p = value * (1.0 - sat); | |
2344 var q = value * (1.0 - (sat * f)); | |
2345 var t = value * (1.0 - (sat * (1.0 - f))); | |
2346 if (i == 0) { | |
2347 r = value; | |
2348 g = t; | |
2349 b = p; | |
2350 } else if (i == 1) { | |
2351 r = q; | |
2352 g = value; | |
2353 b = p; | |
2354 } else if (i == 2) { | |
2355 r = p; | |
2356 g = value; | |
2357 b = t; | |
2358 } else if (i == 3) { | |
2359 r = p; | |
2360 g = q; | |
2361 b = value; | |
2362 } else if (i == 4) { | |
2363 r = t; | |
2364 g = p; | |
2365 b = value; | |
2366 } else { | |
2367 r = value; | |
2368 g = p; | |
2369 b = q; | |
2370 } | |
2371 } | |
2372 if (output_object) { | |
2373 return {"red": r, "green": g, "blue": b}; | |
2374 } else { | |
2375 return (Math.floor(r * 255) << 15) | (Math.floor(g * 255) << 8) | (Math.floor(b * 255)); | |
2376 } | |
2377 }; | |
2378 | |
2379 // Calculate a distance score between two colours in LAB colourspace | |
2380 Alphabet.lab_dist = function(lab1, lab2) { | |
2381 var c1 = Math.sqrt((lab1.l * lab1.l) + (lab1.a * lab1.a)); | |
2382 var c2 = Math.sqrt((lab2.l * lab2.l) + (lab2.a * lab2.a)); | |
2383 var dc = c1 - c2; | |
2384 var dl = lab1.l - lab2.l; | |
2385 var da = lab1.a - lab2.a; | |
2386 var db = lab1.b - lab2.b; | |
2387 // we don't want NaN due to rounding errors so fudge things a bit... | |
2388 var dh = 0; | |
2389 var dh_squared = (da * da) + (db * db) - (dc * dc); | |
2390 if (dh_squared > 0) { | |
2391 dh = Math.sqrt(dh_squared); | |
2392 } | |
2393 var first = dl; | |
2394 var second = dc / (1.0 + (0.045 * c1)); | |
2395 var third = dh / (1.0 + (0.015 * c1)); | |
2396 return Math.sqrt((first * first) + (second * second) + (third * third)); | |
2397 }; | |
2398 | |
2399 // convert an RGB value into a HSL value | |
2400 Alphabet.rgb2hsl = function(rgb) { | |
2401 "use strict"; | |
2402 var min, max, delta, h, s, l, r, g, b; | |
2403 if (typeof rgb == "number") { | |
2404 r = ((rgb >> 16) & 0xFF) / 255.0; | |
2405 g = ((rgb >> 8) & 0xFF) / 255.0; | |
2406 b = (rgb & 0xFF) / 255.0; | |
2407 } else { | |
2408 r = rgb.red; | |
2409 g = rgb.green; | |
2410 b = rgb.blue; | |
2411 } | |
2412 min = Math.min(r, g, b); | |
2413 max = Math.max(r, g, b); | |
2414 delta = max - min; | |
2415 l = min + (delta / 2); | |
2416 if (max == min) { | |
2417 h = 0; // achromatic (grayscale) | |
2418 s = 0; | |
2419 } else { | |
2420 if (l > 0.5) { | |
2421 s = delta / (2 - max - min); | |
2422 } else { | |
2423 s = delta / (max + min); | |
2424 } | |
2425 if (max == r) { | |
2426 h = (g - b) / delta; | |
2427 if (g < b) h += 6; | |
2428 } else if (max == g) { | |
2429 h = ((b - r) / delta) + 2; | |
2430 } else { | |
2431 h = ((r - g) / delta) + 4; | |
2432 } | |
2433 h /= 6; | |
2434 } | |
2435 return {"h": h, "s": s, "l": l}; | |
2436 }; | |
2437 | |
2438 // convert a HSL value into an RGB value | |
2439 Alphabet.hsl2rgb = function(hsl, output_object) { | |
2440 "use strict"; | |
2441 function _hue(p, q, t) { | |
2442 "use strict"; | |
2443 if (t < 0) t += 1; | |
2444 else if (t > 1) t -= 1; | |
2445 if (t < (1.0 / 6.0)) { | |
2446 return p + ((q - p) * 6.0 * t); | |
2447 } else if (t < 0.5) { | |
2448 return q; | |
2449 } else if (t < (2.0 / 3.0)) { | |
2450 return p + ((q - p) * ((2.0 / 3.0) - t) * 6.0); | |
2451 } else { | |
2452 return p; | |
2453 } | |
2454 } | |
2455 var r, g, b, p, q; | |
2456 if (hsl.s == 0) { | |
2457 // achromatic (grayscale) | |
2458 r = hsl.l; | |
2459 g = hsl.l; | |
2460 b = hsl.l; | |
2461 } else { | |
2462 if (hsl.l < 0.5) { | |
2463 q = hsl.l * (1 + hsl.s); | |
2464 } else { | |
2465 q = hsl.l + hsl.s - (hsl.l * hsl.s); | |
2466 } | |
2467 p = (2 * hsl.l) - q; | |
2468 r = _hue(p, q, hsl.h + (1.0 / 3.0)); | |
2469 g = _hue(p, q, hsl.h); | |
2470 b = _hue(p, q, hsl.h - (1.0 / 3.0)); | |
2471 } | |
2472 if (output_object) { | |
2473 return {"red": r, "green": g, "blue": b}; | |
2474 } else { | |
2475 return (Math.floor(r * 255) << 15) | (Math.floor(g * 255) << 8) | (Math.floor(b * 255)); | |
2476 } | |
2477 }; | |
2478 | |
2479 Alphabet.lighten_colour = function(rgb) { | |
2480 "use strict"; | |
2481 var hsl = Alphabet.rgb2hsl(rgb); | |
2482 hsl.l += (1.0 - hsl.l) * 2 / 3; | |
2483 return Alphabet.hsl2rgb(hsl, typeof rgb != "number"); | |
2484 }; | |
2485 | |
2486 //====================================================================== | |
2487 // end Alphabet object | |
2488 //====================================================================== | |
2489 | |
2490 //====================================================================== | |
2491 // start StandardAlphabet object | |
2492 //====================================================================== | |
2493 | |
2494 // an extension of the alphabet object to support some additional fields | |
2495 // only present in standard alphabets. | |
2496 var StandardAlphabet = function(enum_code, enum_name, alphabet_data) { | |
2497 Alphabet.apply(this, [alphabet_data]); | |
2498 this.enum_code = enum_code; | |
2499 this.enum_name = enum_name; | |
2500 }; | |
2501 StandardAlphabet.prototype = Alphabet.prototype; | |
2502 StandardAlphabet.prototype.constructor = StandardAlphabet; | |
2503 | |
2504 // A unique code for this standard alphabet. | |
2505 // This code will be a power of 2 to enable creation of bitsets for | |
2506 // a selection of standard alphabets. | |
2507 StandardAlphabet.prototype.get_code = function() { | |
2508 return this.enum_code; | |
2509 }; | |
2510 | |
2511 // A unique name for this standard alphabet. | |
2512 // this name will be all upper case and the same as the property that | |
2513 // refers to this alphabet in the AlphStd collection. | |
2514 StandardAlphabet.prototype.get_enum = function() { | |
2515 return this.enum_name; | |
2516 }; | |
2517 | |
2518 //====================================================================== | |
2519 // end StandardAlphabet object | |
2520 //====================================================================== | |
2521 | |
2522 // A collection of standard alphabets. | |
2523 var AlphStd = { | |
2524 RNA: new StandardAlphabet(1, "RNA", { | |
2525 "name": "RNA", | |
2526 "like": "RNA", | |
2527 "ncore": 4, | |
2528 "symbols": [ | |
2529 {"symbol": "A", "name": "Adenine", "colour": "CC0000"}, | |
2530 {"symbol": "C", "name": "Cytosine", "colour": "0000CC"}, | |
2531 {"symbol": "G", "name": "Guanine", "colour": "FFB300"}, | |
2532 {"symbol": "U", "name": "Uracil", "colour": "008000", | |
2533 "aliases": "T"}, | |
2534 {"symbol": "N", "name": "Any base", "equals": "ACGU", "aliases": "X."}, | |
2535 {"symbol": "V", "name": "Not U", "equals": "ACG"}, | |
2536 {"symbol": "H", "name": "Not G", "equals": "ACU"}, | |
2537 {"symbol": "D", "name": "Not C", "equals": "AGU"}, | |
2538 {"symbol": "B", "name": "Not A", "equals": "CGU"}, | |
2539 {"symbol": "M", "name": "Amino", "equals": "AC"}, | |
2540 {"symbol": "R", "name": "Purine", "equals": "AG"}, | |
2541 {"symbol": "W", "name": "Weak", "equals": "AU"}, | |
2542 {"symbol": "S", "name": "Strong", "equals": "CG"}, | |
2543 {"symbol": "Y", "name": "Pyrimidine", "equals": "CU"}, | |
2544 {"symbol": "K", "name": "Keto", "equals": "GU"} | |
2545 ] | |
2546 }), | |
2547 DNA: new StandardAlphabet(2, "DNA", { | |
2548 "name": "DNA", | |
2549 "like": "DNA", | |
2550 "ncore": 4, | |
2551 "symbols": [ | |
2552 {"symbol": "A", "name": "Adenine", "colour": "CC0000", "complement": "T"}, | |
2553 {"symbol": "C", "name": "Cytosine", "colour": "0000CC", "complement": "G"}, | |
2554 {"symbol": "G", "name": "Guanine", "colour": "FFB300", "complement": "C"}, | |
2555 {"symbol": "T", "name": "Thymine", "colour": "008000", "complement": "A", | |
2556 "aliases": "U"}, | |
2557 {"symbol": "N", "name": "Any base", "equals": "ACGT", "aliases": "X."}, | |
2558 {"symbol": "V", "name": "Not T", "equals": "ACG"}, | |
2559 {"symbol": "H", "name": "Not G", "equals": "ACT"}, | |
2560 {"symbol": "D", "name": "Not C", "equals": "AGT"}, | |
2561 {"symbol": "B", "name": "Not A", "equals": "CGT"}, | |
2562 {"symbol": "M", "name": "Amino", "equals": "AC"}, | |
2563 {"symbol": "R", "name": "Purine", "equals": "AG"}, | |
2564 {"symbol": "W", "name": "Weak", "equals": "AT"}, | |
2565 {"symbol": "S", "name": "Strong", "equals": "CG"}, | |
2566 {"symbol": "Y", "name": "Pyrimidine", "equals": "CT"}, | |
2567 {"symbol": "K", "name": "Keto", "equals": "GT"} | |
2568 ] | |
2569 }), | |
2570 PROTEIN: new StandardAlphabet(4, "PROTEIN", { | |
2571 "name": "Protein", | |
2572 "like": "PROTEIN", | |
2573 "ncore": 20, | |
2574 "symbols": [ | |
2575 {"symbol": "A", "name": "Alanine", "colour": "0000CC"}, | |
2576 {"symbol": "C", "name": "Cysteine", "colour": "0000CC"}, | |
2577 {"symbol": "D", "name": "Aspartic acid", "colour": "FF00FF"}, | |
2578 {"symbol": "E", "name": "Glutamic acid", "colour": "FF00FF"}, | |
2579 {"symbol": "F", "name": "Phenylalanine", "colour": "0000CC"}, | |
2580 {"symbol": "G", "name": "Glycine", "colour": "FFB300"}, | |
2581 {"symbol": "H", "name": "Histidine", "colour": "FFCCCC"}, | |
2582 {"symbol": "I", "name": "Isoleucine", "colour": "0000CC"}, | |
2583 {"symbol": "K", "name": "Lysine", "colour": "CC0000"}, | |
2584 {"symbol": "L", "name": "Leucine", "colour": "0000CC"}, | |
2585 {"symbol": "M", "name": "Methionine", "colour": "0000CC"}, | |
2586 {"symbol": "N", "name": "Asparagine", "colour": "008000"}, | |
2587 {"symbol": "P", "name": "Proline", "colour": "FFFF00"}, | |
2588 {"symbol": "Q", "name": "Glutamine", "colour": "008000"}, | |
2589 {"symbol": "R", "name": "Arginine", "colour": "CC0000"}, | |
2590 {"symbol": "S", "name": "Serine", "colour": "008000"}, | |
2591 {"symbol": "T", "name": "Threonine", "colour": "008000"}, | |
2592 {"symbol": "V", "name": "Valine", "colour": "0000CC"}, | |
2593 {"symbol": "W", "name": "Tryptophan", "colour": "0000CC"}, | |
2594 {"symbol": "Y", "name": "Tyrosine", "colour": "33E6CC"}, | |
2595 {"symbol": "X", "name": "Any amino acid", "equals": "ACDEFGHIKLMNPQRSTVWY", "aliases": "*."}, | |
2596 {"symbol": "B", "name": "Asparagine or Aspartic acid", "equals": "DN"}, | |
2597 {"symbol": "Z", "name": "Glutamine or Glutamic acid", "equals": "EQ"}, | |
2598 {"symbol": "J", "name": "Leucine or Isoleucine", "equals": "IL"} | |
2599 ] | |
2600 }) | |
2601 }; | |
2602 | |
2603 //====================================================================== | |
2604 // start Symbol object | |
2605 //====================================================================== | |
2606 var Symbol = function(alph_index, scale, alphabet) { | |
2607 "use strict"; | |
2608 //variable prototype | |
2609 this.symbol = alphabet.get_symbol(alph_index); | |
2610 this.scale = scale; | |
2611 this.colour = alphabet.get_colour(alph_index); | |
2612 }; | |
2613 | |
2614 Symbol.prototype.get_symbol = function() { | |
2615 "use strict"; | |
2616 return this.symbol; | |
2617 }; | |
2618 | |
2619 Symbol.prototype.get_scale = function() { | |
2620 "use strict"; | |
2621 return this.scale; | |
2622 }; | |
2623 | |
2624 Symbol.prototype.get_colour = function() { | |
2625 "use strict"; | |
2626 return this.colour; | |
2627 }; | |
2628 | |
2629 Symbol.prototype.toString = function() { | |
2630 "use strict"; | |
2631 return this.symbol + " " + (Math.round(this.scale*1000)/10) + "%"; | |
2632 }; | |
2633 | |
2634 function compare_symbol(sym1, sym2) { | |
2635 "use strict"; | |
2636 if (sym1.get_scale() < sym2.get_scale()) { | |
2637 return -1; | |
2638 } else if (sym1.get_scale() > sym2.get_scale()) { | |
2639 return 1; | |
2640 } else { | |
2641 return 0; | |
2642 } | |
2643 } | |
2644 //====================================================================== | |
2645 // end Symbol object | |
2646 //====================================================================== | |
2647 | |
2648 //====================================================================== | |
2649 // start Pspm object | |
2650 //====================================================================== | |
2651 var Pspm = function(matrix, name, ltrim, rtrim, nsites, evalue, pssm, alt) { | |
2652 "use strict"; | |
2653 var row, col, data, row_sum, delta, evalue_re; | |
2654 if (typeof name !== "string") { | |
2655 name = ""; | |
2656 } | |
2657 this.name = name; | |
2658 //construct | |
2659 if (matrix instanceof Pspm) { | |
2660 // copy constructor | |
2661 this.alph_length = matrix.alph_length; | |
2662 this.motif_length = matrix.motif_length; | |
2663 this.name = matrix.name; | |
2664 this.alt = matrix.alt; | |
2665 this.nsites = matrix.nsites; | |
2666 this.evalue = matrix.evalue; | |
2667 this.ltrim = matrix.ltrim; | |
2668 this.rtrim = matrix.rtrim; | |
2669 this.pspm = []; | |
2670 for (row = 0; row < matrix.motif_length; row++) { | |
2671 this.pspm[row] = []; | |
2672 for (col = 0; col < matrix.alph_length; col++) { | |
2673 this.pspm[row][col] = matrix.pspm[row][col]; | |
2674 } | |
2675 } | |
2676 if (matrix.pssm != null) { | |
2677 this.pssm = []; | |
2678 for (row = 0; row < matrix.motif_length; row++) { | |
2679 this.pspm[row] = []; | |
2680 for (col = 0; col < matrix.alph_length; col++) { | |
2681 this.pssm[row][col] = matrix.pssm[row][col]; | |
2682 } | |
2683 } | |
2684 } | |
2685 } else { | |
2686 // check parameters | |
2687 if (ltrim == null) { | |
2688 ltrim = 0; | |
2689 } else if (typeof ltrim !== "number" || ltrim % 1 !== 0 || ltrim < 0) { | |
2690 throw new Error("ltrim must be a non-negative integer, got: " + ltrim); | |
2691 } | |
2692 if (rtrim == null) { | |
2693 rtrim = 0; | |
2694 } else if (typeof rtrim !== "number" || rtrim % 1 !== 0 || rtrim < 0) { | |
2695 throw new Error("rtrim must be a non-negative integer, got: " + rtrim); | |
2696 } | |
2697 if (nsites != null) { | |
2698 if (typeof nsites !== "number" || nsites < 0) { | |
2699 throw new Error("nsites must be a positive number, got: " + nsites); | |
2700 } else if (nsites == 0) { | |
2701 nsites = null; | |
2702 } | |
2703 } | |
2704 if (evalue != null) { | |
2705 if (typeof evalue === "number") { | |
2706 if (evalue < 0) { | |
2707 throw new Error("evalue must be a non-negative number, got: " + evalue); | |
2708 } | |
2709 } else if (typeof evalue === "string") { | |
2710 evalue_re = /^((?:[+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?)|inf)$/; | |
2711 if (!evalue_re.test(evalue)) { | |
2712 throw new Error("evalue must be a non-negative number, got: " + evalue); | |
2713 } | |
2714 } else { | |
2715 throw new Error("evalue must be a non-negative number, got: " + evalue); | |
2716 } | |
2717 } | |
2718 // set properties | |
2719 this.name = name; | |
2720 this.alt = alt; | |
2721 this.nsites = nsites; | |
2722 this.evalue = evalue; | |
2723 this.ltrim = ltrim; | |
2724 this.rtrim = rtrim; | |
2725 if (typeof matrix === "string") { | |
2726 // string constructor | |
2727 data = parse_pspm_string(matrix); | |
2728 this.alph_length = data["alph_length"]; | |
2729 this.motif_length = data["motif_length"]; | |
2730 this.pspm = data["pspm"]; | |
2731 if (this.evalue == null) { | |
2732 if (data["evalue"] != null) { | |
2733 this.evalue = data["evalue"]; | |
2734 } else { | |
2735 this.evalue = 0; | |
2736 } | |
2737 } | |
2738 if (this.nsites == null) { | |
2739 if (typeof data["nsites"] === "number") { | |
2740 this.nsites = data["nsites"]; | |
2741 } else { | |
2742 this.nsites = 20; | |
2743 } | |
2744 } | |
2745 } else { | |
2746 // assume pspm is a nested array | |
2747 this.motif_length = matrix.length; | |
2748 this.alph_length = (matrix.length > 0 ? matrix[0].length : 0); | |
2749 if (this.nsites == null) { | |
2750 this.nsites = 20; | |
2751 } | |
2752 if (this.evalue == null) { | |
2753 this.evalue = 0; | |
2754 } | |
2755 this.pspm = []; | |
2756 // copy pspm and check | |
2757 for (row = 0; row < this.motif_length; row++) { | |
2758 if (this.alph_length != matrix[row].length) { | |
2759 throw new Error("COLUMN_MISMATCH"); | |
2760 } | |
2761 this.pspm[row] = []; | |
2762 row_sum = 0; | |
2763 for (col = 0; col < this.alph_length; col++) { | |
2764 this.pspm[row][col] = matrix[row][col]; | |
2765 row_sum += this.pspm[row][col]; | |
2766 } | |
2767 delta = 0.1; | |
2768 if (isNaN(row_sum) || (row_sum > 1 && (row_sum - 1) > delta) || | |
2769 (row_sum < 1 && (1 - row_sum) > delta)) { | |
2770 throw new Error("INVALID_SUM"); | |
2771 } | |
2772 } | |
2773 // copy pssm | |
2774 if (pssm != null) { | |
2775 this.pssm = []; | |
2776 for (row = 0; row < this.motif_length; row++) { | |
2777 this.pssm[row] = []; | |
2778 for (col = 0; col < this.alph_length; col++) { | |
2779 this.pssm[row][col] = pssm[row][col]; | |
2780 } | |
2781 } | |
2782 } | |
2783 } | |
2784 } | |
2785 }; | |
2786 | |
2787 Pspm.prototype.copy = function() { | |
2788 "use strict"; | |
2789 return new Pspm(this); | |
2790 }; | |
2791 | |
2792 Pspm.prototype.reverse = function() { | |
2793 "use strict"; | |
2794 var x, y, temp, temp_trim; | |
2795 //reverse | |
2796 x = 0; | |
2797 y = this.motif_length-1; | |
2798 while (x < y) { | |
2799 temp = this.pspm[x]; | |
2800 this.pspm[x] = this.pspm[y]; | |
2801 this.pspm[y] = temp; | |
2802 x++; | |
2803 y--; | |
2804 } | |
2805 // reverse pssm (if defined) | |
2806 if (typeof this.pssm !== "undefined") { | |
2807 //reverse | |
2808 x = 0; | |
2809 y = this.motif_length-1; | |
2810 while (x < y) { | |
2811 temp = this.pssm[x]; | |
2812 this.pspm[x] = this.pssm[y]; | |
2813 this.pssm[y] = temp; | |
2814 x++; | |
2815 y--; | |
2816 } | |
2817 } | |
2818 //swap triming | |
2819 temp_trim = this.ltrim; | |
2820 this.ltrim = this.rtrim; | |
2821 this.rtrim = temp_trim; | |
2822 return this; //allow function chaining... | |
2823 }; | |
2824 | |
2825 Pspm.prototype.reverse_complement = function(alphabet) { | |
2826 "use strict"; | |
2827 var x, y, temp, i, row, c, temp_trim; | |
2828 if (this.alph_length != alphabet.get_size_core()) { | |
2829 throw new Error("The alphabet size does not match the size of the pspm."); | |
2830 } | |
2831 if (!alphabet.has_complement()) { | |
2832 throw new Error("The specified alphabet can not be complemented."); | |
2833 } | |
2834 // reverse motif | |
2835 this.reverse(); | |
2836 //complement | |
2837 for (x = 0; x < this.motif_length; x++) { | |
2838 row = this.pspm[x]; | |
2839 for (i = 0; i < row.length; i++) { | |
2840 c = alphabet.get_complement(i); | |
2841 if (c < i) continue; | |
2842 temp = row[i]; | |
2843 row[i] = row[c]; | |
2844 row[c] = temp; | |
2845 } | |
2846 } | |
2847 // complement pssm (if defined) | |
2848 if (typeof this.pssm !== "undefined") { | |
2849 //complement | |
2850 for (x = 0; x < this.motif_length; x++) { | |
2851 row = this.pssm[x]; | |
2852 for (i = 0; i < row.length; i++) { | |
2853 c = alphabet.get_complement(i); | |
2854 if (c < i) continue; | |
2855 temp = row[i]; | |
2856 row[i] = row[c]; | |
2857 row[c] = temp; | |
2858 } | |
2859 } | |
2860 } | |
2861 return this; //allow function chaining... | |
2862 }; | |
2863 | |
2864 Pspm.prototype.get_stack = function(position, alphabet, ssc) { | |
2865 "use strict"; | |
2866 var row, stack_ic, alphabet_ic, stack, i, sym; | |
2867 if (this.alph_length != alphabet.get_size_core()) { | |
2868 throw new Error("The alphabet size does not match the size of the pspm."); | |
2869 } | |
2870 row = this.pspm[position]; | |
2871 stack_ic = this.get_stack_ic(position, alphabet); | |
2872 if (ssc) stack_ic -= this.get_error(alphabet); | |
2873 alphabet_ic = alphabet.get_ic(); | |
2874 stack = []; | |
2875 for (i = 0; i < this.alph_length; i++) { | |
2876 sym = new Symbol(i, row[i]*stack_ic/alphabet_ic, alphabet); | |
2877 if (sym.get_scale() <= 0) { | |
2878 continue; | |
2879 } | |
2880 stack.push(sym); | |
2881 } | |
2882 stack.sort(compare_symbol); | |
2883 return stack; | |
2884 }; | |
2885 | |
2886 Pspm.prototype.get_stack_ic = function(position, alphabet) { | |
2887 "use strict"; | |
2888 var row, H, i; | |
2889 if (this.alph_length != alphabet.get_size_core()) { | |
2890 throw new Error("The alphabet size does not match the size fo the pspm."); | |
2891 } | |
2892 row = this.pspm[position]; | |
2893 H = 0; | |
2894 for (i = 0; i < this.alph_length; i++) { | |
2895 if (row[i] === 0) { | |
2896 continue; | |
2897 } | |
2898 H -= (row[i] * (Math.log(row[i]) / Math.LN2)); | |
2899 } | |
2900 return alphabet.get_ic() - H; | |
2901 }; | |
2902 | |
2903 Pspm.prototype.get_error = function(alphabet) { | |
2904 "use strict"; | |
2905 if (this.nsites === 0) { | |
2906 return 0; | |
2907 } | |
2908 return (alphabet.get_size_core()-1) / (2 * Math.LN2 * this.nsites); | |
2909 }; | |
2910 | |
2911 Pspm.prototype.get_motif_length = function() { | |
2912 "use strict"; | |
2913 return this.motif_length; | |
2914 }; | |
2915 | |
2916 Pspm.prototype.get_alph_length = function() { | |
2917 "use strict"; | |
2918 return this.alph_length; | |
2919 }; | |
2920 | |
2921 Pspm.prototype.get_left_trim = function() { | |
2922 "use strict"; | |
2923 return this.ltrim; | |
2924 }; | |
2925 | |
2926 Pspm.prototype.get_right_trim = function() { | |
2927 "use strict"; | |
2928 return this.rtrim; | |
2929 }; | |
2930 | |
2931 Pspm.prototype.as_best_match = function(alphabet) { | |
2932 "use strict"; | |
2933 var match, odds, best_odds, best_index; | |
2934 var i, j; | |
2935 match = ""; | |
2936 for (i = 0; i < this.motif_length; i++) { | |
2937 best_index = 0; | |
2938 best_odds = this.pspm[i][0] / alphabet.get_bg_freq(0); | |
2939 for (j = 1; j < this.alph_length; j++) { | |
2940 odds = this.pspm[i][j] / alphabet.get_bg_freq(j); | |
2941 if (odds > best_odds) { | |
2942 best_odds = odds; | |
2943 best_index = j; | |
2944 } | |
2945 } | |
2946 match += alphabet.get_symbol(best_index); | |
2947 } | |
2948 return match; | |
2949 }; | |
2950 | |
2951 Pspm.prototype.as_count_matrix = function() { | |
2952 "use strict"; | |
2953 var count, count_text, text; | |
2954 var i, j; | |
2955 text = ""; | |
2956 for (i = 0; i < this.motif_length; i++) { | |
2957 if (i !== 0) { | |
2958 text += "\n"; | |
2959 } | |
2960 for (j = 0; j < this.alph_length; j++) { | |
2961 if (j !== 0) { | |
2962 text += " "; | |
2963 } | |
2964 count = Math.round(this.nsites * this.pspm[i][j]); | |
2965 count_text = "" + count; | |
2966 // pad up to length of 4 | |
2967 if (count_text.length < 4) { | |
2968 text += (new Array(5 - count_text.length)).join(" ") + count_text; | |
2969 } else { | |
2970 text += count_text; | |
2971 } | |
2972 } | |
2973 } | |
2974 return text; | |
2975 }; | |
2976 | |
2977 Pspm.prototype.as_probability_matrix = function() { | |
2978 "use strict"; | |
2979 var text; | |
2980 var i, j; | |
2981 text = ""; | |
2982 for (i = 0; i < this.motif_length; i++) { | |
2983 if (i !== 0) { | |
2984 text += "\n"; | |
2985 } | |
2986 for (j = 0; j < this.alph_length; j++) { | |
2987 if (j !== 0) { | |
2988 text += " "; | |
2989 } | |
2990 text += this.pspm[i][j].toFixed(6); | |
2991 } | |
2992 } | |
2993 return text; | |
2994 }; | |
2995 | |
2996 Pspm.prototype.as_score_matrix = function(alphabet, pseudo) { | |
2997 "use strict"; | |
2998 var me, score, out, row, col, score_text; | |
2999 me = this; | |
3000 if (typeof this.pssm === "undefined") { | |
3001 if (!(typeof alphabet === "object" && alphabet != null && alphabet instanceof Alphabet)) { | |
3002 throw new Error("The alphabet is required to generate the pssm."); | |
3003 } | |
3004 if (typeof pseudo === "undefined") { | |
3005 pseudo = 0.01; | |
3006 } else if (typeof pseudo !== "number" || pseudo < 0) { | |
3007 throw new Error("Expected positive number for pseudocount"); | |
3008 } | |
3009 score = function(row, col) { | |
3010 "use strict"; | |
3011 var p, bg, p2; | |
3012 p = me.pspm[row][col]; | |
3013 bg = alphabet.get_bg_freq(col); | |
3014 p2 = (p * me.nsites + bg * pseudo) / (me.nsites + pseudo); | |
3015 return (p2 > 0 ? Math.round((Math.log(p2 / bg) / Math.LN2) * 100) : -10000); | |
3016 }; | |
3017 } else { | |
3018 score = function(row, col) { | |
3019 "use strict"; | |
3020 return me.pssm[row][col]; | |
3021 }; | |
3022 } | |
3023 out = ""; | |
3024 for (row = 0; row < this.motif_length; row++) { | |
3025 for (col = 0; col < this.alph_length; col++) { | |
3026 if (col !== 0) { | |
3027 out += " "; | |
3028 } | |
3029 score_text = "" + score(row, col); | |
3030 // pad out to 6 characters | |
3031 if (score_text.length < 6) { | |
3032 out += (new Array(7 - score_text.length)).join(" ") + score_text; | |
3033 } else { | |
3034 out += score_text; | |
3035 } | |
3036 } | |
3037 out += "\n"; | |
3038 } | |
3039 return out; | |
3040 } | |
3041 | |
3042 Pspm.prototype.as_pspm = function() { | |
3043 "use strict"; | |
3044 return "letter-probability matrix: alength= " + this.alph_length + | |
3045 " w= " + this.motif_length + " nsites= " + this.nsites + | |
3046 " E= " + (typeof this.evalue === "number" ? | |
3047 this.evalue.toExponential() : this.evalue) + "\n" + | |
3048 this.as_probability_matrix(); | |
3049 }; | |
3050 | |
3051 Pspm.prototype.as_pssm = function(alphabet, pseudo) { | |
3052 "use strict"; | |
3053 return "log-odds matrix: alength= " + this.alph_length + | |
3054 " w= " + this.motif_length + | |
3055 " E= " + (typeof this.evalue == "number" ? | |
3056 this.evalue.toExponential() : this.evalue) + "\n" + | |
3057 this.as_score_matrix(alphabet, pseudo); | |
3058 }; | |
3059 | |
3060 Pspm.prototype.as_meme = function(options) { | |
3061 var with_header, with_pspm, with_pssm, version, alphabet, bg_source, pseudocount, strands; | |
3062 var out, alen, i; | |
3063 // get the options | |
3064 if (typeof options !== "object" || options === null) { | |
3065 options = {}; | |
3066 } | |
3067 with_header = (typeof options["with_header"] === "boolean" ? options["with_header"] : false); | |
3068 with_pspm = (typeof options["with_pspm"] === "boolean" ? options["with_pspm"] : false); | |
3069 with_pssm = (typeof options["with_pssm"] === "boolean" ? options["with_pssm"] : false); | |
3070 if (!with_pspm && !with_pssm) with_pspm = true; | |
3071 if (with_header) { | |
3072 if (typeof options["version"] === "string" && /^\d+(?:\.\d+){0,2}$/.test(options["version"])) { | |
3073 version = options["version"]; | |
3074 } else if (typeof options["version"] === "number") { | |
3075 version = options["version"].toFixed(0); | |
3076 } else { | |
3077 version = "4"; | |
3078 } | |
3079 if (typeof options["strands"] === "number" && options["strands"] === 1) { | |
3080 strands = 1; | |
3081 } else { | |
3082 strands = 2; | |
3083 } | |
3084 if (typeof options["bg_source"] === "string") { | |
3085 bg_source = options["bg_source"]; | |
3086 } else { | |
3087 bg_source = "unknown source"; | |
3088 } | |
3089 if (typeof options["alphabet"] === "object" && options["alphabet"] != null | |
3090 && options["alphabet"] instanceof Alphabet) { | |
3091 alphabet = options["alphabet"]; | |
3092 } else { | |
3093 throw new Error("The alphabet is required to generate the header."); | |
3094 } | |
3095 } | |
3096 // now create the output | |
3097 out = ""; | |
3098 if (with_header) { | |
3099 out = "MEME version " + version + "\n\n"; | |
3100 out += alphabet.as_meme() + "\n"; | |
3101 if (alphabet.has_complement()) { // assume DNA has both strands unless otherwise specified | |
3102 out += "strands: " + (strands === 1 ? "+" : "+ -") + "\n\n"; | |
3103 } | |
3104 out += "Background letter frequencies (from " + bg_source + "):\n"; | |
3105 alen = alphabet.get_size_core(); | |
3106 for (i = 0; i < alen; i++) { | |
3107 if (i !== 0) { | |
3108 if (i % 9 === 0) { // maximum of nine entries per line | |
3109 out += "\n"; | |
3110 } else { | |
3111 out += " "; | |
3112 } | |
3113 } | |
3114 out += alphabet.get_symbol(i) + " " + alphabet.get_bg_freq(i).toFixed(3); | |
3115 } | |
3116 } | |
3117 out += "\n\n"; | |
3118 out += "MOTIF " + this.name + (this.alt == null ? "" : " " + this.alt); | |
3119 if (with_pssm) { | |
3120 out += "\n\n"; | |
3121 out += this.as_pssm(options["alphabet"], options["pseudocount"]); | |
3122 } | |
3123 if (with_pspm) { | |
3124 out += "\n\n"; | |
3125 out += this.as_pspm(); | |
3126 } | |
3127 return out; | |
3128 } | |
3129 | |
3130 Pspm.prototype.toString = function() { | |
3131 "use strict"; | |
3132 var str, i, row; | |
3133 str = ""; | |
3134 for (i = 0; i < this.pspm.length; i++) { | |
3135 row = this.pspm[i]; | |
3136 str += row.join("\t") + "\n"; | |
3137 } | |
3138 return str; | |
3139 }; | |
3140 | |
3141 function parse_pspm_properties(str) { | |
3142 "use strict"; | |
3143 var parts, i, eqpos, before, after, properties, prop, num, num_re; | |
3144 num_re = /^((?:[+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?)|inf)$/; | |
3145 parts = trim(str).split(/\s+/); | |
3146 // split up words containing = | |
3147 for (i = 0; i < parts.length;) { | |
3148 eqpos = parts[i].indexOf("="); | |
3149 if (eqpos != -1) { | |
3150 before = parts[i].substr(0, eqpos); | |
3151 after = parts[i].substr(eqpos+1); | |
3152 if (before.length > 0 && after.length > 0) { | |
3153 parts.splice(i, 1, before, "=", after); | |
3154 i += 3; | |
3155 } else if (before.length > 0) { | |
3156 parts.splice(i, 1, before, "="); | |
3157 i += 2; | |
3158 } else if (after.length > 0) { | |
3159 parts.splice(i, 1, "=", after); | |
3160 i += 2; | |
3161 } else { | |
3162 parts.splice(i, 1, "="); | |
3163 i++; | |
3164 } | |
3165 } else { | |
3166 i++; | |
3167 } | |
3168 } | |
3169 properties = {}; | |
3170 for (i = 0; i < parts.length; i += 3) { | |
3171 if (parts.length - i < 3) { | |
3172 throw new Error("Expected PSPM property was incomplete. "+ | |
3173 "Remaing parts are: " + parts.slice(i).join(" ")); | |
3174 } | |
3175 if (parts[i+1] !== "=") { | |
3176 throw new Error("Expected '=' in PSPM property between key and " + | |
3177 "value but got " + parts[i+1]); | |
3178 } | |
3179 prop = parts[i].toLowerCase(); | |
3180 num = parts[i+2]; | |
3181 if (!num_re.test(num)) { | |
3182 throw new Error("Expected numeric value for PSPM property '" + | |
3183 prop + "' but got '" + num + "'"); | |
3184 } | |
3185 properties[prop] = num; | |
3186 } | |
3187 return properties; | |
3188 } | |
3189 | |
3190 function parse_pspm_string(pspm_string) { | |
3191 "use strict"; | |
3192 var header_re, lines, first_line, line_num, col_num, alph_length, | |
3193 motif_length, nsites, evalue, pspm, i, line, match, props, parts, | |
3194 j, prob; | |
3195 header_re = /^letter-probability\s+matrix:(.*)$/i; | |
3196 lines = pspm_string.split(/\n/); | |
3197 first_line = true; | |
3198 line_num = 0; | |
3199 col_num = 0; | |
3200 alph_length; | |
3201 motif_length; | |
3202 nsites; | |
3203 evalue; | |
3204 pspm = []; | |
3205 for (i = 0; i < lines.length; i++) { | |
3206 line = trim(lines[i]); | |
3207 if (line.length === 0) { | |
3208 continue; | |
3209 } | |
3210 // check the first line for a header though allow matrices without it | |
3211 if (first_line) { | |
3212 first_line = false; | |
3213 match = header_re.exec(line); | |
3214 if (match !== null) { | |
3215 props = parse_pspm_properties(match[1]); | |
3216 if (props.hasOwnProperty("alength")) { | |
3217 alph_length = parseFloat(props["alength"]); | |
3218 if (alph_length != 4 && alph_length != 20) { | |
3219 throw new Error("PSPM property alength should be 4 or 20" + | |
3220 " but got " + alph_length); | |
3221 } | |
3222 } | |
3223 if (props.hasOwnProperty("w")) { | |
3224 motif_length = parseFloat(props["w"]); | |
3225 if (motif_length % 1 !== 0 || motif_length < 1) { | |
3226 throw new Error("PSPM property w should be an integer larger " + | |
3227 "than zero but got " + motif_length); | |
3228 } | |
3229 } | |
3230 if (props.hasOwnProperty("nsites")) { | |
3231 nsites = parseFloat(props["nsites"]); | |
3232 if (nsites <= 0) { | |
3233 throw new Error("PSPM property nsites should be larger than " + | |
3234 "zero but got " + nsites); | |
3235 } | |
3236 } | |
3237 if (props.hasOwnProperty("e")) { | |
3238 evalue = props["e"]; | |
3239 if (evalue < 0) { | |
3240 throw new Error("PSPM property evalue should be " + | |
3241 "non-negative but got " + evalue); | |
3242 } | |
3243 } | |
3244 continue; | |
3245 } | |
3246 } | |
3247 pspm[line_num] = []; | |
3248 col_num = 0; | |
3249 parts = line.split(/\s+/); | |
3250 for (j = 0; j < parts.length; j++) { | |
3251 prob = parseFloat(parts[j]); | |
3252 if (prob != parts[j] || prob < 0 || prob > 1) { | |
3253 throw new Error("Expected probability but got '" + parts[j] + "'"); | |
3254 } | |
3255 pspm[line_num][col_num] = prob; | |
3256 col_num++; | |
3257 } | |
3258 line_num++; | |
3259 } | |
3260 if (typeof motif_length === "number") { | |
3261 if (pspm.length != motif_length) { | |
3262 throw new Error("Expected PSPM to have a motif length of " + | |
3263 motif_length + " but it was actually " + pspm.length); | |
3264 } | |
3265 } else { | |
3266 motif_length = pspm.length; | |
3267 } | |
3268 if (typeof alph_length !== "number") { | |
3269 alph_length = pspm[0].length; | |
3270 if (alph_length != 4 && alph_length != 20) { | |
3271 throw new Error("Expected length of first row in the PSPM to be " + | |
3272 "either 4 or 20 but got " + alph_length); | |
3273 } | |
3274 } | |
3275 for (i = 0; i < pspm.length; i++) { | |
3276 if (pspm[i].length != alph_length) { | |
3277 throw new Error("Expected PSPM row " + i + " to have a length of " + | |
3278 alph_length + " but the length was " + pspm[i].length); | |
3279 } | |
3280 } | |
3281 return {"pspm": pspm, "motif_length": motif_length, | |
3282 "alph_length": alph_length, "nsites": nsites, "evalue": evalue}; | |
3283 } | |
3284 //====================================================================== | |
3285 // end Pspm object | |
3286 //====================================================================== | |
3287 | |
3288 //====================================================================== | |
3289 // start Logo object | |
3290 //====================================================================== | |
3291 | |
3292 var Logo = function(alphabet, options) { | |
3293 "use strict"; | |
3294 this.alphabet = alphabet; | |
3295 this.fine_text = ""; | |
3296 this.x_axis = 1; | |
3297 this.y_axis = true; | |
3298 this.xlate_nsyms = 1; | |
3299 this.xlate_start = null; | |
3300 this.xlate_end = null; | |
3301 this.pspm_list = []; | |
3302 this.pspm_column = []; | |
3303 this.rows = 0; | |
3304 this.columns = 0; | |
3305 if (typeof options === "string") { | |
3306 // the old method signature had fine_text here so we support that | |
3307 this.fine_text = options; | |
3308 } else if (typeof options === "object" && options != null) { | |
3309 this.fine_text = (typeof options.fine_text === "string" ? options.fine_text : ""); | |
3310 this.x_axis = (typeof options.x_axis === "boolean" ? (options.x_axis ? 1 : 0) : 1); | |
3311 if (options.x_axis_hidden != null && options.x_axis_hidden) this.x_axis = -1; | |
3312 this.y_axis = (typeof options.y_axis === "boolean" ? options.y_axis : true); | |
3313 this.xlate_nsyms = (typeof options.xlate_nsyms === "number" ? options.xlate_nsyms : this.xlate_nsyms); | |
3314 this.xlate_start = (typeof options.xlate_start === "number" ? options.xlate_start : this.xlate_start); | |
3315 this.xlate_end = (typeof options.xlate_end === "number" ? options.xlate_end : this.xlate_end); | |
3316 } | |
3317 }; | |
3318 | |
3319 Logo.prototype.add_pspm = function(pspm, column) { | |
3320 "use strict"; | |
3321 var col; | |
3322 if (typeof column === "undefined") { | |
3323 column = 0; | |
3324 } else if (column < 0) { | |
3325 throw new Error("Column index out of bounds."); | |
3326 } | |
3327 this.pspm_list[this.rows] = pspm; | |
3328 this.pspm_column[this.rows] = column; | |
3329 this.rows++; | |
3330 col = column + pspm.get_motif_length(); | |
3331 if (col > this.columns) { | |
3332 this.columns = col; | |
3333 } | |
3334 }; | |
3335 | |
3336 Logo.prototype.get_columns = function() { | |
3337 "use strict"; | |
3338 return this.columns; | |
3339 }; | |
3340 | |
3341 Logo.prototype.get_xlate_nsyms = function() { | |
3342 "use strict"; | |
3343 return this.xlate_nsyms; | |
3344 }; | |
3345 | |
3346 Logo.prototype.get_xlate_start = function() { | |
3347 "use strict"; | |
3348 return (this.xlate_start != null ? this.xlate_start : 0); | |
3349 }; | |
3350 | |
3351 Logo.prototype.get_xlate_end = function() { | |
3352 "use strict"; | |
3353 return (this.xlate_end != null ? this.xlate_end : this.columns * this.xlate_nsyms); | |
3354 }; | |
3355 | |
3356 Logo.prototype.get_xlate_columns = function() { | |
3357 "use strict"; | |
3358 return this.get_xlate_end() - this.get_xlate_start(); | |
3359 }; | |
3360 | |
3361 Logo.prototype.get_rows = function() { | |
3362 "use strict"; | |
3363 return this.rows; | |
3364 }; | |
3365 | |
3366 Logo.prototype.get_pspm = function(row_index) { | |
3367 "use strict"; | |
3368 if (row_index < 0 || row_index >= this.rows) { | |
3369 throw new Error("INDEX_OUT_OF_BOUNDS"); | |
3370 } | |
3371 return this.pspm_list[row_index]; | |
3372 }; | |
3373 | |
3374 Logo.prototype.get_offset = function(row_index) { | |
3375 "use strict"; | |
3376 if (row_index < 0 || row_index >= this.rows) { | |
3377 throw new Error("INDEX_OUT_OF_BOUNDS"); | |
3378 } | |
3379 return this.pspm_column[row_index]; | |
3380 }; | |
3381 | |
3382 Logo.prototype._as_eps_data = function(ssc, errbars) { | |
3383 var i, j, pos, stack_pos, pspm, stack, sym, out; | |
3384 out = ""; | |
3385 for (i = 0; i < this.rows; i++) { | |
3386 out += "\nStartLine\n"; | |
3387 // Indent | |
3388 for (j = 0; j < this.pspm_column[i]; j++) { | |
3389 out += "() startstack\nendstack\n\n"; | |
3390 } | |
3391 pspm = this.pspm_list[i]; | |
3392 if (pspm.get_left_trim() > 0) { | |
3393 out += "MuteColour\nDrawTrimEdge\n" + pspm.get_left_trim() + " DrawTrimBg\n"; | |
3394 } | |
3395 for (pos = 0; pos < pspm.get_motif_length(); pos++) { | |
3396 if (pos != 0 && pos == pspm.get_left_trim()) { // enable full colour | |
3397 out += "DrawTrimEdge\nRestoreColour\n"; | |
3398 } else if (pos == (pspm.get_motif_length() - pspm.get_right_trim())) { | |
3399 out += "MuteColour\n" + pspm.get_right_trim() + " DrawTrimBg\n"; | |
3400 } | |
3401 out += "(" + (pos + 1) + ") startstack\n"; | |
3402 stack = pspm.get_stack(pos, this.alphabet, ssc); | |
3403 for (stack_pos = 0; stack_pos < stack.length; stack_pos++) { | |
3404 sym = stack[stack_pos]; | |
3405 out += " " + (sym.get_scale() * this.alphabet.get_ic()) + " (" + sym.get_symbol() + ") numchar\n"; | |
3406 } | |
3407 if (errbars) { | |
3408 out += " " + pspm.get_error(this.alphabet) + " Ibeam\n"; | |
3409 } | |
3410 out += "endstack\n\n"; | |
3411 } | |
3412 if (pspm.get_right_trim() > 0 || pspm.get_left_trim() == pspm.get_motif_length()) { | |
3413 out += "RestoreColour\n"; | |
3414 } | |
3415 out += "EndLine\n"; | |
3416 } | |
3417 return out; | |
3418 }; | |
3419 | |
3420 Logo.prototype.as_eps = function(options) { | |
3421 "use strict"; | |
3422 if (this.xlate_nsyms != 1) throw new Error("Unsupported setting xlate_nsyms for EPS"); | |
3423 if (this.xlate_start != null) throw new Error("Unsupported setting xlate_start for EPS"); | |
3424 if (this.xlate_end != null) throw new Error("Unsupported setting xlate_end for EPS"); | |
3425 | |
3426 var LOGOHEIGHT = 7.5; // default height of line in cm | |
3427 var cm2pts, height, width, now, ssc, errbars; | |
3428 if (typeof options === "undefined") { | |
3429 options = {}; | |
3430 } | |
3431 cm2pts = 72 / 2.54; | |
3432 if (typeof options.logo_height == "number") { | |
3433 height = options.logo_height; | |
3434 } else { | |
3435 height = LOGOHEIGHT * this.rows; | |
3436 } | |
3437 if (typeof options.logo_width == "number") { | |
3438 width = options.logo_width; | |
3439 } else { | |
3440 width = this.columns + 2; | |
3441 } | |
3442 now = new Date(); | |
3443 ssc = (typeof options.ssc == "boolean" ? options.ssc : false); | |
3444 errbars = (typeof options.show_error_bar == "boolean" ? options.show_error_bar : ssc); | |
3445 var values = { | |
3446 "LOGOHEIGHT": height, | |
3447 "LOGOWIDTH": width, | |
3448 "BOUNDINGHEIGHT": Math.round(height * cm2pts), | |
3449 "BOUNDINGWIDTH": Math.round(width * cm2pts), | |
3450 "LOGOLINEHEIGHT": (height / this.rows), | |
3451 "CHARSPERLINE": this.columns, | |
3452 "BARBITS": this.alphabet.get_ic(), | |
3453 "LOGOTYPE": (this.alphabet.has_complement() ? "NA" : "AA"), | |
3454 "CREATIONDATE": now.getDate() + "." + (now.getMonth() + 1) + "." + now.getFullYear() + " " + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds(), | |
3455 "ERRORBARFRACTION": (typeof options.error_bar_fraction == "number" ? options.error_bar_fraction : 1.0), | |
3456 "TICBITS": (typeof options.ticbits == "number" ? options.ticbits : 1.0), | |
3457 "TITLE": (typeof options.title == "string" ? options.title : ""), | |
3458 "FINEPRINT": (typeof options.fineprint == "string" ? options.fineprint : this.fine_text), | |
3459 "XAXISLABEL": (typeof options.xaxislabel == "string" ? options.xaxislabel : ""), | |
3460 "YAXISLABEL": (typeof options.yaxislabel == "string" ? options.yaxislabel : "bits"), | |
3461 "SSC": ssc, | |
3462 "YAXIS": (typeof options.show_y_axis == "boolean" ? options.show_y_axis : this.y_axis), | |
3463 "SHOWENDS": (typeof options.show_ends == "boolean" ? options.show_ends : false), | |
3464 "ERRBAR": errbars, | |
3465 "OUTLINE": (typeof options.show_outline == "boolean" ? options.show_outline : false), | |
3466 "NUMBERING": (typeof options.show_numbering == "boolean" ? options.show_numbering : this.x_axis != 0), | |
3467 "SHOWINGBOX": (typeof options.show_box == "boolean" ? options.show_box : false), | |
3468 "CREATOR": (typeof options.creator == "string" ? options.creator : "motif_logo.js"), | |
3469 "FONTSIZE": (typeof options.label_font_size == "number" ? options.label_font_size : 12), | |
3470 "TITLEFONTSIZE": (typeof options.title_font_size == "number" ? options.title_font_size : 12), | |
3471 "SMALLFONTSIZE": (typeof options.small_font_size == "number" ? options.small_font_size : 6), | |
3472 "TOPMARGIN" : (typeof options.top_margin == "number" ? options.top_margin : 0.9), | |
3473 "BOTTOMMARGIN": (typeof options.bottom_margin == "number" ? options.bottom_margin : 0.9), | |
3474 "COLORDICT": this.alphabet._as_eps_dict(), | |
3475 "DATA": this._as_eps_data(ssc, errbars) | |
3476 }; | |
3477 // now this requires that the script containing the template has been imported! | |
3478 return motif_logo_template(values); | |
3479 }; | |
3480 | |
3481 //====================================================================== | |
3482 // end Logo object | |
3483 //====================================================================== | |
3484 | |
3485 // calculate the exact size (in pixels) of an object drawn on the | |
3486 // canvas assuming that the background of the canvas is transparent. | |
3487 function canvas_bounds(ctx, cwidth, cheight) { | |
3488 "use strict"; | |
3489 var data, r, c, top_line, bottom_line, left_line, right_line, | |
3490 txt_width, txt_height; | |
3491 | |
3492 // extract the image data | |
3493 data = ctx.getImageData(0, 0, cwidth, cheight).data; | |
3494 | |
3495 // set initial values | |
3496 top_line = -1; bottom_line = -1; left_line = -1; right_line = -1; | |
3497 txt_width = 0; txt_height = 0; | |
3498 | |
3499 // Find the top-most line with a non-transparent pixel | |
3500 for (r = 0; r < cheight; r++) { | |
3501 for (c = 0; c < cwidth; c++) { | |
3502 if (data[r * cwidth * 4 + c * 4 + 3]) { | |
3503 top_line = r; | |
3504 break; | |
3505 } | |
3506 } | |
3507 if (top_line != -1) { | |
3508 break; | |
3509 } | |
3510 } | |
3511 | |
3512 // Only bother looking if we found at least one set pixel... | |
3513 if (top_line != -1) { | |
3514 | |
3515 //find the last line with a non-transparent pixel | |
3516 for (r = cheight-1; r >= top_line; r--) { | |
3517 for(c = 0; c < cwidth; c++) { | |
3518 if(data[r * cwidth * 4 + c * 4 + 3]) { | |
3519 bottom_line = r; | |
3520 break; | |
3521 } | |
3522 } | |
3523 if (bottom_line != -1) { | |
3524 break; | |
3525 } | |
3526 } | |
3527 // calculate height | |
3528 txt_height = bottom_line - top_line + 1; | |
3529 | |
3530 // Find the left-most line with a non-transparent pixel | |
3531 for (c = 0; c < cwidth; c++) { | |
3532 for (r = top_line; r <= bottom_line; r++) { | |
3533 if (data[r * cwidth * 4 + c * 4 + 3]) { | |
3534 left_line = c; | |
3535 break; | |
3536 } | |
3537 } | |
3538 if (left_line != -1) { | |
3539 break; | |
3540 } | |
3541 } | |
3542 | |
3543 //find the right most line with a non-transparent pixel | |
3544 for (c = cwidth-1; c >= left_line; c--) { | |
3545 for(r = top_line; r <= bottom_line; r++) { | |
3546 if(data[r * cwidth * 4 + c * 4 + 3]) { | |
3547 right_line = c; | |
3548 break; | |
3549 } | |
3550 } | |
3551 if (right_line != -1) { | |
3552 break; | |
3553 } | |
3554 } | |
3555 txt_width = right_line - left_line + 1; | |
3556 } | |
3557 | |
3558 //return the bounds | |
3559 return {bound_top: top_line, bound_bottom: bottom_line, | |
3560 bound_left: left_line, bound_right: right_line, width: txt_width, | |
3561 height: txt_height}; | |
3562 } | |
3563 | |
3564 //====================================================================== | |
3565 // start RasterizedAlphabet | |
3566 //====================================================================== | |
3567 | |
3568 // Rasterize Alphabet | |
3569 // 1) Measure width of text at default font for all symbols in alphabet | |
3570 // 2) sort in width ascending | |
3571 // 3) Drop the top and bottom 10% (designed to ignore outliers like 'W' and 'I') | |
3572 // 4) Calculate the average as the maximum scaling factor (designed to stop I becoming a rectangular blob). | |
3573 // 5) Assume scale of zero would result in width of zero, interpolate scale required to make perfect width font | |
3574 // 6) Draw text onto temp canvas at calculated scale | |
3575 // 7) Find bounds of drawn text | |
3576 // 8) Paint on to another canvas at the desired height (but only scaling width to fit if larger). | |
3577 var RasterizedAlphabet = function(alphabet, logo_scale, font, width) { | |
3578 "use strict"; | |
3579 var default_size, safety_pad, canvas, ctx, middle, baseline, widths, sizes, | |
3580 i, sym, size, tenpercent, avg_width, scale, | |
3581 target_width, target_height; | |
3582 //variable prototypes | |
3583 this.alphabet = alphabet; | |
3584 this.scale = logo_scale; | |
3585 this.sym_cache = {}; | |
3586 this.stack_num_cache = []; | |
3587 this.scale_num_cache = []; | |
3588 // size of canvas | |
3589 default_size = 60; // size of measuring canvas | |
3590 safety_pad = 20; // pixels to pad around so we don't miss the edges | |
3591 // create a canvas to do our measuring | |
3592 canvas = document.createElement("canvas"); | |
3593 if (!canvas.getContext) throw new Error("No canvas support"); | |
3594 canvas.width = default_size + 2 * safety_pad; | |
3595 canvas.height = default_size + 2 * safety_pad; | |
3596 middle = Math.round(canvas.width / 2); | |
3597 baseline = Math.round(canvas.height - safety_pad); | |
3598 ctx = canvas.getContext('2d'); | |
3599 if (!supports_text(ctx)) throw new Error("Canvas does not support text"); | |
3600 ctx.font = font; | |
3601 ctx.textAlign = "center"; | |
3602 ctx.translate(middle, baseline); | |
3603 // list of widths | |
3604 widths = []; | |
3605 sizes = []; | |
3606 //now measure each letter in the alphabet | |
3607 for (i = 0; i < alphabet.get_size_core(); ++i) { | |
3608 // reset the canvas | |
3609 ctx.clearRect(0, 0, canvas.width, canvas.height); | |
3610 ctx.fillStyle = alphabet.get_colour(i); | |
3611 // draw the test text | |
3612 ctx.fillText(alphabet.get_symbol(i), 0, 0); | |
3613 //measure | |
3614 size = canvas_bounds(ctx, canvas.width, canvas.height); | |
3615 if (size.width === 0) throw new Error("Invisible symbol!"); | |
3616 widths.push(size.width); | |
3617 sizes[i] = size; | |
3618 } | |
3619 //sort the widths | |
3620 widths.sort(function(a,b) {return a - b;}); | |
3621 //drop 10% of the items off each end | |
3622 tenpercent = Math.floor(widths.length / 10); | |
3623 for (i = 0; i < tenpercent; ++i) { | |
3624 widths.pop(); | |
3625 widths.shift(); | |
3626 } | |
3627 //calculate average width | |
3628 avg_width = 0; | |
3629 for (i = 0; i < widths.length; ++i) { | |
3630 avg_width += widths[i]; | |
3631 } | |
3632 avg_width /= widths.length; | |
3633 // calculate the target width | |
3634 target_width = width * this.scale * 2; | |
3635 // calculate scales | |
3636 for (i = 0; i < alphabet.get_size_core(); ++i) { | |
3637 sym = alphabet.get_symbol(i); | |
3638 size = sizes[i]; | |
3639 // calculate scale | |
3640 scale = target_width / Math.max(avg_width, size.width); | |
3641 // estimate scaled height | |
3642 target_height = size.height * scale; | |
3643 // create an appropriately sized canvas | |
3644 canvas = document.createElement("canvas"); | |
3645 canvas.width = target_width; | |
3646 canvas.height = target_height + safety_pad * 2; | |
3647 // calculate the middle | |
3648 middle = Math.round(canvas.width / 2); | |
3649 // calculate the baseline | |
3650 baseline = Math.round(canvas.height - safety_pad); | |
3651 // get the context and prepare to draw the rasterized text | |
3652 ctx = canvas.getContext('2d'); | |
3653 ctx.font = font; | |
3654 ctx.fillStyle = alphabet.get_colour(i); | |
3655 ctx.textAlign = "center"; | |
3656 ctx.translate(middle, baseline); | |
3657 ctx.save(); | |
3658 ctx.scale(scale, scale); | |
3659 // draw the text | |
3660 ctx.fillText(sym, 0, 0); | |
3661 ctx.restore(); | |
3662 this.sym_cache[sym] = {"image": canvas, "size": canvas_bounds(ctx, canvas.width, canvas.height)}; | |
3663 } | |
3664 }; | |
3665 | |
3666 RasterizedAlphabet.prototype.get_alphabet = function() { | |
3667 return this.alphabet; | |
3668 }; | |
3669 | |
3670 RasterizedAlphabet.prototype.get_scale = function() { | |
3671 return this.scale; | |
3672 }; | |
3673 | |
3674 RasterizedAlphabet.prototype.draw_stack_sym = function(ctx, letter, dx, dy, dWidth, dHeight) { | |
3675 "use strict"; | |
3676 var entry, image, size; | |
3677 entry = this.sym_cache[letter]; | |
3678 image = entry.image; | |
3679 size = entry.size; | |
3680 ctx.drawImage(image, 0, size.bound_top -1, image.width, size.height+1, dx, dy, dWidth, dHeight); | |
3681 }; | |
3682 | |
3683 RasterizedAlphabet.prototype.draw_stack_num = function(ctx, font, stack_width, index) { | |
3684 var image, image_ctx, text_length; | |
3685 if (index >= this.stack_num_cache.length) { | |
3686 image = document.createElement("canvas"); | |
3687 // measure the text | |
3688 image_ctx = image.getContext('2d'); | |
3689 image_ctx.save(); | |
3690 image_ctx.font = font; | |
3691 text_length = image_ctx.measureText("" + (index + 1)).width; | |
3692 image_ctx.restore(); | |
3693 // resize the canvas to fit | |
3694 image.width = Math.ceil(stack_width); | |
3695 image.height = Math.ceil(text_length); | |
3696 // draw the text | |
3697 image_ctx = image.getContext('2d'); | |
3698 image_ctx.translate(Math.round(stack_width / 2), 0); | |
3699 image_ctx.font = font; | |
3700 image_ctx.textBaseline = "middle"; | |
3701 image_ctx.textAlign = "right"; | |
3702 image_ctx.rotate(-(Math.PI / 2)); | |
3703 image_ctx.fillText("" + (index + 1), 0, 0); | |
3704 this.stack_num_cache[index] = image; | |
3705 } else { | |
3706 image = this.stack_num_cache[index]; | |
3707 } | |
3708 ctx.drawImage(image, 0, 0); | |
3709 } | |
3710 | |
3711 RasterizedAlphabet.prototype.draw_scale_num = function(ctx, font, num) { | |
3712 var image, image_ctx, text_size, m_length; | |
3713 if (num >= this.scale_num_cache.length) { | |
3714 image = document.createElement("canvas"); | |
3715 // measure the text | |
3716 image_ctx = image.getContext('2d'); | |
3717 image_ctx.font = font; | |
3718 text_size = image_ctx.measureText("" + num); | |
3719 if (text_size.actualBoundingBoxAscent && text_size.actualBoundingBoxDesent) { | |
3720 // resize the canvas to fit | |
3721 image.width = Math.ceil(text_size.width); | |
3722 image.height = Math.ceil(text_size.actualBoundingBoxAscent + text_size.actualBoundingBoxDesent); | |
3723 // draw the text | |
3724 image_ctx = image.getContext('2d'); | |
3725 image_ctx.font = font; | |
3726 image_ctx.textAlign = "right"; | |
3727 image_ctx.fillText("" + num, image.width, text_size.actualBoundingBoxAscent); | |
3728 } else { | |
3729 // measure width of 'm' to approximate height, we double it later anyway | |
3730 m_length = image_ctx.measureText("m").width; | |
3731 // resize the canvas to fit | |
3732 image.width = Math.ceil(text_size.width); | |
3733 image.height = Math.ceil(2 * m_length); | |
3734 // draw the text | |
3735 image_ctx = image.getContext('2d'); | |
3736 image_ctx.font = font; | |
3737 image_ctx.textAlign = "right"; | |
3738 image_ctx.textBaseline = "middle"; | |
3739 image_ctx.fillText("" + num, image.width, m_length); | |
3740 } | |
3741 this.scale_num_cache[num] = image; | |
3742 } else { | |
3743 image = this.scale_num_cache[num]; | |
3744 } | |
3745 ctx.drawImage(image, -image.width, -Math.round(image.height / 2)) | |
3746 } | |
3747 | |
3748 //====================================================================== | |
3749 // end RasterizedAlphabet | |
3750 //====================================================================== | |
3751 | |
3752 //====================================================================== | |
3753 // start LogoMetrics object | |
3754 //====================================================================== | |
3755 | |
3756 var LogoMetrics = function(ctx, logo_columns, logo_rows, has_names, has_finetext, x_axis, y_axis) { | |
3757 "use strict"; | |
3758 var i, row_height; | |
3759 //variable prototypes | |
3760 this.pad_top = (has_names ? 5 : 0); | |
3761 this.pad_left = (y_axis ? 10 : 0); | |
3762 this.pad_right = (has_finetext ? 15 : 0); | |
3763 this.pad_bottom = 0; | |
3764 this.pad_middle = 20; | |
3765 this.name_height = 14; | |
3766 this.name_font = "bold " + this.name_height + "px Times, sans-serif"; | |
3767 this.name_spacer = 0; | |
3768 this.y_axis = y_axis; | |
3769 this.y_label = "bits"; | |
3770 this.y_label_height = 12; | |
3771 this.y_label_font = "bold " + this.y_label_height + "px Helvetica, sans-serif"; | |
3772 this.y_label_spacer = 3; | |
3773 this.y_num_height = 12; | |
3774 this.y_num_width = 0; | |
3775 this.y_num_font = "bold " + this.y_num_height + "px Helvetica, sans-serif"; | |
3776 this.y_tic_width = 5; | |
3777 this.stack_pad_left = 0; | |
3778 this.stack_font = "bold 25px Helvetica, sans-serif"; | |
3779 this.stack_height = 90; | |
3780 this.stack_width = 26; | |
3781 this.stacks_pad_right = 5; | |
3782 this.x_axis = x_axis; | |
3783 this.x_num_above = 2; | |
3784 this.x_num_height = 12; | |
3785 this.x_num_width = 0; | |
3786 this.x_num_font = "bold " + this.x_num_height + "px Helvetica, sans-serif"; | |
3787 this.fine_txt_height = 6; | |
3788 this.fine_txt_above = 2; | |
3789 this.fine_txt_font = "normal " + this.fine_txt_height + "px Helvetica, sans-serif"; | |
3790 this.letter_metrics = new Array(); | |
3791 this.summed_width = 0; | |
3792 this.summed_height = 0; | |
3793 //calculate the width of the y axis numbers | |
3794 ctx.font = this.y_num_font; | |
3795 for (i = 0; i <= 2; i++) { | |
3796 this.y_num_width = Math.max(this.y_num_width, ctx.measureText("" + i).width); | |
3797 } | |
3798 //calculate the width of the x axis numbers (but they are rotated so it becomes height) | |
3799 if (x_axis == 1) { | |
3800 ctx.font = this.x_num_font; | |
3801 for (i = 1; i <= logo_columns; i++) { | |
3802 this.x_num_width = Math.max(this.x_num_width, ctx.measureText("" + i).width); | |
3803 } | |
3804 } else if (x_axis == 0) { | |
3805 this.x_num_height = 4; | |
3806 this.x_num_width = 4; | |
3807 } else { | |
3808 this.x_num_height = 0; | |
3809 this.x_num_width = 0; | |
3810 } | |
3811 | |
3812 //calculate how much vertical space we want to draw this | |
3813 //first we add the padding at the top and bottom since that's always there | |
3814 this.summed_height += this.pad_top + this.pad_bottom; | |
3815 //all except the last row have the same amount of space allocated to them | |
3816 if (logo_rows > 1) { | |
3817 row_height = this.stack_height + this.pad_middle; | |
3818 if (has_names) { | |
3819 row_height += this.name_height; | |
3820 //the label is allowed to overlap into the spacer | |
3821 row_height += Math.max(this.y_num_height/2, this.name_spacer); | |
3822 //the label is allowed to overlap the space used by the other label | |
3823 row_height += Math.max(this.y_num_height/2, this.x_num_height + this.x_num_above); | |
3824 } else { | |
3825 row_height += this.y_num_height/2; | |
3826 //the label is allowed to overlap the space used by the other label | |
3827 row_height += Math.max(this.y_num_height/2, this.x_num_height + this.x_num_above); | |
3828 } | |
3829 this.summed_height += row_height * (logo_rows - 1); | |
3830 } | |
3831 //the last row has the name and fine text below it but no padding | |
3832 this.summed_height += this.stack_height + (this.y_axis ? this.y_num_height/2 : 0); | |
3833 | |
3834 var fine_txt_total = (has_finetext ? this.fine_txt_height + this.fine_txt_above : 0); | |
3835 if (has_names) { | |
3836 this.summed_height += fine_txt_total + this.name_height; | |
3837 this.summed_height += Math.max((this.y_axis ? this.y_num_height/2 : 0), | |
3838 this.x_num_height + this.x_num_above + this.name_spacer); | |
3839 } else { | |
3840 this.summed_height += Math.max((this.y_axis ? this.y_num_height/2 : 0), | |
3841 this.x_num_height + this.x_num_above + fine_txt_total); | |
3842 } | |
3843 | |
3844 //calculate how much horizontal space we want to draw this | |
3845 //first add the padding at the left and right since that's always there | |
3846 this.summed_width += this.pad_left + this.pad_right; | |
3847 if (this.y_axis) { | |
3848 //add on the space for the y-axis label | |
3849 this.summed_width += this.y_label_height + this.y_label_spacer; | |
3850 //add on the space for the y-axis | |
3851 this.summed_width += this.y_num_width + this.y_tic_width; | |
3852 } | |
3853 //add on the space for the stacks | |
3854 this.summed_width += (this.stack_pad_left + this.stack_width) * logo_columns; | |
3855 //add on the padding after the stacks (an offset from the fine text) | |
3856 this.summed_width += this.stacks_pad_right; | |
3857 | |
3858 }; | |
3859 | |
3860 //====================================================================== | |
3861 // end LogoMetrics object | |
3862 //====================================================================== | |
3863 | |
3864 //found this trick at http://talideon.com/weblog/2005/02/detecting-broken-images-js.cfm | |
3865 function image_ok(img) { | |
3866 "use strict"; | |
3867 // During the onload event, IE correctly identifies any images that | |
3868 // weren't downloaded as not complete. Others should too. Gecko-based | |
3869 // browsers act like NS4 in that they report this incorrectly. | |
3870 if (!img.complete) { | |
3871 return false; | |
3872 } | |
3873 // However, they do have two very useful properties: naturalWidth and | |
3874 // naturalHeight. These give the true size of the image. If it failed | |
3875 // to load, either of these should be zero. | |
3876 if (typeof img.naturalWidth !== "undefined" && img.naturalWidth === 0) { | |
3877 return false; | |
3878 } | |
3879 // No other way of checking: assume it's ok. | |
3880 return true; | |
3881 } | |
3882 | |
3883 function supports_text(ctx) { | |
3884 "use strict"; | |
3885 if (!ctx.fillText) { | |
3886 return false; | |
3887 } | |
3888 if (!ctx.measureText) { | |
3889 return false; | |
3890 } | |
3891 return true; | |
3892 } | |
3893 | |
3894 //draws the scale, returns the width | |
3895 function draw_scale(ctx, metrics, alphabet_ic, raster) { | |
3896 "use strict"; | |
3897 var tic_height, i; | |
3898 tic_height = metrics.stack_height / alphabet_ic; | |
3899 ctx.save(); | |
3900 ctx.translate(metrics.y_label_height, metrics.y_num_height/2); | |
3901 //draw the axis label | |
3902 ctx.save(); | |
3903 ctx.font = metrics.y_label_font; | |
3904 ctx.translate(0, metrics.stack_height/2); | |
3905 ctx.rotate(-(Math.PI / 2)); | |
3906 ctx.textAlign = "center"; | |
3907 ctx.fillText("bits", 0, 0); | |
3908 ctx.restore(); | |
3909 | |
3910 ctx.translate(metrics.y_label_spacer + metrics.y_num_width, 0); | |
3911 | |
3912 //draw the axis tics | |
3913 ctx.save(); | |
3914 ctx.translate(0, metrics.stack_height); | |
3915 for (i = 0; i <= alphabet_ic; i++) { | |
3916 //draw the number | |
3917 ctx.save(); | |
3918 ctx.translate(-1, 0); | |
3919 raster.draw_scale_num(ctx, metrics.y_num_font, i); | |
3920 ctx.restore(); | |
3921 //draw the tic | |
3922 ctx.fillRect(0, -1, metrics.y_tic_width, 2); | |
3923 //prepare for next tic | |
3924 ctx.translate(0, -tic_height); | |
3925 } | |
3926 ctx.restore(); | |
3927 | |
3928 ctx.fillRect(metrics.y_tic_width - 2, 0, 2, metrics.stack_height) | |
3929 | |
3930 ctx.restore(); | |
3931 } | |
3932 | |
3933 function draw_stack_num(ctx, metrics, row_index, raster) { | |
3934 "use strict"; | |
3935 ctx.save(); | |
3936 ctx.translate(0, Math.round(metrics.stack_height + metrics.x_num_above)); | |
3937 if (metrics.x_axis == 1) { | |
3938 raster.draw_stack_num(ctx, metrics.x_num_font, metrics.stack_width, row_index); | |
3939 } else if (metrics.x_axis == 0) { | |
3940 // draw dots instead of the numbers (good for small logos) | |
3941 ctx.beginPath(); | |
3942 var radius = Math.round(metrics.x_num_height / 2); | |
3943 ctx.arc(Math.round(metrics.stack_width / 2), radius, radius, 0, 2 * Math.PI, false); | |
3944 ctx.fill(); | |
3945 } | |
3946 ctx.restore(); | |
3947 } | |
3948 | |
3949 function draw_stack(ctx, metrics, symbols, raster) { | |
3950 "use strict"; | |
3951 var preferred_pad, sym_min, i, sym, sym_height, pad; | |
3952 preferred_pad = 0; | |
3953 sym_min = 5; | |
3954 | |
3955 ctx.save();//1 | |
3956 ctx.translate(0, metrics.stack_height); | |
3957 for (i = 0; i < symbols.length; i++) { | |
3958 sym = symbols[i]; | |
3959 sym_height = metrics.stack_height * sym.get_scale(); | |
3960 | |
3961 pad = preferred_pad; | |
3962 if (sym_height - pad < sym_min) { | |
3963 pad = Math.min(pad, Math.max(0, sym_height - sym_min)); | |
3964 } | |
3965 sym_height -= pad; | |
3966 | |
3967 //translate to the correct position | |
3968 ctx.translate(0, -(pad/2 + sym_height)); | |
3969 | |
3970 //draw | |
3971 raster.draw_stack_sym(ctx, sym.get_symbol(), 0, 0, metrics.stack_width, sym_height); | |
3972 //translate past the padding | |
3973 ctx.translate(0, -(pad/2)); | |
3974 } | |
3975 ctx.restore();//1 | |
3976 } | |
3977 | |
3978 function draw_dashed_line(ctx, pattern, start, x1, y1, x2, y2) { | |
3979 "use strict"; | |
3980 var x, y, len, i, dx, dy, tlen, theta, mulx, muly, lx, ly; | |
3981 dx = x2 - x1; | |
3982 dy = y2 - y1; | |
3983 tlen = Math.pow(dx*dx + dy*dy, 0.5); | |
3984 theta = Math.atan2(dy,dx); | |
3985 mulx = Math.cos(theta); | |
3986 muly = Math.sin(theta); | |
3987 lx = []; | |
3988 ly = []; | |
3989 for (i = 0; i < pattern; ++i) { | |
3990 lx.push(pattern[i] * mulx); | |
3991 ly.push(pattern[i] * muly); | |
3992 } | |
3993 i = start; | |
3994 x = x1; | |
3995 y = y1; | |
3996 len = 0; | |
3997 ctx.beginPath(); | |
3998 while (len + pattern[i] < tlen) { | |
3999 ctx.moveTo(x, y); | |
4000 x += lx[i]; | |
4001 y += ly[i]; | |
4002 ctx.lineTo(x, y); | |
4003 len += pattern[i]; | |
4004 i = (i + 1) % pattern.length; | |
4005 x += lx[i]; | |
4006 y += ly[i]; | |
4007 len += pattern[i]; | |
4008 i = (i + 1) % pattern.length; | |
4009 } | |
4010 if (len < tlen) { | |
4011 ctx.moveTo(x, y); | |
4012 x += mulx * (tlen - len); | |
4013 y += muly * (tlen - len); | |
4014 ctx.lineTo(x, y); | |
4015 } | |
4016 ctx.stroke(); | |
4017 } | |
4018 | |
4019 function draw_trim_background(ctx, metrics, left_start, left_end, left_divider, right_start, right_end, right_divider) { | |
4020 "use strict"; | |
4021 var left_size = left_end - left_start; | |
4022 var right_size = right_end - right_start; | |
4023 var line_x; | |
4024 | |
4025 ctx.save();//s8 | |
4026 ctx.fillStyle = "rgb(240, 240, 240)"; | |
4027 if (left_size > 0) { | |
4028 ctx.fillRect(left_start * metrics.stack_width, 0, left_size * metrics.stack_width, metrics.stack_height); | |
4029 } | |
4030 if (right_size > 0) { | |
4031 ctx.fillRect(right_start * metrics.stack_width, 0, right_size * metrics.stack_width, metrics.stack_height); | |
4032 } | |
4033 ctx.fillStyle = "rgb(51, 51, 51)"; | |
4034 if (left_size > 0 && left_divider) { | |
4035 line_x = (left_end * metrics.stack_width) - 0.5; | |
4036 draw_dashed_line(ctx, [3], 0, line_x, 0, line_x, metrics.stack_height); | |
4037 } | |
4038 if (right_size > 0 && right_divider) { | |
4039 line_x = (right_start * metrics.stack_width) + 0.5; | |
4040 draw_dashed_line(ctx, [3], 0, line_x, 0, line_x, metrics.stack_height); | |
4041 } | |
4042 ctx.restore();//s8 | |
4043 } | |
4044 | |
4045 function size_logo_on_canvas(logo, canvas, show_names, scale) { | |
4046 "use strict"; | |
4047 var draw_name, draw_finetext, metrics; | |
4048 draw_name = (typeof show_names === "boolean" ? show_names : (logo.get_rows() > 1)); | |
4049 draw_finetext = (logo.fine_text.length > 0); | |
4050 if (canvas.width !== 0 && canvas.height !== 0) { | |
4051 return; | |
4052 } | |
4053 metrics = new LogoMetrics(canvas.getContext('2d'), | |
4054 logo.get_xlate_columns(), logo.get_rows(), draw_name, draw_finetext, logo.x_axis, logo.y_axis); | |
4055 if (typeof scale == "number") { | |
4056 //resize the canvas to fit the scaled logo | |
4057 canvas.width = metrics.summed_width * scale; | |
4058 canvas.height = metrics.summed_height * scale; | |
4059 } else { | |
4060 if (canvas.width === 0 && canvas.height === 0) { | |
4061 canvas.width = metrics.summed_width; | |
4062 canvas.height = metrics.summed_height; | |
4063 } else if (canvas.width === 0) { | |
4064 canvas.width = metrics.summed_width * (canvas.height / metrics.summed_height); | |
4065 } else if (canvas.height === 0) { | |
4066 canvas.height = metrics.summed_height * (canvas.width / metrics.summed_width); | |
4067 } | |
4068 } | |
4069 } | |
4070 | |
4071 function draw_logo_on_canvas(logo, canvas, show_names, scale) { | |
4072 "use strict"; | |
4073 var i, draw_name, draw_finetext, ctx, metrics, raster, pspm_i, pspm, | |
4074 offset, col_index, motif_position, ssc; | |
4075 ssc = false; | |
4076 draw_name = (typeof show_names === "boolean" ? show_names : (logo.get_rows() > 1)); | |
4077 draw_finetext = (logo.fine_text.length > 0); | |
4078 ctx = canvas.getContext('2d'); | |
4079 //assume that the user wants the canvas scaled equally so calculate what the best width for this image should be | |
4080 metrics = new LogoMetrics(ctx, logo.get_xlate_columns(), logo.get_rows(), draw_name, draw_finetext, logo.x_axis, logo.y_axis); | |
4081 if (typeof scale == "number") { | |
4082 //resize the canvas to fit the scaled logo | |
4083 canvas.width = metrics.summed_width * scale; | |
4084 canvas.height = metrics.summed_height * scale; | |
4085 } else { | |
4086 if (canvas.width === 0 && canvas.height === 0) { | |
4087 scale = 1; | |
4088 canvas.width = metrics.summed_width; | |
4089 canvas.height = metrics.summed_height; | |
4090 } else if (canvas.width === 0) { | |
4091 scale = canvas.height / metrics.summed_height; | |
4092 canvas.width = metrics.summed_width * scale; | |
4093 } else if (canvas.height === 0) { | |
4094 scale = canvas.width / metrics.summed_width; | |
4095 canvas.height = metrics.summed_height * scale; | |
4096 } else { | |
4097 scale = Math.min(canvas.width / metrics.summed_width, canvas.height / metrics.summed_height); | |
4098 } | |
4099 } | |
4100 // cache the raster based on the assumption that we will be drawing a lot | |
4101 // of logos the same size and alphabet | |
4102 if (typeof draw_logo_on_canvas.raster_cache === "undefined") { | |
4103 draw_logo_on_canvas.raster_cache = []; | |
4104 } | |
4105 for (i = 0; i < draw_logo_on_canvas.raster_cache.length; i++) { | |
4106 raster = draw_logo_on_canvas.raster_cache[i]; | |
4107 if (raster.get_alphabet().equals(logo.alphabet) && | |
4108 Math.abs(raster.get_scale() - scale) < 0.1) break; | |
4109 raster = null; | |
4110 } | |
4111 if (raster == null) { | |
4112 raster = new RasterizedAlphabet(logo.alphabet, scale, metrics.stack_font, metrics.stack_width); | |
4113 draw_logo_on_canvas.raster_cache.push(raster); | |
4114 } | |
4115 ctx = canvas.getContext('2d'); | |
4116 ctx.save();//s1 | |
4117 ctx.scale(scale, scale); | |
4118 ctx.save();//s2 | |
4119 ctx.save();//s7 | |
4120 //create margin | |
4121 ctx.translate(Math.round(metrics.pad_left), Math.round(metrics.pad_top)); | |
4122 for (pspm_i = 0; pspm_i < logo.get_rows(); ++pspm_i) { | |
4123 pspm = logo.get_pspm(pspm_i); | |
4124 offset = logo.get_offset(pspm_i); | |
4125 //optionally draw name if this isn't the last row or is the only row | |
4126 if (draw_name && (logo.get_rows() == 1 || pspm_i != (logo.get_rows()-1))) { | |
4127 ctx.save();//s4 | |
4128 ctx.translate(Math.round(metrics.summed_width/2), Math.round(metrics.name_height)); | |
4129 ctx.font = metrics.name_font; | |
4130 ctx.textAlign = "center"; | |
4131 ctx.fillText(pspm.name, 0, 0); | |
4132 ctx.restore();//s4 | |
4133 ctx.translate(0, Math.round(metrics.name_height + | |
4134 Math.min(0, metrics.name_spacer - metrics.y_num_height/2))); | |
4135 } | |
4136 //draw scale | |
4137 if (logo.y_axis) draw_scale(ctx, metrics, logo.alphabet.get_ic(), raster); | |
4138 ctx.save();//s5 | |
4139 //translate across past the scale | |
4140 if (logo.y_axis) { | |
4141 ctx.translate(Math.round(metrics.y_label_height + metrics.y_label_spacer + | |
4142 metrics.y_num_width + metrics.y_tic_width), Math.round(metrics.y_num_height / 2)); | |
4143 } | |
4144 //draw the trimming background | |
4145 if (pspm.get_left_trim() > 0 || pspm.get_right_trim() > 0) { | |
4146 var left_start = offset * logo.get_xlate_nsyms(); | |
4147 var left_end = (offset + pspm.get_left_trim()) * logo.get_xlate_nsyms(); | |
4148 var left_divider = true; | |
4149 if (left_end < logo.get_xlate_start() || left_start > logo.get_xlate_end()) { | |
4150 // no overlap | |
4151 left_start = 0; | |
4152 left_end = 0; | |
4153 left_divider = false; | |
4154 } else { | |
4155 if (left_start < logo.get_xlate_start()) { | |
4156 left_start = logo.get_xlate_start(); | |
4157 } | |
4158 if (left_end > logo.get_xlate_end()) { | |
4159 left_end = logo.get_xlate_end(); | |
4160 left_divider = false; | |
4161 } | |
4162 left_start -= logo.get_xlate_start(); | |
4163 left_end -= logo.get_xlate_start(); | |
4164 if (left_end < left_start) { | |
4165 left_start = 0; | |
4166 left_end = 0; | |
4167 left_divider = false; | |
4168 } | |
4169 } | |
4170 var right_end = (offset + pspm.get_motif_length()) * logo.get_xlate_nsyms(); | |
4171 //var right_start = right_end - (pspm.get_left_trim() * logo.get_xlate_nsyms()); | |
4172 var right_start = right_end - (pspm.get_right_trim() * logo.get_xlate_nsyms()); | |
4173 var right_divider = true; | |
4174 if (right_end < logo.get_xlate_start() || right_start > logo.get_xlate_end()) { | |
4175 // no overlap | |
4176 right_start = 0; | |
4177 right_end = 0; | |
4178 right_divider = false; | |
4179 } else { | |
4180 if (right_start < logo.get_xlate_start()) { | |
4181 right_start = logo.get_xlate_start(); | |
4182 right_divider = false; | |
4183 } | |
4184 if (right_end > logo.get_xlate_end()) { | |
4185 right_end = logo.get_xlate_end(); | |
4186 } | |
4187 right_start -= logo.get_xlate_start(); | |
4188 right_end -= logo.get_xlate_start(); | |
4189 if (right_end < right_start) { | |
4190 right_start = 0; | |
4191 right_end = 0; | |
4192 right_divider = false; | |
4193 } | |
4194 } | |
4195 draw_trim_background(ctx, metrics, left_start, left_end, left_divider, right_start, right_end, right_divider); | |
4196 } | |
4197 //draw letters | |
4198 var xlate_col; | |
4199 for (xlate_col = logo.get_xlate_start(); xlate_col < logo.get_xlate_end(); xlate_col++) { | |
4200 ctx.translate(metrics.stack_pad_left,0); | |
4201 col_index = Math.floor(xlate_col / logo.get_xlate_nsyms()); | |
4202 if (xlate_col % logo.get_xlate_nsyms() == 0) { | |
4203 if (col_index >= offset && col_index < (offset + pspm.get_motif_length())) { | |
4204 motif_position = col_index - offset; | |
4205 draw_stack_num(ctx, metrics, motif_position, raster); | |
4206 draw_stack(ctx, metrics, pspm.get_stack(motif_position, logo.alphabet, ssc), raster); | |
4207 } | |
4208 } else { | |
4209 if (col_index >= offset && col_index < (offset + pspm.get_motif_length())) { | |
4210 ctx.save();// s5.1 | |
4211 ctx.translate(0, Math.round(metrics.stack_height)); | |
4212 // TODO draw a dot or dash or something to indicate continuity of the motif | |
4213 ctx.restore(); //s5.1 | |
4214 } | |
4215 } | |
4216 ctx.translate(Math.round(metrics.stack_width), 0); | |
4217 } | |
4218 ctx.restore();//s5 | |
4219 ////optionally draw name if this is the last row but isn't the only row | |
4220 if (draw_name && (logo.get_rows() != 1 && pspm_i == (logo.get_rows()-1))) { | |
4221 //translate vertically past the stack and axis's | |
4222 ctx.translate(0, metrics.y_num_height/2 + metrics.stack_height + | |
4223 Math.max(metrics.y_num_height/2, metrics.x_num_above + metrics.x_num_width + metrics.name_spacer)); | |
4224 | |
4225 ctx.save();//s6 | |
4226 ctx.translate(metrics.summed_width/2, metrics.name_height); | |
4227 ctx.font = metrics.name_font; | |
4228 ctx.textAlign = "center"; | |
4229 ctx.fillText(pspm.name, 0, 0); | |
4230 ctx.restore();//s6 | |
4231 ctx.translate(0, metrics.name_height); | |
4232 } else { | |
4233 //translate vertically past the stack and axis's | |
4234 ctx.translate(0, metrics.y_num_height/2 + metrics.stack_height + | |
4235 Math.max(metrics.y_num_height/2, metrics.x_num_above + metrics.x_num_width)); | |
4236 } | |
4237 //if not the last row then add middle padding | |
4238 if (pspm_i != (logo.get_rows() -1)) { | |
4239 ctx.translate(0, metrics.pad_middle); | |
4240 } | |
4241 } | |
4242 ctx.restore();//s7 | |
4243 if (logo.fine_text.length > 0) { | |
4244 ctx.translate(metrics.summed_width - metrics.pad_right, metrics.summed_height - metrics.pad_bottom); | |
4245 ctx.font = metrics.fine_txt_font; | |
4246 ctx.textAlign = "right"; | |
4247 ctx.fillText(logo.fine_text, 0,0); | |
4248 } | |
4249 ctx.restore();//s2 | |
4250 ctx.restore();//s1 | |
4251 } | |
4252 | |
4253 function create_canvas(c_width, c_height, c_id, c_title, c_display) { | |
4254 "use strict"; | |
4255 var canvas = document.createElement("canvas"); | |
4256 //check for canvas support before attempting anything | |
4257 if (!canvas.getContext) { | |
4258 return null; | |
4259 } | |
4260 var ctx = canvas.getContext('2d'); | |
4261 //check for html5 text drawing support | |
4262 if (!supports_text(ctx)) { | |
4263 return null; | |
4264 } | |
4265 //size the canvas | |
4266 canvas.width = c_width; | |
4267 canvas.height = c_height; | |
4268 canvas.id = c_id; | |
4269 canvas.title = c_title; | |
4270 canvas.style.display = c_display; | |
4271 return canvas; | |
4272 } | |
4273 | |
4274 function logo_1(alphabet, fine_text, pspm) { | |
4275 "use strict"; | |
4276 var logo = new Logo(alphabet, fine_text); | |
4277 logo.add_pspm(pspm); | |
4278 return logo; | |
4279 } | |
4280 | |
4281 function logo_2(alphabet, fine_text, target, query, query_offset) { | |
4282 "use strict"; | |
4283 var logo = new Logo(alphabet, fine_text); | |
4284 if (query_offset < 0) { | |
4285 logo.add_pspm(target, -query_offset); | |
4286 logo.add_pspm(query); | |
4287 } else { | |
4288 logo.add_pspm(target); | |
4289 logo.add_pspm(query, query_offset); | |
4290 } | |
4291 return logo; | |
4292 } | |
4293 | |
4294 /* | |
4295 * Specifies an alternate source for an image. | |
4296 * If the image with the image_id specified has | |
4297 * not loaded then a generated logo will be used | |
4298 * to replace it. | |
4299 * | |
4300 * Note that the image must either have dimensions | |
4301 * or a scale must be set. | |
4302 */ | |
4303 function alternate_logo(logo, image_id, scale) { | |
4304 "use strict"; | |
4305 var image = document.getElementById(image_id); | |
4306 if (!image) { | |
4307 alert("Can't find specified image id (" + image_id + ")"); | |
4308 return; | |
4309 } | |
4310 //if the image has loaded then there is no reason to use the canvas | |
4311 if (image_ok(image)) { | |
4312 return; | |
4313 } | |
4314 //the image has failed to load so replace it with a canvas if we can. | |
4315 var canvas = create_canvas(image.width, image.height, image_id, image.title, image.style.display); | |
4316 if (canvas === null) { | |
4317 return; | |
4318 } | |
4319 //draw the logo on the canvas | |
4320 draw_logo_on_canvas(logo, canvas, null, scale); | |
4321 //replace the image with the canvas | |
4322 image.parentNode.replaceChild(canvas, image); | |
4323 } | |
4324 | |
4325 /* | |
4326 * Specifes that the element with the specified id | |
4327 * should be replaced with a generated logo. | |
4328 */ | |
4329 function replace_logo(logo, replace_id, scale, title_txt, display_style) { | |
4330 "use strict"; | |
4331 var element = document.getElementById(replace_id); | |
4332 if (!replace_id) { | |
4333 alert("Can't find specified id (" + replace_id + ")"); | |
4334 return; | |
4335 } | |
4336 //found the element! | |
4337 var canvas = create_canvas(50, 120, replace_id, title_txt, display_style); | |
4338 if (canvas === null) { | |
4339 return; | |
4340 } | |
4341 //draw the logo on the canvas | |
4342 draw_logo_on_canvas(logo, canvas, null, scale); | |
4343 //replace the element with the canvas | |
4344 element.parentNode.replaceChild(canvas, element); | |
4345 } | |
4346 | |
4347 /* | |
4348 * Fast string trimming implementation found at | |
4349 * http://blog.stevenlevithan.com/archives/faster-trim-javascript | |
4350 * | |
4351 * Note that regex is good at removing leading space but | |
4352 * bad at removing trailing space as it has to first go through | |
4353 * the whole string. | |
4354 */ | |
4355 function trim (str) { | |
4356 "use strict"; | |
4357 var ws, i; | |
4358 str = str.replace(/^\s\s*/, ''); | |
4359 ws = /\s/; i = str.length; | |
4360 while (ws.test(str.charAt(--i))); | |
4361 return str.slice(0, i + 1); | |
4362 } | |
4363 </script> | |
4364 <script> | |
4365 | |
4366 // PRIVATE GLOBAL (uhoh) | |
4367 var _block_colour_lookup = {}; | |
4368 | |
4369 function block_colour(index) { | |
4370 function hsl2rgb(hue, saturation, lightness) { | |
4371 "use strict"; | |
4372 function _hue(p, q, t) { | |
4373 "use strict"; | |
4374 if (t < 0) t += 1; | |
4375 else if (t > 1) t -= 1; | |
4376 if (t < (1.0 / 6.0)) { | |
4377 return p + ((q - p) * 6.0 * t); | |
4378 } else if (t < 0.5) { | |
4379 return q; | |
4380 } else if (t < (2.0 / 3.0)) { | |
4381 return p + ((q - p) * ((2.0 / 3.0) - t) * 6.0); | |
4382 } else { | |
4383 return p; | |
4384 } | |
4385 } | |
4386 function _pad_hex(value) { | |
4387 var hex = Math.round(value * 255).toString(16); | |
4388 if (hex.length < 2) hex = "0" + hex; | |
4389 return hex; | |
4390 } | |
4391 var r, g, b, p, q; | |
4392 if (saturation == 0) { | |
4393 // achromatic (grayscale) | |
4394 r = lightness; | |
4395 g = lightness; | |
4396 b = lightness; | |
4397 } else { | |
4398 if (lightness < 0.5) { | |
4399 q = lightness * (1 + saturation); | |
4400 } else { | |
4401 q = lightness + saturation - (lightness * saturation); | |
4402 } | |
4403 p = (2 * lightness) - q; | |
4404 r = _hue(p, q, hue + (1.0 / 3.0)); | |
4405 g = _hue(p, q, hue); | |
4406 b = _hue(p, q, hue - (1.0 / 3.0)); | |
4407 } | |
4408 return "#" + _pad_hex(r) + _pad_hex(g) + _pad_hex(b); | |
4409 } | |
4410 if (typeof index !== "number" || index % 1 !== 0 || index < 0) return "#000000"; | |
4411 // check for override | |
4412 if (_block_colour_lookup[index] == null) { | |
4413 var start = 0; //red | |
4414 var sat = 100; | |
4415 var light = 50; | |
4416 var divisions = 1 << Math.ceil(Math.log(index + 1) / Math.LN2); | |
4417 hue = start + (360 / divisions) * ((index - (divisions >> 1)) * 2 + 1); | |
4418 // colour input fields only support values in the form #RRGGBB | |
4419 _block_colour_lookup[index] = hsl2rgb(hue / 360, sat / 100, light / 100); | |
4420 } | |
4421 return _block_colour_lookup[index]; | |
4422 } | |
4423 | |
4424 function set_block_colour(index, new_colour) { | |
4425 _block_colour_lookup[index] = new_colour; | |
4426 var blocks = document.querySelectorAll("div.block_motif[data-colour-index=\"" + index + "\"]"); | |
4427 var i; | |
4428 for (i = 0; i < blocks.length; i++) { | |
4429 blocks[i].style.backgroundColor = new_colour; | |
4430 } | |
4431 var swatches = document.querySelectorAll("div.legend_swatch[data-colour-index=\"" + index + "\"]"); | |
4432 var picker; | |
4433 for (i = 0; i < swatches.length; i++) { | |
4434 swatches[i].style.backgroundColor = new_colour; | |
4435 picker = swatches[i].querySelector("input[type=\"color\"]"); | |
4436 if (picker != null) picker.value = new_colour; | |
4437 } | |
4438 } | |
4439 | |
4440 function make_block_legend_entry(motif_name, motif_colour_index) { | |
4441 if (typeof make_block_legend_entry.has_colour_picker !== "boolean") { | |
4442 // test if colour picker is supported, based off Modernizer | |
4443 // see http://stackoverflow.com/a/7787648/66387 | |
4444 make_block_legend_entry.has_colour_picker = (function() { | |
4445 var doc_ele = document.documentElement; | |
4446 // We first check to see if the type we give it sticks.. | |
4447 var input_ele = document.createElement('input'); | |
4448 input_ele.setAttribute('type', 'color'); | |
4449 var value_ok = input_ele.type !== 'text'; | |
4450 if (value_ok) { | |
4451 // If the type does, we feed it a textual value, which shouldn't be valid. | |
4452 // If the value doesn't stick, we know there's input sanitization which infers a custom UI | |
4453 var smile = ':)'; | |
4454 input_ele.value = smile; | |
4455 input_ele.style.cssText = 'position:absolute;visibility:hidden;'; | |
4456 // chuck into DOM and force reflow for Opera bug in 11.00 | |
4457 // github.com/Modernizr/Modernizr/issues#issue/159 | |
4458 doc_ele.appendChild(input_ele); | |
4459 doc_ele.offsetWidth; | |
4460 value_ok = input_ele.value != smile; | |
4461 doc_ele.removeChild(input_ele); | |
4462 } | |
4463 return value_ok; | |
4464 })(); | |
4465 } | |
4466 var entry = document.createElement("div"); | |
4467 entry.className = "legend_entry"; | |
4468 var swatch; | |
4469 swatch = document.createElement("div"); | |
4470 swatch.className = "legend_swatch"; | |
4471 swatch.setAttribute("data-colour-index", motif_colour_index); | |
4472 swatch.style.backgroundColor = block_colour(motif_colour_index); | |
4473 if (make_block_legend_entry.has_colour_picker) { | |
4474 var picker = document.createElement("input"); | |
4475 picker.type = "color"; | |
4476 picker.value = block_colour(motif_colour_index); | |
4477 picker.addEventListener("change", function(e) { | |
4478 set_block_colour(motif_colour_index, picker.value); | |
4479 }, false); | |
4480 swatch.addEventListener("click", function(e) { | |
4481 picker.click(); | |
4482 }, false); | |
4483 swatch.appendChild(picker); | |
4484 } | |
4485 entry.appendChild(swatch); | |
4486 var name = document.createElement("div"); | |
4487 name.className = "legend_text"; | |
4488 name.appendChild(document.createTextNode(motif_name)); | |
4489 entry.appendChild(name); | |
4490 return entry; | |
4491 } | |
4492 | |
4493 function make_block_ruler(max_len) { | |
4494 var container = document.createElement("div"); | |
4495 container.className = "block_container"; | |
4496 var step; | |
4497 if (max_len < 50) { | |
4498 step = 1; | |
4499 } else if (max_len < 100) { | |
4500 step = 2; | |
4501 } else if (max_len < 200) { | |
4502 step = 4; | |
4503 } else if (max_len < 500) { | |
4504 step = 10; | |
4505 } else if (max_len < 1000) { | |
4506 step = 20; | |
4507 } else if (max_len < 2000) { | |
4508 step = 40; | |
4509 } else if (max_len < 5000) { | |
4510 step = 100; | |
4511 } else if (max_len < 10000) { | |
4512 step = 200; | |
4513 } else if (max_len < 20000) { | |
4514 step = 400; | |
4515 } else { | |
4516 step = Math.floor(max_len / 20000) * 400; | |
4517 } | |
4518 var peroid; | |
4519 if (max_len < 10) { | |
4520 peroid = 1; | |
4521 } else if (max_len < 20) { | |
4522 peroid = 2; | |
4523 } else { | |
4524 peroid = 5; | |
4525 } | |
4526 var i, cycle, offset, tic, label; | |
4527 for (i = 0, cycle = 0; i < max_len; i += step, cycle = (cycle + 1) % peroid) { | |
4528 offset = "" + ((i / max_len) * 100) + "%"; | |
4529 tic = document.createElement("div"); | |
4530 tic.style.left = offset; | |
4531 tic.className = (cycle == 0 ? "tic_major" : "tic_minor"); | |
4532 container.appendChild(tic); | |
4533 if (cycle == 0) { | |
4534 label = document.createElement("div"); | |
4535 label.className = "tic_label"; | |
4536 label.style.left = offset; | |
4537 label.appendChild(document.createTextNode(i)); | |
4538 container.appendChild(label); | |
4539 } | |
4540 } | |
4541 return container; | |
4542 } | |
4543 | |
4544 function _calculate_block_needle_drag_pos(e, data) { | |
4545 var mouse; | |
4546 e = e || window.event; | |
4547 if (e.pageX || ev.pageY) { | |
4548 mouse = {"x": e.pageX, "y": e.pageY}; | |
4549 } else { | |
4550 mouse = { | |
4551 x:e.clientX + document.body.scrollLeft - document.body.clientLeft, | |
4552 y:e.clientY + document.body.scrollTop - document.body.clientTop | |
4553 }; | |
4554 } | |
4555 var cont = data.container; | |
4556 var dragable_length = cont.clientWidth - | |
4557 (cont.style.paddingLeft ? cont.style.paddingLeft : 0) - | |
4558 (cont.style.paddingRight ? cont.style.paddingRight : 0); | |
4559 //I believe that the offset parent is the body | |
4560 //otherwise I would need to make this recursive | |
4561 //maybe clientLeft would work, but the explanation of | |
4562 //it is hard to understand and it apparently doesn't work | |
4563 //in firefox 2. | |
4564 var diff = mouse.x - cont.offsetLeft; | |
4565 if (diff < 0) diff = 0; | |
4566 if (diff > dragable_length) diff = dragable_length; | |
4567 var pos = Math.round(diff / dragable_length * data.max); | |
4568 if (pos > data.len) pos = data.len; | |
4569 return pos; | |
4570 } | |
4571 | |
4572 function _update_block_needle_drag(e, data, done) { | |
4573 "use strict"; | |
4574 var pos = _calculate_block_needle_drag_pos(e, data); | |
4575 // read the needle positions | |
4576 var left = parseInt(data.llabel.textContent, 10) - data.off - 1; | |
4577 var right = parseInt(data.rlabel.textContent, 10) - data.off; | |
4578 // validate needle positions | |
4579 if (left >= data.len) left = data.len - 1; | |
4580 if (left < 0) left = 0; | |
4581 if (right > data.len) right = data.len; | |
4582 if (right <= left) right = left + 1; | |
4583 // calculate the new needle positions | |
4584 if (data.moveboth) { | |
4585 var size = right - left; | |
4586 if (data.isleft) { | |
4587 if ((pos + size) > data.len) pos = data.len - size; | |
4588 left = pos; | |
4589 right = pos + size; | |
4590 } else { | |
4591 if ((pos - size) < 0) pos = size; | |
4592 left = pos - size; | |
4593 right = pos; | |
4594 } | |
4595 } else { | |
4596 if (data.isleft) { | |
4597 if (pos >= right) pos = right - 1; | |
4598 left = pos; | |
4599 } else { | |
4600 if (pos <= left) pos = left + 1; | |
4601 right = pos; | |
4602 } | |
4603 } | |
4604 // update the needle positions | |
4605 data.lneedle.style.left = "" + (left / data.max * 100) + "%"; | |
4606 data.llabel.textContent = "" + (left + data.off + 1); | |
4607 data.rneedle.style.left = "" + (right / data.max * 100) + "%"; | |
4608 data.rlabel.textContent = "" + (right + data.off); | |
4609 data.handler(left, right, done); | |
4610 } | |
4611 | |
4612 function _make_block_needle_drag_start_handler(isleft, data) { | |
4613 return function (e) { | |
4614 data.isleft = isleft; | |
4615 data.moveboth = !(e.shiftKey); | |
4616 document.addEventListener("mousemove", data.drag_during, false); | |
4617 document.addEventListener("mouseup", data.drag_end, false); | |
4618 }; | |
4619 } | |
4620 | |
4621 function _make_block_needle_drag_end_handler(data) { | |
4622 return function (e) { | |
4623 document.removeEventListener("mousemove", data.drag_during, false); | |
4624 document.removeEventListener("mouseup", data.drag_end, false); | |
4625 _update_block_needle_drag(e, data, true); | |
4626 }; | |
4627 } | |
4628 | |
4629 function _make_block_needle_drag_during_handler(data) { | |
4630 return function (e) { | |
4631 _update_block_needle_drag(e, data, false); | |
4632 }; | |
4633 } | |
4634 | |
4635 // private function used by make_block_container | |
4636 function _make_block_needle(isleft, value, data) { | |
4637 var vbar = document.createElement('div'); | |
4638 vbar.className = "block_needle " + (isleft ? "left" : "right"); | |
4639 vbar.style.left = "" + (value / data.max * 100)+ "%"; | |
4640 var label = document.createElement('div'); | |
4641 label.className = "block_handle " + (isleft ? "left" : "right"); | |
4642 // The needles sit between the sequence positions, so the left one sits at the | |
4643 // start and the right at the end. This is why 1 is added to the displayed | |
4644 // value for a left handle as the user doesn't need to know about this detail | |
4645 label.textContent = "" + (isleft ? value + data.off + 1 : value + data.off); | |
4646 label.unselectable = "on"; // so IE and Opera don't select the text, others are done in css | |
4647 label.title = "Drag to move the displayed range. Hold shift and drag to change " + (isleft ? "lower" : "upper") + " bound of the range."; | |
4648 vbar.appendChild(label); | |
4649 if (isleft) { | |
4650 data.lneedle = vbar; | |
4651 data.llabel = label; | |
4652 } else { | |
4653 data.rneedle = vbar; | |
4654 data.rlabel = label; | |
4655 } | |
4656 label.addEventListener("mousedown", _make_block_needle_drag_start_handler(isleft, data), false); | |
4657 return vbar; | |
4658 } | |
4659 | |
4660 function make_block_container(is_stranded, has_both_strands, max_len, show_len, offset, range_handler) { | |
4661 offset = (offset != null ? offset : 0); | |
4662 // make the container for the block diagram | |
4663 var container = document.createElement("div"); | |
4664 container.className = "block_container"; | |
4665 container.setAttribute("data-max", max_len); | |
4666 container.setAttribute("data-off", offset); | |
4667 if (is_stranded) { | |
4668 var plus = document.createElement("div"); | |
4669 plus.appendChild(document.createTextNode("+")); | |
4670 plus.className = "block_plus_sym"; | |
4671 container.appendChild(plus); | |
4672 if (has_both_strands) { | |
4673 var minus = document.createElement("div"); | |
4674 minus.appendChild(document.createTextNode("-")); | |
4675 minus.className = "block_minus_sym"; | |
4676 container.appendChild(minus); | |
4677 } | |
4678 } | |
4679 var rule = document.createElement("div"); | |
4680 rule.className = "block_rule"; | |
4681 rule.style.width = ((show_len / max_len) * 100) + "%"; | |
4682 container.appendChild(rule); | |
4683 if (range_handler != null) { | |
4684 var range_data = { | |
4685 "max": max_len, | |
4686 "len": show_len, | |
4687 "off": offset, | |
4688 "handler": range_handler, | |
4689 "container": container, | |
4690 "lneedle": null, "llabel": null, | |
4691 "rneedle": null, "rlabel": null, | |
4692 "isleft": false, "moveboth" : false | |
4693 }; | |
4694 range_data.drag_during = _make_block_needle_drag_during_handler(range_data); | |
4695 range_data.drag_end = _make_block_needle_drag_end_handler(range_data); | |
4696 container.appendChild(_make_block_needle(false, 1, range_data)); // add right first so z-index works | |
4697 container.appendChild(_make_block_needle(true, 0, range_data)); | |
4698 } | |
4699 return container; | |
4700 } | |
4701 | |
4702 function make_block_label(container, max_len, pos, length, message) { | |
4703 "use strict"; | |
4704 var label = document.createElement("div"); | |
4705 label.className = "block_label"; | |
4706 label.style.left = (((pos + (length / 2)) / max_len) * 100) + "%"; | |
4707 label.appendChild(document.createTextNode(message)); | |
4708 container.appendChild(label); | |
4709 } | |
4710 | |
4711 function make_block(container, max_len, | |
4712 site_pos, site_len, site_pvalue, site_rc, site_colour_index, site_secondary) { | |
4713 "use strict"; | |
4714 var block_height, block, block_region1, block_region2; | |
4715 var max_block_height = 12; | |
4716 var max_pvalue = 1e-10; | |
4717 // calculate the height of the block | |
4718 block_height = (site_pvalue < max_pvalue ? max_block_height : | |
4719 (Math.log(site_pvalue) / Math.log(max_pvalue)) * max_block_height); | |
4720 if (block_height < 1) block_height = 1; | |
4721 // create a block to represent the motif | |
4722 block = document.createElement("div"); | |
4723 block.className = "block_motif" + (site_secondary ? " scanned_site" : "") + (site_rc ? " bottom" : " top"); | |
4724 block.style.left = ((site_pos / max_len) * 100) + "%"; | |
4725 block.style.top = (!site_rc ? max_block_height - block_height : | |
4726 max_block_height + 1) + "px"; | |
4727 block.style.width = ((site_len / max_len) * 100) + "%"; | |
4728 block.style.height = block_height + "px"; | |
4729 block.style.backgroundColor = block_colour(site_colour_index); | |
4730 block.setAttribute("data-colour-index", site_colour_index); | |
4731 // add to container | |
4732 container.appendChild(block); | |
4733 var activator = function (e) { | |
4734 toggle_class(block, "active", true); | |
4735 var new_e = new e.constructor(e.type, e); | |
4736 block.dispatchEvent(new_e); | |
4737 }; | |
4738 var deactivator = function (e) { | |
4739 toggle_class(block, "active", false); | |
4740 var new_e = new e.constructor(e.type, e); | |
4741 block.dispatchEvent(new_e); | |
4742 } | |
4743 // create a larger region to detect mouseover for the block | |
4744 block_region1 = document.createElement("div"); | |
4745 block_region1.className = "block_region top" + | |
4746 (site_secondary ? " scanned_site" : "") + (site_rc ? "" : " main"); | |
4747 block_region1.style.left = block.style.left; | |
4748 block_region1.style.width = block.style.width; | |
4749 block_region1.addEventListener('mouseover', activator, false); | |
4750 block_region1.addEventListener('mouseout', deactivator, false); | |
4751 container.appendChild(block_region1); | |
4752 block_region2 = document.createElement("div"); | |
4753 block_region2.className = "block_region bottom" + | |
4754 (site_secondary ? " scanned_site" : "") + (site_rc ? " main" : ""); | |
4755 block_region2.style.left = block.style.left; | |
4756 block_region2.style.width = block.style.width; | |
4757 block_region2.addEventListener('mouseover', activator, false); | |
4758 block_region2.addEventListener('mouseout', deactivator, false); | |
4759 container.appendChild(block_region2); | |
4760 return block; | |
4761 } | |
4762 | |
4763 function set_block_needle_positions(containingNode, start, end) { | |
4764 var container, lneedle, llabel, rneedle, rlabel, max, off, left, right; | |
4765 container = (/\bblock_container\b/.test(containingNode.className) ? containingNode : containingNode.querySelector(".block_container")); | |
4766 max = parseInt(container.getAttribute("data-max"), 10); | |
4767 off = parseInt(container.getAttribute("data-off"), 10); | |
4768 left = start - off; | |
4769 right = end - off; | |
4770 lneedle = containingNode.querySelector(".block_needle.left"); | |
4771 llabel = lneedle.querySelector(".block_handle.left"); | |
4772 rneedle = containingNode.querySelector(".block_needle.right"); | |
4773 rlabel = rneedle.querySelector(".block_handle.right"); | |
4774 // update the needle positions | |
4775 lneedle.style.left = "" + (left / max * 100) + "%"; | |
4776 llabel.textContent = "" + (left + off + 1); | |
4777 rneedle.style.left = "" + (right / max * 100) + "%"; | |
4778 rlabel.textContent = "" + (right + off); | |
4779 } | |
4780 | |
4781 function get_block_needle_positions(containingNode) { | |
4782 var container, llabel, rlabel, max, off, left, right; | |
4783 container = (/\bblock_container\b/.test(containingNode.className) ? containingNode : containingNode.querySelector(".block_container")); | |
4784 max = parseInt(container.getAttribute("data-max"), 10); | |
4785 off = parseInt(container.getAttribute("data-off"), 10); | |
4786 llabel = containingNode.querySelector(".block_needle.left > .block_handle.left"); | |
4787 rlabel = containingNode.querySelector(".block_needle.right > .block_handle.right"); | |
4788 left = parseInt(llabel.textContent, 10) - off - 1; | |
4789 right = parseInt(rlabel.textContent, 10) - off; | |
4790 return {"start": left + off, "end": right + off}; | |
4791 } | |
4792 </script> | |
4793 <script> | |
4794 function make_alpha_bg_table(alph, freqs) { | |
4795 function colour_symbol(index) { | |
4796 var span = document.createElement("span"); | |
4797 span.appendChild(document.createTextNode(alph.get_symbol(index))); | |
4798 span.style.color = alph.get_colour(index); | |
4799 span.className = "alpha_symbol"; | |
4800 return span; | |
4801 } | |
4802 var table, thead, tbody, row, th, span, i; | |
4803 // create table | |
4804 table = document.createElement("table"); | |
4805 table.className = "alpha_bg_table"; | |
4806 // create header | |
4807 thead = document.createElement("thead"); | |
4808 table.appendChild(thead); | |
4809 row = thead.insertRow(thead.rows.length); | |
4810 if (alph.has_complement()) { | |
4811 add_text_header_cell(row, "Name", "pop_alph_name"); | |
4812 if (freqs != null) add_text_header_cell(row, "Freq.", "pop_alph_freq"); | |
4813 if (alph.has_bg()) add_text_header_cell(row, "Bg.", "pop_alph_bg"); | |
4814 add_text_header_cell(row, ""); | |
4815 add_text_header_cell(row, ""); | |
4816 add_text_header_cell(row, ""); | |
4817 if (alph.has_bg()) add_text_header_cell(row, "Bg.", "pop_alph_bg"); | |
4818 if (freqs != null) add_text_header_cell(row, "Freq.", "pop_alph_freq"); | |
4819 add_text_header_cell(row, "Name", "pop_alph_name"); | |
4820 } else { | |
4821 add_text_header_cell(row, ""); | |
4822 add_text_header_cell(row, "Name", "pop_alph_name"); | |
4823 if (freqs != null) add_text_header_cell(row, "Freq.", "pop_alph_freq"); | |
4824 if (alph.has_bg()) add_text_header_cell(row, "Bg.", "pop_alph_bg"); | |
4825 } | |
4826 // add alphabet entries | |
4827 tbody = document.createElement("tbody"); | |
4828 table.appendChild(tbody); | |
4829 if (alph.has_complement()) { | |
4830 for (i = 0; i < alph.get_size_core(); i++) { | |
4831 var c = alph.get_complement(i); | |
4832 if (i > c) continue; | |
4833 row = tbody.insertRow(tbody.rows.length); | |
4834 add_text_cell(row, alph.get_name(i)); | |
4835 if (freqs != null) add_text_cell(row, "" + freqs[i].toFixed(3)); | |
4836 if (alph.has_bg()) add_text_cell(row, "" + alph.get_bg_freq(i).toFixed(3)); | |
4837 add_cell(row, colour_symbol(i)); | |
4838 add_text_cell(row, "~"); | |
4839 add_cell(row, colour_symbol(c)); | |
4840 if (alph.has_bg()) add_text_cell(row, "" + alph.get_bg_freq(c).toFixed(3)); | |
4841 if (freqs != null) add_text_cell(row, "" + freqs[c].toFixed(3)); | |
4842 add_text_cell(row, alph.get_name(c)); | |
4843 } | |
4844 } else { | |
4845 for (i = 0; i < alph.get_size_core(); i++) { | |
4846 row = tbody.insertRow(tbody.rows.length); | |
4847 add_cell(row, colour_symbol(i)); | |
4848 add_text_cell(row, alph.get_name(i)); | |
4849 if (freqs != null) add_text_cell(row, "" + freqs[i].toFixed(3)); | |
4850 if (alph.has_bg()) add_text_cell(row, "" + alph.get_bg_freq(i).toFixed(3)); | |
4851 } | |
4852 } | |
4853 return table; | |
4854 } | |
4855 | |
4856 </script> | |
4857 <script> | |
4858 var current_motif = 0; | |
4859 var meme_alphabet = new Alphabet(data.alphabet, data.background.freqs); | |
4860 | |
4861 var DelayLogoTask = function(logo, canvas) { | |
4862 this.logo = logo; | |
4863 this.canvas = canvas; | |
4864 }; | |
4865 | |
4866 DelayLogoTask.prototype.run = function () { | |
4867 draw_logo_on_canvas(this.logo, this.canvas, false); | |
4868 }; | |
4869 | |
4870 function motif_pspm(index) { | |
4871 var motif, pwm, psm, name, ltrim, rtrim, nsites, evalue; | |
4872 // get motif | |
4873 motif = data["motifs"][index]; | |
4874 // get motif paramters | |
4875 pwm = motif["pwm"]; | |
4876 psm = motif["psm"]; | |
4877 name = "" + (index + 1); ltrim = 0; rtrim = 0; | |
4878 nsites = motif["nsites"]; evalue = motif["evalue"]; | |
4879 // make pspm | |
4880 return new Pspm(pwm, name, ltrim, rtrim, nsites, evalue, psm); | |
4881 } | |
4882 | |
4883 function motif_count_matrix(index) { | |
4884 return motif_pspm(index).as_count_matrix(); | |
4885 } | |
4886 | |
4887 function motif_prob_matrix(index) { | |
4888 return motif_pspm(index).as_probability_matrix(); | |
4889 } | |
4890 | |
4891 function motif_minimal_meme(index) { | |
4892 return motif_pspm(index).as_meme({ | |
4893 "with_header": true, | |
4894 "with_pspm": true, | |
4895 "with_pssm": true, | |
4896 "version": data["version"], | |
4897 "alphabet": meme_alphabet, | |
4898 "strands": (meme_alphabet.has_complement() && data.options.revcomp ? 2 : 1) | |
4899 }); | |
4900 } | |
4901 | |
4902 function motif_fasta(index) { | |
4903 "use strict"; | |
4904 var motif, sites, site, seq, sequences, sequence, i, num, counter, out; | |
4905 counter = {}; | |
4906 sequences = data["sequence_db"]["sequences"]; | |
4907 motif = data["motifs"][index]; | |
4908 sites = motif["sites"]; | |
4909 out = ""; | |
4910 for (i = 0; i < sites.length; i++) { | |
4911 site = sites[i]; | |
4912 seq = site["seq"]; | |
4913 sequence = sequences[seq]; | |
4914 counter[seq] = (num = counter[seq]) ? (++num) : (num = 1); // inc counter | |
4915 if (i !== 0) {out += "\n";} | |
4916 out += ">" + sequence["name"] + "_site_" + num + " offset= " + site["pos"] + | |
4917 (site["rc"] ? " RC\n" : "\n"); | |
4918 out += site["match"]; | |
4919 } | |
4920 return out; | |
4921 } | |
4922 | |
4923 function motif_raw(index) { | |
4924 "use strict"; | |
4925 var sites, i, out; | |
4926 sites = data["motifs"][index]["sites"]; | |
4927 out = ""; | |
4928 for (i = 0; i < sites.length; i++) { | |
4929 if (i !== 0) {out += "\n";} | |
4930 out += sites[i]["match"]; | |
4931 } | |
4932 return out; | |
4933 } | |
4934 | |
4935 function clone_template(template) { | |
4936 "use strict"; | |
4937 var node, help_btns, i, button; | |
4938 node = $(template).cloneNode(true); | |
4939 toggle_class(node, "template", false); | |
4940 node.id = ""; | |
4941 help_btns = node.querySelectorAll(".help"); | |
4942 for (i = 0; i < help_btns.length; i++) { | |
4943 button = help_btns[i]; | |
4944 if (button.hasAttribute("data-topic")) { | |
4945 button.tabIndex = "0"; | |
4946 button.addEventListener("click", __toggle_help, false); | |
4947 button.addEventListener("keydown", __toggle_help, false); | |
4948 } | |
4949 } | |
4950 return node; | |
4951 } | |
4952 | |
4953 function set_tvar(template, tvar, value) { | |
4954 var node; | |
4955 node = find_child(template, tvar); | |
4956 if (node === null) { | |
4957 throw new Error("Template does not contain variable " + tvar); | |
4958 } | |
4959 node.innerHTML = ""; | |
4960 if (typeof value !== "object") { | |
4961 node.appendChild(document.createTextNode(value)); | |
4962 } else { | |
4963 node.appendChild(value); | |
4964 } | |
4965 } | |
4966 | |
4967 function make_logo(alphabet, pspm, rc, offset, className) { | |
4968 if (rc) pspm = pspm.copy().reverse_complement(alphabet); | |
4969 var logo = new Logo(alphabet, ""); | |
4970 logo.add_pspm(pspm, offset); | |
4971 var canvas = document.createElement('canvas'); | |
4972 canvas.height = 50; | |
4973 canvas.width = 0; | |
4974 canvas.className = className; | |
4975 size_logo_on_canvas(logo, canvas, false); | |
4976 add_draw_task(canvas, new DelayLogoTask(logo, canvas)); | |
4977 return canvas; | |
4978 } | |
4979 | |
4980 function make_small_logo(alphabet, pspm, options) { | |
4981 if (typeof options === "undefined") options = {}; | |
4982 if (options.rc) pspm = pspm.copy().reverse_complement(alphabet); | |
4983 var logo = new Logo(alphabet, {x_axis: false, y_axis: false}); | |
4984 logo.add_pspm(pspm, (typeof options.offset === "number" ? options.offset : 0)); | |
4985 var canvas = document.createElement('canvas'); | |
4986 if (typeof options.className === "string") canvas.className = options.className; | |
4987 if (typeof options.width === "number" && options.width > 0) { | |
4988 canvas.height = 0; | |
4989 canvas.width = options.width; | |
4990 draw_logo_on_canvas(logo, canvas, false); | |
4991 } else { | |
4992 draw_logo_on_canvas(logo, canvas, false, 1/3); | |
4993 } | |
4994 return canvas; | |
4995 } | |
4996 | |
4997 function make_large_logo(alphabet, pspm, rc, offset, className) { | |
4998 if (rc) pspm = pspm.copy().reverse_complement(alphabet); | |
4999 var logo = new Logo(alphabet, ""); | |
5000 logo.add_pspm(pspm, offset); | |
5001 var canvas = document.createElement('canvas'); | |
5002 canvas.height = 200; | |
5003 canvas.width = 0; | |
5004 canvas.className = className; | |
5005 size_logo_on_canvas(logo, canvas, false); | |
5006 add_draw_task(canvas, new DelayLogoTask(logo, canvas)); | |
5007 return canvas; | |
5008 } | |
5009 | |
5010 function make_sym_btn(symbol, title, action) { | |
5011 var box; | |
5012 box = document.createElement("div"); | |
5013 box.tabIndex = 0; | |
5014 box.className = "sym_btn"; | |
5015 box.appendChild(document.createTextNode(symbol)); | |
5016 box.title = title; | |
5017 box.addEventListener('click', action, false); | |
5018 box.addEventListener('keydown', action, false); | |
5019 return box; | |
5020 } | |
5021 | |
5022 function make_seq(alphabet, seq) { | |
5023 var i, j, letter, lbox, sbox; | |
5024 sbox = document.createElement("span"); | |
5025 for (i = 0; i < seq.length; i = j) { | |
5026 letter = seq.charAt(i); | |
5027 for (j = i+1; j < seq.length; j++) { | |
5028 if (seq.charAt(j) !== letter) { | |
5029 break; | |
5030 } | |
5031 } | |
5032 lbox = document.createElement("span"); | |
5033 lbox.style.color = alphabet.get_colour(alphabet.get_index(letter)); | |
5034 lbox.appendChild(document.createTextNode(seq.substring(i, j))); | |
5035 sbox.appendChild(lbox); | |
5036 } | |
5037 return sbox; | |
5038 } | |
5039 | |
5040 // | |
5041 // make_pv_text | |
5042 // | |
5043 // Returns the string p-value, with the p italicised. | |
5044 /// | |
5045 function make_pv_text() { | |
5046 var pv_text = document.createElement("span"); | |
5047 var pv_italic_text = document.createElement("span"); | |
5048 pv_italic_text.appendChild(document.createTextNode("p")); | |
5049 pv_italic_text.style.fontStyle = "italic"; | |
5050 pv_text.appendChild(pv_italic_text); | |
5051 pv_text.appendChild(document.createTextNode("-value")); | |
5052 return pv_text; | |
5053 } | |
5054 | |
5055 function append_site_entries(tbody, motif, site_index, count) { | |
5056 "use strict"; | |
5057 var i, end; | |
5058 var sites, site, sequences, sequence; | |
5059 var rbody; | |
5060 if (typeof count !== "number") { | |
5061 count = 20; | |
5062 } | |
5063 sequences = data["sequence_db"]["sequences"]; | |
5064 sites = motif["sites"]; | |
5065 end = Math.min(site_index + count, sites.length); | |
5066 for (i = site_index; i < end; i++) { | |
5067 site = sites[i]; | |
5068 sequence = sequences[site["seq"]]; | |
5069 | |
5070 rbody = tbody.insertRow(tbody.rows.length); | |
5071 add_text_cell(rbody, "" + (site["seq"] + 1) + ".", "site_num"); | |
5072 add_text_cell(rbody, sequence["name"], "site_name"); | |
5073 add_text_cell(rbody, site["rc"] ? "-" : "+", "site_strand"); | |
5074 add_text_cell(rbody, site["pos"] + 1, "site_start"); | |
5075 add_text_cell(rbody, site["pvalue"].toExponential(2), "site_pvalue"); | |
5076 add_text_cell(rbody, site["lflank"], "site lflank"); | |
5077 add_cell(rbody, make_seq(meme_alphabet, site["match"]), "site match"); | |
5078 add_text_cell(rbody, site["rflank"], "site rflank"); | |
5079 } | |
5080 return i; | |
5081 } | |
5082 | |
5083 function make_site_entries() { | |
5084 "use strict"; | |
5085 var region; | |
5086 region = this; | |
5087 if (region.data_site_index >= region.data_motif["sites"].length) { | |
5088 // all sites created | |
5089 region.removeEventListener('scroll', make_site_entries, false); | |
5090 return; | |
5091 } | |
5092 // if there's still 100 pixels to scroll than don't do anything yet | |
5093 if (region.scrollHeight - (region.scrollTop + region.offsetHeight) > 100) { | |
5094 return; | |
5095 } | |
5096 | |
5097 region.data_site_index = append_site_entries( | |
5098 find_child(region, "sites_tbl").tBodies[0], | |
5099 region.data_motif, region.data_site_index, 20 | |
5100 ); | |
5101 } | |
5102 | |
5103 function make_sites(motif) { | |
5104 "use strict"; | |
5105 function add_site_header(row, title, nopad, help_topic, tag_class) { | |
5106 var div, divcp, th; | |
5107 th = document.createElement("th"); | |
5108 div = document.createElement("div"); | |
5109 div.className = "sites_th_inner"; | |
5110 if (typeof title !== "object") { | |
5111 title = document.createTextNode("" + title); | |
5112 } | |
5113 div.appendChild(title); | |
5114 if (help_topic) { | |
5115 div.appendChild(document.createTextNode("\xA0")); | |
5116 div.appendChild(help_button(help_topic)); | |
5117 } | |
5118 divcp = div.cloneNode(true); | |
5119 divcp.className = "sites_th_hidden"; | |
5120 th.appendChild(div); | |
5121 th.appendChild(divcp); | |
5122 if (nopad) { | |
5123 th.className = "nopad"; | |
5124 } | |
5125 if (tag_class) { | |
5126 th.className += " " + tag_class; | |
5127 } | |
5128 row.appendChild(th); | |
5129 } | |
5130 var outer_tbl, inner_tbl, tbl, thead, tbody, rhead; | |
5131 | |
5132 outer_tbl = document.createElement("div"); | |
5133 outer_tbl.className = "sites_outer"; | |
5134 | |
5135 inner_tbl = document.createElement("div"); | |
5136 inner_tbl.className = "sites_inner"; | |
5137 outer_tbl.appendChild(inner_tbl); | |
5138 | |
5139 tbl = document.createElement("table"); | |
5140 tbl.className = "sites_tbl"; | |
5141 inner_tbl.appendChild(tbl); | |
5142 | |
5143 thead = document.createElement("thead"); | |
5144 tbl.appendChild(thead); | |
5145 tbody = document.createElement("tbody"); | |
5146 tbl.appendChild(tbody); | |
5147 | |
5148 rhead = thead.insertRow(thead.rows.length); | |
5149 add_site_header(rhead, "", true); | |
5150 add_site_header(rhead, "Name", false, "pop_seq_name"); | |
5151 add_site_header(rhead, "Strand", false, "pop_site_strand", "site_strand_title"); | |
5152 add_site_header(rhead, "Start", false, "pop_site_start"); | |
5153 add_site_header(rhead, make_pv_text(), false, "pop_site_pvalue"); | |
5154 add_site_header(rhead, "", false); | |
5155 add_site_header(rhead, "Sites", true, "pop_site_match"); | |
5156 add_site_header(rhead, "", false); | |
5157 | |
5158 inner_tbl.data_motif = motif; | |
5159 inner_tbl.data_site_index = append_site_entries(tbody, motif, 0, 20); | |
5160 if (inner_tbl.data_site_index < motif["sites"].length) { | |
5161 inner_tbl.addEventListener('scroll', make_site_entries, false); | |
5162 } | |
5163 return outer_tbl; | |
5164 } | |
5165 | |
5166 function make_motif_table_entry(row, alphabet, ordinal, motif, colw) { | |
5167 "use strict"; | |
5168 function ev_sig(evalue_str) { | |
5169 "use strict"; | |
5170 var ev_re, match, sig, exp, num; | |
5171 ev_re = /^(.*)e(.*)$/; | |
5172 if (match = ev_re.exec(evalue_str)) { | |
5173 sig = parseFloat(match[1]); | |
5174 exp = parseInt(match[2]); | |
5175 if (exp >= 0) { | |
5176 return false; | |
5177 } else if (exp <= -3) { | |
5178 return true; | |
5179 } else { | |
5180 return sig * Math.pow(10, exp) <= 0.05; | |
5181 } | |
5182 } | |
5183 return true; | |
5184 } | |
5185 function make_preview(alphabet, motif) { | |
5186 "use strict"; | |
5187 var pspm, preview, preview_rc; | |
5188 var box, btn_box, logo_box, btn_plus, btn_minus; | |
5189 if (motif["preview_logo"]) { | |
5190 preview = motif["preview_logo"]; | |
5191 preview_rc = motif["preview_logo_rc"]; | |
5192 } else { | |
5193 pspm = new Pspm(motif["pwm"]); | |
5194 preview = make_logo(alphabet, pspm); | |
5195 motif["preview_logo"] = preview; | |
5196 if (alphabet.has_complement()) { | |
5197 preview_rc = make_logo(alphabet, pspm, true, 0, "logo_rc"); | |
5198 motif["preview_logo_rc"] = preview_rc; | |
5199 } | |
5200 } | |
5201 if (preview_rc) { | |
5202 btn_plus = document.createElement("div"); | |
5203 btn_plus.appendChild(document.createTextNode("+")); | |
5204 btn_plus.className = "preview_btn plus"; | |
5205 btn_plus.tabIndex = "0"; | |
5206 btn_plus.addEventListener("click", action_btn_rc, false); | |
5207 btn_plus.addEventListener("keydown", action_btn_rc, false); | |
5208 btn_minus = document.createElement("div"); | |
5209 btn_minus.appendChild(document.createTextNode("-")); | |
5210 btn_minus.className = "preview_btn minus"; | |
5211 btn_minus.tabIndex = "0"; | |
5212 btn_minus.addEventListener("click", action_btn_rc, false); | |
5213 btn_minus.addEventListener("keydown", action_btn_rc, false); | |
5214 btn_box = document.createElement("div"); | |
5215 btn_box.className = "preview_btn_box"; | |
5216 btn_box.appendChild(btn_plus); | |
5217 btn_box.appendChild(btn_minus); | |
5218 } | |
5219 logo_box = document.createElement("div"); | |
5220 logo_box.className = "preview_logo_box"; | |
5221 logo_box.appendChild(preview); | |
5222 if (preview_rc) logo_box.appendChild(preview_rc); | |
5223 box = document.createElement("div"); | |
5224 box.className = "preview_box"; | |
5225 if (preview_rc) box.appendChild(btn_box); | |
5226 box.appendChild(logo_box); | |
5227 if (preview_rc) { | |
5228 if (motif["rc"]) { | |
5229 btn_minus.className += " active"; | |
5230 logo_box.className += " show_rc_logo"; | |
5231 } else { | |
5232 btn_plus.className += " active"; | |
5233 } | |
5234 } | |
5235 return box; | |
5236 } | |
5237 var pspm, preview, preview_rc, c; | |
5238 row.data_motif = motif; | |
5239 row.data_ordinal = ordinal; | |
5240 if (!ev_sig(motif["evalue"])) { | |
5241 row.style.opacity = 0.4; | |
5242 } | |
5243 add_text_cell(row, "" + ordinal + ".", "motif_ordinal"); | |
5244 add_cell(row, make_preview(alphabet, motif), "motif_logo"); | |
5245 add_text_cell(row, motif["evalue"], "motif_evalue"); | |
5246 add_text_cell(row, motif["nsites"], "motif_nsites"); | |
5247 add_text_cell(row, motif["len"], "motif_width"); | |
5248 add_cell(row, make_sym_btn("\u21A7", "Show more information.", | |
5249 action_show_more), "motif_more"); | |
5250 add_cell(row, | |
5251 make_sym_btn("\u21E2", | |
5252 "Submit the motif to another MEME Suite program or download it.", | |
5253 action_show_outpop), | |
5254 "motif_submit"); | |
5255 if (colw) { | |
5256 for (c = 0; c < row.cells.length; c++) { | |
5257 row.cells[c].style.minWidth = colw[c] + "px"; | |
5258 } | |
5259 } | |
5260 } | |
5261 | |
5262 function make_motifs_table(alphabet, start_ordinal, motifs, colw, stop_reason) { | |
5263 var i, j; | |
5264 var tbl, thead, tbody, tfoot, row, preview; | |
5265 var motif, pspm; | |
5266 | |
5267 tbl = document.createElement("table"); | |
5268 | |
5269 thead = document.createElement("thead"); | |
5270 tbl.appendChild(thead); | |
5271 tbody = document.createElement("tbody"); | |
5272 tbl.appendChild(tbody); | |
5273 tfoot = document.createElement("tfoot"); | |
5274 tbl.appendChild(tfoot); | |
5275 | |
5276 row = thead.insertRow(thead.rows.length); | |
5277 add_text_header_cell(row, "", "", "motif_ordinal"); | |
5278 add_text_header_cell(row, "Logo", "", "motif_logo"); | |
5279 add_text_header_cell(row, "E-value", "pop_ev", "motif_evalue"); | |
5280 add_text_header_cell(row, "Sites", "pop_sites", "motif_nsites"); | |
5281 add_text_header_cell(row, "Width", "pop_width", "motif_width"); | |
5282 add_text_header_cell(row, "More", "pop_more", "motif_more"); | |
5283 add_text_header_cell(row, "Submit/Download", "pop_submit_dl", "motif_submit"); | |
5284 | |
5285 for (i = 0; i < motifs.length; i++) { | |
5286 row = tbody.insertRow(tbody.rows.length); | |
5287 make_motif_table_entry(row, alphabet, start_ordinal + i, motifs[i], colw); | |
5288 } | |
5289 | |
5290 row = tfoot.insertRow(tfoot.rows.length); | |
5291 add_text_header_cell(row, stop_reason, "", "stop_reason", "", 6); | |
5292 | |
5293 return tbl; | |
5294 } | |
5295 | |
5296 function make_expanded_motif(alphabet, ordinal, motif, less_x, submit_x) { | |
5297 "use strict"; | |
5298 var box, pspm, logo_box, large_logo, large_logo_rc, tab_logo, tab_logo_rc; | |
5299 var btn, offset, norc; | |
5300 | |
5301 box = clone_template("tmpl_motif_expanded"); | |
5302 box.data_motif = motif; | |
5303 box.data_ordinal = ordinal; | |
5304 | |
5305 pspm = new Pspm(motif["pwm"]); | |
5306 if (typeof motif["rc"] !== "boolean") { | |
5307 motif["rc"] = false; | |
5308 } | |
5309 if (motif["large_logo"]) { | |
5310 large_logo = motif["large_logo"]; | |
5311 large_logo_rc = motif["large_logo_rc"]; | |
5312 } else { | |
5313 large_logo = make_large_logo(alphabet, pspm, false, 0); | |
5314 motif["large_logo"] = large_logo; | |
5315 if (alphabet.has_complement()) { | |
5316 large_logo_rc = make_large_logo(alphabet, pspm, true, 0, "logo_rc"); | |
5317 motif["large_logo_rc"] = large_logo_rc; | |
5318 } | |
5319 } | |
5320 norc = (large_logo_rc == null); | |
5321 toggle_class(box, "norc", norc); | |
5322 | |
5323 logo_box = find_child(box, "tvar_logo"); | |
5324 logo_box.appendChild(large_logo); | |
5325 if (large_logo_rc) logo_box.appendChild(large_logo_rc); | |
5326 toggle_class(logo_box, "show_rc_logo", motif["rc"]); | |
5327 | |
5328 tab_logo = find_child(box, "tvar_tab"); | |
5329 tab_logo_rc = find_child(box, "tvar_tab_rc"); | |
5330 | |
5331 toggle_class(tab_logo, "activeTab", !motif["rc"]); | |
5332 toggle_class(tab_logo_rc, "activeTab", motif["rc"]); | |
5333 | |
5334 tab_logo.addEventListener('click', action_rc_tab, false); | |
5335 tab_logo.addEventListener('keydown', action_rc_tab, false); | |
5336 tab_logo_rc.addEventListener('click', action_rc_tab, false); | |
5337 tab_logo_rc.addEventListener('keydown', action_rc_tab, false); | |
5338 | |
5339 set_tvar(box, "tvar_ordinal", ordinal); | |
5340 set_tvar(box, "tvar_evalue", motif["evalue"]); | |
5341 set_tvar(box, "tvar_width", motif["len"]); | |
5342 set_tvar(box, "tvar_site_count", motif["nsites"]); | |
5343 set_tvar(box, "tvar_llr", motif["llr"]); | |
5344 set_tvar(box, "tvar_ic", motif["ic"]); | |
5345 set_tvar(box, "tvar_re", motif["re"]); | |
5346 set_tvar(box, "tvar_bt", motif["bt"]); | |
5347 set_tvar(box, "tvar_sites", make_sites(motif)); | |
5348 | |
5349 offset = 32; // 1* 5px padding + 2 * 10px padding + 2 * 2px border + 3px ?? | |
5350 | |
5351 btn = find_child(box, "tvar_less"); | |
5352 btn.style.left = (less_x - offset) + "px"; | |
5353 btn.addEventListener('click', action_show_less, false); | |
5354 btn.addEventListener('keydown', action_show_less, false); | |
5355 btn = find_child(box, "tvar_submit"); | |
5356 btn.style.left = (submit_x - offset) + "px"; | |
5357 btn.addEventListener('click', action_show_outpop, false); | |
5358 btn.addEventListener('keydown', action_show_outpop, false); | |
5359 return box; | |
5360 } | |
5361 | |
5362 | |
5363 // | |
5364 // | |
5365 /// | |
5366 function make_motifs() { | |
5367 "use strict"; | |
5368 function pixel_value(str_in) { | |
5369 "use strict"; | |
5370 var px_re, match; | |
5371 px_re = /^(\d+)px$/; | |
5372 if (match = px_re.exec(str_in)) { | |
5373 return parseInt(match[1], 10); | |
5374 } | |
5375 return 0; | |
5376 } | |
5377 var container, tbl; | |
5378 var colw, r, row, c, cell, cell_style, pad_left, pad_right; | |
5379 | |
5380 // make the motifs table | |
5381 container = $("motifs"); | |
5382 container.innerHTML = ""; // clear content | |
5383 | |
5384 tbl = make_motifs_table(meme_alphabet, 1, data["motifs"], colw, data["stop_reason"]); | |
5385 container.appendChild(tbl); | |
5386 | |
5387 // measure table column widths | |
5388 colw = []; | |
5389 row = tbl.tBodies[0].rows[0]; | |
5390 for (c = 0; c < row.cells.length; c++) { | |
5391 var padLeft, padRight; | |
5392 cell = row.cells[c]; | |
5393 cell_style = window.getComputedStyle(cell, null); | |
5394 pad_left = pixel_value(cell_style.getPropertyValue("padding-left")); | |
5395 pad_right = pixel_value(cell_style.getPropertyValue("padding-right")); | |
5396 colw[c] = cell.clientWidth - pad_left - pad_right; | |
5397 if (typeof colw[c] !== "number" || colw[c] < 0) { | |
5398 colw[c] = 1; | |
5399 } | |
5400 } | |
5401 | |
5402 // set minimum table column widths on each row so later when we remove rows it still aligns | |
5403 for (r = 0; r < tbl.tBodies[0].rows.length; r++) { | |
5404 row = tbl.tBodies[0].rows[r]; | |
5405 for (c = 0; c < row.cells.length; c++) { | |
5406 row.cells[c].style.minWidth = colw[c] + "px"; | |
5407 } | |
5408 } | |
5409 | |
5410 // store the table column widths so we can create rows latter with the same minimums | |
5411 container.data_colw = colw; | |
5412 | |
5413 // calculate the x offset for the buttons | |
5414 row = tbl.tBodies[0].rows[0]; | |
5415 container.data_more_x = coords(find_child(find_child(row, "motif_more"), "sym_btn"))[0]; | |
5416 container.data_submit_x = coords(find_child(find_child(row, "motif_submit"), "sym_btn"))[0]; | |
5417 | |
5418 draw_on_screen(); | |
5419 } | |
5420 | |
5421 function make_meme_block(container, max_seq_len, is_scan, site) { | |
5422 "use strict"; | |
5423 var motif = data.motifs[site.motif]; | |
5424 var block = make_block(container, max_seq_len, site.pos, motif.len, | |
5425 site.pvalue, site.rc, site.motif, is_scan); | |
5426 var handler = (is_scan ? | |
5427 make_scan_popup(site, motif, block) : | |
5428 make_block_popup(site, motif, block)); | |
5429 block.addEventListener("mouseover", handler, false); | |
5430 block.addEventListener("mouseout", handler, false); | |
5431 } | |
5432 | |
5433 function append_blocks_entries(tbody, seq_index, count) { | |
5434 "use strict"; | |
5435 var i, end, j; | |
5436 var max_pvalue, max_block_height, max_seq_len, sequences; | |
5437 var sequence, sites, scans, scan; | |
5438 var container, plus, minus, rule, row; | |
5439 // define some constants | |
5440 max_seq_len = data.sequence_db.max_length; | |
5441 // determine how many to load | |
5442 end = Math.min(seq_index + count, data.sequence_db.sequences.length); | |
5443 for (i = seq_index; i < end; i++) { | |
5444 // get the sequence | |
5445 sequence = data.sequence_db.sequences[i]; | |
5446 // make the containers for the block diagram | |
5447 container = make_block_container(meme_alphabet.has_complement(), | |
5448 data.options.revcomp, max_seq_len, sequence.length); | |
5449 // create blocks for the motif sites | |
5450 sites = sequence["sites"]; | |
5451 for (j = 0; j < sites.length; j++) | |
5452 make_meme_block(container, max_seq_len, false, sites[j]); | |
5453 // create blocks for the scanned sites | |
5454 scan = data.scan[i]; | |
5455 for (j = 0; j < scan.sites.length; j++) | |
5456 make_meme_block(container, max_seq_len, true, scan.sites[j]); | |
5457 // create a row for the sequence | |
5458 row = tbody.insertRow(tbody.rows.length); | |
5459 toggle_class(row, "empty_seq", sites.length == 0 && scan.sites.length == 0); | |
5460 toggle_class(row, "only_scan", sites.length == 0 && scan.sites.length > 0); | |
5461 add_text_cell(row, (i + 1) + ".", "blockdiag_num"); | |
5462 add_text_cell(row, sequence["name"], "blockdiag_name"); | |
5463 add_text_cell(row, scan["pvalue"].toExponential(2), "blockdiag_pvalue"); | |
5464 add_cell(row, container, "block_td"); | |
5465 } | |
5466 return end; | |
5467 } | |
5468 | |
5469 function make_blocks_entries() { | |
5470 "use strict"; | |
5471 var region; | |
5472 region = this; | |
5473 if (region.data_blocks_index >= data["sequence_db"]["sequences"].length) { | |
5474 // all sites created | |
5475 region.removeEventListener('scroll', make_blocks_entries, false); | |
5476 return; | |
5477 } | |
5478 // if there's still 100 pixels to scroll than don't do anything yet | |
5479 if (region.scrollHeight - (region.scrollTop + region.offsetHeight) > 100) { | |
5480 return; | |
5481 } | |
5482 | |
5483 region.data_blocks_index = append_blocks_entries( | |
5484 find_child(region, "blocks_tbl").tBodies[0], | |
5485 region.data_blocks_index, 20 | |
5486 ); | |
5487 } | |
5488 | |
5489 function make_blocks() { | |
5490 "use strict"; | |
5491 function add_seqs_filter(container, id, checked, label_text, help_topic) { | |
5492 "use strict"; | |
5493 var label, radio; | |
5494 radio = document.createElement("input"); | |
5495 radio.type = "radio"; | |
5496 radio.name = "seqs_display"; | |
5497 radio.id = id; | |
5498 radio.checked = checked; | |
5499 radio.addEventListener('click', action_seqs_filter, false); | |
5500 label = document.createElement("label"); | |
5501 label.appendChild(document.createTextNode(label_text)); | |
5502 label.htmlFor = id; | |
5503 container.appendChild(radio); | |
5504 container.appendChild(label); | |
5505 if (help_topic) { | |
5506 container.appendChild(document.createTextNode("\xA0")); | |
5507 container.appendChild(help_button(help_topic)); | |
5508 } | |
5509 } | |
5510 function add_blocks_header(row, title, nopad, help_topic) { | |
5511 "use strict"; | |
5512 var div, divcp, th; | |
5513 th = document.createElement("th"); | |
5514 div = document.createElement("div"); | |
5515 div.className = "blocks_th_inner"; | |
5516 if (typeof title !== "object") { | |
5517 title = document.createTextNode("" + title); | |
5518 } | |
5519 div.appendChild(title); | |
5520 if (help_topic) { | |
5521 div.appendChild(document.createTextNode("\xA0")); | |
5522 div.appendChild(help_button(help_topic)); | |
5523 } | |
5524 divcp = div.cloneNode(true); | |
5525 divcp.className = "blocks_th_hidden"; | |
5526 th.appendChild(div); | |
5527 th.appendChild(divcp); | |
5528 if (nopad) { | |
5529 th.className = "nopad"; | |
5530 } | |
5531 row.appendChild(th); | |
5532 } | |
5533 var container; | |
5534 var page, view_height, outer_tbl, inner_tbl, tbl, thead, tbody, rhead; | |
5535 var in_view, i, seq_count; | |
5536 | |
5537 page = (document.compatMode === "CSS1Compat") ? document.documentElement : document.body; | |
5538 view_height = Math.max(page.clientHeight - 300, 300); | |
5539 | |
5540 container = $("blocks"); | |
5541 toggle_class(container, "hide_empty_seqs", true); | |
5542 toggle_class(container, "hide_only_scan", true); | |
5543 container.innerHTML = ""; | |
5544 add_seqs_filter(container, "rdo_sites_only", true, "Only Motif Sites", "pop_motif_sites"); | |
5545 add_seqs_filter(container, "rdo_sites_and_scan", false, "Motif Sites+Scanned Sites", "pop_scanned_sites"); | |
5546 add_seqs_filter(container, "rdo_all_seqs", false, "All Sequences", "pop_all_sequences"); | |
5547 | |
5548 outer_tbl = document.createElement("div"); | |
5549 outer_tbl.className = "blocks_outer"; | |
5550 | |
5551 inner_tbl = document.createElement("div"); | |
5552 inner_tbl.id = "blocks_scroll"; | |
5553 inner_tbl.className = "blocks_inner"; | |
5554 inner_tbl.style.maxHeight = view_height + "px"; | |
5555 outer_tbl.appendChild(inner_tbl); | |
5556 | |
5557 tbl = document.createElement("table"); | |
5558 tbl.className = "blocks_tbl"; | |
5559 inner_tbl.appendChild(tbl); | |
5560 | |
5561 thead = document.createElement("thead"); | |
5562 tbl.appendChild(thead); | |
5563 tbody = document.createElement("tbody"); | |
5564 tbl.appendChild(tbody); | |
5565 | |
5566 rhead = thead.insertRow(thead.rows.length); | |
5567 add_blocks_header(rhead, "", true); | |
5568 add_blocks_header(rhead, "Name", false, "pop_seq_name"); | |
5569 add_blocks_header(rhead, make_pv_text(), false, "pop_seq_pvalue"); | |
5570 add_blocks_header(rhead, "Motif Location", false, "pop_motif_location"); | |
5571 | |
5572 container.appendChild(outer_tbl); | |
5573 | |
5574 | |
5575 seq_count = data["sequence_db"]["sequences"].length; | |
5576 in_view = Math.max(Math.ceil(view_height / 25), 1); | |
5577 i = append_blocks_entries(tbody, 0, in_view); | |
5578 | |
5579 while (i < seq_count && inner_tbl.scrollHeight - (inner_tbl.scrollTop + inner_tbl.offsetHeight) < 400) { | |
5580 i = append_blocks_entries(tbody, i, 20); | |
5581 } | |
5582 inner_tbl.data_blocks_index = i; | |
5583 if (i < seq_count) { | |
5584 inner_tbl.addEventListener('scroll', make_blocks_entries, false); | |
5585 } | |
5586 } | |
5587 | |
5588 function make_scan_popup(site, motif) { | |
5589 return function (e) { | |
5590 "use strict"; | |
5591 var pop, xy, padding, edge_padding, pop_left, pop_top, page_width; | |
5592 var lflank, match, rflank, pspm; | |
5593 if (!e) var e = window.event; | |
5594 pop = make_scan_popup.pop; | |
5595 if (e.type === "mouseover") { | |
5596 if (pop) return; | |
5597 pop = clone_template("tmpl_scan_info"); | |
5598 pspm = new Pspm(motif.pwm); | |
5599 if (site.rc) pspm.reverse_complement(meme_alphabet); | |
5600 set_tvar(pop, "tvar_logo", make_small_logo(meme_alphabet, pspm, {"className": "scan_logo"})); | |
5601 set_tvar(pop, "tvar_motif", motif.id); | |
5602 set_tvar(pop, "tvar_pvalue", site.pvalue.toExponential(2)); | |
5603 set_tvar(pop, "tvar_start", site.pos + 1); | |
5604 set_tvar(pop, "tvar_end", site.pos + motif.len); | |
5605 | |
5606 document.body.appendChild(pop); | |
5607 position_popup(this, pop); | |
5608 make_scan_popup.pop = pop; | |
5609 } else if (e.type === "mouseout") { | |
5610 if (pop) { | |
5611 pop.parentNode.removeChild(pop); | |
5612 make_scan_popup.pop = null; | |
5613 } | |
5614 } | |
5615 }; | |
5616 } | |
5617 | |
5618 function make_block_popup(site, motif, block) { | |
5619 return function (e) { | |
5620 "use strict"; | |
5621 var pop; | |
5622 var lflank, match, rflank, pspm, ruler, match_seq, match_width; | |
5623 if (!e) var e = window.event; | |
5624 pop = make_block_popup.pop; | |
5625 if (e.type === "mouseover") { | |
5626 if (pop) return; | |
5627 pop = clone_template("tmpl_block_info"); | |
5628 pspm = new Pspm(motif.pwm); | |
5629 if (site.rc) { // must be dna | |
5630 pspm.reverse_complement(meme_alphabet); | |
5631 lflank = meme_alphabet.invcomp_seq(site.rflank); | |
5632 match = meme_alphabet.invcomp_seq(site.match); | |
5633 rflank = meme_alphabet.invcomp_seq(site.lflank); | |
5634 } else { | |
5635 lflank = site.lflank; | |
5636 match = site.match; | |
5637 rflank = site.rflank; | |
5638 } | |
5639 ruler = document.getElementById("measure_match"); | |
5640 match_seq = make_seq(meme_alphabet, match); | |
5641 ruler.innerHTML = ""; | |
5642 ruler.appendChild(match_seq); | |
5643 match_width = ruler.clientWidth; | |
5644 ruler.removeChild(match_seq); | |
5645 set_tvar(pop, "tvar_lflank", lflank); | |
5646 set_tvar(pop, "tvar_match", match_seq); | |
5647 set_tvar(pop, "tvar_rflank", rflank); | |
5648 set_tvar(pop, "tvar_logo_pad", lflank); | |
5649 set_tvar(pop, "tvar_logo", make_small_logo(meme_alphabet, pspm, {"width": match_width})); | |
5650 set_tvar(pop, "tvar_motif", motif.id); | |
5651 set_tvar(pop, "tvar_pvalue", site.pvalue.toExponential(2)); | |
5652 set_tvar(pop, "tvar_start", site.pos + 1); | |
5653 set_tvar(pop, "tvar_end", site.pos + motif.len); | |
5654 | |
5655 document.body.appendChild(pop); | |
5656 position_popup(block, pop); | |
5657 make_block_popup.pop = pop; | |
5658 } else if (e.type === "mouseout") { | |
5659 if (pop) { | |
5660 pop.parentNode.removeChild(pop); | |
5661 make_block_popup.pop = null; | |
5662 } | |
5663 } | |
5664 }; | |
5665 } | |
5666 | |
5667 function update_outpop_format(index) { | |
5668 switch(parseInt($("text_format").value)) { | |
5669 case 0: // count matrix | |
5670 $("outpop_text").value = motif_count_matrix(index); | |
5671 $("text_name").value = "motif_" + (index + 1) + "_counts.txt"; | |
5672 break; | |
5673 case 1: // prob matrix | |
5674 $("outpop_text").value = motif_prob_matrix(index); | |
5675 $("text_name").value = "motif_" + (index + 1) + "_freqs.txt"; | |
5676 break; | |
5677 case 2: // minimal meme | |
5678 $("outpop_text").value = motif_minimal_meme(index); | |
5679 $("text_name").value = "motif_" + (index + 1) + ".txt"; | |
5680 break; | |
5681 case 3: // fasta | |
5682 $("outpop_text").value = motif_fasta(index); | |
5683 $("text_name").value = "motif_" + (index + 1) + "_fasta.txt"; | |
5684 break; | |
5685 case 4: // raw | |
5686 $("outpop_text").value = motif_raw(index); | |
5687 $("text_name").value = "motif_" + (index + 1) + "_raw.txt"; | |
5688 break; | |
5689 default: | |
5690 throw new Error("Unknown motif format"); | |
5691 } | |
5692 } | |
5693 | |
5694 function update_outpop_motif(index) { | |
5695 "use strict"; | |
5696 var motifs, motif, pspm, logo, canvas, num; | |
5697 motifs = data["motifs"]; | |
5698 if (index < 0 || index >= motifs.length) {return;} | |
5699 current_motif = index; | |
5700 motif = motifs[index]; | |
5701 pspm = new Pspm(motif["pwm"]); | |
5702 logo = new Logo(meme_alphabet, ""); | |
5703 logo.add_pspm(pspm, 0); | |
5704 canvas = $("outpop_logo"); | |
5705 canvas.width = canvas.width; // clear canvas | |
5706 draw_logo_on_canvas(logo, canvas, false); | |
5707 if (meme_alphabet.has_complement()) { | |
5708 pspm.reverse_complement(meme_alphabet); | |
5709 logo = new Logo(meme_alphabet, ""); | |
5710 canvas = $("outpop_logo_rc"); | |
5711 canvas.width = canvas.width; // clear canvas | |
5712 draw_logo_on_canvas(logo, canvas, false); | |
5713 } | |
5714 num = $("outpop_num"); | |
5715 num.innerHTML = ""; | |
5716 num.appendChild(document.createTextNode("" + (index + 1))); | |
5717 update_outpop_format(index); | |
5718 } | |
5719 | |
5720 // | |
5721 // action_show_more | |
5722 // | |
5723 // Show more information on the motif. | |
5724 /// | |
5725 function action_show_more(e) { | |
5726 var node, tr, tbody, table, container, motif, ordinal; | |
5727 var expanded_motif; | |
5728 if (!e) e = window.event; | |
5729 if (e.type === "keydown") { | |
5730 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
5731 return; | |
5732 } | |
5733 // stop a submit or something like that | |
5734 e.preventDefault(); | |
5735 } | |
5736 // find the row that contains the cell | |
5737 node = this; | |
5738 do { | |
5739 if (node.tagName === "TR") break; | |
5740 } while (node = node.parentNode); | |
5741 if (!node) throw new Error("Expected to find row!?"); | |
5742 tr = node; | |
5743 // get info | |
5744 motif = tr.data_motif; | |
5745 ordinal = tr.data_ordinal; | |
5746 // find tbody | |
5747 do { | |
5748 if (node.tagName === "TBODY") break; | |
5749 } while (node = node.parentNode); | |
5750 if (!node) throw new Error("Expected to find tbody!?"); | |
5751 tbody = node; | |
5752 // find table | |
5753 do { | |
5754 if (node.tagName === "TABLE") break; | |
5755 } while (node = node.parentNode); | |
5756 if (!node) throw new Error("Expected to find table!?"); | |
5757 table = node; | |
5758 // find container | |
5759 container = node.parentNode; | |
5760 // make a expanded motif | |
5761 motif["expanded"] = true; | |
5762 expanded_motif = make_expanded_motif(meme_alphabet, ordinal, motif, | |
5763 container.data_more_x, container.data_submit_x); | |
5764 // now determine how to place it | |
5765 if (tbody.rows.length === 1) { | |
5766 // only us in the table so the table can be replaced | |
5767 container.replaceChild(expanded_motif, table); | |
5768 } else if (tbody.rows[0] === tr) { | |
5769 // first row, so remove and insert an expanded motif before | |
5770 table.deleteRow(tr.rowIndex); | |
5771 container.insertBefore(expanded_motif, table); | |
5772 } else if (tbody.rows[tbody.rows.length -1] === tr) { | |
5773 // last row, so remove and insert an expanded motif after | |
5774 table.deleteRow(tr.rowIndex); | |
5775 container.insertBefore(expanded_motif, table.nextSibling); | |
5776 } else { | |
5777 var table2, tbody2; | |
5778 table2 = table.cloneNode(false); | |
5779 table2.appendChild(table.tHead.cloneNode(true)); | |
5780 tbody2 = table.tBodies[0].cloneNode(false); | |
5781 table2.appendChild(tbody2); | |
5782 container.insertBefore(table2, table.nextSibling); | |
5783 for (i = tbody.rows.length - 1; i >= 0; i--) { | |
5784 row = tbody.rows[i]; | |
5785 row.parentNode.removeChild(row); | |
5786 if (row === tr) { | |
5787 break; | |
5788 } | |
5789 tbody2.insertBefore(row, tbody2.rows[0]); | |
5790 } | |
5791 container.insertBefore(expanded_motif, table2); | |
5792 } | |
5793 find_child(expanded_motif, "tvar_less").focus(); | |
5794 } | |
5795 | |
5796 // | |
5797 // action_show_less | |
5798 // | |
5799 // Show less information on the motif. | |
5800 /// | |
5801 function action_show_less(e) { | |
5802 var btn; | |
5803 var expanded_motif, container, motif, ordinal, colw, focus_target; | |
5804 var table, tbody, tbody2, row, table_before, table_after; | |
5805 if (!e) e = window.event; | |
5806 if (e.type === "keydown") { | |
5807 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
5808 return; | |
5809 } | |
5810 // stop a submit or something like that | |
5811 e.preventDefault(); | |
5812 } | |
5813 btn = this; | |
5814 // find expanded motif | |
5815 expanded_motif = find_parent(btn, "expanded_motif"); | |
5816 if (!expanded_motif) throw new Error("Expected expanded motif."); | |
5817 // find the container | |
5818 container = expanded_motif.parentNode; | |
5819 // get data | |
5820 motif = expanded_motif.data_motif; | |
5821 ordinal = expanded_motif.data_ordinal; | |
5822 colw = container.data_colw; | |
5823 // get the table before | |
5824 table_before = expanded_motif.previousSibling; | |
5825 if (table_before && table_before.tagName !== "TABLE") { | |
5826 table_before = null; | |
5827 } | |
5828 // get the table after | |
5829 table_after = expanded_motif.nextSibling; | |
5830 if (table_after && table_after.tagName !== "TABLE") { | |
5831 table_after = null; | |
5832 } | |
5833 // see if there is a table below or above that we can put this in. | |
5834 // if there is a table both below and above then add this motif and | |
5835 // all ones below to the above table | |
5836 motif["expanded"] = false; | |
5837 if (table_before && table_after) { | |
5838 tbody = table_before.tBodies[0]; | |
5839 row = tbody.insertRow(tbody.rows.length); | |
5840 make_motif_table_entry(row, meme_alphabet, ordinal, motif, colw); | |
5841 focus_target = find_child(row.cells[5], "sym_btn"); | |
5842 container.removeChild(expanded_motif); | |
5843 tbody2 = table_after.tBodies[0]; | |
5844 while (tbody2.rows.length > 0) { | |
5845 row = tbody2.rows[0]; | |
5846 row.parentNode.removeChild(row); | |
5847 tbody.appendChild(row); | |
5848 } | |
5849 container.removeChild(table_after); | |
5850 } else if (table_before) { | |
5851 tbody = table_before.tBodies[0]; | |
5852 row = tbody.insertRow(tbody.rows.length); | |
5853 make_motif_table_entry(row, meme_alphabet, ordinal, motif, colw); | |
5854 focus_target = find_child(row.cells[5], "sym_btn"); | |
5855 container.removeChild(expanded_motif); | |
5856 } else if (table_after) { | |
5857 tbody = table_after.tBodies[0]; | |
5858 row = tbody.insertRow(0); | |
5859 make_motif_table_entry(row, meme_alphabet, ordinal, motif, colw); | |
5860 focus_target = find_child(row.cells[5], "sym_btn"); | |
5861 container.removeChild(expanded_motif); | |
5862 } else { | |
5863 //no table above or below! | |
5864 // make a new table | |
5865 table = make_motifs_table(meme_alphabet, ordinal, [motif], colw, data["stop_reason"]); | |
5866 focus_target = find_child(table.tBodies[0].rows[0].cells[5], "sym_btn"); | |
5867 container.replaceChild(table, expanded_motif); | |
5868 } | |
5869 focus_target.focus(); | |
5870 } | |
5871 | |
5872 function action_show_outpop(e) { | |
5873 "use strict"; | |
5874 function init() { | |
5875 "use strict"; | |
5876 var close_btn, next_btn, prev_btn, cancel_btn, do_btn; | |
5877 var tab1, tab2, tab3; | |
5878 var pnl1, pnl2, pnl3; | |
5879 var format_list; | |
5880 var tbl_submit, inputs, i, default_prog; | |
5881 close_btn = $("outpop_close"); | |
5882 close_btn.addEventListener("click", action_hide_outpop, false); | |
5883 close_btn.addEventListener("keydown", action_hide_outpop, false); | |
5884 next_btn = $("outpop_next"); | |
5885 next_btn.addEventListener("click", action_outpop_next, false); | |
5886 next_btn.addEventListener("keydown", action_outpop_next, false); | |
5887 prev_btn = $("outpop_prev"); | |
5888 prev_btn.addEventListener("click", action_outpop_prev, false); | |
5889 prev_btn.addEventListener("keydown", action_outpop_prev, false); | |
5890 cancel_btn = $("outpop_cancel"); | |
5891 cancel_btn.addEventListener("click", action_hide_outpop, false); | |
5892 do_btn = $("outpop_do"); | |
5893 do_btn.addEventListener("click", action_outpop_submit, false); | |
5894 tab1 = $("outpop_tab_1"); | |
5895 tab1.tabIndex = 0; | |
5896 tab1.addEventListener("click", action_outpop_tab, false); | |
5897 tab1.addEventListener("keydown", action_outpop_tab, false); | |
5898 tab2 = $("outpop_tab_2"); | |
5899 tab2.tabIndex = 0; | |
5900 tab2.addEventListener("click", action_outpop_tab, false); | |
5901 tab2.addEventListener("keydown", action_outpop_tab, false); | |
5902 tab3 = $("outpop_tab_3"); | |
5903 tab3.tabIndex = 0; | |
5904 tab3.addEventListener("click", action_outpop_tab, false); | |
5905 tab3.addEventListener("keydown", action_outpop_tab, false); | |
5906 pnl1 = $("outpop_pnl_1"); | |
5907 pnl2 = $("outpop_pnl_2"); | |
5908 pnl3 = $("outpop_pnl_3"); | |
5909 toggle_class(tab1, "activeTab", true); | |
5910 toggle_class(tab2, "activeTab", false); | |
5911 toggle_class(tab3, "activeTab", false); | |
5912 pnl1.style.display = "block"; | |
5913 pnl2.style.display = "none"; | |
5914 pnl3.style.display = "none"; | |
5915 format_list = $("text_format"); | |
5916 format_list.addEventListener("change", action_outpop_format, false); | |
5917 // setup program selection | |
5918 tbl_submit = $("programs"); | |
5919 // when not dna, hide the inputs for programs that require dna motifs | |
5920 toggle_class(tbl_submit, "alphabet_dna", meme_alphabet.has_complement());//TODO FIXME alphabet_dna is a bad name for a field when allowing custom alphabets | |
5921 // add a click listener for the radio buttons | |
5922 inputs = tbl_submit.querySelectorAll("input[type='radio']"); | |
5923 for (i = 0; i < inputs.length; i++) { | |
5924 inputs[i].addEventListener("click", action_outpop_program, false); | |
5925 } | |
5926 // ensure that a default program option is selected for DNA and Protein | |
5927 default_prog = document.getElementById(meme_alphabet.has_complement() ? "submit_tomtom" : "submit_fimo"); //TODO FIXME Tomtom might require a more strict definition of DNA | |
5928 default_prog.checked = true; | |
5929 action_outpop_program.call(default_prog); | |
5930 // disable reverse-complement when not DNA | |
5931 $("logo_rc_option").disabled = !meme_alphabet.has_complement(); | |
5932 // set errorbars on when ssc is on | |
5933 $("logo_ssc").addEventListener("change", action_outpop_ssc, false); | |
5934 } | |
5935 var node; | |
5936 // store the focused element | |
5937 action_hide_outpop.last_active = document.activeElement; | |
5938 if (!e) e = window.event; | |
5939 if (e.type === "keydown") { | |
5940 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
5941 return; | |
5942 } | |
5943 // stop a submit or something like that | |
5944 e.preventDefault(); | |
5945 } | |
5946 // hide the help popup | |
5947 help_popup(); | |
5948 // on first load initilize the popup | |
5949 if (!action_show_outpop.ready) { | |
5950 init(); | |
5951 action_show_outpop.ready = true; | |
5952 } | |
5953 // load the motif logo | |
5954 node = this; | |
5955 do { | |
5956 if (/\bexpanded_motif\b/.test(node.className) || node.tagName === "TR") break; | |
5957 } while (node = node.parentNode); | |
5958 if (node === null) throw new Error("Expected node!"); | |
5959 update_outpop_motif(node.data_ordinal - 1); | |
5960 // display the download popup | |
5961 $("grey_out_page").style.display = "block"; | |
5962 $("download").style.display = "block"; | |
5963 $("outpop_close").focus(); | |
5964 } | |
5965 | |
5966 function action_hide_outpop(e) { | |
5967 if (!e) e = window.event; | |
5968 if (e.type === "keydown") { | |
5969 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
5970 return; | |
5971 } | |
5972 // stop a submit or something like that | |
5973 e.preventDefault(); | |
5974 } | |
5975 $("download").style.display = "none"; | |
5976 $("grey_out_page").style.display = "none"; | |
5977 if (typeof action_hide_outpop.last_active !== "undefined") { | |
5978 action_hide_outpop.last_active.focus(); | |
5979 } | |
5980 } | |
5981 | |
5982 function action_outpop_next(e) { | |
5983 if (!e) e = window.event; | |
5984 if (e.type === "keydown") { | |
5985 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
5986 return; | |
5987 } | |
5988 // stop a submit or something like that | |
5989 e.preventDefault(); | |
5990 } | |
5991 update_outpop_motif(current_motif + 1); | |
5992 } | |
5993 | |
5994 function action_outpop_prev(e) { | |
5995 if (!e) e = window.event; | |
5996 if (e.type === "keydown") { | |
5997 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
5998 return; | |
5999 } | |
6000 // stop a submit or something like that | |
6001 e.preventDefault(); | |
6002 } | |
6003 update_outpop_motif(current_motif - 1); | |
6004 } | |
6005 | |
6006 function action_outpop_program() { | |
6007 "use strict"; | |
6008 var table, tr, rows, i; | |
6009 tr = find_parent_tag(this, "TR"); | |
6010 table = find_parent_tag(tr, "TABLE"); | |
6011 rows = table.querySelectorAll("tr"); | |
6012 for (i = 0; i < rows.length; i++) { | |
6013 toggle_class(rows[i], "selected", rows[i] === tr); | |
6014 } | |
6015 } | |
6016 | |
6017 function action_outpop_ssc() { | |
6018 "use strict"; | |
6019 $("logo_err").value = $("logo_ssc").value; | |
6020 } | |
6021 | |
6022 function action_outpop_submit(e) { | |
6023 "use strict"; | |
6024 var form, input, program, motifs; | |
6025 // find out which program is selected | |
6026 var radios, i; | |
6027 radios = document.getElementsByName("program"); | |
6028 program = "fimo"; // default to fimo, since it works with all alphabet types | |
6029 for (i = 0; i < radios.length; i++) { | |
6030 if (radios[i].checked) program = radios[i].value; | |
6031 } | |
6032 | |
6033 motifs = motif_minimal_meme(current_motif); | |
6034 form = document.createElement("form"); | |
6035 form.setAttribute("method", "post"); | |
6036 form.setAttribute("action", site_url + "/tools/" + program); | |
6037 | |
6038 input = document.createElement("input"); | |
6039 input.setAttribute("type", "hidden"); | |
6040 input.setAttribute("name", "motifs_embed"); | |
6041 input.setAttribute("value", motifs); | |
6042 form.appendChild(input); | |
6043 | |
6044 document.body.appendChild(form); | |
6045 form.submit(); | |
6046 document.body.removeChild(form); | |
6047 } | |
6048 | |
6049 function action_outpop_download_motif(e) { | |
6050 $("text_form").submit(); | |
6051 } | |
6052 | |
6053 function action_outpop_download_logo(e) { | |
6054 "use strict"; | |
6055 $("logo_motifs").value = motif_minimal_meme(current_motif); | |
6056 $("logo_form").submit(); | |
6057 } | |
6058 | |
6059 function action_btn_rc(e) { | |
6060 "use strict"; | |
6061 var node, tr, motif, box, logo_box, tab_st, tab_rc, rc; | |
6062 if (!e) e = window.event; | |
6063 if (e.type === "keydown") { | |
6064 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
6065 return; | |
6066 } | |
6067 // stop a submit or something like that | |
6068 e.preventDefault(); | |
6069 } | |
6070 node = this; | |
6071 do { | |
6072 if (node.tagName === "TR") break; | |
6073 } while (node = node.parentNode); | |
6074 if (!node) throw new Error("Expected to find row!?"); | |
6075 tr = node; | |
6076 // get info | |
6077 motif = tr.data_motif; | |
6078 box = find_parent(this, "preview_box"); | |
6079 logo_box = find_child(box, "preview_logo_box"); | |
6080 tab_st = find_child(box, "plus"); | |
6081 tab_rc = find_child(box, "minus"); | |
6082 rc = (this === tab_rc); | |
6083 motif["rc"] = rc; | |
6084 toggle_class(logo_box, "show_rc_logo", rc); | |
6085 toggle_class(tab_st, "active", !rc); | |
6086 toggle_class(tab_rc, "active", rc); | |
6087 } | |
6088 | |
6089 function action_rc_tab(e) { | |
6090 "use strict"; | |
6091 var box, logo_box, tab_st, tab_rc, rc; | |
6092 if (!e) e = window.event; | |
6093 if (e.type === "keydown") { | |
6094 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
6095 return; | |
6096 } | |
6097 // stop a submit or something like that | |
6098 e.preventDefault(); | |
6099 } | |
6100 box = find_parent(this, "expanded_motif"); | |
6101 logo_box = find_child(box, "tvar_logo"); | |
6102 tab_st = find_child(box, "tvar_tab"); | |
6103 tab_rc = find_child(box, "tvar_tab_rc"); | |
6104 rc = (this === tab_rc); | |
6105 box.data_motif["rc"] = rc; | |
6106 toggle_class(logo_box, "show_rc_logo", rc); | |
6107 toggle_class(tab_st, "activeTab", !rc); | |
6108 toggle_class(tab_rc, "activeTab", rc); | |
6109 } | |
6110 | |
6111 function action_outpop_tab(e) { | |
6112 "use strict"; | |
6113 var tab1, tab2, tab3, pnl1, pnl2, pnl3, do_btn; | |
6114 if (!e) e = window.event; | |
6115 if (e.type === "keydown") { | |
6116 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
6117 return; | |
6118 } | |
6119 // stop a submit or something like that | |
6120 e.preventDefault(); | |
6121 } | |
6122 tab1 = $("outpop_tab_1"); | |
6123 tab2 = $("outpop_tab_2"); | |
6124 tab3 = $("outpop_tab_3"); | |
6125 pnl1 = $("outpop_pnl_1"); | |
6126 pnl2 = $("outpop_pnl_2"); | |
6127 pnl3 = $("outpop_pnl_3"); | |
6128 do_btn = $("outpop_do"); | |
6129 | |
6130 toggle_class(tab1, "activeTab", (this === tab1)); | |
6131 toggle_class(tab2, "activeTab", (this === tab2)); | |
6132 toggle_class(tab3, "activeTab", (this === tab3)); | |
6133 pnl1.style.display = ((this === tab1) ? "block" : "none"); | |
6134 pnl2.style.display = ((this === tab2) ? "block" : "none"); | |
6135 pnl3.style.display = ((this === tab3) ? "block" : "none"); | |
6136 do_btn.value = ((this === tab1) ? "Submit" : "Download"); | |
6137 do_btn.removeEventListener("click", action_outpop_submit, false); | |
6138 do_btn.removeEventListener("click", action_outpop_download_logo, false); | |
6139 do_btn.removeEventListener("click", action_outpop_download_motif, false); | |
6140 if (this === tab1) { | |
6141 do_btn.addEventListener("click", action_outpop_submit, false); | |
6142 } else if (this === tab2) { | |
6143 do_btn.addEventListener("click", action_outpop_download_motif, false); | |
6144 } else { | |
6145 do_btn.addEventListener("click", action_outpop_download_logo, false); | |
6146 } | |
6147 } | |
6148 | |
6149 function action_seqs_filter() { | |
6150 "use strict"; | |
6151 var block_container; | |
6152 block_container = $("blocks"); | |
6153 if ($("rdo_all_seqs").checked) { | |
6154 toggle_class(block_container, "hide_empty_seqs", false); | |
6155 toggle_class(block_container, "hide_only_scan", false); | |
6156 } else if ($("rdo_sites_and_scan").checked) { | |
6157 toggle_class(block_container, "hide_empty_seqs", true); | |
6158 toggle_class(block_container, "hide_only_scan", false); | |
6159 } else if ($("rdo_sites_only").checked) { | |
6160 toggle_class(block_container, "hide_empty_seqs", true); | |
6161 toggle_class(block_container, "hide_only_scan", true); | |
6162 } | |
6163 } | |
6164 | |
6165 function action_outpop_format() { | |
6166 update_outpop_format(current_motif); | |
6167 } | |
6168 | |
6169 // | |
6170 // page_loaded | |
6171 // | |
6172 // Called when the page has loaded for the first time. | |
6173 /// | |
6174 function page_loaded() { | |
6175 post_load_setup(); | |
6176 } | |
6177 | |
6178 // | |
6179 // page_loaded | |
6180 // | |
6181 // Called when a cached page is reshown. | |
6182 /// | |
6183 function page_shown(e) { | |
6184 if (e.persisted) post_load_setup(); | |
6185 } | |
6186 | |
6187 // | |
6188 // page_loaded | |
6189 // | |
6190 // Called when the page is resized | |
6191 /// | |
6192 function page_resized() { | |
6193 var page, blocks_scroll; | |
6194 update_scroll_pad(); | |
6195 page = (document.compatMode === "CSS1Compat") ? document.documentElement : document.body; | |
6196 blocks_scroll = $("blocks_scroll"); | |
6197 if (blocks_scroll) { | |
6198 blocks_scroll.style.maxHeight = Math.max(page.clientHeight - 300, 300) + "px"; | |
6199 } | |
6200 } | |
6201 | |
6202 // | |
6203 // pre_load_setup | |
6204 // | |
6205 // Run before the page is displayed | |
6206 /// | |
6207 function pre_load_setup() { | |
6208 var start, hue, sat, light, divisions; | |
6209 var i, j, motifs, motif, sites, site, sequences, sequence; | |
6210 var max_seq_len; | |
6211 motifs = data["motifs"]; | |
6212 sequences = data["sequence_db"]["sequences"]; | |
6213 max_seq_len = 1; | |
6214 for (i = 0; i < sequences.length; i++) { | |
6215 sequence = sequences[i]; | |
6216 sequence["sites"] = []; | |
6217 if (sequence["length"] > max_seq_len) { | |
6218 max_seq_len = sequence["length"]; | |
6219 } | |
6220 } | |
6221 data["sequence_db"]["max_length"] = max_seq_len; | |
6222 // use hsl colours | |
6223 start = 0; //red | |
6224 sat = 100; | |
6225 light = 50; | |
6226 for (i = 0; i < motifs.length; i++) { | |
6227 motif = motifs[i]; | |
6228 // give the motif a colour | |
6229 divisions = 1 << Math.ceil(Math.log(i + 1) / Math.LN2); | |
6230 hue = start + (360 / divisions) * ((i - (divisions >> 1)) * 2 + 1); | |
6231 motif["colour"] = "hsl(" + hue + ", " + sat + "%, " + light + "%)"; | |
6232 // associate sites with sequences as well | |
6233 // to make generating the block diagram easier | |
6234 sites = motif["sites"]; | |
6235 for (j = 0; j < sites.length; j++) { | |
6236 site = sites[j]; | |
6237 sequence = sequences[site["seq"]]; | |
6238 // record the motif index | |
6239 site["motif"] = i; | |
6240 // add the site to the sequence | |
6241 sequence["sites"].push(site); | |
6242 } | |
6243 } | |
6244 } | |
6245 | |
6246 // | |
6247 // post_load_setup | |
6248 // | |
6249 // Run when the page has loaded, or been reloaded. | |
6250 // | |
6251 function post_load_setup() { | |
6252 update_scroll_pad(); | |
6253 if (data["motifs"].length > 0) { | |
6254 make_motifs(); | |
6255 make_blocks(); | |
6256 } else { | |
6257 $("motifs").innerHTML = "<p>No significant motifs found!</p>"; // clear content | |
6258 $("motifs").innerHTML += "<p><b>" + data["stop_reason"] + "</b></p>"; | |
6259 $("blocks").innerHTML = "<p>No significant motifs found!</p>"; | |
6260 } | |
6261 } | |
6262 | |
6263 pre_load_setup(); | |
6264 </script> | |
6265 <style> | |
6266 /* The following is the content of meme.css */ | |
6267 body { background-color:white; font-size: 12px; font-family: Verdana, Arial, Helvetica, sans-serif;} | |
6268 | |
6269 div.help { | |
6270 display: inline-block; | |
6271 margin: 0px; | |
6272 padding: 0px; | |
6273 width: 12px; | |
6274 height: 13px; | |
6275 cursor: pointer; | |
6276 background-image: url(data:image/gif;base64,R0lGODlhDAANAIABANR0AP///yH5BAEAAAEALAAAAAAMAA0AAAIdhI8Xy22MIFgv1DttrrJ7mlGNNo4c+aFg6SQuUAAAOw==); | |
6277 } | |
6278 | |
6279 div.help:hover { | |
6280 background-image: url(data:image/gif;base64,R0lGODlhDAANAKEAANR0AP///9R0ANR0ACH+EUNyZWF0ZWQgd2l0aCBHSU1QACH5BAEAAAIALAAAAAAMAA0AAAIdDGynCe3PgoxONntvwqz2/z2K2ImjR0KhmSIZUgAAOw==); | |
6281 } | |
6282 | |
6283 p.spaced { line-height: 1.8em;} | |
6284 | |
6285 span.citation { font-family: "Book Antiqua", "Palatino Linotype", serif; color: #004a4d;} | |
6286 | |
6287 p.pad { padding-left: 30px; padding-top: 5px; padding-bottom: 10px;} | |
6288 | |
6289 td.jump { font-size: 13px; color: #ffffff; background-color: #00666a; | |
6290 font-family: Georgia, "Times New Roman", Times, serif;} | |
6291 | |
6292 a.jump { margin: 15px 0 0; font-style: normal; font-variant: small-caps; | |
6293 font-weight: bolder; font-family: Georgia, "Times New Roman", Times, serif;} | |
6294 | |
6295 h2.mainh {font-size: 1.5em; font-style: normal; margin: 15px 0 0; | |
6296 font-variant: small-caps; font-family: Georgia, "Times New Roman", Times, serif;} | |
6297 | |
6298 h2.line {border-bottom: 1px solid #CCCCCC; font-size: 1.5em; font-style: normal; | |
6299 margin: 15px 0 0; padding-bottom: 3px; font-variant: small-caps; | |
6300 font-family: Georgia, "Times New Roman", Times, serif;} | |
6301 | |
6302 h4 {border-bottom: 1px solid #CCCCCC; font-size: 1.2em; font-style: normal; | |
6303 margin: 10px 0 0; padding-bottom: 3px; font-family: Georgia, "Times New Roman", Times, serif;} | |
6304 | |
6305 h5 {margin: 0px} | |
6306 | |
6307 a.help { font-size: 9px; font-style: normal; text-transform: uppercase; | |
6308 font-family: Georgia, "Times New Roman", Times, serif;} | |
6309 | |
6310 div.pad { padding-left: 30px; padding-top: 5px; padding-bottom: 10px;} | |
6311 | |
6312 div.pad1 { margin: 10px 5px;} | |
6313 | |
6314 div.pad2 { margin: 25px 5px 5px;} | |
6315 h2.pad2 { padding: 25px 5px 5px;} | |
6316 | |
6317 div.pad3 { padding: 5px 0px 10px 30px;} | |
6318 | |
6319 div.box { border: 2px solid #CCCCCC; padding:10px; overflow: hidden;} | |
6320 | |
6321 div.bar { border-left: 7px solid #00666a; padding:5px; margin-top:25px; } | |
6322 | |
6323 div.subsection {margin:25px 0px;} | |
6324 | |
6325 img {border:0px none;} | |
6326 | |
6327 th.majorth {text-align:left;} | |
6328 th.minorth {font-weight:normal; text-align:left; width:8em; padding: 3px 0px;} | |
6329 th.actionth {font-weight:normal; text-align:left;} | |
6330 | |
6331 .explain h5 {font-size:1em; margin-left: 1em;} | |
6332 | |
6333 div.doc {margin-left: 2em; margin-bottom: 3em;} | |
6334 | |
6335 th.trainingset { | |
6336 border-bottom: thin dashed black; | |
6337 font-weight:normal; | |
6338 padding:0px 10px; | |
6339 } | |
6340 div.pop_content { | |
6341 position:absolute; | |
6342 z-index:50; | |
6343 width:300px; | |
6344 padding: 5px; | |
6345 background: #E4ECEC; | |
6346 font-size: 12px; | |
6347 font-family: Arial; | |
6348 border-style: double; | |
6349 border-width: 3px; | |
6350 border-color: #AA2244; | |
6351 display:none; | |
6352 } | |
6353 | |
6354 div.pop_content > *:first-child { | |
6355 margin-top: 0px; | |
6356 } | |
6357 | |
6358 div.pop_content h1, div.pop_content h2, div.pop_content h3, div.pop_content h4, | |
6359 div.pop_content h5, div.pop_content h6, div.pop_content p { | |
6360 margin: 0px; | |
6361 } | |
6362 | |
6363 div.pop_content p + h1, div.pop_content p + h2, div.pop_content p + h3, | |
6364 div.pop_content p + h4, div.pop_content p + h5, div.pop_content p + h6 { | |
6365 margin-top: 5px; | |
6366 } | |
6367 | |
6368 div.pop_content p + p { | |
6369 margin-top: 5px; | |
6370 } | |
6371 | |
6372 div.pop_content > *:last-child { | |
6373 margin-bottom: 0px; | |
6374 } | |
6375 | |
6376 div.pop_content div.pop_close { | |
6377 /* old definition */ | |
6378 float:right; | |
6379 bottom: 0; | |
6380 } | |
6381 | |
6382 div.pop_content span.pop_close, div.pop_content span.pop_back { | |
6383 display: inline-block; | |
6384 border: 2px outset #661429; | |
6385 background-color: #CCC; | |
6386 padding-left: 1px; | |
6387 padding-right: 1px; | |
6388 padding-top: 0px; | |
6389 padding-bottom: 0px; | |
6390 cursor: pointer; | |
6391 color: #AA2244; /*#661429;*/ | |
6392 font-weight: bold; | |
6393 } | |
6394 | |
6395 div.pop_content span.pop_close:active, div.pop_content span.pop_back:active { | |
6396 border-style: inset; | |
6397 } | |
6398 | |
6399 div.pop_content span.pop_close { | |
6400 float:right; | |
6401 /*border: 2px outset #AA002B;*/ | |
6402 /*color: #AA2244;*/ | |
6403 } | |
6404 | |
6405 div.pop_content:not(.nested) .nested_only { | |
6406 display: none; | |
6407 } | |
6408 | |
6409 div.pop_back_sec { | |
6410 margin-bottom: 5px; | |
6411 } | |
6412 | |
6413 div.pop_close_sec { | |
6414 margin-top: 5px; | |
6415 } | |
6416 | |
6417 table.hide_advanced tr.advanced { | |
6418 display: none; | |
6419 } | |
6420 span.show_more { | |
6421 display: none; | |
6422 } | |
6423 table.hide_advanced span.show_more { | |
6424 display: inline; | |
6425 } | |
6426 table.hide_advanced span.show_less { | |
6427 display: none; | |
6428 } | |
6429 | |
6430 | |
6431 /***************************************************************************** | |
6432 * Program logo styling | |
6433 ****************************************************************************/ | |
6434 div.prog_logo { | |
6435 border-bottom: 0.25em solid #0f5f60; | |
6436 height: 4.5em; | |
6437 width: 24em; | |
6438 display:inline-block; | |
6439 } | |
6440 div.prog_logo img { | |
6441 float:left; | |
6442 width: 4em; | |
6443 border-style: none; | |
6444 margin-right: 0.2em; | |
6445 } | |
6446 div.prog_logo h1, div.prog_logo h1:hover, div.prog_logo h1:active, div.prog_logo h1:visited { | |
6447 margin:0; | |
6448 padding:0; | |
6449 font-family: Arial, Helvetica, sans-serif; | |
6450 font-size: 3.2em; | |
6451 line-height: 1em; | |
6452 vertical-align: top; | |
6453 display: block; | |
6454 color: #026666; | |
6455 letter-spacing: -0.06em; | |
6456 text-shadow: 0.04em 0.06em 0.05em #666; | |
6457 } | |
6458 div.prog_logo h2, div.prog_logo h2:hover, div.prog_logo h2:active, div.prog_logo h2:visited { | |
6459 display: block; | |
6460 margin:0; | |
6461 padding:0; | |
6462 font-family: Helvetica, sans-serif; | |
6463 font-size: 0.9em; | |
6464 line-height: 1em; | |
6465 letter-spacing: -0.06em; | |
6466 color: black; | |
6467 } | |
6468 | |
6469 div.big.prog_logo { | |
6470 font-size: 18px; | |
6471 } | |
6472 | |
6473 </style> | |
6474 <style> | |
6475 .block_td { | |
6476 height:25px; | |
6477 } | |
6478 .block_container { | |
6479 position:relative; | |
6480 box-sizing: border-box; | |
6481 height: 25px; | |
6482 padding: 0px; | |
6483 margin: 0px; | |
6484 margin-left: 1em; | |
6485 } | |
6486 .block_label { | |
6487 position: absolute; | |
6488 display: inline-block; | |
6489 padding: 3px; | |
6490 z-index: 4; | |
6491 top: 6px; | |
6492 height: 12px; | |
6493 line-height: 12px; | |
6494 font-size: 12px; | |
6495 background-color: white; | |
6496 border: 1px solid black; | |
6497 -moz-border-radius: 12px; | |
6498 -webkit-border-radius: 12px; | |
6499 border-radius: 12px; | |
6500 transform: translateX(-50%); | |
6501 } | |
6502 .block_motif { | |
6503 position: absolute; | |
6504 z-index: 3; | |
6505 top: 0px; | |
6506 box-sizing: border-box; | |
6507 border: 1px solid black; | |
6508 height: 12px; | |
6509 background-color: cyan; | |
6510 } | |
6511 .block_motif.top { | |
6512 border-bottom-width: 0; | |
6513 } | |
6514 .block_motif.bottom { | |
6515 border-top-width: 0; | |
6516 } | |
6517 .block_motif.scanned_site { | |
6518 opacity: 0.3; | |
6519 } | |
6520 .block_motif.scanned_site.active { | |
6521 opacity: 0.9; | |
6522 } | |
6523 .block_region { | |
6524 position:absolute; | |
6525 z-index:6; | |
6526 height:25px; | |
6527 top:0px; | |
6528 } | |
6529 .block_region.main { | |
6530 z-index:8; | |
6531 } | |
6532 .block_region.scanned_site { | |
6533 z-index:5; | |
6534 } | |
6535 .block_region.scanned_site.main { | |
6536 z-index:7; | |
6537 } | |
6538 .block_region.top { | |
6539 height:13px; | |
6540 } | |
6541 .block_region.bottom { | |
6542 height:13px; | |
6543 top:12px; | |
6544 } | |
6545 .block_rule { | |
6546 position:absolute; | |
6547 z-index:2; | |
6548 width:100%; | |
6549 height:1px; | |
6550 top:12px; | |
6551 left:0px; | |
6552 background-color:gray; | |
6553 } | |
6554 .block_plus_sym { | |
6555 position:absolute; | |
6556 z-index:4; | |
6557 line-height:12px; | |
6558 top:0px; | |
6559 left:-1em; | |
6560 } | |
6561 .block_minus_sym { | |
6562 position:absolute; | |
6563 z-index:4; | |
6564 line-height:12px; | |
6565 top:13px; | |
6566 left:-1em; | |
6567 } | |
6568 | |
6569 .tic_major { | |
6570 position:absolute; | |
6571 top:0em; | |
6572 height:0.5em; | |
6573 width: 2px; | |
6574 margin-left: -1px; | |
6575 background-color: blue; | |
6576 } | |
6577 .tic_minor { | |
6578 position:absolute; | |
6579 top:0em; | |
6580 height:0.2em; | |
6581 width: 1px; | |
6582 margin-left: -0.5px; | |
6583 background-color: blue; | |
6584 } | |
6585 .tic_label { | |
6586 position:absolute; | |
6587 display: inline-block; | |
6588 top:0.5em; | |
6589 height: 1em; | |
6590 color: blue; | |
6591 transform: translateX(-50%); | |
6592 } | |
6593 | |
6594 .block_needle { | |
6595 position:absolute; | |
6596 z-index:4; | |
6597 height:30px; | |
6598 width:1px; | |
6599 top:-2px; | |
6600 background-color:gray; | |
6601 } | |
6602 .block_needle.right { | |
6603 height: 60px; | |
6604 } | |
6605 .block_handle { | |
6606 position: absolute; | |
6607 display: inline-block; | |
6608 z-index: 5; | |
6609 top: 27px; | |
6610 min-width: 3ex; | |
6611 text-align: center; | |
6612 font-size: 12px; | |
6613 line-height: 12px; | |
6614 transform: translateX(-50%); | |
6615 background-color: LightGrey; | |
6616 border:3px outset grey; | |
6617 cursor: pointer; | |
6618 -webkit-user-select: none; /* Chrome/Safari */ | |
6619 -moz-user-select: none; /* Firefox */ | |
6620 -ms-user-select: none; /* IE10+ */ | |
6621 /* Rules below not implemented in browsers yet */ | |
6622 -o-user-select: none; | |
6623 user-select: none; | |
6624 } | |
6625 .block_handle.right { | |
6626 top: 47px; | |
6627 } | |
6628 | |
6629 .legend_container { | |
6630 text-align: right; | |
6631 } | |
6632 .legend_entry { | |
6633 display: inline-block; | |
6634 padding: 5px; | |
6635 } | |
6636 div.legend_swatch { | |
6637 box-sizing: border-box; | |
6638 width: 15px; | |
6639 height: 15px; | |
6640 border: 1px solid black; | |
6641 background-color: cyan; | |
6642 float: left; | |
6643 } | |
6644 div.legend_swatch input { | |
6645 display: none; | |
6646 } | |
6647 .legend_text { | |
6648 line-height: 15px; | |
6649 margin-left: 20px; | |
6650 } | |
6651 </style> | |
6652 <style> | |
6653 /* meme output specific css */ | |
6654 | |
6655 div.pop_block { | |
6656 position:absolute; | |
6657 z-index:5; | |
6658 padding: 5px; | |
6659 border: 1px solid black; | |
6660 display: inline-block; | |
6661 background-color: white; | |
6662 } | |
6663 | |
6664 #measure_match { | |
6665 position: absolute; | |
6666 visibility: hidden; | |
6667 height: auto; | |
6668 width: auto; | |
6669 white-space: nowrap; | |
6670 } | |
6671 | |
6672 div.template { | |
6673 position: absolute; | |
6674 z-index: 1; | |
6675 left: 0; | |
6676 top: 0; | |
6677 visibility: hidden; | |
6678 } | |
6679 | |
6680 table.block_information { | |
6681 margin-left: auto; | |
6682 margin-right: auto; | |
6683 } | |
6684 | |
6685 table.block_information * th { | |
6686 text-align: right; | |
6687 } | |
6688 | |
6689 *.hide_empty_seqs * tr.empty_seq { | |
6690 display: none; | |
6691 } | |
6692 | |
6693 *.hide_only_scan * tr.only_scan { | |
6694 display: none; | |
6695 } | |
6696 | |
6697 *.hide_only_scan * div.scanned_site { | |
6698 display: none; | |
6699 } | |
6700 | |
6701 td.symaction { | |
6702 text-align: center; | |
6703 text-decoration: underline; | |
6704 font-size: 20px; | |
6705 cursor: pointer; | |
6706 } | |
6707 div.sym_btn { | |
6708 display:inline-block; | |
6709 text-decoration: underline; | |
6710 cursor: pointer; | |
6711 font-size: 20px; | |
6712 line-height:20px; | |
6713 text-align: center; | |
6714 width: 20px; | |
6715 height: 20px; | |
6716 color: blue; | |
6717 } | |
6718 div.sym_btn:hover { | |
6719 color: white; | |
6720 background-color: blue; | |
6721 } | |
6722 | |
6723 div.sym_btn.positioned { | |
6724 position: absolute; | |
6725 top: 0px; | |
6726 } | |
6727 | |
6728 div.actionbutton { | |
6729 display:inline-block; | |
6730 cursor: pointer; | |
6731 font-size: 18px; | |
6732 line-height:20px; | |
6733 padding: 5px; | |
6734 margin: 10px 0; | |
6735 border: 1px solid black; | |
6736 } | |
6737 | |
6738 div.actionbutton:hover { | |
6739 color:#FFF; | |
6740 background-color:#000; | |
6741 } | |
6742 | |
6743 div.param_box { | |
6744 display: inline-block; | |
6745 margin-right: 20px; | |
6746 } | |
6747 | |
6748 span.param { | |
6749 font-weight: bold; | |
6750 } | |
6751 | |
6752 div.box + div.box { | |
6753 margin-top: 5px; | |
6754 } | |
6755 | |
6756 div.sites_outer { | |
6757 position: relative; | |
6758 padding-top: 20px; /* height of header */ | |
6759 display: inline-block; | |
6760 } | |
6761 | |
6762 div.sites_inner { | |
6763 overflow-x: hidden; | |
6764 overflow-y: auto; | |
6765 max-height: 200px; | |
6766 } | |
6767 table.sites_tbl { | |
6768 border-collapse: collapse; | |
6769 } | |
6770 | |
6771 div.sites_th_inner { | |
6772 position: absolute; | |
6773 top: 0; | |
6774 line-height: 20px; /* height of header */ | |
6775 text-align: left; | |
6776 padding-left: 5px; | |
6777 } | |
6778 th.nopad div.sites_th_inner { | |
6779 padding-left: 0; | |
6780 } | |
6781 div.sites_th_hidden { | |
6782 visibility: hidden; | |
6783 height: 0; | |
6784 padding: 0 10px; | |
6785 } | |
6786 th.nopad div.sites_th_hidden { | |
6787 padding: 0; | |
6788 } | |
6789 div.sites_inner * th { | |
6790 height: 0; | |
6791 } | |
6792 | |
6793 table.sites_tbl { | |
6794 overflow-x: hidden; | |
6795 overflow-y: auto; | |
6796 } | |
6797 | |
6798 .site_num { | |
6799 text-align: right; | |
6800 } | |
6801 .site_name { | |
6802 padding:0px 5px; | |
6803 text-align:left; | |
6804 } | |
6805 .site_strand { | |
6806 padding:0px 5px; | |
6807 text-align:center; | |
6808 } | |
6809 .norc .site_strand, .norc .site_strand_title { | |
6810 display: none; | |
6811 } | |
6812 .site_start { | |
6813 padding:0px 15px; | |
6814 text-align: right; | |
6815 } | |
6816 .site_pvalue { | |
6817 text-align:center; | |
6818 padding:0px 15px; | |
6819 text-align:right; | |
6820 white-space: nowrap; | |
6821 } | |
6822 .lflank, .rflank, .match, .alpha_symbol { | |
6823 font-weight:bold; | |
6824 font-size:15px; | |
6825 font-family: 'Courier New', Courier, monospace; | |
6826 color:gray; | |
6827 } | |
6828 | |
6829 .site.lflank { | |
6830 text-align:right; | |
6831 padding-right:5px; | |
6832 color:gray; | |
6833 } | |
6834 .site.match { | |
6835 text-align:center; | |
6836 } | |
6837 .site.rflank { | |
6838 text-align:left; | |
6839 padding-left:5px; | |
6840 padding-right: 20px; | |
6841 } | |
6842 | |
6843 th.stop_reason { | |
6844 text-align: left; | |
6845 padding-right: 10px; | |
6846 } | |
6847 | |
6848 th.motif_ordinal { | |
6849 | |
6850 } | |
6851 td.motif_ordinal { | |
6852 text-align: right; | |
6853 padding-right: 10px; | |
6854 } | |
6855 th.motif_logo { | |
6856 padding-right: 10px; | |
6857 } | |
6858 td.motif_logo { | |
6859 padding-right: 10px; | |
6860 } | |
6861 th.motif_evalue { | |
6862 text-align:right; | |
6863 padding-right: 10px; | |
6864 } | |
6865 td.motif_evalue { | |
6866 text-align: right; | |
6867 white-space: nowrap; | |
6868 padding-right: 20px; | |
6869 } | |
6870 th.motif_nsites { | |
6871 text-align: right; | |
6872 padding-right: 10px; | |
6873 } | |
6874 td.motif_nsites { | |
6875 text-align: right; | |
6876 padding-right: 20px; | |
6877 } | |
6878 th.motif_width { | |
6879 text-align: right; | |
6880 padding-right: 5px; | |
6881 } | |
6882 td.motif_width { | |
6883 text-align: right; | |
6884 padding-right: 15px; | |
6885 } | |
6886 th.motif_more { | |
6887 padding: 0 5px; | |
6888 } | |
6889 td.motif_more { | |
6890 text-align: center; | |
6891 padding: 0 5px; | |
6892 } | |
6893 th.motif_submit { | |
6894 padding: 0 5px; | |
6895 } | |
6896 td.motif_submit { | |
6897 text-align: center; | |
6898 padding: 0 5px; | |
6899 } | |
6900 th.motif_download { | |
6901 padding-left: 5px; | |
6902 } | |
6903 td.motif_download { | |
6904 text-align: center; | |
6905 padding-left: 5px; | |
6906 } | |
6907 | |
6908 | |
6909 div.tabArea { | |
6910 font-size: 80%; | |
6911 font-weight: bold; | |
6912 } | |
6913 | |
6914 .norc div.tabArea { | |
6915 display: none; | |
6916 } | |
6917 | |
6918 span.tab, span.tab:visited { | |
6919 cursor: pointer; | |
6920 color: #888; | |
6921 background-color: #ddd; | |
6922 border: 2px solid #ccc; | |
6923 padding: 2px 1em; | |
6924 text-decoration: none; | |
6925 } | |
6926 span.tab.middle { | |
6927 border-left-width: 0px; | |
6928 } | |
6929 div.tabArea.base span.tab { | |
6930 border-top-width: 0px; | |
6931 } | |
6932 div.tabArea.top span.tab { | |
6933 border-bottom-width: 0px; | |
6934 } | |
6935 | |
6936 span.tab:hover { | |
6937 background-color: #bbb; | |
6938 border-color: #bbb; | |
6939 color: #666; | |
6940 } | |
6941 span.tab.activeTab, span.tab.activeTab:hover, span.tab.activeTab:visited { | |
6942 background-color: white; | |
6943 color: black; | |
6944 cursor: default; | |
6945 } | |
6946 div.tabMain { | |
6947 border: 2px solid #ccc; | |
6948 background-color: white; | |
6949 padding: 10px; | |
6950 } | |
6951 div.tabMain.base { | |
6952 margin-top: 5px; | |
6953 display: inline-block; | |
6954 max-width: 98%; | |
6955 } | |
6956 | |
6957 div.tabMain.top { | |
6958 margin-bottom: 5px; | |
6959 } | |
6960 | |
6961 div.tabCenter { | |
6962 max-width: 100%; | |
6963 overflow-x: auto; | |
6964 height: 200px; | |
6965 overflow-y: hidden; | |
6966 } | |
6967 | |
6968 canvas.logo_rc { | |
6969 display:none; | |
6970 } | |
6971 .show_rc_logo > canvas { | |
6972 display: none; | |
6973 } | |
6974 .show_rc_logo > canvas.logo_rc { | |
6975 display: block; | |
6976 } | |
6977 | |
6978 canvas.scan_logo { | |
6979 margin-left: 10px; | |
6980 } | |
6981 | |
6982 div.blocks_outer { | |
6983 position: relative; | |
6984 padding-top: 20px; /* height of header */ | |
6985 } | |
6986 | |
6987 div.blocks_inner { | |
6988 overflow-x: hidden; | |
6989 overflow-y: auto; | |
6990 max-height: 200px; | |
6991 } | |
6992 table.blocks_tbl { | |
6993 border-collapse: collapse; | |
6994 width: 100%; | |
6995 } | |
6996 | |
6997 div.blocks_th_inner { | |
6998 position: absolute; | |
6999 top: 0; | |
7000 line-height: 20px; /* height of header */ | |
7001 text-align: left; | |
7002 padding-left: 5px; | |
7003 } | |
7004 th.nopad div.blocks_th_inner { | |
7005 padding-left: 0; | |
7006 } | |
7007 div.blocks_th_hidden { | |
7008 visibility: hidden; | |
7009 height: 0; | |
7010 padding: 0 10px; | |
7011 } | |
7012 th.nopad div.blocks_th_hidden { | |
7013 padding: 0; | |
7014 } | |
7015 div.blocks_inner * th { | |
7016 height: 0; | |
7017 } | |
7018 | |
7019 table.blocks_tbl { | |
7020 overflow-x: hidden; | |
7021 overflow-y: auto; | |
7022 } | |
7023 td.block_td { | |
7024 width: 99%; | |
7025 } | |
7026 | |
7027 *.blockdiag_num { | |
7028 text-align: right; | |
7029 } | |
7030 | |
7031 td.blockdiag_name { | |
7032 text-align: left; | |
7033 padding:0px 10px; | |
7034 } | |
7035 | |
7036 td.blockdiag_pvalue { | |
7037 padding:0px 10px; | |
7038 text-align:right; | |
7039 white-space: nowrap; | |
7040 } | |
7041 | |
7042 div.preview_btn { | |
7043 border: 2px solid white; | |
7044 height: 16px; | |
7045 width: 16px; | |
7046 font-size: 12px; | |
7047 line-height: 16px; | |
7048 text-align: center; | |
7049 cursor: pointer; | |
7050 } | |
7051 div.preview_btn + div.preview_btn { | |
7052 margin-top: 3px; | |
7053 } | |
7054 | |
7055 div.preview_btn.active { | |
7056 border: 2px solid black; | |
7057 cursor: default; | |
7058 } | |
7059 | |
7060 div.preview_btn:hover { | |
7061 background-color: black; | |
7062 color: white; | |
7063 border-color: black; | |
7064 } | |
7065 | |
7066 div.preview_btn.active:hover { | |
7067 background-color: white; | |
7068 color: black; | |
7069 border-color: black; | |
7070 } | |
7071 | |
7072 | |
7073 div.preview_btn_box { | |
7074 position: absolute; | |
7075 left: 0px; | |
7076 top: 0px; | |
7077 padding: 3px; | |
7078 } | |
7079 | |
7080 div.preview_logo_box { | |
7081 height: 50px; | |
7082 overflow-y: hidden; | |
7083 } | |
7084 | |
7085 div.preview_btn_box + div.preview_logo_box { | |
7086 margin-left: 25px; | |
7087 } | |
7088 | |
7089 div.preview_box { | |
7090 position: relative; | |
7091 } | |
7092 | |
7093 div.grey_background { | |
7094 position:fixed; | |
7095 z-index: 8; | |
7096 background-color: #000; | |
7097 -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; | |
7098 opacity: 0.5; | |
7099 left: 0; | |
7100 top: 0; | |
7101 width: 100%; | |
7102 height: 100%; | |
7103 } | |
7104 | |
7105 div.popup_wrapper { | |
7106 position:fixed; | |
7107 z-index:9; | |
7108 width:100%; | |
7109 height:0; | |
7110 top:50%; | |
7111 left:0; | |
7112 } | |
7113 | |
7114 div.popup { | |
7115 width: 600px; | |
7116 z-index:9; | |
7117 margin-left: auto; | |
7118 margin-right: auto; | |
7119 padding: 5px; | |
7120 background-color: #FFF; | |
7121 border-style: double; | |
7122 border-width: 5px; | |
7123 border-color: #00666a; | |
7124 position:relative; | |
7125 } | |
7126 div.close { | |
7127 cursor: pointer; | |
7128 border: 1px solid black; | |
7129 width:15px; | |
7130 height:15px; | |
7131 line-height:15px; /* this causes vertical centering */ | |
7132 text-align:center; | |
7133 background-color:#FFF; | |
7134 color:#000; | |
7135 font-size:15px; | |
7136 font-family:monospace; | |
7137 } | |
7138 | |
7139 div.close:hover { | |
7140 color:#FFF; | |
7141 background-color:#000; | |
7142 } | |
7143 | |
7144 div.navnum { | |
7145 width:100%; | |
7146 height:20px; | |
7147 line-height:20px; | |
7148 text-align:center; | |
7149 font-size:medium; | |
7150 } | |
7151 | |
7152 div.navarrow { | |
7153 font-size: 30px; | |
7154 text-decoration:none; | |
7155 cursor: pointer; | |
7156 -moz-user-select: none; | |
7157 -webkit-user-select: none; | |
7158 -ms-user-select: none; | |
7159 } | |
7160 | |
7161 div.navarrow > span.inactive { | |
7162 display: inline; | |
7163 } | |
7164 div.navarrow > span.active { | |
7165 display: none; | |
7166 } | |
7167 | |
7168 div.navarrow:hover > span.active { | |
7169 display: inline; | |
7170 } | |
7171 div.navarrow:hover > span.inactive { | |
7172 display: none; | |
7173 } | |
7174 | |
7175 table.programs { | |
7176 width: 100%; | |
7177 } | |
7178 | |
7179 table.programs tr { | |
7180 background-color: #EFE; | |
7181 } | |
7182 | |
7183 table.programs tr.selected { | |
7184 background-color: #262; | |
7185 color: #FFF; | |
7186 } | |
7187 | |
7188 table.programs tr.dna_only { | |
7189 display: none; | |
7190 } | |
7191 | |
7192 table.programs.alphabet_dna tr.dna_only { | |
7193 display: table-row; | |
7194 } | |
7195 | |
7196 div.programs_scroll { | |
7197 width: 100%; | |
7198 height: 90px; | |
7199 overflow-y: auto; | |
7200 overflow-x: hidden; | |
7201 margin: 0 auto; | |
7202 } | |
7203 table.inputs, table.alpha_bg_table { | |
7204 margin-top: 20px; | |
7205 border-collapse:collapse; | |
7206 } | |
7207 table.inputs * td, table.inputs * th, table.alpha_bg_table * td, table.alpha_bg_table * th { | |
7208 padding-left: 15px; | |
7209 padding-right: 15px; | |
7210 padding-top: 1px; | |
7211 padding-bottom: 1px; | |
7212 } | |
7213 | |
7214 table.hide_psp td.col_psp, table.hide_psp th.col_psp { | |
7215 display: none; | |
7216 } | |
7217 | |
7218 /* program settings */ | |
7219 span.mod_oops, span.mod_zoops, span.mod_anr { | |
7220 display: none; | |
7221 } | |
7222 td.oops span.mod_oops,td.zoops span.mod_zoops, td.anr span.mod_anr { | |
7223 display: inline; | |
7224 } | |
7225 span.strand_none, span.strand_given, span.strand_both { | |
7226 display: none; | |
7227 } | |
7228 td.none span.strand_none, td.given span.strand_given, td.both span.strand_both { | |
7229 display: inline; | |
7230 } | |
7231 span.spmap_uni, span.spmap_pam { | |
7232 display: none; | |
7233 } | |
7234 td.uni span.spmap_uni, td.pam span.spmap_pam { | |
7235 display: inline; | |
7236 } | |
7237 span.prior_dirichlet, span.prior_dmix, span.prior_mega, span.prior_megap, span.prior_addone { | |
7238 display: none; | |
7239 } | |
7240 td.dirichlet span.prior_dirichlet, td.dmix span.prior_dmix, td.mega span.prior_mega, | |
7241 td.megap span.prior_megap, td.addone span.prior_addone { | |
7242 display: inline; | |
7243 } | |
7244 span.noendgaps_on, span.noendgaps_off { | |
7245 display: none; | |
7246 } | |
7247 td.on span.noendgaps_on, td.off span.noendgaps_off { | |
7248 display: inline; | |
7249 } | |
7250 span.substring_on, span.substring_off { | |
7251 display: none; | |
7252 } | |
7253 td.on span.substring_on, td.off span.substring_off { | |
7254 display: inline; | |
7255 } | |
7256 </style> | |
7257 </head> | |
7258 <body onload="page_loaded()" onpageshow="page_shown(event)" onresize="page_resized()"> | |
7259 <!-- --> | |
7260 <div id="grey_out_page" class="grey_background" style="display:none;"> | |
7261 </div> | |
7262 <!-- Help popups --> | |
7263 <div class="pop_content" id="pop_"> | |
7264 <p>Help poup.</p> | |
7265 <div style="float:right; bottom:0px;">[ | |
7266 <a href="javascript:help_popup()">close</a> ]</div> | |
7267 </div> | |
7268 <div class="pop_content" id="pop_ev"> | |
7269 <p>The statistical significance of the motif. MEME usually finds the most | |
7270 statistically significant (low E-value) motifs first. It is unusual to | |
7271 consider a motif with an E-value larger than 0.05 significant so, as an | |
7272 additional indicator, MEME displays these partially transparent.</p> | |
7273 <p>The E-value of a motif is based on its log likelihood ratio, width, | |
7274 sites, the background letter frequencies (given in the command line | |
7275 summary), and the size of the training set.</p> | |
7276 <p>The E-value is an estimate of the expected number of motifs with the | |
7277 given log likelihood ratio (or higher), and with the same width and site | |
7278 count, that one would find in a similarly sized set of random | |
7279 sequences (sequences where each position is independent and letters are | |
7280 chosen according to the background letter frequencies).</p> | |
7281 <div style="float:right; bottom:0px;">[ | |
7282 <a href="javascript:help_popup()">close</a> ]</div> | |
7283 </div> | |
7284 <div class="pop_content" id="pop_sites"> | |
7285 <p>The number of sites contributing to the construction of the motif.</p> | |
7286 <div style="float:right; bottom:0px;">[ | |
7287 <a href="javascript:help_popup()">close</a> ]</div> | |
7288 </div> | |
7289 <div class="pop_content" id="pop_width"> | |
7290 <p>The width of the motif. Each motif describes a pattern of a fixed | |
7291 width, as no gaps are allowed in MEME motifs.</p> | |
7292 <div style="float:right; bottom:0px;">[ | |
7293 <a href="javascript:help_popup()">close</a> ]</div> | |
7294 </div> | |
7295 <div class="pop_content" id="pop_more"> | |
7296 <p>Click on the blue symbol below to reveal more information about this motif.</p> | |
7297 <div style="float:right; bottom:0px;">[ | |
7298 <a href="javascript:help_popup()">close</a> ]</div> | |
7299 </div> | |
7300 <div class="pop_content" id="pop_submit_dl"> | |
7301 <p>Click on the blue symbol below to reveal options allowing you | |
7302 to submit this motif to another MEME Suite motif analysis program, to download this | |
7303 motif in various text formats, or to download a sequence "logo" of | |
7304 this motif PNG or EPS format.</p> | |
7305 <h5>Supported Programs</h5> | |
7306 <dl> | |
7307 <dt>Tomtom</dt> | |
7308 <dd>Tomtom is a tool for searching for similar known motifs. | |
7309 [<a href="http://meme-suite.org/doc/tomtom.html?man_type=web">manual</a>]</dd> | |
7310 <dt>MAST</dt> | |
7311 <dd>MAST is a tool for searching biological sequence databases for | |
7312 sequences that contain one or more of a group of known motifs. | |
7313 [<a href="http://meme-suite.org/doc/mast.html?man_type=web">manual</a>]</dd> | |
7314 <dt>FIMO</dt> | |
7315 <dd>FIMO is a tool for searching biological sequence databases for | |
7316 sequences that contain one or more known motifs. | |
7317 [<a href="http://meme-suite.org/doc/fimo.html?man_type=web">manual</a>]</dd> | |
7318 <dt>GOMO</dt> | |
7319 <dd>GOMO is a tool for identifying possible roles (Gene Ontology | |
7320 terms) for DNA binding motifs. | |
7321 [<a href="http://meme-suite.org/doc/gomo.html?man_type=web">manual</a>]</dd> | |
7322 <dt>SpaMo</dt> | |
7323 <dd>SpaMo is a tool for inferring possible transcription factor | |
7324 complexes by finding motifs with enriched spacings. | |
7325 [<a href="http://meme-suite.org/doc/spamo.html?man_type=web">manual</a>]</dd> | |
7326 </dl> | |
7327 <div style="float:right; bottom:0px;">[ | |
7328 <a href="javascript:help_popup()">close</a> ]</div> | |
7329 </div> | |
7330 <div class="pop_content" id="pop_llr"> | |
7331 <p>The log likelihood ratio of the motif.The log likelihood ratio is the | |
7332 logarithm of the ratio of the probability of the occurrences of the motif | |
7333 given the motif model (likelihood given the motif) versus their | |
7334 probability given the background model (likelihood given the null model). | |
7335 (Normally the background model is a 0-order Markov model using the | |
7336 background letter frequencies, but higher order Markov models may be | |
7337 specified via the -bfile option to MEME.).</p> | |
7338 <div style="float:right; bottom:0px;">[ | |
7339 <a href="javascript:help_popup()">close</a> ]</div> | |
7340 </div> | |
7341 <div class="pop_content" id="pop_ic"> | |
7342 <p>The information content of the motif in bits. It is equal to the sum | |
7343 of the uncorrected information content, R(), in the columns of the pwm. | |
7344 This is equal relative entropy of the motif relative to a uniform | |
7345 background frequency model.</p> | |
7346 <div style="float:right; bottom:0px;">[ | |
7347 <a href="javascript:help_popup()">close</a> ]</div> | |
7348 </div> | |
7349 <div class="pop_content" id="pop_re"> | |
7350 <p>The relative entropy of the motif.</p> | |
7351 | |
7352 <p style="font-family: monospace;">re = llr / (sites * ln(2))</p> | |
7353 <div style="float:right; bottom:0px;">[ | |
7354 <a href="javascript:help_popup()">close</a> ]</div> | |
7355 </div> | |
7356 <div class="pop_content" id="pop_bt"> | |
7357 <p>The Bayes Threshold.</p> | |
7358 <div style="float:right; bottom:0px;">[ | |
7359 <a href="javascript:help_popup()">close</a> ]</div> | |
7360 </div> | |
7361 <div class="pop_content" id="pop_site_strand"> | |
7362 <p>The strand used for the motif site.</p> | |
7363 <dl> | |
7364 <dt>+</dt> | |
7365 <dd>The motif site was found in the sequence as it was supplied.</dd> | |
7366 <dt>-</dt> | |
7367 <dd>The motif site was found in the reverse complement of the supplied sequence.</dd> | |
7368 </dl> | |
7369 <div style="float:right; bottom:0px;">[ | |
7370 <a href="javascript:help_popup()">close</a> ]</div> | |
7371 </div> | |
7372 <div class="pop_content" id="pop_site_start"> | |
7373 <p>The position in the sequence where the motif site starts. If a motif | |
7374 started right at the begining of a sequence it would be described as | |
7375 starting at position 1.</p> | |
7376 <div style="float:right; bottom:0px;">[ | |
7377 <a href="javascript:help_popup()">close</a> ]</div> | |
7378 </div> | |
7379 <div class="pop_content" id="pop_site_pvalue"> | |
7380 <p>The probability that an equal or better site would be found in a | |
7381 random sequence of the same length conforming to the background letter | |
7382 frequencies.</p> | |
7383 <div style="float:right; bottom:0px;">[ | |
7384 <a href="javascript:help_popup()">close</a> ]</div> | |
7385 </div> | |
7386 <div class="pop_content" id="pop_site_match"> | |
7387 <p>A motif site with the 10 flanking letters on either side.</p> | |
7388 <p>When the site is not on the given strand then the site | |
7389 and both flanks are reverse complemented so they align.</p> | |
7390 <div style="float:right; bottom:0px;">[ | |
7391 <a href="javascript:help_popup()">close</a> ]</div> | |
7392 </div> | |
7393 | |
7394 <div class="pop_content" id="pop_seq_name"> | |
7395 <p>The name of the sequences as given in the FASTA file.</p> | |
7396 <p>The number to the left of the sequence name is the ordinal | |
7397 of the sequence.</p> | |
7398 <div style="float:right; bottom:0px;">[ | |
7399 <a href="javascript:help_popup()">close</a> ]</div> | |
7400 </div> | |
7401 | |
7402 <div class="pop_content" id="pop_motif_sites"> | |
7403 <p>These are the motif sites predicted by MEME and used to build the motif.</p> | |
7404 <p>These sites are shown in solid color and hovering the cursor | |
7405 over a site will reveal details about the site. Only sequences | |
7406 that contain a motif site are shown.</p> | |
7407 <div style="float:right; bottom:0px;">[ | |
7408 <a href="javascript:help_popup()">close</a> ]</div> | |
7409 </div> | |
7410 | |
7411 <div class="pop_content" id="pop_scanned_sites"> | |
7412 <p>These are the motif sites predicted by MEME plus | |
7413 any additional sites detected using a motif scanning | |
7414 algorithm.</p> | |
7415 <p>These MEME sites are shown in solid color and | |
7416 additional scanned sites are shown in transparent color. | |
7417 Hovering the cursor over a site will reveal details about the site. | |
7418 Only sequences containing a predicted or scanned motif site are shown.</p> | |
7419 <p>The scanned sites are predicted using a | |
7420 log-odds scoring matrix constructed from the MEME sites. | |
7421 Only scanned sites with position <i>p</i>-values less | |
7422 than 0.0001 are shown.</p> | |
7423 <div style="float:right; bottom:0px;">[ | |
7424 <a href="javascript:help_popup()">close</a> ]</div> | |
7425 </div> | |
7426 | |
7427 <div class="pop_content" id="pop_all_sequences"> | |
7428 <p>These are the same sites as shown by selecting the | |
7429 "Motif Sites + Scanned Sites" button except that all | |
7430 sequences, including those with no sites, are included | |
7431 in the diagram.</p> | |
7432 <div style="float:right; bottom:0px;">[ | |
7433 <a href="javascript:help_popup()">close</a> ]</div> | |
7434 </div> | |
7435 | |
7436 <div class="pop_content" id="pop_seq_pvalue"> | |
7437 <p>This is the combined match <i>p</i>-value.</p> | |
7438 <p>The combined match <i>p</i>-value is defined as the probability that a | |
7439 random sequence (with the same length and conforming to the background) | |
7440 would have position <i>p</i>-values such that the product is smaller | |
7441 or equal to the value calulated for the sequence under test.</p> | |
7442 <p>The position <i>p</i>-value is defined as the probability that a | |
7443 random sequence (with the same length and conforming to the background) | |
7444 would have a match to the motif under test with a score greater or equal | |
7445 to the largest found in the sequence under test.</p> | |
7446 <p>Hovering your mouse over a motif site in the motif location | |
7447 block diagram will show its position <i>p</i>-value and other information | |
7448 about the site.</p> | |
7449 | |
7450 <div style="float:right; bottom:0px;">[ | |
7451 <a href="javascript:help_popup()">close</a> ]</div> | |
7452 </div> | |
7453 <div class="pop_content" id="pop_motif_location"> | |
7454 <p>This diagram shows the location of motif sites.</p> | |
7455 <p>Each block shows the position and strength of a motif | |
7456 site. The height of a block gives an indication of the | |
7457 significance of the site as taller blocks are more significant. | |
7458 The height is calculated to be proportional to the negative | |
7459 logarithm of the <i>p</i>-value of the site, truncated at | |
7460 the height for a <i>p</i>-value of 1e-10.</p> | |
7461 <p>For complementable alphabets (like DNA), sites on the | |
7462 positive strand are shown above the line, | |
7463 sites on the negative strand are shown below.</p> | |
7464 <p>Placing the cursor | |
7465 over a motif site will reveal more information about the site | |
7466 including its position <i>p</i>-value. (See the help | |
7467 for the <i>p</i>-value column for an explanation of position | |
7468 <i>p</i>-values.)</p> | |
7469 <div style="float:right; bottom:0px;">[ | |
7470 <a href="javascript:help_popup()">close</a> ]</div> | |
7471 </div> | |
7472 | |
7473 <div class="pop_content" id="pop_seq_source"> | |
7474 <p>The name of the file of sequences input to MEME.</p> | |
7475 <div style="float:right; bottom:0px;">[ | |
7476 <a href="javascript:help_popup()">close</a> ]</div> | |
7477 </div> | |
7478 <div class="pop_content" id="pop_psp_source"> | |
7479 <p>The position specific priors file used by MEME to find the motifs.</p> | |
7480 <div style="float:right; bottom:0px;">[ | |
7481 <a href="javascript:help_popup()">close</a> ]</div> | |
7482 </div> | |
7483 <div class="pop_content" id="pop_seq_alph"> | |
7484 <p>The alphabet used by the sequences.</p> | |
7485 <div style="float:right; bottom:0px;">[ | |
7486 <a href="javascript:help_popup()">close</a> ]</div> | |
7487 </div> | |
7488 <div class="pop_content" id="pop_seq_count"> | |
7489 <p>The number of sequences provided as input to MEME.</p> | |
7490 <div style="float:right; bottom:0px;">[ | |
7491 <a href="javascript:help_popup()">close</a> ]</div> | |
7492 </div> | |
7493 | |
7494 <div class="pop_content" id="pop_alph_name"> | |
7495 <p>The name of the alphabet symbol.</p> | |
7496 <div style="float:right; bottom:0px;">[ | |
7497 <a href="javascript:help_popup()">close</a> ]</div> | |
7498 </div> | |
7499 <div class="pop_content" id="pop_alph_freq"> | |
7500 <p>The frequency of the alphabet symbol in the dataset with a pseudocount | |
7501 so it is never zero.</p> | |
7502 <div style="float:right; bottom:0px;">[ | |
7503 <a href="javascript:help_popup()">close</a> ]</div> | |
7504 </div> | |
7505 <div class="pop_content" id="pop_alph_bg"> | |
7506 <p>The frequency of the alphabet symbol as defined by the background model.</p> | |
7507 <div style="float:right; bottom:0px;">[ | |
7508 <a href="javascript:help_popup()">close</a> ]</div> | |
7509 </div> | |
7510 | |
7511 <!-- templates --> | |
7512 <div id="measure_match" class="match"></div> | |
7513 <div class="template pop_block" id="tmpl_block_info"> | |
7514 <div> | |
7515 <span class="tvar_logo_pad lflank" style="visibility:hidden;"></span> | |
7516 <span class="tvar_logo"></span> | |
7517 </div> | |
7518 <div class="block_sequence_fragment"> | |
7519 <span class="tvar_lflank lflank"></span> | |
7520 <span class="tvar_match match"></span> | |
7521 <span class="tvar_rflank rflank"></span> | |
7522 </div> | |
7523 <table class="block_information"> | |
7524 <tr><th>Motif</th><td class="tvar_motif">1</td></tr> | |
7525 <tr><th><i>p</i>-value</th><td class="tvar_pvalue">8.23e-7</td></tr> | |
7526 <tr><th>Start</th><td class="tvar_start">23</td></tr> | |
7527 <tr><th>End</th><td class="tvar_end">33</td></tr> | |
7528 </table> | |
7529 </div> | |
7530 | |
7531 <div class="template pop_block" id="tmpl_scan_info"> | |
7532 <h5>Scanned Site</h5> | |
7533 <div class="tvar_logo"></div> | |
7534 <table class="block_information"> | |
7535 <tr><th>Motif</th><td class="tvar_motif">1</td></tr> | |
7536 <tr><th><i>p</i>-value</th><td class="tvar_pvalue">8.23e-7</td></tr> | |
7537 <tr><th>Start</th><td class="tvar_start">23</td></tr> | |
7538 <tr><th>End</th><td class="tvar_end">33</td></tr> | |
7539 </table> | |
7540 </div> | |
7541 | |
7542 <div class="template box expanded_motif" id="tmpl_motif_expanded"> | |
7543 <div style="position: relative; min-height: 20px"> | |
7544 <div class="param_box"> | |
7545 <span class="param"><span class="tvar_ordinal"></span>.</span> | |
7546 </div> | |
7547 <div class="sym_btn positioned tvar_less" tabindex="0" | |
7548 title="Show less information.">↥</div> | |
7549 <div class="sym_btn positioned tvar_submit" tabindex="0" | |
7550 title="Submit the motif to another MEME Suite program or download it.">⇢</div> | |
7551 </div> | |
7552 <div> | |
7553 <div class="param_box"> | |
7554 <span class="param"><i>E</i>-value:</span> | |
7555 <span class="tvar_evalue"></span> | |
7556 <div class="help" data-topic="pop_ev"></div> | |
7557 </div> | |
7558 <div class="param_box"> | |
7559 <span class="param">Site Count:</span> | |
7560 <span class="tvar_site_count"></span> | |
7561 <div class="help" data-topic="pop_sites"></div> | |
7562 </div> | |
7563 <div class="param_box"> | |
7564 <span class="param">Width:</span> | |
7565 <span class="tvar_width"></span> | |
7566 <div class="help" data-topic="pop_width"></div> | |
7567 </div> | |
7568 </div> | |
7569 <div class="tabMain base"> | |
7570 <div class="tabCenter tvar_logo"></div> | |
7571 </div> | |
7572 <div class="tabArea base"> | |
7573 <span class="tvar_tab tab" tabindex="0">Standard</span><span | |
7574 class="tvar_tab_rc tab middle" tabindex="0">Reverse | |
7575 Complement</span> | |
7576 </div> | |
7577 <div style="padding: 10px 0"> | |
7578 <div class="param_box"> | |
7579 <span class="param">Log Likelihood Ratio:</span> | |
7580 <span class="tvar_llr"></span> | |
7581 <div class="help" data-topic="pop_llr"></div> | |
7582 </div> | |
7583 <div class="param_box"> | |
7584 <span class="param">Information Content:</span> | |
7585 <span class="tvar_ic"></span> | |
7586 <div class="help" data-topic="pop_ic"></div> | |
7587 </div> | |
7588 <div class="param_box"> | |
7589 <span class="param">Relative Entropy:</span> | |
7590 <span class="tvar_re"></span> | |
7591 <div class="help" data-topic="pop_re"></div> | |
7592 </div> | |
7593 <div class="param_box"> | |
7594 <span class="param">Bayes Threshold:</span> | |
7595 <span class="tvar_bt"></span> | |
7596 <div class="help" data-topic="pop_bt"></div> | |
7597 </div> | |
7598 </div> | |
7599 <div class="tvar_sites"></div> | |
7600 </div> | |
7601 | |
7602 | |
7603 <div class="popup_wrapper"> | |
7604 <div class="popup" style="display:none; top: -150px;" id="download"> | |
7605 <div> | |
7606 <div style="float:right; "> | |
7607 <div id="outpop_close" class="close" tabindex="0">x</div> | |
7608 </div> | |
7609 <h2 class="mainh" style="margin:0; padding:0;">Submit or Download</h2> | |
7610 <div style="clear:both"></div> | |
7611 </div> | |
7612 <div style="height:100px"> | |
7613 <div style="float:right; width: 30px;"> | |
7614 <div id="outpop_prev" class="navarrow" tabindex="0"> | |
7615 <span class="inactive">⇧</span><span class="active">⬆</span> | |
7616 </div> | |
7617 <div id="outpop_num" class="navnum"></div> | |
7618 <div id="outpop_next" class="navarrow" tabindex="0"> | |
7619 <span class="inactive">⇩</span><span class="active">⬇</span> | |
7620 </div> | |
7621 </div> | |
7622 <div id="logo_box" style="height: 100px; margin-right: 40px;"> | |
7623 <canvas id="outpop_logo" height="100" width="580"></canvas> | |
7624 <canvas id="outpop_logo_rc" class="logo_rc" height="100" width="580"></canvas> | |
7625 </div> | |
7626 </div> | |
7627 <div> | |
7628 <!-- tabs start --> | |
7629 <div class="tabArea top"> | |
7630 <span id="outpop_tab_1" class="tab">Submit Motif</span><span | |
7631 id="outpop_tab_2" class="tab middle">Download Motif</span><span | |
7632 id="outpop_tab_3" class="tab middle">Download Logo</span> | |
7633 </div> | |
7634 <div class="tabMain top"> | |
7635 <!-- Submit to another program --> | |
7636 <div id="outpop_pnl_1"> | |
7637 <h4 class="compact">Submit to program</h4> | |
7638 <table id="programs" class="programs"> | |
7639 <tr class="dna_only"> | |
7640 <td><input type="radio" name="program" value="tomtom" id="submit_tomtom"></td> | |
7641 <td><label for="submit_tomtom">Tomtom</label></td> | |
7642 <td><label for="submit_tomtom">Find similar motifs in | |
7643 published libraries or a library you supply.</label></td> | |
7644 </tr> | |
7645 <tr> | |
7646 <td><input type="radio" name="program" value="fimo" id="submit_fimo"></td> | |
7647 <td><label for="submit_fimo">FIMO</label></td> | |
7648 <td><label for="submit_fimo">Find motif occurrences in | |
7649 sequence data.</label></td> | |
7650 </tr> | |
7651 <tr> | |
7652 <td><input type="radio" name="program" value="mast" id="submit_mast"></td> | |
7653 <td><label for="submit_mast">MAST</label></td> | |
7654 <td><label for="submit_mast">Rank sequences by affinity to | |
7655 groups of motifs.</label></td> | |
7656 </tr> | |
7657 <tr class="dna_only"> | |
7658 <td><input type="radio" name="program" value="gomo" id="submit_gomo"></td> | |
7659 <td><label for="submit_gomo">GOMo</label></td> | |
7660 <td><label for="submit_gomo">Identify possible roles (Gene | |
7661 Ontology terms) for motifs.</label></td> | |
7662 </tr> | |
7663 <tr class="dna_only"> | |
7664 <td><input type="radio" name="program" value="spamo" id="submit_spamo"></td> | |
7665 <td><label for="submit_spamo">SpaMo</label></td> | |
7666 <td><label for="submit_spamo">Find other motifs that are | |
7667 enriched at specific close spacings which might imply the existance of a complex.</label></td> | |
7668 </tr> | |
7669 </table> | |
7670 </div> | |
7671 <!-- download text format --> | |
7672 <div id="outpop_pnl_2"> | |
7673 <div> | |
7674 <label for="text_format">Format:</label> | |
7675 <select id="text_format"> | |
7676 <option value="0">Count Matrix</option> | |
7677 <option value="1">Probability Matrix</option> | |
7678 <option value="2">Minimal MEME</option> | |
7679 <option value="3">FASTA</option> | |
7680 <option value="4">Raw</option> | |
7681 </select> | |
7682 </div> | |
7683 <form id="text_form" method="post" action=""> | |
7684 <script>$("text_form").action = site_url + "/utilities/save_generated_file";</script> | |
7685 <input type="hidden" id="text_name" name="name" value="motif.txt"> | |
7686 <input type="hidden" name="mime_type" value="text/plain"> | |
7687 <textarea id="outpop_text" name="content" | |
7688 style="width:99%; white-space: pre; word-wrap: normal; overflow-x: scroll;" | |
7689 rows="8" readonly="readonly" wrap="off"></textarea> | |
7690 </form> | |
7691 </div> | |
7692 <!-- download logo format --> | |
7693 <div id="outpop_pnl_3"> | |
7694 <form id="logo_form" method="post" action=""> | |
7695 <script>$("logo_form").action = site_url + "/utilities/generate_logo";</script> | |
7696 <input type="hidden" name="program" value="MEME"/> | |
7697 <input type="hidden" id="logo_motifs" name="motifs" value=""/> | |
7698 <table> | |
7699 <tr> | |
7700 <td><label for="logo_format">Format:</label></td> | |
7701 <td> | |
7702 <select id="logo_format" name="png"> | |
7703 <option value="1">PNG (for web)</option> | |
7704 <option value="0">EPS (for publication)</option> | |
7705 </select> | |
7706 </td> | |
7707 </tr> | |
7708 <tr> | |
7709 <td><label for="logo_rc">Orientation:</label></td> | |
7710 <td> | |
7711 <select id="logo_rc" name="rc1"> | |
7712 <option value="0">Normal</option> | |
7713 <option value="1" id="logo_rc_option">Reverse Complement</option> | |
7714 </select> | |
7715 </td> | |
7716 </tr> | |
7717 <tr> | |
7718 <td><label for="logo_ssc">Small Sample Correction:</label></td> | |
7719 <td> | |
7720 <input type="hidden" id="logo_err" name="errbars" value="0"/> | |
7721 <select id="logo_ssc" name="ssc"> | |
7722 <option value="0">Off</option> | |
7723 <option value="1">On</option> | |
7724 </select> | |
7725 </td> | |
7726 </tr> | |
7727 <tr> | |
7728 <td><label for="logo_width">Width:</label></td> | |
7729 <td> | |
7730 <input type="text" id="logo_width" size="4" placeholder="default" name="width"/> cm | |
7731 </td> | |
7732 </tr> | |
7733 <tr> | |
7734 <td><label for="logo_height">Height:</label></td> | |
7735 <td> | |
7736 <input type="text" id="logo_height" size="4" placeholder="default" name="height"/> cm | |
7737 </td> | |
7738 </tr> | |
7739 </table> | |
7740 </form> | |
7741 </div> | |
7742 <!-- Buttons --> | |
7743 <div> | |
7744 <div style="float:left;"> | |
7745 <input type="button" id="outpop_do" value="Submit" /> | |
7746 </div> | |
7747 <div style="float:right;"> | |
7748 <input id="outpop_cancel" type="button" value="Cancel" /> | |
7749 </div> | |
7750 <div style="clear:both;"></div> | |
7751 </div> | |
7752 </div> | |
7753 </div> | |
7754 </div> | |
7755 </div> | |
7756 | |
7757 | |
7758 | |
7759 <!-- Page starts here --> | |
7760 <div id="top" class="pad1"> | |
7761 <div class="prog_logo big"> | |
7762 <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"> | |
7763 <h1>MEME</h1> | |
7764 <h2>Multiple Em for Motif Elicitation</h2> | |
7765 </div> | |
7766 <p> | |
7767 For further information on how to interpret these results or to get a | |
7768 copy of the MEME software please access | |
7769 <a href="http://meme-suite.org/">http://meme-suite.org</a>. | |
7770 </p> | |
7771 <p>If you use MEME in your research, please cite the following paper:<br /> | |
7772 <span class="citation"> | |
7773 Timothy L. Bailey and Charles Elkan, | |
7774 "Fitting a mixture model by expectation maximization to discover motifs in biopolymers", | |
7775 <em>Proceedings of the Second International Conference on Intelligent Systems | |
7776 for Molecular Biology</em>, pp. 28-36, AAAI Press, Menlo Park, California, 1994. | |
7777 <a href="http://meme-suite.org/doc/ismb94.pdf">[pdf]</a> | |
7778 </span> | |
7779 </p> | |
7780 </div> | |
7781 <!-- navigation --> | |
7782 <div class="pad2"> | |
7783 <a class="jump" href="#motifs_sec">Discovered Motifs</a> | |
7784 | | |
7785 <a class="jump" href="#sites_sec">Motif Locations</a> | |
7786 | | |
7787 <a class="jump" href="#inputs_sec">Inputs & Settings</a> | |
7788 | | |
7789 <a class="jump" href="#info_sec">Program information</a> | |
7790 </div> | |
7791 <!-- alert the user when their browser is not up to the task --> | |
7792 <noscript><h1 style="color:red">Javascript is required to view these results!</h1></noscript> | |
7793 <h1 id="html5_warning" style="color:red; display:none;">Your browser does not support canvas!</h1> | |
7794 <script> | |
7795 if (!window.HTMLCanvasElement) $("html5_warning").style.display = "block"; | |
7796 </script> | |
7797 <h2 class="mainh pad2" id="motifs_sec">Discovered Motifs</h2> | |
7798 <div id="motifs" class="box"> | |
7799 <p>Please wait... Loading...</p> | |
7800 <p>If the page has fully loaded and this message does not disappear then an error may have occurred.</p> | |
7801 </div> | |
7802 <h2 class="mainh pad2" id="sites_sec">Motif Locations</h2> | |
7803 <div id="blocks" class="box"> | |
7804 <p>Please wait... Loading...</p> | |
7805 <p>If the page has fully loaded and this message does not disappear then an error may have occurred.</p> | |
7806 </div> | |
7807 <h2 class="mainh pad2" id="inputs_sec">Inputs & Settings</h2> | |
7808 <div class="box"> | |
7809 <h4>Sequences</h4> | |
7810 <table id="seq_info" class="inputs"> | |
7811 <tr><th>Source <div class="help" data-topic="pop_seq_source"></div></th> | |
7812 <th class="col_psp">PSP Source <div class="help" data-topic="pop_psp_source"></div></th> | |
7813 <th>Alphabet <div class="help" data-topic="pop_seq_alph"></div></th> | |
7814 <th>Sequence Count <div class="help" data-topic="pop_seq_count"></div></th> | |
7815 </tr> | |
7816 <tr> | |
7817 <td id="ins_seq_source"></td> | |
7818 <td id="ins_seq_psp" class="col_psp"></td> | |
7819 <td id="ins_seq_alphabet"></td> | |
7820 <td id="ins_seq_count"></td> | |
7821 </tr> | |
7822 </table> | |
7823 <script> | |
7824 { | |
7825 var db = data.sequence_db; | |
7826 $("ins_seq_source").innerHTML = db.source; | |
7827 $("ins_seq_alphabet").innerHTML = meme_alphabet.get_alphabet_name(); | |
7828 $("ins_seq_count").innerHTML = db.sequences.length; | |
7829 if (db.psp) { | |
7830 $("ins_seq_psp").innerHTML = db.psp; | |
7831 } | |
7832 toggle_class($("seq_info"), "hide_psp", !(db.psp)); | |
7833 } | |
7834 </script> | |
7835 <h4>Background</h4> | |
7836 <span id="alpha_bg"></span> | |
7837 <script> | |
7838 { | |
7839 $("alpha_bg").appendChild(make_alpha_bg_table(meme_alphabet, data.sequence_db.freqs)); | |
7840 } | |
7841 </script> | |
7842 <h4>Other Settings</h4> | |
7843 <table id="tbl_settings" class="inputs hide_advanced"> | |
7844 <tr> | |
7845 <th>Motif Site Distribution</th> | |
7846 <td id="opt_mod"> | |
7847 <span class="mod_zoops">ZOOPS: Zero or one site per sequence</span> | |
7848 <span class="mod_oops">OOPS: Exactly one site per sequence</span> | |
7849 <span class="mod_anr">ANR: Any number of sites per sequence</span> | |
7850 </td> | |
7851 </tr> | |
7852 <tr> | |
7853 <th>Site Strand Handling</th> | |
7854 <td id="opt_strand"> | |
7855 <span class="strand_none">This alphabet only has one strand</span> | |
7856 <span class="strand_given">Sites must be on the given strand</span> | |
7857 <span class="strand_both">Sites may be on either strand</span> | |
7858 </td> | |
7859 </tr> | |
7860 <tr> | |
7861 <th>Maximum Number of Motifs</th> | |
7862 <td id="opt_nmotifs"></td> | |
7863 </tr> | |
7864 <tr> | |
7865 <th>Motif E-value Threshold</th> | |
7866 <td id="opt_evt"></td> | |
7867 </tr> | |
7868 <tr> | |
7869 <th>Minimum Motif Width</th> | |
7870 <td id="opt_minw"></td> | |
7871 </tr> | |
7872 <tr> | |
7873 <th>Maximum Motif Width</th> | |
7874 <td id="opt_maxw"></td> | |
7875 </tr> | |
7876 <tr> | |
7877 <th>Minimum Sites per Motif</th> | |
7878 <td id="opt_minsites"></td> | |
7879 </tr> | |
7880 <tr> | |
7881 <th>Maximum Sites per Motif</th> | |
7882 <td id="opt_maxsites"></td> | |
7883 </tr> | |
7884 <tr class="advanced"> | |
7885 <th>Bias on Number of Sites</th> | |
7886 <td id="opt_wnsites"></td> | |
7887 </tr> | |
7888 <tr class="advanced"> | |
7889 <th>Sequence Prior</th> | |
7890 <td id="opt_prior"> | |
7891 <span class="prior_dirichlet">Simple Dirichlet</span> | |
7892 <span class="prior_dmix">Dirichlets Mix</span> | |
7893 <span class="prior_mega">Mega-weight Dirichlets Mix</span> | |
7894 <span class="prior_megap">Mega-weight Dirichlets Mix Plus</span> | |
7895 <span class="prior_addone">Add One</span> | |
7896 </td> | |
7897 </tr> | |
7898 <tr class="advanced"> | |
7899 <th>Sequence Prior Strength</th> | |
7900 <td id="opt_b"></td> | |
7901 </tr> | |
7902 <tr class="advanced"> | |
7903 <th>EM Starting Point Source</th> | |
7904 <td id="opt_substring"> | |
7905 <span class="substring_on">From substrings in input sequences</span> | |
7906 <span class="substring_off">From strings on command line (-cons)</span> | |
7907 </td> | |
7908 </tr> | |
7909 <tr class="advanced"> | |
7910 <th>EM Starting Point Map Type</th> | |
7911 <td id="opt_spmap"> | |
7912 <span class="spmap_uni">Uniform</span> | |
7913 <span class="spmap_pam">Point Accepted Mutation</span> | |
7914 </td> | |
7915 </tr> | |
7916 <tr class="advanced"> | |
7917 <th>EM Starting Point Fuzz</th> | |
7918 <td id="opt_spfuzz"></td> | |
7919 </tr> | |
7920 <tr class="advanced"> | |
7921 <th>EM Maximum Iterations</th> | |
7922 <td id="opt_maxiter"></td> | |
7923 </tr> | |
7924 <tr class="advanced"> | |
7925 <th>EM Improvement Threshold</th> | |
7926 <td id="opt_distance"></td> | |
7927 </tr> | |
7928 <tr class="advanced"> | |
7929 <th>Trim Gap Open Cost</th> | |
7930 <td id="opt_wg"></td> | |
7931 </tr> | |
7932 <tr class="advanced"> | |
7933 <th>Trim Gap Extend Cost</th> | |
7934 <td id="opt_ws"></td> | |
7935 </tr> | |
7936 <tr class="advanced"> | |
7937 <th>End Gap Treatment</th> | |
7938 <td id="opt_noendgaps"> | |
7939 <span class="noendgaps_on">No cost</span> | |
7940 <span class="noendgaps_off">Same cost as other gaps</span> | |
7941 </td> | |
7942 </tr> | |
7943 <tr> | |
7944 <td colspan="2" style="text-align: center"> | |
7945 <a href="javascript:toggle_class(document.getElementById('tbl_settings'), 'hide_advanced')"> | |
7946 <span class="show_more">Show Advanced Settings</span> | |
7947 <span class="show_less">Hide Advanced Settings</span> | |
7948 </a> | |
7949 </td> | |
7950 </tr> | |
7951 </table> | |
7952 <script> | |
7953 { | |
7954 $("opt_mod").className = data.options.mod; | |
7955 $("opt_strand").className = (meme_alphabet.has_complement() ? (data.options.revcomp ? "both" : "given") : "none"); | |
7956 $("opt_nmotifs").textContent = data.options.nmotifs; | |
7957 $("opt_evt").textContent = (typeof data.options.evt === "number" ? data.options.evt : "no limit"); | |
7958 $("opt_minw").textContent = data.options.minw; | |
7959 $("opt_maxw").textContent = data.options.maxw; | |
7960 $("opt_minsites").textContent = data.options.minsites; | |
7961 $("opt_maxsites").textContent = data.options.maxsites; | |
7962 $("opt_wnsites").textContent = data.options.wnsites; | |
7963 $("opt_spmap").className = data.options.spmap; | |
7964 $("opt_spfuzz").textContent = data.options.spfuzz; | |
7965 $("opt_prior").className = data.options.prior; | |
7966 $("opt_b").textContent = data.options.b; | |
7967 $("opt_maxiter").textContent = data.options.maxiter; | |
7968 $("opt_distance").textContent = data.options.distance; | |
7969 $("opt_wg").textContent = data.options.wg; | |
7970 $("opt_ws").textContent = data.options.ws; | |
7971 $("opt_noendgaps").className = (data.options.noendgaps ? "on" : "off"); | |
7972 $("opt_substring").className = (data.options.substring ? "on" : "off"); | |
7973 } | |
7974 </script> | |
7975 </div> | |
7976 <!-- list information on this program --> | |
7977 <div id="info_sec" class="bar"> | |
7978 <div class="subsection"> | |
7979 <h5 id="version">MEME version</h5> | |
7980 <span id="ins_version"></span> | |
7981 (Release date: <span id="ins_release"></span>)<br> | |
7982 </div> | |
7983 <script> | |
7984 $("ins_version").innerHTML = data["version"]; | |
7985 $("ins_release").innerHTML = data["release"]; | |
7986 </script> | |
7987 <div class="subsection"> | |
7988 <h5 id="reference">Reference</h5> | |
7989 <span class="citation"> | |
7990 Timothy L. Bailey and Charles Elkan, | |
7991 "Fitting a mixture model by expectation maximization to discover motifs in biopolymers", | |
7992 <em>Proceedings of the Second International Conference on Intelligent Systems | |
7993 for Molecular Biology</em>, pp. 28-36, AAAI Press, Menlo Park, California, 1994. | |
7994 </span> | |
7995 </div> | |
7996 <div class="subsection"> | |
7997 <h5 id="command">Command line</h5> | |
7998 <textarea id="cmd" rows="5" style="width:100%;" readonly="readonly"> | |
7999 </textarea> | |
8000 <script>$("cmd").value = data["cmd"].join(" ");</script> | |
8001 </div> | |
8002 </div> | |
8003 | |
8004 </body> | |
8005 </html> |