Mercurial > repos > iuc > meme_fimo
comparison test-data/meme_output_test2.html @ 14:7e302e528795 draft
"planemo upload for repository https://github.com/galaxyproject/tools-iuc/tree/master/tools/meme commit 86a94f48321780dbe18ef5b099434c347ec2f4d0"
| author | iuc |
|---|---|
| date | Wed, 11 Dec 2019 23:04:10 +0000 |
| parents | e37874b1f811 |
| children | 6f68fb7ef9f0 |
comparison
equal
deleted
inserted
replaced
| 13:daf857eed38f | 14:7e302e528795 |
|---|---|
| 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_test2_out", "-nostatus", | 14 "meme", |
| 15 "-maxsize", "1000000", "-sf", "Galaxy_FASTA_Input", "-dna", "-mod", | 15 "-o", |
| 16 "zoops", "-nmotifs", "1", "-wnsites", "0.8", "-minw", "8", "-maxw", | 16 "-nostatus", "-maxsize", "1000000", "-sf", "Galaxy_FASTA_Input", |
| 17 "50", "-wg", "11", "-ws", "1", "-maxiter", "50", "-distance", | 17 "-dna", "-mod", "zoops", "-nmotifs", "1", "-wnsites", "0.8", |
| 18 "0.001", "-prior", "dirichlet", "-b", "0.01", "-plib", | 18 "-minw", "8", "-maxw", "50", "-wg", "11", "-ws", "1", "-maxiter", |
| 19 "prior30.plib", "-spmap", "uni", "-spfuzz", "0.5" | 19 "50", "-distance", "0.001", "-prior", "dirichlet", "-b", "0.01", |
| 20 "-plib", | |
| 21 "-spmap", "uni", "-spfuzz", "0.5" | |
| 20 ], | 22 ], |
| 21 "options": { | |
| 22 "mod": "zoops", | |
| 23 "revcomp": false, | |
| 24 "nmotifs": 1, | |
| 25 "minw": 8, | |
| 26 "maxw": 50, | |
| 27 "minsites": 2, | |
| 28 "maxsites": 30, | |
| 29 "wnsites": 0.8, | |
| 30 "spmap": "uni", | |
| 31 "spfuzz": 0.5, | |
| 32 "maxwords": -1, | |
| 33 "prior": "dirichlet", | |
| 34 "b": 0.01, | |
| 35 "maxiter": 50, | |
| 36 "distance": 0.001, | |
| 37 "wg": 11, | |
| 38 "ws": 1, | |
| 39 "noendgaps": false, | |
| 40 "substring": true | |
| 41 }, | |
| 42 "alphabet": { | |
| 43 "name": "DNA", | |
| 44 "like": "dna", | |
| 45 "ncore": 4, | |
| 46 "symbols": [ | |
| 47 { | |
| 48 "symbol": "A", | |
| 49 "name": "Adenine", | |
| 50 "colour": "CC0000", | |
| 51 "complement": "T" | |
| 52 }, { | |
| 53 "symbol": "C", | |
| 54 "name": "Cytosine", | |
| 55 "colour": "0000CC", | |
| 56 "complement": "G" | |
| 57 }, { | |
| 58 "symbol": "G", | |
| 59 "name": "Guanine", | |
| 60 "colour": "FFB300", | |
| 61 "complement": "C" | |
| 62 }, { | |
| 63 "symbol": "T", | |
| 64 "aliases": "U", | |
| 65 "name": "Thymine", | |
| 66 "colour": "008000", | |
| 67 "complement": "A" | |
| 68 }, { | |
| 69 "symbol": "N", | |
| 70 "aliases": "X.", | |
| 71 "name": "Any base", | |
| 72 "equals": "ACGT" | |
| 73 }, { | |
| 74 "symbol": "V", | |
| 75 "name": "Not T", | |
| 76 "equals": "ACG" | |
| 77 }, { | |
| 78 "symbol": "H", | |
| 79 "name": "Not G", | |
| 80 "equals": "ACT" | |
| 81 }, { | |
| 82 "symbol": "D", | |
| 83 "name": "Not C", | |
| 84 "equals": "AGT" | |
| 85 }, { | |
| 86 "symbol": "B", | |
| 87 "name": "Not A", | |
| 88 "equals": "CGT" | |
| 89 }, { | |
| 90 "symbol": "M", | |
| 91 "name": "Amino", | |
| 92 "equals": "AC" | |
| 93 }, { | |
| 94 "symbol": "R", | |
| 95 "name": "Purine", | |
| 96 "equals": "AG" | |
| 97 }, { | |
| 98 "symbol": "W", | |
| 99 "name": "Weak", | |
| 100 "equals": "AT" | |
| 101 }, { | |
| 102 "symbol": "S", | |
| 103 "name": "Strong", | |
| 104 "equals": "CG" | |
| 105 }, { | |
| 106 "symbol": "Y", | |
| 107 "name": "Pyrimidine", | |
| 108 "equals": "CT" | |
| 109 }, { | |
| 110 "symbol": "K", | |
| 111 "name": "Keto", | |
| 112 "equals": "GT" | |
| 113 } | |
| 114 ] | |
| 115 }, | |
| 116 "background": { | |
| 117 "freqs": [0.294, 0.231, 0.257, 0.217] | |
| 118 }, | |
| 119 "sequence_db": { | |
| 120 "source": "Galaxy_FASTA_Input", | |
| 121 "psp_source": "prior30.plib", | |
| 122 "freqs": [0.294, 0.231, 0.257, 0.217], | |
| 123 "sequences": [ | |
| 124 { | |
| 125 "name": "chr21_19617074_19617124_+", | |
| 126 "length": 50, | |
| 127 "weight": 1.000000 | |
| 128 }, { | |
| 129 "name": "chr21_26934381_26934431_+", | |
| 130 "length": 50, | |
| 131 "weight": 1.000000 | |
| 132 }, { | |
| 133 "name": "chr21_28217753_28217803_-", | |
| 134 "length": 50, | |
| 135 "weight": 1.000000 | |
| 136 }, { | |
| 137 "name": "chr21_31710037_31710087_-", | |
| 138 "length": 50, | |
| 139 "weight": 1.000000 | |
| 140 }, { | |
| 141 "name": "chr21_31744582_31744632_-", | |
| 142 "length": 50, | |
| 143 "weight": 1.000000 | |
| 144 }, { | |
| 145 "name": "chr21_31768316_31768366_+", | |
| 146 "length": 50, | |
| 147 "weight": 1.000000 | |
| 148 }, { | |
| 149 "name": "chr21_31914206_31914256_-", | |
| 150 "length": 50, | |
| 151 "weight": 1.000000 | |
| 152 }, { | |
| 153 "name": "chr21_31933633_31933683_-", | |
| 154 "length": 50, | |
| 155 "weight": 1.000000 | |
| 156 }, { | |
| 157 "name": "chr21_31962741_31962791_-", | |
| 158 "length": 50, | |
| 159 "weight": 1.000000 | |
| 160 }, { | |
| 161 "name": "chr21_31964683_31964733_+", | |
| 162 "length": 50, | |
| 163 "weight": 1.000000 | |
| 164 }, { | |
| 165 "name": "chr21_31973364_31973414_+", | |
| 166 "length": 50, | |
| 167 "weight": 1.000000 | |
| 168 }, { | |
| 169 "name": "chr21_31992870_31992920_+", | |
| 170 "length": 50, | |
| 171 "weight": 1.000000 | |
| 172 }, { | |
| 173 "name": "chr21_32185595_32185645_-", | |
| 174 "length": 50, | |
| 175 "weight": 1.000000 | |
| 176 }, { | |
| 177 "name": "chr21_32202076_32202126_-", | |
| 178 "length": 50, | |
| 179 "weight": 1.000000 | |
| 180 }, { | |
| 181 "name": "chr21_32253899_32253949_-", | |
| 182 "length": 50, | |
| 183 "weight": 1.000000 | |
| 184 }, { | |
| 185 "name": "chr21_32410820_32410870_-", | |
| 186 "length": 50, | |
| 187 "weight": 1.000000 | |
| 188 }, { | |
| 189 "name": "chr21_36411748_36411798_-", | |
| 190 "length": 50, | |
| 191 "weight": 1.000000 | |
| 192 }, { | |
| 193 "name": "chr21_37838750_37838800_-", | |
| 194 "length": 50, | |
| 195 "weight": 1.000000 | |
| 196 }, { | |
| 197 "name": "chr21_45705687_45705737_+", | |
| 198 "length": 50, | |
| 199 "weight": 1.000000 | |
| 200 }, { | |
| 201 "name": "chr21_45971413_45971463_-", | |
| 202 "length": 50, | |
| 203 "weight": 1.000000 | |
| 204 }, { | |
| 205 "name": "chr21_45978668_45978718_-", | |
| 206 "length": 50, | |
| 207 "weight": 1.000000 | |
| 208 }, { | |
| 209 "name": "chr21_45993530_45993580_+", | |
| 210 "length": 50, | |
| 211 "weight": 1.000000 | |
| 212 }, { | |
| 213 "name": "chr21_46020421_46020471_+", | |
| 214 "length": 50, | |
| 215 "weight": 1.000000 | |
| 216 }, { | |
| 217 "name": "chr21_46031920_46031970_+", | |
| 218 "length": 50, | |
| 219 "weight": 1.000000 | |
| 220 }, { | |
| 221 "name": "chr21_46046964_46047014_+", | |
| 222 "length": 50, | |
| 223 "weight": 1.000000 | |
| 224 }, { | |
| 225 "name": "chr21_46057197_46057247_+", | |
| 226 "length": 50, | |
| 227 "weight": 1.000000 | |
| 228 }, { | |
| 229 "name": "chr21_46086869_46086919_-", | |
| 230 "length": 50, | |
| 231 "weight": 1.000000 | |
| 232 }, { | |
| 233 "name": "chr21_46102103_46102153_-", | |
| 234 "length": 50, | |
| 235 "weight": 1.000000 | |
| 236 }, { | |
| 237 "name": "chr21_47517957_47518007_+", | |
| 238 "length": 50, | |
| 239 "weight": 1.000000 | |
| 240 }, { | |
| 241 "name": "chr21_47575506_47575556_-", | |
| 242 "length": 50, | |
| 243 "weight": 1.000000 | |
| 244 } | |
| 245 ] | |
| 246 }, | |
| 247 "motifs": [ | 23 "motifs": [ |
| 248 { | |
| 249 "db": 0, | |
| 250 "id": "GGSRTATAAAA", | |
| 251 "alt": "MEME-1", | |
| 252 "len": 11, | |
| 253 "nsites": 30, | |
| 254 "evalue": "5.1e-040", | |
| 255 "ic": 13.0, | |
| 256 "re": 12.2, | |
| 257 "llr": 254, | |
| 258 "bt": 5.2854, | |
| 259 "time": 0.376000, | |
| 260 "psm": [ | |
| 261 [-14, -179, 114, -112], [3, -1155, 137, -270], | |
| 262 [-114, 20, 86, -71], [3, -279, 122, -170], | |
| 263 [-1155, -1155, -295, 215], [156, -179, -1155, -170], | |
| 264 [-1155, -1155, -1155, 220], [172, -279, -1155, -1155], | |
| 265 [125, -1155, -1155, 46], [167, -179, -1155, -1155], | |
| 266 [144, -1155, -63, -270] | |
| 267 ], | |
| 268 "pwm": [ | |
| 269 [0.266667, 0.066667, 0.566667, 0.100000], | |
| 270 [0.300000, 0.000000, 0.666667, 0.033333], | |
| 271 [0.133333, 0.266667, 0.466667, 0.133333], | |
| 272 [0.300000, 0.033333, 0.600000, 0.066667], | |
| 273 [0.000000, 0.000000, 0.033333, 0.966667], | |
| 274 [0.866667, 0.066667, 0.000000, 0.066667], | |
| 275 [0.000000, 0.000000, 0.000000, 1.000000], | |
| 276 [0.966667, 0.033333, 0.000000, 0.000000], | |
| 277 [0.700000, 0.000000, 0.000000, 0.300000], | |
| 278 [0.933333, 0.066667, 0.000000, 0.000000], | |
| 279 [0.800000, 0.000000, 0.166667, 0.033333] | |
| 280 ], | |
| 281 "sites": [ | |
| 282 { | |
| 283 "seq": 24, | |
| 284 "pos": 12, | |
| 285 "rc": false, | |
| 286 "pvalue": 4.51e-07, | |
| 287 "lflank": "AAGGCCAGGA", | |
| 288 "match": "GGGGTATAAAA", | |
| 289 "rflank": "GCCTGAGAGC" | |
| 290 }, { | |
| 291 "seq": 23, | |
| 292 "pos": 15, | |
| 293 "rc": false, | |
| 294 "pvalue": 2.22e-06, | |
| 295 "lflank": "ATACCCAGGG", | |
| 296 "match": "AGGGTATAAAA", | |
| 297 "rflank": "CCTCAGCAGC" | |
| 298 }, { | |
| 299 "seq": 13, | |
| 300 "pos": 13, | |
| 301 "rc": false, | |
| 302 "pvalue": 2.74e-06, | |
| 303 "lflank": "CCACCAGCTT", | |
| 304 "match": "GAGGTATAAAA", | |
| 305 "rflank": "AGCCCTGTAC" | |
| 306 }, { | |
| 307 "seq": 25, | |
| 308 "pos": 36, | |
| 309 "rc": false, | |
| 310 "pvalue": 4.86e-06, | |
| 311 "lflank": "ACAGGCCCTG", | |
| 312 "match": "GGCATATAAAA", | |
| 313 "rflank": "GCC" | |
| 314 }, { | |
| 315 "seq": 21, | |
| 316 "pos": 7, | |
| 317 "rc": false, | |
| 318 "pvalue": 4.86e-06, | |
| 319 "lflank": "CCAAGGA", | |
| 320 "match": "GGAGTATAAAA", | |
| 321 "rflank": "GCCCCACAAA" | |
| 322 }, { | |
| 323 "seq": 19, | |
| 324 "pos": 9, | |
| 325 "rc": false, | |
| 326 "pvalue": 4.86e-06, | |
| 327 "lflank": "CAGGCCCTG", | |
| 328 "match": "GGCATATAAAA", | |
| 329 "rflank": "GCCCCAGCAG" | |
| 330 }, { | |
| 331 "seq": 9, | |
| 332 "pos": 13, | |
| 333 "rc": false, | |
| 334 "pvalue": 4.86e-06, | |
| 335 "lflank": "GATTCACTGA", | |
| 336 "match": "GGCATATAAAA", | |
| 337 "rflank": "GGCCCTCTGC" | |
| 338 }, { | |
| 339 "seq": 28, | |
| 340 "pos": 32, | |
| 341 "rc": false, | |
| 342 "pvalue": 6.48e-06, | |
| 343 "lflank": "CCGGCGGGGC", | |
| 344 "match": "GGGGTATAAAG", | |
| 345 "rflank": "GGGGCGG" | |
| 346 }, { | |
| 347 "seq": 20, | |
| 348 "pos": 4, | |
| 349 "rc": false, | |
| 350 "pvalue": 6.48e-06, | |
| 351 "lflank": "CAGA", | |
| 352 "match": "GGGGTATAAAG", | |
| 353 "rflank": "GTTCCGACCA" | |
| 354 }, { | |
| 355 "seq": 12, | |
| 356 "pos": 18, | |
| 357 "rc": false, | |
| 358 "pvalue": 6.48e-06, | |
| 359 "lflank": "CACCAGAGCT", | |
| 360 "match": "GGGATATATAA", | |
| 361 "rflank": "AGAAGGTTCT" | |
| 362 }, { | |
| 363 "seq": 15, | |
| 364 "pos": 21, | |
| 365 "rc": false, | |
| 366 "pvalue": 1.38e-05, | |
| 367 "lflank": "AATCACTGAG", | |
| 368 "match": "GATGTATAAAA", | |
| 369 "rflank": "GTCCCAGGGA" | |
| 370 }, { | |
| 371 "seq": 11, | |
| 372 "pos": 16, | |
| 373 "rc": false, | |
| 374 "pvalue": 1.38e-05, | |
| 375 "lflank": "CACTATTGAA", | |
| 376 "match": "GATGTATAAAA", | |
| 377 "rflank": "TTTCATTTGC" | |
| 378 }, { | |
| 379 "seq": 0, | |
| 380 "pos": 39, | |
| 381 "rc": false, | |
| 382 "pvalue": 1.41e-05, | |
| 383 "lflank": "CCTCGGGACG", | |
| 384 "match": "TGGGTATATAA", | |
| 385 "rflank": "" | |
| 386 }, { | |
| 387 "seq": 6, | |
| 388 "pos": 15, | |
| 389 "rc": false, | |
| 390 "pvalue": 1.61e-05, | |
| 391 "lflank": "CCCACTACTT", | |
| 392 "match": "AGAGTATAAAA", | |
| 393 "rflank": "TCATTCTGAG" | |
| 394 }, { | |
| 395 "seq": 22, | |
| 396 "pos": 2, | |
| 397 "rc": false, | |
| 398 "pvalue": 1.95e-05, | |
| 399 "lflank": "GA", | |
| 400 "match": "GACATATAAAA", | |
| 401 "rflank": "GCCAACATCC" | |
| 402 }, { | |
| 403 "seq": 14, | |
| 404 "pos": 17, | |
| 405 "rc": false, | |
| 406 "pvalue": 1.95e-05, | |
| 407 "lflank": "CCCACCAGCA", | |
| 408 "match": "AGGATATATAA", | |
| 409 "rflank": "AAGCTCAGGA" | |
| 410 }, { | |
| 411 "seq": 18, | |
| 412 "pos": 37, | |
| 413 "rc": false, | |
| 414 "pvalue": 2.16e-05, | |
| 415 "lflank": "CGTGGTCGCG", | |
| 416 "match": "GGGGTATAACA", | |
| 417 "rflank": "GC" | |
| 418 }, { | |
| 419 "seq": 29, | |
| 420 "pos": 30, | |
| 421 "rc": false, | |
| 422 "pvalue": 3.04e-05, | |
| 423 "lflank": "GCTGCCGGTG", | |
| 424 "match": "AGCGTATAAAG", | |
| 425 "rflank": "GCCCTGGCG" | |
| 426 }, { | |
| 427 "seq": 4, | |
| 428 "pos": 12, | |
| 429 "rc": false, | |
| 430 "pvalue": 3.04e-05, | |
| 431 "lflank": "CAGGTCTAAG", | |
| 432 "match": "AGCATATATAA", | |
| 433 "rflank": "CTTGGAGTCC" | |
| 434 }, { | |
| 435 "seq": 5, | |
| 436 "pos": 0, | |
| 437 "rc": false, | |
| 438 "pvalue": 3.67e-05, | |
| 439 "lflank": "", | |
| 440 "match": "AACGTATATAA", | |
| 441 "rflank": "ATGGTCCTGT" | |
| 442 }, { | |
| 443 "seq": 1, | |
| 444 "pos": 27, | |
| 445 "rc": false, | |
| 446 "pvalue": 3.93e-05, | |
| 447 "lflank": "AGTCACAAGT", | |
| 448 "match": "GAGTTATAAAA", | |
| 449 "rflank": "GGGTCGCACG" | |
| 450 }, { | |
| 451 "seq": 7, | |
| 452 "pos": 4, | |
| 453 "rc": false, | |
| 454 "pvalue": 5.65e-05, | |
| 455 "lflank": "TCAG", | |
| 456 "match": "AGTATATATAA", | |
| 457 "rflank": "ATGTTCCTGT" | |
| 458 }, { | |
| 459 "seq": 3, | |
| 460 "pos": 14, | |
| 461 "rc": false, | |
| 462 "pvalue": 6.24e-05, | |
| 463 "lflank": "CCCAGGTTTC", | |
| 464 "match": "TGAGTATATAA", | |
| 465 "rflank": "TCGCCGCACC" | |
| 466 }, { | |
| 467 "seq": 16, | |
| 468 "pos": 22, | |
| 469 "rc": false, | |
| 470 "pvalue": 7.15e-05, | |
| 471 "lflank": "AGTTTCAGTT", | |
| 472 "match": "GGCATCTAAAA", | |
| 473 "rflank": "attatataac" | |
| 474 }, { | |
| 475 "seq": 27, | |
| 476 "pos": 36, | |
| 477 "rc": false, | |
| 478 "pvalue": 1.39e-04, | |
| 479 "lflank": "TGCCTGGGTC", | |
| 480 "match": "CAGGTATAAAG", | |
| 481 "rflank": "GCT" | |
| 482 }, { | |
| 483 "seq": 26, | |
| 484 "pos": 37, | |
| 485 "rc": false, | |
| 486 "pvalue": 1.39e-04, | |
| 487 "lflank": "TGCCTGGGCC", | |
| 488 "match": "CAGGTATAAAG", | |
| 489 "rflank": "GC" | |
| 490 }, { | |
| 491 "seq": 17, | |
| 492 "pos": 2, | |
| 493 "rc": false, | |
| 494 "pvalue": 4.81e-04, | |
| 495 "lflank": "ga", | |
| 496 "match": "TGGTTTTATAA", | |
| 497 "rflank": "ggggcctcac" | |
| 498 }, { | |
| 499 "seq": 8, | |
| 500 "pos": 13, | |
| 501 "rc": false, | |
| 502 "pvalue": 8.57e-04, | |
| 503 "lflank": "TATAACTCAG", | |
| 504 "match": "GTTGGATAAAA", | |
| 505 "rflank": "TAATTTGTAC" | |
| 506 }, { | |
| 507 "seq": 10, | |
| 508 "pos": 7, | |
| 509 "rc": false, | |
| 510 "pvalue": 1.47e-03, | |
| 511 "lflank": "aaactta", | |
| 512 "match": "AAACTCTATAA", | |
| 513 "rflank": "acttaaaact" | |
| 514 }, { | |
| 515 "seq": 2, | |
| 516 "pos": 26, | |
| 517 "rc": false, | |
| 518 "pvalue": 2.64e-03, | |
| 519 "lflank": "GGTGGGGGTG", | |
| 520 "match": "GGGGTTTCACT", | |
| 521 "rflank": "GGTCCACTAT" | |
| 522 } | |
| 523 ] | |
| 524 } | |
| 525 ], | |
| 526 "scan": [ | |
| 527 { | |
| 528 "pvalue": 5.63e-04, | |
| 529 "sites": [ | |
| 530 { | |
| 531 "motif": 0, | |
| 532 "pos": 39, | |
| 533 "rc": false, | |
| 534 "pvalue": 1.41e-05 | |
| 535 } | |
| 536 ] | |
| 537 }, { | |
| 538 "pvalue": 1.57e-03, | |
| 539 "sites": [ | |
| 540 { | |
| 541 "motif": 0, | |
| 542 "pos": 27, | |
| 543 "rc": false, | |
| 544 "pvalue": 3.93e-05 | |
| 545 } | |
| 546 ] | |
| 547 }, { | |
| 548 "pvalue": 1.00e-01, | |
| 549 "sites": [] | |
| 550 }, { | |
| 551 "pvalue": 2.49e-03, | |
| 552 "sites": [ | |
| 553 { | |
| 554 "motif": 0, | |
| 555 "pos": 14, | |
| 556 "rc": false, | |
| 557 "pvalue": 6.24e-05 | |
| 558 } | |
| 559 ] | |
| 560 }, { | |
| 561 "pvalue": 1.22e-03, | |
| 562 "sites": [ | |
| 563 { | |
| 564 "motif": 0, | |
| 565 "pos": 12, | |
| 566 "rc": false, | |
| 567 "pvalue": 3.04e-05 | |
| 568 } | |
| 569 ] | |
| 570 }, { | |
| 571 "pvalue": 1.47e-03, | |
| 572 "sites": [ | |
| 573 { | |
| 574 "motif": 0, | |
| 575 "pos": 0, | |
| 576 "rc": false, | |
| 577 "pvalue": 3.67e-05 | |
| 578 } | |
| 579 ] | |
| 580 }, { | |
| 581 "pvalue": 6.45e-04, | |
| 582 "sites": [ | |
| 583 { | |
| 584 "motif": 0, | |
| 585 "pos": 15, | |
| 586 "rc": false, | |
| 587 "pvalue": 1.61e-05 | |
| 588 } | |
| 589 ] | |
| 590 }, { | |
| 591 "pvalue": 2.26e-03, | |
| 592 "sites": [ | |
| 593 { | |
| 594 "motif": 0, | |
| 595 "pos": 4, | |
| 596 "rc": false, | |
| 597 "pvalue": 5.65e-05 | |
| 598 } | |
| 599 ] | |
| 600 }, { | |
| 601 "pvalue": 3.37e-02, | |
| 602 "sites": [] | |
| 603 }, { | |
| 604 "pvalue": 1.95e-04, | |
| 605 "sites": [ | |
| 606 { | |
| 607 "motif": 0, | |
| 608 "pos": 13, | |
| 609 "rc": false, | |
| 610 "pvalue": 4.86e-06 | |
| 611 } | |
| 612 ] | |
| 613 }, { | |
| 614 "pvalue": 5.73e-02, | |
| 615 "sites": [] | |
| 616 }, { | |
| 617 "pvalue": 5.52e-04, | |
| 618 "sites": [ | |
| 619 { | |
| 620 "motif": 0, | |
| 621 "pos": 16, | |
| 622 "rc": false, | |
| 623 "pvalue": 1.38e-05 | |
| 624 } | |
| 625 ] | |
| 626 }, { | |
| 627 "pvalue": 2.59e-04, | |
| 628 "sites": [ | |
| 629 { | |
| 630 "motif": 0, | |
| 631 "pos": 18, | |
| 632 "rc": false, | |
| 633 "pvalue": 6.48e-06 | |
| 634 } | |
| 635 ] | |
| 636 }, { | |
| 637 "pvalue": 1.10e-04, | |
| 638 "sites": [ | |
| 639 { | |
| 640 "motif": 0, | |
| 641 "pos": 13, | |
| 642 "rc": false, | |
| 643 "pvalue": 2.74e-06 | |
| 644 } | |
| 645 ] | |
| 646 }, { | |
| 647 "pvalue": 7.78e-04, | |
| 648 "sites": [ | |
| 649 { | |
| 650 "motif": 0, | |
| 651 "pos": 17, | |
| 652 "rc": false, | |
| 653 "pvalue": 1.95e-05 | |
| 654 } | |
| 655 ] | |
| 656 }, { | |
| 657 "pvalue": 5.52e-04, | |
| 658 "sites": [ | |
| 659 { | |
| 660 "motif": 0, | |
| 661 "pos": 21, | |
| 662 "rc": false, | |
| 663 "pvalue": 1.38e-05 | |
| 664 } | |
| 665 ] | |
| 666 }, { | |
| 667 "pvalue": 2.85e-03, | |
| 668 "sites": [ | |
| 669 { | |
| 670 "motif": 0, | |
| 671 "pos": 22, | |
| 672 "rc": false, | |
| 673 "pvalue": 7.15e-05 | |
| 674 } | |
| 675 ] | |
| 676 }, { | |
| 677 "pvalue": 1.90e-02, | |
| 678 "sites": [] | |
| 679 }, { | |
| 680 "pvalue": 8.63e-04, | |
| 681 "sites": [ | |
| 682 { | |
| 683 "motif": 0, | |
| 684 "pos": 37, | |
| 685 "rc": false, | |
| 686 "pvalue": 2.16e-05 | |
| 687 } | |
| 688 ] | |
| 689 }, { | |
| 690 "pvalue": 1.95e-04, | |
| 691 "sites": [ | |
| 692 { | |
| 693 "motif": 0, | |
| 694 "pos": 9, | |
| 695 "rc": false, | |
| 696 "pvalue": 4.86e-06 | |
| 697 } | |
| 698 ] | |
| 699 }, { | |
| 700 "pvalue": 2.59e-04, | |
| 701 "sites": [ | |
| 702 { | |
| 703 "motif": 0, | |
| 704 "pos": 4, | |
| 705 "rc": false, | |
| 706 "pvalue": 6.48e-06 | |
| 707 } | |
| 708 ] | |
| 709 }, { | |
| 710 "pvalue": 1.95e-04, | |
| 711 "sites": [ | |
| 712 { | |
| 713 "motif": 0, | |
| 714 "pos": 7, | |
| 715 "rc": false, | |
| 716 "pvalue": 4.86e-06 | |
| 717 } | |
| 718 ] | |
| 719 }, { | |
| 720 "pvalue": 7.78e-04, | |
| 721 "sites": [ | |
| 722 { | |
| 723 "motif": 0, | |
| 724 "pos": 2, | |
| 725 "rc": false, | |
| 726 "pvalue": 1.95e-05 | |
| 727 } | |
| 728 ] | |
| 729 }, { | |
| 730 "pvalue": 8.89e-05, | |
| 731 "sites": [ | |
| 732 { | |
| 733 "motif": 0, | |
| 734 "pos": 15, | |
| 735 "rc": false, | |
| 736 "pvalue": 2.22e-06 | |
| 737 } | |
| 738 ] | |
| 739 }, { | |
| 740 "pvalue": 1.80e-05, | |
| 741 "sites": [ | |
| 742 { | |
| 743 "motif": 0, | |
| 744 "pos": 12, | |
| 745 "rc": false, | |
| 746 "pvalue": 4.51e-07 | |
| 747 } | |
| 748 ] | |
| 749 }, { | |
| 750 "pvalue": 1.95e-04, | |
| 751 "sites": [ | |
| 752 { | |
| 753 "motif": 0, | |
| 754 "pos": 36, | |
| 755 "rc": false, | |
| 756 "pvalue": 4.86e-06 | |
| 757 } | |
| 758 ] | |
| 759 }, { | |
| 760 "pvalue": 5.54e-03, | |
| 761 "sites": [] | |
| 762 }, { | |
| 763 "pvalue": 5.54e-03, | |
| 764 "sites": [] | |
| 765 }, { | |
| 766 "pvalue": 2.59e-04, | |
| 767 "sites": [ | |
| 768 { | |
| 769 "motif": 0, | |
| 770 "pos": 32, | |
| 771 "rc": false, | |
| 772 "pvalue": 6.48e-06 | |
| 773 } | |
| 774 ] | |
| 775 }, { | |
| 776 "pvalue": 1.22e-03, | |
| 777 "sites": [ | |
| 778 { | |
| 779 "motif": 0, | |
| 780 "pos": 30, | |
| 781 "rc": false, | |
| 782 "pvalue": 3.04e-05 | |
| 783 } | |
| 784 ] | |
| 785 } | |
| 786 ] | 24 ] |
| 787 }; | 25 }; |
| 788 </script> | 26 </script> |
| 789 <script> | |
| 790 var site_url = "http://meme-suite.org"; | 27 var site_url = "http://meme-suite.org"; |
| 791 </script> | |
| 792 <script> | |
| 793 | |
| 794 /* | |
| 795 * $ | |
| 796 * | |
| 797 * Shorthand function for getElementById | |
| 798 */ | |
| 799 function $(el) { | |
| 800 return document.getElementById(el); | |
| 801 } | |
| 802 | |
| 803 | |
| 804 /* | |
| 805 * See http://stackoverflow.com/a/5450113/66387 | |
| 806 * Does string multiplication like the perl x operator. | |
| 807 */ | |
| 808 function string_mult(pattern, count) { | |
| 809 if (count < 1) return ''; | |
| 810 var result = ''; | |
| 811 while (count > 1) { | |
| 812 if (count & 1) result += pattern; | |
| 813 count >>= 1, pattern += pattern; | |
| 814 } | |
| 815 return result + pattern; | |
| 816 } | |
| 817 | |
| 818 /* | |
| 819 * See http://stackoverflow.com/questions/814613/how-to-read-get-data-from-a-url-using-javascript | |
| 820 * Slightly modified with information from | |
| 821 * https://developer.mozilla.org/en/DOM/window.location | |
| 822 */ | |
| 823 function parse_params() { | |
| 824 "use strict"; | |
| 825 var search, queryStart, queryEnd, query, params, nvPairs, i, nv, n, v; | |
| 826 search = window.location.search; | |
| 827 queryStart = search.indexOf("?") + 1; | |
| 828 queryEnd = search.indexOf("#") + 1 || search.length + 1; | |
| 829 query = search.slice(queryStart, queryEnd - 1); | |
| 830 | |
| 831 if (query === search || query === "") return {}; | |
| 832 | |
| 833 params = {}; | |
| 834 nvPairs = query.replace(/\+/g, " ").split("&"); | |
| 835 | |
| 836 for (i = 0; i < nvPairs.length; i++) { | |
| 837 nv = nvPairs[i].split("="); | |
| 838 n = decodeURIComponent(nv[0]); | |
| 839 v = decodeURIComponent(nv[1]); | |
| 840 // allow a name to be used multiple times | |
| 841 // storing each value in the array | |
| 842 if (!(n in params)) { | |
| 843 params[n] = []; | |
| 844 } | |
| 845 params[n].push(nv.length === 2 ? v : null); | |
| 846 } | |
| 847 return params; | |
| 848 } | |
| 849 | |
| 850 /* | |
| 851 * coords | |
| 852 * | |
| 853 * Calculates the x and y offset of an element. | |
| 854 * From http://www.quirksmode.org/js/findpos.html | |
| 855 * with alterations to take into account scrolling regions | |
| 856 */ | |
| 857 function coords(elem) { | |
| 858 var myX = myY = 0; | |
| 859 if (elem.getBoundingClientRect) { | |
| 860 var rect; | |
| 861 rect = elem.getBoundingClientRect(); | |
| 862 myX = rect.left + ((typeof window.pageXOffset !== "undefined") ? | |
| 863 window.pageXOffset : document.body.scrollLeft); | |
| 864 myY = rect.top + ((typeof window.pageYOffset !== "undefined") ? | |
| 865 window.pageYOffset : document.body.scrollTop); | |
| 866 } else { | |
| 867 // this fall back doesn't properly handle absolutely positioned elements | |
| 868 // inside a scrollable box | |
| 869 var node; | |
| 870 if (elem.offsetParent) { | |
| 871 // subtract all scrolling | |
| 872 node = elem; | |
| 873 do { | |
| 874 myX -= node.scrollLeft ? node.scrollLeft : 0; | |
| 875 myY -= node.scrollTop ? node.scrollTop : 0; | |
| 876 } while (node = node.parentNode); | |
| 877 // this will include the page scrolling (which is unwanted) so add it back on | |
| 878 myX += (typeof window.pageXOffset !== "undefined") ? window.pageXOffset : document.body.scrollLeft; | |
| 879 myY += (typeof window.pageYOffset !== "undefined") ? window.pageYOffset : document.body.scrollTop; | |
| 880 // sum up offsets | |
| 881 node = elem; | |
| 882 do { | |
| 883 myX += node.offsetLeft; | |
| 884 myY += node.offsetTop; | |
| 885 } while (node = node.offsetParent); | |
| 886 } | |
| 887 } | |
| 888 return [myX, myY]; | |
| 889 } | |
| 890 | |
| 891 /* | |
| 892 * position_popup | |
| 893 * | |
| 894 * Positions a popup relative to an anchor element. | |
| 895 * | |
| 896 * The avaliable positions are: | |
| 897 * 0 - Centered below the anchor. | |
| 898 */ | |
| 899 function position_popup(anchor, popup, position) { | |
| 900 "use strict"; | |
| 901 var a_x, a_y, a_w, a_h, p_x, p_y, p_w, p_h; | |
| 902 var a_xy, spacer, margin, scrollbar, page_w; | |
| 903 // define constants | |
| 904 spacer = 5; | |
| 905 margin = 15; | |
| 906 scrollbar = 15; | |
| 907 // define the positions and widths | |
| 908 a_xy = coords(anchor); | |
| 909 a_x = a_xy[0]; | |
| 910 a_y = a_xy[1]; | |
| 911 a_w = anchor.offsetWidth; | |
| 912 a_h = anchor.offsetHeight; | |
| 913 p_w = popup.offsetWidth; | |
| 914 p_h = popup.offsetHeight; | |
| 915 page_w = null; | |
| 916 if (window.innerWidth) { | |
| 917 page_w = window.innerWidth; | |
| 918 } else if (document.body) { | |
| 919 page_w = document.body.clientWidth; | |
| 920 } | |
| 921 // check the position type is defined | |
| 922 if (typeof position !== "number") { | |
| 923 position = 0; | |
| 924 } | |
| 925 // calculate the popup position | |
| 926 switch (position) { | |
| 927 case 1: | |
| 928 p_x = a_x + a_w + spacer; | |
| 929 p_y = a_y + (a_h / 2) - (p_h / 2); | |
| 930 break; | |
| 931 case 0: | |
| 932 default: | |
| 933 p_x = a_x + (a_w / 2) - (p_w / 2); | |
| 934 p_y = a_y + a_h + spacer; | |
| 935 break; | |
| 936 } | |
| 937 // constrain the popup position | |
| 938 if (p_x < margin) { | |
| 939 p_x = margin; | |
| 940 } else if (page_w != null && (p_x + p_w) > (page_w - margin - scrollbar)) { | |
| 941 p_x = page_w - margin - scrollbar - p_w; | |
| 942 } | |
| 943 if (p_y < margin) { | |
| 944 p_y = margin; | |
| 945 } | |
| 946 // position the popup | |
| 947 popup.style.left = p_x + "px"; | |
| 948 popup.style.top = p_y + "px"; | |
| 949 } | |
| 950 | |
| 951 function lookup_help_popup(popup_id) { | |
| 952 var _body, pop, info; | |
| 953 pop = document.getElementById(popup_id); | |
| 954 if (pop == null) { | |
| 955 _body = document.getElementsByTagName("body")[0]; | |
| 956 pop = document.createElement("div"); | |
| 957 pop.className = "pop_content"; | |
| 958 pop.id = popup_id; | |
| 959 pop.style.backgroundColor = "#FFC"; | |
| 960 pop.style.borderColor = "black"; | |
| 961 info = document.createElement("p"); | |
| 962 info.style.fontWeight = "bold"; | |
| 963 info.appendChild(document.createTextNode("Error: No popup for topic \"" + popup_id + "\".")); | |
| 964 pop.appendChild(info); | |
| 965 // this might cause problems with the menu, but as this only happens | |
| 966 // when something is already wrong I don't think that's too much of a problem | |
| 967 _body.insertBefore(pop, _body.firstChild); | |
| 968 } | |
| 969 if (document.getElementsByTagName('body')[0].hasAttribute("data-autobtns")) { | |
| 970 if (!/\bauto_buttons\b/.test(pop.className)) { | |
| 971 pop.className += " auto_buttons"; | |
| 972 var back_btn_sec = document.createElement("div"); | |
| 973 back_btn_sec.className = "nested_only pop_back_sec"; | |
| 974 var back_btn = document.createElement("span"); | |
| 975 back_btn.className = "pop_back"; | |
| 976 back_btn.appendChild(document.createTextNode("<< back")); | |
| 977 back_btn.addEventListener("click", function(e) { | |
| 978 help_return(); | |
| 979 }, false); | |
| 980 back_btn_sec.appendChild(back_btn); | |
| 981 pop.insertBefore(back_btn_sec, pop.firstChild); | |
| 982 var close_btn_sec = document.createElement("div"); | |
| 983 close_btn_sec.className = "pop_close_sec"; | |
| 984 var close_btn = document.createElement("span"); | |
| 985 close_btn.className = "pop_close"; | |
| 986 close_btn.appendChild(document.createTextNode("close")); | |
| 987 close_btn.addEventListener("click", function(e) { | |
| 988 help_popup(); | |
| 989 }, false); | |
| 990 close_btn_sec.appendChild(close_btn); | |
| 991 pop.appendChild(close_btn_sec); | |
| 992 } | |
| 993 } | |
| 994 return pop; | |
| 995 } | |
| 996 | |
| 997 /* | |
| 998 * help_popup | |
| 999 * | |
| 1000 * Moves around help pop-ups so they appear | |
| 1001 * below an activator. | |
| 1002 */ | |
| 1003 function help_popup(activator, popup_id) { | |
| 1004 "use strict"; | |
| 1005 var pop; | |
| 1006 // set default values | |
| 1007 if (typeof help_popup.popup === "undefined") { | |
| 1008 help_popup.popup = []; | |
| 1009 } | |
| 1010 if (typeof help_popup.activator === "undefined") { | |
| 1011 help_popup.activator = null; | |
| 1012 } | |
| 1013 var last_pop = (help_popup.popup.length > 0 ? help_popup.popup[help_popup.popup.length - 1] : null); | |
| 1014 if (typeof(activator) == "undefined") { // no activator so hide | |
| 1015 if (last_pop != null) { | |
| 1016 last_pop.style.display = 'none'; | |
| 1017 help_popup.popup = []; | |
| 1018 } | |
| 1019 return; | |
| 1020 } | |
| 1021 pop = lookup_help_popup(popup_id); | |
| 1022 if (pop == last_pop) { | |
| 1023 if (activator == help_popup.activator) { | |
| 1024 //hide popup (as we've already shown it for the current help button) | |
| 1025 last_pop.style.display = 'none'; | |
| 1026 help_popup.popup = []; | |
| 1027 return; // toggling complete! | |
| 1028 } | |
| 1029 } else if (last_pop != null) { | |
| 1030 //activating different popup so hide current one | |
| 1031 last_pop.style.display = 'none'; | |
| 1032 } | |
| 1033 help_popup.popup = [pop]; | |
| 1034 help_popup.activator = activator; | |
| 1035 toggle_class(pop, "nested", false); | |
| 1036 //must make the popup visible to measure it or it has zero width | |
| 1037 pop.style.display = 'block'; | |
| 1038 position_popup(activator, pop); | |
| 1039 } | |
| 1040 | |
| 1041 /* | |
| 1042 * help_refine | |
| 1043 * | |
| 1044 * Intended for links within a help popup. Stores a stack of state so | |
| 1045 * you can go back. | |
| 1046 */ | |
| 1047 function help_refine(popup_id) { | |
| 1048 if (help_popup.popup == null || help_popup.popup.length == 0 || help_popup.activator == null) { | |
| 1049 throw new Error("Can not refine a help popup when one is not shown!"); | |
| 1050 } | |
| 1051 var pop = lookup_help_popup(popup_id); | |
| 1052 var last_pop = help_popup.popup[help_popup.popup.length - 1]; | |
| 1053 if (pop == last_pop) return; // slightly odd, but no real cause for alarm | |
| 1054 help_popup.popup.push(pop); | |
| 1055 toggle_class(pop, "nested", true); | |
| 1056 last_pop.style.display = "none"; | |
| 1057 //must make the popup visible to measure it or it has zero width | |
| 1058 pop.style.display = "block"; | |
| 1059 position_popup(help_popup.activator, pop); | |
| 1060 } | |
| 1061 | |
| 1062 /* | |
| 1063 * help_return | |
| 1064 * | |
| 1065 * Intended for links within a help popup. Stores a stack of state so | |
| 1066 * you can go back. | |
| 1067 */ | |
| 1068 function help_return() { | |
| 1069 if (help_popup.popup == null || help_popup.popup.length == 0 || help_popup.activator == null) { | |
| 1070 throw new Error("Can not return to a earlier help popup when one is not shown!"); | |
| 1071 } | |
| 1072 var last_pop = help_popup.popup.pop(); | |
| 1073 last_pop.style.display = "none"; | |
| 1074 var pop = (help_popup.popup.length > 0 ? help_popup.popup[help_popup.popup.length - 1] : null); | |
| 1075 if (pop != null) { | |
| 1076 toggle_class(pop, "nested", help_popup.popup.length > 1); | |
| 1077 pop.style.display = "block"; | |
| 1078 position_popup(help_popup.activator, pop); | |
| 1079 } else { | |
| 1080 help_popup.activator = null; | |
| 1081 } | |
| 1082 } | |
| 1083 | |
| 1084 /* | |
| 1085 * update_scroll_pad | |
| 1086 * | |
| 1087 * Creates padding at the bottom of the page to allow | |
| 1088 * scrolling of anything into view. | |
| 1089 */ | |
| 1090 function update_scroll_pad() { | |
| 1091 var page, pad; | |
| 1092 page = (document.compatMode === "CSS1Compat") ? document.documentElement : document.body; | |
| 1093 pad = $("scrollpad"); | |
| 1094 if (pad === null) { | |
| 1095 pad = document.createElement("div"); | |
| 1096 pad.id = 'scrollpad'; | |
| 1097 document.getElementsByTagName('body')[0].appendChild(pad); | |
| 1098 } | |
| 1099 pad.style.height = Math.abs(page.clientHeight - 100) + "px"; | |
| 1100 } | |
| 1101 | |
| 1102 function substitute_classes(node, remove, add) { | |
| 1103 "use strict"; | |
| 1104 var list, all, i, cls, classes; | |
| 1105 list = node.className.split(/\s+/); | |
| 1106 all = {}; | |
| 1107 for (i = 0; i < list.length; i++) { | |
| 1108 if (list[i].length > 0) all[list[i]] = true; | |
| 1109 } | |
| 1110 for (i = 0; i < remove.length; i++) { | |
| 1111 if (all.hasOwnProperty(remove[i])) { | |
| 1112 delete all[remove[i]]; | |
| 1113 } | |
| 1114 } | |
| 1115 for (i = 0; i < add.length; i++) { | |
| 1116 all[add[i]] = true; | |
| 1117 } | |
| 1118 classes = ""; | |
| 1119 for (cls in all) { | |
| 1120 classes += cls + " "; | |
| 1121 } | |
| 1122 node.className = classes; | |
| 1123 } | |
| 1124 | |
| 1125 /* | |
| 1126 * toggle_class | |
| 1127 * | |
| 1128 * Adds or removes a class from the node. If the parameter 'enabled' is not | |
| 1129 * passed then the existence of the class will be toggled, otherwise it will be | |
| 1130 * included if enabled is true. | |
| 1131 */ | |
| 1132 function toggle_class(node, cls, enabled) { | |
| 1133 var classes = node.className; | |
| 1134 var list = classes.replace(/^\s+/, '').replace(/\s+$/, '').split(/\s+/); | |
| 1135 var found = false; | |
| 1136 for (var i = 0; i < list.length; i++) { | |
| 1137 if (list[i] == cls) { | |
| 1138 list.splice(i, 1); | |
| 1139 i--; | |
| 1140 found = true; | |
| 1141 } | |
| 1142 } | |
| 1143 if (typeof enabled == "undefined") { | |
| 1144 if (!found) list.push(cls); | |
| 1145 } else { | |
| 1146 if (enabled) list.push(cls); | |
| 1147 } | |
| 1148 node.className = list.join(" "); | |
| 1149 } | |
| 1150 | |
| 1151 /* | |
| 1152 * find_child | |
| 1153 * | |
| 1154 * Searches child nodes in depth first order and returns the first it finds | |
| 1155 * with the className specified. | |
| 1156 * TODO replace with querySelector | |
| 1157 */ | |
| 1158 function find_child(node, className) { | |
| 1159 var pattern; | |
| 1160 if (node == null || typeof node !== "object") { | |
| 1161 return null; | |
| 1162 } | |
| 1163 if (typeof className === "string") { | |
| 1164 pattern = new RegExp("\\b" + className + "\\b"); | |
| 1165 } else { | |
| 1166 pattern = className; | |
| 1167 } | |
| 1168 if (node.nodeType == Node.ELEMENT_NODE && | |
| 1169 pattern.test(node.className)) { | |
| 1170 return node; | |
| 1171 } else { | |
| 1172 var result = null; | |
| 1173 for (var i = 0; i < node.childNodes.length; i++) { | |
| 1174 result = find_child(node.childNodes[i], pattern); | |
| 1175 if (result != null) break; | |
| 1176 } | |
| 1177 return result; | |
| 1178 } | |
| 1179 } | |
| 1180 | |
| 1181 /* | |
| 1182 * find_parent | |
| 1183 * | |
| 1184 * Searches parent nodes outwards from the node and returns the first it finds | |
| 1185 * with the className specified. | |
| 1186 */ | |
| 1187 function find_parent(node, className) { | |
| 1188 var pattern; | |
| 1189 pattern = new RegExp("\\b" + className + "\\b"); | |
| 1190 do { | |
| 1191 if (node.nodeType == Node.ELEMENT_NODE && | |
| 1192 pattern.test(node.className)) { | |
| 1193 return node; | |
| 1194 } | |
| 1195 } while (node = node.parentNode); | |
| 1196 return null; | |
| 1197 } | |
| 1198 | |
| 1199 /* | |
| 1200 * find_parent_tag | |
| 1201 * | |
| 1202 * Searches parent nodes outwards from the node and returns the first it finds | |
| 1203 * with the tag name specified. HTML tags should be specified in upper case. | |
| 1204 */ | |
| 1205 function find_parent_tag(node, tag_name) { | |
| 1206 do { | |
| 1207 if (node.nodeType == Node.ELEMENT_NODE && node.tagName == tag_name) { | |
| 1208 return node; | |
| 1209 } | |
| 1210 } while (node = node.parentNode); | |
| 1211 return null; | |
| 1212 } | |
| 1213 | |
| 1214 /* | |
| 1215 * __toggle_help | |
| 1216 * | |
| 1217 * Uses the 'topic' property of the this object to | |
| 1218 * toggle display of a help topic. | |
| 1219 * | |
| 1220 * This function is not intended to be called directly. | |
| 1221 */ | |
| 1222 function __toggle_help(e) { | |
| 1223 if (!e) e = window.event; | |
| 1224 if (e.type === "keydown") { | |
| 1225 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
| 1226 return; | |
| 1227 } | |
| 1228 // stop a submit or something like that | |
| 1229 e.preventDefault(); | |
| 1230 } | |
| 1231 | |
| 1232 help_popup(this, this.getAttribute("data-topic")); | |
| 1233 } | |
| 1234 | |
| 1235 function setup_help_button(button) { | |
| 1236 "use strict"; | |
| 1237 var topic; | |
| 1238 if (button.hasAttribute("data-topic")) { | |
| 1239 topic = button.getAttribute("data-topic"); | |
| 1240 if (document.getElementById(topic) != null) { | |
| 1241 button.tabIndex = "0"; // make keyboard selectable | |
| 1242 button.addEventListener("click", function() { | |
| 1243 help_popup(button, topic); | |
| 1244 }, false); | |
| 1245 button.addEventListener("keydown", function(e) { | |
| 1246 // toggle only on Enter or Spacebar, let other keys do their thing | |
| 1247 if (e.keyCode !== 13 && e.keyCode !== 32) return; | |
| 1248 // stop a submit or something like that | |
| 1249 e.preventDefault(); | |
| 1250 help_popup(button, topic); | |
| 1251 }, false); | |
| 1252 } else { | |
| 1253 button.style.visibility = "hidden"; | |
| 1254 } | |
| 1255 } | |
| 1256 button.className += " active"; | |
| 1257 } | |
| 1258 | |
| 1259 /* | |
| 1260 * help_button | |
| 1261 * | |
| 1262 * Makes a help button for the passed topic. | |
| 1263 */ | |
| 1264 function help_button(topic) { | |
| 1265 var btn = document.createElement("div"); | |
| 1266 btn.className = "help"; | |
| 1267 btn.setAttribute("data-topic", topic); | |
| 1268 setup_help_button(btn); | |
| 1269 return btn; | |
| 1270 } | |
| 1271 | |
| 1272 /* | |
| 1273 * prepare_download | |
| 1274 * | |
| 1275 * Sets the attributes of a link to setup a file download using the given content. | |
| 1276 * If no link is provided then create one and click it. | |
| 1277 */ | |
| 1278 function prepare_download(content, mimetype, filename, link) { | |
| 1279 "use strict"; | |
| 1280 // if no link is provided then create one and click it | |
| 1281 var click_link = false; | |
| 1282 if (!link) { | |
| 1283 link = document.createElement("a"); | |
| 1284 click_link = true; | |
| 1285 } | |
| 1286 try { | |
| 1287 // Use a BLOB to convert the text into a data URL. | |
| 1288 // We could do this manually with a base 64 conversion. | |
| 1289 // This will only be supported on modern browsers, | |
| 1290 // hence the try block. | |
| 1291 var blob = new Blob([content], {type: mimetype}); | |
| 1292 var reader = new FileReader(); | |
| 1293 reader.onloadend = function() { | |
| 1294 // If we're lucky the browser will also support the download | |
| 1295 // attribute which will let us suggest a file name to save the link. | |
| 1296 // Otherwise it is likely that the filename will be unintelligible. | |
| 1297 link.setAttribute("download", filename); | |
| 1298 link.href = reader.result; | |
| 1299 if (click_link) { | |
| 1300 // must add the link to click it | |
| 1301 document.body.appendChild(link); | |
| 1302 link.click(); | |
| 1303 document.body.removeChild(link); | |
| 1304 } | |
| 1305 } | |
| 1306 reader.readAsDataURL(blob); | |
| 1307 } catch (error) { | |
| 1308 if (console && console.log) console.log(error); | |
| 1309 // probably an old browser | |
| 1310 link.href = ""; | |
| 1311 link.visible = false; | |
| 1312 } | |
| 1313 } | |
| 1314 | |
| 1315 /* | |
| 1316 * add_cell | |
| 1317 * | |
| 1318 * Add a cell to the table row. | |
| 1319 */ | |
| 1320 function add_cell(row, node, cls, click_action) { | |
| 1321 var cell = row.insertCell(row.cells.length); | |
| 1322 if (node) cell.appendChild(node); | |
| 1323 if (cls && cls !== "") cell.className = cls; | |
| 1324 if (click_action) cell.addEventListener("click", click_action, false); | |
| 1325 } | |
| 1326 | |
| 1327 /* | |
| 1328 * add_header_cell | |
| 1329 * | |
| 1330 * Add a header cell to the table row. | |
| 1331 */ | |
| 1332 function add_header_cell(row, node, help_topic, cls, colspan) { | |
| 1333 var th = document.createElement("th"); | |
| 1334 if (node) th.appendChild(node); | |
| 1335 if (help_topic && help_topic !== "") th.appendChild(help_button(help_topic)); | |
| 1336 if (cls && cls !== "") th.className = cls; | |
| 1337 if (typeof colspan == "number" && colspan > 1) th.colSpan = colspan; | |
| 1338 row.appendChild(th); | |
| 1339 } | |
| 1340 | |
| 1341 /* | |
| 1342 * add_text_cell | |
| 1343 * | |
| 1344 * Add a text cell to the table row. | |
| 1345 */ | |
| 1346 function add_text_cell(row, text, cls, action) { | |
| 1347 var node = null; | |
| 1348 if (typeof(text) != 'undefined') node = document.createTextNode(text); | |
| 1349 add_cell(row, node, cls, action); | |
| 1350 } | |
| 1351 | |
| 1352 /* | |
| 1353 * add_text_header_cell | |
| 1354 * | |
| 1355 * Add a text header cell to the table row. | |
| 1356 */ | |
| 1357 function add_text_header_cell(row, text, help_topic, cls, action, colspan) { | |
| 1358 var node = null; | |
| 1359 if (typeof(text) != 'undefined') { | |
| 1360 var nbsp = (help_topic ? "\u00A0" : ""); | |
| 1361 var str = "" + text; | |
| 1362 var parts = str.split(/\n/); | |
| 1363 if (parts.length === 1) { | |
| 1364 if (action) { | |
| 1365 node = document.createElement("span"); | |
| 1366 node.appendChild(document.createTextNode(str + nbsp)); | |
| 1367 } else { | |
| 1368 node = document.createTextNode(str + nbsp); | |
| 1369 } | |
| 1370 } else { | |
| 1371 node = document.createElement("span"); | |
| 1372 for (var i = 0; i < parts.length; i++) { | |
| 1373 if (i !== 0) { | |
| 1374 node.appendChild(document.createElement("br")); | |
| 1375 } | |
| 1376 node.appendChild(document.createTextNode(parts[i])); | |
| 1377 } | |
| 1378 } | |
| 1379 if (action) { | |
| 1380 node.addEventListener("click", action, false); | |
| 1381 node.style.cursor = "pointer"; | |
| 1382 } | |
| 1383 } | |
| 1384 add_header_cell(row, node, help_topic, cls, colspan); | |
| 1385 } | |
| 1386 | |
| 1387 function setup_help() { | |
| 1388 "use strict"; | |
| 1389 var help_buttons, i; | |
| 1390 help_buttons = document.querySelectorAll(".help:not(.active)"); | |
| 1391 for (i = 0; i < help_buttons.length; i++) { | |
| 1392 setup_help_button(help_buttons[i]); | |
| 1393 } | |
| 1394 } | |
| 1395 | |
| 1396 function setup_scrollpad() { | |
| 1397 "use strict"; | |
| 1398 if (document.getElementsByTagName('body')[0].hasAttribute("data-scrollpad") && document.getElementById("scrollpad") == null) { | |
| 1399 window.addEventListener("resize", update_scroll_pad, false); | |
| 1400 update_scroll_pad(); | |
| 1401 } | |
| 1402 } | |
| 1403 | |
| 1404 // anon function to avoid polluting global scope | |
| 1405 (function() { | |
| 1406 "use strict"; | |
| 1407 window.addEventListener("load", function load(evt) { | |
| 1408 window.removeEventListener("load", load, false); | |
| 1409 setup_help(); | |
| 1410 setup_scrollpad(); | |
| 1411 }, false); | |
| 1412 })(); | |
| 1413 | |
| 1414 /* | |
| 1415 * make_link | |
| 1416 * | |
| 1417 * Creates a text node and if a URL is specified it surrounds it with a link. | |
| 1418 * If the URL doesn't begin with "http://" it automatically adds it, as | |
| 1419 * relative links don't make much sense in this context. | |
| 1420 */ | |
| 1421 function make_link(text, url) { | |
| 1422 var textNode = null; | |
| 1423 var link = null; | |
| 1424 if (typeof text !== "undefined" && text !== null) textNode = document.createTextNode(text); | |
| 1425 if (typeof url === "string") { | |
| 1426 if (url.indexOf("//") == -1) { | |
| 1427 url = "http://" + url; | |
| 1428 } | |
| 1429 link = document.createElement('a'); | |
| 1430 link.href = url; | |
| 1431 if (textNode) link.appendChild(textNode); | |
| 1432 return link; | |
| 1433 } | |
| 1434 return textNode; | |
| 1435 } | |
| 1436 </script> | |
| 1437 <script> | |
| 1438 // | |
| 1439 // return true if any part of the passed element is visible in the viewport | |
| 1440 // | |
| 1441 function element_in_viewport(elem) { | |
| 1442 var rect; | |
| 1443 try { | |
| 1444 rect = elem.getBoundingClientRect(); | |
| 1445 } catch (e) { | |
| 1446 return false; | |
| 1447 } | |
| 1448 return ( | |
| 1449 rect.top < (window.innerHeight || document.body.clientHeight) && | |
| 1450 rect.bottom > 0 && | |
| 1451 rect.left < (window.innerWidth || document.body.clientWidth) && | |
| 1452 rect.right > 0 | |
| 1453 ); | |
| 1454 } | |
| 1455 | |
| 1456 // | |
| 1457 // Functions to delay a drawing task until it is required or it would not lag the display to do so | |
| 1458 // | |
| 1459 | |
| 1460 // a list of items still to be drawn | |
| 1461 var drawable_list = []; | |
| 1462 // the delay between drawing objects that are not currently visible | |
| 1463 var draw_delay = 1; | |
| 1464 // the delay after a user interaction | |
| 1465 var user_delay = 300; | |
| 1466 // the delay after a user has stopped scrolling and is viewing the stuff drawn on the current page | |
| 1467 var stop_delay = 300; | |
| 1468 // the timer handle; allows resetting of the timer after user interactions | |
| 1469 var draw_timer = null; | |
| 1470 | |
| 1471 // | |
| 1472 // Drawable | |
| 1473 // | |
| 1474 // elem - a page element which defines the position on the page that drawing is to be done | |
| 1475 // task - an object with the method run which takes care of painting the object | |
| 1476 // | |
| 1477 var Drawable = function(elem, task) { | |
| 1478 this.elem = elem; | |
| 1479 this.task = task; | |
| 1480 } | |
| 1481 | |
| 1482 // | |
| 1483 // Drawable.is_visible | |
| 1484 // | |
| 1485 // Determines if the element is visible in the viewport | |
| 1486 // | |
| 1487 Drawable.prototype.is_visible = function() { | |
| 1488 return element_in_viewport(this.elem); | |
| 1489 } | |
| 1490 | |
| 1491 // | |
| 1492 // Drawable.run | |
| 1493 // | |
| 1494 // Run the task held by the drawable | |
| 1495 Drawable.prototype.run = function() { | |
| 1496 if (this.task) this.task.run(); | |
| 1497 this.task = null; | |
| 1498 } | |
| 1499 | |
| 1500 // | |
| 1501 // Drawable.run | |
| 1502 // | |
| 1503 // Run the task iff visible | |
| 1504 // returns true if the task ran or has already run | |
| 1505 Drawable.prototype.run_visible = function() { | |
| 1506 if (this.task) { | |
| 1507 if (element_in_viewport(this.elem)) { | |
| 1508 this.task.run(); | |
| 1509 this.task = null; | |
| 1510 return true; | |
| 1511 } | |
| 1512 return false; | |
| 1513 } else { | |
| 1514 return true; | |
| 1515 } | |
| 1516 } | |
| 1517 | |
| 1518 // | |
| 1519 // draw_on_screen | |
| 1520 // | |
| 1521 // Checks each drawable object and draws those on screen. | |
| 1522 // | |
| 1523 function draw_on_screen() { | |
| 1524 var found = false; | |
| 1525 for (var i = 0; i < drawable_list.length; i++) { | |
| 1526 if (drawable_list[i].run_visible()) { | |
| 1527 drawable_list.splice(i--, 1); | |
| 1528 found = true; | |
| 1529 } | |
| 1530 } | |
| 1531 return found; | |
| 1532 } | |
| 1533 | |
| 1534 // | |
| 1535 // process_draw_tasks | |
| 1536 // | |
| 1537 // Called on a delay to process the next avaliable | |
| 1538 // draw task. | |
| 1539 // | |
| 1540 function process_draw_tasks() { | |
| 1541 var delay = draw_delay; | |
| 1542 draw_timer = null; | |
| 1543 if (drawable_list.length == 0) return; //no more tasks | |
| 1544 if (draw_on_screen()) { | |
| 1545 delay = stop_delay; //give the user a chance to scroll | |
| 1546 } else { | |
| 1547 //get next task | |
| 1548 var drawable = drawable_list.shift(); | |
| 1549 drawable.task.run(); | |
| 1550 } | |
| 1551 //allow UI updates between tasks | |
| 1552 draw_timer = window.setTimeout("process_draw_tasks()", delay); | |
| 1553 } | |
| 1554 | |
| 1555 // | |
| 1556 // delayed_process_draw_tasks | |
| 1557 // | |
| 1558 // Call process_draw_tasks after a short delay. | |
| 1559 // The delay serves to group multiple redundant events. | |
| 1560 // Should be set as event handler for onscroll and onresize. | |
| 1561 // | |
| 1562 function delayed_process_draw_tasks() { | |
| 1563 //reset the timer | |
| 1564 if (drawable_list.length > 0) { | |
| 1565 if (draw_timer != null) clearTimeout(draw_timer); | |
| 1566 draw_timer = window.setTimeout("process_draw_tasks()", user_delay); | |
| 1567 } | |
| 1568 } | |
| 1569 | |
| 1570 // | |
| 1571 // add_draw_task | |
| 1572 // | |
| 1573 // Add a drawing task to be called immediately if it is | |
| 1574 // visible, or to be called on a delay to reduce stuttering | |
| 1575 // effect on the web browser. | |
| 1576 function add_draw_task(elem, task) { | |
| 1577 drawable = new Drawable(elem, task); | |
| 1578 if (drawable.is_visible()) { | |
| 1579 task.run(); | |
| 1580 } else { | |
| 1581 drawable_list.push(drawable); | |
| 1582 //reset timer | |
| 1583 if (draw_timer != null) clearTimeout(draw_timer); | |
| 1584 draw_timer = window.setTimeout("process_draw_tasks()", user_delay); | |
| 1585 } | |
| 1586 } | |
| 1587 | |
| 1588 </script> | |
| 1589 <script> | |
| 1590 //====================================================================== | |
| 1591 // start Alphabet object | |
| 1592 //====================================================================== | |
| 1593 var Alphabet = function(alphabet, background) { | |
| 1594 "use strict"; | |
| 1595 var i, j, sym, aliases, complement, comp_e_sym, ambigs, generate_background; | |
| 1596 generate_background = (background == null); | |
| 1597 if (generate_background) { | |
| 1598 background = []; | |
| 1599 for (i = 0; i < alphabet.ncore; i++) background[i] = 1.0 / alphabet.ncore; | |
| 1600 } else if (alphabet.ncore != background.length) { | |
| 1601 throw new Error("The background length does not match the alphabet length."); | |
| 1602 } | |
| 1603 this.name = alphabet.name; | |
| 1604 this.like = (alphabet.like != null ? alphabet.like.toUpperCase() : null); | |
| 1605 this.ncore = alphabet.ncore; | |
| 1606 this.symbols = alphabet.symbols; | |
| 1607 this.background = background; | |
| 1608 this.genbg = generate_background; | |
| 1609 this.encode = {}; | |
| 1610 this.encode2core = {}; | |
| 1611 this.complement = {}; | |
| 1612 // check if all symbols are same case | |
| 1613 var seen_uc = false; | |
| 1614 var seen_lc = false; | |
| 1615 var check_case = function (syms) { | |
| 1616 var s, sym; | |
| 1617 if (typeof syms === "string") { | |
| 1618 for (s = 0; s < syms.length; s++) { | |
| 1619 sym = syms.charAt(s); | |
| 1620 if (sym >= 'a' && sym <= 'z') seen_lc = true; | |
| 1621 else if (sym >= 'A' && sym <= 'Z') seen_uc = true; | |
| 1622 } | |
| 1623 } | |
| 1624 }; | |
| 1625 for (i = 0; i < this.symbols.length; i++) { | |
| 1626 check_case(this.symbols[i].symbol); | |
| 1627 check_case(this.symbols[i].aliases); | |
| 1628 } | |
| 1629 // now map symbols to indexes | |
| 1630 var update_array = function(array, syms, index) { | |
| 1631 var s, sym; | |
| 1632 if (typeof syms === "string") { | |
| 1633 for (s = 0; s < syms.length; s++) { | |
| 1634 sym = syms.charAt(s); | |
| 1635 array[sym] = index; | |
| 1636 // when only a single case is used, then encode as case insensitive | |
| 1637 if (seen_uc != seen_lc) { | |
| 1638 if (sym >= 'a' && sym <= 'z') { | |
| 1639 array[sym.toUpperCase()] = index; | |
| 1640 } else if (sym >= 'A' && sym <= 'Z') { | |
| 1641 array[sym.toLowerCase()] = index; | |
| 1642 } | |
| 1643 } | |
| 1644 } | |
| 1645 } | |
| 1646 } | |
| 1647 // map core symbols to index | |
| 1648 for (i = 0; i < this.ncore; i++) { | |
| 1649 update_array(this.encode2core, this.symbols[i].symbol, i); | |
| 1650 update_array(this.encode, this.symbols[i].symbol, i); | |
| 1651 update_array(this.encode2core, this.symbols[i].aliases, i); | |
| 1652 update_array(this.encode, this.symbols[i].aliases, i); | |
| 1653 } | |
| 1654 // map ambigous symbols to index | |
| 1655 ambigs = {}; | |
| 1656 for (i = this.ncore; i < this.symbols.length; i++) { | |
| 1657 update_array(this.encode, this.symbols[i].symbol, i); | |
| 1658 update_array(this.encode, this.symbols[i].aliases, i); | |
| 1659 ambigs[this.symbols[i].equals] = i; | |
| 1660 } | |
| 1661 // determine complements | |
| 1662 for (i = 0; i < this.ncore; i++) { | |
| 1663 complement = this.symbols[i].complement; | |
| 1664 if (typeof complement === "string") { | |
| 1665 this.complement[i] = this.encode2core[complement]; | |
| 1666 } | |
| 1667 } | |
| 1668 next_symbol: | |
| 1669 for (i = this.ncore; i < this.symbols.length; i++) { | |
| 1670 complement = ""; | |
| 1671 for (j = 0; j < this.symbols[i].equals.length; j++) { | |
| 1672 comp_e_sym = this.complement[this.encode2core[this.symbols[i].equals.charAt(j)]]; | |
| 1673 if (typeof comp_e_sym !== "number") continue next_symbol; | |
| 1674 complement += this.symbols[comp_e_sym].symbol; | |
| 1675 } | |
| 1676 complement = complement.split("").sort().join(""); | |
| 1677 if (typeof ambigs[complement] === "number") { | |
| 1678 this.complement[i] = ambigs[complement]; | |
| 1679 } | |
| 1680 } | |
| 1681 // determine case insensitivity | |
| 1682 this.case_insensitive = true; | |
| 1683 if (seen_uc == seen_lc) { | |
| 1684 // when there is a mixture of cases it probably won't | |
| 1685 // be case insensitive but we still need to check | |
| 1686 loop: | |
| 1687 for (i = 0; i < this.symbols.length; i++) { | |
| 1688 sym = this.symbols[i].symbol; | |
| 1689 if (sym >= 'A' && sym <= 'Z') { | |
| 1690 if (this.encode[sym.toLowerCase()] != i) { | |
| 1691 this.case_insensitive = false; | |
| 1692 break loop; | |
| 1693 } | |
| 1694 } else if (sym >= 'a' && sym <= 'z') { | |
| 1695 if (this.encode[sym.toUpperCase()] != i) { | |
| 1696 this.case_insensitive = false; | |
| 1697 break loop; | |
| 1698 } | |
| 1699 } | |
| 1700 aliases = this.symbols[i].aliases; | |
| 1701 if (aliases != null) { | |
| 1702 for (j = 0; j < aliases.length; j++) { | |
| 1703 sym = aliases.charAt(j); | |
| 1704 if (sym >= 'A' && sym <= 'Z') { | |
| 1705 if (this.encode[sym.toLowerCase()] != i) { | |
| 1706 this.case_insensitive = false; | |
| 1707 break loop; | |
| 1708 } | |
| 1709 } else if (sym >= 'a' && sym <= 'z') { | |
| 1710 if (this.encode[sym.toUpperCase()] != i) { | |
| 1711 this.case_insensitive = false; | |
| 1712 break loop; | |
| 1713 } | |
| 1714 } | |
| 1715 } | |
| 1716 } | |
| 1717 } | |
| 1718 } | |
| 1719 // normalise aliases to remove the prime symbol and eliminate | |
| 1720 // the alternate cases when the alphabet is case insensitive | |
| 1721 var seen, out; | |
| 1722 for (i = 0; i < this.symbols.length; i++) { | |
| 1723 sym = this.symbols[i].symbol; | |
| 1724 aliases = this.symbols[i].aliases; | |
| 1725 if (typeof aliases != "string") aliases = ""; | |
| 1726 seen = {}; | |
| 1727 out = []; | |
| 1728 if (this.case_insensitive) { | |
| 1729 sym = sym.toUpperCase(); | |
| 1730 aliases = aliases.toUpperCase(); | |
| 1731 } | |
| 1732 seen[sym] = true; | |
| 1733 for (j = 0; j < aliases.length; j++) { | |
| 1734 if (!seen[aliases.charAt(j)]) { | |
| 1735 seen[aliases.charAt(j)] = true; | |
| 1736 out.push(aliases.charAt(j)); | |
| 1737 } | |
| 1738 } | |
| 1739 this.symbols[i].aliases = out.sort().join(""); | |
| 1740 } | |
| 1741 }; | |
| 1742 // return the name of the alphabet | |
| 1743 Alphabet.prototype.get_alphabet_name = function() { | |
| 1744 return this.name; | |
| 1745 }; | |
| 1746 // return if the alphabet can be complemented | |
| 1747 Alphabet.prototype.has_complement = function() { | |
| 1748 return (typeof this.symbols[0].complement === "string"); | |
| 1749 }; | |
| 1750 // return true if an uppercase letter has the same meaning as the lowercase form | |
| 1751 Alphabet.prototype.is_case_insensitive = function() { | |
| 1752 return this.case_insensitive; | |
| 1753 }; | |
| 1754 // return the information content of an alphabet letter | |
| 1755 Alphabet.prototype.get_ic = function() { | |
| 1756 return Math.log(this.ncore) / Math.LN2; | |
| 1757 }; | |
| 1758 // return the count of the core alphabet symbols | |
| 1759 Alphabet.prototype.get_size_core = function() { | |
| 1760 return this.ncore; | |
| 1761 }; | |
| 1762 // return the count of all alphabet symbols | |
| 1763 Alphabet.prototype.get_size_full = function() { | |
| 1764 return this.symbols.length; | |
| 1765 }; | |
| 1766 // return the symbol for the given alphabet index | |
| 1767 Alphabet.prototype.get_symbol = function(alph_index) { | |
| 1768 "use strict"; | |
| 1769 if (alph_index < 0 || alph_index >= this.symbols.length) { | |
| 1770 throw new Error("Alphabet index out of bounds"); | |
| 1771 } | |
| 1772 return this.symbols[alph_index].symbol; | |
| 1773 }; | |
| 1774 // return the aliases for the given alphabet index | |
| 1775 Alphabet.prototype.get_aliases = function(alph_index) { | |
| 1776 "use strict"; | |
| 1777 if (alph_index < 0 || alph_index >= this.symbols.length) { | |
| 1778 throw new Error("Alphabet index out of bounds"); | |
| 1779 } | |
| 1780 var sym_obj = this.symbols[alph_index]; | |
| 1781 return (sym_obj.aliases != null ? sym_obj.aliases : ""); | |
| 1782 }; | |
| 1783 // return the name for the given alphabet index | |
| 1784 Alphabet.prototype.get_name = function(alph_index) { | |
| 1785 "use strict"; | |
| 1786 var sym; | |
| 1787 if (alph_index < 0 || alph_index >= this.symbols.length) { | |
| 1788 throw new Error("Alphabet index out of bounds"); | |
| 1789 } | |
| 1790 sym = this.symbols[alph_index]; | |
| 1791 return (typeof sym.name === "string" ? sym.name : sym.symbol); | |
| 1792 }; | |
| 1793 // return the alphabet it is like or null | |
| 1794 Alphabet.prototype.get_like = function() { | |
| 1795 "use strict"; | |
| 1796 return this.like; | |
| 1797 }; | |
| 1798 // return the index of the complement for the given alphabet index | |
| 1799 Alphabet.prototype.get_complement = function(alph_index) { | |
| 1800 var comp_e_sym = this.complement[alph_index]; | |
| 1801 if (typeof comp_e_sym === "number") { | |
| 1802 return comp_e_sym; | |
| 1803 } else { | |
| 1804 return -1; | |
| 1805 } | |
| 1806 }; | |
| 1807 // return a string containing the core symbols | |
| 1808 Alphabet.prototype.get_symbols = function() { | |
| 1809 "use strict"; | |
| 1810 var i, core_symbols; | |
| 1811 core_symbols = ""; | |
| 1812 for (i = 0; i < this.ncore; i++) { | |
| 1813 core_symbols += this.symbols[i].symbol; | |
| 1814 } | |
| 1815 return core_symbols; | |
| 1816 }; | |
| 1817 // return if the background was not a uniform generated background | |
| 1818 Alphabet.prototype.has_bg = function() { | |
| 1819 "use strict"; | |
| 1820 return !this.genbg; | |
| 1821 }; | |
| 1822 // get the background frequency for the index | |
| 1823 Alphabet.prototype.get_bg_freq = function(alph_index) { | |
| 1824 "use strict"; | |
| 1825 var freq, i, symbols; | |
| 1826 if (alph_index >= 0) { | |
| 1827 if (alph_index < this.ncore) { | |
| 1828 return this.background[alph_index]; | |
| 1829 } else if (alph_index < this.symbols.length) { | |
| 1830 freq = 0; | |
| 1831 symbols = this.symbols[alph_index].equals; | |
| 1832 for (i = 0; i < symbols.length; i++) { | |
| 1833 freq += this.background[this.encode2core[symbols.charAt(i)]]; | |
| 1834 } | |
| 1835 return freq; | |
| 1836 } | |
| 1837 } | |
| 1838 throw new Error("The alphabet index is out of range."); | |
| 1839 }; | |
| 1840 // get the colour of the index | |
| 1841 Alphabet.prototype.get_colour = function(alph_index) { | |
| 1842 "use strict"; | |
| 1843 if (alph_index < 0 || alph_index >= this.symbols.length) { | |
| 1844 throw new Error("BAD_ALPHABET_INDEX"); | |
| 1845 } | |
| 1846 if (typeof this.symbols[alph_index].colour != "string") { | |
| 1847 return "black"; | |
| 1848 } | |
| 1849 return "#" + this.symbols[alph_index].colour; | |
| 1850 }; | |
| 1851 // get the rgb componets of the colour at the index | |
| 1852 Alphabet.prototype.get_rgb = function(alph_index) { | |
| 1853 "use strict"; | |
| 1854 if (alph_index < 0 || alph_index >= this.symbols.length) { | |
| 1855 throw new Error("BAD_ALPHABET_INDEX"); | |
| 1856 } | |
| 1857 if (typeof this.symbols[alph_index].colour != "string") { | |
| 1858 return {"red": 0, "green": 0, "blue": 0}; | |
| 1859 } | |
| 1860 var colour = this.symbols[alph_index].colour; | |
| 1861 var red = parseInt(colour.substr(0, 2), 16) / 255; | |
| 1862 var green = parseInt(colour.substr(2, 2), 16) / 255; | |
| 1863 var blue = parseInt(colour.substr(4, 2), 16) / 255; | |
| 1864 return {"red": red, "green": green, "blue": blue}; | |
| 1865 }; | |
| 1866 // convert a symbol into the index | |
| 1867 Alphabet.prototype.get_index = function(letter) { | |
| 1868 "use strict"; | |
| 1869 var alph_index; | |
| 1870 alph_index = this.encode[letter]; | |
| 1871 if (typeof alph_index === "undefined") { | |
| 1872 return -1; | |
| 1873 } | |
| 1874 return alph_index; | |
| 1875 }; | |
| 1876 // convert a symbol into the list of core indexes that it equals | |
| 1877 Alphabet.prototype.get_indexes = function(letter) { | |
| 1878 "use strict"; | |
| 1879 var alph_index, comprise_str, i, comprise_list; | |
| 1880 alph_index = this.encode[letter]; | |
| 1881 if (typeof alph_index === "undefined") { | |
| 1882 throw new Error("Unknown letter"); | |
| 1883 } | |
| 1884 comprise_str = this.symbols[alph_index].equals; | |
| 1885 comprise_list = []; | |
| 1886 if (typeof comprise_str == "string") { | |
| 1887 for (i = 0; i < comprise_str.length; i++) { | |
| 1888 comprise_list.push(this.encode2core[comprise_str.charAt(i)]); | |
| 1889 } | |
| 1890 } else { | |
| 1891 comprise_list.push(alph_index); | |
| 1892 } | |
| 1893 return comprise_list; | |
| 1894 }; | |
| 1895 // check if a symbol is the primary way of representing the symbol in the alphabet | |
| 1896 Alphabet.prototype.is_prime_symbol = function(letter) { | |
| 1897 var alph_index; | |
| 1898 alph_index = this.encode[letter]; | |
| 1899 if (alph_index == null) return false; | |
| 1900 if (this.is_case_insensitive()) { | |
| 1901 return (this.symbols[alph_index].symbol.toUpperCase() == letter.toUpperCase()); | |
| 1902 } else { | |
| 1903 return (this.symbols[alph_index].symbol == letter); | |
| 1904 } | |
| 1905 }; | |
| 1906 // compare 2 alphabets | |
| 1907 Alphabet.prototype.equals = function(other) { | |
| 1908 "use strict"; | |
| 1909 var i, sym1, sym2; | |
| 1910 // first check that it's actually an alphabet object | |
| 1911 if (!(typeof other === "object" && other != null && other instanceof Alphabet)) { | |
| 1912 return false; | |
| 1913 } | |
| 1914 // second shortcircuit if it's the same object | |
| 1915 if (this === other) return true; | |
| 1916 // compare | |
| 1917 if (this.name !== other.name) return false; | |
| 1918 if (this.ncore !== other.ncore) return false; | |
| 1919 if (this.symbols.length !== other.symbols.length) return false; | |
| 1920 for (i = 0; i < this.symbols.length; i++) { | |
| 1921 sym1 = this.symbols[i]; | |
| 1922 sym2 = other.symbols[i]; | |
| 1923 if (sym1.symbol !== sym2.symbol) return false; | |
| 1924 if (sym1.aliases !== sym2.aliases) return false; | |
| 1925 if (sym1.name !== sym2.name) return false; | |
| 1926 if (typeof sym1.colour !== typeof sym2.colour || | |
| 1927 (typeof sym1.colour === "string" && typeof sym2.colour === "string" && | |
| 1928 parseInt(sym1.colour, 16) != parseInt(sym2.colour, 16))) { | |
| 1929 return false; | |
| 1930 } | |
| 1931 if (sym1.complement !== sym2.complement) return false; | |
| 1932 if (sym1.equals !== sym2.equals) return false; | |
| 1933 } | |
| 1934 return true; | |
| 1935 }; | |
| 1936 Alphabet.prototype.check_core_subset = function(super_alph) { | |
| 1937 var complement_same = true; | |
| 1938 var seen_set = {}; | |
| 1939 var sub_i, sub_symbol, super_i, super_symbol; | |
| 1940 for (sub_i = 0; sub_i < this.ncore; sub_i++) { | |
| 1941 sub_symbol = this.symbols[sub_i]; | |
| 1942 super_i = super_alph.encode[sub_symbol.symbol]; | |
| 1943 if (super_i == null) return 0; | |
| 1944 super_symbol = super_alph.symbols[super_i]; | |
| 1945 if (seen_set[super_i]) return 0; | |
| 1946 seen_set[super_i] = true; | |
| 1947 // check complement | |
| 1948 if (sub_symbol.complement != null && super_symbol.complement != null) { | |
| 1949 if (super_alph.encode[sub_symbol.complement] != super_alph.encode[super_symbol.complement]) { | |
| 1950 complement_same = false; | |
| 1951 } | |
| 1952 } else if (sub_symbol.complement != null || super_symbol.complement != null) { | |
| 1953 complement_same = false; | |
| 1954 } | |
| 1955 } | |
| 1956 return (complement_same ? 1 : -1); | |
| 1957 }; | |
| 1958 // convert a sequence to its reverse complement | |
| 1959 Alphabet.prototype.invcomp_seq = function(seq) { | |
| 1960 "use strict"; | |
| 1961 var syms, i, e_sym, comp_e_sym; | |
| 1962 if (!this.has_complement()) throw new Error("Alphabet must be complementable"); | |
| 1963 syms = seq.split(""); | |
| 1964 for (i = 0; i < syms.length; i++) { | |
| 1965 e_sym = this.encode[syms[i]]; | |
| 1966 if (typeof e_sym === "undefined") { | |
| 1967 e_sym = this.ncore; // wildcard | |
| 1968 } | |
| 1969 comp_e_sym = this.complement[e_sym]; | |
| 1970 if (typeof comp_e_sym === "undefined") { | |
| 1971 comp_e_sym = e_sym; // not complementable | |
| 1972 } | |
| 1973 syms[i] = this.symbols[comp_e_sym].symbol; | |
| 1974 } | |
| 1975 return syms.reverse().join(""); | |
| 1976 }; | |
| 1977 // convert the alphabet to the text version | |
| 1978 Alphabet.prototype.as_text = function() { | |
| 1979 "use strict"; | |
| 1980 function name_as_text(name) { | |
| 1981 var i, c, out; | |
| 1982 out = "\""; | |
| 1983 for (i = 0; i < name.length; i++) { | |
| 1984 c = name.charAt(i); | |
| 1985 if (c == "\"") { | |
| 1986 out += "\\\""; | |
| 1987 } else if (c == "/") { | |
| 1988 out += "\\/"; | |
| 1989 } else if (c == "\\") { | |
| 1990 out += "\\\\"; | |
| 1991 } else { | |
| 1992 out += c; | |
| 1993 } | |
| 1994 } | |
| 1995 out += "\""; | |
| 1996 return out; | |
| 1997 } | |
| 1998 function symbol_as_text(sym) { | |
| 1999 var out; | |
| 2000 out = sym.symbol; | |
| 2001 if (typeof sym.name === "string" && sym.name != sym.symbol) { | |
| 2002 out += " " + name_as_text(sym.name); | |
| 2003 } | |
| 2004 if (typeof sym.colour === "string") { | |
| 2005 out += " " + sym.colour; | |
| 2006 } | |
| 2007 return out; | |
| 2008 } | |
| 2009 var out, i, j, c, sym; | |
| 2010 out = ""; | |
| 2011 // output core symbols with 2 way complements | |
| 2012 for (i = 0; i < this.ncore; i++) { | |
| 2013 c = this.complement[i]; | |
| 2014 if (typeof c === "number" && i < c && this.complement[c] === i) { | |
| 2015 out += symbol_as_text(this.symbols[i]) + " ~ " + symbol_as_text(this.symbols[c]) + "\n"; | |
| 2016 } | |
| 2017 } | |
| 2018 // output core symbols with no complement | |
| 2019 for (i = 0; i < this.ncore; i++) { | |
| 2020 if (typeof this.complement[i] === "undefined") { | |
| 2021 out += symbol_as_text(this.symbols[i]) + "\n"; | |
| 2022 } | |
| 2023 } | |
| 2024 // output ambiguous symbols that have comprising characters | |
| 2025 for (i = this.ncore; i < this.symbols.length; i++) { | |
| 2026 if (this.symbols[i].equals.length == 0) break; | |
| 2027 out += symbol_as_text(this.symbols[i]) + " = " + this.symbols[i].equals + "\n"; | |
| 2028 if (typeof this.symbols[i].aliases === "string") { | |
| 2029 for (j = 0; j < this.symbols[i].aliases.length; j++) { | |
| 2030 if (this.symbols[i].aliases.charAt(j) == this.symbols[i].symbol) continue; | |
| 2031 out += this.symbols[i].aliases.charAt(j) + " = " + this.symbols[i].equals + "\n"; | |
| 2032 } | |
| 2033 } | |
| 2034 } | |
| 2035 // output aliases of core symbols | |
| 2036 for (i = 0; i < this.ncore; i++) { | |
| 2037 if (typeof this.symbols[i].aliases === "string") { | |
| 2038 for (j = 0; j < this.symbols[i].aliases.length; j++) { | |
| 2039 if (this.symbols[i].aliases.charAt(j) == this.symbols[i].symbol) continue; | |
| 2040 out += this.symbols[i].aliases.charAt(j) + " = " + this.symbols[i].symbol + "\n"; | |
| 2041 } | |
| 2042 } | |
| 2043 } | |
| 2044 // output gap symbols | |
| 2045 i = this.symbols.length - 1; | |
| 2046 if (this.symbols[i].equals.length == 0) { | |
| 2047 out += symbol_as_text(this.symbols[i]) + " =\n"; | |
| 2048 if (typeof this.symbols[i].aliases === "string") { | |
| 2049 for (j = 0; j < this.symbols[i].aliases.length; j++) { | |
| 2050 if (this.symbols[i].aliases.charAt(j) == this.symbols[i].symbol) continue; | |
| 2051 out += this.symbols[i].aliases.charAt(j) + " =\n"; | |
| 2052 } | |
| 2053 } | |
| 2054 } | |
| 2055 return out; | |
| 2056 }; | |
| 2057 // output the alphabet as it appears in minimal MEME format | |
| 2058 Alphabet.prototype.as_meme = function() { | |
| 2059 "use strict"; | |
| 2060 function name_as_text(name) { | |
| 2061 var i, c, out; | |
| 2062 out = "\""; | |
| 2063 for (i = 0; i < name.length; i++) { | |
| 2064 c = name.charAt(i); | |
| 2065 if (c == "\"") { | |
| 2066 out += "\\\""; | |
| 2067 } else if (c == "/") { | |
| 2068 out += "\\/"; | |
| 2069 } else if (c == "\\") { | |
| 2070 out += "\\\\"; | |
| 2071 } else { | |
| 2072 out += c; | |
| 2073 } | |
| 2074 } | |
| 2075 out += "\""; | |
| 2076 return out; | |
| 2077 } | |
| 2078 if (this.equals(AlphStd.DNA)) { | |
| 2079 return "ALPHABET= ACGT\n"; | |
| 2080 } else if (this.equals(AlphStd.PROTEIN)) { | |
| 2081 return "ALPHABET= ACDEFGHIKLMNPQRSTVWY\n"; | |
| 2082 } else { | |
| 2083 return "ALPHABET" + | |
| 2084 (this.name != null ? " " + name_as_text(this.name) : "") + | |
| 2085 (this.like != null ? " " + this.like + "-LIKE" : "") + "\n" + | |
| 2086 this.as_text() + "END ALPHABET\n"; | |
| 2087 } | |
| 2088 }; | |
| 2089 | |
| 2090 // Returns a table showing all the letters in the alphabet | |
| 2091 Alphabet.prototype.as_table = function() { | |
| 2092 "use strict"; | |
| 2093 var i, j, row, th, td, aliases, equals, sym; | |
| 2094 var table = document.createElement("table"); | |
| 2095 // create the core symbol header | |
| 2096 row = table.insertRow(table.rows.length); | |
| 2097 th = document.createElement("th"); | |
| 2098 th.appendChild(document.createTextNode("Symbol(s)")); | |
| 2099 row.appendChild(th); | |
| 2100 th = document.createElement("th"); | |
| 2101 th.appendChild(document.createTextNode("Name")); | |
| 2102 row.appendChild(th); | |
| 2103 th = document.createElement("th"); | |
| 2104 if (this.has_complement()) { | |
| 2105 th.appendChild(document.createTextNode("Complement")); | |
| 2106 } | |
| 2107 row.appendChild(th); | |
| 2108 // list the core symbols | |
| 2109 for (i = 0; i < this.ncore; i++) { | |
| 2110 row = table.insertRow(table.rows.length); | |
| 2111 td = document.createElement("td"); | |
| 2112 if (this.symbols[i].colour != null) { | |
| 2113 td.style.color = '#' + this.symbols[i].colour; | |
| 2114 } | |
| 2115 td.appendChild(document.createTextNode(this.symbols[i].symbol)); | |
| 2116 aliases = this.get_aliases(i); | |
| 2117 if (aliases.length > 0) { | |
| 2118 td.appendChild(document.createTextNode(' ' + aliases.split('').join(' '))); | |
| 2119 } | |
| 2120 row.appendChild(td); | |
| 2121 td = document.createElement("td"); | |
| 2122 if (this.symbols[i].name != null) { | |
| 2123 td.appendChild(document.createTextNode(this.symbols[i].name)); | |
| 2124 } | |
| 2125 row.appendChild(td); | |
| 2126 td = document.createElement("td"); | |
| 2127 if (this.symbols[i].complement != null) { | |
| 2128 td.style.color = this.get_colour(this.get_index(this.symbols[i].complement)); | |
| 2129 td.appendChild(document.createTextNode(this.symbols[i].complement)); | |
| 2130 } | |
| 2131 row.appendChild(td); | |
| 2132 } | |
| 2133 // create the ambiguous symbol header | |
| 2134 row = table.insertRow(table.rows.length); | |
| 2135 th = document.createElement("th"); | |
| 2136 th.appendChild(document.createTextNode("Symbol(s)")); | |
| 2137 row.appendChild(th); | |
| 2138 th = document.createElement("th"); | |
| 2139 th.appendChild(document.createTextNode("Name")); | |
| 2140 row.appendChild(th); | |
| 2141 th = document.createElement("th"); | |
| 2142 th.appendChild(document.createTextNode("Matches")); | |
| 2143 row.appendChild(th); | |
| 2144 // list the ambiguous symbols | |
| 2145 for (i = this.ncore; i < this.symbols.length; i++) { | |
| 2146 row = table.insertRow(table.rows.length); | |
| 2147 td = document.createElement("td"); | |
| 2148 if (this.symbols[i].colour != null) { | |
| 2149 td.style.color = '#' + this.symbols[i].colour; | |
| 2150 } | |
| 2151 td.appendChild(document.createTextNode(this.symbols[i].symbol)); | |
| 2152 aliases = this.get_aliases(i); | |
| 2153 if (aliases.length > 0) { | |
| 2154 td.appendChild(document.createTextNode(' ' + aliases.split('').join(' '))); | |
| 2155 } | |
| 2156 row.appendChild(td); | |
| 2157 td = document.createElement("td"); | |
| 2158 if (this.symbols[i].name != null) { | |
| 2159 td.appendChild(document.createTextNode(this.symbols[i].name)); | |
| 2160 } | |
| 2161 row.appendChild(td); | |
| 2162 td = document.createElement("td"); | |
| 2163 equals = this.symbols[i].equals.split(''); | |
| 2164 for (j = 0; j < equals.length; j++) { | |
| 2165 if (j != 0) td.appendChild(document.createTextNode(' ')); | |
| 2166 sym = document.createElement("span"); | |
| 2167 sym.style.color = this.get_colour(this.get_index(equals[j])); | |
| 2168 sym.appendChild(document.createTextNode(equals[j])); | |
| 2169 td.appendChild(sym); | |
| 2170 } | |
| 2171 row.appendChild(td); | |
| 2172 } | |
| 2173 return table; | |
| 2174 }; | |
| 2175 | |
| 2176 // returns a dictionary of the colours for EPS | |
| 2177 Alphabet.prototype._as_eps_dict = function() { | |
| 2178 "use strict"; | |
| 2179 var i, sym, rgb; | |
| 2180 var out = "/fullColourDict <<\n"; | |
| 2181 for (i = 0; i < this.ncore; i++) { | |
| 2182 sym = this.get_symbol(i); | |
| 2183 sym = sym.replace(/\\/g, "\\\\"); | |
| 2184 sym = sym.replace(/\(/g, "\\("); | |
| 2185 sym = sym.replace(/\)/g, "\\)"); | |
| 2186 rgb = this.get_rgb(i); | |
| 2187 out += " (" + sym + ") [" + rgb.red.toFixed(4) + " " + rgb.green.toFixed(4) + " " + rgb.blue.toFixed(4) + "]\n"; | |
| 2188 } | |
| 2189 out += ">> def\n"; | |
| 2190 out += "/mutedColourDict <<\n"; | |
| 2191 for (i = 0; i < this.ncore; i++) { | |
| 2192 sym = this.get_symbol(i); | |
| 2193 sym = sym.replace(/\\/g, "\\\\"); | |
| 2194 sym = sym.replace(/\(/g, "\\("); | |
| 2195 sym = sym.replace(/\)/g, "\\)"); | |
| 2196 rgb = Alphabet.lighten_colour(this.get_rgb(i)); | |
| 2197 out += " (" + sym + ") [" + rgb.red.toFixed(4) + " " + rgb.green.toFixed(4) + " " + rgb.blue.toFixed(4) + "]\n"; | |
| 2198 } | |
| 2199 out += ">> def\n"; | |
| 2200 return out; | |
| 2201 }; | |
| 2202 | |
| 2203 // return the alphabet name or a list of primary symbols | |
| 2204 Alphabet.prototype.toString = function() { | |
| 2205 "use strict"; | |
| 2206 if (this.name != null) { | |
| 2207 return this.name; | |
| 2208 } else { | |
| 2209 return this.get_symbols(); | |
| 2210 } | |
| 2211 }; | |
| 2212 | |
| 2213 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| 2214 // Helper functions | |
| 2215 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| 2216 | |
| 2217 // Convert a colour specified in RGB colourspace values into LAB colourspace | |
| 2218 Alphabet.rgb2lab = function(rgb) { | |
| 2219 "use strict"; | |
| 2220 var xyzHelper, labHelper; | |
| 2221 // XYZ helper | |
| 2222 xyzHelper = function(value) { | |
| 2223 if (value > 0.0445) { | |
| 2224 value = (value + 0.055) / 1.055; | |
| 2225 value = Math.pow(value, 2.4); | |
| 2226 } else { | |
| 2227 value /= 12.92; | |
| 2228 } | |
| 2229 value *= 100; | |
| 2230 return value; | |
| 2231 }; | |
| 2232 // lab helper | |
| 2233 labHelper = function(value) { | |
| 2234 if (value > 0.008856) { | |
| 2235 value = Math.pow(value, 1.0 / 3.0); | |
| 2236 } else { | |
| 2237 value = (7.787 * value) + (16.0 / 116.0); | |
| 2238 } | |
| 2239 return value; | |
| 2240 }; | |
| 2241 // convert into XYZ colourspace | |
| 2242 var c1, c2, c3; | |
| 2243 if (typeof rgb == "number") { | |
| 2244 c1 = xyzHelper(((rgb >> 16) & 0xFF) / 255.0); | |
| 2245 c2 = xyzHelper(((rgb >> 8) & 0xFF) / 255.0); | |
| 2246 c3 = xyzHelper((rgb & 0xFF) / 255.0); | |
| 2247 } else { | |
| 2248 c1 = xyzHelper(rgb.red); | |
| 2249 c2 = xyzHelper(rgb.green); | |
| 2250 c3 = xyzHelper(rgb.blue); | |
| 2251 } | |
| 2252 var x = (c1 * 0.4124) + (c2 * 0.3576) + (c3 * 0.1805); | |
| 2253 var y = (c1 * 0.2126) + (c2 * 0.7152) + (c3 * 0.0722); | |
| 2254 var z = (c1 * 0.0193) + (c2 * 0.1192) + (c3 * 0.9505); | |
| 2255 // convert into Lab colourspace | |
| 2256 c1 = labHelper(x / 95.047); | |
| 2257 c2 = labHelper(y / 100.0); | |
| 2258 c3 = labHelper(z / 108.883); | |
| 2259 var l = (116.0 * c2) - 16; | |
| 2260 var a = 500.0 * (c1 - c2); | |
| 2261 var b = 200.0 * (c2 - c3); | |
| 2262 return {"l": l, "a": a, "b": b}; | |
| 2263 }; | |
| 2264 | |
| 2265 // Convert a colour specified in HSV colourspace into RGB colourspace | |
| 2266 Alphabet.hsv2rgb = function(hue, sat, value, output_object) { | |
| 2267 // achromatic (grey) | |
| 2268 var r = value; | |
| 2269 var g = value; | |
| 2270 var b = value; | |
| 2271 if (sat != 0) { | |
| 2272 var h = hue / 60.0; | |
| 2273 var i = Math.floor(h); | |
| 2274 var f = h - i; | |
| 2275 var p = value * (1.0 - sat); | |
| 2276 var q = value * (1.0 - (sat * f)); | |
| 2277 var t = value * (1.0 - (sat * (1.0 - f))); | |
| 2278 if (i == 0) { | |
| 2279 r = value; | |
| 2280 g = t; | |
| 2281 b = p; | |
| 2282 } else if (i == 1) { | |
| 2283 r = q; | |
| 2284 g = value; | |
| 2285 b = p; | |
| 2286 } else if (i == 2) { | |
| 2287 r = p; | |
| 2288 g = value; | |
| 2289 b = t; | |
| 2290 } else if (i == 3) { | |
| 2291 r = p; | |
| 2292 g = q; | |
| 2293 b = value; | |
| 2294 } else if (i == 4) { | |
| 2295 r = t; | |
| 2296 g = p; | |
| 2297 b = value; | |
| 2298 } else { | |
| 2299 r = value; | |
| 2300 g = p; | |
| 2301 b = q; | |
| 2302 } | |
| 2303 } | |
| 2304 if (output_object) { | |
| 2305 return {"red": r, "green": g, "blue": b}; | |
| 2306 } else { | |
| 2307 return (Math.floor(r * 255) << 15) | (Math.floor(g * 255) << 8) | (Math.floor(b * 255)); | |
| 2308 } | |
| 2309 }; | |
| 2310 | |
| 2311 // Calculate a distance score between two colours in LAB colourspace | |
| 2312 Alphabet.lab_dist = function(lab1, lab2) { | |
| 2313 var c1 = Math.sqrt((lab1.l * lab1.l) + (lab1.a * lab1.a)); | |
| 2314 var c2 = Math.sqrt((lab2.l * lab2.l) + (lab2.a * lab2.a)); | |
| 2315 var dc = c1 - c2; | |
| 2316 var dl = lab1.l - lab2.l; | |
| 2317 var da = lab1.a - lab2.a; | |
| 2318 var db = lab1.b - lab2.b; | |
| 2319 // we don't want NaN due to rounding errors so fudge things a bit... | |
| 2320 var dh = 0; | |
| 2321 var dh_squared = (da * da) + (db * db) - (dc * dc); | |
| 2322 if (dh_squared > 0) { | |
| 2323 dh = Math.sqrt(dh_squared); | |
| 2324 } | |
| 2325 var first = dl; | |
| 2326 var second = dc / (1.0 + (0.045 * c1)); | |
| 2327 var third = dh / (1.0 + (0.015 * c1)); | |
| 2328 return Math.sqrt((first * first) + (second * second) + (third * third)); | |
| 2329 }; | |
| 2330 | |
| 2331 // convert an RGB value into a HSL value | |
| 2332 Alphabet.rgb2hsl = function(rgb) { | |
| 2333 "use strict"; | |
| 2334 var min, max, delta, h, s, l, r, g, b; | |
| 2335 if (typeof rgb == "number") { | |
| 2336 r = ((rgb >> 16) & 0xFF) / 255.0; | |
| 2337 g = ((rgb >> 8) & 0xFF) / 255.0; | |
| 2338 b = (rgb & 0xFF) / 255.0; | |
| 2339 } else { | |
| 2340 r = rgb.red; | |
| 2341 g = rgb.green; | |
| 2342 b = rgb.blue; | |
| 2343 } | |
| 2344 min = Math.min(r, g, b); | |
| 2345 max = Math.max(r, g, b); | |
| 2346 delta = max - min; | |
| 2347 l = min + (delta / 2); | |
| 2348 if (max == min) { | |
| 2349 h = 0; // achromatic (grayscale) | |
| 2350 s = 0; | |
| 2351 } else { | |
| 2352 if (l > 0.5) { | |
| 2353 s = delta / (2 - max - min); | |
| 2354 } else { | |
| 2355 s = delta / (max + min); | |
| 2356 } | |
| 2357 if (max == r) { | |
| 2358 h = (g - b) / delta; | |
| 2359 if (g < b) h += 6; | |
| 2360 } else if (max == g) { | |
| 2361 h = ((b - r) / delta) + 2; | |
| 2362 } else { | |
| 2363 h = ((r - g) / delta) + 4; | |
| 2364 } | |
| 2365 h /= 6; | |
| 2366 } | |
| 2367 return {"h": h, "s": s, "l": l}; | |
| 2368 }; | |
| 2369 | |
| 2370 // convert a HSL value into an RGB value | |
| 2371 Alphabet.hsl2rgb = function(hsl, output_object) { | |
| 2372 "use strict"; | |
| 2373 function _hue(p, q, t) { | |
| 2374 "use strict"; | |
| 2375 if (t < 0) t += 1; | |
| 2376 else if (t > 1) t -= 1; | |
| 2377 if (t < (1.0 / 6.0)) { | |
| 2378 return p + ((q - p) * 6.0 * t); | |
| 2379 } else if (t < 0.5) { | |
| 2380 return q; | |
| 2381 } else if (t < (2.0 / 3.0)) { | |
| 2382 return p + ((q - p) * ((2.0 / 3.0) - t) * 6.0); | |
| 2383 } else { | |
| 2384 return p; | |
| 2385 } | |
| 2386 } | |
| 2387 var r, g, b, p, q; | |
| 2388 if (hsl.s == 0) { | |
| 2389 // achromatic (grayscale) | |
| 2390 r = hsl.l; | |
| 2391 g = hsl.l; | |
| 2392 b = hsl.l; | |
| 2393 } else { | |
| 2394 if (hsl.l < 0.5) { | |
| 2395 q = hsl.l * (1 + hsl.s); | |
| 2396 } else { | |
| 2397 q = hsl.l + hsl.s - (hsl.l * hsl.s); | |
| 2398 } | |
| 2399 p = (2 * hsl.l) - q; | |
| 2400 r = _hue(p, q, hsl.h + (1.0 / 3.0)); | |
| 2401 g = _hue(p, q, hsl.h); | |
| 2402 b = _hue(p, q, hsl.h - (1.0 / 3.0)); | |
| 2403 } | |
| 2404 if (output_object) { | |
| 2405 return {"red": r, "green": g, "blue": b}; | |
| 2406 } else { | |
| 2407 return (Math.floor(r * 255) << 15) | (Math.floor(g * 255) << 8) | (Math.floor(b * 255)); | |
| 2408 } | |
| 2409 }; | |
| 2410 | |
| 2411 Alphabet.lighten_colour = function(rgb) { | |
| 2412 "use strict"; | |
| 2413 var hsl = Alphabet.rgb2hsl(rgb); | |
| 2414 hsl.l += (1.0 - hsl.l) * 2 / 3; | |
| 2415 return Alphabet.hsl2rgb(hsl, typeof rgb != "number"); | |
| 2416 }; | |
| 2417 | |
| 2418 //====================================================================== | |
| 2419 // end Alphabet object | |
| 2420 //====================================================================== | |
| 2421 | |
| 2422 //====================================================================== | |
| 2423 // start StandardAlphabet object | |
| 2424 //====================================================================== | |
| 2425 | |
| 2426 // an extension of the alphabet object to support some additional fields | |
| 2427 // only present in standard alphabets. | |
| 2428 var StandardAlphabet = function(enum_code, enum_name, alphabet_data) { | |
| 2429 Alphabet.apply(this, [alphabet_data]); | |
| 2430 this.enum_code = enum_code; | |
| 2431 this.enum_name = enum_name; | |
| 2432 }; | |
| 2433 StandardAlphabet.prototype = Alphabet.prototype; | |
| 2434 StandardAlphabet.prototype.constructor = StandardAlphabet; | |
| 2435 | |
| 2436 // A unique code for this standard alphabet. | |
| 2437 // This code will be a power of 2 to enable creation of bitsets for | |
| 2438 // a selection of standard alphabets. | |
| 2439 StandardAlphabet.prototype.get_code = function() { | |
| 2440 return this.enum_code; | |
| 2441 }; | |
| 2442 | |
| 2443 // A unique name for this standard alphabet. | |
| 2444 // this name will be all upper case and the same as the property that | |
| 2445 // refers to this alphabet in the AlphStd collection. | |
| 2446 StandardAlphabet.prototype.get_enum = function() { | |
| 2447 return this.enum_name; | |
| 2448 }; | |
| 2449 | |
| 2450 //====================================================================== | |
| 2451 // end StandardAlphabet object | |
| 2452 //====================================================================== | |
| 2453 | |
| 2454 // A collection of standard alphabets. | |
| 2455 var AlphStd = { | |
| 2456 RNA: new StandardAlphabet(1, "RNA", { | |
| 2457 "name": "RNA", | |
| 2458 "like": "RNA", | |
| 2459 "ncore": 4, | |
| 2460 "symbols": [ | |
| 2461 {"symbol": "A", "name": "Adenine", "colour": "CC0000"}, | |
| 2462 {"symbol": "C", "name": "Cytosine", "colour": "0000CC"}, | |
| 2463 {"symbol": "G", "name": "Guanine", "colour": "FFB300"}, | |
| 2464 {"symbol": "U", "name": "Uracil", "colour": "008000", | |
| 2465 "aliases": "T"}, | |
| 2466 {"symbol": "N", "name": "Any base", "equals": "ACGU", "aliases": "X."}, | |
| 2467 {"symbol": "V", "name": "Not U", "equals": "ACG"}, | |
| 2468 {"symbol": "H", "name": "Not G", "equals": "ACU"}, | |
| 2469 {"symbol": "D", "name": "Not C", "equals": "AGU"}, | |
| 2470 {"symbol": "B", "name": "Not A", "equals": "CGU"}, | |
| 2471 {"symbol": "M", "name": "Amino", "equals": "AC"}, | |
| 2472 {"symbol": "R", "name": "Purine", "equals": "AG"}, | |
| 2473 {"symbol": "W", "name": "Weak", "equals": "AU"}, | |
| 2474 {"symbol": "S", "name": "Strong", "equals": "CG"}, | |
| 2475 {"symbol": "Y", "name": "Pyrimidine", "equals": "CU"}, | |
| 2476 {"symbol": "K", "name": "Keto", "equals": "GU"} | |
| 2477 ] | |
| 2478 }), | |
| 2479 DNA: new StandardAlphabet(2, "DNA", { | |
| 2480 "name": "DNA", | |
| 2481 "like": "DNA", | |
| 2482 "ncore": 4, | |
| 2483 "symbols": [ | |
| 2484 {"symbol": "A", "name": "Adenine", "colour": "CC0000", "complement": "T"}, | |
| 2485 {"symbol": "C", "name": "Cytosine", "colour": "0000CC", "complement": "G"}, | |
| 2486 {"symbol": "G", "name": "Guanine", "colour": "FFB300", "complement": "C"}, | |
| 2487 {"symbol": "T", "name": "Thymine", "colour": "008000", "complement": "A", | |
| 2488 "aliases": "U"}, | |
| 2489 {"symbol": "N", "name": "Any base", "equals": "ACGT", "aliases": "X."}, | |
| 2490 {"symbol": "V", "name": "Not T", "equals": "ACG"}, | |
| 2491 {"symbol": "H", "name": "Not G", "equals": "ACT"}, | |
| 2492 {"symbol": "D", "name": "Not C", "equals": "AGT"}, | |
| 2493 {"symbol": "B", "name": "Not A", "equals": "CGT"}, | |
| 2494 {"symbol": "M", "name": "Amino", "equals": "AC"}, | |
| 2495 {"symbol": "R", "name": "Purine", "equals": "AG"}, | |
| 2496 {"symbol": "W", "name": "Weak", "equals": "AT"}, | |
| 2497 {"symbol": "S", "name": "Strong", "equals": "CG"}, | |
| 2498 {"symbol": "Y", "name": "Pyrimidine", "equals": "CT"}, | |
| 2499 {"symbol": "K", "name": "Keto", "equals": "GT"} | |
| 2500 ] | |
| 2501 }), | |
| 2502 PROTEIN: new StandardAlphabet(4, "PROTEIN", { | |
| 2503 "name": "Protein", | |
| 2504 "like": "PROTEIN", | |
| 2505 "ncore": 20, | |
| 2506 "symbols": [ | |
| 2507 {"symbol": "A", "name": "Alanine", "colour": "0000CC"}, | |
| 2508 {"symbol": "C", "name": "Cysteine", "colour": "0000CC"}, | |
| 2509 {"symbol": "D", "name": "Aspartic acid", "colour": "FF00FF"}, | |
| 2510 {"symbol": "E", "name": "Glutamic acid", "colour": "FF00FF"}, | |
| 2511 {"symbol": "F", "name": "Phenylalanine", "colour": "0000CC"}, | |
| 2512 {"symbol": "G", "name": "Glycine", "colour": "FFB300"}, | |
| 2513 {"symbol": "H", "name": "Histidine", "colour": "FFCCCC"}, | |
| 2514 {"symbol": "I", "name": "Isoleucine", "colour": "0000CC"}, | |
| 2515 {"symbol": "K", "name": "Lysine", "colour": "CC0000"}, | |
| 2516 {"symbol": "L", "name": "Leucine", "colour": "0000CC"}, | |
| 2517 {"symbol": "M", "name": "Methionine", "colour": "0000CC"}, | |
| 2518 {"symbol": "N", "name": "Asparagine", "colour": "008000"}, | |
| 2519 {"symbol": "P", "name": "Proline", "colour": "FFFF00"}, | |
| 2520 {"symbol": "Q", "name": "Glutamine", "colour": "008000"}, | |
| 2521 {"symbol": "R", "name": "Arginine", "colour": "CC0000"}, | |
| 2522 {"symbol": "S", "name": "Serine", "colour": "008000"}, | |
| 2523 {"symbol": "T", "name": "Threonine", "colour": "008000"}, | |
| 2524 {"symbol": "V", "name": "Valine", "colour": "0000CC"}, | |
| 2525 {"symbol": "W", "name": "Tryptophan", "colour": "0000CC"}, | |
| 2526 {"symbol": "Y", "name": "Tyrosine", "colour": "33E6CC"}, | |
| 2527 {"symbol": "X", "name": "Any amino acid", "equals": "ACDEFGHIKLMNPQRSTVWY", "aliases": "*."}, | |
| 2528 {"symbol": "B", "name": "Asparagine or Aspartic acid", "equals": "DN"}, | |
| 2529 {"symbol": "Z", "name": "Glutamine or Glutamic acid", "equals": "EQ"}, | |
| 2530 {"symbol": "J", "name": "Leucine or Isoleucine", "equals": "IL"} | |
| 2531 ] | |
| 2532 }) | |
| 2533 }; | |
| 2534 | |
| 2535 //====================================================================== | |
| 2536 // start Symbol object | |
| 2537 //====================================================================== | |
| 2538 var Symbol = function(alph_index, scale, alphabet) { | |
| 2539 "use strict"; | |
| 2540 //variable prototype | |
| 2541 this.symbol = alphabet.get_symbol(alph_index); | |
| 2542 this.scale = scale; | |
| 2543 this.colour = alphabet.get_colour(alph_index); | |
| 2544 }; | |
| 2545 | |
| 2546 Symbol.prototype.get_symbol = function() { | |
| 2547 "use strict"; | |
| 2548 return this.symbol; | |
| 2549 }; | |
| 2550 | |
| 2551 Symbol.prototype.get_scale = function() { | |
| 2552 "use strict"; | |
| 2553 return this.scale; | |
| 2554 }; | |
| 2555 | |
| 2556 Symbol.prototype.get_colour = function() { | |
| 2557 "use strict"; | |
| 2558 return this.colour; | |
| 2559 }; | |
| 2560 | |
| 2561 Symbol.prototype.toString = function() { | |
| 2562 "use strict"; | |
| 2563 return this.symbol + " " + (Math.round(this.scale*1000)/10) + "%"; | |
| 2564 }; | |
| 2565 | |
| 2566 function compare_symbol(sym1, sym2) { | |
| 2567 "use strict"; | |
| 2568 if (sym1.get_scale() < sym2.get_scale()) { | |
| 2569 return -1; | |
| 2570 } else if (sym1.get_scale() > sym2.get_scale()) { | |
| 2571 return 1; | |
| 2572 } else { | |
| 2573 return 0; | |
| 2574 } | |
| 2575 } | |
| 2576 //====================================================================== | |
| 2577 // end Symbol object | |
| 2578 //====================================================================== | |
| 2579 | |
| 2580 //====================================================================== | |
| 2581 // start Pspm object | |
| 2582 //====================================================================== | |
| 2583 var Pspm = function(matrix, name, ltrim, rtrim, nsites, evalue, pssm, alt) { | |
| 2584 "use strict"; | |
| 2585 var row, col, data, row_sum, delta, evalue_re; | |
| 2586 if (typeof name !== "string") { | |
| 2587 name = ""; | |
| 2588 } | |
| 2589 this.name = name; | |
| 2590 //construct | |
| 2591 if (matrix instanceof Pspm) { | |
| 2592 // copy constructor | |
| 2593 this.alph_length = matrix.alph_length; | |
| 2594 this.motif_length = matrix.motif_length; | |
| 2595 this.name = matrix.name; | |
| 2596 this.alt = matrix.alt; | |
| 2597 this.nsites = matrix.nsites; | |
| 2598 this.evalue = matrix.evalue; | |
| 2599 this.ltrim = matrix.ltrim; | |
| 2600 this.rtrim = matrix.rtrim; | |
| 2601 this.pspm = []; | |
| 2602 for (row = 0; row < matrix.motif_length; row++) { | |
| 2603 this.pspm[row] = []; | |
| 2604 for (col = 0; col < matrix.alph_length; col++) { | |
| 2605 this.pspm[row][col] = matrix.pspm[row][col]; | |
| 2606 } | |
| 2607 } | |
| 2608 if (matrix.pssm != null) { | |
| 2609 this.pssm = []; | |
| 2610 for (row = 0; row < matrix.motif_length; row++) { | |
| 2611 this.pspm[row] = []; | |
| 2612 for (col = 0; col < matrix.alph_length; col++) { | |
| 2613 this.pssm[row][col] = matrix.pssm[row][col]; | |
| 2614 } | |
| 2615 } | |
| 2616 } | |
| 2617 } else { | |
| 2618 // check parameters | |
| 2619 if (ltrim == null) { | |
| 2620 ltrim = 0; | |
| 2621 } else if (typeof ltrim !== "number" || ltrim % 1 !== 0 || ltrim < 0) { | |
| 2622 throw new Error("ltrim must be a non-negative integer, got: " + ltrim); | |
| 2623 } | |
| 2624 if (rtrim == null) { | |
| 2625 rtrim = 0; | |
| 2626 } else if (typeof rtrim !== "number" || rtrim % 1 !== 0 || rtrim < 0) { | |
| 2627 throw new Error("rtrim must be a non-negative integer, got: " + rtrim); | |
| 2628 } | |
| 2629 if (nsites != null) { | |
| 2630 if (typeof nsites !== "number" || nsites < 0) { | |
| 2631 throw new Error("nsites must be a positive number, got: " + nsites); | |
| 2632 } else if (nsites == 0) { | |
| 2633 nsites = null; | |
| 2634 } | |
| 2635 } | |
| 2636 if (evalue != null) { | |
| 2637 if (typeof evalue === "number") { | |
| 2638 if (evalue < 0) { | |
| 2639 throw new Error("evalue must be a non-negative number, got: " + evalue); | |
| 2640 } | |
| 2641 } else if (typeof evalue === "string") { | |
| 2642 evalue_re = /^((?:[+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?)|inf)$/; | |
| 2643 if (!evalue_re.test(evalue)) { | |
| 2644 throw new Error("evalue must be a non-negative number, got: " + evalue); | |
| 2645 } | |
| 2646 } else { | |
| 2647 throw new Error("evalue must be a non-negative number, got: " + evalue); | |
| 2648 } | |
| 2649 } | |
| 2650 // set properties | |
| 2651 this.name = name; | |
| 2652 this.alt = alt; | |
| 2653 this.nsites = nsites; | |
| 2654 this.evalue = evalue; | |
| 2655 this.ltrim = ltrim; | |
| 2656 this.rtrim = rtrim; | |
| 2657 if (typeof matrix === "string") { | |
| 2658 // string constructor | |
| 2659 data = parse_pspm_string(matrix); | |
| 2660 this.alph_length = data["alph_length"]; | |
| 2661 this.motif_length = data["motif_length"]; | |
| 2662 this.pspm = data["pspm"]; | |
| 2663 if (this.evalue == null) { | |
| 2664 if (data["evalue"] != null) { | |
| 2665 this.evalue = data["evalue"]; | |
| 2666 } else { | |
| 2667 this.evalue = 0; | |
| 2668 } | |
| 2669 } | |
| 2670 if (this.nsites == null) { | |
| 2671 if (typeof data["nsites"] === "number") { | |
| 2672 this.nsites = data["nsites"]; | |
| 2673 } else { | |
| 2674 this.nsites = 20; | |
| 2675 } | |
| 2676 } | |
| 2677 } else { | |
| 2678 // assume pspm is a nested array | |
| 2679 this.motif_length = matrix.length; | |
| 2680 this.alph_length = (matrix.length > 0 ? matrix[0].length : 0); | |
| 2681 if (this.nsites == null) { | |
| 2682 this.nsites = 20; | |
| 2683 } | |
| 2684 if (this.evalue == null) { | |
| 2685 this.evalue = 0; | |
| 2686 } | |
| 2687 this.pspm = []; | |
| 2688 // copy pspm and check | |
| 2689 for (row = 0; row < this.motif_length; row++) { | |
| 2690 if (this.alph_length != matrix[row].length) { | |
| 2691 throw new Error("COLUMN_MISMATCH"); | |
| 2692 } | |
| 2693 this.pspm[row] = []; | |
| 2694 row_sum = 0; | |
| 2695 for (col = 0; col < this.alph_length; col++) { | |
| 2696 this.pspm[row][col] = matrix[row][col]; | |
| 2697 row_sum += this.pspm[row][col]; | |
| 2698 } | |
| 2699 delta = 0.1; | |
| 2700 if (isNaN(row_sum) || (row_sum > 1 && (row_sum - 1) > delta) || | |
| 2701 (row_sum < 1 && (1 - row_sum) > delta)) { | |
| 2702 throw new Error("INVALID_SUM"); | |
| 2703 } | |
| 2704 } | |
| 2705 // copy pssm | |
| 2706 if (pssm != null) { | |
| 2707 this.pssm = []; | |
| 2708 for (row = 0; row < this.motif_length; row++) { | |
| 2709 this.pssm[row] = []; | |
| 2710 for (col = 0; col < this.alph_length; col++) { | |
| 2711 this.pssm[row][col] = pssm[row][col]; | |
| 2712 } | |
| 2713 } | |
| 2714 } | |
| 2715 } | |
| 2716 } | |
| 2717 }; | |
| 2718 | |
| 2719 Pspm.prototype.copy = function() { | |
| 2720 "use strict"; | |
| 2721 return new Pspm(this); | |
| 2722 }; | |
| 2723 | |
| 2724 Pspm.prototype.reverse = function() { | |
| 2725 "use strict"; | |
| 2726 var x, y, temp, temp_trim; | |
| 2727 //reverse | |
| 2728 x = 0; | |
| 2729 y = this.motif_length-1; | |
| 2730 while (x < y) { | |
| 2731 temp = this.pspm[x]; | |
| 2732 this.pspm[x] = this.pspm[y]; | |
| 2733 this.pspm[y] = temp; | |
| 2734 x++; | |
| 2735 y--; | |
| 2736 } | |
| 2737 // reverse pssm (if defined) | |
| 2738 if (typeof this.pssm !== "undefined") { | |
| 2739 //reverse | |
| 2740 x = 0; | |
| 2741 y = this.motif_length-1; | |
| 2742 while (x < y) { | |
| 2743 temp = this.pssm[x]; | |
| 2744 this.pspm[x] = this.pssm[y]; | |
| 2745 this.pssm[y] = temp; | |
| 2746 x++; | |
| 2747 y--; | |
| 2748 } | |
| 2749 } | |
| 2750 //swap triming | |
| 2751 temp_trim = this.ltrim; | |
| 2752 this.ltrim = this.rtrim; | |
| 2753 this.rtrim = temp_trim; | |
| 2754 return this; //allow function chaining... | |
| 2755 }; | |
| 2756 | |
| 2757 Pspm.prototype.reverse_complement = function(alphabet) { | |
| 2758 "use strict"; | |
| 2759 var x, y, temp, i, row, c, temp_trim; | |
| 2760 if (this.alph_length != alphabet.get_size_core()) { | |
| 2761 throw new Error("The alphabet size does not match the size of the pspm."); | |
| 2762 } | |
| 2763 if (!alphabet.has_complement()) { | |
| 2764 throw new Error("The specified alphabet can not be complemented."); | |
| 2765 } | |
| 2766 // reverse motif | |
| 2767 this.reverse(); | |
| 2768 //complement | |
| 2769 for (x = 0; x < this.motif_length; x++) { | |
| 2770 row = this.pspm[x]; | |
| 2771 for (i = 0; i < row.length; i++) { | |
| 2772 c = alphabet.get_complement(i); | |
| 2773 if (c < i) continue; | |
| 2774 temp = row[i]; | |
| 2775 row[i] = row[c]; | |
| 2776 row[c] = temp; | |
| 2777 } | |
| 2778 } | |
| 2779 // complement pssm (if defined) | |
| 2780 if (typeof this.pssm !== "undefined") { | |
| 2781 //complement | |
| 2782 for (x = 0; x < this.motif_length; x++) { | |
| 2783 row = this.pssm[x]; | |
| 2784 for (i = 0; i < row.length; i++) { | |
| 2785 c = alphabet.get_complement(i); | |
| 2786 if (c < i) continue; | |
| 2787 temp = row[i]; | |
| 2788 row[i] = row[c]; | |
| 2789 row[c] = temp; | |
| 2790 } | |
| 2791 } | |
| 2792 } | |
| 2793 return this; //allow function chaining... | |
| 2794 }; | |
| 2795 | |
| 2796 Pspm.prototype.get_stack = function(position, alphabet, ssc) { | |
| 2797 "use strict"; | |
| 2798 var row, stack_ic, alphabet_ic, stack, i, sym; | |
| 2799 if (this.alph_length != alphabet.get_size_core()) { | |
| 2800 throw new Error("The alphabet size does not match the size of the pspm."); | |
| 2801 } | |
| 2802 row = this.pspm[position]; | |
| 2803 stack_ic = this.get_stack_ic(position, alphabet); | |
| 2804 if (ssc) stack_ic -= this.get_error(alphabet); | |
| 2805 alphabet_ic = alphabet.get_ic(); | |
| 2806 stack = []; | |
| 2807 for (i = 0; i < this.alph_length; i++) { | |
| 2808 sym = new Symbol(i, row[i]*stack_ic/alphabet_ic, alphabet); | |
| 2809 if (sym.get_scale() <= 0) { | |
| 2810 continue; | |
| 2811 } | |
| 2812 stack.push(sym); | |
| 2813 } | |
| 2814 stack.sort(compare_symbol); | |
| 2815 return stack; | |
| 2816 }; | |
| 2817 | |
| 2818 Pspm.prototype.get_stack_ic = function(position, alphabet) { | |
| 2819 "use strict"; | |
| 2820 var row, H, i; | |
| 2821 if (this.alph_length != alphabet.get_size_core()) { | |
| 2822 throw new Error("The alphabet size does not match the size fo the pspm."); | |
| 2823 } | |
| 2824 row = this.pspm[position]; | |
| 2825 H = 0; | |
| 2826 for (i = 0; i < this.alph_length; i++) { | |
| 2827 if (row[i] === 0) { | |
| 2828 continue; | |
| 2829 } | |
| 2830 H -= (row[i] * (Math.log(row[i]) / Math.LN2)); | |
| 2831 } | |
| 2832 return alphabet.get_ic() - H; | |
| 2833 }; | |
| 2834 | |
| 2835 Pspm.prototype.get_error = function(alphabet) { | |
| 2836 "use strict"; | |
| 2837 if (this.nsites === 0) { | |
| 2838 return 0; | |
| 2839 } | |
| 2840 return (alphabet.get_size_core()-1) / (2 * Math.LN2 * this.nsites); | |
| 2841 }; | |
| 2842 | |
| 2843 Pspm.prototype.get_motif_length = function() { | |
| 2844 "use strict"; | |
| 2845 return this.motif_length; | |
| 2846 }; | |
| 2847 | |
| 2848 Pspm.prototype.get_alph_length = function() { | |
| 2849 "use strict"; | |
| 2850 return this.alph_length; | |
| 2851 }; | |
| 2852 | |
| 2853 Pspm.prototype.get_left_trim = function() { | |
| 2854 "use strict"; | |
| 2855 return this.ltrim; | |
| 2856 }; | |
| 2857 | |
| 2858 Pspm.prototype.get_right_trim = function() { | |
| 2859 "use strict"; | |
| 2860 return this.rtrim; | |
| 2861 }; | |
| 2862 | |
| 2863 Pspm.prototype.as_best_match = function(alphabet) { | |
| 2864 "use strict"; | |
| 2865 var match, odds, best_odds, best_index; | |
| 2866 var i, j; | |
| 2867 match = ""; | |
| 2868 for (i = 0; i < this.motif_length; i++) { | |
| 2869 best_index = 0; | |
| 2870 best_odds = this.pspm[i][0] / alphabet.get_bg_freq(0); | |
| 2871 for (j = 1; j < this.alph_length; j++) { | |
| 2872 odds = this.pspm[i][j] / alphabet.get_bg_freq(j); | |
| 2873 if (odds > best_odds) { | |
| 2874 best_odds = odds; | |
| 2875 best_index = j; | |
| 2876 } | |
| 2877 } | |
| 2878 match += alphabet.get_symbol(best_index); | |
| 2879 } | |
| 2880 return match; | |
| 2881 }; | |
| 2882 | |
| 2883 Pspm.prototype.as_count_matrix = function() { | |
| 2884 "use strict"; | |
| 2885 var count, count_text, text; | |
| 2886 var i, j; | |
| 2887 text = ""; | |
| 2888 for (i = 0; i < this.motif_length; i++) { | |
| 2889 if (i !== 0) { | |
| 2890 text += "\n"; | |
| 2891 } | |
| 2892 for (j = 0; j < this.alph_length; j++) { | |
| 2893 if (j !== 0) { | |
| 2894 text += " "; | |
| 2895 } | |
| 2896 count = Math.round(this.nsites * this.pspm[i][j]); | |
| 2897 count_text = "" + count; | |
| 2898 // pad up to length of 4 | |
| 2899 if (count_text.length < 4) { | |
| 2900 text += (new Array(5 - count_text.length)).join(" ") + count_text; | |
| 2901 } else { | |
| 2902 text += count_text; | |
| 2903 } | |
| 2904 } | |
| 2905 } | |
| 2906 return text; | |
| 2907 }; | |
| 2908 | |
| 2909 Pspm.prototype.as_probability_matrix = function() { | |
| 2910 "use strict"; | |
| 2911 var text; | |
| 2912 var i, j; | |
| 2913 text = ""; | |
| 2914 for (i = 0; i < this.motif_length; i++) { | |
| 2915 if (i !== 0) { | |
| 2916 text += "\n"; | |
| 2917 } | |
| 2918 for (j = 0; j < this.alph_length; j++) { | |
| 2919 if (j !== 0) { | |
| 2920 text += " "; | |
| 2921 } | |
| 2922 text += this.pspm[i][j].toFixed(6); | |
| 2923 } | |
| 2924 } | |
| 2925 return text; | |
| 2926 }; | |
| 2927 | |
| 2928 Pspm.prototype.as_score_matrix = function(alphabet, pseudo) { | |
| 2929 "use strict"; | |
| 2930 var me, score, out, row, col, score_text; | |
| 2931 me = this; | |
| 2932 if (typeof this.pssm === "undefined") { | |
| 2933 if (!(typeof alphabet === "object" && alphabet != null && alphabet instanceof Alphabet)) { | |
| 2934 throw new Error("The alphabet is required to generate the pssm."); | |
| 2935 } | |
| 2936 if (typeof pseudo === "undefined") { | |
| 2937 pseudo = 0.01; | |
| 2938 } else if (typeof pseudo !== "number" || pseudo < 0) { | |
| 2939 throw new Error("Expected positive number for pseudocount"); | |
| 2940 } | |
| 2941 score = function(row, col) { | |
| 2942 "use strict"; | |
| 2943 var p, bg, p2; | |
| 2944 p = me.pspm[row][col]; | |
| 2945 bg = alphabet.get_bg_freq(col); | |
| 2946 p2 = (p * me.nsites + bg * pseudo) / (me.nsites + pseudo); | |
| 2947 return (p2 > 0 ? Math.round((Math.log(p2 / bg) / Math.LN2) * 100) : -10000); | |
| 2948 }; | |
| 2949 } else { | |
| 2950 score = function(row, col) { | |
| 2951 "use strict"; | |
| 2952 return me.pssm[row][col]; | |
| 2953 }; | |
| 2954 } | |
| 2955 out = ""; | |
| 2956 for (row = 0; row < this.motif_length; row++) { | |
| 2957 for (col = 0; col < this.alph_length; col++) { | |
| 2958 if (col !== 0) { | |
| 2959 out += " "; | |
| 2960 } | |
| 2961 score_text = "" + score(row, col); | |
| 2962 // pad out to 6 characters | |
| 2963 if (score_text.length < 6) { | |
| 2964 out += (new Array(7 - score_text.length)).join(" ") + score_text; | |
| 2965 } else { | |
| 2966 out += score_text; | |
| 2967 } | |
| 2968 } | |
| 2969 out += "\n"; | |
| 2970 } | |
| 2971 return out; | |
| 2972 } | |
| 2973 | |
| 2974 Pspm.prototype.as_pspm = function() { | |
| 2975 "use strict"; | |
| 2976 return "letter-probability matrix: alength= " + this.alph_length + | |
| 2977 " w= " + this.motif_length + " nsites= " + this.nsites + | |
| 2978 " E= " + (typeof this.evalue === "number" ? | |
| 2979 this.evalue.toExponential() : this.evalue) + "\n" + | |
| 2980 this.as_probability_matrix(); | |
| 2981 }; | |
| 2982 | |
| 2983 Pspm.prototype.as_pssm = function(alphabet, pseudo) { | |
| 2984 "use strict"; | |
| 2985 return "log-odds matrix: alength= " + this.alph_length + | |
| 2986 " w= " + this.motif_length + | |
| 2987 " E= " + (typeof this.evalue == "number" ? | |
| 2988 this.evalue.toExponential() : this.evalue) + "\n" + | |
| 2989 this.as_score_matrix(alphabet, pseudo); | |
| 2990 }; | |
| 2991 | |
| 2992 Pspm.prototype.as_meme = function(options) { | |
| 2993 var with_header, with_pspm, with_pssm, version, alphabet, bg_source, pseudocount, strands; | |
| 2994 var out, alen, i; | |
| 2995 // get the options | |
| 2996 if (typeof options !== "object" || options === null) { | |
| 2997 options = {}; | |
| 2998 } | |
| 2999 with_header = (typeof options["with_header"] === "boolean" ? options["with_header"] : false); | |
| 3000 with_pspm = (typeof options["with_pspm"] === "boolean" ? options["with_pspm"] : false); | |
| 3001 with_pssm = (typeof options["with_pssm"] === "boolean" ? options["with_pssm"] : false); | |
| 3002 if (!with_pspm && !with_pssm) with_pspm = true; | |
| 3003 if (with_header) { | |
| 3004 if (typeof options["version"] === "string" && /^\d+(?:\.\d+){0,2}$/.test(options["version"])) { | |
| 3005 version = options["version"]; | |
| 3006 } else if (typeof options["version"] === "number") { | |
| 3007 version = options["version"].toFixed(0); | |
| 3008 } else { | |
| 3009 version = "4"; | |
| 3010 } | |
| 3011 if (typeof options["strands"] === "number" && options["strands"] === 1) { | |
| 3012 strands = 1; | |
| 3013 } else { | |
| 3014 strands = 2; | |
| 3015 } | |
| 3016 if (typeof options["bg_source"] === "string") { | |
| 3017 bg_source = options["bg_source"]; | |
| 3018 } else { | |
| 3019 bg_source = "unknown source"; | |
| 3020 } | |
| 3021 if (typeof options["alphabet"] === "object" && options["alphabet"] != null | |
| 3022 && options["alphabet"] instanceof Alphabet) { | |
| 3023 alphabet = options["alphabet"]; | |
| 3024 } else { | |
| 3025 throw new Error("The alphabet is required to generate the header."); | |
| 3026 } | |
| 3027 } | |
| 3028 // now create the output | |
| 3029 out = ""; | |
| 3030 if (with_header) { | |
| 3031 out = "MEME version " + version + "\n\n"; | |
| 3032 out += alphabet.as_meme() + "\n"; | |
| 3033 if (alphabet.has_complement()) { // assume DNA has both strands unless otherwise specified | |
| 3034 out += "strands: " + (strands === 1 ? "+" : "+ -") + "\n\n"; | |
| 3035 } | |
| 3036 out += "Background letter frequencies (from " + bg_source + "):\n"; | |
| 3037 alen = alphabet.get_size_core(); | |
| 3038 for (i = 0; i < alen; i++) { | |
| 3039 if (i !== 0) { | |
| 3040 if (i % 9 === 0) { // maximum of nine entries per line | |
| 3041 out += "\n"; | |
| 3042 } else { | |
| 3043 out += " "; | |
| 3044 } | |
| 3045 } | |
| 3046 out += alphabet.get_symbol(i) + " " + alphabet.get_bg_freq(i).toFixed(3); | |
| 3047 } | |
| 3048 } | |
| 3049 out += "\n\n"; | |
| 3050 out += "MOTIF " + this.name + (this.alt == null ? "" : " " + this.alt); | |
| 3051 if (with_pssm) { | |
| 3052 out += "\n\n"; | |
| 3053 out += this.as_pssm(options["alphabet"], options["pseudocount"]); | |
| 3054 } | |
| 3055 if (with_pspm) { | |
| 3056 out += "\n\n"; | |
| 3057 out += this.as_pspm(); | |
| 3058 } | |
| 3059 return out; | |
| 3060 } | |
| 3061 | |
| 3062 Pspm.prototype.toString = function() { | |
| 3063 "use strict"; | |
| 3064 var str, i, row; | |
| 3065 str = ""; | |
| 3066 for (i = 0; i < this.pspm.length; i++) { | |
| 3067 row = this.pspm[i]; | |
| 3068 str += row.join("\t") + "\n"; | |
| 3069 } | |
| 3070 return str; | |
| 3071 }; | |
| 3072 | |
| 3073 function parse_pspm_properties(str) { | |
| 3074 "use strict"; | |
| 3075 var parts, i, eqpos, before, after, properties, prop, num, num_re; | |
| 3076 num_re = /^((?:[+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?)|inf)$/; | |
| 3077 parts = trim(str).split(/\s+/); | |
| 3078 // split up words containing = | |
| 3079 for (i = 0; i < parts.length;) { | |
| 3080 eqpos = parts[i].indexOf("="); | |
| 3081 if (eqpos != -1) { | |
| 3082 before = parts[i].substr(0, eqpos); | |
| 3083 after = parts[i].substr(eqpos+1); | |
| 3084 if (before.length > 0 && after.length > 0) { | |
| 3085 parts.splice(i, 1, before, "=", after); | |
| 3086 i += 3; | |
| 3087 } else if (before.length > 0) { | |
| 3088 parts.splice(i, 1, before, "="); | |
| 3089 i += 2; | |
| 3090 } else if (after.length > 0) { | |
| 3091 parts.splice(i, 1, "=", after); | |
| 3092 i += 2; | |
| 3093 } else { | |
| 3094 parts.splice(i, 1, "="); | |
| 3095 i++; | |
| 3096 } | |
| 3097 } else { | |
| 3098 i++; | |
| 3099 } | |
| 3100 } | |
| 3101 properties = {}; | |
| 3102 for (i = 0; i < parts.length; i += 3) { | |
| 3103 if (parts.length - i < 3) { | |
| 3104 throw new Error("Expected PSPM property was incomplete. "+ | |
| 3105 "Remaing parts are: " + parts.slice(i).join(" ")); | |
| 3106 } | |
| 3107 if (parts[i+1] !== "=") { | |
| 3108 throw new Error("Expected '=' in PSPM property between key and " + | |
| 3109 "value but got " + parts[i+1]); | |
| 3110 } | |
| 3111 prop = parts[i].toLowerCase(); | |
| 3112 num = parts[i+2]; | |
| 3113 if (!num_re.test(num)) { | |
| 3114 throw new Error("Expected numeric value for PSPM property '" + | |
| 3115 prop + "' but got '" + num + "'"); | |
| 3116 } | |
| 3117 properties[prop] = num; | |
| 3118 } | |
| 3119 return properties; | |
| 3120 } | |
| 3121 | |
| 3122 function parse_pspm_string(pspm_string) { | |
| 3123 "use strict"; | |
| 3124 var header_re, lines, first_line, line_num, col_num, alph_length, | |
| 3125 motif_length, nsites, evalue, pspm, i, line, match, props, parts, | |
| 3126 j, prob; | |
| 3127 header_re = /^letter-probability\s+matrix:(.*)$/i; | |
| 3128 lines = pspm_string.split(/\n/); | |
| 3129 first_line = true; | |
| 3130 line_num = 0; | |
| 3131 col_num = 0; | |
| 3132 alph_length; | |
| 3133 motif_length; | |
| 3134 nsites; | |
| 3135 evalue; | |
| 3136 pspm = []; | |
| 3137 for (i = 0; i < lines.length; i++) { | |
| 3138 line = trim(lines[i]); | |
| 3139 if (line.length === 0) { | |
| 3140 continue; | |
| 3141 } | |
| 3142 // check the first line for a header though allow matrices without it | |
| 3143 if (first_line) { | |
| 3144 first_line = false; | |
| 3145 match = header_re.exec(line); | |
| 3146 if (match !== null) { | |
| 3147 props = parse_pspm_properties(match[1]); | |
| 3148 if (props.hasOwnProperty("alength")) { | |
| 3149 alph_length = parseFloat(props["alength"]); | |
| 3150 if (alph_length != 4 && alph_length != 20) { | |
| 3151 throw new Error("PSPM property alength should be 4 or 20" + | |
| 3152 " but got " + alph_length); | |
| 3153 } | |
| 3154 } | |
| 3155 if (props.hasOwnProperty("w")) { | |
| 3156 motif_length = parseFloat(props["w"]); | |
| 3157 if (motif_length % 1 !== 0 || motif_length < 1) { | |
| 3158 throw new Error("PSPM property w should be an integer larger " + | |
| 3159 "than zero but got " + motif_length); | |
| 3160 } | |
| 3161 } | |
| 3162 if (props.hasOwnProperty("nsites")) { | |
| 3163 nsites = parseFloat(props["nsites"]); | |
| 3164 if (nsites <= 0) { | |
| 3165 throw new Error("PSPM property nsites should be larger than " + | |
| 3166 "zero but got " + nsites); | |
| 3167 } | |
| 3168 } | |
| 3169 if (props.hasOwnProperty("e")) { | |
| 3170 evalue = props["e"]; | |
| 3171 if (evalue < 0) { | |
| 3172 throw new Error("PSPM property evalue should be " + | |
| 3173 "non-negative but got " + evalue); | |
| 3174 } | |
| 3175 } | |
| 3176 continue; | |
| 3177 } | |
| 3178 } | |
| 3179 pspm[line_num] = []; | |
| 3180 col_num = 0; | |
| 3181 parts = line.split(/\s+/); | |
| 3182 for (j = 0; j < parts.length; j++) { | |
| 3183 prob = parseFloat(parts[j]); | |
| 3184 if (prob != parts[j] || prob < 0 || prob > 1) { | |
| 3185 throw new Error("Expected probability but got '" + parts[j] + "'"); | |
| 3186 } | |
| 3187 pspm[line_num][col_num] = prob; | |
| 3188 col_num++; | |
| 3189 } | |
| 3190 line_num++; | |
| 3191 } | |
| 3192 if (typeof motif_length === "number") { | |
| 3193 if (pspm.length != motif_length) { | |
| 3194 throw new Error("Expected PSPM to have a motif length of " + | |
| 3195 motif_length + " but it was actually " + pspm.length); | |
| 3196 } | |
| 3197 } else { | |
| 3198 motif_length = pspm.length; | |
| 3199 } | |
| 3200 if (typeof alph_length !== "number") { | |
| 3201 alph_length = pspm[0].length; | |
| 3202 if (alph_length != 4 && alph_length != 20) { | |
| 3203 throw new Error("Expected length of first row in the PSPM to be " + | |
| 3204 "either 4 or 20 but got " + alph_length); | |
| 3205 } | |
| 3206 } | |
| 3207 for (i = 0; i < pspm.length; i++) { | |
| 3208 if (pspm[i].length != alph_length) { | |
| 3209 throw new Error("Expected PSPM row " + i + " to have a length of " + | |
| 3210 alph_length + " but the length was " + pspm[i].length); | |
| 3211 } | |
| 3212 } | |
| 3213 return {"pspm": pspm, "motif_length": motif_length, | |
| 3214 "alph_length": alph_length, "nsites": nsites, "evalue": evalue}; | |
| 3215 } | |
| 3216 //====================================================================== | |
| 3217 // end Pspm object | |
| 3218 //====================================================================== | |
| 3219 | |
| 3220 //====================================================================== | |
| 3221 // start Logo object | |
| 3222 //====================================================================== | |
| 3223 | |
| 3224 var Logo = function(alphabet, options) { | |
| 3225 "use strict"; | |
| 3226 this.alphabet = alphabet; | |
| 3227 this.fine_text = ""; | |
| 3228 this.x_axis = 1; | |
| 3229 this.y_axis = true; | |
| 3230 this.xlate_nsyms = 1; | |
| 3231 this.xlate_start = null; | |
| 3232 this.xlate_end = null; | |
| 3233 this.pspm_list = []; | |
| 3234 this.pspm_column = []; | |
| 3235 this.rows = 0; | |
| 3236 this.columns = 0; | |
| 3237 if (typeof options === "string") { | |
| 3238 // the old method signature had fine_text here so we support that | |
| 3239 this.fine_text = options; | |
| 3240 } else if (typeof options === "object" && options != null) { | |
| 3241 this.fine_text = (typeof options.fine_text === "string" ? options.fine_text : ""); | |
| 3242 this.x_axis = (typeof options.x_axis === "boolean" ? (options.x_axis ? 1 : 0) : 1); | |
| 3243 if (options.x_axis_hidden != null && options.x_axis_hidden) this.x_axis = -1; | |
| 3244 this.y_axis = (typeof options.y_axis === "boolean" ? options.y_axis : true); | |
| 3245 this.xlate_nsyms = (typeof options.xlate_nsyms === "number" ? options.xlate_nsyms : this.xlate_nsyms); | |
| 3246 this.xlate_start = (typeof options.xlate_start === "number" ? options.xlate_start : this.xlate_start); | |
| 3247 this.xlate_end = (typeof options.xlate_end === "number" ? options.xlate_end : this.xlate_end); | |
| 3248 } | |
| 3249 }; | |
| 3250 | |
| 3251 Logo.prototype.add_pspm = function(pspm, column) { | |
| 3252 "use strict"; | |
| 3253 var col; | |
| 3254 if (typeof column === "undefined") { | |
| 3255 column = 0; | |
| 3256 } else if (column < 0) { | |
| 3257 throw new Error("Column index out of bounds."); | |
| 3258 } | |
| 3259 this.pspm_list[this.rows] = pspm; | |
| 3260 this.pspm_column[this.rows] = column; | |
| 3261 this.rows++; | |
| 3262 col = column + pspm.get_motif_length(); | |
| 3263 if (col > this.columns) { | |
| 3264 this.columns = col; | |
| 3265 } | |
| 3266 }; | |
| 3267 | |
| 3268 Logo.prototype.get_columns = function() { | |
| 3269 "use strict"; | |
| 3270 return this.columns; | |
| 3271 }; | |
| 3272 | |
| 3273 Logo.prototype.get_xlate_nsyms = function() { | |
| 3274 "use strict"; | |
| 3275 return this.xlate_nsyms; | |
| 3276 }; | |
| 3277 | |
| 3278 Logo.prototype.get_xlate_start = function() { | |
| 3279 "use strict"; | |
| 3280 return (this.xlate_start != null ? this.xlate_start : 0); | |
| 3281 }; | |
| 3282 | |
| 3283 Logo.prototype.get_xlate_end = function() { | |
| 3284 "use strict"; | |
| 3285 return (this.xlate_end != null ? this.xlate_end : this.columns * this.xlate_nsyms); | |
| 3286 }; | |
| 3287 | |
| 3288 Logo.prototype.get_xlate_columns = function() { | |
| 3289 "use strict"; | |
| 3290 return this.get_xlate_end() - this.get_xlate_start(); | |
| 3291 }; | |
| 3292 | |
| 3293 Logo.prototype.get_rows = function() { | |
| 3294 "use strict"; | |
| 3295 return this.rows; | |
| 3296 }; | |
| 3297 | |
| 3298 Logo.prototype.get_pspm = function(row_index) { | |
| 3299 "use strict"; | |
| 3300 if (row_index < 0 || row_index >= this.rows) { | |
| 3301 throw new Error("INDEX_OUT_OF_BOUNDS"); | |
| 3302 } | |
| 3303 return this.pspm_list[row_index]; | |
| 3304 }; | |
| 3305 | |
| 3306 Logo.prototype.get_offset = function(row_index) { | |
| 3307 "use strict"; | |
| 3308 if (row_index < 0 || row_index >= this.rows) { | |
| 3309 throw new Error("INDEX_OUT_OF_BOUNDS"); | |
| 3310 } | |
| 3311 return this.pspm_column[row_index]; | |
| 3312 }; | |
| 3313 | |
| 3314 Logo.prototype._as_eps_data = function(ssc, errbars) { | |
| 3315 var i, j, pos, stack_pos, pspm, stack, sym, out; | |
| 3316 out = ""; | |
| 3317 for (i = 0; i < this.rows; i++) { | |
| 3318 out += "\nStartLine\n"; | |
| 3319 // Indent | |
| 3320 for (j = 0; j < this.pspm_column[i]; j++) { | |
| 3321 out += "() startstack\nendstack\n\n"; | |
| 3322 } | |
| 3323 pspm = this.pspm_list[i]; | |
| 3324 if (pspm.get_left_trim() > 0) { | |
| 3325 out += "MuteColour\nDrawTrimEdge\n" + pspm.get_left_trim() + " DrawTrimBg\n"; | |
| 3326 } | |
| 3327 for (pos = 0; pos < pspm.get_motif_length(); pos++) { | |
| 3328 if (pos != 0 && pos == pspm.get_left_trim()) { // enable full colour | |
| 3329 out += "DrawTrimEdge\nRestoreColour\n"; | |
| 3330 } else if (pos == (pspm.get_motif_length() - pspm.get_right_trim())) { | |
| 3331 out += "MuteColour\n" + pspm.get_right_trim() + " DrawTrimBg\n"; | |
| 3332 } | |
| 3333 out += "(" + (pos + 1) + ") startstack\n"; | |
| 3334 stack = pspm.get_stack(pos, this.alphabet, ssc); | |
| 3335 for (stack_pos = 0; stack_pos < stack.length; stack_pos++) { | |
| 3336 sym = stack[stack_pos]; | |
| 3337 out += " " + (sym.get_scale() * this.alphabet.get_ic()) + " (" + sym.get_symbol() + ") numchar\n"; | |
| 3338 } | |
| 3339 if (errbars) { | |
| 3340 out += " " + pspm.get_error(this.alphabet) + " Ibeam\n"; | |
| 3341 } | |
| 3342 out += "endstack\n\n"; | |
| 3343 } | |
| 3344 if (pspm.get_right_trim() > 0 || pspm.get_left_trim() == pspm.get_motif_length()) { | |
| 3345 out += "RestoreColour\n"; | |
| 3346 } | |
| 3347 out += "EndLine\n"; | |
| 3348 } | |
| 3349 return out; | |
| 3350 }; | |
| 3351 | |
| 3352 Logo.prototype.as_eps = function(options) { | |
| 3353 "use strict"; | |
| 3354 if (this.xlate_nsyms != 1) throw new Error("Unsupported setting xlate_nsyms for EPS"); | |
| 3355 if (this.xlate_start != null) throw new Error("Unsupported setting xlate_start for EPS"); | |
| 3356 if (this.xlate_end != null) throw new Error("Unsupported setting xlate_end for EPS"); | |
| 3357 | |
| 3358 var LOGOHEIGHT = 7.5; // default height of line in cm | |
| 3359 var cm2pts, height, width, now, ssc, errbars; | |
| 3360 if (typeof options === "undefined") { | |
| 3361 options = {}; | |
| 3362 } | |
| 3363 cm2pts = 72 / 2.54; | |
| 3364 if (typeof options.logo_height == "number") { | |
| 3365 height = options.logo_height; | |
| 3366 } else { | |
| 3367 height = LOGOHEIGHT * this.rows; | |
| 3368 } | |
| 3369 if (typeof options.logo_width == "number") { | |
| 3370 width = options.logo_width; | |
| 3371 } else { | |
| 3372 width = this.columns + 2; | |
| 3373 } | |
| 3374 now = new Date(); | |
| 3375 ssc = (typeof options.ssc == "boolean" ? options.ssc : false); | |
| 3376 errbars = (typeof options.show_error_bar == "boolean" ? options.show_error_bar : ssc); | |
| 3377 var values = { | |
| 3378 "LOGOHEIGHT": height, | |
| 3379 "LOGOWIDTH": width, | |
| 3380 "BOUNDINGHEIGHT": Math.round(height * cm2pts), | |
| 3381 "BOUNDINGWIDTH": Math.round(width * cm2pts), | |
| 3382 "LOGOLINEHEIGHT": (height / this.rows), | |
| 3383 "CHARSPERLINE": this.columns, | |
| 3384 "BARBITS": this.alphabet.get_ic(), | |
| 3385 "LOGOTYPE": (this.alphabet.has_complement() ? "NA" : "AA"), | |
| 3386 "CREATIONDATE": now.getDate() + "." + (now.getMonth() + 1) + "." + now.getFullYear() + " " + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds(), | |
| 3387 "ERRORBARFRACTION": (typeof options.error_bar_fraction == "number" ? options.error_bar_fraction : 1.0), | |
| 3388 "TICBITS": (typeof options.ticbits == "number" ? options.ticbits : 1.0), | |
| 3389 "TITLE": (typeof options.title == "string" ? options.title : ""), | |
| 3390 "FINEPRINT": (typeof options.fineprint == "string" ? options.fineprint : this.fine_text), | |
| 3391 "XAXISLABEL": (typeof options.xaxislabel == "string" ? options.xaxislabel : ""), | |
| 3392 "YAXISLABEL": (typeof options.yaxislabel == "string" ? options.yaxislabel : "bits"), | |
| 3393 "SSC": ssc, | |
| 3394 "YAXIS": (typeof options.show_y_axis == "boolean" ? options.show_y_axis : this.y_axis), | |
| 3395 "SHOWENDS": (typeof options.show_ends == "boolean" ? options.show_ends : false), | |
| 3396 "ERRBAR": errbars, | |
| 3397 "OUTLINE": (typeof options.show_outline == "boolean" ? options.show_outline : false), | |
| 3398 "NUMBERING": (typeof options.show_numbering == "boolean" ? options.show_numbering : this.x_axis != 0), | |
| 3399 "SHOWINGBOX": (typeof options.show_box == "boolean" ? options.show_box : false), | |
| 3400 "CREATOR": (typeof options.creator == "string" ? options.creator : "motif_logo.js"), | |
| 3401 "FONTSIZE": (typeof options.label_font_size == "number" ? options.label_font_size : 12), | |
| 3402 "TITLEFONTSIZE": (typeof options.title_font_size == "number" ? options.title_font_size : 12), | |
| 3403 "SMALLFONTSIZE": (typeof options.small_font_size == "number" ? options.small_font_size : 6), | |
| 3404 "TOPMARGIN" : (typeof options.top_margin == "number" ? options.top_margin : 0.9), | |
| 3405 "BOTTOMMARGIN": (typeof options.bottom_margin == "number" ? options.bottom_margin : 0.9), | |
| 3406 "COLORDICT": this.alphabet._as_eps_dict(), | |
| 3407 "DATA": this._as_eps_data(ssc, errbars) | |
| 3408 }; | |
| 3409 // now this requires that the script containing the template has been imported! | |
| 3410 return motif_logo_template(values); | |
| 3411 }; | |
| 3412 | |
| 3413 //====================================================================== | |
| 3414 // end Logo object | |
| 3415 //====================================================================== | |
| 3416 | |
| 3417 // calculate the exact size (in pixels) of an object drawn on the | |
| 3418 // canvas assuming that the background of the canvas is transparent. | |
| 3419 function canvas_bounds(ctx, cwidth, cheight) { | |
| 3420 "use strict"; | |
| 3421 var data, r, c, top_line, bottom_line, left_line, right_line, | |
| 3422 txt_width, txt_height; | |
| 3423 | |
| 3424 // extract the image data | |
| 3425 data = ctx.getImageData(0, 0, cwidth, cheight).data; | |
| 3426 | |
| 3427 // set initial values | |
| 3428 top_line = -1; bottom_line = -1; left_line = -1; right_line = -1; | |
| 3429 txt_width = 0; txt_height = 0; | |
| 3430 | |
| 3431 // Find the top-most line with a non-transparent pixel | |
| 3432 for (r = 0; r < cheight; r++) { | |
| 3433 for (c = 0; c < cwidth; c++) { | |
| 3434 if (data[r * cwidth * 4 + c * 4 + 3]) { | |
| 3435 top_line = r; | |
| 3436 break; | |
| 3437 } | |
| 3438 } | |
| 3439 if (top_line != -1) { | |
| 3440 break; | |
| 3441 } | |
| 3442 } | |
| 3443 | |
| 3444 // Only bother looking if we found at least one set pixel... | |
| 3445 if (top_line != -1) { | |
| 3446 | |
| 3447 //find the last line with a non-transparent pixel | |
| 3448 for (r = cheight-1; r >= top_line; r--) { | |
| 3449 for(c = 0; c < cwidth; c++) { | |
| 3450 if(data[r * cwidth * 4 + c * 4 + 3]) { | |
| 3451 bottom_line = r; | |
| 3452 break; | |
| 3453 } | |
| 3454 } | |
| 3455 if (bottom_line != -1) { | |
| 3456 break; | |
| 3457 } | |
| 3458 } | |
| 3459 // calculate height | |
| 3460 txt_height = bottom_line - top_line + 1; | |
| 3461 | |
| 3462 // Find the left-most line with a non-transparent pixel | |
| 3463 for (c = 0; c < cwidth; c++) { | |
| 3464 for (r = top_line; r <= bottom_line; r++) { | |
| 3465 if (data[r * cwidth * 4 + c * 4 + 3]) { | |
| 3466 left_line = c; | |
| 3467 break; | |
| 3468 } | |
| 3469 } | |
| 3470 if (left_line != -1) { | |
| 3471 break; | |
| 3472 } | |
| 3473 } | |
| 3474 | |
| 3475 //find the right most line with a non-transparent pixel | |
| 3476 for (c = cwidth-1; c >= left_line; c--) { | |
| 3477 for(r = top_line; r <= bottom_line; r++) { | |
| 3478 if(data[r * cwidth * 4 + c * 4 + 3]) { | |
| 3479 right_line = c; | |
| 3480 break; | |
| 3481 } | |
| 3482 } | |
| 3483 if (right_line != -1) { | |
| 3484 break; | |
| 3485 } | |
| 3486 } | |
| 3487 txt_width = right_line - left_line + 1; | |
| 3488 } | |
| 3489 | |
| 3490 //return the bounds | |
| 3491 return {bound_top: top_line, bound_bottom: bottom_line, | |
| 3492 bound_left: left_line, bound_right: right_line, width: txt_width, | |
| 3493 height: txt_height}; | |
| 3494 } | |
| 3495 | |
| 3496 //====================================================================== | |
| 3497 // start RasterizedAlphabet | |
| 3498 //====================================================================== | |
| 3499 | |
| 3500 // Rasterize Alphabet | |
| 3501 // 1) Measure width of text at default font for all symbols in alphabet | |
| 3502 // 2) sort in width ascending | |
| 3503 // 3) Drop the top and bottom 10% (designed to ignore outliers like 'W' and 'I') | |
| 3504 // 4) Calculate the average as the maximum scaling factor (designed to stop I becoming a rectangular blob). | |
| 3505 // 5) Assume scale of zero would result in width of zero, interpolate scale required to make perfect width font | |
| 3506 // 6) Draw text onto temp canvas at calculated scale | |
| 3507 // 7) Find bounds of drawn text | |
| 3508 // 8) Paint on to another canvas at the desired height (but only scaling width to fit if larger). | |
| 3509 var RasterizedAlphabet = function(alphabet, logo_scale, font, width) { | |
| 3510 "use strict"; | |
| 3511 var default_size, safety_pad, canvas, ctx, middle, baseline, widths, sizes, | |
| 3512 i, sym, size, tenpercent, avg_width, scale, | |
| 3513 target_width, target_height; | |
| 3514 //variable prototypes | |
| 3515 this.alphabet = alphabet; | |
| 3516 this.scale = logo_scale; | |
| 3517 this.sym_cache = {}; | |
| 3518 this.stack_num_cache = []; | |
| 3519 this.scale_num_cache = []; | |
| 3520 // size of canvas | |
| 3521 default_size = 60; // size of measuring canvas | |
| 3522 safety_pad = 20; // pixels to pad around so we don't miss the edges | |
| 3523 // create a canvas to do our measuring | |
| 3524 canvas = document.createElement("canvas"); | |
| 3525 if (!canvas.getContext) throw new Error("No canvas support"); | |
| 3526 canvas.width = default_size + 2 * safety_pad; | |
| 3527 canvas.height = default_size + 2 * safety_pad; | |
| 3528 middle = Math.round(canvas.width / 2); | |
| 3529 baseline = Math.round(canvas.height - safety_pad); | |
| 3530 ctx = canvas.getContext('2d'); | |
| 3531 if (!supports_text(ctx)) throw new Error("Canvas does not support text"); | |
| 3532 ctx.font = font; | |
| 3533 ctx.textAlign = "center"; | |
| 3534 ctx.translate(middle, baseline); | |
| 3535 // list of widths | |
| 3536 widths = []; | |
| 3537 sizes = []; | |
| 3538 //now measure each letter in the alphabet | |
| 3539 for (i = 0; i < alphabet.get_size_core(); ++i) { | |
| 3540 // reset the canvas | |
| 3541 ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| 3542 ctx.fillStyle = alphabet.get_colour(i); | |
| 3543 // draw the test text | |
| 3544 ctx.fillText(alphabet.get_symbol(i), 0, 0); | |
| 3545 //measure | |
| 3546 size = canvas_bounds(ctx, canvas.width, canvas.height); | |
| 3547 if (size.width === 0) throw new Error("Invisible symbol!"); | |
| 3548 widths.push(size.width); | |
| 3549 sizes[i] = size; | |
| 3550 } | |
| 3551 //sort the widths | |
| 3552 widths.sort(function(a,b) {return a - b;}); | |
| 3553 //drop 10% of the items off each end | |
| 3554 tenpercent = Math.floor(widths.length / 10); | |
| 3555 for (i = 0; i < tenpercent; ++i) { | |
| 3556 widths.pop(); | |
| 3557 widths.shift(); | |
| 3558 } | |
| 3559 //calculate average width | |
| 3560 avg_width = 0; | |
| 3561 for (i = 0; i < widths.length; ++i) { | |
| 3562 avg_width += widths[i]; | |
| 3563 } | |
| 3564 avg_width /= widths.length; | |
| 3565 // calculate the target width | |
| 3566 target_width = width * this.scale * 2; | |
| 3567 // calculate scales | |
| 3568 for (i = 0; i < alphabet.get_size_core(); ++i) { | |
| 3569 sym = alphabet.get_symbol(i); | |
| 3570 size = sizes[i]; | |
| 3571 // calculate scale | |
| 3572 scale = target_width / Math.max(avg_width, size.width); | |
| 3573 // estimate scaled height | |
| 3574 target_height = size.height * scale; | |
| 3575 // create an appropriately sized canvas | |
| 3576 canvas = document.createElement("canvas"); | |
| 3577 canvas.width = target_width; | |
| 3578 canvas.height = target_height + safety_pad * 2; | |
| 3579 // calculate the middle | |
| 3580 middle = Math.round(canvas.width / 2); | |
| 3581 // calculate the baseline | |
| 3582 baseline = Math.round(canvas.height - safety_pad); | |
| 3583 // get the context and prepare to draw the rasterized text | |
| 3584 ctx = canvas.getContext('2d'); | |
| 3585 ctx.font = font; | |
| 3586 ctx.fillStyle = alphabet.get_colour(i); | |
| 3587 ctx.textAlign = "center"; | |
| 3588 ctx.translate(middle, baseline); | |
| 3589 ctx.save(); | |
| 3590 ctx.scale(scale, scale); | |
| 3591 // draw the text | |
| 3592 ctx.fillText(sym, 0, 0); | |
| 3593 ctx.restore(); | |
| 3594 this.sym_cache[sym] = {"image": canvas, "size": canvas_bounds(ctx, canvas.width, canvas.height)}; | |
| 3595 } | |
| 3596 }; | |
| 3597 | |
| 3598 RasterizedAlphabet.prototype.get_alphabet = function() { | |
| 3599 return this.alphabet; | |
| 3600 }; | |
| 3601 | |
| 3602 RasterizedAlphabet.prototype.get_scale = function() { | |
| 3603 return this.scale; | |
| 3604 }; | |
| 3605 | |
| 3606 RasterizedAlphabet.prototype.draw_stack_sym = function(ctx, letter, dx, dy, dWidth, dHeight) { | |
| 3607 "use strict"; | |
| 3608 var entry, image, size; | |
| 3609 entry = this.sym_cache[letter]; | |
| 3610 image = entry.image; | |
| 3611 size = entry.size; | |
| 3612 ctx.drawImage(image, 0, size.bound_top -1, image.width, size.height+1, dx, dy, dWidth, dHeight); | |
| 3613 }; | |
| 3614 | |
| 3615 RasterizedAlphabet.prototype.draw_stack_num = function(ctx, font, stack_width, index) { | |
| 3616 var image, image_ctx, text_length; | |
| 3617 if (index >= this.stack_num_cache.length) { | |
| 3618 image = document.createElement("canvas"); | |
| 3619 // measure the text | |
| 3620 image_ctx = image.getContext('2d'); | |
| 3621 image_ctx.save(); | |
| 3622 image_ctx.font = font; | |
| 3623 text_length = image_ctx.measureText("" + (index + 1)).width; | |
| 3624 image_ctx.restore(); | |
| 3625 // resize the canvas to fit | |
| 3626 image.width = Math.ceil(stack_width); | |
| 3627 image.height = Math.ceil(text_length); | |
| 3628 // draw the text | |
| 3629 image_ctx = image.getContext('2d'); | |
| 3630 image_ctx.translate(Math.round(stack_width / 2), 0); | |
| 3631 image_ctx.font = font; | |
| 3632 image_ctx.textBaseline = "middle"; | |
| 3633 image_ctx.textAlign = "right"; | |
| 3634 image_ctx.rotate(-(Math.PI / 2)); | |
| 3635 image_ctx.fillText("" + (index + 1), 0, 0); | |
| 3636 this.stack_num_cache[index] = image; | |
| 3637 } else { | |
| 3638 image = this.stack_num_cache[index]; | |
| 3639 } | |
| 3640 ctx.drawImage(image, 0, 0); | |
| 3641 } | |
| 3642 | |
| 3643 RasterizedAlphabet.prototype.draw_scale_num = function(ctx, font, num) { | |
| 3644 var image, image_ctx, text_size, m_length; | |
| 3645 if (num >= this.scale_num_cache.length) { | |
| 3646 image = document.createElement("canvas"); | |
| 3647 // measure the text | |
| 3648 image_ctx = image.getContext('2d'); | |
| 3649 image_ctx.font = font; | |
| 3650 text_size = image_ctx.measureText("" + num); | |
| 3651 if (text_size.actualBoundingBoxAscent && text_size.actualBoundingBoxDesent) { | |
| 3652 // resize the canvas to fit | |
| 3653 image.width = Math.ceil(text_size.width); | |
| 3654 image.height = Math.ceil(text_size.actualBoundingBoxAscent + text_size.actualBoundingBoxDesent); | |
| 3655 // draw the text | |
| 3656 image_ctx = image.getContext('2d'); | |
| 3657 image_ctx.font = font; | |
| 3658 image_ctx.textAlign = "right"; | |
| 3659 image_ctx.fillText("" + num, image.width, text_size.actualBoundingBoxAscent); | |
| 3660 } else { | |
| 3661 // measure width of 'm' to approximate height, we double it later anyway | |
| 3662 m_length = image_ctx.measureText("m").width; | |
| 3663 // resize the canvas to fit | |
| 3664 image.width = Math.ceil(text_size.width); | |
| 3665 image.height = Math.ceil(2 * m_length); | |
| 3666 // draw the text | |
| 3667 image_ctx = image.getContext('2d'); | |
| 3668 image_ctx.font = font; | |
| 3669 image_ctx.textAlign = "right"; | |
| 3670 image_ctx.textBaseline = "middle"; | |
| 3671 image_ctx.fillText("" + num, image.width, m_length); | |
| 3672 } | |
| 3673 this.scale_num_cache[num] = image; | |
| 3674 } else { | |
| 3675 image = this.scale_num_cache[num]; | |
| 3676 } | |
| 3677 ctx.drawImage(image, -image.width, -Math.round(image.height / 2)) | |
| 3678 } | |
| 3679 | |
| 3680 //====================================================================== | |
| 3681 // end RasterizedAlphabet | |
| 3682 //====================================================================== | |
| 3683 | |
| 3684 //====================================================================== | |
| 3685 // start LogoMetrics object | |
| 3686 //====================================================================== | |
| 3687 | |
| 3688 var LogoMetrics = function(ctx, logo_columns, logo_rows, has_names, has_finetext, x_axis, y_axis) { | |
| 3689 "use strict"; | |
| 3690 var i, row_height; | |
| 3691 //variable prototypes | |
| 3692 this.pad_top = (has_names ? 5 : 0); | |
| 3693 this.pad_left = (y_axis ? 10 : 0); | |
| 3694 this.pad_right = (has_finetext ? 15 : 0); | |
| 3695 this.pad_bottom = 0; | |
| 3696 this.pad_middle = 20; | |
| 3697 this.name_height = 14; | |
| 3698 this.name_font = "bold " + this.name_height + "px Times, sans-serif"; | |
| 3699 this.name_spacer = 0; | |
| 3700 this.y_axis = y_axis; | |
| 3701 this.y_label = "bits"; | |
| 3702 this.y_label_height = 12; | |
| 3703 this.y_label_font = "bold " + this.y_label_height + "px Helvetica, sans-serif"; | |
| 3704 this.y_label_spacer = 3; | |
| 3705 this.y_num_height = 12; | |
| 3706 this.y_num_width = 0; | |
| 3707 this.y_num_font = "bold " + this.y_num_height + "px Helvetica, sans-serif"; | |
| 3708 this.y_tic_width = 5; | |
| 3709 this.stack_pad_left = 0; | |
| 3710 this.stack_font = "bold 25px Helvetica, sans-serif"; | |
| 3711 this.stack_height = 90; | |
| 3712 this.stack_width = 26; | |
| 3713 this.stacks_pad_right = 5; | |
| 3714 this.x_axis = x_axis; | |
| 3715 this.x_num_above = 2; | |
| 3716 this.x_num_height = 12; | |
| 3717 this.x_num_width = 0; | |
| 3718 this.x_num_font = "bold " + this.x_num_height + "px Helvetica, sans-serif"; | |
| 3719 this.fine_txt_height = 6; | |
| 3720 this.fine_txt_above = 2; | |
| 3721 this.fine_txt_font = "normal " + this.fine_txt_height + "px Helvetica, sans-serif"; | |
| 3722 this.letter_metrics = new Array(); | |
| 3723 this.summed_width = 0; | |
| 3724 this.summed_height = 0; | |
| 3725 //calculate the width of the y axis numbers | |
| 3726 ctx.font = this.y_num_font; | |
| 3727 for (i = 0; i <= 2; i++) { | |
| 3728 this.y_num_width = Math.max(this.y_num_width, ctx.measureText("" + i).width); | |
| 3729 } | |
| 3730 //calculate the width of the x axis numbers (but they are rotated so it becomes height) | |
| 3731 if (x_axis == 1) { | |
| 3732 ctx.font = this.x_num_font; | |
| 3733 for (i = 1; i <= logo_columns; i++) { | |
| 3734 this.x_num_width = Math.max(this.x_num_width, ctx.measureText("" + i).width); | |
| 3735 } | |
| 3736 } else if (x_axis == 0) { | |
| 3737 this.x_num_height = 4; | |
| 3738 this.x_num_width = 4; | |
| 3739 } else { | |
| 3740 this.x_num_height = 0; | |
| 3741 this.x_num_width = 0; | |
| 3742 } | |
| 3743 | |
| 3744 //calculate how much vertical space we want to draw this | |
| 3745 //first we add the padding at the top and bottom since that's always there | |
| 3746 this.summed_height += this.pad_top + this.pad_bottom; | |
| 3747 //all except the last row have the same amount of space allocated to them | |
| 3748 if (logo_rows > 1) { | |
| 3749 row_height = this.stack_height + this.pad_middle; | |
| 3750 if (has_names) { | |
| 3751 row_height += this.name_height; | |
| 3752 //the label is allowed to overlap into the spacer | |
| 3753 row_height += Math.max(this.y_num_height/2, this.name_spacer); | |
| 3754 //the label is allowed to overlap the space used by the other label | |
| 3755 row_height += Math.max(this.y_num_height/2, this.x_num_height + this.x_num_above); | |
| 3756 } else { | |
| 3757 row_height += this.y_num_height/2; | |
| 3758 //the label is allowed to overlap the space used by the other label | |
| 3759 row_height += Math.max(this.y_num_height/2, this.x_num_height + this.x_num_above); | |
| 3760 } | |
| 3761 this.summed_height += row_height * (logo_rows - 1); | |
| 3762 } | |
| 3763 //the last row has the name and fine text below it but no padding | |
| 3764 this.summed_height += this.stack_height + (this.y_axis ? this.y_num_height/2 : 0); | |
| 3765 | |
| 3766 var fine_txt_total = (has_finetext ? this.fine_txt_height + this.fine_txt_above : 0); | |
| 3767 if (has_names) { | |
| 3768 this.summed_height += fine_txt_total + this.name_height; | |
| 3769 this.summed_height += Math.max((this.y_axis ? this.y_num_height/2 : 0), | |
| 3770 this.x_num_height + this.x_num_above + this.name_spacer); | |
| 3771 } else { | |
| 3772 this.summed_height += Math.max((this.y_axis ? this.y_num_height/2 : 0), | |
| 3773 this.x_num_height + this.x_num_above + fine_txt_total); | |
| 3774 } | |
| 3775 | |
| 3776 //calculate how much horizontal space we want to draw this | |
| 3777 //first add the padding at the left and right since that's always there | |
| 3778 this.summed_width += this.pad_left + this.pad_right; | |
| 3779 if (this.y_axis) { | |
| 3780 //add on the space for the y-axis label | |
| 3781 this.summed_width += this.y_label_height + this.y_label_spacer; | |
| 3782 //add on the space for the y-axis | |
| 3783 this.summed_width += this.y_num_width + this.y_tic_width; | |
| 3784 } | |
| 3785 //add on the space for the stacks | |
| 3786 this.summed_width += (this.stack_pad_left + this.stack_width) * logo_columns; | |
| 3787 //add on the padding after the stacks (an offset from the fine text) | |
| 3788 this.summed_width += this.stacks_pad_right; | |
| 3789 | |
| 3790 }; | |
| 3791 | |
| 3792 //====================================================================== | |
| 3793 // end LogoMetrics object | |
| 3794 //====================================================================== | |
| 3795 | |
| 3796 //found this trick at http://talideon.com/weblog/2005/02/detecting-broken-images-js.cfm | |
| 3797 function image_ok(img) { | |
| 3798 "use strict"; | |
| 3799 // During the onload event, IE correctly identifies any images that | |
| 3800 // weren't downloaded as not complete. Others should too. Gecko-based | |
| 3801 // browsers act like NS4 in that they report this incorrectly. | |
| 3802 if (!img.complete) { | |
| 3803 return false; | |
| 3804 } | |
| 3805 // However, they do have two very useful properties: naturalWidth and | |
| 3806 // naturalHeight. These give the true size of the image. If it failed | |
| 3807 // to load, either of these should be zero. | |
| 3808 if (typeof img.naturalWidth !== "undefined" && img.naturalWidth === 0) { | |
| 3809 return false; | |
| 3810 } | |
| 3811 // No other way of checking: assume it's ok. | |
| 3812 return true; | |
| 3813 } | |
| 3814 | |
| 3815 function supports_text(ctx) { | |
| 3816 "use strict"; | |
| 3817 if (!ctx.fillText) { | |
| 3818 return false; | |
| 3819 } | |
| 3820 if (!ctx.measureText) { | |
| 3821 return false; | |
| 3822 } | |
| 3823 return true; | |
| 3824 } | |
| 3825 | |
| 3826 //draws the scale, returns the width | |
| 3827 function draw_scale(ctx, metrics, alphabet_ic, raster) { | |
| 3828 "use strict"; | |
| 3829 var tic_height, i; | |
| 3830 tic_height = metrics.stack_height / alphabet_ic; | |
| 3831 ctx.save(); | |
| 3832 ctx.translate(metrics.y_label_height, metrics.y_num_height/2); | |
| 3833 //draw the axis label | |
| 3834 ctx.save(); | |
| 3835 ctx.font = metrics.y_label_font; | |
| 3836 ctx.translate(0, metrics.stack_height/2); | |
| 3837 ctx.rotate(-(Math.PI / 2)); | |
| 3838 ctx.textAlign = "center"; | |
| 3839 ctx.fillText("bits", 0, 0); | |
| 3840 ctx.restore(); | |
| 3841 | |
| 3842 ctx.translate(metrics.y_label_spacer + metrics.y_num_width, 0); | |
| 3843 | |
| 3844 //draw the axis tics | |
| 3845 ctx.save(); | |
| 3846 ctx.translate(0, metrics.stack_height); | |
| 3847 for (i = 0; i <= alphabet_ic; i++) { | |
| 3848 //draw the number | |
| 3849 ctx.save(); | |
| 3850 ctx.translate(-1, 0); | |
| 3851 raster.draw_scale_num(ctx, metrics.y_num_font, i); | |
| 3852 ctx.restore(); | |
| 3853 //draw the tic | |
| 3854 ctx.fillRect(0, -1, metrics.y_tic_width, 2); | |
| 3855 //prepare for next tic | |
| 3856 ctx.translate(0, -tic_height); | |
| 3857 } | |
| 3858 ctx.restore(); | |
| 3859 | |
| 3860 ctx.fillRect(metrics.y_tic_width - 2, 0, 2, metrics.stack_height) | |
| 3861 | |
| 3862 ctx.restore(); | |
| 3863 } | |
| 3864 | |
| 3865 function draw_stack_num(ctx, metrics, row_index, raster) { | |
| 3866 "use strict"; | |
| 3867 ctx.save(); | |
| 3868 ctx.translate(0, Math.round(metrics.stack_height + metrics.x_num_above)); | |
| 3869 if (metrics.x_axis == 1) { | |
| 3870 raster.draw_stack_num(ctx, metrics.x_num_font, metrics.stack_width, row_index); | |
| 3871 } else if (metrics.x_axis == 0) { | |
| 3872 // draw dots instead of the numbers (good for small logos) | |
| 3873 ctx.beginPath(); | |
| 3874 var radius = Math.round(metrics.x_num_height / 2); | |
| 3875 ctx.arc(Math.round(metrics.stack_width / 2), radius, radius, 0, 2 * Math.PI, false); | |
| 3876 ctx.fill(); | |
| 3877 } | |
| 3878 ctx.restore(); | |
| 3879 } | |
| 3880 | |
| 3881 function draw_stack(ctx, metrics, symbols, raster) { | |
| 3882 "use strict"; | |
| 3883 var preferred_pad, sym_min, i, sym, sym_height, pad; | |
| 3884 preferred_pad = 0; | |
| 3885 sym_min = 5; | |
| 3886 | |
| 3887 ctx.save();//1 | |
| 3888 ctx.translate(0, metrics.stack_height); | |
| 3889 for (i = 0; i < symbols.length; i++) { | |
| 3890 sym = symbols[i]; | |
| 3891 sym_height = metrics.stack_height * sym.get_scale(); | |
| 3892 | |
| 3893 pad = preferred_pad; | |
| 3894 if (sym_height - pad < sym_min) { | |
| 3895 pad = Math.min(pad, Math.max(0, sym_height - sym_min)); | |
| 3896 } | |
| 3897 sym_height -= pad; | |
| 3898 | |
| 3899 //translate to the correct position | |
| 3900 ctx.translate(0, -(pad/2 + sym_height)); | |
| 3901 | |
| 3902 //draw | |
| 3903 raster.draw_stack_sym(ctx, sym.get_symbol(), 0, 0, metrics.stack_width, sym_height); | |
| 3904 //translate past the padding | |
| 3905 ctx.translate(0, -(pad/2)); | |
| 3906 } | |
| 3907 ctx.restore();//1 | |
| 3908 } | |
| 3909 | |
| 3910 function draw_dashed_line(ctx, pattern, start, x1, y1, x2, y2) { | |
| 3911 "use strict"; | |
| 3912 var x, y, len, i, dx, dy, tlen, theta, mulx, muly, lx, ly; | |
| 3913 dx = x2 - x1; | |
| 3914 dy = y2 - y1; | |
| 3915 tlen = Math.pow(dx*dx + dy*dy, 0.5); | |
| 3916 theta = Math.atan2(dy,dx); | |
| 3917 mulx = Math.cos(theta); | |
| 3918 muly = Math.sin(theta); | |
| 3919 lx = []; | |
| 3920 ly = []; | |
| 3921 for (i = 0; i < pattern; ++i) { | |
| 3922 lx.push(pattern[i] * mulx); | |
| 3923 ly.push(pattern[i] * muly); | |
| 3924 } | |
| 3925 i = start; | |
| 3926 x = x1; | |
| 3927 y = y1; | |
| 3928 len = 0; | |
| 3929 ctx.beginPath(); | |
| 3930 while (len + pattern[i] < tlen) { | |
| 3931 ctx.moveTo(x, y); | |
| 3932 x += lx[i]; | |
| 3933 y += ly[i]; | |
| 3934 ctx.lineTo(x, y); | |
| 3935 len += pattern[i]; | |
| 3936 i = (i + 1) % pattern.length; | |
| 3937 x += lx[i]; | |
| 3938 y += ly[i]; | |
| 3939 len += pattern[i]; | |
| 3940 i = (i + 1) % pattern.length; | |
| 3941 } | |
| 3942 if (len < tlen) { | |
| 3943 ctx.moveTo(x, y); | |
| 3944 x += mulx * (tlen - len); | |
| 3945 y += muly * (tlen - len); | |
| 3946 ctx.lineTo(x, y); | |
| 3947 } | |
| 3948 ctx.stroke(); | |
| 3949 } | |
| 3950 | |
| 3951 function draw_trim_background(ctx, metrics, left_start, left_end, left_divider, right_start, right_end, right_divider) { | |
| 3952 "use strict"; | |
| 3953 var left_size = left_end - left_start; | |
| 3954 var right_size = right_end - right_start; | |
| 3955 var line_x; | |
| 3956 | |
| 3957 ctx.save();//s8 | |
| 3958 ctx.fillStyle = "rgb(240, 240, 240)"; | |
| 3959 if (left_size > 0) { | |
| 3960 ctx.fillRect(left_start * metrics.stack_width, 0, left_size * metrics.stack_width, metrics.stack_height); | |
| 3961 } | |
| 3962 if (right_size > 0) { | |
| 3963 ctx.fillRect(right_start * metrics.stack_width, 0, right_size * metrics.stack_width, metrics.stack_height); | |
| 3964 } | |
| 3965 ctx.fillStyle = "rgb(51, 51, 51)"; | |
| 3966 if (left_size > 0 && left_divider) { | |
| 3967 line_x = (left_end * metrics.stack_width) - 0.5; | |
| 3968 draw_dashed_line(ctx, [3], 0, line_x, 0, line_x, metrics.stack_height); | |
| 3969 } | |
| 3970 if (right_size > 0 && right_divider) { | |
| 3971 line_x = (right_start * metrics.stack_width) + 0.5; | |
| 3972 draw_dashed_line(ctx, [3], 0, line_x, 0, line_x, metrics.stack_height); | |
| 3973 } | |
| 3974 ctx.restore();//s8 | |
| 3975 } | |
| 3976 | |
| 3977 function size_logo_on_canvas(logo, canvas, show_names, scale) { | |
| 3978 "use strict"; | |
| 3979 var draw_name, draw_finetext, metrics; | |
| 3980 draw_name = (typeof show_names === "boolean" ? show_names : (logo.get_rows() > 1)); | |
| 3981 draw_finetext = (logo.fine_text.length > 0); | |
| 3982 if (canvas.width !== 0 && canvas.height !== 0) { | |
| 3983 return; | |
| 3984 } | |
| 3985 metrics = new LogoMetrics(canvas.getContext('2d'), | |
| 3986 logo.get_xlate_columns(), logo.get_rows(), draw_name, draw_finetext, logo.x_axis, logo.y_axis); | |
| 3987 if (typeof scale == "number") { | |
| 3988 //resize the canvas to fit the scaled logo | |
| 3989 canvas.width = metrics.summed_width * scale; | |
| 3990 canvas.height = metrics.summed_height * scale; | |
| 3991 } else { | |
| 3992 if (canvas.width === 0 && canvas.height === 0) { | |
| 3993 canvas.width = metrics.summed_width; | |
| 3994 canvas.height = metrics.summed_height; | |
| 3995 } else if (canvas.width === 0) { | |
| 3996 canvas.width = metrics.summed_width * (canvas.height / metrics.summed_height); | |
| 3997 } else if (canvas.height === 0) { | |
| 3998 canvas.height = metrics.summed_height * (canvas.width / metrics.summed_width); | |
| 3999 } | |
| 4000 } | |
| 4001 } | |
| 4002 | |
| 4003 function draw_logo_on_canvas(logo, canvas, show_names, scale) { | |
| 4004 "use strict"; | |
| 4005 var i, draw_name, draw_finetext, ctx, metrics, raster, pspm_i, pspm, | |
| 4006 offset, col_index, motif_position, ssc; | |
| 4007 ssc = false; | |
| 4008 draw_name = (typeof show_names === "boolean" ? show_names : (logo.get_rows() > 1)); | |
| 4009 draw_finetext = (logo.fine_text.length > 0); | |
| 4010 ctx = canvas.getContext('2d'); | |
| 4011 //assume that the user wants the canvas scaled equally so calculate what the best width for this image should be | |
| 4012 metrics = new LogoMetrics(ctx, logo.get_xlate_columns(), logo.get_rows(), draw_name, draw_finetext, logo.x_axis, logo.y_axis); | |
| 4013 if (typeof scale == "number") { | |
| 4014 //resize the canvas to fit the scaled logo | |
| 4015 canvas.width = metrics.summed_width * scale; | |
| 4016 canvas.height = metrics.summed_height * scale; | |
| 4017 } else { | |
| 4018 if (canvas.width === 0 && canvas.height === 0) { | |
| 4019 scale = 1; | |
| 4020 canvas.width = metrics.summed_width; | |
| 4021 canvas.height = metrics.summed_height; | |
| 4022 } else if (canvas.width === 0) { | |
| 4023 scale = canvas.height / metrics.summed_height; | |
| 4024 canvas.width = metrics.summed_width * scale; | |
| 4025 } else if (canvas.height === 0) { | |
| 4026 scale = canvas.width / metrics.summed_width; | |
| 4027 canvas.height = metrics.summed_height * scale; | |
| 4028 } else { | |
| 4029 scale = Math.min(canvas.width / metrics.summed_width, canvas.height / metrics.summed_height); | |
| 4030 } | |
| 4031 } | |
| 4032 // cache the raster based on the assumption that we will be drawing a lot | |
| 4033 // of logos the same size and alphabet | |
| 4034 if (typeof draw_logo_on_canvas.raster_cache === "undefined") { | |
| 4035 draw_logo_on_canvas.raster_cache = []; | |
| 4036 } | |
| 4037 for (i = 0; i < draw_logo_on_canvas.raster_cache.length; i++) { | |
| 4038 raster = draw_logo_on_canvas.raster_cache[i]; | |
| 4039 if (raster.get_alphabet().equals(logo.alphabet) && | |
| 4040 Math.abs(raster.get_scale() - scale) < 0.1) break; | |
| 4041 raster = null; | |
| 4042 } | |
| 4043 if (raster == null) { | |
| 4044 raster = new RasterizedAlphabet(logo.alphabet, scale, metrics.stack_font, metrics.stack_width); | |
| 4045 draw_logo_on_canvas.raster_cache.push(raster); | |
| 4046 } | |
| 4047 ctx = canvas.getContext('2d'); | |
| 4048 ctx.save();//s1 | |
| 4049 ctx.scale(scale, scale); | |
| 4050 ctx.save();//s2 | |
| 4051 ctx.save();//s7 | |
| 4052 //create margin | |
| 4053 ctx.translate(Math.round(metrics.pad_left), Math.round(metrics.pad_top)); | |
| 4054 for (pspm_i = 0; pspm_i < logo.get_rows(); ++pspm_i) { | |
| 4055 pspm = logo.get_pspm(pspm_i); | |
| 4056 offset = logo.get_offset(pspm_i); | |
| 4057 //optionally draw name if this isn't the last row or is the only row | |
| 4058 if (draw_name && (logo.get_rows() == 1 || pspm_i != (logo.get_rows()-1))) { | |
| 4059 ctx.save();//s4 | |
| 4060 ctx.translate(Math.round(metrics.summed_width/2), Math.round(metrics.name_height)); | |
| 4061 ctx.font = metrics.name_font; | |
| 4062 ctx.textAlign = "center"; | |
| 4063 ctx.fillText(pspm.name, 0, 0); | |
| 4064 ctx.restore();//s4 | |
| 4065 ctx.translate(0, Math.round(metrics.name_height + | |
| 4066 Math.min(0, metrics.name_spacer - metrics.y_num_height/2))); | |
| 4067 } | |
| 4068 //draw scale | |
| 4069 if (logo.y_axis) draw_scale(ctx, metrics, logo.alphabet.get_ic(), raster); | |
| 4070 ctx.save();//s5 | |
| 4071 //translate across past the scale | |
| 4072 if (logo.y_axis) { | |
| 4073 ctx.translate(Math.round(metrics.y_label_height + metrics.y_label_spacer + | |
| 4074 metrics.y_num_width + metrics.y_tic_width), Math.round(metrics.y_num_height / 2)); | |
| 4075 } | |
| 4076 //draw the trimming background | |
| 4077 if (pspm.get_left_trim() > 0 || pspm.get_right_trim() > 0) { | |
| 4078 var left_start = offset * logo.get_xlate_nsyms(); | |
| 4079 var left_end = (offset + pspm.get_left_trim()) * logo.get_xlate_nsyms(); | |
| 4080 var left_divider = true; | |
| 4081 if (left_end < logo.get_xlate_start() || left_start > logo.get_xlate_end()) { | |
| 4082 // no overlap | |
| 4083 left_start = 0; | |
| 4084 left_end = 0; | |
| 4085 left_divider = false; | |
| 4086 } else { | |
| 4087 if (left_start < logo.get_xlate_start()) { | |
| 4088 left_start = logo.get_xlate_start(); | |
| 4089 } | |
| 4090 if (left_end > logo.get_xlate_end()) { | |
| 4091 left_end = logo.get_xlate_end(); | |
| 4092 left_divider = false; | |
| 4093 } | |
| 4094 left_start -= logo.get_xlate_start(); | |
| 4095 left_end -= logo.get_xlate_start(); | |
| 4096 if (left_end < left_start) { | |
| 4097 left_start = 0; | |
| 4098 left_end = 0; | |
| 4099 left_divider = false; | |
| 4100 } | |
| 4101 } | |
| 4102 var right_end = (offset + pspm.get_motif_length()) * logo.get_xlate_nsyms(); | |
| 4103 //var right_start = right_end - (pspm.get_left_trim() * logo.get_xlate_nsyms()); | |
| 4104 var right_start = right_end - (pspm.get_right_trim() * logo.get_xlate_nsyms()); | |
| 4105 var right_divider = true; | |
| 4106 if (right_end < logo.get_xlate_start() || right_start > logo.get_xlate_end()) { | |
| 4107 // no overlap | |
| 4108 right_start = 0; | |
| 4109 right_end = 0; | |
| 4110 right_divider = false; | |
| 4111 } else { | |
| 4112 if (right_start < logo.get_xlate_start()) { | |
| 4113 right_start = logo.get_xlate_start(); | |
| 4114 right_divider = false; | |
| 4115 } | |
| 4116 if (right_end > logo.get_xlate_end()) { | |
| 4117 right_end = logo.get_xlate_end(); | |
| 4118 } | |
| 4119 right_start -= logo.get_xlate_start(); | |
| 4120 right_end -= logo.get_xlate_start(); | |
| 4121 if (right_end < right_start) { | |
| 4122 right_start = 0; | |
| 4123 right_end = 0; | |
| 4124 right_divider = false; | |
| 4125 } | |
| 4126 } | |
| 4127 draw_trim_background(ctx, metrics, left_start, left_end, left_divider, right_start, right_end, right_divider); | |
| 4128 } | |
| 4129 //draw letters | |
| 4130 var xlate_col; | |
| 4131 for (xlate_col = logo.get_xlate_start(); xlate_col < logo.get_xlate_end(); xlate_col++) { | |
| 4132 ctx.translate(metrics.stack_pad_left,0); | |
| 4133 col_index = Math.floor(xlate_col / logo.get_xlate_nsyms()); | |
| 4134 if (xlate_col % logo.get_xlate_nsyms() == 0) { | |
| 4135 if (col_index >= offset && col_index < (offset + pspm.get_motif_length())) { | |
| 4136 motif_position = col_index - offset; | |
| 4137 draw_stack_num(ctx, metrics, motif_position, raster); | |
| 4138 draw_stack(ctx, metrics, pspm.get_stack(motif_position, logo.alphabet, ssc), raster); | |
| 4139 } | |
| 4140 } else { | |
| 4141 if (col_index >= offset && col_index < (offset + pspm.get_motif_length())) { | |
| 4142 ctx.save();// s5.1 | |
| 4143 ctx.translate(0, Math.round(metrics.stack_height)); | |
| 4144 // TODO draw a dot or dash or something to indicate continuity of the motif | |
| 4145 ctx.restore(); //s5.1 | |
| 4146 } | |
| 4147 } | |
| 4148 ctx.translate(Math.round(metrics.stack_width), 0); | |
| 4149 } | |
| 4150 ctx.restore();//s5 | |
| 4151 ////optionally draw name if this is the last row but isn't the only row | |
| 4152 if (draw_name && (logo.get_rows() != 1 && pspm_i == (logo.get_rows()-1))) { | |
| 4153 //translate vertically past the stack and axis's | |
| 4154 ctx.translate(0, metrics.y_num_height/2 + metrics.stack_height + | |
| 4155 Math.max(metrics.y_num_height/2, metrics.x_num_above + metrics.x_num_width + metrics.name_spacer)); | |
| 4156 | |
| 4157 ctx.save();//s6 | |
| 4158 ctx.translate(metrics.summed_width/2, metrics.name_height); | |
| 4159 ctx.font = metrics.name_font; | |
| 4160 ctx.textAlign = "center"; | |
| 4161 ctx.fillText(pspm.name, 0, 0); | |
| 4162 ctx.restore();//s6 | |
| 4163 ctx.translate(0, metrics.name_height); | |
| 4164 } else { | |
| 4165 //translate vertically past the stack and axis's | |
| 4166 ctx.translate(0, metrics.y_num_height/2 + metrics.stack_height + | |
| 4167 Math.max(metrics.y_num_height/2, metrics.x_num_above + metrics.x_num_width)); | |
| 4168 } | |
| 4169 //if not the last row then add middle padding | |
| 4170 if (pspm_i != (logo.get_rows() -1)) { | |
| 4171 ctx.translate(0, metrics.pad_middle); | |
| 4172 } | |
| 4173 } | |
| 4174 ctx.restore();//s7 | |
| 4175 if (logo.fine_text.length > 0) { | |
| 4176 ctx.translate(metrics.summed_width - metrics.pad_right, metrics.summed_height - metrics.pad_bottom); | |
| 4177 ctx.font = metrics.fine_txt_font; | |
| 4178 ctx.textAlign = "right"; | |
| 4179 ctx.fillText(logo.fine_text, 0,0); | |
| 4180 } | |
| 4181 ctx.restore();//s2 | |
| 4182 ctx.restore();//s1 | |
| 4183 } | |
| 4184 | |
| 4185 function create_canvas(c_width, c_height, c_id, c_title, c_display) { | |
| 4186 "use strict"; | |
| 4187 var canvas = document.createElement("canvas"); | |
| 4188 //check for canvas support before attempting anything | |
| 4189 if (!canvas.getContext) { | |
| 4190 return null; | |
| 4191 } | |
| 4192 var ctx = canvas.getContext('2d'); | |
| 4193 //check for html5 text drawing support | |
| 4194 if (!supports_text(ctx)) { | |
| 4195 return null; | |
| 4196 } | |
| 4197 //size the canvas | |
| 4198 canvas.width = c_width; | |
| 4199 canvas.height = c_height; | |
| 4200 canvas.id = c_id; | |
| 4201 canvas.title = c_title; | |
| 4202 canvas.style.display = c_display; | |
| 4203 return canvas; | |
| 4204 } | |
| 4205 | |
| 4206 function logo_1(alphabet, fine_text, pspm) { | |
| 4207 "use strict"; | |
| 4208 var logo = new Logo(alphabet, fine_text); | |
| 4209 logo.add_pspm(pspm); | |
| 4210 return logo; | |
| 4211 } | |
| 4212 | |
| 4213 function logo_2(alphabet, fine_text, target, query, query_offset) { | |
| 4214 "use strict"; | |
| 4215 var logo = new Logo(alphabet, fine_text); | |
| 4216 if (query_offset < 0) { | |
| 4217 logo.add_pspm(target, -query_offset); | |
| 4218 logo.add_pspm(query); | |
| 4219 } else { | |
| 4220 logo.add_pspm(target); | |
| 4221 logo.add_pspm(query, query_offset); | |
| 4222 } | |
| 4223 return logo; | |
| 4224 } | |
| 4225 | |
| 4226 /* | |
| 4227 * Specifies an alternate source for an image. | |
| 4228 * If the image with the image_id specified has | |
| 4229 * not loaded then a generated logo will be used | |
| 4230 * to replace it. | |
| 4231 * | |
| 4232 * Note that the image must either have dimensions | |
| 4233 * or a scale must be set. | |
| 4234 */ | |
| 4235 function alternate_logo(logo, image_id, scale) { | |
| 4236 "use strict"; | |
| 4237 var image = document.getElementById(image_id); | |
| 4238 if (!image) { | |
| 4239 alert("Can't find specified image id (" + image_id + ")"); | |
| 4240 return; | |
| 4241 } | |
| 4242 //if the image has loaded then there is no reason to use the canvas | |
| 4243 if (image_ok(image)) { | |
| 4244 return; | |
| 4245 } | |
| 4246 //the image has failed to load so replace it with a canvas if we can. | |
| 4247 var canvas = create_canvas(image.width, image.height, image_id, image.title, image.style.display); | |
| 4248 if (canvas === null) { | |
| 4249 return; | |
| 4250 } | |
| 4251 //draw the logo on the canvas | |
| 4252 draw_logo_on_canvas(logo, canvas, null, scale); | |
| 4253 //replace the image with the canvas | |
| 4254 image.parentNode.replaceChild(canvas, image); | |
| 4255 } | |
| 4256 | |
| 4257 /* | |
| 4258 * Specifes that the element with the specified id | |
| 4259 * should be replaced with a generated logo. | |
| 4260 */ | |
| 4261 function replace_logo(logo, replace_id, scale, title_txt, display_style) { | |
| 4262 "use strict"; | |
| 4263 var element = document.getElementById(replace_id); | |
| 4264 if (!replace_id) { | |
| 4265 alert("Can't find specified id (" + replace_id + ")"); | |
| 4266 return; | |
| 4267 } | |
| 4268 //found the element! | |
| 4269 var canvas = create_canvas(50, 120, replace_id, title_txt, display_style); | |
| 4270 if (canvas === null) { | |
| 4271 return; | |
| 4272 } | |
| 4273 //draw the logo on the canvas | |
| 4274 draw_logo_on_canvas(logo, canvas, null, scale); | |
| 4275 //replace the element with the canvas | |
| 4276 element.parentNode.replaceChild(canvas, element); | |
| 4277 } | |
| 4278 | |
| 4279 /* | |
| 4280 * Fast string trimming implementation found at | |
| 4281 * http://blog.stevenlevithan.com/archives/faster-trim-javascript | |
| 4282 * | |
| 4283 * Note that regex is good at removing leading space but | |
| 4284 * bad at removing trailing space as it has to first go through | |
| 4285 * the whole string. | |
| 4286 */ | |
| 4287 function trim (str) { | |
| 4288 "use strict"; | |
| 4289 var ws, i; | |
| 4290 str = str.replace(/^\s\s*/, ''); | |
| 4291 ws = /\s/; i = str.length; | |
| 4292 while (ws.test(str.charAt(--i))); | |
| 4293 return str.slice(0, i + 1); | |
| 4294 } | |
| 4295 </script> | |
| 4296 <script> | |
| 4297 | |
| 4298 // PRIVATE GLOBAL (uhoh) | |
| 4299 var _block_colour_lookup = {}; | |
| 4300 | |
| 4301 function block_colour(index) { | |
| 4302 function hsl2rgb(hue, saturation, lightness) { | |
| 4303 "use strict"; | |
| 4304 function _hue(p, q, t) { | |
| 4305 "use strict"; | |
| 4306 if (t < 0) t += 1; | |
| 4307 else if (t > 1) t -= 1; | |
| 4308 if (t < (1.0 / 6.0)) { | |
| 4309 return p + ((q - p) * 6.0 * t); | |
| 4310 } else if (t < 0.5) { | |
| 4311 return q; | |
| 4312 } else if (t < (2.0 / 3.0)) { | |
| 4313 return p + ((q - p) * ((2.0 / 3.0) - t) * 6.0); | |
| 4314 } else { | |
| 4315 return p; | |
| 4316 } | |
| 4317 } | |
| 4318 function _pad_hex(value) { | |
| 4319 var hex = Math.round(value * 255).toString(16); | |
| 4320 if (hex.length < 2) hex = "0" + hex; | |
| 4321 return hex; | |
| 4322 } | |
| 4323 var r, g, b, p, q; | |
| 4324 if (saturation == 0) { | |
| 4325 // achromatic (grayscale) | |
| 4326 r = lightness; | |
| 4327 g = lightness; | |
| 4328 b = lightness; | |
| 4329 } else { | |
| 4330 if (lightness < 0.5) { | |
| 4331 q = lightness * (1 + saturation); | |
| 4332 } else { | |
| 4333 q = lightness + saturation - (lightness * saturation); | |
| 4334 } | |
| 4335 p = (2 * lightness) - q; | |
| 4336 r = _hue(p, q, hue + (1.0 / 3.0)); | |
| 4337 g = _hue(p, q, hue); | |
| 4338 b = _hue(p, q, hue - (1.0 / 3.0)); | |
| 4339 } | |
| 4340 return "#" + _pad_hex(r) + _pad_hex(g) + _pad_hex(b); | |
| 4341 } | |
| 4342 if (typeof index !== "number" || index % 1 !== 0 || index < 0) return "#000000"; | |
| 4343 // check for override | |
| 4344 if (_block_colour_lookup[index] == null) { | |
| 4345 var start = 0; //red | |
| 4346 var sat = 100; | |
| 4347 var light = 50; | |
| 4348 var divisions = 1 << Math.ceil(Math.log(index + 1) / Math.LN2); | |
| 4349 hue = start + (360 / divisions) * ((index - (divisions >> 1)) * 2 + 1); | |
| 4350 // colour input fields only support values in the form #RRGGBB | |
| 4351 _block_colour_lookup[index] = hsl2rgb(hue / 360, sat / 100, light / 100); | |
| 4352 } | |
| 4353 return _block_colour_lookup[index]; | |
| 4354 } | |
| 4355 | |
| 4356 function set_block_colour(index, new_colour) { | |
| 4357 _block_colour_lookup[index] = new_colour; | |
| 4358 var blocks = document.querySelectorAll("div.block_motif[data-colour-index=\"" + index + "\"]"); | |
| 4359 var i; | |
| 4360 for (i = 0; i < blocks.length; i++) { | |
| 4361 blocks[i].style.backgroundColor = new_colour; | |
| 4362 } | |
| 4363 var swatches = document.querySelectorAll("div.legend_swatch[data-colour-index=\"" + index + "\"]"); | |
| 4364 var picker; | |
| 4365 for (i = 0; i < swatches.length; i++) { | |
| 4366 swatches[i].style.backgroundColor = new_colour; | |
| 4367 picker = swatches[i].querySelector("input[type=\"color\"]"); | |
| 4368 if (picker != null) picker.value = new_colour; | |
| 4369 } | |
| 4370 } | |
| 4371 | |
| 4372 function make_block_legend_entry(motif_name, motif_colour_index) { | |
| 4373 if (typeof make_block_legend_entry.has_colour_picker !== "boolean") { | |
| 4374 // test if colour picker is supported, based off Modernizer | |
| 4375 // see http://stackoverflow.com/a/7787648/66387 | |
| 4376 make_block_legend_entry.has_colour_picker = (function() { | |
| 4377 var doc_ele = document.documentElement; | |
| 4378 // We first check to see if the type we give it sticks.. | |
| 4379 var input_ele = document.createElement('input'); | |
| 4380 input_ele.setAttribute('type', 'color'); | |
| 4381 var value_ok = input_ele.type !== 'text'; | |
| 4382 if (value_ok) { | |
| 4383 // If the type does, we feed it a textual value, which shouldn't be valid. | |
| 4384 // If the value doesn't stick, we know there's input sanitization which infers a custom UI | |
| 4385 var smile = ':)'; | |
| 4386 input_ele.value = smile; | |
| 4387 input_ele.style.cssText = 'position:absolute;visibility:hidden;'; | |
| 4388 // chuck into DOM and force reflow for Opera bug in 11.00 | |
| 4389 // github.com/Modernizr/Modernizr/issues#issue/159 | |
| 4390 doc_ele.appendChild(input_ele); | |
| 4391 doc_ele.offsetWidth; | |
| 4392 value_ok = input_ele.value != smile; | |
| 4393 doc_ele.removeChild(input_ele); | |
| 4394 } | |
| 4395 return value_ok; | |
| 4396 })(); | |
| 4397 } | |
| 4398 var entry = document.createElement("div"); | |
| 4399 entry.className = "legend_entry"; | |
| 4400 var swatch; | |
| 4401 swatch = document.createElement("div"); | |
| 4402 swatch.className = "legend_swatch"; | |
| 4403 swatch.setAttribute("data-colour-index", motif_colour_index); | |
| 4404 swatch.style.backgroundColor = block_colour(motif_colour_index); | |
| 4405 if (make_block_legend_entry.has_colour_picker) { | |
| 4406 var picker = document.createElement("input"); | |
| 4407 picker.type = "color"; | |
| 4408 picker.value = block_colour(motif_colour_index); | |
| 4409 picker.addEventListener("change", function(e) { | |
| 4410 set_block_colour(motif_colour_index, picker.value); | |
| 4411 }, false); | |
| 4412 swatch.addEventListener("click", function(e) { | |
| 4413 picker.click(); | |
| 4414 }, false); | |
| 4415 swatch.appendChild(picker); | |
| 4416 } | |
| 4417 entry.appendChild(swatch); | |
| 4418 var name = document.createElement("div"); | |
| 4419 name.className = "legend_text"; | |
| 4420 name.appendChild(document.createTextNode(motif_name)); | |
| 4421 entry.appendChild(name); | |
| 4422 return entry; | |
| 4423 } | |
| 4424 | |
| 4425 function make_block_ruler(max_len) { | |
| 4426 var container = document.createElement("div"); | |
| 4427 container.className = "block_container"; | |
| 4428 var step; | |
| 4429 if (max_len < 50) { | |
| 4430 step = 1; | |
| 4431 } else if (max_len < 100) { | |
| 4432 step = 2; | |
| 4433 } else if (max_len < 200) { | |
| 4434 step = 4; | |
| 4435 } else if (max_len < 500) { | |
| 4436 step = 10; | |
| 4437 } else if (max_len < 1000) { | |
| 4438 step = 20; | |
| 4439 } else if (max_len < 2000) { | |
| 4440 step = 40; | |
| 4441 } else if (max_len < 5000) { | |
| 4442 step = 100; | |
| 4443 } else if (max_len < 10000) { | |
| 4444 step = 200; | |
| 4445 } else if (max_len < 20000) { | |
| 4446 step = 400; | |
| 4447 } else { | |
| 4448 step = Math.floor(max_len / 20000) * 400; | |
| 4449 } | |
| 4450 var peroid; | |
| 4451 if (max_len < 10) { | |
| 4452 peroid = 1; | |
| 4453 } else if (max_len < 20) { | |
| 4454 peroid = 2; | |
| 4455 } else { | |
| 4456 peroid = 5; | |
| 4457 } | |
| 4458 var i, cycle, offset, tic, label; | |
| 4459 for (i = 0, cycle = 0; i < max_len; i += step, cycle = (cycle + 1) % peroid) { | |
| 4460 offset = "" + ((i / max_len) * 100) + "%"; | |
| 4461 tic = document.createElement("div"); | |
| 4462 tic.style.left = offset; | |
| 4463 tic.className = (cycle == 0 ? "tic_major" : "tic_minor"); | |
| 4464 container.appendChild(tic); | |
| 4465 if (cycle == 0) { | |
| 4466 label = document.createElement("div"); | |
| 4467 label.className = "tic_label"; | |
| 4468 label.style.left = offset; | |
| 4469 label.appendChild(document.createTextNode(i)); | |
| 4470 container.appendChild(label); | |
| 4471 } | |
| 4472 } | |
| 4473 return container; | |
| 4474 } | |
| 4475 | |
| 4476 function _calculate_block_needle_drag_pos(e, data) { | |
| 4477 var mouse; | |
| 4478 e = e || window.event; | |
| 4479 if (e.pageX || ev.pageY) { | |
| 4480 mouse = {"x": e.pageX, "y": e.pageY}; | |
| 4481 } else { | |
| 4482 mouse = { | |
| 4483 x:e.clientX + document.body.scrollLeft - document.body.clientLeft, | |
| 4484 y:e.clientY + document.body.scrollTop - document.body.clientTop | |
| 4485 }; | |
| 4486 } | |
| 4487 var cont = data.container; | |
| 4488 var dragable_length = cont.clientWidth - | |
| 4489 (cont.style.paddingLeft ? cont.style.paddingLeft : 0) - | |
| 4490 (cont.style.paddingRight ? cont.style.paddingRight : 0); | |
| 4491 //I believe that the offset parent is the body | |
| 4492 //otherwise I would need to make this recursive | |
| 4493 //maybe clientLeft would work, but the explanation of | |
| 4494 //it is hard to understand and it apparently doesn't work | |
| 4495 //in firefox 2. | |
| 4496 var diff = mouse.x - cont.offsetLeft; | |
| 4497 if (diff < 0) diff = 0; | |
| 4498 if (diff > dragable_length) diff = dragable_length; | |
| 4499 var pos = Math.round(diff / dragable_length * data.max); | |
| 4500 if (pos > data.len) pos = data.len; | |
| 4501 return pos; | |
| 4502 } | |
| 4503 | |
| 4504 function _update_block_needle_drag(e, data, done) { | |
| 4505 "use strict"; | |
| 4506 var pos = _calculate_block_needle_drag_pos(e, data); | |
| 4507 // read the needle positions | |
| 4508 var left = parseInt(data.llabel.textContent, 10) - data.off - 1; | |
| 4509 var right = parseInt(data.rlabel.textContent, 10) - data.off; | |
| 4510 // validate needle positions | |
| 4511 if (left >= data.len) left = data.len - 1; | |
| 4512 if (left < 0) left = 0; | |
| 4513 if (right > data.len) right = data.len; | |
| 4514 if (right <= left) right = left + 1; | |
| 4515 // calculate the new needle positions | |
| 4516 if (data.moveboth) { | |
| 4517 var size = right - left; | |
| 4518 if (data.isleft) { | |
| 4519 if ((pos + size) > data.len) pos = data.len - size; | |
| 4520 left = pos; | |
| 4521 right = pos + size; | |
| 4522 } else { | |
| 4523 if ((pos - size) < 0) pos = size; | |
| 4524 left = pos - size; | |
| 4525 right = pos; | |
| 4526 } | |
| 4527 } else { | |
| 4528 if (data.isleft) { | |
| 4529 if (pos >= right) pos = right - 1; | |
| 4530 left = pos; | |
| 4531 } else { | |
| 4532 if (pos <= left) pos = left + 1; | |
| 4533 right = pos; | |
| 4534 } | |
| 4535 } | |
| 4536 // update the needle positions | |
| 4537 data.lneedle.style.left = "" + (left / data.max * 100) + "%"; | |
| 4538 data.llabel.textContent = "" + (left + data.off + 1); | |
| 4539 data.rneedle.style.left = "" + (right / data.max * 100) + "%"; | |
| 4540 data.rlabel.textContent = "" + (right + data.off); | |
| 4541 data.handler(left, right, done); | |
| 4542 } | |
| 4543 | |
| 4544 function _make_block_needle_drag_start_handler(isleft, data) { | |
| 4545 return function (e) { | |
| 4546 data.isleft = isleft; | |
| 4547 data.moveboth = !(e.shiftKey); | |
| 4548 document.addEventListener("mousemove", data.drag_during, false); | |
| 4549 document.addEventListener("mouseup", data.drag_end, false); | |
| 4550 }; | |
| 4551 } | |
| 4552 | |
| 4553 function _make_block_needle_drag_end_handler(data) { | |
| 4554 return function (e) { | |
| 4555 document.removeEventListener("mousemove", data.drag_during, false); | |
| 4556 document.removeEventListener("mouseup", data.drag_end, false); | |
| 4557 _update_block_needle_drag(e, data, true); | |
| 4558 }; | |
| 4559 } | |
| 4560 | |
| 4561 function _make_block_needle_drag_during_handler(data) { | |
| 4562 return function (e) { | |
| 4563 _update_block_needle_drag(e, data, false); | |
| 4564 }; | |
| 4565 } | |
| 4566 | |
| 4567 // private function used by make_block_container | |
| 4568 function _make_block_needle(isleft, value, data) { | |
| 4569 var vbar = document.createElement('div'); | |
| 4570 vbar.className = "block_needle " + (isleft ? "left" : "right"); | |
| 4571 vbar.style.left = "" + (value / data.max * 100)+ "%"; | |
| 4572 var label = document.createElement('div'); | |
| 4573 label.className = "block_handle " + (isleft ? "left" : "right"); | |
| 4574 // The needles sit between the sequence positions, so the left one sits at the | |
| 4575 // start and the right at the end. This is why 1 is added to the displayed | |
| 4576 // value for a left handle as the user doesn't need to know about this detail | |
| 4577 label.textContent = "" + (isleft ? value + data.off + 1 : value + data.off); | |
| 4578 label.unselectable = "on"; // so IE and Opera don't select the text, others are done in css | |
| 4579 label.title = "Drag to move the displayed range. Hold shift and drag to change " + (isleft ? "lower" : "upper") + " bound of the range."; | |
| 4580 vbar.appendChild(label); | |
| 4581 if (isleft) { | |
| 4582 data.lneedle = vbar; | |
| 4583 data.llabel = label; | |
| 4584 } else { | |
| 4585 data.rneedle = vbar; | |
| 4586 data.rlabel = label; | |
| 4587 } | |
| 4588 label.addEventListener("mousedown", _make_block_needle_drag_start_handler(isleft, data), false); | |
| 4589 return vbar; | |
| 4590 } | |
| 4591 | |
| 4592 function make_block_container(is_stranded, has_both_strands, max_len, show_len, offset, range_handler) { | |
| 4593 offset = (offset != null ? offset : 0); | |
| 4594 // make the container for the block diagram | |
| 4595 var container = document.createElement("div"); | |
| 4596 container.className = "block_container"; | |
| 4597 container.setAttribute("data-max", max_len); | |
| 4598 container.setAttribute("data-off", offset); | |
| 4599 if (is_stranded) { | |
| 4600 var plus = document.createElement("div"); | |
| 4601 plus.appendChild(document.createTextNode("+")); | |
| 4602 plus.className = "block_plus_sym"; | |
| 4603 container.appendChild(plus); | |
| 4604 if (has_both_strands) { | |
| 4605 var minus = document.createElement("div"); | |
| 4606 minus.appendChild(document.createTextNode("-")); | |
| 4607 minus.className = "block_minus_sym"; | |
| 4608 container.appendChild(minus); | |
| 4609 } | |
| 4610 } | |
| 4611 var rule = document.createElement("div"); | |
| 4612 rule.className = "block_rule"; | |
| 4613 rule.style.width = ((show_len / max_len) * 100) + "%"; | |
| 4614 container.appendChild(rule); | |
| 4615 if (range_handler != null) { | |
| 4616 var range_data = { | |
| 4617 "max": max_len, | |
| 4618 "len": show_len, | |
| 4619 "off": offset, | |
| 4620 "handler": range_handler, | |
| 4621 "container": container, | |
| 4622 "lneedle": null, "llabel": null, | |
| 4623 "rneedle": null, "rlabel": null, | |
| 4624 "isleft": false, "moveboth" : false | |
| 4625 }; | |
| 4626 range_data.drag_during = _make_block_needle_drag_during_handler(range_data); | |
| 4627 range_data.drag_end = _make_block_needle_drag_end_handler(range_data); | |
| 4628 container.appendChild(_make_block_needle(false, 1, range_data)); // add right first so z-index works | |
| 4629 container.appendChild(_make_block_needle(true, 0, range_data)); | |
| 4630 } | |
| 4631 return container; | |
| 4632 } | |
| 4633 | |
| 4634 function make_block_label(container, max_len, pos, length, message) { | |
| 4635 "use strict"; | |
| 4636 var label = document.createElement("div"); | |
| 4637 label.className = "block_label"; | |
| 4638 label.style.left = (((pos + (length / 2)) / max_len) * 100) + "%"; | |
| 4639 label.appendChild(document.createTextNode(message)); | |
| 4640 container.appendChild(label); | |
| 4641 } | |
| 4642 | |
| 4643 function make_block(container, max_len, | |
| 4644 site_pos, site_len, site_pvalue, site_rc, site_colour_index, site_secondary) { | |
| 4645 "use strict"; | |
| 4646 var block_height, block, block_region1, block_region2; | |
| 4647 var max_block_height = 12; | |
| 4648 var max_pvalue = 1e-10; | |
| 4649 // calculate the height of the block | |
| 4650 block_height = (site_pvalue < max_pvalue ? max_block_height : | |
| 4651 (Math.log(site_pvalue) / Math.log(max_pvalue)) * max_block_height); | |
| 4652 if (block_height < 1) block_height = 1; | |
| 4653 // create a block to represent the motif | |
| 4654 block = document.createElement("div"); | |
| 4655 block.className = "block_motif" + (site_secondary ? " scanned_site" : "") + (site_rc ? " bottom" : " top"); | |
| 4656 block.style.left = ((site_pos / max_len) * 100) + "%"; | |
| 4657 block.style.top = (!site_rc ? max_block_height - block_height : | |
| 4658 max_block_height + 1) + "px"; | |
| 4659 block.style.width = ((site_len / max_len) * 100) + "%"; | |
| 4660 block.style.height = block_height + "px"; | |
| 4661 block.style.backgroundColor = block_colour(site_colour_index); | |
| 4662 block.setAttribute("data-colour-index", site_colour_index); | |
| 4663 // add to container | |
| 4664 container.appendChild(block); | |
| 4665 var activator = function (e) { | |
| 4666 toggle_class(block, "active", true); | |
| 4667 var new_e = new e.constructor(e.type, e); | |
| 4668 block.dispatchEvent(new_e); | |
| 4669 }; | |
| 4670 var deactivator = function (e) { | |
| 4671 toggle_class(block, "active", false); | |
| 4672 var new_e = new e.constructor(e.type, e); | |
| 4673 block.dispatchEvent(new_e); | |
| 4674 } | |
| 4675 // create a larger region to detect mouseover for the block | |
| 4676 block_region1 = document.createElement("div"); | |
| 4677 block_region1.className = "block_region top" + | |
| 4678 (site_secondary ? " scanned_site" : "") + (site_rc ? "" : " main"); | |
| 4679 block_region1.style.left = block.style.left; | |
| 4680 block_region1.style.width = block.style.width; | |
| 4681 block_region1.addEventListener('mouseover', activator, false); | |
| 4682 block_region1.addEventListener('mouseout', deactivator, false); | |
| 4683 container.appendChild(block_region1); | |
| 4684 block_region2 = document.createElement("div"); | |
| 4685 block_region2.className = "block_region bottom" + | |
| 4686 (site_secondary ? " scanned_site" : "") + (site_rc ? " main" : ""); | |
| 4687 block_region2.style.left = block.style.left; | |
| 4688 block_region2.style.width = block.style.width; | |
| 4689 block_region2.addEventListener('mouseover', activator, false); | |
| 4690 block_region2.addEventListener('mouseout', deactivator, false); | |
| 4691 container.appendChild(block_region2); | |
| 4692 return block; | |
| 4693 } | |
| 4694 | |
| 4695 function set_block_needle_positions(containingNode, start, end) { | |
| 4696 var container, lneedle, llabel, rneedle, rlabel, max, off, left, right; | |
| 4697 container = (/\bblock_container\b/.test(containingNode.className) ? containingNode : containingNode.querySelector(".block_container")); | |
| 4698 max = parseInt(container.getAttribute("data-max"), 10); | |
| 4699 off = parseInt(container.getAttribute("data-off"), 10); | |
| 4700 left = start - off; | |
| 4701 right = end - off; | |
| 4702 lneedle = containingNode.querySelector(".block_needle.left"); | |
| 4703 llabel = lneedle.querySelector(".block_handle.left"); | |
| 4704 rneedle = containingNode.querySelector(".block_needle.right"); | |
| 4705 rlabel = rneedle.querySelector(".block_handle.right"); | |
| 4706 // update the needle positions | |
| 4707 lneedle.style.left = "" + (left / max * 100) + "%"; | |
| 4708 llabel.textContent = "" + (left + off + 1); | |
| 4709 rneedle.style.left = "" + (right / max * 100) + "%"; | |
| 4710 rlabel.textContent = "" + (right + off); | |
| 4711 } | |
| 4712 | |
| 4713 function get_block_needle_positions(containingNode) { | |
| 4714 var container, llabel, rlabel, max, off, left, right; | |
| 4715 container = (/\bblock_container\b/.test(containingNode.className) ? containingNode : containingNode.querySelector(".block_container")); | |
| 4716 max = parseInt(container.getAttribute("data-max"), 10); | |
| 4717 off = parseInt(container.getAttribute("data-off"), 10); | |
| 4718 llabel = containingNode.querySelector(".block_needle.left > .block_handle.left"); | |
| 4719 rlabel = containingNode.querySelector(".block_needle.right > .block_handle.right"); | |
| 4720 left = parseInt(llabel.textContent, 10) - off - 1; | |
| 4721 right = parseInt(rlabel.textContent, 10) - off; | |
| 4722 return {"start": left + off, "end": right + off}; | |
| 4723 } | |
| 4724 </script> | |
| 4725 <script> | |
| 4726 function make_alpha_bg_table(alph, freqs) { | |
| 4727 function colour_symbol(index) { | |
| 4728 var span = document.createElement("span"); | |
| 4729 span.appendChild(document.createTextNode(alph.get_symbol(index))); | |
| 4730 span.style.color = alph.get_colour(index); | |
| 4731 span.className = "alpha_symbol"; | |
| 4732 return span; | |
| 4733 } | |
| 4734 var table, thead, tbody, row, th, span, i; | |
| 4735 // create table | |
| 4736 table = document.createElement("table"); | |
| 4737 table.className = "alpha_bg_table"; | |
| 4738 // create header | |
| 4739 thead = document.createElement("thead"); | |
| 4740 table.appendChild(thead); | |
| 4741 row = thead.insertRow(thead.rows.length); | |
| 4742 if (alph.has_complement()) { | |
| 4743 add_text_header_cell(row, "Name", "pop_alph_name"); | |
| 4744 if (freqs != null) add_text_header_cell(row, "Freq.", "pop_alph_freq"); | |
| 4745 if (alph.has_bg()) add_text_header_cell(row, "Bg.", "pop_alph_bg"); | |
| 4746 add_text_header_cell(row, ""); | |
| 4747 add_text_header_cell(row, ""); | |
| 4748 add_text_header_cell(row, ""); | |
| 4749 if (alph.has_bg()) add_text_header_cell(row, "Bg.", "pop_alph_bg"); | |
| 4750 if (freqs != null) add_text_header_cell(row, "Freq.", "pop_alph_freq"); | |
| 4751 add_text_header_cell(row, "Name", "pop_alph_name"); | |
| 4752 } else { | |
| 4753 add_text_header_cell(row, ""); | |
| 4754 add_text_header_cell(row, "Name", "pop_alph_name"); | |
| 4755 if (freqs != null) add_text_header_cell(row, "Freq.", "pop_alph_freq"); | |
| 4756 if (alph.has_bg()) add_text_header_cell(row, "Bg.", "pop_alph_bg"); | |
| 4757 } | |
| 4758 // add alphabet entries | |
| 4759 tbody = document.createElement("tbody"); | |
| 4760 table.appendChild(tbody); | |
| 4761 if (alph.has_complement()) { | |
| 4762 for (i = 0; i < alph.get_size_core(); i++) { | |
| 4763 var c = alph.get_complement(i); | |
| 4764 if (i > c) continue; | |
| 4765 row = tbody.insertRow(tbody.rows.length); | |
| 4766 add_text_cell(row, alph.get_name(i)); | |
| 4767 if (freqs != null) add_text_cell(row, "" + freqs[i].toFixed(3)); | |
| 4768 if (alph.has_bg()) add_text_cell(row, "" + alph.get_bg_freq(i).toFixed(3)); | |
| 4769 add_cell(row, colour_symbol(i)); | |
| 4770 add_text_cell(row, "~"); | |
| 4771 add_cell(row, colour_symbol(c)); | |
| 4772 if (alph.has_bg()) add_text_cell(row, "" + alph.get_bg_freq(c).toFixed(3)); | |
| 4773 if (freqs != null) add_text_cell(row, "" + freqs[c].toFixed(3)); | |
| 4774 add_text_cell(row, alph.get_name(c)); | |
| 4775 } | |
| 4776 } else { | |
| 4777 for (i = 0; i < alph.get_size_core(); i++) { | |
| 4778 row = tbody.insertRow(tbody.rows.length); | |
| 4779 add_cell(row, colour_symbol(i)); | |
| 4780 add_text_cell(row, alph.get_name(i)); | |
| 4781 if (freqs != null) add_text_cell(row, "" + freqs[i].toFixed(3)); | |
| 4782 if (alph.has_bg()) add_text_cell(row, "" + alph.get_bg_freq(i).toFixed(3)); | |
| 4783 } | |
| 4784 } | |
| 4785 return table; | |
| 4786 } | |
| 4787 | |
| 4788 </script> | |
| 4789 <script> | |
| 4790 var current_motif = 0; | |
| 4791 var meme_alphabet = new Alphabet(data.alphabet, data.background.freqs); | |
| 4792 | |
| 4793 var DelayLogoTask = function(logo, canvas) { | |
| 4794 this.logo = logo; | |
| 4795 this.canvas = canvas; | |
| 4796 }; | |
| 4797 | |
| 4798 DelayLogoTask.prototype.run = function () { | |
| 4799 draw_logo_on_canvas(this.logo, this.canvas, false); | |
| 4800 }; | |
| 4801 | |
| 4802 function motif_pspm(index) { | |
| 4803 var motif, pwm, psm, name, ltrim, rtrim, nsites, evalue; | |
| 4804 // get motif | |
| 4805 motif = data["motifs"][index]; | |
| 4806 // get motif paramters | |
| 4807 pwm = motif["pwm"]; | |
| 4808 psm = motif["psm"]; | |
| 4809 name = "" + (index + 1); ltrim = 0; rtrim = 0; | |
| 4810 nsites = motif["nsites"]; evalue = motif["evalue"]; | |
| 4811 // make pspm | |
| 4812 return new Pspm(pwm, name, ltrim, rtrim, nsites, evalue, psm); | |
| 4813 } | |
| 4814 | |
| 4815 function motif_count_matrix(index) { | |
| 4816 return motif_pspm(index).as_count_matrix(); | |
| 4817 } | |
| 4818 | |
| 4819 function motif_prob_matrix(index) { | |
| 4820 return motif_pspm(index).as_probability_matrix(); | |
| 4821 } | |
| 4822 | |
| 4823 function motif_minimal_meme(index) { | |
| 4824 return motif_pspm(index).as_meme({ | |
| 4825 "with_header": true, | |
| 4826 "with_pspm": true, | |
| 4827 "with_pssm": true, | |
| 4828 "version": data["version"], | |
| 4829 "alphabet": meme_alphabet, | |
| 4830 "strands": (meme_alphabet.has_complement() && data.options.revcomp ? 2 : 1) | |
| 4831 }); | |
| 4832 } | |
| 4833 | |
| 4834 function motif_fasta(index) { | |
| 4835 "use strict"; | |
| 4836 var motif, sites, site, seq, sequences, sequence, i, num, counter, out; | |
| 4837 counter = {}; | |
| 4838 sequences = data["sequence_db"]["sequences"]; | |
| 4839 motif = data["motifs"][index]; | |
| 4840 sites = motif["sites"]; | |
| 4841 out = ""; | |
| 4842 for (i = 0; i < sites.length; i++) { | |
| 4843 site = sites[i]; | |
| 4844 seq = site["seq"]; | |
| 4845 sequence = sequences[seq]; | |
| 4846 counter[seq] = (num = counter[seq]) ? (++num) : (num = 1); // inc counter | |
| 4847 if (i !== 0) {out += "\n";} | |
| 4848 out += ">" + sequence["name"] + "_site_" + num + " offset= " + site["pos"] + | |
| 4849 (site["rc"] ? " RC\n" : "\n"); | |
| 4850 out += site["match"]; | |
| 4851 } | |
| 4852 return out; | |
| 4853 } | |
| 4854 | |
| 4855 function motif_raw(index) { | |
| 4856 "use strict"; | |
| 4857 var sites, i, out; | |
| 4858 sites = data["motifs"][index]["sites"]; | |
| 4859 out = ""; | |
| 4860 for (i = 0; i < sites.length; i++) { | |
| 4861 if (i !== 0) {out += "\n";} | |
| 4862 out += sites[i]["match"]; | |
| 4863 } | |
| 4864 return out; | |
| 4865 } | |
| 4866 | |
| 4867 function clone_template(template) { | |
| 4868 "use strict"; | |
| 4869 var node, help_btns, i, button; | |
| 4870 node = $(template).cloneNode(true); | |
| 4871 toggle_class(node, "template", false); | |
| 4872 node.id = ""; | |
| 4873 help_btns = node.querySelectorAll(".help"); | |
| 4874 for (i = 0; i < help_btns.length; i++) { | |
| 4875 button = help_btns[i]; | |
| 4876 if (button.hasAttribute("data-topic")) { | |
| 4877 button.tabIndex = "0"; | |
| 4878 button.addEventListener("click", __toggle_help, false); | |
| 4879 button.addEventListener("keydown", __toggle_help, false); | |
| 4880 } | |
| 4881 } | |
| 4882 return node; | |
| 4883 } | |
| 4884 | |
| 4885 function set_tvar(template, tvar, value) { | |
| 4886 var node; | |
| 4887 node = find_child(template, tvar); | |
| 4888 if (node === null) { | |
| 4889 throw new Error("Template does not contain variable " + tvar); | |
| 4890 } | |
| 4891 node.innerHTML = ""; | |
| 4892 if (typeof value !== "object") { | |
| 4893 node.appendChild(document.createTextNode(value)); | |
| 4894 } else { | |
| 4895 node.appendChild(value); | |
| 4896 } | |
| 4897 } | |
| 4898 | |
| 4899 function make_logo(alphabet, pspm, rc, offset, className) { | |
| 4900 if (rc) pspm = pspm.copy().reverse_complement(alphabet); | |
| 4901 var logo = new Logo(alphabet, ""); | |
| 4902 logo.add_pspm(pspm, offset); | |
| 4903 var canvas = document.createElement('canvas'); | |
| 4904 canvas.height = 50; | |
| 4905 canvas.width = 0; | |
| 4906 canvas.className = className; | |
| 4907 size_logo_on_canvas(logo, canvas, false); | |
| 4908 add_draw_task(canvas, new DelayLogoTask(logo, canvas)); | |
| 4909 return canvas; | |
| 4910 } | |
| 4911 | |
| 4912 function make_small_logo(alphabet, pspm, options) { | |
| 4913 if (typeof options === "undefined") options = {}; | |
| 4914 if (options.rc) pspm = pspm.copy().reverse_complement(alphabet); | |
| 4915 var logo = new Logo(alphabet, {x_axis: false, y_axis: false}); | |
| 4916 logo.add_pspm(pspm, (typeof options.offset === "number" ? options.offset : 0)); | |
| 4917 var canvas = document.createElement('canvas'); | |
| 4918 if (typeof options.className === "string") canvas.className = options.className; | |
| 4919 if (typeof options.width === "number" && options.width > 0) { | |
| 4920 canvas.height = 0; | |
| 4921 canvas.width = options.width; | |
| 4922 draw_logo_on_canvas(logo, canvas, false); | |
| 4923 } else { | |
| 4924 draw_logo_on_canvas(logo, canvas, false, 1/3); | |
| 4925 } | |
| 4926 return canvas; | |
| 4927 } | |
| 4928 | |
| 4929 function make_large_logo(alphabet, pspm, rc, offset, className) { | |
| 4930 if (rc) pspm = pspm.copy().reverse_complement(alphabet); | |
| 4931 var logo = new Logo(alphabet, ""); | |
| 4932 logo.add_pspm(pspm, offset); | |
| 4933 var canvas = document.createElement('canvas'); | |
| 4934 canvas.height = 200; | |
| 4935 canvas.width = 0; | |
| 4936 canvas.className = className; | |
| 4937 size_logo_on_canvas(logo, canvas, false); | |
| 4938 add_draw_task(canvas, new DelayLogoTask(logo, canvas)); | |
| 4939 return canvas; | |
| 4940 } | |
| 4941 | |
| 4942 function make_sym_btn(symbol, title, action) { | |
| 4943 var box; | |
| 4944 box = document.createElement("div"); | |
| 4945 box.tabIndex = 0; | |
| 4946 box.className = "sym_btn"; | |
| 4947 box.appendChild(document.createTextNode(symbol)); | |
| 4948 box.title = title; | |
| 4949 box.addEventListener('click', action, false); | |
| 4950 box.addEventListener('keydown', action, false); | |
| 4951 return box; | |
| 4952 } | |
| 4953 | |
| 4954 function make_seq(alphabet, seq) { | |
| 4955 var i, j, letter, lbox, sbox; | |
| 4956 sbox = document.createElement("span"); | |
| 4957 for (i = 0; i < seq.length; i = j) { | |
| 4958 letter = seq.charAt(i); | |
| 4959 for (j = i+1; j < seq.length; j++) { | |
| 4960 if (seq.charAt(j) !== letter) { | |
| 4961 break; | |
| 4962 } | |
| 4963 } | |
| 4964 lbox = document.createElement("span"); | |
| 4965 lbox.style.color = alphabet.get_colour(alphabet.get_index(letter)); | |
| 4966 lbox.appendChild(document.createTextNode(seq.substring(i, j))); | |
| 4967 sbox.appendChild(lbox); | |
| 4968 } | |
| 4969 return sbox; | |
| 4970 } | |
| 4971 | |
| 4972 // | |
| 4973 // make_pv_text | |
| 4974 // | |
| 4975 // Returns the string p-value, with the p italicised. | |
| 4976 /// | |
| 4977 function make_pv_text() { | |
| 4978 var pv_text = document.createElement("span"); | |
| 4979 var pv_italic_text = document.createElement("span"); | |
| 4980 pv_italic_text.appendChild(document.createTextNode("p")); | |
| 4981 pv_italic_text.style.fontStyle = "italic"; | |
| 4982 pv_text.appendChild(pv_italic_text); | |
| 4983 pv_text.appendChild(document.createTextNode("-value")); | |
| 4984 return pv_text; | |
| 4985 } | |
| 4986 | |
| 4987 function append_site_entries(tbody, motif, site_index, count) { | |
| 4988 "use strict"; | |
| 4989 var i, end; | |
| 4990 var sites, site, sequences, sequence; | |
| 4991 var rbody; | |
| 4992 if (typeof count !== "number") { | |
| 4993 count = 20; | |
| 4994 } | |
| 4995 sequences = data["sequence_db"]["sequences"]; | |
| 4996 sites = motif["sites"]; | |
| 4997 end = Math.min(site_index + count, sites.length); | |
| 4998 for (i = site_index; i < end; i++) { | |
| 4999 site = sites[i]; | |
| 5000 sequence = sequences[site["seq"]]; | |
| 5001 | |
| 5002 rbody = tbody.insertRow(tbody.rows.length); | |
| 5003 add_text_cell(rbody, "" + (site["seq"] + 1) + ".", "site_num"); | |
| 5004 add_text_cell(rbody, sequence["name"], "site_name"); | |
| 5005 add_text_cell(rbody, site["rc"] ? "-" : "+", "site_strand"); | |
| 5006 add_text_cell(rbody, site["pos"] + 1, "site_start"); | |
| 5007 add_text_cell(rbody, site["pvalue"].toExponential(2), "site_pvalue"); | |
| 5008 add_text_cell(rbody, site["lflank"], "site lflank"); | |
| 5009 add_cell(rbody, make_seq(meme_alphabet, site["match"]), "site match"); | |
| 5010 add_text_cell(rbody, site["rflank"], "site rflank"); | |
| 5011 } | |
| 5012 return i; | |
| 5013 } | |
| 5014 | |
| 5015 function make_site_entries() { | |
| 5016 "use strict"; | |
| 5017 var region; | |
| 5018 region = this; | |
| 5019 if (region.data_site_index >= region.data_motif["sites"].length) { | |
| 5020 // all sites created | |
| 5021 region.removeEventListener('scroll', make_site_entries, false); | |
| 5022 return; | |
| 5023 } | |
| 5024 // if there's still 100 pixels to scroll than don't do anything yet | |
| 5025 if (region.scrollHeight - (region.scrollTop + region.offsetHeight) > 100) { | |
| 5026 return; | |
| 5027 } | |
| 5028 | |
| 5029 region.data_site_index = append_site_entries( | |
| 5030 find_child(region, "sites_tbl").tBodies[0], | |
| 5031 region.data_motif, region.data_site_index, 20 | |
| 5032 ); | |
| 5033 } | |
| 5034 | |
| 5035 function make_sites(motif) { | |
| 5036 "use strict"; | |
| 5037 function add_site_header(row, title, nopad, help_topic, tag_class) { | |
| 5038 var div, divcp, th; | |
| 5039 th = document.createElement("th"); | |
| 5040 div = document.createElement("div"); | |
| 5041 div.className = "sites_th_inner"; | |
| 5042 if (typeof title !== "object") { | |
| 5043 title = document.createTextNode("" + title); | |
| 5044 } | |
| 5045 div.appendChild(title); | |
| 5046 if (help_topic) { | |
| 5047 div.appendChild(document.createTextNode("\xA0")); | |
| 5048 div.appendChild(help_button(help_topic)); | |
| 5049 } | |
| 5050 divcp = div.cloneNode(true); | |
| 5051 divcp.className = "sites_th_hidden"; | |
| 5052 th.appendChild(div); | |
| 5053 th.appendChild(divcp); | |
| 5054 if (nopad) { | |
| 5055 th.className = "nopad"; | |
| 5056 } | |
| 5057 if (tag_class) { | |
| 5058 th.className += " " + tag_class; | |
| 5059 } | |
| 5060 row.appendChild(th); | |
| 5061 } | |
| 5062 var outer_tbl, inner_tbl, tbl, thead, tbody, rhead; | |
| 5063 | |
| 5064 outer_tbl = document.createElement("div"); | |
| 5065 outer_tbl.className = "sites_outer"; | |
| 5066 | |
| 5067 inner_tbl = document.createElement("div"); | |
| 5068 inner_tbl.className = "sites_inner"; | |
| 5069 outer_tbl.appendChild(inner_tbl); | |
| 5070 | |
| 5071 tbl = document.createElement("table"); | |
| 5072 tbl.className = "sites_tbl"; | |
| 5073 inner_tbl.appendChild(tbl); | |
| 5074 | |
| 5075 thead = document.createElement("thead"); | |
| 5076 tbl.appendChild(thead); | |
| 5077 tbody = document.createElement("tbody"); | |
| 5078 tbl.appendChild(tbody); | |
| 5079 | |
| 5080 rhead = thead.insertRow(thead.rows.length); | |
| 5081 add_site_header(rhead, "", true); | |
| 5082 add_site_header(rhead, "Name", false, "pop_seq_name"); | |
| 5083 add_site_header(rhead, "Strand", false, "pop_site_strand", "site_strand_title"); | |
| 5084 add_site_header(rhead, "Start", false, "pop_site_start"); | |
| 5085 add_site_header(rhead, make_pv_text(), false, "pop_site_pvalue"); | |
| 5086 add_site_header(rhead, "", false); | |
| 5087 add_site_header(rhead, "Sites", true, "pop_site_match"); | |
| 5088 add_site_header(rhead, "", false); | |
| 5089 | |
| 5090 inner_tbl.data_motif = motif; | |
| 5091 inner_tbl.data_site_index = append_site_entries(tbody, motif, 0, 20); | |
| 5092 if (inner_tbl.data_site_index < motif["sites"].length) { | |
| 5093 inner_tbl.addEventListener('scroll', make_site_entries, false); | |
| 5094 } | |
| 5095 return outer_tbl; | |
| 5096 } | |
| 5097 | |
| 5098 function make_motif_table_entry(row, alphabet, ordinal, motif, colw) { | |
| 5099 "use strict"; | |
| 5100 function ev_sig(evalue_str) { | |
| 5101 "use strict"; | |
| 5102 var ev_re, match, sig, exp, num; | |
| 5103 ev_re = /^(.*)e(.*)$/; | |
| 5104 if (match = ev_re.exec(evalue_str)) { | |
| 5105 sig = parseFloat(match[1]); | |
| 5106 exp = parseInt(match[2]); | |
| 5107 if (exp >= 0) { | |
| 5108 return false; | |
| 5109 } else if (exp <= -3) { | |
| 5110 return true; | |
| 5111 } else { | |
| 5112 return sig * Math.pow(10, exp) <= 0.05; | |
| 5113 } | |
| 5114 } | |
| 5115 return true; | |
| 5116 } | |
| 5117 function make_preview(alphabet, motif) { | |
| 5118 "use strict"; | |
| 5119 var pspm, preview, preview_rc; | |
| 5120 var box, btn_box, logo_box, btn_plus, btn_minus; | |
| 5121 if (motif["preview_logo"]) { | |
| 5122 preview = motif["preview_logo"]; | |
| 5123 preview_rc = motif["preview_logo_rc"]; | |
| 5124 } else { | |
| 5125 pspm = new Pspm(motif["pwm"]); | |
| 5126 preview = make_logo(alphabet, pspm); | |
| 5127 motif["preview_logo"] = preview; | |
| 5128 if (alphabet.has_complement()) { | |
| 5129 preview_rc = make_logo(alphabet, pspm, true, 0, "logo_rc"); | |
| 5130 motif["preview_logo_rc"] = preview_rc; | |
| 5131 } | |
| 5132 } | |
| 5133 if (preview_rc) { | |
| 5134 btn_plus = document.createElement("div"); | |
| 5135 btn_plus.appendChild(document.createTextNode("+")); | |
| 5136 btn_plus.className = "preview_btn plus"; | |
| 5137 btn_plus.tabIndex = "0"; | |
| 5138 btn_plus.addEventListener("click", action_btn_rc, false); | |
| 5139 btn_plus.addEventListener("keydown", action_btn_rc, false); | |
| 5140 btn_minus = document.createElement("div"); | |
| 5141 btn_minus.appendChild(document.createTextNode("-")); | |
| 5142 btn_minus.className = "preview_btn minus"; | |
| 5143 btn_minus.tabIndex = "0"; | |
| 5144 btn_minus.addEventListener("click", action_btn_rc, false); | |
| 5145 btn_minus.addEventListener("keydown", action_btn_rc, false); | |
| 5146 btn_box = document.createElement("div"); | |
| 5147 btn_box.className = "preview_btn_box"; | |
| 5148 btn_box.appendChild(btn_plus); | |
| 5149 btn_box.appendChild(btn_minus); | |
| 5150 } | |
| 5151 logo_box = document.createElement("div"); | |
| 5152 logo_box.className = "preview_logo_box"; | |
| 5153 logo_box.appendChild(preview); | |
| 5154 if (preview_rc) logo_box.appendChild(preview_rc); | |
| 5155 box = document.createElement("div"); | |
| 5156 box.className = "preview_box"; | |
| 5157 if (preview_rc) box.appendChild(btn_box); | |
| 5158 box.appendChild(logo_box); | |
| 5159 if (preview_rc) { | |
| 5160 if (motif["rc"]) { | |
| 5161 btn_minus.className += " active"; | |
| 5162 logo_box.className += " show_rc_logo"; | |
| 5163 } else { | |
| 5164 btn_plus.className += " active"; | |
| 5165 } | |
| 5166 } | |
| 5167 return box; | |
| 5168 } | |
| 5169 var pspm, preview, preview_rc, c; | |
| 5170 row.data_motif = motif; | |
| 5171 row.data_ordinal = ordinal; | |
| 5172 if (!ev_sig(motif["evalue"])) { | |
| 5173 row.style.opacity = 0.4; | |
| 5174 } | |
| 5175 add_text_cell(row, "" + ordinal + ".", "motif_ordinal"); | |
| 5176 add_cell(row, make_preview(alphabet, motif), "motif_logo"); | |
| 5177 add_text_cell(row, motif["evalue"], "motif_evalue"); | |
| 5178 add_text_cell(row, motif["nsites"], "motif_nsites"); | |
| 5179 add_text_cell(row, motif["len"], "motif_width"); | |
| 5180 add_cell(row, make_sym_btn("\u21A7", "Show more information.", | |
| 5181 action_show_more), "motif_more"); | |
| 5182 add_cell(row, | |
| 5183 make_sym_btn("\u21E2", | |
| 5184 "Submit the motif to another MEME Suite program or download it.", | |
| 5185 action_show_outpop), | |
| 5186 "motif_submit"); | |
| 5187 if (colw) { | |
| 5188 for (c = 0; c < row.cells.length; c++) { | |
| 5189 row.cells[c].style.minWidth = colw[c] + "px"; | |
| 5190 } | |
| 5191 } | |
| 5192 } | |
| 5193 | |
| 5194 function make_motifs_table(alphabet, start_ordinal, motifs, colw, stop_reason) { | |
| 5195 var i, j; | |
| 5196 var tbl, thead, tbody, tfoot, row, preview; | |
| 5197 var motif, pspm; | |
| 5198 | |
| 5199 tbl = document.createElement("table"); | |
| 5200 | |
| 5201 thead = document.createElement("thead"); | |
| 5202 tbl.appendChild(thead); | |
| 5203 tbody = document.createElement("tbody"); | |
| 5204 tbl.appendChild(tbody); | |
| 5205 tfoot = document.createElement("tfoot"); | |
| 5206 tbl.appendChild(tfoot); | |
| 5207 | |
| 5208 row = thead.insertRow(thead.rows.length); | |
| 5209 add_text_header_cell(row, "", "", "motif_ordinal"); | |
| 5210 add_text_header_cell(row, "Logo", "", "motif_logo"); | |
| 5211 add_text_header_cell(row, "E-value", "pop_ev", "motif_evalue"); | |
| 5212 add_text_header_cell(row, "Sites", "pop_sites", "motif_nsites"); | |
| 5213 add_text_header_cell(row, "Width", "pop_width", "motif_width"); | |
| 5214 add_text_header_cell(row, "More", "pop_more", "motif_more"); | |
| 5215 add_text_header_cell(row, "Submit/Download", "pop_submit_dl", "motif_submit"); | |
| 5216 | |
| 5217 for (i = 0; i < motifs.length; i++) { | |
| 5218 row = tbody.insertRow(tbody.rows.length); | |
| 5219 make_motif_table_entry(row, alphabet, start_ordinal + i, motifs[i], colw); | |
| 5220 } | |
| 5221 | |
| 5222 row = tfoot.insertRow(tfoot.rows.length); | |
| 5223 add_text_header_cell(row, stop_reason, "", "stop_reason", "", 6); | |
| 5224 | |
| 5225 return tbl; | |
| 5226 } | |
| 5227 | |
| 5228 function make_expanded_motif(alphabet, ordinal, motif, less_x, submit_x) { | |
| 5229 "use strict"; | |
| 5230 var box, pspm, logo_box, large_logo, large_logo_rc, tab_logo, tab_logo_rc; | |
| 5231 var btn, offset, norc; | |
| 5232 | |
| 5233 box = clone_template("tmpl_motif_expanded"); | |
| 5234 box.data_motif = motif; | |
| 5235 box.data_ordinal = ordinal; | |
| 5236 | |
| 5237 pspm = new Pspm(motif["pwm"]); | |
| 5238 if (typeof motif["rc"] !== "boolean") { | |
| 5239 motif["rc"] = false; | |
| 5240 } | |
| 5241 if (motif["large_logo"]) { | |
| 5242 large_logo = motif["large_logo"]; | |
| 5243 large_logo_rc = motif["large_logo_rc"]; | |
| 5244 } else { | |
| 5245 large_logo = make_large_logo(alphabet, pspm, false, 0); | |
| 5246 motif["large_logo"] = large_logo; | |
| 5247 if (alphabet.has_complement()) { | |
| 5248 large_logo_rc = make_large_logo(alphabet, pspm, true, 0, "logo_rc"); | |
| 5249 motif["large_logo_rc"] = large_logo_rc; | |
| 5250 } | |
| 5251 } | |
| 5252 norc = (large_logo_rc == null); | |
| 5253 toggle_class(box, "norc", norc); | |
| 5254 | |
| 5255 logo_box = find_child(box, "tvar_logo"); | |
| 5256 logo_box.appendChild(large_logo); | |
| 5257 if (large_logo_rc) logo_box.appendChild(large_logo_rc); | |
| 5258 toggle_class(logo_box, "show_rc_logo", motif["rc"]); | |
| 5259 | |
| 5260 tab_logo = find_child(box, "tvar_tab"); | |
| 5261 tab_logo_rc = find_child(box, "tvar_tab_rc"); | |
| 5262 | |
| 5263 toggle_class(tab_logo, "activeTab", !motif["rc"]); | |
| 5264 toggle_class(tab_logo_rc, "activeTab", motif["rc"]); | |
| 5265 | |
| 5266 tab_logo.addEventListener('click', action_rc_tab, false); | |
| 5267 tab_logo.addEventListener('keydown', action_rc_tab, false); | |
| 5268 tab_logo_rc.addEventListener('click', action_rc_tab, false); | |
| 5269 tab_logo_rc.addEventListener('keydown', action_rc_tab, false); | |
| 5270 | |
| 5271 set_tvar(box, "tvar_ordinal", ordinal); | |
| 5272 set_tvar(box, "tvar_evalue", motif["evalue"]); | |
| 5273 set_tvar(box, "tvar_width", motif["len"]); | |
| 5274 set_tvar(box, "tvar_site_count", motif["nsites"]); | |
| 5275 set_tvar(box, "tvar_llr", motif["llr"]); | |
| 5276 set_tvar(box, "tvar_ic", motif["ic"]); | |
| 5277 set_tvar(box, "tvar_re", motif["re"]); | |
| 5278 set_tvar(box, "tvar_bt", motif["bt"]); | |
| 5279 set_tvar(box, "tvar_sites", make_sites(motif)); | |
| 5280 | |
| 5281 offset = 32; // 1* 5px padding + 2 * 10px padding + 2 * 2px border + 3px ?? | |
| 5282 | |
| 5283 btn = find_child(box, "tvar_less"); | |
| 5284 btn.style.left = (less_x - offset) + "px"; | |
| 5285 btn.addEventListener('click', action_show_less, false); | |
| 5286 btn.addEventListener('keydown', action_show_less, false); | |
| 5287 btn = find_child(box, "tvar_submit"); | |
| 5288 btn.style.left = (submit_x - offset) + "px"; | |
| 5289 btn.addEventListener('click', action_show_outpop, false); | |
| 5290 btn.addEventListener('keydown', action_show_outpop, false); | |
| 5291 return box; | |
| 5292 } | |
| 5293 | |
| 5294 | |
| 5295 // | |
| 5296 // | |
| 5297 /// | |
| 5298 function make_motifs() { | |
| 5299 "use strict"; | |
| 5300 function pixel_value(str_in) { | |
| 5301 "use strict"; | |
| 5302 var px_re, match; | |
| 5303 px_re = /^(\d+)px$/; | |
| 5304 if (match = px_re.exec(str_in)) { | |
| 5305 return parseInt(match[1], 10); | |
| 5306 } | |
| 5307 return 0; | |
| 5308 } | |
| 5309 var container, tbl; | |
| 5310 var colw, r, row, c, cell, cell_style, pad_left, pad_right; | |
| 5311 | |
| 5312 // make the motifs table | |
| 5313 container = $("motifs"); | |
| 5314 container.innerHTML = ""; // clear content | |
| 5315 | |
| 5316 tbl = make_motifs_table(meme_alphabet, 1, data["motifs"], colw, data["stop_reason"]); | |
| 5317 container.appendChild(tbl); | |
| 5318 | |
| 5319 // measure table column widths | |
| 5320 colw = []; | |
| 5321 row = tbl.tBodies[0].rows[0]; | |
| 5322 for (c = 0; c < row.cells.length; c++) { | |
| 5323 var padLeft, padRight; | |
| 5324 cell = row.cells[c]; | |
| 5325 cell_style = window.getComputedStyle(cell, null); | |
| 5326 pad_left = pixel_value(cell_style.getPropertyValue("padding-left")); | |
| 5327 pad_right = pixel_value(cell_style.getPropertyValue("padding-right")); | |
| 5328 colw[c] = cell.clientWidth - pad_left - pad_right; | |
| 5329 if (typeof colw[c] !== "number" || colw[c] < 0) { | |
| 5330 colw[c] = 1; | |
| 5331 } | |
| 5332 } | |
| 5333 | |
| 5334 // set minimum table column widths on each row so later when we remove rows it still aligns | |
| 5335 for (r = 0; r < tbl.tBodies[0].rows.length; r++) { | |
| 5336 row = tbl.tBodies[0].rows[r]; | |
| 5337 for (c = 0; c < row.cells.length; c++) { | |
| 5338 row.cells[c].style.minWidth = colw[c] + "px"; | |
| 5339 } | |
| 5340 } | |
| 5341 | |
| 5342 // store the table column widths so we can create rows latter with the same minimums | |
| 5343 container.data_colw = colw; | |
| 5344 | |
| 5345 // calculate the x offset for the buttons | |
| 5346 row = tbl.tBodies[0].rows[0]; | |
| 5347 container.data_more_x = coords(find_child(find_child(row, "motif_more"), "sym_btn"))[0]; | |
| 5348 container.data_submit_x = coords(find_child(find_child(row, "motif_submit"), "sym_btn"))[0]; | |
| 5349 | |
| 5350 draw_on_screen(); | |
| 5351 } | |
| 5352 | |
| 5353 function make_meme_block(container, max_seq_len, is_scan, site) { | |
| 5354 "use strict"; | |
| 5355 var motif = data.motifs[site.motif]; | |
| 5356 var block = make_block(container, max_seq_len, site.pos, motif.len, | |
| 5357 site.pvalue, site.rc, site.motif, is_scan); | |
| 5358 var handler = (is_scan ? | |
| 5359 make_scan_popup(site, motif, block) : | |
| 5360 make_block_popup(site, motif, block)); | |
| 5361 block.addEventListener("mouseover", handler, false); | |
| 5362 block.addEventListener("mouseout", handler, false); | |
| 5363 } | |
| 5364 | |
| 5365 function append_blocks_entries(tbody, seq_index, count) { | |
| 5366 "use strict"; | |
| 5367 var i, end, j; | |
| 5368 var max_pvalue, max_block_height, max_seq_len, sequences; | |
| 5369 var sequence, sites, scans, scan; | |
| 5370 var container, plus, minus, rule, row; | |
| 5371 // define some constants | |
| 5372 max_seq_len = data.sequence_db.max_length; | |
| 5373 // determine how many to load | |
| 5374 end = Math.min(seq_index + count, data.sequence_db.sequences.length); | |
| 5375 for (i = seq_index; i < end; i++) { | |
| 5376 // get the sequence | |
| 5377 sequence = data.sequence_db.sequences[i]; | |
| 5378 // make the containers for the block diagram | |
| 5379 container = make_block_container(meme_alphabet.has_complement(), | |
| 5380 data.options.revcomp, max_seq_len, sequence.length); | |
| 5381 // create blocks for the motif sites | |
| 5382 sites = sequence["sites"]; | |
| 5383 for (j = 0; j < sites.length; j++) | |
| 5384 make_meme_block(container, max_seq_len, false, sites[j]); | |
| 5385 // create blocks for the scanned sites | |
| 5386 scan = data.scan[i]; | |
| 5387 for (j = 0; j < scan.sites.length; j++) | |
| 5388 make_meme_block(container, max_seq_len, true, scan.sites[j]); | |
| 5389 // create a row for the sequence | |
| 5390 row = tbody.insertRow(tbody.rows.length); | |
| 5391 toggle_class(row, "empty_seq", sites.length == 0 && scan.sites.length == 0); | |
| 5392 toggle_class(row, "only_scan", sites.length == 0 && scan.sites.length > 0); | |
| 5393 add_text_cell(row, (i + 1) + ".", "blockdiag_num"); | |
| 5394 add_text_cell(row, sequence["name"], "blockdiag_name"); | |
| 5395 add_text_cell(row, scan["pvalue"].toExponential(2), "blockdiag_pvalue"); | |
| 5396 add_cell(row, container, "block_td"); | |
| 5397 } | |
| 5398 return end; | |
| 5399 } | |
| 5400 | |
| 5401 function make_blocks_entries() { | |
| 5402 "use strict"; | |
| 5403 var region; | |
| 5404 region = this; | |
| 5405 if (region.data_blocks_index >= data["sequence_db"]["sequences"].length) { | |
| 5406 // all sites created | |
| 5407 region.removeEventListener('scroll', make_blocks_entries, false); | |
| 5408 return; | |
| 5409 } | |
| 5410 // if there's still 100 pixels to scroll than don't do anything yet | |
| 5411 if (region.scrollHeight - (region.scrollTop + region.offsetHeight) > 100) { | |
| 5412 return; | |
| 5413 } | |
| 5414 | |
| 5415 region.data_blocks_index = append_blocks_entries( | |
| 5416 find_child(region, "blocks_tbl").tBodies[0], | |
| 5417 region.data_blocks_index, 20 | |
| 5418 ); | |
| 5419 } | |
| 5420 | |
| 5421 function make_blocks() { | |
| 5422 "use strict"; | |
| 5423 function add_seqs_filter(container, id, checked, label_text, help_topic) { | |
| 5424 "use strict"; | |
| 5425 var label, radio; | |
| 5426 radio = document.createElement("input"); | |
| 5427 radio.type = "radio"; | |
| 5428 radio.name = "seqs_display"; | |
| 5429 radio.id = id; | |
| 5430 radio.checked = checked; | |
| 5431 radio.addEventListener('click', action_seqs_filter, false); | |
| 5432 label = document.createElement("label"); | |
| 5433 label.appendChild(document.createTextNode(label_text)); | |
| 5434 label.htmlFor = id; | |
| 5435 container.appendChild(radio); | |
| 5436 container.appendChild(label); | |
| 5437 if (help_topic) { | |
| 5438 container.appendChild(document.createTextNode("\xA0")); | |
| 5439 container.appendChild(help_button(help_topic)); | |
| 5440 } | |
| 5441 } | |
| 5442 function add_blocks_header(row, title, nopad, help_topic) { | |
| 5443 "use strict"; | |
| 5444 var div, divcp, th; | |
| 5445 th = document.createElement("th"); | |
| 5446 div = document.createElement("div"); | |
| 5447 div.className = "blocks_th_inner"; | |
| 5448 if (typeof title !== "object") { | |
| 5449 title = document.createTextNode("" + title); | |
| 5450 } | |
| 5451 div.appendChild(title); | |
| 5452 if (help_topic) { | |
| 5453 div.appendChild(document.createTextNode("\xA0")); | |
| 5454 div.appendChild(help_button(help_topic)); | |
| 5455 } | |
| 5456 divcp = div.cloneNode(true); | |
| 5457 divcp.className = "blocks_th_hidden"; | |
| 5458 th.appendChild(div); | |
| 5459 th.appendChild(divcp); | |
| 5460 if (nopad) { | |
| 5461 th.className = "nopad"; | |
| 5462 } | |
| 5463 row.appendChild(th); | |
| 5464 } | |
| 5465 var container; | |
| 5466 var page, view_height, outer_tbl, inner_tbl, tbl, thead, tbody, rhead; | |
| 5467 var in_view, i, seq_count; | |
| 5468 | |
| 5469 page = (document.compatMode === "CSS1Compat") ? document.documentElement : document.body; | |
| 5470 view_height = Math.max(page.clientHeight - 300, 300); | |
| 5471 | |
| 5472 container = $("blocks"); | |
| 5473 toggle_class(container, "hide_empty_seqs", true); | |
| 5474 toggle_class(container, "hide_only_scan", true); | |
| 5475 container.innerHTML = ""; | |
| 5476 add_seqs_filter(container, "rdo_sites_only", true, "Only Motif Sites", "pop_motif_sites"); | |
| 5477 add_seqs_filter(container, "rdo_sites_and_scan", false, "Motif Sites+Scanned Sites", "pop_scanned_sites"); | |
| 5478 add_seqs_filter(container, "rdo_all_seqs", false, "All Sequences", "pop_all_sequences"); | |
| 5479 | |
| 5480 outer_tbl = document.createElement("div"); | |
| 5481 outer_tbl.className = "blocks_outer"; | |
| 5482 | |
| 5483 inner_tbl = document.createElement("div"); | |
| 5484 inner_tbl.id = "blocks_scroll"; | |
| 5485 inner_tbl.className = "blocks_inner"; | |
| 5486 inner_tbl.style.maxHeight = view_height + "px"; | |
| 5487 outer_tbl.appendChild(inner_tbl); | |
| 5488 | |
| 5489 tbl = document.createElement("table"); | |
| 5490 tbl.className = "blocks_tbl"; | |
| 5491 inner_tbl.appendChild(tbl); | |
| 5492 | |
| 5493 thead = document.createElement("thead"); | |
| 5494 tbl.appendChild(thead); | |
| 5495 tbody = document.createElement("tbody"); | |
| 5496 tbl.appendChild(tbody); | |
| 5497 | |
| 5498 rhead = thead.insertRow(thead.rows.length); | |
| 5499 add_blocks_header(rhead, "", true); | |
| 5500 add_blocks_header(rhead, "Name", false, "pop_seq_name"); | |
| 5501 add_blocks_header(rhead, make_pv_text(), false, "pop_seq_pvalue"); | |
| 5502 add_blocks_header(rhead, "Motif Location", false, "pop_motif_location"); | |
| 5503 | |
| 5504 container.appendChild(outer_tbl); | |
| 5505 | |
| 5506 | |
| 5507 seq_count = data["sequence_db"]["sequences"].length; | |
| 5508 in_view = Math.max(Math.ceil(view_height / 25), 1); | |
| 5509 i = append_blocks_entries(tbody, 0, in_view); | |
| 5510 | |
| 5511 while (i < seq_count && inner_tbl.scrollHeight - (inner_tbl.scrollTop + inner_tbl.offsetHeight) < 400) { | |
| 5512 i = append_blocks_entries(tbody, i, 20); | |
| 5513 } | |
| 5514 inner_tbl.data_blocks_index = i; | |
| 5515 if (i < seq_count) { | |
| 5516 inner_tbl.addEventListener('scroll', make_blocks_entries, false); | |
| 5517 } | |
| 5518 } | |
| 5519 | |
| 5520 function make_scan_popup(site, motif) { | |
| 5521 return function (e) { | |
| 5522 "use strict"; | |
| 5523 var pop, xy, padding, edge_padding, pop_left, pop_top, page_width; | |
| 5524 var lflank, match, rflank, pspm; | |
| 5525 if (!e) var e = window.event; | |
| 5526 pop = make_scan_popup.pop; | |
| 5527 if (e.type === "mouseover") { | |
| 5528 if (pop) return; | |
| 5529 pop = clone_template("tmpl_scan_info"); | |
| 5530 pspm = new Pspm(motif.pwm); | |
| 5531 if (site.rc) pspm.reverse_complement(meme_alphabet); | |
| 5532 set_tvar(pop, "tvar_logo", make_small_logo(meme_alphabet, pspm, {"className": "scan_logo"})); | |
| 5533 set_tvar(pop, "tvar_motif", motif.id); | |
| 5534 set_tvar(pop, "tvar_pvalue", site.pvalue.toExponential(2)); | |
| 5535 set_tvar(pop, "tvar_start", site.pos + 1); | |
| 5536 set_tvar(pop, "tvar_end", site.pos + motif.len); | |
| 5537 | |
| 5538 document.body.appendChild(pop); | |
| 5539 position_popup(this, pop); | |
| 5540 make_scan_popup.pop = pop; | |
| 5541 } else if (e.type === "mouseout") { | |
| 5542 if (pop) { | |
| 5543 pop.parentNode.removeChild(pop); | |
| 5544 make_scan_popup.pop = null; | |
| 5545 } | |
| 5546 } | |
| 5547 }; | |
| 5548 } | |
| 5549 | |
| 5550 function make_block_popup(site, motif, block) { | |
| 5551 return function (e) { | |
| 5552 "use strict"; | |
| 5553 var pop; | |
| 5554 var lflank, match, rflank, pspm, ruler, match_seq, match_width; | |
| 5555 if (!e) var e = window.event; | |
| 5556 pop = make_block_popup.pop; | |
| 5557 if (e.type === "mouseover") { | |
| 5558 if (pop) return; | |
| 5559 pop = clone_template("tmpl_block_info"); | |
| 5560 pspm = new Pspm(motif.pwm); | |
| 5561 if (site.rc) { // must be dna | |
| 5562 pspm.reverse_complement(meme_alphabet); | |
| 5563 lflank = meme_alphabet.invcomp_seq(site.rflank); | |
| 5564 match = meme_alphabet.invcomp_seq(site.match); | |
| 5565 rflank = meme_alphabet.invcomp_seq(site.lflank); | |
| 5566 } else { | |
| 5567 lflank = site.lflank; | |
| 5568 match = site.match; | |
| 5569 rflank = site.rflank; | |
| 5570 } | |
| 5571 ruler = document.getElementById("measure_match"); | |
| 5572 match_seq = make_seq(meme_alphabet, match); | |
| 5573 ruler.innerHTML = ""; | |
| 5574 ruler.appendChild(match_seq); | |
| 5575 match_width = ruler.clientWidth; | |
| 5576 ruler.removeChild(match_seq); | |
| 5577 set_tvar(pop, "tvar_lflank", lflank); | |
| 5578 set_tvar(pop, "tvar_match", match_seq); | |
| 5579 set_tvar(pop, "tvar_rflank", rflank); | |
| 5580 set_tvar(pop, "tvar_logo_pad", lflank); | |
| 5581 set_tvar(pop, "tvar_logo", make_small_logo(meme_alphabet, pspm, {"width": match_width})); | |
| 5582 set_tvar(pop, "tvar_motif", motif.id); | |
| 5583 set_tvar(pop, "tvar_pvalue", site.pvalue.toExponential(2)); | |
| 5584 set_tvar(pop, "tvar_start", site.pos + 1); | |
| 5585 set_tvar(pop, "tvar_end", site.pos + motif.len); | |
| 5586 | |
| 5587 document.body.appendChild(pop); | |
| 5588 position_popup(block, pop); | |
| 5589 make_block_popup.pop = pop; | |
| 5590 } else if (e.type === "mouseout") { | |
| 5591 if (pop) { | |
| 5592 pop.parentNode.removeChild(pop); | |
| 5593 make_block_popup.pop = null; | |
| 5594 } | |
| 5595 } | |
| 5596 }; | |
| 5597 } | |
| 5598 | |
| 5599 function update_outpop_format(index) { | |
| 5600 switch(parseInt($("text_format").value)) { | |
| 5601 case 0: // count matrix | |
| 5602 $("outpop_text").value = motif_count_matrix(index); | |
| 5603 $("text_name").value = "motif_" + (index + 1) + "_counts.txt"; | |
| 5604 break; | |
| 5605 case 1: // prob matrix | |
| 5606 $("outpop_text").value = motif_prob_matrix(index); | |
| 5607 $("text_name").value = "motif_" + (index + 1) + "_freqs.txt"; | |
| 5608 break; | |
| 5609 case 2: // minimal meme | |
| 5610 $("outpop_text").value = motif_minimal_meme(index); | |
| 5611 $("text_name").value = "motif_" + (index + 1) + ".txt"; | |
| 5612 break; | |
| 5613 case 3: // fasta | |
| 5614 $("outpop_text").value = motif_fasta(index); | |
| 5615 $("text_name").value = "motif_" + (index + 1) + "_fasta.txt"; | |
| 5616 break; | |
| 5617 case 4: // raw | |
| 5618 $("outpop_text").value = motif_raw(index); | |
| 5619 $("text_name").value = "motif_" + (index + 1) + "_raw.txt"; | |
| 5620 break; | |
| 5621 default: | |
| 5622 throw new Error("Unknown motif format"); | |
| 5623 } | |
| 5624 } | |
| 5625 | |
| 5626 function update_outpop_motif(index) { | |
| 5627 "use strict"; | |
| 5628 var motifs, motif, pspm, logo, canvas, num; | |
| 5629 motifs = data["motifs"]; | |
| 5630 if (index < 0 || index >= motifs.length) {return;} | |
| 5631 current_motif = index; | |
| 5632 motif = motifs[index]; | |
| 5633 pspm = new Pspm(motif["pwm"]); | |
| 5634 logo = new Logo(meme_alphabet, ""); | |
| 5635 logo.add_pspm(pspm, 0); | |
| 5636 canvas = $("outpop_logo"); | |
| 5637 canvas.width = canvas.width; // clear canvas | |
| 5638 draw_logo_on_canvas(logo, canvas, false); | |
| 5639 if (meme_alphabet.has_complement()) { | |
| 5640 pspm.reverse_complement(meme_alphabet); | |
| 5641 logo = new Logo(meme_alphabet, ""); | |
| 5642 canvas = $("outpop_logo_rc"); | |
| 5643 canvas.width = canvas.width; // clear canvas | |
| 5644 draw_logo_on_canvas(logo, canvas, false); | |
| 5645 } | |
| 5646 num = $("outpop_num"); | |
| 5647 num.innerHTML = ""; | |
| 5648 num.appendChild(document.createTextNode("" + (index + 1))); | |
| 5649 update_outpop_format(index); | |
| 5650 } | |
| 5651 | |
| 5652 // | |
| 5653 // action_show_more | |
| 5654 // | |
| 5655 // Show more information on the motif. | |
| 5656 /// | |
| 5657 function action_show_more(e) { | |
| 5658 var node, tr, tbody, table, container, motif, ordinal; | |
| 5659 var expanded_motif; | |
| 5660 if (!e) e = window.event; | |
| 5661 if (e.type === "keydown") { | |
| 5662 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
| 5663 return; | |
| 5664 } | |
| 5665 // stop a submit or something like that | |
| 5666 e.preventDefault(); | |
| 5667 } | |
| 5668 // find the row that contains the cell | |
| 5669 node = this; | |
| 5670 do { | |
| 5671 if (node.tagName === "TR") break; | |
| 5672 } while (node = node.parentNode); | |
| 5673 if (!node) throw new Error("Expected to find row!?"); | |
| 5674 tr = node; | |
| 5675 // get info | |
| 5676 motif = tr.data_motif; | |
| 5677 ordinal = tr.data_ordinal; | |
| 5678 // find tbody | |
| 5679 do { | |
| 5680 if (node.tagName === "TBODY") break; | |
| 5681 } while (node = node.parentNode); | |
| 5682 if (!node) throw new Error("Expected to find tbody!?"); | |
| 5683 tbody = node; | |
| 5684 // find table | |
| 5685 do { | |
| 5686 if (node.tagName === "TABLE") break; | |
| 5687 } while (node = node.parentNode); | |
| 5688 if (!node) throw new Error("Expected to find table!?"); | |
| 5689 table = node; | |
| 5690 // find container | |
| 5691 container = node.parentNode; | |
| 5692 // make a expanded motif | |
| 5693 motif["expanded"] = true; | |
| 5694 expanded_motif = make_expanded_motif(meme_alphabet, ordinal, motif, | |
| 5695 container.data_more_x, container.data_submit_x); | |
| 5696 // now determine how to place it | |
| 5697 if (tbody.rows.length === 1) { | |
| 5698 // only us in the table so the table can be replaced | |
| 5699 container.replaceChild(expanded_motif, table); | |
| 5700 } else if (tbody.rows[0] === tr) { | |
| 5701 // first row, so remove and insert an expanded motif before | |
| 5702 table.deleteRow(tr.rowIndex); | |
| 5703 container.insertBefore(expanded_motif, table); | |
| 5704 } else if (tbody.rows[tbody.rows.length -1] === tr) { | |
| 5705 // last row, so remove and insert an expanded motif after | |
| 5706 table.deleteRow(tr.rowIndex); | |
| 5707 container.insertBefore(expanded_motif, table.nextSibling); | |
| 5708 } else { | |
| 5709 var table2, tbody2; | |
| 5710 table2 = table.cloneNode(false); | |
| 5711 table2.appendChild(table.tHead.cloneNode(true)); | |
| 5712 tbody2 = table.tBodies[0].cloneNode(false); | |
| 5713 table2.appendChild(tbody2); | |
| 5714 container.insertBefore(table2, table.nextSibling); | |
| 5715 for (i = tbody.rows.length - 1; i >= 0; i--) { | |
| 5716 row = tbody.rows[i]; | |
| 5717 row.parentNode.removeChild(row); | |
| 5718 if (row === tr) { | |
| 5719 break; | |
| 5720 } | |
| 5721 tbody2.insertBefore(row, tbody2.rows[0]); | |
| 5722 } | |
| 5723 container.insertBefore(expanded_motif, table2); | |
| 5724 } | |
| 5725 find_child(expanded_motif, "tvar_less").focus(); | |
| 5726 } | |
| 5727 | |
| 5728 // | |
| 5729 // action_show_less | |
| 5730 // | |
| 5731 // Show less information on the motif. | |
| 5732 /// | |
| 5733 function action_show_less(e) { | |
| 5734 var btn; | |
| 5735 var expanded_motif, container, motif, ordinal, colw, focus_target; | |
| 5736 var table, tbody, tbody2, row, table_before, table_after; | |
| 5737 if (!e) e = window.event; | |
| 5738 if (e.type === "keydown") { | |
| 5739 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
| 5740 return; | |
| 5741 } | |
| 5742 // stop a submit or something like that | |
| 5743 e.preventDefault(); | |
| 5744 } | |
| 5745 btn = this; | |
| 5746 // find expanded motif | |
| 5747 expanded_motif = find_parent(btn, "expanded_motif"); | |
| 5748 if (!expanded_motif) throw new Error("Expected expanded motif."); | |
| 5749 // find the container | |
| 5750 container = expanded_motif.parentNode; | |
| 5751 // get data | |
| 5752 motif = expanded_motif.data_motif; | |
| 5753 ordinal = expanded_motif.data_ordinal; | |
| 5754 colw = container.data_colw; | |
| 5755 // get the table before | |
| 5756 table_before = expanded_motif.previousSibling; | |
| 5757 if (table_before && table_before.tagName !== "TABLE") { | |
| 5758 table_before = null; | |
| 5759 } | |
| 5760 // get the table after | |
| 5761 table_after = expanded_motif.nextSibling; | |
| 5762 if (table_after && table_after.tagName !== "TABLE") { | |
| 5763 table_after = null; | |
| 5764 } | |
| 5765 // see if there is a table below or above that we can put this in. | |
| 5766 // if there is a table both below and above then add this motif and | |
| 5767 // all ones below to the above table | |
| 5768 motif["expanded"] = false; | |
| 5769 if (table_before && table_after) { | |
| 5770 tbody = table_before.tBodies[0]; | |
| 5771 row = tbody.insertRow(tbody.rows.length); | |
| 5772 make_motif_table_entry(row, meme_alphabet, ordinal, motif, colw); | |
| 5773 focus_target = find_child(row.cells[5], "sym_btn"); | |
| 5774 container.removeChild(expanded_motif); | |
| 5775 tbody2 = table_after.tBodies[0]; | |
| 5776 while (tbody2.rows.length > 0) { | |
| 5777 row = tbody2.rows[0]; | |
| 5778 row.parentNode.removeChild(row); | |
| 5779 tbody.appendChild(row); | |
| 5780 } | |
| 5781 container.removeChild(table_after); | |
| 5782 } else if (table_before) { | |
| 5783 tbody = table_before.tBodies[0]; | |
| 5784 row = tbody.insertRow(tbody.rows.length); | |
| 5785 make_motif_table_entry(row, meme_alphabet, ordinal, motif, colw); | |
| 5786 focus_target = find_child(row.cells[5], "sym_btn"); | |
| 5787 container.removeChild(expanded_motif); | |
| 5788 } else if (table_after) { | |
| 5789 tbody = table_after.tBodies[0]; | |
| 5790 row = tbody.insertRow(0); | |
| 5791 make_motif_table_entry(row, meme_alphabet, ordinal, motif, colw); | |
| 5792 focus_target = find_child(row.cells[5], "sym_btn"); | |
| 5793 container.removeChild(expanded_motif); | |
| 5794 } else { | |
| 5795 //no table above or below! | |
| 5796 // make a new table | |
| 5797 table = make_motifs_table(meme_alphabet, ordinal, [motif], colw, data["stop_reason"]); | |
| 5798 focus_target = find_child(table.tBodies[0].rows[0].cells[5], "sym_btn"); | |
| 5799 container.replaceChild(table, expanded_motif); | |
| 5800 } | |
| 5801 focus_target.focus(); | |
| 5802 } | |
| 5803 | |
| 5804 function action_show_outpop(e) { | |
| 5805 "use strict"; | |
| 5806 function init() { | |
| 5807 "use strict"; | |
| 5808 var close_btn, next_btn, prev_btn, cancel_btn, do_btn; | |
| 5809 var tab1, tab2, tab3; | |
| 5810 var pnl1, pnl2, pnl3; | |
| 5811 var format_list; | |
| 5812 var tbl_submit, inputs, i, default_prog; | |
| 5813 close_btn = $("outpop_close"); | |
| 5814 close_btn.addEventListener("click", action_hide_outpop, false); | |
| 5815 close_btn.addEventListener("keydown", action_hide_outpop, false); | |
| 5816 next_btn = $("outpop_next"); | |
| 5817 next_btn.addEventListener("click", action_outpop_next, false); | |
| 5818 next_btn.addEventListener("keydown", action_outpop_next, false); | |
| 5819 prev_btn = $("outpop_prev"); | |
| 5820 prev_btn.addEventListener("click", action_outpop_prev, false); | |
| 5821 prev_btn.addEventListener("keydown", action_outpop_prev, false); | |
| 5822 cancel_btn = $("outpop_cancel"); | |
| 5823 cancel_btn.addEventListener("click", action_hide_outpop, false); | |
| 5824 do_btn = $("outpop_do"); | |
| 5825 do_btn.addEventListener("click", action_outpop_submit, false); | |
| 5826 tab1 = $("outpop_tab_1"); | |
| 5827 tab1.tabIndex = 0; | |
| 5828 tab1.addEventListener("click", action_outpop_tab, false); | |
| 5829 tab1.addEventListener("keydown", action_outpop_tab, false); | |
| 5830 tab2 = $("outpop_tab_2"); | |
| 5831 tab2.tabIndex = 0; | |
| 5832 tab2.addEventListener("click", action_outpop_tab, false); | |
| 5833 tab2.addEventListener("keydown", action_outpop_tab, false); | |
| 5834 tab3 = $("outpop_tab_3"); | |
| 5835 tab3.tabIndex = 0; | |
| 5836 tab3.addEventListener("click", action_outpop_tab, false); | |
| 5837 tab3.addEventListener("keydown", action_outpop_tab, false); | |
| 5838 pnl1 = $("outpop_pnl_1"); | |
| 5839 pnl2 = $("outpop_pnl_2"); | |
| 5840 pnl3 = $("outpop_pnl_3"); | |
| 5841 toggle_class(tab1, "activeTab", true); | |
| 5842 toggle_class(tab2, "activeTab", false); | |
| 5843 toggle_class(tab3, "activeTab", false); | |
| 5844 pnl1.style.display = "block"; | |
| 5845 pnl2.style.display = "none"; | |
| 5846 pnl3.style.display = "none"; | |
| 5847 format_list = $("text_format"); | |
| 5848 format_list.addEventListener("change", action_outpop_format, false); | |
| 5849 // setup program selection | |
| 5850 tbl_submit = $("programs"); | |
| 5851 // when not dna, hide the inputs for programs that require dna motifs | |
| 5852 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 | |
| 5853 // add a click listener for the radio buttons | |
| 5854 inputs = tbl_submit.querySelectorAll("input[type='radio']"); | |
| 5855 for (i = 0; i < inputs.length; i++) { | |
| 5856 inputs[i].addEventListener("click", action_outpop_program, false); | |
| 5857 } | |
| 5858 // ensure that a default program option is selected for DNA and Protein | |
| 5859 default_prog = document.getElementById(meme_alphabet.has_complement() ? "submit_tomtom" : "submit_fimo"); //TODO FIXME Tomtom might require a more strict definition of DNA | |
| 5860 default_prog.checked = true; | |
| 5861 action_outpop_program.call(default_prog); | |
| 5862 // disable reverse-complement when not DNA | |
| 5863 $("logo_rc_option").disabled = !meme_alphabet.has_complement(); | |
| 5864 // set errorbars on when ssc is on | |
| 5865 $("logo_ssc").addEventListener("change", action_outpop_ssc, false); | |
| 5866 } | |
| 5867 var node; | |
| 5868 // store the focused element | |
| 5869 action_hide_outpop.last_active = document.activeElement; | |
| 5870 if (!e) e = window.event; | |
| 5871 if (e.type === "keydown") { | |
| 5872 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
| 5873 return; | |
| 5874 } | |
| 5875 // stop a submit or something like that | |
| 5876 e.preventDefault(); | |
| 5877 } | |
| 5878 // hide the help popup | |
| 5879 help_popup(); | |
| 5880 // on first load initilize the popup | |
| 5881 if (!action_show_outpop.ready) { | |
| 5882 init(); | |
| 5883 action_show_outpop.ready = true; | |
| 5884 } | |
| 5885 // load the motif logo | |
| 5886 node = this; | |
| 5887 do { | |
| 5888 if (/\bexpanded_motif\b/.test(node.className) || node.tagName === "TR") break; | |
| 5889 } while (node = node.parentNode); | |
| 5890 if (node === null) throw new Error("Expected node!"); | |
| 5891 update_outpop_motif(node.data_ordinal - 1); | |
| 5892 // display the download popup | |
| 5893 $("grey_out_page").style.display = "block"; | |
| 5894 $("download").style.display = "block"; | |
| 5895 $("outpop_close").focus(); | |
| 5896 } | |
| 5897 | |
| 5898 function action_hide_outpop(e) { | |
| 5899 if (!e) e = window.event; | |
| 5900 if (e.type === "keydown") { | |
| 5901 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
| 5902 return; | |
| 5903 } | |
| 5904 // stop a submit or something like that | |
| 5905 e.preventDefault(); | |
| 5906 } | |
| 5907 $("download").style.display = "none"; | |
| 5908 $("grey_out_page").style.display = "none"; | |
| 5909 if (typeof action_hide_outpop.last_active !== "undefined") { | |
| 5910 action_hide_outpop.last_active.focus(); | |
| 5911 } | |
| 5912 } | |
| 5913 | |
| 5914 function action_outpop_next(e) { | |
| 5915 if (!e) e = window.event; | |
| 5916 if (e.type === "keydown") { | |
| 5917 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
| 5918 return; | |
| 5919 } | |
| 5920 // stop a submit or something like that | |
| 5921 e.preventDefault(); | |
| 5922 } | |
| 5923 update_outpop_motif(current_motif + 1); | |
| 5924 } | |
| 5925 | |
| 5926 function action_outpop_prev(e) { | |
| 5927 if (!e) e = window.event; | |
| 5928 if (e.type === "keydown") { | |
| 5929 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
| 5930 return; | |
| 5931 } | |
| 5932 // stop a submit or something like that | |
| 5933 e.preventDefault(); | |
| 5934 } | |
| 5935 update_outpop_motif(current_motif - 1); | |
| 5936 } | |
| 5937 | |
| 5938 function action_outpop_program() { | |
| 5939 "use strict"; | |
| 5940 var table, tr, rows, i; | |
| 5941 tr = find_parent_tag(this, "TR"); | |
| 5942 table = find_parent_tag(tr, "TABLE"); | |
| 5943 rows = table.querySelectorAll("tr"); | |
| 5944 for (i = 0; i < rows.length; i++) { | |
| 5945 toggle_class(rows[i], "selected", rows[i] === tr); | |
| 5946 } | |
| 5947 } | |
| 5948 | |
| 5949 function action_outpop_ssc() { | |
| 5950 "use strict"; | |
| 5951 $("logo_err").value = $("logo_ssc").value; | |
| 5952 } | |
| 5953 | |
| 5954 function action_outpop_submit(e) { | |
| 5955 "use strict"; | |
| 5956 var form, input, program, motifs; | |
| 5957 // find out which program is selected | |
| 5958 var radios, i; | |
| 5959 radios = document.getElementsByName("program"); | |
| 5960 program = "fimo"; // default to fimo, since it works with all alphabet types | |
| 5961 for (i = 0; i < radios.length; i++) { | |
| 5962 if (radios[i].checked) program = radios[i].value; | |
| 5963 } | |
| 5964 | |
| 5965 motifs = motif_minimal_meme(current_motif); | |
| 5966 form = document.createElement("form"); | |
| 5967 form.setAttribute("method", "post"); | |
| 5968 form.setAttribute("action", site_url + "/tools/" + program); | |
| 5969 | |
| 5970 input = document.createElement("input"); | |
| 5971 input.setAttribute("type", "hidden"); | |
| 5972 input.setAttribute("name", "motifs_embed"); | |
| 5973 input.setAttribute("value", motifs); | |
| 5974 form.appendChild(input); | |
| 5975 | |
| 5976 document.body.appendChild(form); | |
| 5977 form.submit(); | |
| 5978 document.body.removeChild(form); | |
| 5979 } | |
| 5980 | |
| 5981 function action_outpop_download_motif(e) { | |
| 5982 $("text_form").submit(); | |
| 5983 } | |
| 5984 | |
| 5985 function action_outpop_download_logo(e) { | |
| 5986 "use strict"; | |
| 5987 $("logo_motifs").value = motif_minimal_meme(current_motif); | |
| 5988 $("logo_form").submit(); | |
| 5989 } | |
| 5990 | |
| 5991 function action_btn_rc(e) { | |
| 5992 "use strict"; | |
| 5993 var node, tr, motif, box, logo_box, tab_st, tab_rc, rc; | |
| 5994 if (!e) e = window.event; | |
| 5995 if (e.type === "keydown") { | |
| 5996 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
| 5997 return; | |
| 5998 } | |
| 5999 // stop a submit or something like that | |
| 6000 e.preventDefault(); | |
| 6001 } | |
| 6002 node = this; | |
| 6003 do { | |
| 6004 if (node.tagName === "TR") break; | |
| 6005 } while (node = node.parentNode); | |
| 6006 if (!node) throw new Error("Expected to find row!?"); | |
| 6007 tr = node; | |
| 6008 // get info | |
| 6009 motif = tr.data_motif; | |
| 6010 box = find_parent(this, "preview_box"); | |
| 6011 logo_box = find_child(box, "preview_logo_box"); | |
| 6012 tab_st = find_child(box, "plus"); | |
| 6013 tab_rc = find_child(box, "minus"); | |
| 6014 rc = (this === tab_rc); | |
| 6015 motif["rc"] = rc; | |
| 6016 toggle_class(logo_box, "show_rc_logo", rc); | |
| 6017 toggle_class(tab_st, "active", !rc); | |
| 6018 toggle_class(tab_rc, "active", rc); | |
| 6019 } | |
| 6020 | |
| 6021 function action_rc_tab(e) { | |
| 6022 "use strict"; | |
| 6023 var box, logo_box, tab_st, tab_rc, rc; | |
| 6024 if (!e) e = window.event; | |
| 6025 if (e.type === "keydown") { | |
| 6026 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
| 6027 return; | |
| 6028 } | |
| 6029 // stop a submit or something like that | |
| 6030 e.preventDefault(); | |
| 6031 } | |
| 6032 box = find_parent(this, "expanded_motif"); | |
| 6033 logo_box = find_child(box, "tvar_logo"); | |
| 6034 tab_st = find_child(box, "tvar_tab"); | |
| 6035 tab_rc = find_child(box, "tvar_tab_rc"); | |
| 6036 rc = (this === tab_rc); | |
| 6037 box.data_motif["rc"] = rc; | |
| 6038 toggle_class(logo_box, "show_rc_logo", rc); | |
| 6039 toggle_class(tab_st, "activeTab", !rc); | |
| 6040 toggle_class(tab_rc, "activeTab", rc); | |
| 6041 } | |
| 6042 | |
| 6043 function action_outpop_tab(e) { | |
| 6044 "use strict"; | |
| 6045 var tab1, tab2, tab3, pnl1, pnl2, pnl3, do_btn; | |
| 6046 if (!e) e = window.event; | |
| 6047 if (e.type === "keydown") { | |
| 6048 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
| 6049 return; | |
| 6050 } | |
| 6051 // stop a submit or something like that | |
| 6052 e.preventDefault(); | |
| 6053 } | |
| 6054 tab1 = $("outpop_tab_1"); | |
| 6055 tab2 = $("outpop_tab_2"); | |
| 6056 tab3 = $("outpop_tab_3"); | |
| 6057 pnl1 = $("outpop_pnl_1"); | |
| 6058 pnl2 = $("outpop_pnl_2"); | |
| 6059 pnl3 = $("outpop_pnl_3"); | |
| 6060 do_btn = $("outpop_do"); | |
| 6061 | |
| 6062 toggle_class(tab1, "activeTab", (this === tab1)); | |
| 6063 toggle_class(tab2, "activeTab", (this === tab2)); | |
| 6064 toggle_class(tab3, "activeTab", (this === tab3)); | |
| 6065 pnl1.style.display = ((this === tab1) ? "block" : "none"); | |
| 6066 pnl2.style.display = ((this === tab2) ? "block" : "none"); | |
| 6067 pnl3.style.display = ((this === tab3) ? "block" : "none"); | |
| 6068 do_btn.value = ((this === tab1) ? "Submit" : "Download"); | |
| 6069 do_btn.removeEventListener("click", action_outpop_submit, false); | |
| 6070 do_btn.removeEventListener("click", action_outpop_download_logo, false); | |
| 6071 do_btn.removeEventListener("click", action_outpop_download_motif, false); | |
| 6072 if (this === tab1) { | |
| 6073 do_btn.addEventListener("click", action_outpop_submit, false); | |
| 6074 } else if (this === tab2) { | |
| 6075 do_btn.addEventListener("click", action_outpop_download_motif, false); | |
| 6076 } else { | |
| 6077 do_btn.addEventListener("click", action_outpop_download_logo, false); | |
| 6078 } | |
| 6079 } | |
| 6080 | |
| 6081 function action_seqs_filter() { | |
| 6082 "use strict"; | |
| 6083 var block_container; | |
| 6084 block_container = $("blocks"); | |
| 6085 if ($("rdo_all_seqs").checked) { | |
| 6086 toggle_class(block_container, "hide_empty_seqs", false); | |
| 6087 toggle_class(block_container, "hide_only_scan", false); | |
| 6088 } else if ($("rdo_sites_and_scan").checked) { | |
| 6089 toggle_class(block_container, "hide_empty_seqs", true); | |
| 6090 toggle_class(block_container, "hide_only_scan", false); | |
| 6091 } else if ($("rdo_sites_only").checked) { | |
| 6092 toggle_class(block_container, "hide_empty_seqs", true); | |
| 6093 toggle_class(block_container, "hide_only_scan", true); | |
| 6094 } | |
| 6095 } | |
| 6096 | |
| 6097 function action_outpop_format() { | |
| 6098 update_outpop_format(current_motif); | |
| 6099 } | |
| 6100 | |
| 6101 // | |
| 6102 // page_loaded | |
| 6103 // | |
| 6104 // Called when the page has loaded for the first time. | |
| 6105 /// | |
| 6106 function page_loaded() { | |
| 6107 post_load_setup(); | |
| 6108 } | |
| 6109 | |
| 6110 // | |
| 6111 // page_loaded | |
| 6112 // | |
| 6113 // Called when a cached page is reshown. | |
| 6114 /// | |
| 6115 function page_shown(e) { | |
| 6116 if (e.persisted) post_load_setup(); | |
| 6117 } | |
| 6118 | |
| 6119 // | |
| 6120 // page_loaded | |
| 6121 // | |
| 6122 // Called when the page is resized | |
| 6123 /// | |
| 6124 function page_resized() { | |
| 6125 var page, blocks_scroll; | |
| 6126 update_scroll_pad(); | |
| 6127 page = (document.compatMode === "CSS1Compat") ? document.documentElement : document.body; | |
| 6128 blocks_scroll = $("blocks_scroll"); | |
| 6129 if (blocks_scroll) { | |
| 6130 blocks_scroll.style.maxHeight = Math.max(page.clientHeight - 300, 300) + "px"; | |
| 6131 } | |
| 6132 } | |
| 6133 | |
| 6134 // | |
| 6135 // pre_load_setup | |
| 6136 // | |
| 6137 // Run before the page is displayed | |
| 6138 /// | |
| 6139 function pre_load_setup() { | |
| 6140 var start, hue, sat, light, divisions; | |
| 6141 var i, j, motifs, motif, sites, site, sequences, sequence; | |
| 6142 var max_seq_len; | |
| 6143 motifs = data["motifs"]; | |
| 6144 sequences = data["sequence_db"]["sequences"]; | |
| 6145 max_seq_len = 1; | |
| 6146 for (i = 0; i < sequences.length; i++) { | |
| 6147 sequence = sequences[i]; | |
| 6148 sequence["sites"] = []; | |
| 6149 if (sequence["length"] > max_seq_len) { | |
| 6150 max_seq_len = sequence["length"]; | |
| 6151 } | |
| 6152 } | |
| 6153 data["sequence_db"]["max_length"] = max_seq_len; | |
| 6154 // use hsl colours | |
| 6155 start = 0; //red | |
| 6156 sat = 100; | |
| 6157 light = 50; | |
| 6158 for (i = 0; i < motifs.length; i++) { | |
| 6159 motif = motifs[i]; | |
| 6160 // give the motif a colour | |
| 6161 divisions = 1 << Math.ceil(Math.log(i + 1) / Math.LN2); | |
| 6162 hue = start + (360 / divisions) * ((i - (divisions >> 1)) * 2 + 1); | |
| 6163 motif["colour"] = "hsl(" + hue + ", " + sat + "%, " + light + "%)"; | |
| 6164 // associate sites with sequences as well | |
| 6165 // to make generating the block diagram easier | |
| 6166 sites = motif["sites"]; | |
| 6167 for (j = 0; j < sites.length; j++) { | |
| 6168 site = sites[j]; | |
| 6169 sequence = sequences[site["seq"]]; | |
| 6170 // record the motif index | |
| 6171 site["motif"] = i; | |
| 6172 // add the site to the sequence | |
| 6173 sequence["sites"].push(site); | |
| 6174 } | |
| 6175 } | |
| 6176 } | |
| 6177 | |
| 6178 // | |
| 6179 // post_load_setup | |
| 6180 // | |
| 6181 // Run when the page has loaded, or been reloaded. | |
| 6182 // | |
| 6183 function post_load_setup() { | |
| 6184 update_scroll_pad(); | |
| 6185 if (data["motifs"].length > 0) { | |
| 6186 make_motifs(); | |
| 6187 make_blocks(); | |
| 6188 } else { | |
| 6189 $("motifs").innerHTML = "<p>No significant motifs found!</p>"; // clear content | |
| 6190 $("motifs").innerHTML += "<p><b>" + data["stop_reason"] + "</b></p>"; | |
| 6191 $("blocks").innerHTML = "<p>No significant motifs found!</p>"; | |
| 6192 } | |
| 6193 } | |
| 6194 | |
| 6195 pre_load_setup(); | |
| 6196 </script> | |
| 6197 <style> | |
| 6198 /* The following is the content of meme.css */ | |
| 6199 body { background-color:white; font-size: 12px; font-family: Verdana, Arial, Helvetica, sans-serif;} | |
| 6200 | |
| 6201 div.help { | |
| 6202 display: inline-block; | |
| 6203 margin: 0px; | |
| 6204 padding: 0px; | |
| 6205 width: 12px; | |
| 6206 height: 13px; | |
| 6207 cursor: pointer; | |
| 6208 background-image: url(data:image/gif;base64,R0lGODlhDAANAIABANR0AP///yH5BAEAAAEALAAAAAAMAA0AAAIdhI8Xy22MIFgv1DttrrJ7mlGNNo4c+aFg6SQuUAAAOw==); | |
| 6209 } | |
| 6210 | |
| 6211 div.help:hover { | |
| 6212 background-image: url(data:image/gif;base64,R0lGODlhDAANAKEAANR0AP///9R0ANR0ACH+EUNyZWF0ZWQgd2l0aCBHSU1QACH5BAEAAAIALAAAAAAMAA0AAAIdDGynCe3PgoxONntvwqz2/z2K2ImjR0KhmSIZUgAAOw==); | |
| 6213 } | |
| 6214 | |
| 6215 p.spaced { line-height: 1.8em;} | |
| 6216 | |
| 6217 span.citation { font-family: "Book Antiqua", "Palatino Linotype", serif; color: #004a4d;} | |
| 6218 | |
| 6219 p.pad { padding-left: 30px; padding-top: 5px; padding-bottom: 10px;} | |
| 6220 | |
| 6221 td.jump { font-size: 13px; color: #ffffff; background-color: #00666a; | |
| 6222 font-family: Georgia, "Times New Roman", Times, serif;} | |
| 6223 | |
| 6224 a.jump { margin: 15px 0 0; font-style: normal; font-variant: small-caps; | |
| 6225 font-weight: bolder; font-family: Georgia, "Times New Roman", Times, serif;} | |
| 6226 | |
| 6227 h2.mainh {font-size: 1.5em; font-style: normal; margin: 15px 0 0; | |
| 6228 font-variant: small-caps; font-family: Georgia, "Times New Roman", Times, serif;} | |
| 6229 | |
| 6230 h2.line {border-bottom: 1px solid #CCCCCC; font-size: 1.5em; font-style: normal; | |
| 6231 margin: 15px 0 0; padding-bottom: 3px; font-variant: small-caps; | |
| 6232 font-family: Georgia, "Times New Roman", Times, serif;} | |
| 6233 | |
| 6234 h4 {border-bottom: 1px solid #CCCCCC; font-size: 1.2em; font-style: normal; | |
| 6235 margin: 10px 0 0; padding-bottom: 3px; font-family: Georgia, "Times New Roman", Times, serif;} | |
| 6236 | |
| 6237 h5 {margin: 0px} | |
| 6238 | |
| 6239 a.help { font-size: 9px; font-style: normal; text-transform: uppercase; | |
| 6240 font-family: Georgia, "Times New Roman", Times, serif;} | |
| 6241 | |
| 6242 div.pad { padding-left: 30px; padding-top: 5px; padding-bottom: 10px;} | |
| 6243 | |
| 6244 div.pad1 { margin: 10px 5px;} | |
| 6245 | |
| 6246 div.pad2 { margin: 25px 5px 5px;} | |
| 6247 h2.pad2 { padding: 25px 5px 5px;} | |
| 6248 | |
| 6249 div.pad3 { padding: 5px 0px 10px 30px;} | |
| 6250 | |
| 6251 div.box { border: 2px solid #CCCCCC; padding:10px; overflow: hidden;} | |
| 6252 | |
| 6253 div.bar { border-left: 7px solid #00666a; padding:5px; margin-top:25px; } | |
| 6254 | |
| 6255 div.subsection {margin:25px 0px;} | |
| 6256 | |
| 6257 img {border:0px none;} | |
| 6258 | |
| 6259 th.majorth {text-align:left;} | |
| 6260 th.minorth {font-weight:normal; text-align:left; width:8em; padding: 3px 0px;} | |
| 6261 th.actionth {font-weight:normal; text-align:left;} | |
| 6262 | |
| 6263 .explain h5 {font-size:1em; margin-left: 1em;} | |
| 6264 | |
| 6265 div.doc {margin-left: 2em; margin-bottom: 3em;} | |
| 6266 | |
| 6267 th.trainingset { | |
| 6268 border-bottom: thin dashed black; | |
| 6269 font-weight:normal; | |
| 6270 padding:0px 10px; | |
| 6271 } | |
| 6272 div.pop_content { | |
| 6273 position:absolute; | |
| 6274 z-index:50; | |
| 6275 width:300px; | |
| 6276 padding: 5px; | |
| 6277 background: #E4ECEC; | |
| 6278 font-size: 12px; | |
| 6279 font-family: Arial; | |
| 6280 border-style: double; | |
| 6281 border-width: 3px; | |
| 6282 border-color: #AA2244; | |
| 6283 display:none; | |
| 6284 } | |
| 6285 | |
| 6286 div.pop_content > *:first-child { | |
| 6287 margin-top: 0px; | |
| 6288 } | |
| 6289 | |
| 6290 div.pop_content h1, div.pop_content h2, div.pop_content h3, div.pop_content h4, | |
| 6291 div.pop_content h5, div.pop_content h6, div.pop_content p { | |
| 6292 margin: 0px; | |
| 6293 } | |
| 6294 | |
| 6295 div.pop_content p + h1, div.pop_content p + h2, div.pop_content p + h3, | |
| 6296 div.pop_content p + h4, div.pop_content p + h5, div.pop_content p + h6 { | |
| 6297 margin-top: 5px; | |
| 6298 } | |
| 6299 | |
| 6300 div.pop_content p + p { | |
| 6301 margin-top: 5px; | |
| 6302 } | |
| 6303 | |
| 6304 div.pop_content > *:last-child { | |
| 6305 margin-bottom: 0px; | |
| 6306 } | |
| 6307 | |
| 6308 div.pop_content div.pop_close { | |
| 6309 /* old definition */ | |
| 6310 float:right; | |
| 6311 bottom: 0; | |
| 6312 } | |
| 6313 | |
| 6314 div.pop_content span.pop_close, div.pop_content span.pop_back { | |
| 6315 display: inline-block; | |
| 6316 border: 2px outset #661429; | |
| 6317 background-color: #CCC; | |
| 6318 padding-left: 1px; | |
| 6319 padding-right: 1px; | |
| 6320 padding-top: 0px; | |
| 6321 padding-bottom: 0px; | |
| 6322 cursor: pointer; | |
| 6323 color: #AA2244; /*#661429;*/ | |
| 6324 font-weight: bold; | |
| 6325 } | |
| 6326 | |
| 6327 div.pop_content span.pop_close:active, div.pop_content span.pop_back:active { | |
| 6328 border-style: inset; | |
| 6329 } | |
| 6330 | |
| 6331 div.pop_content span.pop_close { | |
| 6332 float:right; | |
| 6333 /*border: 2px outset #AA002B;*/ | |
| 6334 /*color: #AA2244;*/ | |
| 6335 } | |
| 6336 | |
| 6337 div.pop_content:not(.nested) .nested_only { | |
| 6338 display: none; | |
| 6339 } | |
| 6340 | |
| 6341 div.pop_back_sec { | |
| 6342 margin-bottom: 5px; | |
| 6343 } | |
| 6344 | |
| 6345 div.pop_close_sec { | |
| 6346 margin-top: 5px; | |
| 6347 } | |
| 6348 | |
| 6349 table.hide_advanced tr.advanced { | |
| 6350 display: none; | |
| 6351 } | |
| 6352 span.show_more { | |
| 6353 display: none; | |
| 6354 } | |
| 6355 table.hide_advanced span.show_more { | |
| 6356 display: inline; | |
| 6357 } | |
| 6358 table.hide_advanced span.show_less { | |
| 6359 display: none; | |
| 6360 } | |
| 6361 | |
| 6362 | |
| 6363 /***************************************************************************** | |
| 6364 * Program logo styling | |
| 6365 ****************************************************************************/ | |
| 6366 div.prog_logo { | |
| 6367 border-bottom: 0.25em solid #0f5f60; | |
| 6368 height: 4.5em; | |
| 6369 width: 24em; | |
| 6370 display:inline-block; | |
| 6371 } | |
| 6372 div.prog_logo img { | |
| 6373 float:left; | |
| 6374 width: 4em; | |
| 6375 border-style: none; | |
| 6376 margin-right: 0.2em; | |
| 6377 } | |
| 6378 div.prog_logo h1, div.prog_logo h1:hover, div.prog_logo h1:active, div.prog_logo h1:visited { | |
| 6379 margin:0; | |
| 6380 padding:0; | |
| 6381 font-family: Arial, Helvetica, sans-serif; | |
| 6382 font-size: 3.2em; | |
| 6383 line-height: 1em; | |
| 6384 vertical-align: top; | |
| 6385 display: block; | |
| 6386 color: #026666; | |
| 6387 letter-spacing: -0.06em; | |
| 6388 text-shadow: 0.04em 0.06em 0.05em #666; | |
| 6389 } | |
| 6390 div.prog_logo h2, div.prog_logo h2:hover, div.prog_logo h2:active, div.prog_logo h2:visited { | |
| 6391 display: block; | |
| 6392 margin:0; | |
| 6393 padding:0; | |
| 6394 font-family: Helvetica, sans-serif; | |
| 6395 font-size: 0.9em; | |
| 6396 line-height: 1em; | |
| 6397 letter-spacing: -0.06em; | |
| 6398 color: black; | |
| 6399 } | |
| 6400 | |
| 6401 div.big.prog_logo { | |
| 6402 font-size: 18px; | |
| 6403 } | |
| 6404 | |
| 6405 </style> | |
| 6406 <style> | |
| 6407 .block_td { | |
| 6408 height:25px; | |
| 6409 } | |
| 6410 .block_container { | |
| 6411 position:relative; | |
| 6412 box-sizing: border-box; | |
| 6413 height: 25px; | |
| 6414 padding: 0px; | |
| 6415 margin: 0px; | |
| 6416 margin-left: 1em; | |
| 6417 } | |
| 6418 .block_label { | |
| 6419 position: absolute; | |
| 6420 display: inline-block; | |
| 6421 padding: 3px; | |
| 6422 z-index: 4; | |
| 6423 top: 6px; | |
| 6424 height: 12px; | |
| 6425 line-height: 12px; | |
| 6426 font-size: 12px; | |
| 6427 background-color: white; | |
| 6428 border: 1px solid black; | |
| 6429 -moz-border-radius: 12px; | |
| 6430 -webkit-border-radius: 12px; | |
| 6431 border-radius: 12px; | |
| 6432 transform: translateX(-50%); | |
| 6433 } | |
| 6434 .block_motif { | |
| 6435 position: absolute; | |
| 6436 z-index: 3; | |
| 6437 top: 0px; | |
| 6438 box-sizing: border-box; | |
| 6439 border: 1px solid black; | |
| 6440 height: 12px; | |
| 6441 background-color: cyan; | |
| 6442 } | |
| 6443 .block_motif.top { | |
| 6444 border-bottom-width: 0; | |
| 6445 } | |
| 6446 .block_motif.bottom { | |
| 6447 border-top-width: 0; | |
| 6448 } | |
| 6449 .block_motif.scanned_site { | |
| 6450 opacity: 0.3; | |
| 6451 } | |
| 6452 .block_motif.scanned_site.active { | |
| 6453 opacity: 0.9; | |
| 6454 } | |
| 6455 .block_region { | |
| 6456 position:absolute; | |
| 6457 z-index:6; | |
| 6458 height:25px; | |
| 6459 top:0px; | |
| 6460 } | |
| 6461 .block_region.main { | |
| 6462 z-index:8; | |
| 6463 } | |
| 6464 .block_region.scanned_site { | |
| 6465 z-index:5; | |
| 6466 } | |
| 6467 .block_region.scanned_site.main { | |
| 6468 z-index:7; | |
| 6469 } | |
| 6470 .block_region.top { | |
| 6471 height:13px; | |
| 6472 } | |
| 6473 .block_region.bottom { | |
| 6474 height:13px; | |
| 6475 top:12px; | |
| 6476 } | |
| 6477 .block_rule { | |
| 6478 position:absolute; | |
| 6479 z-index:2; | |
| 6480 width:100%; | |
| 6481 height:1px; | |
| 6482 top:12px; | |
| 6483 left:0px; | |
| 6484 background-color:gray; | |
| 6485 } | |
| 6486 .block_plus_sym { | |
| 6487 position:absolute; | |
| 6488 z-index:4; | |
| 6489 line-height:12px; | |
| 6490 top:0px; | |
| 6491 left:-1em; | |
| 6492 } | |
| 6493 .block_minus_sym { | |
| 6494 position:absolute; | |
| 6495 z-index:4; | |
| 6496 line-height:12px; | |
| 6497 top:13px; | |
| 6498 left:-1em; | |
| 6499 } | |
| 6500 | |
| 6501 .tic_major { | |
| 6502 position:absolute; | |
| 6503 top:0em; | |
| 6504 height:0.5em; | |
| 6505 width: 2px; | |
| 6506 margin-left: -1px; | |
| 6507 background-color: blue; | |
| 6508 } | |
| 6509 .tic_minor { | |
| 6510 position:absolute; | |
| 6511 top:0em; | |
| 6512 height:0.2em; | |
| 6513 width: 1px; | |
| 6514 margin-left: -0.5px; | |
| 6515 background-color: blue; | |
| 6516 } | |
| 6517 .tic_label { | |
| 6518 position:absolute; | |
| 6519 display: inline-block; | |
| 6520 top:0.5em; | |
| 6521 height: 1em; | |
| 6522 color: blue; | |
| 6523 transform: translateX(-50%); | |
| 6524 } | |
| 6525 | |
| 6526 .block_needle { | |
| 6527 position:absolute; | |
| 6528 z-index:4; | |
| 6529 height:30px; | |
| 6530 width:1px; | |
| 6531 top:-2px; | |
| 6532 background-color:gray; | |
| 6533 } | |
| 6534 .block_needle.right { | |
| 6535 height: 60px; | |
| 6536 } | |
| 6537 .block_handle { | |
| 6538 position: absolute; | |
| 6539 display: inline-block; | |
| 6540 z-index: 5; | |
| 6541 top: 27px; | |
| 6542 min-width: 3ex; | |
| 6543 text-align: center; | |
| 6544 font-size: 12px; | |
| 6545 line-height: 12px; | |
| 6546 transform: translateX(-50%); | |
| 6547 background-color: LightGrey; | |
| 6548 border:3px outset grey; | |
| 6549 cursor: pointer; | |
| 6550 -webkit-user-select: none; /* Chrome/Safari */ | |
| 6551 -moz-user-select: none; /* Firefox */ | |
| 6552 -ms-user-select: none; /* IE10+ */ | |
| 6553 /* Rules below not implemented in browsers yet */ | |
| 6554 -o-user-select: none; | |
| 6555 user-select: none; | |
| 6556 } | |
| 6557 .block_handle.right { | |
| 6558 top: 47px; | |
| 6559 } | |
| 6560 | |
| 6561 .legend_container { | |
| 6562 text-align: right; | |
| 6563 } | |
| 6564 .legend_entry { | |
| 6565 display: inline-block; | |
| 6566 padding: 5px; | |
| 6567 } | |
| 6568 div.legend_swatch { | |
| 6569 box-sizing: border-box; | |
| 6570 width: 15px; | |
| 6571 height: 15px; | |
| 6572 border: 1px solid black; | |
| 6573 background-color: cyan; | |
| 6574 float: left; | |
| 6575 } | |
| 6576 div.legend_swatch input { | |
| 6577 display: none; | |
| 6578 } | |
| 6579 .legend_text { | |
| 6580 line-height: 15px; | |
| 6581 margin-left: 20px; | |
| 6582 } | |
| 6583 </style> | |
| 6584 <style> | |
| 6585 /* meme output specific css */ | |
| 6586 | |
| 6587 div.pop_block { | |
| 6588 position:absolute; | |
| 6589 z-index:5; | |
| 6590 padding: 5px; | |
| 6591 border: 1px solid black; | |
| 6592 display: inline-block; | |
| 6593 background-color: white; | |
| 6594 } | |
| 6595 | |
| 6596 #measure_match { | |
| 6597 position: absolute; | |
| 6598 visibility: hidden; | |
| 6599 height: auto; | |
| 6600 width: auto; | |
| 6601 white-space: nowrap; | |
| 6602 } | |
| 6603 | |
| 6604 div.template { | |
| 6605 position: absolute; | |
| 6606 z-index: 1; | |
| 6607 left: 0; | |
| 6608 top: 0; | |
| 6609 visibility: hidden; | |
| 6610 } | |
| 6611 | |
| 6612 table.block_information { | |
| 6613 margin-left: auto; | |
| 6614 margin-right: auto; | |
| 6615 } | |
| 6616 | |
| 6617 table.block_information * th { | |
| 6618 text-align: right; | |
| 6619 } | |
| 6620 | |
| 6621 *.hide_empty_seqs * tr.empty_seq { | |
| 6622 display: none; | |
| 6623 } | |
| 6624 | |
| 6625 *.hide_only_scan * tr.only_scan { | |
| 6626 display: none; | |
| 6627 } | |
| 6628 | |
| 6629 *.hide_only_scan * div.scanned_site { | |
| 6630 display: none; | |
| 6631 } | |
| 6632 | |
| 6633 td.symaction { | |
| 6634 text-align: center; | |
| 6635 text-decoration: underline; | |
| 6636 font-size: 20px; | |
| 6637 cursor: pointer; | |
| 6638 } | |
| 6639 div.sym_btn { | |
| 6640 display:inline-block; | |
| 6641 text-decoration: underline; | |
| 6642 cursor: pointer; | |
| 6643 font-size: 20px; | |
| 6644 line-height:20px; | |
| 6645 text-align: center; | |
| 6646 width: 20px; | |
| 6647 height: 20px; | |
| 6648 color: blue; | |
| 6649 } | |
| 6650 div.sym_btn:hover { | |
| 6651 color: white; | |
| 6652 background-color: blue; | |
| 6653 } | |
| 6654 | |
| 6655 div.sym_btn.positioned { | |
| 6656 position: absolute; | |
| 6657 top: 0px; | |
| 6658 } | |
| 6659 | |
| 6660 div.actionbutton { | |
| 6661 display:inline-block; | |
| 6662 cursor: pointer; | |
| 6663 font-size: 18px; | |
| 6664 line-height:20px; | |
| 6665 padding: 5px; | |
| 6666 margin: 10px 0; | |
| 6667 border: 1px solid black; | |
| 6668 } | |
| 6669 | |
| 6670 div.actionbutton:hover { | |
| 6671 color:#FFF; | |
| 6672 background-color:#000; | |
| 6673 } | |
| 6674 | |
| 6675 div.param_box { | |
| 6676 display: inline-block; | |
| 6677 margin-right: 20px; | |
| 6678 } | |
| 6679 | |
| 6680 span.param { | |
| 6681 font-weight: bold; | |
| 6682 } | |
| 6683 | |
| 6684 div.box + div.box { | |
| 6685 margin-top: 5px; | |
| 6686 } | |
| 6687 | |
| 6688 div.sites_outer { | |
| 6689 position: relative; | |
| 6690 padding-top: 20px; /* height of header */ | |
| 6691 display: inline-block; | |
| 6692 } | |
| 6693 | |
| 6694 div.sites_inner { | |
| 6695 overflow-x: hidden; | |
| 6696 overflow-y: auto; | |
| 6697 max-height: 200px; | |
| 6698 } | |
| 6699 table.sites_tbl { | |
| 6700 border-collapse: collapse; | |
| 6701 } | |
| 6702 | |
| 6703 div.sites_th_inner { | |
| 6704 position: absolute; | |
| 6705 top: 0; | |
| 6706 line-height: 20px; /* height of header */ | |
| 6707 text-align: left; | |
| 6708 padding-left: 5px; | |
| 6709 } | |
| 6710 th.nopad div.sites_th_inner { | |
| 6711 padding-left: 0; | |
| 6712 } | |
| 6713 div.sites_th_hidden { | |
| 6714 visibility: hidden; | |
| 6715 height: 0; | |
| 6716 padding: 0 10px; | |
| 6717 } | |
| 6718 th.nopad div.sites_th_hidden { | |
| 6719 padding: 0; | |
| 6720 } | |
| 6721 div.sites_inner * th { | |
| 6722 height: 0; | |
| 6723 } | |
| 6724 | |
| 6725 table.sites_tbl { | |
| 6726 overflow-x: hidden; | |
| 6727 overflow-y: auto; | |
| 6728 } | |
| 6729 | |
| 6730 .site_num { | |
| 6731 text-align: right; | |
| 6732 } | |
| 6733 .site_name { | |
| 6734 padding:0px 5px; | |
| 6735 text-align:left; | |
| 6736 } | |
| 6737 .site_strand { | |
| 6738 padding:0px 5px; | |
| 6739 text-align:center; | |
| 6740 } | |
| 6741 .norc .site_strand, .norc .site_strand_title { | |
| 6742 display: none; | |
| 6743 } | |
| 6744 .site_start { | |
| 6745 padding:0px 15px; | |
| 6746 text-align: right; | |
| 6747 } | |
| 6748 .site_pvalue { | |
| 6749 text-align:center; | |
| 6750 padding:0px 15px; | |
| 6751 text-align:right; | |
| 6752 white-space: nowrap; | |
| 6753 } | |
| 6754 .lflank, .rflank, .match, .alpha_symbol { | |
| 6755 font-weight:bold; | |
| 6756 font-size:15px; | |
| 6757 font-family: 'Courier New', Courier, monospace; | |
| 6758 color:gray; | |
| 6759 } | |
| 6760 | |
| 6761 .site.lflank { | |
| 6762 text-align:right; | |
| 6763 padding-right:5px; | |
| 6764 color:gray; | |
| 6765 } | |
| 6766 .site.match { | |
| 6767 text-align:center; | |
| 6768 } | |
| 6769 .site.rflank { | |
| 6770 text-align:left; | |
| 6771 padding-left:5px; | |
| 6772 padding-right: 20px; | |
| 6773 } | |
| 6774 | |
| 6775 th.stop_reason { | |
| 6776 text-align: left; | |
| 6777 padding-right: 10px; | |
| 6778 } | |
| 6779 | |
| 6780 th.motif_ordinal { | |
| 6781 | |
| 6782 } | |
| 6783 td.motif_ordinal { | |
| 6784 text-align: right; | |
| 6785 padding-right: 10px; | |
| 6786 } | |
| 6787 th.motif_logo { | |
| 6788 padding-right: 10px; | |
| 6789 } | |
| 6790 td.motif_logo { | |
| 6791 padding-right: 10px; | |
| 6792 } | |
| 6793 th.motif_evalue { | |
| 6794 text-align:right; | |
| 6795 padding-right: 10px; | |
| 6796 } | |
| 6797 td.motif_evalue { | |
| 6798 text-align: right; | |
| 6799 white-space: nowrap; | |
| 6800 padding-right: 20px; | |
| 6801 } | |
| 6802 th.motif_nsites { | |
| 6803 text-align: right; | |
| 6804 padding-right: 10px; | |
| 6805 } | |
| 6806 td.motif_nsites { | |
| 6807 text-align: right; | |
| 6808 padding-right: 20px; | |
| 6809 } | |
| 6810 th.motif_width { | |
| 6811 text-align: right; | |
| 6812 padding-right: 5px; | |
| 6813 } | |
| 6814 td.motif_width { | |
| 6815 text-align: right; | |
| 6816 padding-right: 15px; | |
| 6817 } | |
| 6818 th.motif_more { | |
| 6819 padding: 0 5px; | |
| 6820 } | |
| 6821 td.motif_more { | |
| 6822 text-align: center; | |
| 6823 padding: 0 5px; | |
| 6824 } | |
| 6825 th.motif_submit { | |
| 6826 padding: 0 5px; | |
| 6827 } | |
| 6828 td.motif_submit { | |
| 6829 text-align: center; | |
| 6830 padding: 0 5px; | |
| 6831 } | |
| 6832 th.motif_download { | |
| 6833 padding-left: 5px; | |
| 6834 } | |
| 6835 td.motif_download { | |
| 6836 text-align: center; | |
| 6837 padding-left: 5px; | |
| 6838 } | |
| 6839 | |
| 6840 | |
| 6841 div.tabArea { | |
| 6842 font-size: 80%; | |
| 6843 font-weight: bold; | |
| 6844 } | |
| 6845 | |
| 6846 .norc div.tabArea { | |
| 6847 display: none; | |
| 6848 } | |
| 6849 | |
| 6850 span.tab, span.tab:visited { | |
| 6851 cursor: pointer; | |
| 6852 color: #888; | |
| 6853 background-color: #ddd; | |
| 6854 border: 2px solid #ccc; | |
| 6855 padding: 2px 1em; | |
| 6856 text-decoration: none; | |
| 6857 } | |
| 6858 span.tab.middle { | |
| 6859 border-left-width: 0px; | |
| 6860 } | |
| 6861 div.tabArea.base span.tab { | |
| 6862 border-top-width: 0px; | |
| 6863 } | |
| 6864 div.tabArea.top span.tab { | |
| 6865 border-bottom-width: 0px; | |
| 6866 } | |
| 6867 | |
| 6868 span.tab:hover { | |
| 6869 background-color: #bbb; | |
| 6870 border-color: #bbb; | |
| 6871 color: #666; | |
| 6872 } | |
| 6873 span.tab.activeTab, span.tab.activeTab:hover, span.tab.activeTab:visited { | |
| 6874 background-color: white; | |
| 6875 color: black; | |
| 6876 cursor: default; | |
| 6877 } | |
| 6878 div.tabMain { | |
| 6879 border: 2px solid #ccc; | |
| 6880 background-color: white; | |
| 6881 padding: 10px; | |
| 6882 } | |
| 6883 div.tabMain.base { | |
| 6884 margin-top: 5px; | |
| 6885 display: inline-block; | |
| 6886 max-width: 98%; | |
| 6887 } | |
| 6888 | |
| 6889 div.tabMain.top { | |
| 6890 margin-bottom: 5px; | |
| 6891 } | |
| 6892 | |
| 6893 div.tabCenter { | |
| 6894 max-width: 100%; | |
| 6895 overflow-x: auto; | |
| 6896 height: 200px; | |
| 6897 overflow-y: hidden; | |
| 6898 } | |
| 6899 | |
| 6900 canvas.logo_rc { | |
| 6901 display:none; | |
| 6902 } | |
| 6903 .show_rc_logo > canvas { | |
| 6904 display: none; | |
| 6905 } | |
| 6906 .show_rc_logo > canvas.logo_rc { | |
| 6907 display: block; | |
| 6908 } | |
| 6909 | |
| 6910 canvas.scan_logo { | |
| 6911 margin-left: 10px; | |
| 6912 } | |
| 6913 | |
| 6914 div.blocks_outer { | |
| 6915 position: relative; | |
| 6916 padding-top: 20px; /* height of header */ | |
| 6917 } | |
| 6918 | |
| 6919 div.blocks_inner { | |
| 6920 overflow-x: hidden; | |
| 6921 overflow-y: auto; | |
| 6922 max-height: 200px; | |
| 6923 } | |
| 6924 table.blocks_tbl { | |
| 6925 border-collapse: collapse; | |
| 6926 width: 100%; | |
| 6927 } | |
| 6928 | |
| 6929 div.blocks_th_inner { | |
| 6930 position: absolute; | |
| 6931 top: 0; | |
| 6932 line-height: 20px; /* height of header */ | |
| 6933 text-align: left; | |
| 6934 padding-left: 5px; | |
| 6935 } | |
| 6936 th.nopad div.blocks_th_inner { | |
| 6937 padding-left: 0; | |
| 6938 } | |
| 6939 div.blocks_th_hidden { | |
| 6940 visibility: hidden; | |
| 6941 height: 0; | |
| 6942 padding: 0 10px; | |
| 6943 } | |
| 6944 th.nopad div.blocks_th_hidden { | |
| 6945 padding: 0; | |
| 6946 } | |
| 6947 div.blocks_inner * th { | |
| 6948 height: 0; | |
| 6949 } | |
| 6950 | |
| 6951 table.blocks_tbl { | |
| 6952 overflow-x: hidden; | |
| 6953 overflow-y: auto; | |
| 6954 } | |
| 6955 td.block_td { | |
| 6956 width: 99%; | |
| 6957 } | |
| 6958 | |
| 6959 *.blockdiag_num { | |
| 6960 text-align: right; | |
| 6961 } | |
| 6962 | |
| 6963 td.blockdiag_name { | |
| 6964 text-align: left; | |
| 6965 padding:0px 10px; | |
| 6966 } | |
| 6967 | |
| 6968 td.blockdiag_pvalue { | |
| 6969 padding:0px 10px; | |
| 6970 text-align:right; | |
| 6971 white-space: nowrap; | |
| 6972 } | |
| 6973 | |
| 6974 div.preview_btn { | |
| 6975 border: 2px solid white; | |
| 6976 height: 16px; | |
| 6977 width: 16px; | |
| 6978 font-size: 12px; | |
| 6979 line-height: 16px; | |
| 6980 text-align: center; | |
| 6981 cursor: pointer; | |
| 6982 } | |
| 6983 div.preview_btn + div.preview_btn { | |
| 6984 margin-top: 3px; | |
| 6985 } | |
| 6986 | |
| 6987 div.preview_btn.active { | |
| 6988 border: 2px solid black; | |
| 6989 cursor: default; | |
| 6990 } | |
| 6991 | |
| 6992 div.preview_btn:hover { | |
| 6993 background-color: black; | |
| 6994 color: white; | |
| 6995 border-color: black; | |
| 6996 } | |
| 6997 | |
| 6998 div.preview_btn.active:hover { | |
| 6999 background-color: white; | |
| 7000 color: black; | |
| 7001 border-color: black; | |
| 7002 } | |
| 7003 | |
| 7004 | |
| 7005 div.preview_btn_box { | |
| 7006 position: absolute; | |
| 7007 left: 0px; | |
| 7008 top: 0px; | |
| 7009 padding: 3px; | |
| 7010 } | |
| 7011 | |
| 7012 div.preview_logo_box { | |
| 7013 height: 50px; | |
| 7014 overflow-y: hidden; | |
| 7015 } | |
| 7016 | |
| 7017 div.preview_btn_box + div.preview_logo_box { | |
| 7018 margin-left: 25px; | |
| 7019 } | |
| 7020 | |
| 7021 div.preview_box { | |
| 7022 position: relative; | |
| 7023 } | |
| 7024 | |
| 7025 div.grey_background { | |
| 7026 position:fixed; | |
| 7027 z-index: 8; | |
| 7028 background-color: #000; | |
| 7029 -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; | |
| 7030 opacity: 0.5; | |
| 7031 left: 0; | |
| 7032 top: 0; | |
| 7033 width: 100%; | |
| 7034 height: 100%; | |
| 7035 } | |
| 7036 | |
| 7037 div.popup_wrapper { | |
| 7038 position:fixed; | |
| 7039 z-index:9; | |
| 7040 width:100%; | |
| 7041 height:0; | |
| 7042 top:50%; | |
| 7043 left:0; | |
| 7044 } | |
| 7045 | |
| 7046 div.popup { | |
| 7047 width: 600px; | |
| 7048 z-index:9; | |
| 7049 margin-left: auto; | |
| 7050 margin-right: auto; | |
| 7051 padding: 5px; | |
| 7052 background-color: #FFF; | |
| 7053 border-style: double; | |
| 7054 border-width: 5px; | |
| 7055 border-color: #00666a; | |
| 7056 position:relative; | |
| 7057 } | |
| 7058 div.close { | |
| 7059 cursor: pointer; | |
| 7060 border: 1px solid black; | |
| 7061 width:15px; | |
| 7062 height:15px; | |
| 7063 line-height:15px; /* this causes vertical centering */ | |
| 7064 text-align:center; | |
| 7065 background-color:#FFF; | |
| 7066 color:#000; | |
| 7067 font-size:15px; | |
| 7068 font-family:monospace; | |
| 7069 } | |
| 7070 | |
| 7071 div.close:hover { | |
| 7072 color:#FFF; | |
| 7073 background-color:#000; | |
| 7074 } | |
| 7075 | |
| 7076 div.navnum { | |
| 7077 width:100%; | |
| 7078 height:20px; | |
| 7079 line-height:20px; | |
| 7080 text-align:center; | |
| 7081 font-size:medium; | |
| 7082 } | |
| 7083 | |
| 7084 div.navarrow { | |
| 7085 font-size: 30px; | |
| 7086 text-decoration:none; | |
| 7087 cursor: pointer; | |
| 7088 -moz-user-select: none; | |
| 7089 -webkit-user-select: none; | |
| 7090 -ms-user-select: none; | |
| 7091 } | |
| 7092 | |
| 7093 div.navarrow > span.inactive { | |
| 7094 display: inline; | |
| 7095 } | |
| 7096 div.navarrow > span.active { | |
| 7097 display: none; | |
| 7098 } | |
| 7099 | |
| 7100 div.navarrow:hover > span.active { | |
| 7101 display: inline; | |
| 7102 } | |
| 7103 div.navarrow:hover > span.inactive { | |
| 7104 display: none; | |
| 7105 } | |
| 7106 | |
| 7107 table.programs { | |
| 7108 width: 100%; | |
| 7109 } | |
| 7110 | |
| 7111 table.programs tr { | |
| 7112 background-color: #EFE; | |
| 7113 } | |
| 7114 | |
| 7115 table.programs tr.selected { | |
| 7116 background-color: #262; | |
| 7117 color: #FFF; | |
| 7118 } | |
| 7119 | |
| 7120 table.programs tr.dna_only { | |
| 7121 display: none; | |
| 7122 } | |
| 7123 | |
| 7124 table.programs.alphabet_dna tr.dna_only { | |
| 7125 display: table-row; | |
| 7126 } | |
| 7127 | |
| 7128 div.programs_scroll { | |
| 7129 width: 100%; | |
| 7130 height: 90px; | |
| 7131 overflow-y: auto; | |
| 7132 overflow-x: hidden; | |
| 7133 margin: 0 auto; | |
| 7134 } | |
| 7135 table.inputs, table.alpha_bg_table { | |
| 7136 margin-top: 20px; | |
| 7137 border-collapse:collapse; | |
| 7138 } | |
| 7139 table.inputs * td, table.inputs * th, table.alpha_bg_table * td, table.alpha_bg_table * th { | |
| 7140 padding-left: 15px; | |
| 7141 padding-right: 15px; | |
| 7142 padding-top: 1px; | |
| 7143 padding-bottom: 1px; | |
| 7144 } | |
| 7145 | |
| 7146 table.hide_psp td.col_psp, table.hide_psp th.col_psp { | |
| 7147 display: none; | |
| 7148 } | |
| 7149 | |
| 7150 /* program settings */ | |
| 7151 span.mod_oops, span.mod_zoops, span.mod_anr { | |
| 7152 display: none; | |
| 7153 } | |
| 7154 td.oops span.mod_oops,td.zoops span.mod_zoops, td.anr span.mod_anr { | |
| 7155 display: inline; | |
| 7156 } | |
| 7157 span.strand_none, span.strand_given, span.strand_both { | |
| 7158 display: none; | |
| 7159 } | |
| 7160 td.none span.strand_none, td.given span.strand_given, td.both span.strand_both { | |
| 7161 display: inline; | |
| 7162 } | |
| 7163 span.spmap_uni, span.spmap_pam { | |
| 7164 display: none; | |
| 7165 } | |
| 7166 td.uni span.spmap_uni, td.pam span.spmap_pam { | |
| 7167 display: inline; | |
| 7168 } | |
| 7169 span.prior_dirichlet, span.prior_dmix, span.prior_mega, span.prior_megap, span.prior_addone { | |
| 7170 display: none; | |
| 7171 } | |
| 7172 td.dirichlet span.prior_dirichlet, td.dmix span.prior_dmix, td.mega span.prior_mega, | |
| 7173 td.megap span.prior_megap, td.addone span.prior_addone { | |
| 7174 display: inline; | |
| 7175 } | |
| 7176 span.noendgaps_on, span.noendgaps_off { | |
| 7177 display: none; | |
| 7178 } | |
| 7179 td.on span.noendgaps_on, td.off span.noendgaps_off { | |
| 7180 display: inline; | |
| 7181 } | |
| 7182 span.substring_on, span.substring_off { | |
| 7183 display: none; | |
| 7184 } | |
| 7185 td.on span.substring_on, td.off span.substring_off { | |
| 7186 display: inline; | |
| 7187 } | |
| 7188 </style> | |
| 7189 </head> | |
| 7190 <body onload="page_loaded()" onpageshow="page_shown(event)" onresize="page_resized()"> | |
| 7191 <!-- --> | |
| 7192 <div id="grey_out_page" class="grey_background" style="display:none;"> | |
| 7193 </div> | |
| 7194 <!-- Help popups --> | |
| 7195 <div class="pop_content" id="pop_"> | |
| 7196 <p>Help poup.</p> | |
| 7197 <div style="float:right; bottom:0px;">[ | |
| 7198 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7199 </div> | |
| 7200 <div class="pop_content" id="pop_ev"> | |
| 7201 <p>The statistical significance of the motif. MEME usually finds the most | |
| 7202 statistically significant (low E-value) motifs first. It is unusual to | |
| 7203 consider a motif with an E-value larger than 0.05 significant so, as an | |
| 7204 additional indicator, MEME displays these partially transparent.</p> | |
| 7205 <p>The E-value of a motif is based on its log likelihood ratio, width, | |
| 7206 sites, the background letter frequencies (given in the command line | |
| 7207 summary), and the size of the training set.</p> | |
| 7208 <p>The E-value is an estimate of the expected number of motifs with the | |
| 7209 given log likelihood ratio (or higher), and with the same width and site | |
| 7210 count, that one would find in a similarly sized set of random | |
| 7211 sequences (sequences where each position is independent and letters are | |
| 7212 chosen according to the background letter frequencies).</p> | |
| 7213 <div style="float:right; bottom:0px;">[ | |
| 7214 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7215 </div> | |
| 7216 <div class="pop_content" id="pop_sites"> | |
| 7217 <p>The number of sites contributing to the construction of the motif.</p> | |
| 7218 <div style="float:right; bottom:0px;">[ | |
| 7219 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7220 </div> | |
| 7221 <div class="pop_content" id="pop_width"> | |
| 7222 <p>The width of the motif. Each motif describes a pattern of a fixed | |
| 7223 width, as no gaps are allowed in MEME motifs.</p> | |
| 7224 <div style="float:right; bottom:0px;">[ | |
| 7225 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7226 </div> | |
| 7227 <div class="pop_content" id="pop_more"> | |
| 7228 <p>Click on the blue symbol below to reveal more information about this motif.</p> | |
| 7229 <div style="float:right; bottom:0px;">[ | |
| 7230 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7231 </div> | |
| 7232 <div class="pop_content" id="pop_submit_dl"> | |
| 7233 <p>Click on the blue symbol below to reveal options allowing you | |
| 7234 to submit this motif to another MEME Suite motif analysis program, to download this | |
| 7235 motif in various text formats, or to download a sequence "logo" of | |
| 7236 this motif PNG or EPS format.</p> | |
| 7237 <h5>Supported Programs</h5> | |
| 7238 <dl> | |
| 7239 <dt>Tomtom</dt> | |
| 7240 <dd>Tomtom is a tool for searching for similar known motifs. | |
| 7241 [<a href="http://meme-suite.org/doc/tomtom.html?man_type=web">manual</a>]</dd> | |
| 7242 <dt>MAST</dt> | |
| 7243 <dd>MAST is a tool for searching biological sequence databases for | |
| 7244 sequences that contain one or more of a group of known motifs. | |
| 7245 [<a href="http://meme-suite.org/doc/mast.html?man_type=web">manual</a>]</dd> | |
| 7246 <dt>FIMO</dt> | |
| 7247 <dd>FIMO is a tool for searching biological sequence databases for | |
| 7248 sequences that contain one or more known motifs. | |
| 7249 [<a href="http://meme-suite.org/doc/fimo.html?man_type=web">manual</a>]</dd> | |
| 7250 <dt>GOMO</dt> | |
| 7251 <dd>GOMO is a tool for identifying possible roles (Gene Ontology | |
| 7252 terms) for DNA binding motifs. | |
| 7253 [<a href="http://meme-suite.org/doc/gomo.html?man_type=web">manual</a>]</dd> | |
| 7254 <dt>SpaMo</dt> | |
| 7255 <dd>SpaMo is a tool for inferring possible transcription factor | |
| 7256 complexes by finding motifs with enriched spacings. | |
| 7257 [<a href="http://meme-suite.org/doc/spamo.html?man_type=web">manual</a>]</dd> | |
| 7258 </dl> | |
| 7259 <div style="float:right; bottom:0px;">[ | |
| 7260 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7261 </div> | |
| 7262 <div class="pop_content" id="pop_llr"> | |
| 7263 <p>The log likelihood ratio of the motif.The log likelihood ratio is the | |
| 7264 logarithm of the ratio of the probability of the occurrences of the motif | |
| 7265 given the motif model (likelihood given the motif) versus their | |
| 7266 probability given the background model (likelihood given the null model). | |
| 7267 (Normally the background model is a 0-order Markov model using the | |
| 7268 background letter frequencies, but higher order Markov models may be | |
| 7269 specified via the -bfile option to MEME.).</p> | |
| 7270 <div style="float:right; bottom:0px;">[ | |
| 7271 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7272 </div> | |
| 7273 <div class="pop_content" id="pop_ic"> | |
| 7274 <p>The information content of the motif in bits. It is equal to the sum | |
| 7275 of the uncorrected information content, R(), in the columns of the pwm. | |
| 7276 This is equal relative entropy of the motif relative to a uniform | |
| 7277 background frequency model.</p> | |
| 7278 <div style="float:right; bottom:0px;">[ | |
| 7279 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7280 </div> | |
| 7281 <div class="pop_content" id="pop_re"> | |
| 7282 <p>The relative entropy of the motif.</p> | |
| 7283 | |
| 7284 <p style="font-family: monospace;">re = llr / (sites * ln(2))</p> | |
| 7285 <div style="float:right; bottom:0px;">[ | |
| 7286 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7287 </div> | |
| 7288 <div class="pop_content" id="pop_bt"> | |
| 7289 <p>The Bayes Threshold.</p> | |
| 7290 <div style="float:right; bottom:0px;">[ | |
| 7291 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7292 </div> | |
| 7293 <div class="pop_content" id="pop_site_strand"> | |
| 7294 <p>The strand used for the motif site.</p> | |
| 7295 <dl> | |
| 7296 <dt>+</dt> | |
| 7297 <dd>The motif site was found in the sequence as it was supplied.</dd> | |
| 7298 <dt>-</dt> | |
| 7299 <dd>The motif site was found in the reverse complement of the supplied sequence.</dd> | |
| 7300 </dl> | |
| 7301 <div style="float:right; bottom:0px;">[ | |
| 7302 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7303 </div> | |
| 7304 <div class="pop_content" id="pop_site_start"> | |
| 7305 <p>The position in the sequence where the motif site starts. If a motif | |
| 7306 started right at the begining of a sequence it would be described as | |
| 7307 starting at position 1.</p> | |
| 7308 <div style="float:right; bottom:0px;">[ | |
| 7309 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7310 </div> | |
| 7311 <div class="pop_content" id="pop_site_pvalue"> | |
| 7312 <p>The probability that an equal or better site would be found in a | |
| 7313 random sequence of the same length conforming to the background letter | |
| 7314 frequencies.</p> | |
| 7315 <div style="float:right; bottom:0px;">[ | |
| 7316 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7317 </div> | |
| 7318 <div class="pop_content" id="pop_site_match"> | |
| 7319 <p>A motif site with the 10 flanking letters on either side.</p> | |
| 7320 <p>When the site is not on the given strand then the site | |
| 7321 and both flanks are reverse complemented so they align.</p> | |
| 7322 <div style="float:right; bottom:0px;">[ | |
| 7323 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7324 </div> | |
| 7325 | |
| 7326 <div class="pop_content" id="pop_seq_name"> | |
| 7327 <p>The name of the sequences as given in the FASTA file.</p> | |
| 7328 <p>The number to the left of the sequence name is the ordinal | |
| 7329 of the sequence.</p> | |
| 7330 <div style="float:right; bottom:0px;">[ | |
| 7331 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7332 </div> | |
| 7333 | |
| 7334 <div class="pop_content" id="pop_motif_sites"> | |
| 7335 <p>These are the motif sites predicted by MEME and used to build the motif.</p> | |
| 7336 <p>These sites are shown in solid color and hovering the cursor | |
| 7337 over a site will reveal details about the site. Only sequences | |
| 7338 that contain a motif site are shown.</p> | |
| 7339 <div style="float:right; bottom:0px;">[ | |
| 7340 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7341 </div> | |
| 7342 | |
| 7343 <div class="pop_content" id="pop_scanned_sites"> | |
| 7344 <p>These are the motif sites predicted by MEME plus | |
| 7345 any additional sites detected using a motif scanning | |
| 7346 algorithm.</p> | |
| 7347 <p>These MEME sites are shown in solid color and | |
| 7348 additional scanned sites are shown in transparent color. | |
| 7349 Hovering the cursor over a site will reveal details about the site. | |
| 7350 Only sequences containing a predicted or scanned motif site are shown.</p> | |
| 7351 <p>The scanned sites are predicted using a | |
| 7352 log-odds scoring matrix constructed from the MEME sites. | |
| 7353 Only scanned sites with position <i>p</i>-values less | |
| 7354 than 0.0001 are shown.</p> | |
| 7355 <div style="float:right; bottom:0px;">[ | |
| 7356 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7357 </div> | |
| 7358 | |
| 7359 <div class="pop_content" id="pop_all_sequences"> | |
| 7360 <p>These are the same sites as shown by selecting the | |
| 7361 "Motif Sites + Scanned Sites" button except that all | |
| 7362 sequences, including those with no sites, are included | |
| 7363 in the diagram.</p> | |
| 7364 <div style="float:right; bottom:0px;">[ | |
| 7365 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7366 </div> | |
| 7367 | |
| 7368 <div class="pop_content" id="pop_seq_pvalue"> | |
| 7369 <p>This is the combined match <i>p</i>-value.</p> | |
| 7370 <p>The combined match <i>p</i>-value is defined as the probability that a | |
| 7371 random sequence (with the same length and conforming to the background) | |
| 7372 would have position <i>p</i>-values such that the product is smaller | |
| 7373 or equal to the value calulated for the sequence under test.</p> | |
| 7374 <p>The position <i>p</i>-value is defined as the probability that a | |
| 7375 random sequence (with the same length and conforming to the background) | |
| 7376 would have a match to the motif under test with a score greater or equal | |
| 7377 to the largest found in the sequence under test.</p> | |
| 7378 <p>Hovering your mouse over a motif site in the motif location | |
| 7379 block diagram will show its position <i>p</i>-value and other information | |
| 7380 about the site.</p> | |
| 7381 | |
| 7382 <div style="float:right; bottom:0px;">[ | |
| 7383 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7384 </div> | |
| 7385 <div class="pop_content" id="pop_motif_location"> | |
| 7386 <p>This diagram shows the location of motif sites.</p> | |
| 7387 <p>Each block shows the position and strength of a motif | |
| 7388 site. The height of a block gives an indication of the | |
| 7389 significance of the site as taller blocks are more significant. | |
| 7390 The height is calculated to be proportional to the negative | |
| 7391 logarithm of the <i>p</i>-value of the site, truncated at | |
| 7392 the height for a <i>p</i>-value of 1e-10.</p> | |
| 7393 <p>For complementable alphabets (like DNA), sites on the | |
| 7394 positive strand are shown above the line, | |
| 7395 sites on the negative strand are shown below.</p> | |
| 7396 <p>Placing the cursor | |
| 7397 over a motif site will reveal more information about the site | |
| 7398 including its position <i>p</i>-value. (See the help | |
| 7399 for the <i>p</i>-value column for an explanation of position | |
| 7400 <i>p</i>-values.)</p> | |
| 7401 <div style="float:right; bottom:0px;">[ | |
| 7402 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7403 </div> | |
| 7404 | |
| 7405 <div class="pop_content" id="pop_seq_source"> | |
| 7406 <p>The name of the file of sequences input to MEME.</p> | |
| 7407 <div style="float:right; bottom:0px;">[ | |
| 7408 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7409 </div> | |
| 7410 <div class="pop_content" id="pop_psp_source"> | |
| 7411 <p>The position specific priors file used by MEME to find the motifs.</p> | |
| 7412 <div style="float:right; bottom:0px;">[ | |
| 7413 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7414 </div> | |
| 7415 <div class="pop_content" id="pop_seq_alph"> | |
| 7416 <p>The alphabet used by the sequences.</p> | |
| 7417 <div style="float:right; bottom:0px;">[ | |
| 7418 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7419 </div> | |
| 7420 <div class="pop_content" id="pop_seq_count"> | |
| 7421 <p>The number of sequences provided as input to MEME.</p> | |
| 7422 <div style="float:right; bottom:0px;">[ | |
| 7423 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7424 </div> | |
| 7425 | |
| 7426 <div class="pop_content" id="pop_alph_name"> | |
| 7427 <p>The name of the alphabet symbol.</p> | |
| 7428 <div style="float:right; bottom:0px;">[ | |
| 7429 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7430 </div> | |
| 7431 <div class="pop_content" id="pop_alph_freq"> | |
| 7432 <p>The frequency of the alphabet symbol in the dataset with a pseudocount | |
| 7433 so it is never zero.</p> | |
| 7434 <div style="float:right; bottom:0px;">[ | |
| 7435 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7436 </div> | |
| 7437 <div class="pop_content" id="pop_alph_bg"> | |
| 7438 <p>The frequency of the alphabet symbol as defined by the background model.</p> | |
| 7439 <div style="float:right; bottom:0px;">[ | |
| 7440 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7441 </div> | |
| 7442 | |
| 7443 <!-- templates --> | |
| 7444 <div id="measure_match" class="match"></div> | |
| 7445 <div class="template pop_block" id="tmpl_block_info"> | |
| 7446 <div> | |
| 7447 <span class="tvar_logo_pad lflank" style="visibility:hidden;"></span> | |
| 7448 <span class="tvar_logo"></span> | |
| 7449 </div> | |
| 7450 <div class="block_sequence_fragment"> | |
| 7451 <span class="tvar_lflank lflank"></span> | |
| 7452 <span class="tvar_match match"></span> | |
| 7453 <span class="tvar_rflank rflank"></span> | |
| 7454 </div> | |
| 7455 <table class="block_information"> | |
| 7456 <tr><th>Motif</th><td class="tvar_motif">1</td></tr> | |
| 7457 <tr><th><i>p</i>-value</th><td class="tvar_pvalue">8.23e-7</td></tr> | |
| 7458 <tr><th>Start</th><td class="tvar_start">23</td></tr> | |
| 7459 <tr><th>End</th><td class="tvar_end">33</td></tr> | |
| 7460 </table> | |
| 7461 </div> | |
| 7462 | |
| 7463 <div class="template pop_block" id="tmpl_scan_info"> | |
| 7464 <h5>Scanned Site</h5> | |
| 7465 <div class="tvar_logo"></div> | |
| 7466 <table class="block_information"> | |
| 7467 <tr><th>Motif</th><td class="tvar_motif">1</td></tr> | |
| 7468 <tr><th><i>p</i>-value</th><td class="tvar_pvalue">8.23e-7</td></tr> | |
| 7469 <tr><th>Start</th><td class="tvar_start">23</td></tr> | |
| 7470 <tr><th>End</th><td class="tvar_end">33</td></tr> | |
| 7471 </table> | |
| 7472 </div> | |
| 7473 | |
| 7474 <div class="template box expanded_motif" id="tmpl_motif_expanded"> | |
| 7475 <div style="position: relative; min-height: 20px"> | |
| 7476 <div class="param_box"> | |
| 7477 <span class="param"><span class="tvar_ordinal"></span>.</span> | |
| 7478 </div> | |
| 7479 <div class="sym_btn positioned tvar_less" tabindex="0" | |
| 7480 title="Show less information.">↥</div> | |
| 7481 <div class="sym_btn positioned tvar_submit" tabindex="0" | |
| 7482 title="Submit the motif to another MEME Suite program or download it.">⇢</div> | |
| 7483 </div> | |
| 7484 <div> | |
| 7485 <div class="param_box"> | |
| 7486 <span class="param"><i>E</i>-value:</span> | |
| 7487 <span class="tvar_evalue"></span> | |
| 7488 <div class="help" data-topic="pop_ev"></div> | |
| 7489 </div> | |
| 7490 <div class="param_box"> | |
| 7491 <span class="param">Site Count:</span> | |
| 7492 <span class="tvar_site_count"></span> | |
| 7493 <div class="help" data-topic="pop_sites"></div> | |
| 7494 </div> | |
| 7495 <div class="param_box"> | |
| 7496 <span class="param">Width:</span> | |
| 7497 <span class="tvar_width"></span> | |
| 7498 <div class="help" data-topic="pop_width"></div> | |
| 7499 </div> | |
| 7500 </div> | |
| 7501 <div class="tabMain base"> | |
| 7502 <div class="tabCenter tvar_logo"></div> | |
| 7503 </div> | |
| 7504 <div class="tabArea base"> | |
| 7505 <span class="tvar_tab tab" tabindex="0">Standard</span><span | |
| 7506 class="tvar_tab_rc tab middle" tabindex="0">Reverse | |
| 7507 Complement</span> | |
| 7508 </div> | |
| 7509 <div style="padding: 10px 0"> | |
| 7510 <div class="param_box"> | |
| 7511 <span class="param">Log Likelihood Ratio:</span> | |
| 7512 <span class="tvar_llr"></span> | |
| 7513 <div class="help" data-topic="pop_llr"></div> | |
| 7514 </div> | |
| 7515 <div class="param_box"> | |
| 7516 <span class="param">Information Content:</span> | |
| 7517 <span class="tvar_ic"></span> | |
| 7518 <div class="help" data-topic="pop_ic"></div> | |
| 7519 </div> | |
| 7520 <div class="param_box"> | |
| 7521 <span class="param">Relative Entropy:</span> | |
| 7522 <span class="tvar_re"></span> | |
| 7523 <div class="help" data-topic="pop_re"></div> | |
| 7524 </div> | |
| 7525 <div class="param_box"> | |
| 7526 <span class="param">Bayes Threshold:</span> | |
| 7527 <span class="tvar_bt"></span> | |
| 7528 <div class="help" data-topic="pop_bt"></div> | |
| 7529 </div> | |
| 7530 </div> | |
| 7531 <div class="tvar_sites"></div> | |
| 7532 </div> | |
| 7533 | |
| 7534 | |
| 7535 <div class="popup_wrapper"> | |
| 7536 <div class="popup" style="display:none; top: -150px;" id="download"> | |
| 7537 <div> | |
| 7538 <div style="float:right; "> | |
| 7539 <div id="outpop_close" class="close" tabindex="0">x</div> | |
| 7540 </div> | |
| 7541 <h2 class="mainh" style="margin:0; padding:0;">Submit or Download</h2> | |
| 7542 <div style="clear:both"></div> | |
| 7543 </div> | |
| 7544 <div style="height:100px"> | |
| 7545 <div style="float:right; width: 30px;"> | |
| 7546 <div id="outpop_prev" class="navarrow" tabindex="0"> | |
| 7547 <span class="inactive">⇧</span><span class="active">⬆</span> | |
| 7548 </div> | |
| 7549 <div id="outpop_num" class="navnum"></div> | |
| 7550 <div id="outpop_next" class="navarrow" tabindex="0"> | |
| 7551 <span class="inactive">⇩</span><span class="active">⬇</span> | |
| 7552 </div> | |
| 7553 </div> | |
| 7554 <div id="logo_box" style="height: 100px; margin-right: 40px;"> | |
| 7555 <canvas id="outpop_logo" height="100" width="580"></canvas> | |
| 7556 <canvas id="outpop_logo_rc" class="logo_rc" height="100" width="580"></canvas> | |
| 7557 </div> | |
| 7558 </div> | |
| 7559 <div> | |
| 7560 <!-- tabs start --> | |
| 7561 <div class="tabArea top"> | |
| 7562 <span id="outpop_tab_1" class="tab">Submit Motif</span><span | |
| 7563 id="outpop_tab_2" class="tab middle">Download Motif</span><span | |
| 7564 id="outpop_tab_3" class="tab middle">Download Logo</span> | |
| 7565 </div> | |
| 7566 <div class="tabMain top"> | |
| 7567 <!-- Submit to another program --> | |
| 7568 <div id="outpop_pnl_1"> | |
| 7569 <h4 class="compact">Submit to program</h4> | |
| 7570 <table id="programs" class="programs"> | |
| 7571 <tr class="dna_only"> | |
| 7572 <td><input type="radio" name="program" value="tomtom" id="submit_tomtom"></td> | |
| 7573 <td><label for="submit_tomtom">Tomtom</label></td> | |
| 7574 <td><label for="submit_tomtom">Find similar motifs in | |
| 7575 published libraries or a library you supply.</label></td> | |
| 7576 </tr> | |
| 7577 <tr> | |
| 7578 <td><input type="radio" name="program" value="fimo" id="submit_fimo"></td> | |
| 7579 <td><label for="submit_fimo">FIMO</label></td> | |
| 7580 <td><label for="submit_fimo">Find motif occurrences in | |
| 7581 sequence data.</label></td> | |
| 7582 </tr> | |
| 7583 <tr> | |
| 7584 <td><input type="radio" name="program" value="mast" id="submit_mast"></td> | |
| 7585 <td><label for="submit_mast">MAST</label></td> | |
| 7586 <td><label for="submit_mast">Rank sequences by affinity to | |
| 7587 groups of motifs.</label></td> | |
| 7588 </tr> | |
| 7589 <tr class="dna_only"> | |
| 7590 <td><input type="radio" name="program" value="gomo" id="submit_gomo"></td> | |
| 7591 <td><label for="submit_gomo">GOMo</label></td> | |
| 7592 <td><label for="submit_gomo">Identify possible roles (Gene | |
| 7593 Ontology terms) for motifs.</label></td> | |
| 7594 </tr> | |
| 7595 <tr class="dna_only"> | |
| 7596 <td><input type="radio" name="program" value="spamo" id="submit_spamo"></td> | |
| 7597 <td><label for="submit_spamo">SpaMo</label></td> | |
| 7598 <td><label for="submit_spamo">Find other motifs that are | |
| 7599 enriched at specific close spacings which might imply the existance of a complex.</label></td> | |
| 7600 </tr> | |
| 7601 </table> | |
| 7602 </div> | |
| 7603 <!-- download text format --> | |
| 7604 <div id="outpop_pnl_2"> | |
| 7605 <div> | |
| 7606 <label for="text_format">Format:</label> | |
| 7607 <select id="text_format"> | |
| 7608 <option value="0">Count Matrix</option> | |
| 7609 <option value="1">Probability Matrix</option> | |
| 7610 <option value="2">Minimal MEME</option> | |
| 7611 <option value="3">FASTA</option> | |
| 7612 <option value="4">Raw</option> | |
| 7613 </select> | |
| 7614 </div> | |
| 7615 <form id="text_form" method="post" action=""> | |
| 7616 <script>$("text_form").action = site_url + "/utilities/save_generated_file";</script> | |
| 7617 <input type="hidden" id="text_name" name="name" value="motif.txt"> | |
| 7618 <input type="hidden" name="mime_type" value="text/plain"> | |
| 7619 <textarea id="outpop_text" name="content" | |
| 7620 style="width:99%; white-space: pre; word-wrap: normal; overflow-x: scroll;" | |
| 7621 rows="8" readonly="readonly" wrap="off"></textarea> | |
| 7622 </form> | |
| 7623 </div> | |
| 7624 <!-- download logo format --> | |
| 7625 <div id="outpop_pnl_3"> | |
| 7626 <form id="logo_form" method="post" action=""> | |
| 7627 <script>$("logo_form").action = site_url + "/utilities/generate_logo";</script> | |
| 7628 <input type="hidden" name="program" value="MEME"/> | |
| 7629 <input type="hidden" id="logo_motifs" name="motifs" value=""/> | |
| 7630 <table> | |
| 7631 <tr> | |
| 7632 <td><label for="logo_format">Format:</label></td> | |
| 7633 <td> | |
| 7634 <select id="logo_format" name="png"> | |
| 7635 <option value="1">PNG (for web)</option> | |
| 7636 <option value="0">EPS (for publication)</option> | |
| 7637 </select> | |
| 7638 </td> | |
| 7639 </tr> | |
| 7640 <tr> | |
| 7641 <td><label for="logo_rc">Orientation:</label></td> | |
| 7642 <td> | |
| 7643 <select id="logo_rc" name="rc1"> | |
| 7644 <option value="0">Normal</option> | |
| 7645 <option value="1" id="logo_rc_option">Reverse Complement</option> | |
| 7646 </select> | |
| 7647 </td> | |
| 7648 </tr> | |
| 7649 <tr> | |
| 7650 <td><label for="logo_ssc">Small Sample Correction:</label></td> | |
| 7651 <td> | |
| 7652 <input type="hidden" id="logo_err" name="errbars" value="0"/> | |
| 7653 <select id="logo_ssc" name="ssc"> | |
| 7654 <option value="0">Off</option> | |
| 7655 <option value="1">On</option> | |
| 7656 </select> | |
| 7657 </td> | |
| 7658 </tr> | |
| 7659 <tr> | |
| 7660 <td><label for="logo_width">Width:</label></td> | |
| 7661 <td> | |
| 7662 <input type="text" id="logo_width" size="4" placeholder="default" name="width"/> cm | |
| 7663 </td> | |
| 7664 </tr> | |
| 7665 <tr> | |
| 7666 <td><label for="logo_height">Height:</label></td> | |
| 7667 <td> | |
| 7668 <input type="text" id="logo_height" size="4" placeholder="default" name="height"/> cm | |
| 7669 </td> | |
| 7670 </tr> | |
| 7671 </table> | |
| 7672 </form> | |
| 7673 </div> | |
| 7674 <!-- Buttons --> | |
| 7675 <div> | |
| 7676 <div style="float:left;"> | |
| 7677 <input type="button" id="outpop_do" value="Submit" /> | |
| 7678 </div> | |
| 7679 <div style="float:right;"> | |
| 7680 <input id="outpop_cancel" type="button" value="Cancel" /> | |
| 7681 </div> | |
| 7682 <div style="clear:both;"></div> | |
| 7683 </div> | |
| 7684 </div> | |
| 7685 </div> | |
| 7686 </div> | |
| 7687 </div> | |
| 7688 | |
| 7689 | |
| 7690 | |
| 7691 <!-- Page starts here --> | |
| 7692 <div id="top" class="pad1"> | |
| 7693 <div class="prog_logo big"> | |
| 7694 <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"> | |
| 7695 <h1>MEME</h1> | |
| 7696 <h2>Multiple Em for Motif Elicitation</h2> | |
| 7697 </div> | |
| 7698 <p> | |
| 7699 For further information on how to interpret these results or to get a | |
| 7700 copy of the MEME software please access | |
| 7701 <a href="http://meme-suite.org/">http://meme-suite.org</a>. | |
| 7702 </p> | |
| 7703 <p>If you use MEME in your research, please cite the following paper:<br /> | |
| 7704 <span class="citation"> | |
| 7705 Timothy L. Bailey and Charles Elkan, | |
| 7706 "Fitting a mixture model by expectation maximization to discover motifs in biopolymers", | |
| 7707 <em>Proceedings of the Second International Conference on Intelligent Systems | |
| 7708 for Molecular Biology</em>, pp. 28-36, AAAI Press, Menlo Park, California, 1994. | |
| 7709 <a href="http://meme-suite.org/doc/ismb94.pdf">[pdf]</a> | |
| 7710 </span> | |
| 7711 </p> | |
| 7712 </div> | |
| 7713 <!-- navigation --> | |
| 7714 <div class="pad2"> | |
| 7715 <a class="jump" href="#motifs_sec">Discovered Motifs</a> | |
| 7716 | | |
| 7717 <a class="jump" href="#sites_sec">Motif Locations</a> | |
| 7718 | | |
| 7719 <a class="jump" href="#inputs_sec">Inputs & Settings</a> | |
| 7720 | | |
| 7721 <a class="jump" href="#info_sec">Program information</a> | |
| 7722 </div> | |
| 7723 <!-- alert the user when their browser is not up to the task --> | |
| 7724 <noscript><h1 style="color:red">Javascript is required to view these results!</h1></noscript> | |
| 7725 <h1 id="html5_warning" style="color:red; display:none;">Your browser does not support canvas!</h1> | |
| 7726 <script> | |
| 7727 if (!window.HTMLCanvasElement) $("html5_warning").style.display = "block"; | |
| 7728 </script> | |
| 7729 <h2 class="mainh pad2" id="motifs_sec">Discovered Motifs</h2> | |
| 7730 <div id="motifs" class="box"> | |
| 7731 <p>Please wait... Loading...</p> | |
| 7732 <p>If the page has fully loaded and this message does not disappear then an error may have occurred.</p> | |
| 7733 </div> | |
| 7734 <h2 class="mainh pad2" id="sites_sec">Motif Locations</h2> | |
| 7735 <div id="blocks" class="box"> | |
| 7736 <p>Please wait... Loading...</p> | |
| 7737 <p>If the page has fully loaded and this message does not disappear then an error may have occurred.</p> | |
| 7738 </div> | |
| 7739 <h2 class="mainh pad2" id="inputs_sec">Inputs & Settings</h2> | |
| 7740 <div class="box"> | |
| 7741 <h4>Sequences</h4> | |
| 7742 <table id="seq_info" class="inputs"> | |
| 7743 <tr><th>Source <div class="help" data-topic="pop_seq_source"></div></th> | |
| 7744 <th class="col_psp">PSP Source <div class="help" data-topic="pop_psp_source"></div></th> | |
| 7745 <th>Alphabet <div class="help" data-topic="pop_seq_alph"></div></th> | |
| 7746 <th>Sequence Count <div class="help" data-topic="pop_seq_count"></div></th> | |
| 7747 </tr> | |
| 7748 <tr> | |
| 7749 <td id="ins_seq_source"></td> | |
| 7750 <td id="ins_seq_psp" class="col_psp"></td> | |
| 7751 <td id="ins_seq_alphabet"></td> | |
| 7752 <td id="ins_seq_count"></td> | |
| 7753 </tr> | |
| 7754 </table> | |
| 7755 <script> | |
| 7756 { | |
| 7757 var db = data.sequence_db; | |
| 7758 $("ins_seq_source").innerHTML = db.source; | |
| 7759 $("ins_seq_alphabet").innerHTML = meme_alphabet.get_alphabet_name(); | |
| 7760 $("ins_seq_count").innerHTML = db.sequences.length; | |
| 7761 if (db.psp) { | |
| 7762 $("ins_seq_psp").innerHTML = db.psp; | |
| 7763 } | |
| 7764 toggle_class($("seq_info"), "hide_psp", !(db.psp)); | |
| 7765 } | |
| 7766 </script> | |
| 7767 <h4>Background</h4> | |
| 7768 <span id="alpha_bg"></span> | |
| 7769 <script> | |
| 7770 { | |
| 7771 $("alpha_bg").appendChild(make_alpha_bg_table(meme_alphabet, data.sequence_db.freqs)); | |
| 7772 } | |
| 7773 </script> | |
| 7774 <h4>Other Settings</h4> | |
| 7775 <table id="tbl_settings" class="inputs hide_advanced"> | |
| 7776 <tr> | |
| 7777 <th>Motif Site Distribution</th> | |
| 7778 <td id="opt_mod"> | |
| 7779 <span class="mod_zoops">ZOOPS: Zero or one site per sequence</span> | |
| 7780 <span class="mod_oops">OOPS: Exactly one site per sequence</span> | |
| 7781 <span class="mod_anr">ANR: Any number of sites per sequence</span> | |
| 7782 </td> | |
| 7783 </tr> | |
| 7784 <tr> | |
| 7785 <th>Site Strand Handling</th> | |
| 7786 <td id="opt_strand"> | |
| 7787 <span class="strand_none">This alphabet only has one strand</span> | |
| 7788 <span class="strand_given">Sites must be on the given strand</span> | |
| 7789 <span class="strand_both">Sites may be on either strand</span> | |
| 7790 </td> | |
| 7791 </tr> | |
| 7792 <tr> | |
| 7793 <th>Maximum Number of Motifs</th> | |
| 7794 <td id="opt_nmotifs"></td> | |
| 7795 </tr> | |
| 7796 <tr> | |
| 7797 <th>Motif E-value Threshold</th> | |
| 7798 <td id="opt_evt"></td> | |
| 7799 </tr> | |
| 7800 <tr> | |
| 7801 <th>Minimum Motif Width</th> | |
| 7802 <td id="opt_minw"></td> | |
| 7803 </tr> | |
| 7804 <tr> | |
| 7805 <th>Maximum Motif Width</th> | |
| 7806 <td id="opt_maxw"></td> | |
| 7807 </tr> | |
| 7808 <tr> | |
| 7809 <th>Minimum Sites per Motif</th> | |
| 7810 <td id="opt_minsites"></td> | |
| 7811 </tr> | |
| 7812 <tr> | |
| 7813 <th>Maximum Sites per Motif</th> | |
| 7814 <td id="opt_maxsites"></td> | |
| 7815 </tr> | |
| 7816 <tr class="advanced"> | |
| 7817 <th>Bias on Number of Sites</th> | |
| 7818 <td id="opt_wnsites"></td> | |
| 7819 </tr> | |
| 7820 <tr class="advanced"> | |
| 7821 <th>Sequence Prior</th> | |
| 7822 <td id="opt_prior"> | |
| 7823 <span class="prior_dirichlet">Simple Dirichlet</span> | |
| 7824 <span class="prior_dmix">Dirichlets Mix</span> | |
| 7825 <span class="prior_mega">Mega-weight Dirichlets Mix</span> | |
| 7826 <span class="prior_megap">Mega-weight Dirichlets Mix Plus</span> | |
| 7827 <span class="prior_addone">Add One</span> | |
| 7828 </td> | |
| 7829 </tr> | |
| 7830 <tr class="advanced"> | |
| 7831 <th>Sequence Prior Strength</th> | |
| 7832 <td id="opt_b"></td> | |
| 7833 </tr> | |
| 7834 <tr class="advanced"> | |
| 7835 <th>EM Starting Point Source</th> | |
| 7836 <td id="opt_substring"> | |
| 7837 <span class="substring_on">From substrings in input sequences</span> | |
| 7838 <span class="substring_off">From strings on command line (-cons)</span> | |
| 7839 </td> | |
| 7840 </tr> | |
| 7841 <tr class="advanced"> | |
| 7842 <th>EM Starting Point Map Type</th> | |
| 7843 <td id="opt_spmap"> | |
| 7844 <span class="spmap_uni">Uniform</span> | |
| 7845 <span class="spmap_pam">Point Accepted Mutation</span> | |
| 7846 </td> | |
| 7847 </tr> | |
| 7848 <tr class="advanced"> | |
| 7849 <th>EM Starting Point Fuzz</th> | |
| 7850 <td id="opt_spfuzz"></td> | |
| 7851 </tr> | |
| 7852 <tr class="advanced"> | |
| 7853 <th>EM Maximum Iterations</th> | |
| 7854 <td id="opt_maxiter"></td> | |
| 7855 </tr> | |
| 7856 <tr class="advanced"> | |
| 7857 <th>EM Improvement Threshold</th> | |
| 7858 <td id="opt_distance"></td> | |
| 7859 </tr> | |
| 7860 <tr class="advanced"> | |
| 7861 <th>Trim Gap Open Cost</th> | |
| 7862 <td id="opt_wg"></td> | |
| 7863 </tr> | |
| 7864 <tr class="advanced"> | |
| 7865 <th>Trim Gap Extend Cost</th> | |
| 7866 <td id="opt_ws"></td> | |
| 7867 </tr> | |
| 7868 <tr class="advanced"> | |
| 7869 <th>End Gap Treatment</th> | |
| 7870 <td id="opt_noendgaps"> | |
| 7871 <span class="noendgaps_on">No cost</span> | |
| 7872 <span class="noendgaps_off">Same cost as other gaps</span> | |
| 7873 </td> | |
| 7874 </tr> | |
| 7875 <tr> | |
| 7876 <td colspan="2" style="text-align: center"> | |
| 7877 <a href="javascript:toggle_class(document.getElementById('tbl_settings'), 'hide_advanced')"> | |
| 7878 <span class="show_more">Show Advanced Settings</span> | |
| 7879 <span class="show_less">Hide Advanced Settings</span> | |
| 7880 </a> | |
| 7881 </td> | |
| 7882 </tr> | |
| 7883 </table> | |
| 7884 <script> | |
| 7885 { | |
| 7886 $("opt_mod").className = data.options.mod; | |
| 7887 $("opt_strand").className = (meme_alphabet.has_complement() ? (data.options.revcomp ? "both" : "given") : "none"); | |
| 7888 $("opt_nmotifs").textContent = data.options.nmotifs; | |
| 7889 $("opt_evt").textContent = (typeof data.options.evt === "number" ? data.options.evt : "no limit"); | |
| 7890 $("opt_minw").textContent = data.options.minw; | |
| 7891 $("opt_maxw").textContent = data.options.maxw; | |
| 7892 $("opt_minsites").textContent = data.options.minsites; | |
| 7893 $("opt_maxsites").textContent = data.options.maxsites; | |
| 7894 $("opt_wnsites").textContent = data.options.wnsites; | |
| 7895 $("opt_spmap").className = data.options.spmap; | |
| 7896 $("opt_spfuzz").textContent = data.options.spfuzz; | |
| 7897 $("opt_prior").className = data.options.prior; | |
| 7898 $("opt_b").textContent = data.options.b; | |
| 7899 $("opt_maxiter").textContent = data.options.maxiter; | |
| 7900 $("opt_distance").textContent = data.options.distance; | |
| 7901 $("opt_wg").textContent = data.options.wg; | |
| 7902 $("opt_ws").textContent = data.options.ws; | |
| 7903 $("opt_noendgaps").className = (data.options.noendgaps ? "on" : "off"); | |
| 7904 $("opt_substring").className = (data.options.substring ? "on" : "off"); | |
| 7905 } | |
| 7906 </script> | |
| 7907 </div> | |
| 7908 <!-- list information on this program --> | |
| 7909 <div id="info_sec" class="bar"> | |
| 7910 <div class="subsection"> | |
| 7911 <h5 id="version">MEME version</h5> | |
| 7912 <span id="ins_version"></span> | |
| 7913 (Release date: <span id="ins_release"></span>)<br> | |
| 7914 </div> | |
| 7915 <script> | |
| 7916 $("ins_version").innerHTML = data["version"]; | |
| 7917 $("ins_release").innerHTML = data["release"]; | |
| 7918 </script> | |
| 7919 <div class="subsection"> | |
| 7920 <h5 id="reference">Reference</h5> | |
| 7921 <span class="citation"> | |
| 7922 Timothy L. Bailey and Charles Elkan, | |
| 7923 "Fitting a mixture model by expectation maximization to discover motifs in biopolymers", | |
| 7924 <em>Proceedings of the Second International Conference on Intelligent Systems | |
| 7925 for Molecular Biology</em>, pp. 28-36, AAAI Press, Menlo Park, California, 1994. | |
| 7926 </span> | |
| 7927 </div> | |
| 7928 <div class="subsection"> | |
| 7929 <h5 id="command">Command line</h5> | |
| 7930 <textarea id="cmd" rows="5" style="width:100%;" readonly="readonly"> | |
| 7931 </textarea> | |
| 7932 <script>$("cmd").value = data["cmd"].join(" ");</script> | |
| 7933 </div> | |
| 7934 </div> | |
| 7935 | |
| 7936 </body> | |
| 7937 </html> |
