Mercurial > repos > iuc > meme_fimo
comparison test-data/meme_output_test1.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_test1_out", "-nostatus", | 14 "meme", |
| 15 "-maxsize", "1000000" | 15 "-o", |
| 16 "-nostatus", "-maxsize", "1000000" | |
| 16 ], | 17 ], |
| 17 "options": { | 18 "options": { |
| 18 "mod": "zoops", | |
| 19 "revcomp": false, | |
| 20 "nmotifs": 1, | |
| 21 "minw": 8, | |
| 22 "maxw": 50, | |
| 23 "minsites": 2, | |
| 24 "maxsites": 30, | |
| 25 "wnsites": 0.8, | |
| 26 "spmap": "pam", | |
| 27 "spfuzz": 120, | |
| 28 "maxwords": -1, | |
| 29 "prior": "megap", | |
| 30 "b": 7500, | |
| 31 "maxiter": 50, | |
| 32 "distance": 1e-05, | |
| 33 "wg": 11, | |
| 34 "ws": 1, | |
| 35 "noendgaps": false, | |
| 36 "substring": true | |
| 37 }, | |
| 38 "alphabet": { | |
| 39 "name": "Protein", | |
| 40 "like": "protein", | |
| 41 "ncore": 20, | |
| 42 "symbols": [ | |
| 43 { | |
| 44 "symbol": "A", | |
| 45 "name": "Alanine", | |
| 46 "colour": "0000CC" | |
| 47 }, { | |
| 48 "symbol": "C", | |
| 49 "name": "Cysteine", | |
| 50 "colour": "0000CC" | |
| 51 }, { | |
| 52 "symbol": "D", | |
| 53 "name": "Aspartic acid", | |
| 54 "colour": "FF00FF" | |
| 55 }, { | |
| 56 "symbol": "E", | |
| 57 "name": "Glutamic acid", | |
| 58 "colour": "FF00FF" | |
| 59 }, { | |
| 60 "symbol": "F", | |
| 61 "name": "Phenylalanine", | |
| 62 "colour": "0000CC" | |
| 63 }, { | |
| 64 "symbol": "G", | |
| 65 "name": "Glycine", | |
| 66 "colour": "FFB300" | |
| 67 }, { | |
| 68 "symbol": "H", | |
| 69 "name": "Histidine", | |
| 70 "colour": "FFCCCC" | |
| 71 }, { | |
| 72 "symbol": "I", | |
| 73 "name": "Isoleucine", | |
| 74 "colour": "0000CC" | |
| 75 }, { | |
| 76 "symbol": "K", | |
| 77 "name": "Lysine", | |
| 78 "colour": "CC0000" | |
| 79 }, { | |
| 80 "symbol": "L", | |
| 81 "name": "Leucine", | |
| 82 "colour": "0000CC" | |
| 83 }, { | |
| 84 "symbol": "M", | |
| 85 "name": "Methionine", | |
| 86 "colour": "0000CC" | |
| 87 }, { | |
| 88 "symbol": "N", | |
| 89 "name": "Asparagine", | |
| 90 "colour": "008000" | |
| 91 }, { | |
| 92 "symbol": "P", | |
| 93 "name": "Proline", | |
| 94 "colour": "FFFF00" | |
| 95 }, { | |
| 96 "symbol": "Q", | |
| 97 "name": "Glutamine", | |
| 98 "colour": "008000" | |
| 99 }, { | |
| 100 "symbol": "R", | |
| 101 "name": "Arginine", | |
| 102 "colour": "CC0000" | |
| 103 }, { | |
| 104 "symbol": "S", | |
| 105 "name": "Serine", | |
| 106 "colour": "008000" | |
| 107 }, { | |
| 108 "symbol": "T", | |
| 109 "name": "Threonine", | |
| 110 "colour": "008000" | |
| 111 }, { | |
| 112 "symbol": "V", | |
| 113 "name": "Valine", | |
| 114 "colour": "0000CC" | |
| 115 }, { | |
| 116 "symbol": "W", | |
| 117 "name": "Tryptophan", | |
| 118 "colour": "0000CC" | |
| 119 }, { | |
| 120 "symbol": "Y", | |
| 121 "name": "Tyrosine", | |
| 122 "colour": "33E6CC" | |
| 123 }, { | |
| 124 "symbol": "X", | |
| 125 "aliases": "*.", | |
| 126 "name": "Any amino acid", | |
| 127 "equals": "ACDEFGHIKLMNPQRSTVWY" | |
| 128 }, { | |
| 129 "symbol": "B", | |
| 130 "name": "Asparagine or Aspartic acid", | |
| 131 "equals": "DN" | |
| 132 }, { | |
| 133 "symbol": "Z", | |
| 134 "name": "Glutamine or Glutamic acid", | |
| 135 "equals": "EQ" | |
| 136 }, { | |
| 137 "symbol": "J", | |
| 138 "name": "Leucine or Isoleucine", | |
| 139 "equals": "IL" | |
| 140 } | |
| 141 ] | |
| 142 }, | |
| 143 "background": { | |
| 144 "freqs": [ | |
| 145 0.291, 0.229, 0.001, 0.001, 0.001, 0.255, 0.001, 0.001, 0.001, | |
| 146 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.215, 0.001, | |
| 147 0.001, 0.001 | |
| 148 ] | |
| 149 }, | |
| 150 "sequence_db": { | |
| 151 "source": "meme_input_1.fasta", | |
| 152 "psp_source": "prior30.plib", | |
| 153 "freqs": [ | |
| 154 0.294, 0.231, 0.000, 0.000, 0.000, 0.257, 0.000, 0.000, 0.000, | |
| 155 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.217, 0.000, | |
| 156 0.000, 0.000 | |
| 157 ], | |
| 158 "sequences": [ | |
| 159 { | |
| 160 "name": "chr21_19617074_19617124_+", | |
| 161 "length": 50, | |
| 162 "weight": 1.000000 | |
| 163 }, { | |
| 164 "name": "chr21_26934381_26934431_+", | |
| 165 "length": 50, | |
| 166 "weight": 1.000000 | |
| 167 }, { | |
| 168 "name": "chr21_28217753_28217803_-", | |
| 169 "length": 50, | |
| 170 "weight": 1.000000 | |
| 171 }, { | |
| 172 "name": "chr21_31710037_31710087_-", | |
| 173 "length": 50, | |
| 174 "weight": 1.000000 | |
| 175 }, { | |
| 176 "name": "chr21_31744582_31744632_-", | |
| 177 "length": 50, | |
| 178 "weight": 1.000000 | |
| 179 }, { | |
| 180 "name": "chr21_31768316_31768366_+", | |
| 181 "length": 50, | |
| 182 "weight": 1.000000 | |
| 183 }, { | |
| 184 "name": "chr21_31914206_31914256_-", | |
| 185 "length": 50, | |
| 186 "weight": 1.000000 | |
| 187 }, { | |
| 188 "name": "chr21_31933633_31933683_-", | |
| 189 "length": 50, | |
| 190 "weight": 1.000000 | |
| 191 }, { | |
| 192 "name": "chr21_31962741_31962791_-", | |
| 193 "length": 50, | |
| 194 "weight": 1.000000 | |
| 195 }, { | |
| 196 "name": "chr21_31964683_31964733_+", | |
| 197 "length": 50, | |
| 198 "weight": 1.000000 | |
| 199 }, { | |
| 200 "name": "chr21_31973364_31973414_+", | |
| 201 "length": 50, | |
| 202 "weight": 1.000000 | |
| 203 }, { | |
| 204 "name": "chr21_31992870_31992920_+", | |
| 205 "length": 50, | |
| 206 "weight": 1.000000 | |
| 207 }, { | |
| 208 "name": "chr21_32185595_32185645_-", | |
| 209 "length": 50, | |
| 210 "weight": 1.000000 | |
| 211 }, { | |
| 212 "name": "chr21_32202076_32202126_-", | |
| 213 "length": 50, | |
| 214 "weight": 1.000000 | |
| 215 }, { | |
| 216 "name": "chr21_32253899_32253949_-", | |
| 217 "length": 50, | |
| 218 "weight": 1.000000 | |
| 219 }, { | |
| 220 "name": "chr21_32410820_32410870_-", | |
| 221 "length": 50, | |
| 222 "weight": 1.000000 | |
| 223 }, { | |
| 224 "name": "chr21_36411748_36411798_-", | |
| 225 "length": 50, | |
| 226 "weight": 1.000000 | |
| 227 }, { | |
| 228 "name": "chr21_37838750_37838800_-", | |
| 229 "length": 50, | |
| 230 "weight": 1.000000 | |
| 231 }, { | |
| 232 "name": "chr21_45705687_45705737_+", | |
| 233 "length": 50, | |
| 234 "weight": 1.000000 | |
| 235 }, { | |
| 236 "name": "chr21_45971413_45971463_-", | |
| 237 "length": 50, | |
| 238 "weight": 1.000000 | |
| 239 }, { | |
| 240 "name": "chr21_45978668_45978718_-", | |
| 241 "length": 50, | |
| 242 "weight": 1.000000 | |
| 243 }, { | |
| 244 "name": "chr21_45993530_45993580_+", | |
| 245 "length": 50, | |
| 246 "weight": 1.000000 | |
| 247 }, { | |
| 248 "name": "chr21_46020421_46020471_+", | |
| 249 "length": 50, | |
| 250 "weight": 1.000000 | |
| 251 }, { | |
| 252 "name": "chr21_46031920_46031970_+", | |
| 253 "length": 50, | |
| 254 "weight": 1.000000 | |
| 255 }, { | |
| 256 "name": "chr21_46046964_46047014_+", | |
| 257 "length": 50, | |
| 258 "weight": 1.000000 | |
| 259 }, { | |
| 260 "name": "chr21_46057197_46057247_+", | |
| 261 "length": 50, | |
| 262 "weight": 1.000000 | |
| 263 }, { | |
| 264 "name": "chr21_46086869_46086919_-", | |
| 265 "length": 50, | |
| 266 "weight": 1.000000 | |
| 267 }, { | |
| 268 "name": "chr21_46102103_46102153_-", | |
| 269 "length": 50, | |
| 270 "weight": 1.000000 | |
| 271 }, { | |
| 272 "name": "chr21_47517957_47518007_+", | |
| 273 "length": 50, | |
| 274 "weight": 1.000000 | |
| 275 }, { | |
| 276 "name": "chr21_47575506_47575556_-", | |
| 277 "length": 50, | |
| 278 "weight": 1.000000 | |
| 279 } | |
| 280 ] | |
| 281 }, | 19 }, |
| 282 "motifs": [ | 20 "motifs": [ |
| 283 { | |
| 284 "db": 0, | |
| 285 "id": "GGGGTATAAAA", | |
| 286 "alt": "MEME-1", | |
| 287 "len": 11, | |
| 288 "nsites": 25, | |
| 289 "evalue": "2.4e-011", | |
| 290 "ic": 40.0, | |
| 291 "re": 13.8, | |
| 292 "llr": 239, | |
| 293 "bt": 5.33554, | |
| 294 "time": 0.772000, | |
| 295 "psm": [ | |
| 296 [ | |
| 297 -32, -680, 91, 77, 7, 138, -20, 55, 64, 107, 11, 150, 142, 72, | |
| 298 87, 396, -148, 221, -140, -36 | |
| 299 ], [ | |
| 300 -11, -680, 89, 76, 7, 137, -21, 55, 63, 107, 10, 149, 141, 71, | |
| 301 87, 396, -239, 220, -140, -36 | |
| 302 ], [ | |
| 303 -79, 41, 4, 21, -7, 44, -62, 42, -5, 99, 0, 99, 138, 52, 42, | |
| 304 399, -46, 223, -173, -68 | |
| 305 ], [ | |
| 306 11, -677, 48, 47, -2, 127, -43, 46, 27, 101, 3, 124, 138, 60, | |
| 307 62, 397, -235, 220, -160, -55 | |
| 308 ], [ | |
| 309 -596, -820, 12, -21, -53, -267, -74, 37, 16, 44, -37, 98, 31, | |
| 310 9, 19, 319, 212, 127, -193, -95 | |
| 311 ], [ | |
| 312 165, -261, 70, 110, 77, -521, -4, 147, 95, 201, 90, 121, 124, | |
| 313 91, 107, 425, -527, 314, -95, 8 | |
| 314 ], [ | |
| 315 -838, -990, -89, -149, -151, -841, -161, -117, -113, -66, | |
| 316 -209, -68, -69, -129, -91, 111, 221, -55, -255, -173 | |
| 317 ], [ | |
| 318 176, -858, -79, -103, -115, -717, -148, -95, -108, -17, -162, | |
| 319 -61, -12, -95, -69, 193, -737, 52, -240, -153 | |
| 320 ], [ | |
| 321 134, -686, 0, 16, -12, -553, -68, 44, -8, 96, -9, 88, 124, 41, | |
| 322 36, 384, 11, 216, -177, -71 | |
| 323 ], [ | |
| 324 165, -261, 70, 110, 77, -521, -4, 147, 95, 201, 90, 121, 124, | |
| 325 91, 107, 425, -527, 314, -95, 8 | |
| 326 ], [ | |
| 327 147, -614, 89, 129, 93, -121, 12, 160, 113, 217, 108, 144, | |
| 328 144, 111, 125, 447, -241, 332, -81, 22 | |
| 329 ] | |
| 330 ], | |
| 331 "pwm": [ | |
| 332 [ | |
| 333 0.240000, 0.000000, 0.000000, 0.000000, 0.000000, 0.680000, | |
| 334 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
| 335 0.000000, 0.000000, 0.000000, 0.000000, 0.080000, 0.000000, | |
| 336 0.000000, 0.000000 | |
| 337 ], [ | |
| 338 0.280000, 0.000000, 0.000000, 0.000000, 0.000000, 0.680000, | |
| 339 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
| 340 0.000000, 0.000000, 0.000000, 0.000000, 0.040000, 0.000000, | |
| 341 0.000000, 0.000000 | |
| 342 ], [ | |
| 343 0.160000, 0.320000, 0.000000, 0.000000, 0.000000, 0.360000, | |
| 344 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
| 345 0.000000, 0.000000, 0.000000, 0.000000, 0.160000, 0.000000, | |
| 346 0.000000, 0.000000 | |
| 347 ], [ | |
| 348 0.320000, 0.000000, 0.000000, 0.000000, 0.000000, 0.640000, | |
| 349 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
| 350 0.000000, 0.000000, 0.000000, 0.000000, 0.040000, 0.000000, | |
| 351 0.000000, 0.000000 | |
| 352 ], [ | |
| 353 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.040000, | |
| 354 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
| 355 0.000000, 0.000000, 0.000000, 0.000000, 0.960000, 0.000000, | |
| 356 0.000000, 0.000000 | |
| 357 ], [ | |
| 358 0.960000, 0.040000, 0.000000, 0.000000, 0.000000, 0.000000, | |
| 359 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
| 360 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
| 361 0.000000, 0.000000 | |
| 362 ], [ | |
| 363 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
| 364 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
| 365 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, | |
| 366 0.000000, 0.000000 | |
| 367 ], [ | |
| 368 1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
| 369 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
| 370 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
| 371 0.000000, 0.000000 | |
| 372 ], [ | |
| 373 0.760000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
| 374 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
| 375 0.000000, 0.000000, 0.000000, 0.000000, 0.240000, 0.000000, | |
| 376 0.000000, 0.000000 | |
| 377 ], [ | |
| 378 0.960000, 0.040000, 0.000000, 0.000000, 0.000000, 0.000000, | |
| 379 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
| 380 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
| 381 0.000000, 0.000000 | |
| 382 ], [ | |
| 383 0.840000, 0.000000, 0.000000, 0.000000, 0.000000, 0.120000, | |
| 384 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, | |
| 385 0.000000, 0.000000, 0.000000, 0.000000, 0.040000, 0.000000, | |
| 386 0.000000, 0.000000 | |
| 387 ] | |
| 388 ], | |
| 389 "sites": [ | |
| 390 { | |
| 391 "seq": 24, | |
| 392 "pos": 12, | |
| 393 "rc": false, | |
| 394 "pvalue": 1.06e-06, | |
| 395 "lflank": "AAGGCCAGGA", | |
| 396 "match": "GGGGTATAAAA", | |
| 397 "rflank": "GCCTGAGAGC" | |
| 398 }, { | |
| 399 "seq": 25, | |
| 400 "pos": 36, | |
| 401 "rc": false, | |
| 402 "pvalue": 3.41e-06, | |
| 403 "lflank": "ACAGGCCCTG", | |
| 404 "match": "GGCATATAAAA", | |
| 405 "rflank": "GCC" | |
| 406 }, { | |
| 407 "seq": 19, | |
| 408 "pos": 9, | |
| 409 "rc": false, | |
| 410 "pvalue": 3.41e-06, | |
| 411 "lflank": "CAGGCCCTG", | |
| 412 "match": "GGCATATAAAA", | |
| 413 "rflank": "GCCCCAGCAG" | |
| 414 }, { | |
| 415 "seq": 9, | |
| 416 "pos": 13, | |
| 417 "rc": false, | |
| 418 "pvalue": 3.41e-06, | |
| 419 "lflank": "GATTCACTGA", | |
| 420 "match": "GGCATATAAAA", | |
| 421 "rflank": "GGCCCTCTGC" | |
| 422 }, { | |
| 423 "seq": 21, | |
| 424 "pos": 7, | |
| 425 "rc": false, | |
| 426 "pvalue": 4.00e-06, | |
| 427 "lflank": "CCAAGGA", | |
| 428 "match": "GGAGTATAAAA", | |
| 429 "rflank": "GCCCCACAAA" | |
| 430 }, { | |
| 431 "seq": 13, | |
| 432 "pos": 13, | |
| 433 "rc": false, | |
| 434 "pvalue": 5.01e-06, | |
| 435 "lflank": "CCACCAGCTT", | |
| 436 "match": "GAGGTATAAAA", | |
| 437 "rflank": "AGCCCTGTAC" | |
| 438 }, { | |
| 439 "seq": 23, | |
| 440 "pos": 15, | |
| 441 "rc": false, | |
| 442 "pvalue": 6.06e-06, | |
| 443 "lflank": "ATACCCAGGG", | |
| 444 "match": "AGGGTATAAAA", | |
| 445 "rflank": "CCTCAGCAGC" | |
| 446 }, { | |
| 447 "seq": 15, | |
| 448 "pos": 21, | |
| 449 "rc": false, | |
| 450 "pvalue": 8.67e-06, | |
| 451 "lflank": "AATCACTGAG", | |
| 452 "match": "GATGTATAAAA", | |
| 453 "rflank": "GTCCCAGGGA" | |
| 454 }, { | |
| 455 "seq": 12, | |
| 456 "pos": 18, | |
| 457 "rc": false, | |
| 458 "pvalue": 8.67e-06, | |
| 459 "lflank": "CACCAGAGCT", | |
| 460 "match": "GGGATATATAA", | |
| 461 "rflank": "AGAAGGTTCT" | |
| 462 }, { | |
| 463 "seq": 11, | |
| 464 "pos": 16, | |
| 465 "rc": false, | |
| 466 "pvalue": 8.67e-06, | |
| 467 "lflank": "CACTATTGAA", | |
| 468 "match": "GATGTATAAAA", | |
| 469 "rflank": "TTTCATTTGC" | |
| 470 }, { | |
| 471 "seq": 22, | |
| 472 "pos": 2, | |
| 473 "rc": false, | |
| 474 "pvalue": 1.21e-05, | |
| 475 "lflank": "GA", | |
| 476 "match": "GACATATAAAA", | |
| 477 "rflank": "GCCAACATCC" | |
| 478 }, { | |
| 479 "seq": 28, | |
| 480 "pos": 32, | |
| 481 "rc": false, | |
| 482 "pvalue": 1.59e-05, | |
| 483 "lflank": "CCGGCGGGGC", | |
| 484 "match": "GGGGTATAAAG", | |
| 485 "rflank": "GGGGCGG" | |
| 486 }, { | |
| 487 "seq": 20, | |
| 488 "pos": 4, | |
| 489 "rc": false, | |
| 490 "pvalue": 1.59e-05, | |
| 491 "lflank": "CAGA", | |
| 492 "match": "GGGGTATAAAG", | |
| 493 "rflank": "GTTCCGACCA" | |
| 494 }, { | |
| 495 "seq": 6, | |
| 496 "pos": 15, | |
| 497 "rc": false, | |
| 498 "pvalue": 1.68e-05, | |
| 499 "lflank": "CCCACTACTT", | |
| 500 "match": "AGAGTATAAAA", | |
| 501 "rflank": "TCATTCTGAG" | |
| 502 }, { | |
| 503 "seq": 14, | |
| 504 "pos": 19, | |
| 505 "rc": false, | |
| 506 "pvalue": 2.03e-05, | |
| 507 "lflank": "CACCAGCAAG", | |
| 508 "match": "GATATATAAAA", | |
| 509 "rflank": "GCTCAGGAGT" | |
| 510 }, { | |
| 511 "seq": 4, | |
| 512 "pos": 12, | |
| 513 "rc": false, | |
| 514 "pvalue": 3.06e-05, | |
| 515 "lflank": "CAGGTCTAAG", | |
| 516 "match": "AGCATATATAA", | |
| 517 "rflank": "CTTGGAGTCC" | |
| 518 }, { | |
| 519 "seq": 0, | |
| 520 "pos": 39, | |
| 521 "rc": false, | |
| 522 "pvalue": 3.06e-05, | |
| 523 "lflank": "CCTCGGGACG", | |
| 524 "match": "TGGGTATATAA", | |
| 525 "rflank": "" | |
| 526 }, { | |
| 527 "seq": 18, | |
| 528 "pos": 37, | |
| 529 "rc": false, | |
| 530 "pvalue": 3.82e-05, | |
| 531 "lflank": "CGTGGTCGCG", | |
| 532 "match": "GGGGTATAACA", | |
| 533 "rflank": "GC" | |
| 534 }, { | |
| 535 "seq": 5, | |
| 536 "pos": 0, | |
| 537 "rc": false, | |
| 538 "pvalue": 3.82e-05, | |
| 539 "lflank": "", | |
| 540 "match": "AACGTATATAA", | |
| 541 "rflank": "ATGGTCCTGT" | |
| 542 }, { | |
| 543 "seq": 29, | |
| 544 "pos": 30, | |
| 545 "rc": false, | |
| 546 "pvalue": 4.02e-05, | |
| 547 "lflank": "GCTGCCGGTG", | |
| 548 "match": "AGCGTATAAAG", | |
| 549 "rflank": "GCCCTGGCG" | |
| 550 }, { | |
| 551 "seq": 1, | |
| 552 "pos": 27, | |
| 553 "rc": false, | |
| 554 "pvalue": 5.52e-05, | |
| 555 "lflank": "AGTCACAAGT", | |
| 556 "match": "GAGTTATAAAA", | |
| 557 "rflank": "GGGTCGCACG" | |
| 558 }, { | |
| 559 "seq": 3, | |
| 560 "pos": 14, | |
| 561 "rc": false, | |
| 562 "pvalue": 5.94e-05, | |
| 563 "lflank": "CCCAGGTTTC", | |
| 564 "match": "TGAGTATATAA", | |
| 565 "rflank": "TCGCCGCACC" | |
| 566 }, { | |
| 567 "seq": 16, | |
| 568 "pos": 22, | |
| 569 "rc": false, | |
| 570 "pvalue": 6.78e-05, | |
| 571 "lflank": "AGTTTCAGTT", | |
| 572 "match": "GGCATCTAAAA", | |
| 573 "rflank": "attatataac" | |
| 574 }, { | |
| 575 "seq": 7, | |
| 576 "pos": 2, | |
| 577 "rc": false, | |
| 578 "pvalue": 2.08e-04, | |
| 579 "lflank": "TC", | |
| 580 "match": "AGAGTATATAT", | |
| 581 "rflank": "AAATGTTCCT" | |
| 582 }, { | |
| 583 "seq": 8, | |
| 584 "pos": 13, | |
| 585 "rc": false, | |
| 586 "pvalue": 4.05e-04, | |
| 587 "lflank": "TATAACTCAG", | |
| 588 "match": "GTTGGATAAAA", | |
| 589 "rflank": "TAATTTGTAC" | |
| 590 } | |
| 591 ] | |
| 592 } | |
| 593 ], | |
| 594 "scan": [ | 21 "scan": [ |
| 595 { | |
| 596 "pvalue": 1.22e-03, | |
| 597 "sites": [ | |
| 598 { | |
| 599 "motif": 0, | |
| 600 "pos": 39, | |
| 601 "rc": false, | |
| 602 "pvalue": 3.06e-05 | |
| 603 } | |
| 604 ] | |
| 605 }, { | |
| 606 "pvalue": 2.21e-03, | |
| 607 "sites": [ | |
| 608 { | |
| 609 "motif": 0, | |
| 610 "pos": 27, | |
| 611 "rc": false, | |
| 612 "pvalue": 5.52e-05 | |
| 613 } | |
| 614 ] | |
| 615 }, { | |
| 616 "pvalue": 7.29e-01, | |
| 617 "sites": [] | |
| 618 }, { | |
| 619 "pvalue": 2.37e-03, | |
| 620 "sites": [ | |
| 621 { | |
| 622 "motif": 0, | |
| 623 "pos": 14, | |
| 624 "rc": false, | |
| 625 "pvalue": 5.94e-05 | |
| 626 } | |
| 627 ] | |
| 628 }, { | |
| 629 "pvalue": 1.22e-03, | |
| 630 "sites": [ | |
| 631 { | |
| 632 "motif": 0, | |
| 633 "pos": 12, | |
| 634 "rc": false, | |
| 635 "pvalue": 3.06e-05 | |
| 636 } | |
| 637 ] | |
| 638 }, { | |
| 639 "pvalue": 1.53e-03, | |
| 640 "sites": [ | |
| 641 { | |
| 642 "motif": 0, | |
| 643 "pos": 0, | |
| 644 "rc": false, | |
| 645 "pvalue": 3.82e-05 | |
| 646 } | |
| 647 ] | |
| 648 }, { | |
| 649 "pvalue": 6.70e-04, | |
| 650 "sites": [ | |
| 651 { | |
| 652 "motif": 0, | |
| 653 "pos": 15, | |
| 654 "rc": false, | |
| 655 "pvalue": 1.68e-05 | |
| 656 } | |
| 657 ] | |
| 658 }, { | |
| 659 "pvalue": 1.81e-03, | |
| 660 "sites": [ | |
| 661 { | |
| 662 "motif": 0, | |
| 663 "pos": 4, | |
| 664 "rc": false, | |
| 665 "pvalue": 4.54e-05 | |
| 666 } | |
| 667 ] | |
| 668 }, { | |
| 669 "pvalue": 1.61e-02, | |
| 670 "sites": [] | |
| 671 }, { | |
| 672 "pvalue": 1.36e-04, | |
| 673 "sites": [ | |
| 674 { | |
| 675 "motif": 0, | |
| 676 "pos": 13, | |
| 677 "rc": false, | |
| 678 "pvalue": 3.41e-06 | |
| 679 } | |
| 680 ] | |
| 681 }, { | |
| 682 "pvalue": 1.99e-01, | |
| 683 "sites": [] | |
| 684 }, { | |
| 685 "pvalue": 3.47e-04, | |
| 686 "sites": [ | |
| 687 { | |
| 688 "motif": 0, | |
| 689 "pos": 16, | |
| 690 "rc": false, | |
| 691 "pvalue": 8.67e-06 | |
| 692 } | |
| 693 ] | |
| 694 }, { | |
| 695 "pvalue": 3.47e-04, | |
| 696 "sites": [ | |
| 697 { | |
| 698 "motif": 0, | |
| 699 "pos": 18, | |
| 700 "rc": false, | |
| 701 "pvalue": 8.67e-06 | |
| 702 } | |
| 703 ] | |
| 704 }, { | |
| 705 "pvalue": 2.01e-04, | |
| 706 "sites": [ | |
| 707 { | |
| 708 "motif": 0, | |
| 709 "pos": 13, | |
| 710 "rc": false, | |
| 711 "pvalue": 5.01e-06 | |
| 712 } | |
| 713 ] | |
| 714 }, { | |
| 715 "pvalue": 8.11e-04, | |
| 716 "sites": [ | |
| 717 { | |
| 718 "motif": 0, | |
| 719 "pos": 19, | |
| 720 "rc": false, | |
| 721 "pvalue": 2.03e-05 | |
| 722 } | |
| 723 ] | |
| 724 }, { | |
| 725 "pvalue": 3.47e-04, | |
| 726 "sites": [ | |
| 727 { | |
| 728 "motif": 0, | |
| 729 "pos": 21, | |
| 730 "rc": false, | |
| 731 "pvalue": 8.67e-06 | |
| 732 } | |
| 733 ] | |
| 734 }, { | |
| 735 "pvalue": 2.71e-03, | |
| 736 "sites": [ | |
| 737 { | |
| 738 "motif": 0, | |
| 739 "pos": 22, | |
| 740 "rc": false, | |
| 741 "pvalue": 6.78e-05 | |
| 742 } | |
| 743 ] | |
| 744 }, { | |
| 745 "pvalue": 8.23e-02, | |
| 746 "sites": [] | |
| 747 }, { | |
| 748 "pvalue": 1.53e-03, | |
| 749 "sites": [ | |
| 750 { | |
| 751 "motif": 0, | |
| 752 "pos": 37, | |
| 753 "rc": false, | |
| 754 "pvalue": 3.82e-05 | |
| 755 } | |
| 756 ] | |
| 757 }, { | |
| 758 "pvalue": 1.36e-04, | |
| 759 "sites": [ | |
| 760 { | |
| 761 "motif": 0, | |
| 762 "pos": 9, | |
| 763 "rc": false, | |
| 764 "pvalue": 3.41e-06 | |
| 765 } | |
| 766 ] | |
| 767 }, { | |
| 768 "pvalue": 6.37e-04, | |
| 769 "sites": [ | |
| 770 { | |
| 771 "motif": 0, | |
| 772 "pos": 4, | |
| 773 "rc": false, | |
| 774 "pvalue": 1.59e-05 | |
| 775 } | |
| 776 ] | |
| 777 }, { | |
| 778 "pvalue": 1.60e-04, | |
| 779 "sites": [ | |
| 780 { | |
| 781 "motif": 0, | |
| 782 "pos": 7, | |
| 783 "rc": false, | |
| 784 "pvalue": 4.00e-06 | |
| 785 } | |
| 786 ] | |
| 787 }, { | |
| 788 "pvalue": 4.83e-04, | |
| 789 "sites": [ | |
| 790 { | |
| 791 "motif": 0, | |
| 792 "pos": 2, | |
| 793 "rc": false, | |
| 794 "pvalue": 1.21e-05 | |
| 795 } | |
| 796 ] | |
| 797 }, { | |
| 798 "pvalue": 2.43e-04, | |
| 799 "sites": [ | |
| 800 { | |
| 801 "motif": 0, | |
| 802 "pos": 15, | |
| 803 "rc": false, | |
| 804 "pvalue": 6.06e-06 | |
| 805 } | |
| 806 ] | |
| 807 }, { | |
| 808 "pvalue": 4.26e-05, | |
| 809 "sites": [ | |
| 810 { | |
| 811 "motif": 0, | |
| 812 "pos": 12, | |
| 813 "rc": false, | |
| 814 "pvalue": 1.06e-06 | |
| 815 } | |
| 816 ] | |
| 817 }, { | |
| 818 "pvalue": 1.36e-04, | |
| 819 "sites": [ | |
| 820 { | |
| 821 "motif": 0, | |
| 822 "pos": 36, | |
| 823 "rc": false, | |
| 824 "pvalue": 3.41e-06 | |
| 825 } | |
| 826 ] | |
| 827 }, { | |
| 828 "pvalue": 4.30e-02, | |
| 829 "sites": [] | |
| 830 }, { | |
| 831 "pvalue": 4.30e-02, | |
| 832 "sites": [] | |
| 833 }, { | |
| 834 "pvalue": 6.37e-04, | |
| 835 "sites": [ | |
| 836 { | |
| 837 "motif": 0, | |
| 838 "pos": 32, | |
| 839 "rc": false, | |
| 840 "pvalue": 1.59e-05 | |
| 841 } | |
| 842 ] | |
| 843 }, { | |
| 844 "pvalue": 1.61e-03, | |
| 845 "sites": [ | |
| 846 { | |
| 847 "motif": 0, | |
| 848 "pos": 30, | |
| 849 "rc": false, | |
| 850 "pvalue": 4.02e-05 | |
| 851 } | |
| 852 ] | |
| 853 } | |
| 854 ] | |
| 855 }; | |
| 856 </script> | 22 </script> |
| 857 <script> | |
| 858 var site_url = "http://meme-suite.org"; | 23 var site_url = "http://meme-suite.org"; |
| 859 </script> | |
| 860 <script> | |
| 861 | 24 |
| 862 /* | |
| 863 * $ | |
| 864 * | |
| 865 * Shorthand function for getElementById | |
| 866 */ | |
| 867 function $(el) { | |
| 868 return document.getElementById(el); | |
| 869 } | |
| 870 | |
| 871 | |
| 872 /* | |
| 873 * See http://stackoverflow.com/a/5450113/66387 | |
| 874 * Does string multiplication like the perl x operator. | |
| 875 */ | |
| 876 function string_mult(pattern, count) { | |
| 877 if (count < 1) return ''; | |
| 878 var result = ''; | |
| 879 while (count > 1) { | |
| 880 if (count & 1) result += pattern; | |
| 881 count >>= 1, pattern += pattern; | |
| 882 } | |
| 883 return result + pattern; | |
| 884 } | |
| 885 | |
| 886 /* | |
| 887 * See http://stackoverflow.com/questions/814613/how-to-read-get-data-from-a-url-using-javascript | |
| 888 * Slightly modified with information from | |
| 889 * https://developer.mozilla.org/en/DOM/window.location | |
| 890 */ | |
| 891 function parse_params() { | |
| 892 "use strict"; | |
| 893 var search, queryStart, queryEnd, query, params, nvPairs, i, nv, n, v; | |
| 894 search = window.location.search; | |
| 895 queryStart = search.indexOf("?") + 1; | |
| 896 queryEnd = search.indexOf("#") + 1 || search.length + 1; | |
| 897 query = search.slice(queryStart, queryEnd - 1); | |
| 898 | |
| 899 if (query === search || query === "") return {}; | |
| 900 | |
| 901 params = {}; | |
| 902 nvPairs = query.replace(/\+/g, " ").split("&"); | |
| 903 | |
| 904 for (i = 0; i < nvPairs.length; i++) { | |
| 905 nv = nvPairs[i].split("="); | |
| 906 n = decodeURIComponent(nv[0]); | |
| 907 v = decodeURIComponent(nv[1]); | |
| 908 // allow a name to be used multiple times | |
| 909 // storing each value in the array | |
| 910 if (!(n in params)) { | |
| 911 params[n] = []; | |
| 912 } | |
| 913 params[n].push(nv.length === 2 ? v : null); | |
| 914 } | |
| 915 return params; | |
| 916 } | |
| 917 | |
| 918 /* | |
| 919 * coords | |
| 920 * | |
| 921 * Calculates the x and y offset of an element. | |
| 922 * From http://www.quirksmode.org/js/findpos.html | |
| 923 * with alterations to take into account scrolling regions | |
| 924 */ | |
| 925 function coords(elem) { | |
| 926 var myX = myY = 0; | |
| 927 if (elem.getBoundingClientRect) { | |
| 928 var rect; | |
| 929 rect = elem.getBoundingClientRect(); | |
| 930 myX = rect.left + ((typeof window.pageXOffset !== "undefined") ? | |
| 931 window.pageXOffset : document.body.scrollLeft); | |
| 932 myY = rect.top + ((typeof window.pageYOffset !== "undefined") ? | |
| 933 window.pageYOffset : document.body.scrollTop); | |
| 934 } else { | |
| 935 // this fall back doesn't properly handle absolutely positioned elements | |
| 936 // inside a scrollable box | |
| 937 var node; | |
| 938 if (elem.offsetParent) { | |
| 939 // subtract all scrolling | |
| 940 node = elem; | |
| 941 do { | |
| 942 myX -= node.scrollLeft ? node.scrollLeft : 0; | |
| 943 myY -= node.scrollTop ? node.scrollTop : 0; | |
| 944 } while (node = node.parentNode); | |
| 945 // this will include the page scrolling (which is unwanted) so add it back on | |
| 946 myX += (typeof window.pageXOffset !== "undefined") ? window.pageXOffset : document.body.scrollLeft; | |
| 947 myY += (typeof window.pageYOffset !== "undefined") ? window.pageYOffset : document.body.scrollTop; | |
| 948 // sum up offsets | |
| 949 node = elem; | |
| 950 do { | |
| 951 myX += node.offsetLeft; | |
| 952 myY += node.offsetTop; | |
| 953 } while (node = node.offsetParent); | |
| 954 } | |
| 955 } | |
| 956 return [myX, myY]; | |
| 957 } | |
| 958 | |
| 959 /* | |
| 960 * position_popup | |
| 961 * | |
| 962 * Positions a popup relative to an anchor element. | |
| 963 * | |
| 964 * The avaliable positions are: | |
| 965 * 0 - Centered below the anchor. | |
| 966 */ | |
| 967 function position_popup(anchor, popup, position) { | |
| 968 "use strict"; | |
| 969 var a_x, a_y, a_w, a_h, p_x, p_y, p_w, p_h; | |
| 970 var a_xy, spacer, margin, scrollbar, page_w; | |
| 971 // define constants | |
| 972 spacer = 5; | |
| 973 margin = 15; | |
| 974 scrollbar = 15; | |
| 975 // define the positions and widths | |
| 976 a_xy = coords(anchor); | |
| 977 a_x = a_xy[0]; | |
| 978 a_y = a_xy[1]; | |
| 979 a_w = anchor.offsetWidth; | |
| 980 a_h = anchor.offsetHeight; | |
| 981 p_w = popup.offsetWidth; | |
| 982 p_h = popup.offsetHeight; | |
| 983 page_w = null; | |
| 984 if (window.innerWidth) { | |
| 985 page_w = window.innerWidth; | |
| 986 } else if (document.body) { | |
| 987 page_w = document.body.clientWidth; | |
| 988 } | |
| 989 // check the position type is defined | |
| 990 if (typeof position !== "number") { | |
| 991 position = 0; | |
| 992 } | |
| 993 // calculate the popup position | |
| 994 switch (position) { | |
| 995 case 1: | |
| 996 p_x = a_x + a_w + spacer; | |
| 997 p_y = a_y + (a_h / 2) - (p_h / 2); | |
| 998 break; | |
| 999 case 0: | |
| 1000 default: | |
| 1001 p_x = a_x + (a_w / 2) - (p_w / 2); | |
| 1002 p_y = a_y + a_h + spacer; | |
| 1003 break; | |
| 1004 } | |
| 1005 // constrain the popup position | |
| 1006 if (p_x < margin) { | |
| 1007 p_x = margin; | |
| 1008 } else if (page_w != null && (p_x + p_w) > (page_w - margin - scrollbar)) { | |
| 1009 p_x = page_w - margin - scrollbar - p_w; | |
| 1010 } | |
| 1011 if (p_y < margin) { | |
| 1012 p_y = margin; | |
| 1013 } | |
| 1014 // position the popup | |
| 1015 popup.style.left = p_x + "px"; | |
| 1016 popup.style.top = p_y + "px"; | |
| 1017 } | |
| 1018 | |
| 1019 function lookup_help_popup(popup_id) { | |
| 1020 var _body, pop, info; | |
| 1021 pop = document.getElementById(popup_id); | |
| 1022 if (pop == null) { | |
| 1023 _body = document.getElementsByTagName("body")[0]; | |
| 1024 pop = document.createElement("div"); | |
| 1025 pop.className = "pop_content"; | |
| 1026 pop.id = popup_id; | |
| 1027 pop.style.backgroundColor = "#FFC"; | |
| 1028 pop.style.borderColor = "black"; | |
| 1029 info = document.createElement("p"); | |
| 1030 info.style.fontWeight = "bold"; | |
| 1031 info.appendChild(document.createTextNode("Error: No popup for topic \"" + popup_id + "\".")); | |
| 1032 pop.appendChild(info); | |
| 1033 // this might cause problems with the menu, but as this only happens | |
| 1034 // when something is already wrong I don't think that's too much of a problem | |
| 1035 _body.insertBefore(pop, _body.firstChild); | |
| 1036 } | |
| 1037 if (document.getElementsByTagName('body')[0].hasAttribute("data-autobtns")) { | |
| 1038 if (!/\bauto_buttons\b/.test(pop.className)) { | |
| 1039 pop.className += " auto_buttons"; | |
| 1040 var back_btn_sec = document.createElement("div"); | |
| 1041 back_btn_sec.className = "nested_only pop_back_sec"; | |
| 1042 var back_btn = document.createElement("span"); | |
| 1043 back_btn.className = "pop_back"; | |
| 1044 back_btn.appendChild(document.createTextNode("<< back")); | |
| 1045 back_btn.addEventListener("click", function(e) { | |
| 1046 help_return(); | |
| 1047 }, false); | |
| 1048 back_btn_sec.appendChild(back_btn); | |
| 1049 pop.insertBefore(back_btn_sec, pop.firstChild); | |
| 1050 var close_btn_sec = document.createElement("div"); | |
| 1051 close_btn_sec.className = "pop_close_sec"; | |
| 1052 var close_btn = document.createElement("span"); | |
| 1053 close_btn.className = "pop_close"; | |
| 1054 close_btn.appendChild(document.createTextNode("close")); | |
| 1055 close_btn.addEventListener("click", function(e) { | |
| 1056 help_popup(); | |
| 1057 }, false); | |
| 1058 close_btn_sec.appendChild(close_btn); | |
| 1059 pop.appendChild(close_btn_sec); | |
| 1060 } | |
| 1061 } | |
| 1062 return pop; | |
| 1063 } | |
| 1064 | |
| 1065 /* | |
| 1066 * help_popup | |
| 1067 * | |
| 1068 * Moves around help pop-ups so they appear | |
| 1069 * below an activator. | |
| 1070 */ | |
| 1071 function help_popup(activator, popup_id) { | |
| 1072 "use strict"; | |
| 1073 var pop; | |
| 1074 // set default values | |
| 1075 if (typeof help_popup.popup === "undefined") { | |
| 1076 help_popup.popup = []; | |
| 1077 } | |
| 1078 if (typeof help_popup.activator === "undefined") { | |
| 1079 help_popup.activator = null; | |
| 1080 } | |
| 1081 var last_pop = (help_popup.popup.length > 0 ? help_popup.popup[help_popup.popup.length - 1] : null); | |
| 1082 if (typeof(activator) == "undefined") { // no activator so hide | |
| 1083 if (last_pop != null) { | |
| 1084 last_pop.style.display = 'none'; | |
| 1085 help_popup.popup = []; | |
| 1086 } | |
| 1087 return; | |
| 1088 } | |
| 1089 pop = lookup_help_popup(popup_id); | |
| 1090 if (pop == last_pop) { | |
| 1091 if (activator == help_popup.activator) { | |
| 1092 //hide popup (as we've already shown it for the current help button) | |
| 1093 last_pop.style.display = 'none'; | |
| 1094 help_popup.popup = []; | |
| 1095 return; // toggling complete! | |
| 1096 } | |
| 1097 } else if (last_pop != null) { | |
| 1098 //activating different popup so hide current one | |
| 1099 last_pop.style.display = 'none'; | |
| 1100 } | |
| 1101 help_popup.popup = [pop]; | |
| 1102 help_popup.activator = activator; | |
| 1103 toggle_class(pop, "nested", false); | |
| 1104 //must make the popup visible to measure it or it has zero width | |
| 1105 pop.style.display = 'block'; | |
| 1106 position_popup(activator, pop); | |
| 1107 } | |
| 1108 | |
| 1109 /* | |
| 1110 * help_refine | |
| 1111 * | |
| 1112 * Intended for links within a help popup. Stores a stack of state so | |
| 1113 * you can go back. | |
| 1114 */ | |
| 1115 function help_refine(popup_id) { | |
| 1116 if (help_popup.popup == null || help_popup.popup.length == 0 || help_popup.activator == null) { | |
| 1117 throw new Error("Can not refine a help popup when one is not shown!"); | |
| 1118 } | |
| 1119 var pop = lookup_help_popup(popup_id); | |
| 1120 var last_pop = help_popup.popup[help_popup.popup.length - 1]; | |
| 1121 if (pop == last_pop) return; // slightly odd, but no real cause for alarm | |
| 1122 help_popup.popup.push(pop); | |
| 1123 toggle_class(pop, "nested", true); | |
| 1124 last_pop.style.display = "none"; | |
| 1125 //must make the popup visible to measure it or it has zero width | |
| 1126 pop.style.display = "block"; | |
| 1127 position_popup(help_popup.activator, pop); | |
| 1128 } | |
| 1129 | |
| 1130 /* | |
| 1131 * help_return | |
| 1132 * | |
| 1133 * Intended for links within a help popup. Stores a stack of state so | |
| 1134 * you can go back. | |
| 1135 */ | |
| 1136 function help_return() { | |
| 1137 if (help_popup.popup == null || help_popup.popup.length == 0 || help_popup.activator == null) { | |
| 1138 throw new Error("Can not return to a earlier help popup when one is not shown!"); | |
| 1139 } | |
| 1140 var last_pop = help_popup.popup.pop(); | |
| 1141 last_pop.style.display = "none"; | |
| 1142 var pop = (help_popup.popup.length > 0 ? help_popup.popup[help_popup.popup.length - 1] : null); | |
| 1143 if (pop != null) { | |
| 1144 toggle_class(pop, "nested", help_popup.popup.length > 1); | |
| 1145 pop.style.display = "block"; | |
| 1146 position_popup(help_popup.activator, pop); | |
| 1147 } else { | |
| 1148 help_popup.activator = null; | |
| 1149 } | |
| 1150 } | |
| 1151 | |
| 1152 /* | |
| 1153 * update_scroll_pad | |
| 1154 * | |
| 1155 * Creates padding at the bottom of the page to allow | |
| 1156 * scrolling of anything into view. | |
| 1157 */ | |
| 1158 function update_scroll_pad() { | |
| 1159 var page, pad; | |
| 1160 page = (document.compatMode === "CSS1Compat") ? document.documentElement : document.body; | |
| 1161 pad = $("scrollpad"); | |
| 1162 if (pad === null) { | |
| 1163 pad = document.createElement("div"); | |
| 1164 pad.id = 'scrollpad'; | |
| 1165 document.getElementsByTagName('body')[0].appendChild(pad); | |
| 1166 } | |
| 1167 pad.style.height = Math.abs(page.clientHeight - 100) + "px"; | |
| 1168 } | |
| 1169 | |
| 1170 function substitute_classes(node, remove, add) { | |
| 1171 "use strict"; | |
| 1172 var list, all, i, cls, classes; | |
| 1173 list = node.className.split(/\s+/); | |
| 1174 all = {}; | |
| 1175 for (i = 0; i < list.length; i++) { | |
| 1176 if (list[i].length > 0) all[list[i]] = true; | |
| 1177 } | |
| 1178 for (i = 0; i < remove.length; i++) { | |
| 1179 if (all.hasOwnProperty(remove[i])) { | |
| 1180 delete all[remove[i]]; | |
| 1181 } | |
| 1182 } | |
| 1183 for (i = 0; i < add.length; i++) { | |
| 1184 all[add[i]] = true; | |
| 1185 } | |
| 1186 classes = ""; | |
| 1187 for (cls in all) { | |
| 1188 classes += cls + " "; | |
| 1189 } | |
| 1190 node.className = classes; | |
| 1191 } | |
| 1192 | |
| 1193 /* | |
| 1194 * toggle_class | |
| 1195 * | |
| 1196 * Adds or removes a class from the node. If the parameter 'enabled' is not | |
| 1197 * passed then the existence of the class will be toggled, otherwise it will be | |
| 1198 * included if enabled is true. | |
| 1199 */ | |
| 1200 function toggle_class(node, cls, enabled) { | |
| 1201 var classes = node.className; | |
| 1202 var list = classes.replace(/^\s+/, '').replace(/\s+$/, '').split(/\s+/); | |
| 1203 var found = false; | |
| 1204 for (var i = 0; i < list.length; i++) { | |
| 1205 if (list[i] == cls) { | |
| 1206 list.splice(i, 1); | |
| 1207 i--; | |
| 1208 found = true; | |
| 1209 } | |
| 1210 } | |
| 1211 if (typeof enabled == "undefined") { | |
| 1212 if (!found) list.push(cls); | |
| 1213 } else { | |
| 1214 if (enabled) list.push(cls); | |
| 1215 } | |
| 1216 node.className = list.join(" "); | |
| 1217 } | |
| 1218 | |
| 1219 /* | |
| 1220 * find_child | |
| 1221 * | |
| 1222 * Searches child nodes in depth first order and returns the first it finds | |
| 1223 * with the className specified. | |
| 1224 * TODO replace with querySelector | |
| 1225 */ | |
| 1226 function find_child(node, className) { | |
| 1227 var pattern; | |
| 1228 if (node == null || typeof node !== "object") { | |
| 1229 return null; | |
| 1230 } | |
| 1231 if (typeof className === "string") { | |
| 1232 pattern = new RegExp("\\b" + className + "\\b"); | |
| 1233 } else { | |
| 1234 pattern = className; | |
| 1235 } | |
| 1236 if (node.nodeType == Node.ELEMENT_NODE && | |
| 1237 pattern.test(node.className)) { | |
| 1238 return node; | |
| 1239 } else { | |
| 1240 var result = null; | |
| 1241 for (var i = 0; i < node.childNodes.length; i++) { | |
| 1242 result = find_child(node.childNodes[i], pattern); | |
| 1243 if (result != null) break; | |
| 1244 } | |
| 1245 return result; | |
| 1246 } | |
| 1247 } | |
| 1248 | |
| 1249 /* | |
| 1250 * find_parent | |
| 1251 * | |
| 1252 * Searches parent nodes outwards from the node and returns the first it finds | |
| 1253 * with the className specified. | |
| 1254 */ | |
| 1255 function find_parent(node, className) { | |
| 1256 var pattern; | |
| 1257 pattern = new RegExp("\\b" + className + "\\b"); | |
| 1258 do { | |
| 1259 if (node.nodeType == Node.ELEMENT_NODE && | |
| 1260 pattern.test(node.className)) { | |
| 1261 return node; | |
| 1262 } | |
| 1263 } while (node = node.parentNode); | |
| 1264 return null; | |
| 1265 } | |
| 1266 | |
| 1267 /* | |
| 1268 * find_parent_tag | |
| 1269 * | |
| 1270 * Searches parent nodes outwards from the node and returns the first it finds | |
| 1271 * with the tag name specified. HTML tags should be specified in upper case. | |
| 1272 */ | |
| 1273 function find_parent_tag(node, tag_name) { | |
| 1274 do { | |
| 1275 if (node.nodeType == Node.ELEMENT_NODE && node.tagName == tag_name) { | |
| 1276 return node; | |
| 1277 } | |
| 1278 } while (node = node.parentNode); | |
| 1279 return null; | |
| 1280 } | |
| 1281 | |
| 1282 /* | |
| 1283 * __toggle_help | |
| 1284 * | |
| 1285 * Uses the 'topic' property of the this object to | |
| 1286 * toggle display of a help topic. | |
| 1287 * | |
| 1288 * This function is not intended to be called directly. | |
| 1289 */ | |
| 1290 function __toggle_help(e) { | |
| 1291 if (!e) e = window.event; | |
| 1292 if (e.type === "keydown") { | |
| 1293 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
| 1294 return; | |
| 1295 } | |
| 1296 // stop a submit or something like that | |
| 1297 e.preventDefault(); | |
| 1298 } | |
| 1299 | |
| 1300 help_popup(this, this.getAttribute("data-topic")); | |
| 1301 } | |
| 1302 | |
| 1303 function setup_help_button(button) { | |
| 1304 "use strict"; | |
| 1305 var topic; | |
| 1306 if (button.hasAttribute("data-topic")) { | |
| 1307 topic = button.getAttribute("data-topic"); | |
| 1308 if (document.getElementById(topic) != null) { | |
| 1309 button.tabIndex = "0"; // make keyboard selectable | |
| 1310 button.addEventListener("click", function() { | |
| 1311 help_popup(button, topic); | |
| 1312 }, false); | |
| 1313 button.addEventListener("keydown", function(e) { | |
| 1314 // toggle only on Enter or Spacebar, let other keys do their thing | |
| 1315 if (e.keyCode !== 13 && e.keyCode !== 32) return; | |
| 1316 // stop a submit or something like that | |
| 1317 e.preventDefault(); | |
| 1318 help_popup(button, topic); | |
| 1319 }, false); | |
| 1320 } else { | |
| 1321 button.style.visibility = "hidden"; | |
| 1322 } | |
| 1323 } | |
| 1324 button.className += " active"; | |
| 1325 } | |
| 1326 | |
| 1327 /* | |
| 1328 * help_button | |
| 1329 * | |
| 1330 * Makes a help button for the passed topic. | |
| 1331 */ | |
| 1332 function help_button(topic) { | |
| 1333 var btn = document.createElement("div"); | |
| 1334 btn.className = "help"; | |
| 1335 btn.setAttribute("data-topic", topic); | |
| 1336 setup_help_button(btn); | |
| 1337 return btn; | |
| 1338 } | |
| 1339 | |
| 1340 /* | |
| 1341 * prepare_download | |
| 1342 * | |
| 1343 * Sets the attributes of a link to setup a file download using the given content. | |
| 1344 * If no link is provided then create one and click it. | |
| 1345 */ | |
| 1346 function prepare_download(content, mimetype, filename, link) { | |
| 1347 "use strict"; | |
| 1348 // if no link is provided then create one and click it | |
| 1349 var click_link = false; | |
| 1350 if (!link) { | |
| 1351 link = document.createElement("a"); | |
| 1352 click_link = true; | |
| 1353 } | |
| 1354 try { | |
| 1355 // Use a BLOB to convert the text into a data URL. | |
| 1356 // We could do this manually with a base 64 conversion. | |
| 1357 // This will only be supported on modern browsers, | |
| 1358 // hence the try block. | |
| 1359 var blob = new Blob([content], {type: mimetype}); | |
| 1360 var reader = new FileReader(); | |
| 1361 reader.onloadend = function() { | |
| 1362 // If we're lucky the browser will also support the download | |
| 1363 // attribute which will let us suggest a file name to save the link. | |
| 1364 // Otherwise it is likely that the filename will be unintelligible. | |
| 1365 link.setAttribute("download", filename); | |
| 1366 link.href = reader.result; | |
| 1367 if (click_link) { | |
| 1368 // must add the link to click it | |
| 1369 document.body.appendChild(link); | |
| 1370 link.click(); | |
| 1371 document.body.removeChild(link); | |
| 1372 } | |
| 1373 } | |
| 1374 reader.readAsDataURL(blob); | |
| 1375 } catch (error) { | |
| 1376 if (console && console.log) console.log(error); | |
| 1377 // probably an old browser | |
| 1378 link.href = ""; | |
| 1379 link.visible = false; | |
| 1380 } | |
| 1381 } | |
| 1382 | |
| 1383 /* | |
| 1384 * add_cell | |
| 1385 * | |
| 1386 * Add a cell to the table row. | |
| 1387 */ | |
| 1388 function add_cell(row, node, cls, click_action) { | |
| 1389 var cell = row.insertCell(row.cells.length); | |
| 1390 if (node) cell.appendChild(node); | |
| 1391 if (cls && cls !== "") cell.className = cls; | |
| 1392 if (click_action) cell.addEventListener("click", click_action, false); | |
| 1393 } | |
| 1394 | |
| 1395 /* | |
| 1396 * add_header_cell | |
| 1397 * | |
| 1398 * Add a header cell to the table row. | |
| 1399 */ | |
| 1400 function add_header_cell(row, node, help_topic, cls, colspan) { | |
| 1401 var th = document.createElement("th"); | |
| 1402 if (node) th.appendChild(node); | |
| 1403 if (help_topic && help_topic !== "") th.appendChild(help_button(help_topic)); | |
| 1404 if (cls && cls !== "") th.className = cls; | |
| 1405 if (typeof colspan == "number" && colspan > 1) th.colSpan = colspan; | |
| 1406 row.appendChild(th); | |
| 1407 } | |
| 1408 | |
| 1409 /* | |
| 1410 * add_text_cell | |
| 1411 * | |
| 1412 * Add a text cell to the table row. | |
| 1413 */ | |
| 1414 function add_text_cell(row, text, cls, action) { | |
| 1415 var node = null; | |
| 1416 if (typeof(text) != 'undefined') node = document.createTextNode(text); | |
| 1417 add_cell(row, node, cls, action); | |
| 1418 } | |
| 1419 | |
| 1420 /* | |
| 1421 * add_text_header_cell | |
| 1422 * | |
| 1423 * Add a text header cell to the table row. | |
| 1424 */ | |
| 1425 function add_text_header_cell(row, text, help_topic, cls, action, colspan) { | |
| 1426 var node = null; | |
| 1427 if (typeof(text) != 'undefined') { | |
| 1428 var nbsp = (help_topic ? "\u00A0" : ""); | |
| 1429 var str = "" + text; | |
| 1430 var parts = str.split(/\n/); | |
| 1431 if (parts.length === 1) { | |
| 1432 if (action) { | |
| 1433 node = document.createElement("span"); | |
| 1434 node.appendChild(document.createTextNode(str + nbsp)); | |
| 1435 } else { | |
| 1436 node = document.createTextNode(str + nbsp); | |
| 1437 } | |
| 1438 } else { | |
| 1439 node = document.createElement("span"); | |
| 1440 for (var i = 0; i < parts.length; i++) { | |
| 1441 if (i !== 0) { | |
| 1442 node.appendChild(document.createElement("br")); | |
| 1443 } | |
| 1444 node.appendChild(document.createTextNode(parts[i])); | |
| 1445 } | |
| 1446 } | |
| 1447 if (action) { | |
| 1448 node.addEventListener("click", action, false); | |
| 1449 node.style.cursor = "pointer"; | |
| 1450 } | |
| 1451 } | |
| 1452 add_header_cell(row, node, help_topic, cls, colspan); | |
| 1453 } | |
| 1454 | |
| 1455 function setup_help() { | |
| 1456 "use strict"; | |
| 1457 var help_buttons, i; | |
| 1458 help_buttons = document.querySelectorAll(".help:not(.active)"); | |
| 1459 for (i = 0; i < help_buttons.length; i++) { | |
| 1460 setup_help_button(help_buttons[i]); | |
| 1461 } | |
| 1462 } | |
| 1463 | |
| 1464 function setup_scrollpad() { | |
| 1465 "use strict"; | |
| 1466 if (document.getElementsByTagName('body')[0].hasAttribute("data-scrollpad") && document.getElementById("scrollpad") == null) { | |
| 1467 window.addEventListener("resize", update_scroll_pad, false); | |
| 1468 update_scroll_pad(); | |
| 1469 } | |
| 1470 } | |
| 1471 | |
| 1472 // anon function to avoid polluting global scope | |
| 1473 (function() { | |
| 1474 "use strict"; | |
| 1475 window.addEventListener("load", function load(evt) { | |
| 1476 window.removeEventListener("load", load, false); | |
| 1477 setup_help(); | |
| 1478 setup_scrollpad(); | |
| 1479 }, false); | |
| 1480 })(); | |
| 1481 | |
| 1482 /* | |
| 1483 * make_link | |
| 1484 * | |
| 1485 * Creates a text node and if a URL is specified it surrounds it with a link. | |
| 1486 * If the URL doesn't begin with "http://" it automatically adds it, as | |
| 1487 * relative links don't make much sense in this context. | |
| 1488 */ | |
| 1489 function make_link(text, url) { | |
| 1490 var textNode = null; | |
| 1491 var link = null; | |
| 1492 if (typeof text !== "undefined" && text !== null) textNode = document.createTextNode(text); | |
| 1493 if (typeof url === "string") { | |
| 1494 if (url.indexOf("//") == -1) { | |
| 1495 url = "http://" + url; | |
| 1496 } | |
| 1497 link = document.createElement('a'); | |
| 1498 link.href = url; | |
| 1499 if (textNode) link.appendChild(textNode); | |
| 1500 return link; | |
| 1501 } | |
| 1502 return textNode; | |
| 1503 } | |
| 1504 </script> | |
| 1505 <script> | |
| 1506 // | |
| 1507 // return true if any part of the passed element is visible in the viewport | |
| 1508 // | |
| 1509 function element_in_viewport(elem) { | |
| 1510 var rect; | |
| 1511 try { | |
| 1512 rect = elem.getBoundingClientRect(); | |
| 1513 } catch (e) { | |
| 1514 return false; | |
| 1515 } | |
| 1516 return ( | |
| 1517 rect.top < (window.innerHeight || document.body.clientHeight) && | |
| 1518 rect.bottom > 0 && | |
| 1519 rect.left < (window.innerWidth || document.body.clientWidth) && | |
| 1520 rect.right > 0 | |
| 1521 ); | |
| 1522 } | |
| 1523 | |
| 1524 // | |
| 1525 // Functions to delay a drawing task until it is required or it would not lag the display to do so | |
| 1526 // | |
| 1527 | |
| 1528 // a list of items still to be drawn | |
| 1529 var drawable_list = []; | |
| 1530 // the delay between drawing objects that are not currently visible | |
| 1531 var draw_delay = 1; | |
| 1532 // the delay after a user interaction | |
| 1533 var user_delay = 300; | |
| 1534 // the delay after a user has stopped scrolling and is viewing the stuff drawn on the current page | |
| 1535 var stop_delay = 300; | |
| 1536 // the timer handle; allows resetting of the timer after user interactions | |
| 1537 var draw_timer = null; | |
| 1538 | |
| 1539 // | |
| 1540 // Drawable | |
| 1541 // | |
| 1542 // elem - a page element which defines the position on the page that drawing is to be done | |
| 1543 // task - an object with the method run which takes care of painting the object | |
| 1544 // | |
| 1545 var Drawable = function(elem, task) { | |
| 1546 this.elem = elem; | |
| 1547 this.task = task; | |
| 1548 } | |
| 1549 | |
| 1550 // | |
| 1551 // Drawable.is_visible | |
| 1552 // | |
| 1553 // Determines if the element is visible in the viewport | |
| 1554 // | |
| 1555 Drawable.prototype.is_visible = function() { | |
| 1556 return element_in_viewport(this.elem); | |
| 1557 } | |
| 1558 | |
| 1559 // | |
| 1560 // Drawable.run | |
| 1561 // | |
| 1562 // Run the task held by the drawable | |
| 1563 Drawable.prototype.run = function() { | |
| 1564 if (this.task) this.task.run(); | |
| 1565 this.task = null; | |
| 1566 } | |
| 1567 | |
| 1568 // | |
| 1569 // Drawable.run | |
| 1570 // | |
| 1571 // Run the task iff visible | |
| 1572 // returns true if the task ran or has already run | |
| 1573 Drawable.prototype.run_visible = function() { | |
| 1574 if (this.task) { | |
| 1575 if (element_in_viewport(this.elem)) { | |
| 1576 this.task.run(); | |
| 1577 this.task = null; | |
| 1578 return true; | |
| 1579 } | |
| 1580 return false; | |
| 1581 } else { | |
| 1582 return true; | |
| 1583 } | |
| 1584 } | |
| 1585 | |
| 1586 // | |
| 1587 // draw_on_screen | |
| 1588 // | |
| 1589 // Checks each drawable object and draws those on screen. | |
| 1590 // | |
| 1591 function draw_on_screen() { | |
| 1592 var found = false; | |
| 1593 for (var i = 0; i < drawable_list.length; i++) { | |
| 1594 if (drawable_list[i].run_visible()) { | |
| 1595 drawable_list.splice(i--, 1); | |
| 1596 found = true; | |
| 1597 } | |
| 1598 } | |
| 1599 return found; | |
| 1600 } | |
| 1601 | |
| 1602 // | |
| 1603 // process_draw_tasks | |
| 1604 // | |
| 1605 // Called on a delay to process the next avaliable | |
| 1606 // draw task. | |
| 1607 // | |
| 1608 function process_draw_tasks() { | |
| 1609 var delay = draw_delay; | |
| 1610 draw_timer = null; | |
| 1611 if (drawable_list.length == 0) return; //no more tasks | |
| 1612 if (draw_on_screen()) { | |
| 1613 delay = stop_delay; //give the user a chance to scroll | |
| 1614 } else { | |
| 1615 //get next task | |
| 1616 var drawable = drawable_list.shift(); | |
| 1617 drawable.task.run(); | |
| 1618 } | |
| 1619 //allow UI updates between tasks | |
| 1620 draw_timer = window.setTimeout("process_draw_tasks()", delay); | |
| 1621 } | |
| 1622 | |
| 1623 // | |
| 1624 // delayed_process_draw_tasks | |
| 1625 // | |
| 1626 // Call process_draw_tasks after a short delay. | |
| 1627 // The delay serves to group multiple redundant events. | |
| 1628 // Should be set as event handler for onscroll and onresize. | |
| 1629 // | |
| 1630 function delayed_process_draw_tasks() { | |
| 1631 //reset the timer | |
| 1632 if (drawable_list.length > 0) { | |
| 1633 if (draw_timer != null) clearTimeout(draw_timer); | |
| 1634 draw_timer = window.setTimeout("process_draw_tasks()", user_delay); | |
| 1635 } | |
| 1636 } | |
| 1637 | |
| 1638 // | |
| 1639 // add_draw_task | |
| 1640 // | |
| 1641 // Add a drawing task to be called immediately if it is | |
| 1642 // visible, or to be called on a delay to reduce stuttering | |
| 1643 // effect on the web browser. | |
| 1644 function add_draw_task(elem, task) { | |
| 1645 drawable = new Drawable(elem, task); | |
| 1646 if (drawable.is_visible()) { | |
| 1647 task.run(); | |
| 1648 } else { | |
| 1649 drawable_list.push(drawable); | |
| 1650 //reset timer | |
| 1651 if (draw_timer != null) clearTimeout(draw_timer); | |
| 1652 draw_timer = window.setTimeout("process_draw_tasks()", user_delay); | |
| 1653 } | |
| 1654 } | |
| 1655 | |
| 1656 </script> | |
| 1657 <script> | |
| 1658 //====================================================================== | |
| 1659 // start Alphabet object | |
| 1660 //====================================================================== | |
| 1661 var Alphabet = function(alphabet, background) { | |
| 1662 "use strict"; | |
| 1663 var i, j, sym, aliases, complement, comp_e_sym, ambigs, generate_background; | |
| 1664 generate_background = (background == null); | |
| 1665 if (generate_background) { | |
| 1666 background = []; | |
| 1667 for (i = 0; i < alphabet.ncore; i++) background[i] = 1.0 / alphabet.ncore; | |
| 1668 } else if (alphabet.ncore != background.length) { | |
| 1669 throw new Error("The background length does not match the alphabet length."); | |
| 1670 } | |
| 1671 this.name = alphabet.name; | |
| 1672 this.like = (alphabet.like != null ? alphabet.like.toUpperCase() : null); | |
| 1673 this.ncore = alphabet.ncore; | |
| 1674 this.symbols = alphabet.symbols; | |
| 1675 this.background = background; | |
| 1676 this.genbg = generate_background; | |
| 1677 this.encode = {}; | |
| 1678 this.encode2core = {}; | |
| 1679 this.complement = {}; | |
| 1680 // check if all symbols are same case | |
| 1681 var seen_uc = false; | |
| 1682 var seen_lc = false; | |
| 1683 var check_case = function (syms) { | |
| 1684 var s, sym; | |
| 1685 if (typeof syms === "string") { | |
| 1686 for (s = 0; s < syms.length; s++) { | |
| 1687 sym = syms.charAt(s); | |
| 1688 if (sym >= 'a' && sym <= 'z') seen_lc = true; | |
| 1689 else if (sym >= 'A' && sym <= 'Z') seen_uc = true; | |
| 1690 } | |
| 1691 } | |
| 1692 }; | |
| 1693 for (i = 0; i < this.symbols.length; i++) { | |
| 1694 check_case(this.symbols[i].symbol); | |
| 1695 check_case(this.symbols[i].aliases); | |
| 1696 } | |
| 1697 // now map symbols to indexes | |
| 1698 var update_array = function(array, syms, index) { | |
| 1699 var s, sym; | |
| 1700 if (typeof syms === "string") { | |
| 1701 for (s = 0; s < syms.length; s++) { | |
| 1702 sym = syms.charAt(s); | |
| 1703 array[sym] = index; | |
| 1704 // when only a single case is used, then encode as case insensitive | |
| 1705 if (seen_uc != seen_lc) { | |
| 1706 if (sym >= 'a' && sym <= 'z') { | |
| 1707 array[sym.toUpperCase()] = index; | |
| 1708 } else if (sym >= 'A' && sym <= 'Z') { | |
| 1709 array[sym.toLowerCase()] = index; | |
| 1710 } | |
| 1711 } | |
| 1712 } | |
| 1713 } | |
| 1714 } | |
| 1715 // map core symbols to index | |
| 1716 for (i = 0; i < this.ncore; i++) { | |
| 1717 update_array(this.encode2core, this.symbols[i].symbol, i); | |
| 1718 update_array(this.encode, this.symbols[i].symbol, i); | |
| 1719 update_array(this.encode2core, this.symbols[i].aliases, i); | |
| 1720 update_array(this.encode, this.symbols[i].aliases, i); | |
| 1721 } | |
| 1722 // map ambigous symbols to index | |
| 1723 ambigs = {}; | |
| 1724 for (i = this.ncore; i < this.symbols.length; i++) { | |
| 1725 update_array(this.encode, this.symbols[i].symbol, i); | |
| 1726 update_array(this.encode, this.symbols[i].aliases, i); | |
| 1727 ambigs[this.symbols[i].equals] = i; | |
| 1728 } | |
| 1729 // determine complements | |
| 1730 for (i = 0; i < this.ncore; i++) { | |
| 1731 complement = this.symbols[i].complement; | |
| 1732 if (typeof complement === "string") { | |
| 1733 this.complement[i] = this.encode2core[complement]; | |
| 1734 } | |
| 1735 } | |
| 1736 next_symbol: | |
| 1737 for (i = this.ncore; i < this.symbols.length; i++) { | |
| 1738 complement = ""; | |
| 1739 for (j = 0; j < this.symbols[i].equals.length; j++) { | |
| 1740 comp_e_sym = this.complement[this.encode2core[this.symbols[i].equals.charAt(j)]]; | |
| 1741 if (typeof comp_e_sym !== "number") continue next_symbol; | |
| 1742 complement += this.symbols[comp_e_sym].symbol; | |
| 1743 } | |
| 1744 complement = complement.split("").sort().join(""); | |
| 1745 if (typeof ambigs[complement] === "number") { | |
| 1746 this.complement[i] = ambigs[complement]; | |
| 1747 } | |
| 1748 } | |
| 1749 // determine case insensitivity | |
| 1750 this.case_insensitive = true; | |
| 1751 if (seen_uc == seen_lc) { | |
| 1752 // when there is a mixture of cases it probably won't | |
| 1753 // be case insensitive but we still need to check | |
| 1754 loop: | |
| 1755 for (i = 0; i < this.symbols.length; i++) { | |
| 1756 sym = this.symbols[i].symbol; | |
| 1757 if (sym >= 'A' && sym <= 'Z') { | |
| 1758 if (this.encode[sym.toLowerCase()] != i) { | |
| 1759 this.case_insensitive = false; | |
| 1760 break loop; | |
| 1761 } | |
| 1762 } else if (sym >= 'a' && sym <= 'z') { | |
| 1763 if (this.encode[sym.toUpperCase()] != i) { | |
| 1764 this.case_insensitive = false; | |
| 1765 break loop; | |
| 1766 } | |
| 1767 } | |
| 1768 aliases = this.symbols[i].aliases; | |
| 1769 if (aliases != null) { | |
| 1770 for (j = 0; j < aliases.length; j++) { | |
| 1771 sym = aliases.charAt(j); | |
| 1772 if (sym >= 'A' && sym <= 'Z') { | |
| 1773 if (this.encode[sym.toLowerCase()] != i) { | |
| 1774 this.case_insensitive = false; | |
| 1775 break loop; | |
| 1776 } | |
| 1777 } else if (sym >= 'a' && sym <= 'z') { | |
| 1778 if (this.encode[sym.toUpperCase()] != i) { | |
| 1779 this.case_insensitive = false; | |
| 1780 break loop; | |
| 1781 } | |
| 1782 } | |
| 1783 } | |
| 1784 } | |
| 1785 } | |
| 1786 } | |
| 1787 // normalise aliases to remove the prime symbol and eliminate | |
| 1788 // the alternate cases when the alphabet is case insensitive | |
| 1789 var seen, out; | |
| 1790 for (i = 0; i < this.symbols.length; i++) { | |
| 1791 sym = this.symbols[i].symbol; | |
| 1792 aliases = this.symbols[i].aliases; | |
| 1793 if (typeof aliases != "string") aliases = ""; | |
| 1794 seen = {}; | |
| 1795 out = []; | |
| 1796 if (this.case_insensitive) { | |
| 1797 sym = sym.toUpperCase(); | |
| 1798 aliases = aliases.toUpperCase(); | |
| 1799 } | |
| 1800 seen[sym] = true; | |
| 1801 for (j = 0; j < aliases.length; j++) { | |
| 1802 if (!seen[aliases.charAt(j)]) { | |
| 1803 seen[aliases.charAt(j)] = true; | |
| 1804 out.push(aliases.charAt(j)); | |
| 1805 } | |
| 1806 } | |
| 1807 this.symbols[i].aliases = out.sort().join(""); | |
| 1808 } | |
| 1809 }; | |
| 1810 // return the name of the alphabet | |
| 1811 Alphabet.prototype.get_alphabet_name = function() { | |
| 1812 return this.name; | |
| 1813 }; | |
| 1814 // return if the alphabet can be complemented | |
| 1815 Alphabet.prototype.has_complement = function() { | |
| 1816 return (typeof this.symbols[0].complement === "string"); | |
| 1817 }; | |
| 1818 // return true if an uppercase letter has the same meaning as the lowercase form | |
| 1819 Alphabet.prototype.is_case_insensitive = function() { | |
| 1820 return this.case_insensitive; | |
| 1821 }; | |
| 1822 // return the information content of an alphabet letter | |
| 1823 Alphabet.prototype.get_ic = function() { | |
| 1824 return Math.log(this.ncore) / Math.LN2; | |
| 1825 }; | |
| 1826 // return the count of the core alphabet symbols | |
| 1827 Alphabet.prototype.get_size_core = function() { | |
| 1828 return this.ncore; | |
| 1829 }; | |
| 1830 // return the count of all alphabet symbols | |
| 1831 Alphabet.prototype.get_size_full = function() { | |
| 1832 return this.symbols.length; | |
| 1833 }; | |
| 1834 // return the symbol for the given alphabet index | |
| 1835 Alphabet.prototype.get_symbol = function(alph_index) { | |
| 1836 "use strict"; | |
| 1837 if (alph_index < 0 || alph_index >= this.symbols.length) { | |
| 1838 throw new Error("Alphabet index out of bounds"); | |
| 1839 } | |
| 1840 return this.symbols[alph_index].symbol; | |
| 1841 }; | |
| 1842 // return the aliases for the given alphabet index | |
| 1843 Alphabet.prototype.get_aliases = function(alph_index) { | |
| 1844 "use strict"; | |
| 1845 if (alph_index < 0 || alph_index >= this.symbols.length) { | |
| 1846 throw new Error("Alphabet index out of bounds"); | |
| 1847 } | |
| 1848 var sym_obj = this.symbols[alph_index]; | |
| 1849 return (sym_obj.aliases != null ? sym_obj.aliases : ""); | |
| 1850 }; | |
| 1851 // return the name for the given alphabet index | |
| 1852 Alphabet.prototype.get_name = function(alph_index) { | |
| 1853 "use strict"; | |
| 1854 var sym; | |
| 1855 if (alph_index < 0 || alph_index >= this.symbols.length) { | |
| 1856 throw new Error("Alphabet index out of bounds"); | |
| 1857 } | |
| 1858 sym = this.symbols[alph_index]; | |
| 1859 return (typeof sym.name === "string" ? sym.name : sym.symbol); | |
| 1860 }; | |
| 1861 // return the alphabet it is like or null | |
| 1862 Alphabet.prototype.get_like = function() { | |
| 1863 "use strict"; | |
| 1864 return this.like; | |
| 1865 }; | |
| 1866 // return the index of the complement for the given alphabet index | |
| 1867 Alphabet.prototype.get_complement = function(alph_index) { | |
| 1868 var comp_e_sym = this.complement[alph_index]; | |
| 1869 if (typeof comp_e_sym === "number") { | |
| 1870 return comp_e_sym; | |
| 1871 } else { | |
| 1872 return -1; | |
| 1873 } | |
| 1874 }; | |
| 1875 // return a string containing the core symbols | |
| 1876 Alphabet.prototype.get_symbols = function() { | |
| 1877 "use strict"; | |
| 1878 var i, core_symbols; | |
| 1879 core_symbols = ""; | |
| 1880 for (i = 0; i < this.ncore; i++) { | |
| 1881 core_symbols += this.symbols[i].symbol; | |
| 1882 } | |
| 1883 return core_symbols; | |
| 1884 }; | |
| 1885 // return if the background was not a uniform generated background | |
| 1886 Alphabet.prototype.has_bg = function() { | |
| 1887 "use strict"; | |
| 1888 return !this.genbg; | |
| 1889 }; | |
| 1890 // get the background frequency for the index | |
| 1891 Alphabet.prototype.get_bg_freq = function(alph_index) { | |
| 1892 "use strict"; | |
| 1893 var freq, i, symbols; | |
| 1894 if (alph_index >= 0) { | |
| 1895 if (alph_index < this.ncore) { | |
| 1896 return this.background[alph_index]; | |
| 1897 } else if (alph_index < this.symbols.length) { | |
| 1898 freq = 0; | |
| 1899 symbols = this.symbols[alph_index].equals; | |
| 1900 for (i = 0; i < symbols.length; i++) { | |
| 1901 freq += this.background[this.encode2core[symbols.charAt(i)]]; | |
| 1902 } | |
| 1903 return freq; | |
| 1904 } | |
| 1905 } | |
| 1906 throw new Error("The alphabet index is out of range."); | |
| 1907 }; | |
| 1908 // get the colour of the index | |
| 1909 Alphabet.prototype.get_colour = function(alph_index) { | |
| 1910 "use strict"; | |
| 1911 if (alph_index < 0 || alph_index >= this.symbols.length) { | |
| 1912 throw new Error("BAD_ALPHABET_INDEX"); | |
| 1913 } | |
| 1914 if (typeof this.symbols[alph_index].colour != "string") { | |
| 1915 return "black"; | |
| 1916 } | |
| 1917 return "#" + this.symbols[alph_index].colour; | |
| 1918 }; | |
| 1919 // get the rgb componets of the colour at the index | |
| 1920 Alphabet.prototype.get_rgb = function(alph_index) { | |
| 1921 "use strict"; | |
| 1922 if (alph_index < 0 || alph_index >= this.symbols.length) { | |
| 1923 throw new Error("BAD_ALPHABET_INDEX"); | |
| 1924 } | |
| 1925 if (typeof this.symbols[alph_index].colour != "string") { | |
| 1926 return {"red": 0, "green": 0, "blue": 0}; | |
| 1927 } | |
| 1928 var colour = this.symbols[alph_index].colour; | |
| 1929 var red = parseInt(colour.substr(0, 2), 16) / 255; | |
| 1930 var green = parseInt(colour.substr(2, 2), 16) / 255; | |
| 1931 var blue = parseInt(colour.substr(4, 2), 16) / 255; | |
| 1932 return {"red": red, "green": green, "blue": blue}; | |
| 1933 }; | |
| 1934 // convert a symbol into the index | |
| 1935 Alphabet.prototype.get_index = function(letter) { | |
| 1936 "use strict"; | |
| 1937 var alph_index; | |
| 1938 alph_index = this.encode[letter]; | |
| 1939 if (typeof alph_index === "undefined") { | |
| 1940 return -1; | |
| 1941 } | |
| 1942 return alph_index; | |
| 1943 }; | |
| 1944 // convert a symbol into the list of core indexes that it equals | |
| 1945 Alphabet.prototype.get_indexes = function(letter) { | |
| 1946 "use strict"; | |
| 1947 var alph_index, comprise_str, i, comprise_list; | |
| 1948 alph_index = this.encode[letter]; | |
| 1949 if (typeof alph_index === "undefined") { | |
| 1950 throw new Error("Unknown letter"); | |
| 1951 } | |
| 1952 comprise_str = this.symbols[alph_index].equals; | |
| 1953 comprise_list = []; | |
| 1954 if (typeof comprise_str == "string") { | |
| 1955 for (i = 0; i < comprise_str.length; i++) { | |
| 1956 comprise_list.push(this.encode2core[comprise_str.charAt(i)]); | |
| 1957 } | |
| 1958 } else { | |
| 1959 comprise_list.push(alph_index); | |
| 1960 } | |
| 1961 return comprise_list; | |
| 1962 }; | |
| 1963 // check if a symbol is the primary way of representing the symbol in the alphabet | |
| 1964 Alphabet.prototype.is_prime_symbol = function(letter) { | |
| 1965 var alph_index; | |
| 1966 alph_index = this.encode[letter]; | |
| 1967 if (alph_index == null) return false; | |
| 1968 if (this.is_case_insensitive()) { | |
| 1969 return (this.symbols[alph_index].symbol.toUpperCase() == letter.toUpperCase()); | |
| 1970 } else { | |
| 1971 return (this.symbols[alph_index].symbol == letter); | |
| 1972 } | |
| 1973 }; | |
| 1974 // compare 2 alphabets | |
| 1975 Alphabet.prototype.equals = function(other) { | |
| 1976 "use strict"; | |
| 1977 var i, sym1, sym2; | |
| 1978 // first check that it's actually an alphabet object | |
| 1979 if (!(typeof other === "object" && other != null && other instanceof Alphabet)) { | |
| 1980 return false; | |
| 1981 } | |
| 1982 // second shortcircuit if it's the same object | |
| 1983 if (this === other) return true; | |
| 1984 // compare | |
| 1985 if (this.name !== other.name) return false; | |
| 1986 if (this.ncore !== other.ncore) return false; | |
| 1987 if (this.symbols.length !== other.symbols.length) return false; | |
| 1988 for (i = 0; i < this.symbols.length; i++) { | |
| 1989 sym1 = this.symbols[i]; | |
| 1990 sym2 = other.symbols[i]; | |
| 1991 if (sym1.symbol !== sym2.symbol) return false; | |
| 1992 if (sym1.aliases !== sym2.aliases) return false; | |
| 1993 if (sym1.name !== sym2.name) return false; | |
| 1994 if (typeof sym1.colour !== typeof sym2.colour || | |
| 1995 (typeof sym1.colour === "string" && typeof sym2.colour === "string" && | |
| 1996 parseInt(sym1.colour, 16) != parseInt(sym2.colour, 16))) { | |
| 1997 return false; | |
| 1998 } | |
| 1999 if (sym1.complement !== sym2.complement) return false; | |
| 2000 if (sym1.equals !== sym2.equals) return false; | |
| 2001 } | |
| 2002 return true; | |
| 2003 }; | |
| 2004 Alphabet.prototype.check_core_subset = function(super_alph) { | |
| 2005 var complement_same = true; | |
| 2006 var seen_set = {}; | |
| 2007 var sub_i, sub_symbol, super_i, super_symbol; | |
| 2008 for (sub_i = 0; sub_i < this.ncore; sub_i++) { | |
| 2009 sub_symbol = this.symbols[sub_i]; | |
| 2010 super_i = super_alph.encode[sub_symbol.symbol]; | |
| 2011 if (super_i == null) return 0; | |
| 2012 super_symbol = super_alph.symbols[super_i]; | |
| 2013 if (seen_set[super_i]) return 0; | |
| 2014 seen_set[super_i] = true; | |
| 2015 // check complement | |
| 2016 if (sub_symbol.complement != null && super_symbol.complement != null) { | |
| 2017 if (super_alph.encode[sub_symbol.complement] != super_alph.encode[super_symbol.complement]) { | |
| 2018 complement_same = false; | |
| 2019 } | |
| 2020 } else if (sub_symbol.complement != null || super_symbol.complement != null) { | |
| 2021 complement_same = false; | |
| 2022 } | |
| 2023 } | |
| 2024 return (complement_same ? 1 : -1); | |
| 2025 }; | |
| 2026 // convert a sequence to its reverse complement | |
| 2027 Alphabet.prototype.invcomp_seq = function(seq) { | |
| 2028 "use strict"; | |
| 2029 var syms, i, e_sym, comp_e_sym; | |
| 2030 if (!this.has_complement()) throw new Error("Alphabet must be complementable"); | |
| 2031 syms = seq.split(""); | |
| 2032 for (i = 0; i < syms.length; i++) { | |
| 2033 e_sym = this.encode[syms[i]]; | |
| 2034 if (typeof e_sym === "undefined") { | |
| 2035 e_sym = this.ncore; // wildcard | |
| 2036 } | |
| 2037 comp_e_sym = this.complement[e_sym]; | |
| 2038 if (typeof comp_e_sym === "undefined") { | |
| 2039 comp_e_sym = e_sym; // not complementable | |
| 2040 } | |
| 2041 syms[i] = this.symbols[comp_e_sym].symbol; | |
| 2042 } | |
| 2043 return syms.reverse().join(""); | |
| 2044 }; | |
| 2045 // convert the alphabet to the text version | |
| 2046 Alphabet.prototype.as_text = function() { | |
| 2047 "use strict"; | |
| 2048 function name_as_text(name) { | |
| 2049 var i, c, out; | |
| 2050 out = "\""; | |
| 2051 for (i = 0; i < name.length; i++) { | |
| 2052 c = name.charAt(i); | |
| 2053 if (c == "\"") { | |
| 2054 out += "\\\""; | |
| 2055 } else if (c == "/") { | |
| 2056 out += "\\/"; | |
| 2057 } else if (c == "\\") { | |
| 2058 out += "\\\\"; | |
| 2059 } else { | |
| 2060 out += c; | |
| 2061 } | |
| 2062 } | |
| 2063 out += "\""; | |
| 2064 return out; | |
| 2065 } | |
| 2066 function symbol_as_text(sym) { | |
| 2067 var out; | |
| 2068 out = sym.symbol; | |
| 2069 if (typeof sym.name === "string" && sym.name != sym.symbol) { | |
| 2070 out += " " + name_as_text(sym.name); | |
| 2071 } | |
| 2072 if (typeof sym.colour === "string") { | |
| 2073 out += " " + sym.colour; | |
| 2074 } | |
| 2075 return out; | |
| 2076 } | |
| 2077 var out, i, j, c, sym; | |
| 2078 out = ""; | |
| 2079 // output core symbols with 2 way complements | |
| 2080 for (i = 0; i < this.ncore; i++) { | |
| 2081 c = this.complement[i]; | |
| 2082 if (typeof c === "number" && i < c && this.complement[c] === i) { | |
| 2083 out += symbol_as_text(this.symbols[i]) + " ~ " + symbol_as_text(this.symbols[c]) + "\n"; | |
| 2084 } | |
| 2085 } | |
| 2086 // output core symbols with no complement | |
| 2087 for (i = 0; i < this.ncore; i++) { | |
| 2088 if (typeof this.complement[i] === "undefined") { | |
| 2089 out += symbol_as_text(this.symbols[i]) + "\n"; | |
| 2090 } | |
| 2091 } | |
| 2092 // output ambiguous symbols that have comprising characters | |
| 2093 for (i = this.ncore; i < this.symbols.length; i++) { | |
| 2094 if (this.symbols[i].equals.length == 0) break; | |
| 2095 out += symbol_as_text(this.symbols[i]) + " = " + this.symbols[i].equals + "\n"; | |
| 2096 if (typeof this.symbols[i].aliases === "string") { | |
| 2097 for (j = 0; j < this.symbols[i].aliases.length; j++) { | |
| 2098 if (this.symbols[i].aliases.charAt(j) == this.symbols[i].symbol) continue; | |
| 2099 out += this.symbols[i].aliases.charAt(j) + " = " + this.symbols[i].equals + "\n"; | |
| 2100 } | |
| 2101 } | |
| 2102 } | |
| 2103 // output aliases of core symbols | |
| 2104 for (i = 0; i < this.ncore; i++) { | |
| 2105 if (typeof this.symbols[i].aliases === "string") { | |
| 2106 for (j = 0; j < this.symbols[i].aliases.length; j++) { | |
| 2107 if (this.symbols[i].aliases.charAt(j) == this.symbols[i].symbol) continue; | |
| 2108 out += this.symbols[i].aliases.charAt(j) + " = " + this.symbols[i].symbol + "\n"; | |
| 2109 } | |
| 2110 } | |
| 2111 } | |
| 2112 // output gap symbols | |
| 2113 i = this.symbols.length - 1; | |
| 2114 if (this.symbols[i].equals.length == 0) { | |
| 2115 out += symbol_as_text(this.symbols[i]) + " =\n"; | |
| 2116 if (typeof this.symbols[i].aliases === "string") { | |
| 2117 for (j = 0; j < this.symbols[i].aliases.length; j++) { | |
| 2118 if (this.symbols[i].aliases.charAt(j) == this.symbols[i].symbol) continue; | |
| 2119 out += this.symbols[i].aliases.charAt(j) + " =\n"; | |
| 2120 } | |
| 2121 } | |
| 2122 } | |
| 2123 return out; | |
| 2124 }; | |
| 2125 // output the alphabet as it appears in minimal MEME format | |
| 2126 Alphabet.prototype.as_meme = function() { | |
| 2127 "use strict"; | |
| 2128 function name_as_text(name) { | |
| 2129 var i, c, out; | |
| 2130 out = "\""; | |
| 2131 for (i = 0; i < name.length; i++) { | |
| 2132 c = name.charAt(i); | |
| 2133 if (c == "\"") { | |
| 2134 out += "\\\""; | |
| 2135 } else if (c == "/") { | |
| 2136 out += "\\/"; | |
| 2137 } else if (c == "\\") { | |
| 2138 out += "\\\\"; | |
| 2139 } else { | |
| 2140 out += c; | |
| 2141 } | |
| 2142 } | |
| 2143 out += "\""; | |
| 2144 return out; | |
| 2145 } | |
| 2146 if (this.equals(AlphStd.DNA)) { | |
| 2147 return "ALPHABET= ACGT\n"; | |
| 2148 } else if (this.equals(AlphStd.PROTEIN)) { | |
| 2149 return "ALPHABET= ACDEFGHIKLMNPQRSTVWY\n"; | |
| 2150 } else { | |
| 2151 return "ALPHABET" + | |
| 2152 (this.name != null ? " " + name_as_text(this.name) : "") + | |
| 2153 (this.like != null ? " " + this.like + "-LIKE" : "") + "\n" + | |
| 2154 this.as_text() + "END ALPHABET\n"; | |
| 2155 } | |
| 2156 }; | |
| 2157 | |
| 2158 // Returns a table showing all the letters in the alphabet | |
| 2159 Alphabet.prototype.as_table = function() { | |
| 2160 "use strict"; | |
| 2161 var i, j, row, th, td, aliases, equals, sym; | |
| 2162 var table = document.createElement("table"); | |
| 2163 // create the core symbol header | |
| 2164 row = table.insertRow(table.rows.length); | |
| 2165 th = document.createElement("th"); | |
| 2166 th.appendChild(document.createTextNode("Symbol(s)")); | |
| 2167 row.appendChild(th); | |
| 2168 th = document.createElement("th"); | |
| 2169 th.appendChild(document.createTextNode("Name")); | |
| 2170 row.appendChild(th); | |
| 2171 th = document.createElement("th"); | |
| 2172 if (this.has_complement()) { | |
| 2173 th.appendChild(document.createTextNode("Complement")); | |
| 2174 } | |
| 2175 row.appendChild(th); | |
| 2176 // list the core symbols | |
| 2177 for (i = 0; i < this.ncore; i++) { | |
| 2178 row = table.insertRow(table.rows.length); | |
| 2179 td = document.createElement("td"); | |
| 2180 if (this.symbols[i].colour != null) { | |
| 2181 td.style.color = '#' + this.symbols[i].colour; | |
| 2182 } | |
| 2183 td.appendChild(document.createTextNode(this.symbols[i].symbol)); | |
| 2184 aliases = this.get_aliases(i); | |
| 2185 if (aliases.length > 0) { | |
| 2186 td.appendChild(document.createTextNode(' ' + aliases.split('').join(' '))); | |
| 2187 } | |
| 2188 row.appendChild(td); | |
| 2189 td = document.createElement("td"); | |
| 2190 if (this.symbols[i].name != null) { | |
| 2191 td.appendChild(document.createTextNode(this.symbols[i].name)); | |
| 2192 } | |
| 2193 row.appendChild(td); | |
| 2194 td = document.createElement("td"); | |
| 2195 if (this.symbols[i].complement != null) { | |
| 2196 td.style.color = this.get_colour(this.get_index(this.symbols[i].complement)); | |
| 2197 td.appendChild(document.createTextNode(this.symbols[i].complement)); | |
| 2198 } | |
| 2199 row.appendChild(td); | |
| 2200 } | |
| 2201 // create the ambiguous symbol header | |
| 2202 row = table.insertRow(table.rows.length); | |
| 2203 th = document.createElement("th"); | |
| 2204 th.appendChild(document.createTextNode("Symbol(s)")); | |
| 2205 row.appendChild(th); | |
| 2206 th = document.createElement("th"); | |
| 2207 th.appendChild(document.createTextNode("Name")); | |
| 2208 row.appendChild(th); | |
| 2209 th = document.createElement("th"); | |
| 2210 th.appendChild(document.createTextNode("Matches")); | |
| 2211 row.appendChild(th); | |
| 2212 // list the ambiguous symbols | |
| 2213 for (i = this.ncore; i < this.symbols.length; i++) { | |
| 2214 row = table.insertRow(table.rows.length); | |
| 2215 td = document.createElement("td"); | |
| 2216 if (this.symbols[i].colour != null) { | |
| 2217 td.style.color = '#' + this.symbols[i].colour; | |
| 2218 } | |
| 2219 td.appendChild(document.createTextNode(this.symbols[i].symbol)); | |
| 2220 aliases = this.get_aliases(i); | |
| 2221 if (aliases.length > 0) { | |
| 2222 td.appendChild(document.createTextNode(' ' + aliases.split('').join(' '))); | |
| 2223 } | |
| 2224 row.appendChild(td); | |
| 2225 td = document.createElement("td"); | |
| 2226 if (this.symbols[i].name != null) { | |
| 2227 td.appendChild(document.createTextNode(this.symbols[i].name)); | |
| 2228 } | |
| 2229 row.appendChild(td); | |
| 2230 td = document.createElement("td"); | |
| 2231 equals = this.symbols[i].equals.split(''); | |
| 2232 for (j = 0; j < equals.length; j++) { | |
| 2233 if (j != 0) td.appendChild(document.createTextNode(' ')); | |
| 2234 sym = document.createElement("span"); | |
| 2235 sym.style.color = this.get_colour(this.get_index(equals[j])); | |
| 2236 sym.appendChild(document.createTextNode(equals[j])); | |
| 2237 td.appendChild(sym); | |
| 2238 } | |
| 2239 row.appendChild(td); | |
| 2240 } | |
| 2241 return table; | |
| 2242 }; | |
| 2243 | |
| 2244 // returns a dictionary of the colours for EPS | |
| 2245 Alphabet.prototype._as_eps_dict = function() { | |
| 2246 "use strict"; | |
| 2247 var i, sym, rgb; | |
| 2248 var out = "/fullColourDict <<\n"; | |
| 2249 for (i = 0; i < this.ncore; i++) { | |
| 2250 sym = this.get_symbol(i); | |
| 2251 sym = sym.replace(/\\/g, "\\\\"); | |
| 2252 sym = sym.replace(/\(/g, "\\("); | |
| 2253 sym = sym.replace(/\)/g, "\\)"); | |
| 2254 rgb = this.get_rgb(i); | |
| 2255 out += " (" + sym + ") [" + rgb.red.toFixed(4) + " " + rgb.green.toFixed(4) + " " + rgb.blue.toFixed(4) + "]\n"; | |
| 2256 } | |
| 2257 out += ">> def\n"; | |
| 2258 out += "/mutedColourDict <<\n"; | |
| 2259 for (i = 0; i < this.ncore; i++) { | |
| 2260 sym = this.get_symbol(i); | |
| 2261 sym = sym.replace(/\\/g, "\\\\"); | |
| 2262 sym = sym.replace(/\(/g, "\\("); | |
| 2263 sym = sym.replace(/\)/g, "\\)"); | |
| 2264 rgb = Alphabet.lighten_colour(this.get_rgb(i)); | |
| 2265 out += " (" + sym + ") [" + rgb.red.toFixed(4) + " " + rgb.green.toFixed(4) + " " + rgb.blue.toFixed(4) + "]\n"; | |
| 2266 } | |
| 2267 out += ">> def\n"; | |
| 2268 return out; | |
| 2269 }; | |
| 2270 | |
| 2271 // return the alphabet name or a list of primary symbols | |
| 2272 Alphabet.prototype.toString = function() { | |
| 2273 "use strict"; | |
| 2274 if (this.name != null) { | |
| 2275 return this.name; | |
| 2276 } else { | |
| 2277 return this.get_symbols(); | |
| 2278 } | |
| 2279 }; | |
| 2280 | |
| 2281 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| 2282 // Helper functions | |
| 2283 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| 2284 | |
| 2285 // Convert a colour specified in RGB colourspace values into LAB colourspace | |
| 2286 Alphabet.rgb2lab = function(rgb) { | |
| 2287 "use strict"; | |
| 2288 var xyzHelper, labHelper; | |
| 2289 // XYZ helper | |
| 2290 xyzHelper = function(value) { | |
| 2291 if (value > 0.0445) { | |
| 2292 value = (value + 0.055) / 1.055; | |
| 2293 value = Math.pow(value, 2.4); | |
| 2294 } else { | |
| 2295 value /= 12.92; | |
| 2296 } | |
| 2297 value *= 100; | |
| 2298 return value; | |
| 2299 }; | |
| 2300 // lab helper | |
| 2301 labHelper = function(value) { | |
| 2302 if (value > 0.008856) { | |
| 2303 value = Math.pow(value, 1.0 / 3.0); | |
| 2304 } else { | |
| 2305 value = (7.787 * value) + (16.0 / 116.0); | |
| 2306 } | |
| 2307 return value; | |
| 2308 }; | |
| 2309 // convert into XYZ colourspace | |
| 2310 var c1, c2, c3; | |
| 2311 if (typeof rgb == "number") { | |
| 2312 c1 = xyzHelper(((rgb >> 16) & 0xFF) / 255.0); | |
| 2313 c2 = xyzHelper(((rgb >> 8) & 0xFF) / 255.0); | |
| 2314 c3 = xyzHelper((rgb & 0xFF) / 255.0); | |
| 2315 } else { | |
| 2316 c1 = xyzHelper(rgb.red); | |
| 2317 c2 = xyzHelper(rgb.green); | |
| 2318 c3 = xyzHelper(rgb.blue); | |
| 2319 } | |
| 2320 var x = (c1 * 0.4124) + (c2 * 0.3576) + (c3 * 0.1805); | |
| 2321 var y = (c1 * 0.2126) + (c2 * 0.7152) + (c3 * 0.0722); | |
| 2322 var z = (c1 * 0.0193) + (c2 * 0.1192) + (c3 * 0.9505); | |
| 2323 // convert into Lab colourspace | |
| 2324 c1 = labHelper(x / 95.047); | |
| 2325 c2 = labHelper(y / 100.0); | |
| 2326 c3 = labHelper(z / 108.883); | |
| 2327 var l = (116.0 * c2) - 16; | |
| 2328 var a = 500.0 * (c1 - c2); | |
| 2329 var b = 200.0 * (c2 - c3); | |
| 2330 return {"l": l, "a": a, "b": b}; | |
| 2331 }; | |
| 2332 | |
| 2333 // Convert a colour specified in HSV colourspace into RGB colourspace | |
| 2334 Alphabet.hsv2rgb = function(hue, sat, value, output_object) { | |
| 2335 // achromatic (grey) | |
| 2336 var r = value; | |
| 2337 var g = value; | |
| 2338 var b = value; | |
| 2339 if (sat != 0) { | |
| 2340 var h = hue / 60.0; | |
| 2341 var i = Math.floor(h); | |
| 2342 var f = h - i; | |
| 2343 var p = value * (1.0 - sat); | |
| 2344 var q = value * (1.0 - (sat * f)); | |
| 2345 var t = value * (1.0 - (sat * (1.0 - f))); | |
| 2346 if (i == 0) { | |
| 2347 r = value; | |
| 2348 g = t; | |
| 2349 b = p; | |
| 2350 } else if (i == 1) { | |
| 2351 r = q; | |
| 2352 g = value; | |
| 2353 b = p; | |
| 2354 } else if (i == 2) { | |
| 2355 r = p; | |
| 2356 g = value; | |
| 2357 b = t; | |
| 2358 } else if (i == 3) { | |
| 2359 r = p; | |
| 2360 g = q; | |
| 2361 b = value; | |
| 2362 } else if (i == 4) { | |
| 2363 r = t; | |
| 2364 g = p; | |
| 2365 b = value; | |
| 2366 } else { | |
| 2367 r = value; | |
| 2368 g = p; | |
| 2369 b = q; | |
| 2370 } | |
| 2371 } | |
| 2372 if (output_object) { | |
| 2373 return {"red": r, "green": g, "blue": b}; | |
| 2374 } else { | |
| 2375 return (Math.floor(r * 255) << 15) | (Math.floor(g * 255) << 8) | (Math.floor(b * 255)); | |
| 2376 } | |
| 2377 }; | |
| 2378 | |
| 2379 // Calculate a distance score between two colours in LAB colourspace | |
| 2380 Alphabet.lab_dist = function(lab1, lab2) { | |
| 2381 var c1 = Math.sqrt((lab1.l * lab1.l) + (lab1.a * lab1.a)); | |
| 2382 var c2 = Math.sqrt((lab2.l * lab2.l) + (lab2.a * lab2.a)); | |
| 2383 var dc = c1 - c2; | |
| 2384 var dl = lab1.l - lab2.l; | |
| 2385 var da = lab1.a - lab2.a; | |
| 2386 var db = lab1.b - lab2.b; | |
| 2387 // we don't want NaN due to rounding errors so fudge things a bit... | |
| 2388 var dh = 0; | |
| 2389 var dh_squared = (da * da) + (db * db) - (dc * dc); | |
| 2390 if (dh_squared > 0) { | |
| 2391 dh = Math.sqrt(dh_squared); | |
| 2392 } | |
| 2393 var first = dl; | |
| 2394 var second = dc / (1.0 + (0.045 * c1)); | |
| 2395 var third = dh / (1.0 + (0.015 * c1)); | |
| 2396 return Math.sqrt((first * first) + (second * second) + (third * third)); | |
| 2397 }; | |
| 2398 | |
| 2399 // convert an RGB value into a HSL value | |
| 2400 Alphabet.rgb2hsl = function(rgb) { | |
| 2401 "use strict"; | |
| 2402 var min, max, delta, h, s, l, r, g, b; | |
| 2403 if (typeof rgb == "number") { | |
| 2404 r = ((rgb >> 16) & 0xFF) / 255.0; | |
| 2405 g = ((rgb >> 8) & 0xFF) / 255.0; | |
| 2406 b = (rgb & 0xFF) / 255.0; | |
| 2407 } else { | |
| 2408 r = rgb.red; | |
| 2409 g = rgb.green; | |
| 2410 b = rgb.blue; | |
| 2411 } | |
| 2412 min = Math.min(r, g, b); | |
| 2413 max = Math.max(r, g, b); | |
| 2414 delta = max - min; | |
| 2415 l = min + (delta / 2); | |
| 2416 if (max == min) { | |
| 2417 h = 0; // achromatic (grayscale) | |
| 2418 s = 0; | |
| 2419 } else { | |
| 2420 if (l > 0.5) { | |
| 2421 s = delta / (2 - max - min); | |
| 2422 } else { | |
| 2423 s = delta / (max + min); | |
| 2424 } | |
| 2425 if (max == r) { | |
| 2426 h = (g - b) / delta; | |
| 2427 if (g < b) h += 6; | |
| 2428 } else if (max == g) { | |
| 2429 h = ((b - r) / delta) + 2; | |
| 2430 } else { | |
| 2431 h = ((r - g) / delta) + 4; | |
| 2432 } | |
| 2433 h /= 6; | |
| 2434 } | |
| 2435 return {"h": h, "s": s, "l": l}; | |
| 2436 }; | |
| 2437 | |
| 2438 // convert a HSL value into an RGB value | |
| 2439 Alphabet.hsl2rgb = function(hsl, output_object) { | |
| 2440 "use strict"; | |
| 2441 function _hue(p, q, t) { | |
| 2442 "use strict"; | |
| 2443 if (t < 0) t += 1; | |
| 2444 else if (t > 1) t -= 1; | |
| 2445 if (t < (1.0 / 6.0)) { | |
| 2446 return p + ((q - p) * 6.0 * t); | |
| 2447 } else if (t < 0.5) { | |
| 2448 return q; | |
| 2449 } else if (t < (2.0 / 3.0)) { | |
| 2450 return p + ((q - p) * ((2.0 / 3.0) - t) * 6.0); | |
| 2451 } else { | |
| 2452 return p; | |
| 2453 } | |
| 2454 } | |
| 2455 var r, g, b, p, q; | |
| 2456 if (hsl.s == 0) { | |
| 2457 // achromatic (grayscale) | |
| 2458 r = hsl.l; | |
| 2459 g = hsl.l; | |
| 2460 b = hsl.l; | |
| 2461 } else { | |
| 2462 if (hsl.l < 0.5) { | |
| 2463 q = hsl.l * (1 + hsl.s); | |
| 2464 } else { | |
| 2465 q = hsl.l + hsl.s - (hsl.l * hsl.s); | |
| 2466 } | |
| 2467 p = (2 * hsl.l) - q; | |
| 2468 r = _hue(p, q, hsl.h + (1.0 / 3.0)); | |
| 2469 g = _hue(p, q, hsl.h); | |
| 2470 b = _hue(p, q, hsl.h - (1.0 / 3.0)); | |
| 2471 } | |
| 2472 if (output_object) { | |
| 2473 return {"red": r, "green": g, "blue": b}; | |
| 2474 } else { | |
| 2475 return (Math.floor(r * 255) << 15) | (Math.floor(g * 255) << 8) | (Math.floor(b * 255)); | |
| 2476 } | |
| 2477 }; | |
| 2478 | |
| 2479 Alphabet.lighten_colour = function(rgb) { | |
| 2480 "use strict"; | |
| 2481 var hsl = Alphabet.rgb2hsl(rgb); | |
| 2482 hsl.l += (1.0 - hsl.l) * 2 / 3; | |
| 2483 return Alphabet.hsl2rgb(hsl, typeof rgb != "number"); | |
| 2484 }; | |
| 2485 | |
| 2486 //====================================================================== | |
| 2487 // end Alphabet object | |
| 2488 //====================================================================== | |
| 2489 | |
| 2490 //====================================================================== | |
| 2491 // start StandardAlphabet object | |
| 2492 //====================================================================== | |
| 2493 | |
| 2494 // an extension of the alphabet object to support some additional fields | |
| 2495 // only present in standard alphabets. | |
| 2496 var StandardAlphabet = function(enum_code, enum_name, alphabet_data) { | |
| 2497 Alphabet.apply(this, [alphabet_data]); | |
| 2498 this.enum_code = enum_code; | |
| 2499 this.enum_name = enum_name; | |
| 2500 }; | |
| 2501 StandardAlphabet.prototype = Alphabet.prototype; | |
| 2502 StandardAlphabet.prototype.constructor = StandardAlphabet; | |
| 2503 | |
| 2504 // A unique code for this standard alphabet. | |
| 2505 // This code will be a power of 2 to enable creation of bitsets for | |
| 2506 // a selection of standard alphabets. | |
| 2507 StandardAlphabet.prototype.get_code = function() { | |
| 2508 return this.enum_code; | |
| 2509 }; | |
| 2510 | |
| 2511 // A unique name for this standard alphabet. | |
| 2512 // this name will be all upper case and the same as the property that | |
| 2513 // refers to this alphabet in the AlphStd collection. | |
| 2514 StandardAlphabet.prototype.get_enum = function() { | |
| 2515 return this.enum_name; | |
| 2516 }; | |
| 2517 | |
| 2518 //====================================================================== | |
| 2519 // end StandardAlphabet object | |
| 2520 //====================================================================== | |
| 2521 | |
| 2522 // A collection of standard alphabets. | |
| 2523 var AlphStd = { | |
| 2524 RNA: new StandardAlphabet(1, "RNA", { | |
| 2525 "name": "RNA", | |
| 2526 "like": "RNA", | |
| 2527 "ncore": 4, | |
| 2528 "symbols": [ | |
| 2529 {"symbol": "A", "name": "Adenine", "colour": "CC0000"}, | |
| 2530 {"symbol": "C", "name": "Cytosine", "colour": "0000CC"}, | |
| 2531 {"symbol": "G", "name": "Guanine", "colour": "FFB300"}, | |
| 2532 {"symbol": "U", "name": "Uracil", "colour": "008000", | |
| 2533 "aliases": "T"}, | |
| 2534 {"symbol": "N", "name": "Any base", "equals": "ACGU", "aliases": "X."}, | |
| 2535 {"symbol": "V", "name": "Not U", "equals": "ACG"}, | |
| 2536 {"symbol": "H", "name": "Not G", "equals": "ACU"}, | |
| 2537 {"symbol": "D", "name": "Not C", "equals": "AGU"}, | |
| 2538 {"symbol": "B", "name": "Not A", "equals": "CGU"}, | |
| 2539 {"symbol": "M", "name": "Amino", "equals": "AC"}, | |
| 2540 {"symbol": "R", "name": "Purine", "equals": "AG"}, | |
| 2541 {"symbol": "W", "name": "Weak", "equals": "AU"}, | |
| 2542 {"symbol": "S", "name": "Strong", "equals": "CG"}, | |
| 2543 {"symbol": "Y", "name": "Pyrimidine", "equals": "CU"}, | |
| 2544 {"symbol": "K", "name": "Keto", "equals": "GU"} | |
| 2545 ] | |
| 2546 }), | |
| 2547 DNA: new StandardAlphabet(2, "DNA", { | |
| 2548 "name": "DNA", | |
| 2549 "like": "DNA", | |
| 2550 "ncore": 4, | |
| 2551 "symbols": [ | |
| 2552 {"symbol": "A", "name": "Adenine", "colour": "CC0000", "complement": "T"}, | |
| 2553 {"symbol": "C", "name": "Cytosine", "colour": "0000CC", "complement": "G"}, | |
| 2554 {"symbol": "G", "name": "Guanine", "colour": "FFB300", "complement": "C"}, | |
| 2555 {"symbol": "T", "name": "Thymine", "colour": "008000", "complement": "A", | |
| 2556 "aliases": "U"}, | |
| 2557 {"symbol": "N", "name": "Any base", "equals": "ACGT", "aliases": "X."}, | |
| 2558 {"symbol": "V", "name": "Not T", "equals": "ACG"}, | |
| 2559 {"symbol": "H", "name": "Not G", "equals": "ACT"}, | |
| 2560 {"symbol": "D", "name": "Not C", "equals": "AGT"}, | |
| 2561 {"symbol": "B", "name": "Not A", "equals": "CGT"}, | |
| 2562 {"symbol": "M", "name": "Amino", "equals": "AC"}, | |
| 2563 {"symbol": "R", "name": "Purine", "equals": "AG"}, | |
| 2564 {"symbol": "W", "name": "Weak", "equals": "AT"}, | |
| 2565 {"symbol": "S", "name": "Strong", "equals": "CG"}, | |
| 2566 {"symbol": "Y", "name": "Pyrimidine", "equals": "CT"}, | |
| 2567 {"symbol": "K", "name": "Keto", "equals": "GT"} | |
| 2568 ] | |
| 2569 }), | |
| 2570 PROTEIN: new StandardAlphabet(4, "PROTEIN", { | |
| 2571 "name": "Protein", | |
| 2572 "like": "PROTEIN", | |
| 2573 "ncore": 20, | |
| 2574 "symbols": [ | |
| 2575 {"symbol": "A", "name": "Alanine", "colour": "0000CC"}, | |
| 2576 {"symbol": "C", "name": "Cysteine", "colour": "0000CC"}, | |
| 2577 {"symbol": "D", "name": "Aspartic acid", "colour": "FF00FF"}, | |
| 2578 {"symbol": "E", "name": "Glutamic acid", "colour": "FF00FF"}, | |
| 2579 {"symbol": "F", "name": "Phenylalanine", "colour": "0000CC"}, | |
| 2580 {"symbol": "G", "name": "Glycine", "colour": "FFB300"}, | |
| 2581 {"symbol": "H", "name": "Histidine", "colour": "FFCCCC"}, | |
| 2582 {"symbol": "I", "name": "Isoleucine", "colour": "0000CC"}, | |
| 2583 {"symbol": "K", "name": "Lysine", "colour": "CC0000"}, | |
| 2584 {"symbol": "L", "name": "Leucine", "colour": "0000CC"}, | |
| 2585 {"symbol": "M", "name": "Methionine", "colour": "0000CC"}, | |
| 2586 {"symbol": "N", "name": "Asparagine", "colour": "008000"}, | |
| 2587 {"symbol": "P", "name": "Proline", "colour": "FFFF00"}, | |
| 2588 {"symbol": "Q", "name": "Glutamine", "colour": "008000"}, | |
| 2589 {"symbol": "R", "name": "Arginine", "colour": "CC0000"}, | |
| 2590 {"symbol": "S", "name": "Serine", "colour": "008000"}, | |
| 2591 {"symbol": "T", "name": "Threonine", "colour": "008000"}, | |
| 2592 {"symbol": "V", "name": "Valine", "colour": "0000CC"}, | |
| 2593 {"symbol": "W", "name": "Tryptophan", "colour": "0000CC"}, | |
| 2594 {"symbol": "Y", "name": "Tyrosine", "colour": "33E6CC"}, | |
| 2595 {"symbol": "X", "name": "Any amino acid", "equals": "ACDEFGHIKLMNPQRSTVWY", "aliases": "*."}, | |
| 2596 {"symbol": "B", "name": "Asparagine or Aspartic acid", "equals": "DN"}, | |
| 2597 {"symbol": "Z", "name": "Glutamine or Glutamic acid", "equals": "EQ"}, | |
| 2598 {"symbol": "J", "name": "Leucine or Isoleucine", "equals": "IL"} | |
| 2599 ] | |
| 2600 }) | |
| 2601 }; | |
| 2602 | |
| 2603 //====================================================================== | |
| 2604 // start Symbol object | |
| 2605 //====================================================================== | |
| 2606 var Symbol = function(alph_index, scale, alphabet) { | |
| 2607 "use strict"; | |
| 2608 //variable prototype | |
| 2609 this.symbol = alphabet.get_symbol(alph_index); | |
| 2610 this.scale = scale; | |
| 2611 this.colour = alphabet.get_colour(alph_index); | |
| 2612 }; | |
| 2613 | |
| 2614 Symbol.prototype.get_symbol = function() { | |
| 2615 "use strict"; | |
| 2616 return this.symbol; | |
| 2617 }; | |
| 2618 | |
| 2619 Symbol.prototype.get_scale = function() { | |
| 2620 "use strict"; | |
| 2621 return this.scale; | |
| 2622 }; | |
| 2623 | |
| 2624 Symbol.prototype.get_colour = function() { | |
| 2625 "use strict"; | |
| 2626 return this.colour; | |
| 2627 }; | |
| 2628 | |
| 2629 Symbol.prototype.toString = function() { | |
| 2630 "use strict"; | |
| 2631 return this.symbol + " " + (Math.round(this.scale*1000)/10) + "%"; | |
| 2632 }; | |
| 2633 | |
| 2634 function compare_symbol(sym1, sym2) { | |
| 2635 "use strict"; | |
| 2636 if (sym1.get_scale() < sym2.get_scale()) { | |
| 2637 return -1; | |
| 2638 } else if (sym1.get_scale() > sym2.get_scale()) { | |
| 2639 return 1; | |
| 2640 } else { | |
| 2641 return 0; | |
| 2642 } | |
| 2643 } | |
| 2644 //====================================================================== | |
| 2645 // end Symbol object | |
| 2646 //====================================================================== | |
| 2647 | |
| 2648 //====================================================================== | |
| 2649 // start Pspm object | |
| 2650 //====================================================================== | |
| 2651 var Pspm = function(matrix, name, ltrim, rtrim, nsites, evalue, pssm, alt) { | |
| 2652 "use strict"; | |
| 2653 var row, col, data, row_sum, delta, evalue_re; | |
| 2654 if (typeof name !== "string") { | |
| 2655 name = ""; | |
| 2656 } | |
| 2657 this.name = name; | |
| 2658 //construct | |
| 2659 if (matrix instanceof Pspm) { | |
| 2660 // copy constructor | |
| 2661 this.alph_length = matrix.alph_length; | |
| 2662 this.motif_length = matrix.motif_length; | |
| 2663 this.name = matrix.name; | |
| 2664 this.alt = matrix.alt; | |
| 2665 this.nsites = matrix.nsites; | |
| 2666 this.evalue = matrix.evalue; | |
| 2667 this.ltrim = matrix.ltrim; | |
| 2668 this.rtrim = matrix.rtrim; | |
| 2669 this.pspm = []; | |
| 2670 for (row = 0; row < matrix.motif_length; row++) { | |
| 2671 this.pspm[row] = []; | |
| 2672 for (col = 0; col < matrix.alph_length; col++) { | |
| 2673 this.pspm[row][col] = matrix.pspm[row][col]; | |
| 2674 } | |
| 2675 } | |
| 2676 if (matrix.pssm != null) { | |
| 2677 this.pssm = []; | |
| 2678 for (row = 0; row < matrix.motif_length; row++) { | |
| 2679 this.pspm[row] = []; | |
| 2680 for (col = 0; col < matrix.alph_length; col++) { | |
| 2681 this.pssm[row][col] = matrix.pssm[row][col]; | |
| 2682 } | |
| 2683 } | |
| 2684 } | |
| 2685 } else { | |
| 2686 // check parameters | |
| 2687 if (ltrim == null) { | |
| 2688 ltrim = 0; | |
| 2689 } else if (typeof ltrim !== "number" || ltrim % 1 !== 0 || ltrim < 0) { | |
| 2690 throw new Error("ltrim must be a non-negative integer, got: " + ltrim); | |
| 2691 } | |
| 2692 if (rtrim == null) { | |
| 2693 rtrim = 0; | |
| 2694 } else if (typeof rtrim !== "number" || rtrim % 1 !== 0 || rtrim < 0) { | |
| 2695 throw new Error("rtrim must be a non-negative integer, got: " + rtrim); | |
| 2696 } | |
| 2697 if (nsites != null) { | |
| 2698 if (typeof nsites !== "number" || nsites < 0) { | |
| 2699 throw new Error("nsites must be a positive number, got: " + nsites); | |
| 2700 } else if (nsites == 0) { | |
| 2701 nsites = null; | |
| 2702 } | |
| 2703 } | |
| 2704 if (evalue != null) { | |
| 2705 if (typeof evalue === "number") { | |
| 2706 if (evalue < 0) { | |
| 2707 throw new Error("evalue must be a non-negative number, got: " + evalue); | |
| 2708 } | |
| 2709 } else if (typeof evalue === "string") { | |
| 2710 evalue_re = /^((?:[+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?)|inf)$/; | |
| 2711 if (!evalue_re.test(evalue)) { | |
| 2712 throw new Error("evalue must be a non-negative number, got: " + evalue); | |
| 2713 } | |
| 2714 } else { | |
| 2715 throw new Error("evalue must be a non-negative number, got: " + evalue); | |
| 2716 } | |
| 2717 } | |
| 2718 // set properties | |
| 2719 this.name = name; | |
| 2720 this.alt = alt; | |
| 2721 this.nsites = nsites; | |
| 2722 this.evalue = evalue; | |
| 2723 this.ltrim = ltrim; | |
| 2724 this.rtrim = rtrim; | |
| 2725 if (typeof matrix === "string") { | |
| 2726 // string constructor | |
| 2727 data = parse_pspm_string(matrix); | |
| 2728 this.alph_length = data["alph_length"]; | |
| 2729 this.motif_length = data["motif_length"]; | |
| 2730 this.pspm = data["pspm"]; | |
| 2731 if (this.evalue == null) { | |
| 2732 if (data["evalue"] != null) { | |
| 2733 this.evalue = data["evalue"]; | |
| 2734 } else { | |
| 2735 this.evalue = 0; | |
| 2736 } | |
| 2737 } | |
| 2738 if (this.nsites == null) { | |
| 2739 if (typeof data["nsites"] === "number") { | |
| 2740 this.nsites = data["nsites"]; | |
| 2741 } else { | |
| 2742 this.nsites = 20; | |
| 2743 } | |
| 2744 } | |
| 2745 } else { | |
| 2746 // assume pspm is a nested array | |
| 2747 this.motif_length = matrix.length; | |
| 2748 this.alph_length = (matrix.length > 0 ? matrix[0].length : 0); | |
| 2749 if (this.nsites == null) { | |
| 2750 this.nsites = 20; | |
| 2751 } | |
| 2752 if (this.evalue == null) { | |
| 2753 this.evalue = 0; | |
| 2754 } | |
| 2755 this.pspm = []; | |
| 2756 // copy pspm and check | |
| 2757 for (row = 0; row < this.motif_length; row++) { | |
| 2758 if (this.alph_length != matrix[row].length) { | |
| 2759 throw new Error("COLUMN_MISMATCH"); | |
| 2760 } | |
| 2761 this.pspm[row] = []; | |
| 2762 row_sum = 0; | |
| 2763 for (col = 0; col < this.alph_length; col++) { | |
| 2764 this.pspm[row][col] = matrix[row][col]; | |
| 2765 row_sum += this.pspm[row][col]; | |
| 2766 } | |
| 2767 delta = 0.1; | |
| 2768 if (isNaN(row_sum) || (row_sum > 1 && (row_sum - 1) > delta) || | |
| 2769 (row_sum < 1 && (1 - row_sum) > delta)) { | |
| 2770 throw new Error("INVALID_SUM"); | |
| 2771 } | |
| 2772 } | |
| 2773 // copy pssm | |
| 2774 if (pssm != null) { | |
| 2775 this.pssm = []; | |
| 2776 for (row = 0; row < this.motif_length; row++) { | |
| 2777 this.pssm[row] = []; | |
| 2778 for (col = 0; col < this.alph_length; col++) { | |
| 2779 this.pssm[row][col] = pssm[row][col]; | |
| 2780 } | |
| 2781 } | |
| 2782 } | |
| 2783 } | |
| 2784 } | |
| 2785 }; | |
| 2786 | |
| 2787 Pspm.prototype.copy = function() { | |
| 2788 "use strict"; | |
| 2789 return new Pspm(this); | |
| 2790 }; | |
| 2791 | |
| 2792 Pspm.prototype.reverse = function() { | |
| 2793 "use strict"; | |
| 2794 var x, y, temp, temp_trim; | |
| 2795 //reverse | |
| 2796 x = 0; | |
| 2797 y = this.motif_length-1; | |
| 2798 while (x < y) { | |
| 2799 temp = this.pspm[x]; | |
| 2800 this.pspm[x] = this.pspm[y]; | |
| 2801 this.pspm[y] = temp; | |
| 2802 x++; | |
| 2803 y--; | |
| 2804 } | |
| 2805 // reverse pssm (if defined) | |
| 2806 if (typeof this.pssm !== "undefined") { | |
| 2807 //reverse | |
| 2808 x = 0; | |
| 2809 y = this.motif_length-1; | |
| 2810 while (x < y) { | |
| 2811 temp = this.pssm[x]; | |
| 2812 this.pspm[x] = this.pssm[y]; | |
| 2813 this.pssm[y] = temp; | |
| 2814 x++; | |
| 2815 y--; | |
| 2816 } | |
| 2817 } | |
| 2818 //swap triming | |
| 2819 temp_trim = this.ltrim; | |
| 2820 this.ltrim = this.rtrim; | |
| 2821 this.rtrim = temp_trim; | |
| 2822 return this; //allow function chaining... | |
| 2823 }; | |
| 2824 | |
| 2825 Pspm.prototype.reverse_complement = function(alphabet) { | |
| 2826 "use strict"; | |
| 2827 var x, y, temp, i, row, c, temp_trim; | |
| 2828 if (this.alph_length != alphabet.get_size_core()) { | |
| 2829 throw new Error("The alphabet size does not match the size of the pspm."); | |
| 2830 } | |
| 2831 if (!alphabet.has_complement()) { | |
| 2832 throw new Error("The specified alphabet can not be complemented."); | |
| 2833 } | |
| 2834 // reverse motif | |
| 2835 this.reverse(); | |
| 2836 //complement | |
| 2837 for (x = 0; x < this.motif_length; x++) { | |
| 2838 row = this.pspm[x]; | |
| 2839 for (i = 0; i < row.length; i++) { | |
| 2840 c = alphabet.get_complement(i); | |
| 2841 if (c < i) continue; | |
| 2842 temp = row[i]; | |
| 2843 row[i] = row[c]; | |
| 2844 row[c] = temp; | |
| 2845 } | |
| 2846 } | |
| 2847 // complement pssm (if defined) | |
| 2848 if (typeof this.pssm !== "undefined") { | |
| 2849 //complement | |
| 2850 for (x = 0; x < this.motif_length; x++) { | |
| 2851 row = this.pssm[x]; | |
| 2852 for (i = 0; i < row.length; i++) { | |
| 2853 c = alphabet.get_complement(i); | |
| 2854 if (c < i) continue; | |
| 2855 temp = row[i]; | |
| 2856 row[i] = row[c]; | |
| 2857 row[c] = temp; | |
| 2858 } | |
| 2859 } | |
| 2860 } | |
| 2861 return this; //allow function chaining... | |
| 2862 }; | |
| 2863 | |
| 2864 Pspm.prototype.get_stack = function(position, alphabet, ssc) { | |
| 2865 "use strict"; | |
| 2866 var row, stack_ic, alphabet_ic, stack, i, sym; | |
| 2867 if (this.alph_length != alphabet.get_size_core()) { | |
| 2868 throw new Error("The alphabet size does not match the size of the pspm."); | |
| 2869 } | |
| 2870 row = this.pspm[position]; | |
| 2871 stack_ic = this.get_stack_ic(position, alphabet); | |
| 2872 if (ssc) stack_ic -= this.get_error(alphabet); | |
| 2873 alphabet_ic = alphabet.get_ic(); | |
| 2874 stack = []; | |
| 2875 for (i = 0; i < this.alph_length; i++) { | |
| 2876 sym = new Symbol(i, row[i]*stack_ic/alphabet_ic, alphabet); | |
| 2877 if (sym.get_scale() <= 0) { | |
| 2878 continue; | |
| 2879 } | |
| 2880 stack.push(sym); | |
| 2881 } | |
| 2882 stack.sort(compare_symbol); | |
| 2883 return stack; | |
| 2884 }; | |
| 2885 | |
| 2886 Pspm.prototype.get_stack_ic = function(position, alphabet) { | |
| 2887 "use strict"; | |
| 2888 var row, H, i; | |
| 2889 if (this.alph_length != alphabet.get_size_core()) { | |
| 2890 throw new Error("The alphabet size does not match the size fo the pspm."); | |
| 2891 } | |
| 2892 row = this.pspm[position]; | |
| 2893 H = 0; | |
| 2894 for (i = 0; i < this.alph_length; i++) { | |
| 2895 if (row[i] === 0) { | |
| 2896 continue; | |
| 2897 } | |
| 2898 H -= (row[i] * (Math.log(row[i]) / Math.LN2)); | |
| 2899 } | |
| 2900 return alphabet.get_ic() - H; | |
| 2901 }; | |
| 2902 | |
| 2903 Pspm.prototype.get_error = function(alphabet) { | |
| 2904 "use strict"; | |
| 2905 if (this.nsites === 0) { | |
| 2906 return 0; | |
| 2907 } | |
| 2908 return (alphabet.get_size_core()-1) / (2 * Math.LN2 * this.nsites); | |
| 2909 }; | |
| 2910 | |
| 2911 Pspm.prototype.get_motif_length = function() { | |
| 2912 "use strict"; | |
| 2913 return this.motif_length; | |
| 2914 }; | |
| 2915 | |
| 2916 Pspm.prototype.get_alph_length = function() { | |
| 2917 "use strict"; | |
| 2918 return this.alph_length; | |
| 2919 }; | |
| 2920 | |
| 2921 Pspm.prototype.get_left_trim = function() { | |
| 2922 "use strict"; | |
| 2923 return this.ltrim; | |
| 2924 }; | |
| 2925 | |
| 2926 Pspm.prototype.get_right_trim = function() { | |
| 2927 "use strict"; | |
| 2928 return this.rtrim; | |
| 2929 }; | |
| 2930 | |
| 2931 Pspm.prototype.as_best_match = function(alphabet) { | |
| 2932 "use strict"; | |
| 2933 var match, odds, best_odds, best_index; | |
| 2934 var i, j; | |
| 2935 match = ""; | |
| 2936 for (i = 0; i < this.motif_length; i++) { | |
| 2937 best_index = 0; | |
| 2938 best_odds = this.pspm[i][0] / alphabet.get_bg_freq(0); | |
| 2939 for (j = 1; j < this.alph_length; j++) { | |
| 2940 odds = this.pspm[i][j] / alphabet.get_bg_freq(j); | |
| 2941 if (odds > best_odds) { | |
| 2942 best_odds = odds; | |
| 2943 best_index = j; | |
| 2944 } | |
| 2945 } | |
| 2946 match += alphabet.get_symbol(best_index); | |
| 2947 } | |
| 2948 return match; | |
| 2949 }; | |
| 2950 | |
| 2951 Pspm.prototype.as_count_matrix = function() { | |
| 2952 "use strict"; | |
| 2953 var count, count_text, text; | |
| 2954 var i, j; | |
| 2955 text = ""; | |
| 2956 for (i = 0; i < this.motif_length; i++) { | |
| 2957 if (i !== 0) { | |
| 2958 text += "\n"; | |
| 2959 } | |
| 2960 for (j = 0; j < this.alph_length; j++) { | |
| 2961 if (j !== 0) { | |
| 2962 text += " "; | |
| 2963 } | |
| 2964 count = Math.round(this.nsites * this.pspm[i][j]); | |
| 2965 count_text = "" + count; | |
| 2966 // pad up to length of 4 | |
| 2967 if (count_text.length < 4) { | |
| 2968 text += (new Array(5 - count_text.length)).join(" ") + count_text; | |
| 2969 } else { | |
| 2970 text += count_text; | |
| 2971 } | |
| 2972 } | |
| 2973 } | |
| 2974 return text; | |
| 2975 }; | |
| 2976 | |
| 2977 Pspm.prototype.as_probability_matrix = function() { | |
| 2978 "use strict"; | |
| 2979 var text; | |
| 2980 var i, j; | |
| 2981 text = ""; | |
| 2982 for (i = 0; i < this.motif_length; i++) { | |
| 2983 if (i !== 0) { | |
| 2984 text += "\n"; | |
| 2985 } | |
| 2986 for (j = 0; j < this.alph_length; j++) { | |
| 2987 if (j !== 0) { | |
| 2988 text += " "; | |
| 2989 } | |
| 2990 text += this.pspm[i][j].toFixed(6); | |
| 2991 } | |
| 2992 } | |
| 2993 return text; | |
| 2994 }; | |
| 2995 | |
| 2996 Pspm.prototype.as_score_matrix = function(alphabet, pseudo) { | |
| 2997 "use strict"; | |
| 2998 var me, score, out, row, col, score_text; | |
| 2999 me = this; | |
| 3000 if (typeof this.pssm === "undefined") { | |
| 3001 if (!(typeof alphabet === "object" && alphabet != null && alphabet instanceof Alphabet)) { | |
| 3002 throw new Error("The alphabet is required to generate the pssm."); | |
| 3003 } | |
| 3004 if (typeof pseudo === "undefined") { | |
| 3005 pseudo = 0.01; | |
| 3006 } else if (typeof pseudo !== "number" || pseudo < 0) { | |
| 3007 throw new Error("Expected positive number for pseudocount"); | |
| 3008 } | |
| 3009 score = function(row, col) { | |
| 3010 "use strict"; | |
| 3011 var p, bg, p2; | |
| 3012 p = me.pspm[row][col]; | |
| 3013 bg = alphabet.get_bg_freq(col); | |
| 3014 p2 = (p * me.nsites + bg * pseudo) / (me.nsites + pseudo); | |
| 3015 return (p2 > 0 ? Math.round((Math.log(p2 / bg) / Math.LN2) * 100) : -10000); | |
| 3016 }; | |
| 3017 } else { | |
| 3018 score = function(row, col) { | |
| 3019 "use strict"; | |
| 3020 return me.pssm[row][col]; | |
| 3021 }; | |
| 3022 } | |
| 3023 out = ""; | |
| 3024 for (row = 0; row < this.motif_length; row++) { | |
| 3025 for (col = 0; col < this.alph_length; col++) { | |
| 3026 if (col !== 0) { | |
| 3027 out += " "; | |
| 3028 } | |
| 3029 score_text = "" + score(row, col); | |
| 3030 // pad out to 6 characters | |
| 3031 if (score_text.length < 6) { | |
| 3032 out += (new Array(7 - score_text.length)).join(" ") + score_text; | |
| 3033 } else { | |
| 3034 out += score_text; | |
| 3035 } | |
| 3036 } | |
| 3037 out += "\n"; | |
| 3038 } | |
| 3039 return out; | |
| 3040 } | |
| 3041 | |
| 3042 Pspm.prototype.as_pspm = function() { | |
| 3043 "use strict"; | |
| 3044 return "letter-probability matrix: alength= " + this.alph_length + | |
| 3045 " w= " + this.motif_length + " nsites= " + this.nsites + | |
| 3046 " E= " + (typeof this.evalue === "number" ? | |
| 3047 this.evalue.toExponential() : this.evalue) + "\n" + | |
| 3048 this.as_probability_matrix(); | |
| 3049 }; | |
| 3050 | |
| 3051 Pspm.prototype.as_pssm = function(alphabet, pseudo) { | |
| 3052 "use strict"; | |
| 3053 return "log-odds matrix: alength= " + this.alph_length + | |
| 3054 " w= " + this.motif_length + | |
| 3055 " E= " + (typeof this.evalue == "number" ? | |
| 3056 this.evalue.toExponential() : this.evalue) + "\n" + | |
| 3057 this.as_score_matrix(alphabet, pseudo); | |
| 3058 }; | |
| 3059 | |
| 3060 Pspm.prototype.as_meme = function(options) { | |
| 3061 var with_header, with_pspm, with_pssm, version, alphabet, bg_source, pseudocount, strands; | |
| 3062 var out, alen, i; | |
| 3063 // get the options | |
| 3064 if (typeof options !== "object" || options === null) { | |
| 3065 options = {}; | |
| 3066 } | |
| 3067 with_header = (typeof options["with_header"] === "boolean" ? options["with_header"] : false); | |
| 3068 with_pspm = (typeof options["with_pspm"] === "boolean" ? options["with_pspm"] : false); | |
| 3069 with_pssm = (typeof options["with_pssm"] === "boolean" ? options["with_pssm"] : false); | |
| 3070 if (!with_pspm && !with_pssm) with_pspm = true; | |
| 3071 if (with_header) { | |
| 3072 if (typeof options["version"] === "string" && /^\d+(?:\.\d+){0,2}$/.test(options["version"])) { | |
| 3073 version = options["version"]; | |
| 3074 } else if (typeof options["version"] === "number") { | |
| 3075 version = options["version"].toFixed(0); | |
| 3076 } else { | |
| 3077 version = "4"; | |
| 3078 } | |
| 3079 if (typeof options["strands"] === "number" && options["strands"] === 1) { | |
| 3080 strands = 1; | |
| 3081 } else { | |
| 3082 strands = 2; | |
| 3083 } | |
| 3084 if (typeof options["bg_source"] === "string") { | |
| 3085 bg_source = options["bg_source"]; | |
| 3086 } else { | |
| 3087 bg_source = "unknown source"; | |
| 3088 } | |
| 3089 if (typeof options["alphabet"] === "object" && options["alphabet"] != null | |
| 3090 && options["alphabet"] instanceof Alphabet) { | |
| 3091 alphabet = options["alphabet"]; | |
| 3092 } else { | |
| 3093 throw new Error("The alphabet is required to generate the header."); | |
| 3094 } | |
| 3095 } | |
| 3096 // now create the output | |
| 3097 out = ""; | |
| 3098 if (with_header) { | |
| 3099 out = "MEME version " + version + "\n\n"; | |
| 3100 out += alphabet.as_meme() + "\n"; | |
| 3101 if (alphabet.has_complement()) { // assume DNA has both strands unless otherwise specified | |
| 3102 out += "strands: " + (strands === 1 ? "+" : "+ -") + "\n\n"; | |
| 3103 } | |
| 3104 out += "Background letter frequencies (from " + bg_source + "):\n"; | |
| 3105 alen = alphabet.get_size_core(); | |
| 3106 for (i = 0; i < alen; i++) { | |
| 3107 if (i !== 0) { | |
| 3108 if (i % 9 === 0) { // maximum of nine entries per line | |
| 3109 out += "\n"; | |
| 3110 } else { | |
| 3111 out += " "; | |
| 3112 } | |
| 3113 } | |
| 3114 out += alphabet.get_symbol(i) + " " + alphabet.get_bg_freq(i).toFixed(3); | |
| 3115 } | |
| 3116 } | |
| 3117 out += "\n\n"; | |
| 3118 out += "MOTIF " + this.name + (this.alt == null ? "" : " " + this.alt); | |
| 3119 if (with_pssm) { | |
| 3120 out += "\n\n"; | |
| 3121 out += this.as_pssm(options["alphabet"], options["pseudocount"]); | |
| 3122 } | |
| 3123 if (with_pspm) { | |
| 3124 out += "\n\n"; | |
| 3125 out += this.as_pspm(); | |
| 3126 } | |
| 3127 return out; | |
| 3128 } | |
| 3129 | |
| 3130 Pspm.prototype.toString = function() { | |
| 3131 "use strict"; | |
| 3132 var str, i, row; | |
| 3133 str = ""; | |
| 3134 for (i = 0; i < this.pspm.length; i++) { | |
| 3135 row = this.pspm[i]; | |
| 3136 str += row.join("\t") + "\n"; | |
| 3137 } | |
| 3138 return str; | |
| 3139 }; | |
| 3140 | |
| 3141 function parse_pspm_properties(str) { | |
| 3142 "use strict"; | |
| 3143 var parts, i, eqpos, before, after, properties, prop, num, num_re; | |
| 3144 num_re = /^((?:[+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?)|inf)$/; | |
| 3145 parts = trim(str).split(/\s+/); | |
| 3146 // split up words containing = | |
| 3147 for (i = 0; i < parts.length;) { | |
| 3148 eqpos = parts[i].indexOf("="); | |
| 3149 if (eqpos != -1) { | |
| 3150 before = parts[i].substr(0, eqpos); | |
| 3151 after = parts[i].substr(eqpos+1); | |
| 3152 if (before.length > 0 && after.length > 0) { | |
| 3153 parts.splice(i, 1, before, "=", after); | |
| 3154 i += 3; | |
| 3155 } else if (before.length > 0) { | |
| 3156 parts.splice(i, 1, before, "="); | |
| 3157 i += 2; | |
| 3158 } else if (after.length > 0) { | |
| 3159 parts.splice(i, 1, "=", after); | |
| 3160 i += 2; | |
| 3161 } else { | |
| 3162 parts.splice(i, 1, "="); | |
| 3163 i++; | |
| 3164 } | |
| 3165 } else { | |
| 3166 i++; | |
| 3167 } | |
| 3168 } | |
| 3169 properties = {}; | |
| 3170 for (i = 0; i < parts.length; i += 3) { | |
| 3171 if (parts.length - i < 3) { | |
| 3172 throw new Error("Expected PSPM property was incomplete. "+ | |
| 3173 "Remaing parts are: " + parts.slice(i).join(" ")); | |
| 3174 } | |
| 3175 if (parts[i+1] !== "=") { | |
| 3176 throw new Error("Expected '=' in PSPM property between key and " + | |
| 3177 "value but got " + parts[i+1]); | |
| 3178 } | |
| 3179 prop = parts[i].toLowerCase(); | |
| 3180 num = parts[i+2]; | |
| 3181 if (!num_re.test(num)) { | |
| 3182 throw new Error("Expected numeric value for PSPM property '" + | |
| 3183 prop + "' but got '" + num + "'"); | |
| 3184 } | |
| 3185 properties[prop] = num; | |
| 3186 } | |
| 3187 return properties; | |
| 3188 } | |
| 3189 | |
| 3190 function parse_pspm_string(pspm_string) { | |
| 3191 "use strict"; | |
| 3192 var header_re, lines, first_line, line_num, col_num, alph_length, | |
| 3193 motif_length, nsites, evalue, pspm, i, line, match, props, parts, | |
| 3194 j, prob; | |
| 3195 header_re = /^letter-probability\s+matrix:(.*)$/i; | |
| 3196 lines = pspm_string.split(/\n/); | |
| 3197 first_line = true; | |
| 3198 line_num = 0; | |
| 3199 col_num = 0; | |
| 3200 alph_length; | |
| 3201 motif_length; | |
| 3202 nsites; | |
| 3203 evalue; | |
| 3204 pspm = []; | |
| 3205 for (i = 0; i < lines.length; i++) { | |
| 3206 line = trim(lines[i]); | |
| 3207 if (line.length === 0) { | |
| 3208 continue; | |
| 3209 } | |
| 3210 // check the first line for a header though allow matrices without it | |
| 3211 if (first_line) { | |
| 3212 first_line = false; | |
| 3213 match = header_re.exec(line); | |
| 3214 if (match !== null) { | |
| 3215 props = parse_pspm_properties(match[1]); | |
| 3216 if (props.hasOwnProperty("alength")) { | |
| 3217 alph_length = parseFloat(props["alength"]); | |
| 3218 if (alph_length != 4 && alph_length != 20) { | |
| 3219 throw new Error("PSPM property alength should be 4 or 20" + | |
| 3220 " but got " + alph_length); | |
| 3221 } | |
| 3222 } | |
| 3223 if (props.hasOwnProperty("w")) { | |
| 3224 motif_length = parseFloat(props["w"]); | |
| 3225 if (motif_length % 1 !== 0 || motif_length < 1) { | |
| 3226 throw new Error("PSPM property w should be an integer larger " + | |
| 3227 "than zero but got " + motif_length); | |
| 3228 } | |
| 3229 } | |
| 3230 if (props.hasOwnProperty("nsites")) { | |
| 3231 nsites = parseFloat(props["nsites"]); | |
| 3232 if (nsites <= 0) { | |
| 3233 throw new Error("PSPM property nsites should be larger than " + | |
| 3234 "zero but got " + nsites); | |
| 3235 } | |
| 3236 } | |
| 3237 if (props.hasOwnProperty("e")) { | |
| 3238 evalue = props["e"]; | |
| 3239 if (evalue < 0) { | |
| 3240 throw new Error("PSPM property evalue should be " + | |
| 3241 "non-negative but got " + evalue); | |
| 3242 } | |
| 3243 } | |
| 3244 continue; | |
| 3245 } | |
| 3246 } | |
| 3247 pspm[line_num] = []; | |
| 3248 col_num = 0; | |
| 3249 parts = line.split(/\s+/); | |
| 3250 for (j = 0; j < parts.length; j++) { | |
| 3251 prob = parseFloat(parts[j]); | |
| 3252 if (prob != parts[j] || prob < 0 || prob > 1) { | |
| 3253 throw new Error("Expected probability but got '" + parts[j] + "'"); | |
| 3254 } | |
| 3255 pspm[line_num][col_num] = prob; | |
| 3256 col_num++; | |
| 3257 } | |
| 3258 line_num++; | |
| 3259 } | |
| 3260 if (typeof motif_length === "number") { | |
| 3261 if (pspm.length != motif_length) { | |
| 3262 throw new Error("Expected PSPM to have a motif length of " + | |
| 3263 motif_length + " but it was actually " + pspm.length); | |
| 3264 } | |
| 3265 } else { | |
| 3266 motif_length = pspm.length; | |
| 3267 } | |
| 3268 if (typeof alph_length !== "number") { | |
| 3269 alph_length = pspm[0].length; | |
| 3270 if (alph_length != 4 && alph_length != 20) { | |
| 3271 throw new Error("Expected length of first row in the PSPM to be " + | |
| 3272 "either 4 or 20 but got " + alph_length); | |
| 3273 } | |
| 3274 } | |
| 3275 for (i = 0; i < pspm.length; i++) { | |
| 3276 if (pspm[i].length != alph_length) { | |
| 3277 throw new Error("Expected PSPM row " + i + " to have a length of " + | |
| 3278 alph_length + " but the length was " + pspm[i].length); | |
| 3279 } | |
| 3280 } | |
| 3281 return {"pspm": pspm, "motif_length": motif_length, | |
| 3282 "alph_length": alph_length, "nsites": nsites, "evalue": evalue}; | |
| 3283 } | |
| 3284 //====================================================================== | |
| 3285 // end Pspm object | |
| 3286 //====================================================================== | |
| 3287 | |
| 3288 //====================================================================== | |
| 3289 // start Logo object | |
| 3290 //====================================================================== | |
| 3291 | |
| 3292 var Logo = function(alphabet, options) { | |
| 3293 "use strict"; | |
| 3294 this.alphabet = alphabet; | |
| 3295 this.fine_text = ""; | |
| 3296 this.x_axis = 1; | |
| 3297 this.y_axis = true; | |
| 3298 this.xlate_nsyms = 1; | |
| 3299 this.xlate_start = null; | |
| 3300 this.xlate_end = null; | |
| 3301 this.pspm_list = []; | |
| 3302 this.pspm_column = []; | |
| 3303 this.rows = 0; | |
| 3304 this.columns = 0; | |
| 3305 if (typeof options === "string") { | |
| 3306 // the old method signature had fine_text here so we support that | |
| 3307 this.fine_text = options; | |
| 3308 } else if (typeof options === "object" && options != null) { | |
| 3309 this.fine_text = (typeof options.fine_text === "string" ? options.fine_text : ""); | |
| 3310 this.x_axis = (typeof options.x_axis === "boolean" ? (options.x_axis ? 1 : 0) : 1); | |
| 3311 if (options.x_axis_hidden != null && options.x_axis_hidden) this.x_axis = -1; | |
| 3312 this.y_axis = (typeof options.y_axis === "boolean" ? options.y_axis : true); | |
| 3313 this.xlate_nsyms = (typeof options.xlate_nsyms === "number" ? options.xlate_nsyms : this.xlate_nsyms); | |
| 3314 this.xlate_start = (typeof options.xlate_start === "number" ? options.xlate_start : this.xlate_start); | |
| 3315 this.xlate_end = (typeof options.xlate_end === "number" ? options.xlate_end : this.xlate_end); | |
| 3316 } | |
| 3317 }; | |
| 3318 | |
| 3319 Logo.prototype.add_pspm = function(pspm, column) { | |
| 3320 "use strict"; | |
| 3321 var col; | |
| 3322 if (typeof column === "undefined") { | |
| 3323 column = 0; | |
| 3324 } else if (column < 0) { | |
| 3325 throw new Error("Column index out of bounds."); | |
| 3326 } | |
| 3327 this.pspm_list[this.rows] = pspm; | |
| 3328 this.pspm_column[this.rows] = column; | |
| 3329 this.rows++; | |
| 3330 col = column + pspm.get_motif_length(); | |
| 3331 if (col > this.columns) { | |
| 3332 this.columns = col; | |
| 3333 } | |
| 3334 }; | |
| 3335 | |
| 3336 Logo.prototype.get_columns = function() { | |
| 3337 "use strict"; | |
| 3338 return this.columns; | |
| 3339 }; | |
| 3340 | |
| 3341 Logo.prototype.get_xlate_nsyms = function() { | |
| 3342 "use strict"; | |
| 3343 return this.xlate_nsyms; | |
| 3344 }; | |
| 3345 | |
| 3346 Logo.prototype.get_xlate_start = function() { | |
| 3347 "use strict"; | |
| 3348 return (this.xlate_start != null ? this.xlate_start : 0); | |
| 3349 }; | |
| 3350 | |
| 3351 Logo.prototype.get_xlate_end = function() { | |
| 3352 "use strict"; | |
| 3353 return (this.xlate_end != null ? this.xlate_end : this.columns * this.xlate_nsyms); | |
| 3354 }; | |
| 3355 | |
| 3356 Logo.prototype.get_xlate_columns = function() { | |
| 3357 "use strict"; | |
| 3358 return this.get_xlate_end() - this.get_xlate_start(); | |
| 3359 }; | |
| 3360 | |
| 3361 Logo.prototype.get_rows = function() { | |
| 3362 "use strict"; | |
| 3363 return this.rows; | |
| 3364 }; | |
| 3365 | |
| 3366 Logo.prototype.get_pspm = function(row_index) { | |
| 3367 "use strict"; | |
| 3368 if (row_index < 0 || row_index >= this.rows) { | |
| 3369 throw new Error("INDEX_OUT_OF_BOUNDS"); | |
| 3370 } | |
| 3371 return this.pspm_list[row_index]; | |
| 3372 }; | |
| 3373 | |
| 3374 Logo.prototype.get_offset = function(row_index) { | |
| 3375 "use strict"; | |
| 3376 if (row_index < 0 || row_index >= this.rows) { | |
| 3377 throw new Error("INDEX_OUT_OF_BOUNDS"); | |
| 3378 } | |
| 3379 return this.pspm_column[row_index]; | |
| 3380 }; | |
| 3381 | |
| 3382 Logo.prototype._as_eps_data = function(ssc, errbars) { | |
| 3383 var i, j, pos, stack_pos, pspm, stack, sym, out; | |
| 3384 out = ""; | |
| 3385 for (i = 0; i < this.rows; i++) { | |
| 3386 out += "\nStartLine\n"; | |
| 3387 // Indent | |
| 3388 for (j = 0; j < this.pspm_column[i]; j++) { | |
| 3389 out += "() startstack\nendstack\n\n"; | |
| 3390 } | |
| 3391 pspm = this.pspm_list[i]; | |
| 3392 if (pspm.get_left_trim() > 0) { | |
| 3393 out += "MuteColour\nDrawTrimEdge\n" + pspm.get_left_trim() + " DrawTrimBg\n"; | |
| 3394 } | |
| 3395 for (pos = 0; pos < pspm.get_motif_length(); pos++) { | |
| 3396 if (pos != 0 && pos == pspm.get_left_trim()) { // enable full colour | |
| 3397 out += "DrawTrimEdge\nRestoreColour\n"; | |
| 3398 } else if (pos == (pspm.get_motif_length() - pspm.get_right_trim())) { | |
| 3399 out += "MuteColour\n" + pspm.get_right_trim() + " DrawTrimBg\n"; | |
| 3400 } | |
| 3401 out += "(" + (pos + 1) + ") startstack\n"; | |
| 3402 stack = pspm.get_stack(pos, this.alphabet, ssc); | |
| 3403 for (stack_pos = 0; stack_pos < stack.length; stack_pos++) { | |
| 3404 sym = stack[stack_pos]; | |
| 3405 out += " " + (sym.get_scale() * this.alphabet.get_ic()) + " (" + sym.get_symbol() + ") numchar\n"; | |
| 3406 } | |
| 3407 if (errbars) { | |
| 3408 out += " " + pspm.get_error(this.alphabet) + " Ibeam\n"; | |
| 3409 } | |
| 3410 out += "endstack\n\n"; | |
| 3411 } | |
| 3412 if (pspm.get_right_trim() > 0 || pspm.get_left_trim() == pspm.get_motif_length()) { | |
| 3413 out += "RestoreColour\n"; | |
| 3414 } | |
| 3415 out += "EndLine\n"; | |
| 3416 } | |
| 3417 return out; | |
| 3418 }; | |
| 3419 | |
| 3420 Logo.prototype.as_eps = function(options) { | |
| 3421 "use strict"; | |
| 3422 if (this.xlate_nsyms != 1) throw new Error("Unsupported setting xlate_nsyms for EPS"); | |
| 3423 if (this.xlate_start != null) throw new Error("Unsupported setting xlate_start for EPS"); | |
| 3424 if (this.xlate_end != null) throw new Error("Unsupported setting xlate_end for EPS"); | |
| 3425 | |
| 3426 var LOGOHEIGHT = 7.5; // default height of line in cm | |
| 3427 var cm2pts, height, width, now, ssc, errbars; | |
| 3428 if (typeof options === "undefined") { | |
| 3429 options = {}; | |
| 3430 } | |
| 3431 cm2pts = 72 / 2.54; | |
| 3432 if (typeof options.logo_height == "number") { | |
| 3433 height = options.logo_height; | |
| 3434 } else { | |
| 3435 height = LOGOHEIGHT * this.rows; | |
| 3436 } | |
| 3437 if (typeof options.logo_width == "number") { | |
| 3438 width = options.logo_width; | |
| 3439 } else { | |
| 3440 width = this.columns + 2; | |
| 3441 } | |
| 3442 now = new Date(); | |
| 3443 ssc = (typeof options.ssc == "boolean" ? options.ssc : false); | |
| 3444 errbars = (typeof options.show_error_bar == "boolean" ? options.show_error_bar : ssc); | |
| 3445 var values = { | |
| 3446 "LOGOHEIGHT": height, | |
| 3447 "LOGOWIDTH": width, | |
| 3448 "BOUNDINGHEIGHT": Math.round(height * cm2pts), | |
| 3449 "BOUNDINGWIDTH": Math.round(width * cm2pts), | |
| 3450 "LOGOLINEHEIGHT": (height / this.rows), | |
| 3451 "CHARSPERLINE": this.columns, | |
| 3452 "BARBITS": this.alphabet.get_ic(), | |
| 3453 "LOGOTYPE": (this.alphabet.has_complement() ? "NA" : "AA"), | |
| 3454 "CREATIONDATE": now.getDate() + "." + (now.getMonth() + 1) + "." + now.getFullYear() + " " + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds(), | |
| 3455 "ERRORBARFRACTION": (typeof options.error_bar_fraction == "number" ? options.error_bar_fraction : 1.0), | |
| 3456 "TICBITS": (typeof options.ticbits == "number" ? options.ticbits : 1.0), | |
| 3457 "TITLE": (typeof options.title == "string" ? options.title : ""), | |
| 3458 "FINEPRINT": (typeof options.fineprint == "string" ? options.fineprint : this.fine_text), | |
| 3459 "XAXISLABEL": (typeof options.xaxislabel == "string" ? options.xaxislabel : ""), | |
| 3460 "YAXISLABEL": (typeof options.yaxislabel == "string" ? options.yaxislabel : "bits"), | |
| 3461 "SSC": ssc, | |
| 3462 "YAXIS": (typeof options.show_y_axis == "boolean" ? options.show_y_axis : this.y_axis), | |
| 3463 "SHOWENDS": (typeof options.show_ends == "boolean" ? options.show_ends : false), | |
| 3464 "ERRBAR": errbars, | |
| 3465 "OUTLINE": (typeof options.show_outline == "boolean" ? options.show_outline : false), | |
| 3466 "NUMBERING": (typeof options.show_numbering == "boolean" ? options.show_numbering : this.x_axis != 0), | |
| 3467 "SHOWINGBOX": (typeof options.show_box == "boolean" ? options.show_box : false), | |
| 3468 "CREATOR": (typeof options.creator == "string" ? options.creator : "motif_logo.js"), | |
| 3469 "FONTSIZE": (typeof options.label_font_size == "number" ? options.label_font_size : 12), | |
| 3470 "TITLEFONTSIZE": (typeof options.title_font_size == "number" ? options.title_font_size : 12), | |
| 3471 "SMALLFONTSIZE": (typeof options.small_font_size == "number" ? options.small_font_size : 6), | |
| 3472 "TOPMARGIN" : (typeof options.top_margin == "number" ? options.top_margin : 0.9), | |
| 3473 "BOTTOMMARGIN": (typeof options.bottom_margin == "number" ? options.bottom_margin : 0.9), | |
| 3474 "COLORDICT": this.alphabet._as_eps_dict(), | |
| 3475 "DATA": this._as_eps_data(ssc, errbars) | |
| 3476 }; | |
| 3477 // now this requires that the script containing the template has been imported! | |
| 3478 return motif_logo_template(values); | |
| 3479 }; | |
| 3480 | |
| 3481 //====================================================================== | |
| 3482 // end Logo object | |
| 3483 //====================================================================== | |
| 3484 | |
| 3485 // calculate the exact size (in pixels) of an object drawn on the | |
| 3486 // canvas assuming that the background of the canvas is transparent. | |
| 3487 function canvas_bounds(ctx, cwidth, cheight) { | |
| 3488 "use strict"; | |
| 3489 var data, r, c, top_line, bottom_line, left_line, right_line, | |
| 3490 txt_width, txt_height; | |
| 3491 | |
| 3492 // extract the image data | |
| 3493 data = ctx.getImageData(0, 0, cwidth, cheight).data; | |
| 3494 | |
| 3495 // set initial values | |
| 3496 top_line = -1; bottom_line = -1; left_line = -1; right_line = -1; | |
| 3497 txt_width = 0; txt_height = 0; | |
| 3498 | |
| 3499 // Find the top-most line with a non-transparent pixel | |
| 3500 for (r = 0; r < cheight; r++) { | |
| 3501 for (c = 0; c < cwidth; c++) { | |
| 3502 if (data[r * cwidth * 4 + c * 4 + 3]) { | |
| 3503 top_line = r; | |
| 3504 break; | |
| 3505 } | |
| 3506 } | |
| 3507 if (top_line != -1) { | |
| 3508 break; | |
| 3509 } | |
| 3510 } | |
| 3511 | |
| 3512 // Only bother looking if we found at least one set pixel... | |
| 3513 if (top_line != -1) { | |
| 3514 | |
| 3515 //find the last line with a non-transparent pixel | |
| 3516 for (r = cheight-1; r >= top_line; r--) { | |
| 3517 for(c = 0; c < cwidth; c++) { | |
| 3518 if(data[r * cwidth * 4 + c * 4 + 3]) { | |
| 3519 bottom_line = r; | |
| 3520 break; | |
| 3521 } | |
| 3522 } | |
| 3523 if (bottom_line != -1) { | |
| 3524 break; | |
| 3525 } | |
| 3526 } | |
| 3527 // calculate height | |
| 3528 txt_height = bottom_line - top_line + 1; | |
| 3529 | |
| 3530 // Find the left-most line with a non-transparent pixel | |
| 3531 for (c = 0; c < cwidth; c++) { | |
| 3532 for (r = top_line; r <= bottom_line; r++) { | |
| 3533 if (data[r * cwidth * 4 + c * 4 + 3]) { | |
| 3534 left_line = c; | |
| 3535 break; | |
| 3536 } | |
| 3537 } | |
| 3538 if (left_line != -1) { | |
| 3539 break; | |
| 3540 } | |
| 3541 } | |
| 3542 | |
| 3543 //find the right most line with a non-transparent pixel | |
| 3544 for (c = cwidth-1; c >= left_line; c--) { | |
| 3545 for(r = top_line; r <= bottom_line; r++) { | |
| 3546 if(data[r * cwidth * 4 + c * 4 + 3]) { | |
| 3547 right_line = c; | |
| 3548 break; | |
| 3549 } | |
| 3550 } | |
| 3551 if (right_line != -1) { | |
| 3552 break; | |
| 3553 } | |
| 3554 } | |
| 3555 txt_width = right_line - left_line + 1; | |
| 3556 } | |
| 3557 | |
| 3558 //return the bounds | |
| 3559 return {bound_top: top_line, bound_bottom: bottom_line, | |
| 3560 bound_left: left_line, bound_right: right_line, width: txt_width, | |
| 3561 height: txt_height}; | |
| 3562 } | |
| 3563 | |
| 3564 //====================================================================== | |
| 3565 // start RasterizedAlphabet | |
| 3566 //====================================================================== | |
| 3567 | |
| 3568 // Rasterize Alphabet | |
| 3569 // 1) Measure width of text at default font for all symbols in alphabet | |
| 3570 // 2) sort in width ascending | |
| 3571 // 3) Drop the top and bottom 10% (designed to ignore outliers like 'W' and 'I') | |
| 3572 // 4) Calculate the average as the maximum scaling factor (designed to stop I becoming a rectangular blob). | |
| 3573 // 5) Assume scale of zero would result in width of zero, interpolate scale required to make perfect width font | |
| 3574 // 6) Draw text onto temp canvas at calculated scale | |
| 3575 // 7) Find bounds of drawn text | |
| 3576 // 8) Paint on to another canvas at the desired height (but only scaling width to fit if larger). | |
| 3577 var RasterizedAlphabet = function(alphabet, logo_scale, font, width) { | |
| 3578 "use strict"; | |
| 3579 var default_size, safety_pad, canvas, ctx, middle, baseline, widths, sizes, | |
| 3580 i, sym, size, tenpercent, avg_width, scale, | |
| 3581 target_width, target_height; | |
| 3582 //variable prototypes | |
| 3583 this.alphabet = alphabet; | |
| 3584 this.scale = logo_scale; | |
| 3585 this.sym_cache = {}; | |
| 3586 this.stack_num_cache = []; | |
| 3587 this.scale_num_cache = []; | |
| 3588 // size of canvas | |
| 3589 default_size = 60; // size of measuring canvas | |
| 3590 safety_pad = 20; // pixels to pad around so we don't miss the edges | |
| 3591 // create a canvas to do our measuring | |
| 3592 canvas = document.createElement("canvas"); | |
| 3593 if (!canvas.getContext) throw new Error("No canvas support"); | |
| 3594 canvas.width = default_size + 2 * safety_pad; | |
| 3595 canvas.height = default_size + 2 * safety_pad; | |
| 3596 middle = Math.round(canvas.width / 2); | |
| 3597 baseline = Math.round(canvas.height - safety_pad); | |
| 3598 ctx = canvas.getContext('2d'); | |
| 3599 if (!supports_text(ctx)) throw new Error("Canvas does not support text"); | |
| 3600 ctx.font = font; | |
| 3601 ctx.textAlign = "center"; | |
| 3602 ctx.translate(middle, baseline); | |
| 3603 // list of widths | |
| 3604 widths = []; | |
| 3605 sizes = []; | |
| 3606 //now measure each letter in the alphabet | |
| 3607 for (i = 0; i < alphabet.get_size_core(); ++i) { | |
| 3608 // reset the canvas | |
| 3609 ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| 3610 ctx.fillStyle = alphabet.get_colour(i); | |
| 3611 // draw the test text | |
| 3612 ctx.fillText(alphabet.get_symbol(i), 0, 0); | |
| 3613 //measure | |
| 3614 size = canvas_bounds(ctx, canvas.width, canvas.height); | |
| 3615 if (size.width === 0) throw new Error("Invisible symbol!"); | |
| 3616 widths.push(size.width); | |
| 3617 sizes[i] = size; | |
| 3618 } | |
| 3619 //sort the widths | |
| 3620 widths.sort(function(a,b) {return a - b;}); | |
| 3621 //drop 10% of the items off each end | |
| 3622 tenpercent = Math.floor(widths.length / 10); | |
| 3623 for (i = 0; i < tenpercent; ++i) { | |
| 3624 widths.pop(); | |
| 3625 widths.shift(); | |
| 3626 } | |
| 3627 //calculate average width | |
| 3628 avg_width = 0; | |
| 3629 for (i = 0; i < widths.length; ++i) { | |
| 3630 avg_width += widths[i]; | |
| 3631 } | |
| 3632 avg_width /= widths.length; | |
| 3633 // calculate the target width | |
| 3634 target_width = width * this.scale * 2; | |
| 3635 // calculate scales | |
| 3636 for (i = 0; i < alphabet.get_size_core(); ++i) { | |
| 3637 sym = alphabet.get_symbol(i); | |
| 3638 size = sizes[i]; | |
| 3639 // calculate scale | |
| 3640 scale = target_width / Math.max(avg_width, size.width); | |
| 3641 // estimate scaled height | |
| 3642 target_height = size.height * scale; | |
| 3643 // create an appropriately sized canvas | |
| 3644 canvas = document.createElement("canvas"); | |
| 3645 canvas.width = target_width; | |
| 3646 canvas.height = target_height + safety_pad * 2; | |
| 3647 // calculate the middle | |
| 3648 middle = Math.round(canvas.width / 2); | |
| 3649 // calculate the baseline | |
| 3650 baseline = Math.round(canvas.height - safety_pad); | |
| 3651 // get the context and prepare to draw the rasterized text | |
| 3652 ctx = canvas.getContext('2d'); | |
| 3653 ctx.font = font; | |
| 3654 ctx.fillStyle = alphabet.get_colour(i); | |
| 3655 ctx.textAlign = "center"; | |
| 3656 ctx.translate(middle, baseline); | |
| 3657 ctx.save(); | |
| 3658 ctx.scale(scale, scale); | |
| 3659 // draw the text | |
| 3660 ctx.fillText(sym, 0, 0); | |
| 3661 ctx.restore(); | |
| 3662 this.sym_cache[sym] = {"image": canvas, "size": canvas_bounds(ctx, canvas.width, canvas.height)}; | |
| 3663 } | |
| 3664 }; | |
| 3665 | |
| 3666 RasterizedAlphabet.prototype.get_alphabet = function() { | |
| 3667 return this.alphabet; | |
| 3668 }; | |
| 3669 | |
| 3670 RasterizedAlphabet.prototype.get_scale = function() { | |
| 3671 return this.scale; | |
| 3672 }; | |
| 3673 | |
| 3674 RasterizedAlphabet.prototype.draw_stack_sym = function(ctx, letter, dx, dy, dWidth, dHeight) { | |
| 3675 "use strict"; | |
| 3676 var entry, image, size; | |
| 3677 entry = this.sym_cache[letter]; | |
| 3678 image = entry.image; | |
| 3679 size = entry.size; | |
| 3680 ctx.drawImage(image, 0, size.bound_top -1, image.width, size.height+1, dx, dy, dWidth, dHeight); | |
| 3681 }; | |
| 3682 | |
| 3683 RasterizedAlphabet.prototype.draw_stack_num = function(ctx, font, stack_width, index) { | |
| 3684 var image, image_ctx, text_length; | |
| 3685 if (index >= this.stack_num_cache.length) { | |
| 3686 image = document.createElement("canvas"); | |
| 3687 // measure the text | |
| 3688 image_ctx = image.getContext('2d'); | |
| 3689 image_ctx.save(); | |
| 3690 image_ctx.font = font; | |
| 3691 text_length = image_ctx.measureText("" + (index + 1)).width; | |
| 3692 image_ctx.restore(); | |
| 3693 // resize the canvas to fit | |
| 3694 image.width = Math.ceil(stack_width); | |
| 3695 image.height = Math.ceil(text_length); | |
| 3696 // draw the text | |
| 3697 image_ctx = image.getContext('2d'); | |
| 3698 image_ctx.translate(Math.round(stack_width / 2), 0); | |
| 3699 image_ctx.font = font; | |
| 3700 image_ctx.textBaseline = "middle"; | |
| 3701 image_ctx.textAlign = "right"; | |
| 3702 image_ctx.rotate(-(Math.PI / 2)); | |
| 3703 image_ctx.fillText("" + (index + 1), 0, 0); | |
| 3704 this.stack_num_cache[index] = image; | |
| 3705 } else { | |
| 3706 image = this.stack_num_cache[index]; | |
| 3707 } | |
| 3708 ctx.drawImage(image, 0, 0); | |
| 3709 } | |
| 3710 | |
| 3711 RasterizedAlphabet.prototype.draw_scale_num = function(ctx, font, num) { | |
| 3712 var image, image_ctx, text_size, m_length; | |
| 3713 if (num >= this.scale_num_cache.length) { | |
| 3714 image = document.createElement("canvas"); | |
| 3715 // measure the text | |
| 3716 image_ctx = image.getContext('2d'); | |
| 3717 image_ctx.font = font; | |
| 3718 text_size = image_ctx.measureText("" + num); | |
| 3719 if (text_size.actualBoundingBoxAscent && text_size.actualBoundingBoxDesent) { | |
| 3720 // resize the canvas to fit | |
| 3721 image.width = Math.ceil(text_size.width); | |
| 3722 image.height = Math.ceil(text_size.actualBoundingBoxAscent + text_size.actualBoundingBoxDesent); | |
| 3723 // draw the text | |
| 3724 image_ctx = image.getContext('2d'); | |
| 3725 image_ctx.font = font; | |
| 3726 image_ctx.textAlign = "right"; | |
| 3727 image_ctx.fillText("" + num, image.width, text_size.actualBoundingBoxAscent); | |
| 3728 } else { | |
| 3729 // measure width of 'm' to approximate height, we double it later anyway | |
| 3730 m_length = image_ctx.measureText("m").width; | |
| 3731 // resize the canvas to fit | |
| 3732 image.width = Math.ceil(text_size.width); | |
| 3733 image.height = Math.ceil(2 * m_length); | |
| 3734 // draw the text | |
| 3735 image_ctx = image.getContext('2d'); | |
| 3736 image_ctx.font = font; | |
| 3737 image_ctx.textAlign = "right"; | |
| 3738 image_ctx.textBaseline = "middle"; | |
| 3739 image_ctx.fillText("" + num, image.width, m_length); | |
| 3740 } | |
| 3741 this.scale_num_cache[num] = image; | |
| 3742 } else { | |
| 3743 image = this.scale_num_cache[num]; | |
| 3744 } | |
| 3745 ctx.drawImage(image, -image.width, -Math.round(image.height / 2)) | |
| 3746 } | |
| 3747 | |
| 3748 //====================================================================== | |
| 3749 // end RasterizedAlphabet | |
| 3750 //====================================================================== | |
| 3751 | |
| 3752 //====================================================================== | |
| 3753 // start LogoMetrics object | |
| 3754 //====================================================================== | |
| 3755 | |
| 3756 var LogoMetrics = function(ctx, logo_columns, logo_rows, has_names, has_finetext, x_axis, y_axis) { | |
| 3757 "use strict"; | |
| 3758 var i, row_height; | |
| 3759 //variable prototypes | |
| 3760 this.pad_top = (has_names ? 5 : 0); | |
| 3761 this.pad_left = (y_axis ? 10 : 0); | |
| 3762 this.pad_right = (has_finetext ? 15 : 0); | |
| 3763 this.pad_bottom = 0; | |
| 3764 this.pad_middle = 20; | |
| 3765 this.name_height = 14; | |
| 3766 this.name_font = "bold " + this.name_height + "px Times, sans-serif"; | |
| 3767 this.name_spacer = 0; | |
| 3768 this.y_axis = y_axis; | |
| 3769 this.y_label = "bits"; | |
| 3770 this.y_label_height = 12; | |
| 3771 this.y_label_font = "bold " + this.y_label_height + "px Helvetica, sans-serif"; | |
| 3772 this.y_label_spacer = 3; | |
| 3773 this.y_num_height = 12; | |
| 3774 this.y_num_width = 0; | |
| 3775 this.y_num_font = "bold " + this.y_num_height + "px Helvetica, sans-serif"; | |
| 3776 this.y_tic_width = 5; | |
| 3777 this.stack_pad_left = 0; | |
| 3778 this.stack_font = "bold 25px Helvetica, sans-serif"; | |
| 3779 this.stack_height = 90; | |
| 3780 this.stack_width = 26; | |
| 3781 this.stacks_pad_right = 5; | |
| 3782 this.x_axis = x_axis; | |
| 3783 this.x_num_above = 2; | |
| 3784 this.x_num_height = 12; | |
| 3785 this.x_num_width = 0; | |
| 3786 this.x_num_font = "bold " + this.x_num_height + "px Helvetica, sans-serif"; | |
| 3787 this.fine_txt_height = 6; | |
| 3788 this.fine_txt_above = 2; | |
| 3789 this.fine_txt_font = "normal " + this.fine_txt_height + "px Helvetica, sans-serif"; | |
| 3790 this.letter_metrics = new Array(); | |
| 3791 this.summed_width = 0; | |
| 3792 this.summed_height = 0; | |
| 3793 //calculate the width of the y axis numbers | |
| 3794 ctx.font = this.y_num_font; | |
| 3795 for (i = 0; i <= 2; i++) { | |
| 3796 this.y_num_width = Math.max(this.y_num_width, ctx.measureText("" + i).width); | |
| 3797 } | |
| 3798 //calculate the width of the x axis numbers (but they are rotated so it becomes height) | |
| 3799 if (x_axis == 1) { | |
| 3800 ctx.font = this.x_num_font; | |
| 3801 for (i = 1; i <= logo_columns; i++) { | |
| 3802 this.x_num_width = Math.max(this.x_num_width, ctx.measureText("" + i).width); | |
| 3803 } | |
| 3804 } else if (x_axis == 0) { | |
| 3805 this.x_num_height = 4; | |
| 3806 this.x_num_width = 4; | |
| 3807 } else { | |
| 3808 this.x_num_height = 0; | |
| 3809 this.x_num_width = 0; | |
| 3810 } | |
| 3811 | |
| 3812 //calculate how much vertical space we want to draw this | |
| 3813 //first we add the padding at the top and bottom since that's always there | |
| 3814 this.summed_height += this.pad_top + this.pad_bottom; | |
| 3815 //all except the last row have the same amount of space allocated to them | |
| 3816 if (logo_rows > 1) { | |
| 3817 row_height = this.stack_height + this.pad_middle; | |
| 3818 if (has_names) { | |
| 3819 row_height += this.name_height; | |
| 3820 //the label is allowed to overlap into the spacer | |
| 3821 row_height += Math.max(this.y_num_height/2, this.name_spacer); | |
| 3822 //the label is allowed to overlap the space used by the other label | |
| 3823 row_height += Math.max(this.y_num_height/2, this.x_num_height + this.x_num_above); | |
| 3824 } else { | |
| 3825 row_height += this.y_num_height/2; | |
| 3826 //the label is allowed to overlap the space used by the other label | |
| 3827 row_height += Math.max(this.y_num_height/2, this.x_num_height + this.x_num_above); | |
| 3828 } | |
| 3829 this.summed_height += row_height * (logo_rows - 1); | |
| 3830 } | |
| 3831 //the last row has the name and fine text below it but no padding | |
| 3832 this.summed_height += this.stack_height + (this.y_axis ? this.y_num_height/2 : 0); | |
| 3833 | |
| 3834 var fine_txt_total = (has_finetext ? this.fine_txt_height + this.fine_txt_above : 0); | |
| 3835 if (has_names) { | |
| 3836 this.summed_height += fine_txt_total + this.name_height; | |
| 3837 this.summed_height += Math.max((this.y_axis ? this.y_num_height/2 : 0), | |
| 3838 this.x_num_height + this.x_num_above + this.name_spacer); | |
| 3839 } else { | |
| 3840 this.summed_height += Math.max((this.y_axis ? this.y_num_height/2 : 0), | |
| 3841 this.x_num_height + this.x_num_above + fine_txt_total); | |
| 3842 } | |
| 3843 | |
| 3844 //calculate how much horizontal space we want to draw this | |
| 3845 //first add the padding at the left and right since that's always there | |
| 3846 this.summed_width += this.pad_left + this.pad_right; | |
| 3847 if (this.y_axis) { | |
| 3848 //add on the space for the y-axis label | |
| 3849 this.summed_width += this.y_label_height + this.y_label_spacer; | |
| 3850 //add on the space for the y-axis | |
| 3851 this.summed_width += this.y_num_width + this.y_tic_width; | |
| 3852 } | |
| 3853 //add on the space for the stacks | |
| 3854 this.summed_width += (this.stack_pad_left + this.stack_width) * logo_columns; | |
| 3855 //add on the padding after the stacks (an offset from the fine text) | |
| 3856 this.summed_width += this.stacks_pad_right; | |
| 3857 | |
| 3858 }; | |
| 3859 | |
| 3860 //====================================================================== | |
| 3861 // end LogoMetrics object | |
| 3862 //====================================================================== | |
| 3863 | |
| 3864 //found this trick at http://talideon.com/weblog/2005/02/detecting-broken-images-js.cfm | |
| 3865 function image_ok(img) { | |
| 3866 "use strict"; | |
| 3867 // During the onload event, IE correctly identifies any images that | |
| 3868 // weren't downloaded as not complete. Others should too. Gecko-based | |
| 3869 // browsers act like NS4 in that they report this incorrectly. | |
| 3870 if (!img.complete) { | |
| 3871 return false; | |
| 3872 } | |
| 3873 // However, they do have two very useful properties: naturalWidth and | |
| 3874 // naturalHeight. These give the true size of the image. If it failed | |
| 3875 // to load, either of these should be zero. | |
| 3876 if (typeof img.naturalWidth !== "undefined" && img.naturalWidth === 0) { | |
| 3877 return false; | |
| 3878 } | |
| 3879 // No other way of checking: assume it's ok. | |
| 3880 return true; | |
| 3881 } | |
| 3882 | |
| 3883 function supports_text(ctx) { | |
| 3884 "use strict"; | |
| 3885 if (!ctx.fillText) { | |
| 3886 return false; | |
| 3887 } | |
| 3888 if (!ctx.measureText) { | |
| 3889 return false; | |
| 3890 } | |
| 3891 return true; | |
| 3892 } | |
| 3893 | |
| 3894 //draws the scale, returns the width | |
| 3895 function draw_scale(ctx, metrics, alphabet_ic, raster) { | |
| 3896 "use strict"; | |
| 3897 var tic_height, i; | |
| 3898 tic_height = metrics.stack_height / alphabet_ic; | |
| 3899 ctx.save(); | |
| 3900 ctx.translate(metrics.y_label_height, metrics.y_num_height/2); | |
| 3901 //draw the axis label | |
| 3902 ctx.save(); | |
| 3903 ctx.font = metrics.y_label_font; | |
| 3904 ctx.translate(0, metrics.stack_height/2); | |
| 3905 ctx.rotate(-(Math.PI / 2)); | |
| 3906 ctx.textAlign = "center"; | |
| 3907 ctx.fillText("bits", 0, 0); | |
| 3908 ctx.restore(); | |
| 3909 | |
| 3910 ctx.translate(metrics.y_label_spacer + metrics.y_num_width, 0); | |
| 3911 | |
| 3912 //draw the axis tics | |
| 3913 ctx.save(); | |
| 3914 ctx.translate(0, metrics.stack_height); | |
| 3915 for (i = 0; i <= alphabet_ic; i++) { | |
| 3916 //draw the number | |
| 3917 ctx.save(); | |
| 3918 ctx.translate(-1, 0); | |
| 3919 raster.draw_scale_num(ctx, metrics.y_num_font, i); | |
| 3920 ctx.restore(); | |
| 3921 //draw the tic | |
| 3922 ctx.fillRect(0, -1, metrics.y_tic_width, 2); | |
| 3923 //prepare for next tic | |
| 3924 ctx.translate(0, -tic_height); | |
| 3925 } | |
| 3926 ctx.restore(); | |
| 3927 | |
| 3928 ctx.fillRect(metrics.y_tic_width - 2, 0, 2, metrics.stack_height) | |
| 3929 | |
| 3930 ctx.restore(); | |
| 3931 } | |
| 3932 | |
| 3933 function draw_stack_num(ctx, metrics, row_index, raster) { | |
| 3934 "use strict"; | |
| 3935 ctx.save(); | |
| 3936 ctx.translate(0, Math.round(metrics.stack_height + metrics.x_num_above)); | |
| 3937 if (metrics.x_axis == 1) { | |
| 3938 raster.draw_stack_num(ctx, metrics.x_num_font, metrics.stack_width, row_index); | |
| 3939 } else if (metrics.x_axis == 0) { | |
| 3940 // draw dots instead of the numbers (good for small logos) | |
| 3941 ctx.beginPath(); | |
| 3942 var radius = Math.round(metrics.x_num_height / 2); | |
| 3943 ctx.arc(Math.round(metrics.stack_width / 2), radius, radius, 0, 2 * Math.PI, false); | |
| 3944 ctx.fill(); | |
| 3945 } | |
| 3946 ctx.restore(); | |
| 3947 } | |
| 3948 | |
| 3949 function draw_stack(ctx, metrics, symbols, raster) { | |
| 3950 "use strict"; | |
| 3951 var preferred_pad, sym_min, i, sym, sym_height, pad; | |
| 3952 preferred_pad = 0; | |
| 3953 sym_min = 5; | |
| 3954 | |
| 3955 ctx.save();//1 | |
| 3956 ctx.translate(0, metrics.stack_height); | |
| 3957 for (i = 0; i < symbols.length; i++) { | |
| 3958 sym = symbols[i]; | |
| 3959 sym_height = metrics.stack_height * sym.get_scale(); | |
| 3960 | |
| 3961 pad = preferred_pad; | |
| 3962 if (sym_height - pad < sym_min) { | |
| 3963 pad = Math.min(pad, Math.max(0, sym_height - sym_min)); | |
| 3964 } | |
| 3965 sym_height -= pad; | |
| 3966 | |
| 3967 //translate to the correct position | |
| 3968 ctx.translate(0, -(pad/2 + sym_height)); | |
| 3969 | |
| 3970 //draw | |
| 3971 raster.draw_stack_sym(ctx, sym.get_symbol(), 0, 0, metrics.stack_width, sym_height); | |
| 3972 //translate past the padding | |
| 3973 ctx.translate(0, -(pad/2)); | |
| 3974 } | |
| 3975 ctx.restore();//1 | |
| 3976 } | |
| 3977 | |
| 3978 function draw_dashed_line(ctx, pattern, start, x1, y1, x2, y2) { | |
| 3979 "use strict"; | |
| 3980 var x, y, len, i, dx, dy, tlen, theta, mulx, muly, lx, ly; | |
| 3981 dx = x2 - x1; | |
| 3982 dy = y2 - y1; | |
| 3983 tlen = Math.pow(dx*dx + dy*dy, 0.5); | |
| 3984 theta = Math.atan2(dy,dx); | |
| 3985 mulx = Math.cos(theta); | |
| 3986 muly = Math.sin(theta); | |
| 3987 lx = []; | |
| 3988 ly = []; | |
| 3989 for (i = 0; i < pattern; ++i) { | |
| 3990 lx.push(pattern[i] * mulx); | |
| 3991 ly.push(pattern[i] * muly); | |
| 3992 } | |
| 3993 i = start; | |
| 3994 x = x1; | |
| 3995 y = y1; | |
| 3996 len = 0; | |
| 3997 ctx.beginPath(); | |
| 3998 while (len + pattern[i] < tlen) { | |
| 3999 ctx.moveTo(x, y); | |
| 4000 x += lx[i]; | |
| 4001 y += ly[i]; | |
| 4002 ctx.lineTo(x, y); | |
| 4003 len += pattern[i]; | |
| 4004 i = (i + 1) % pattern.length; | |
| 4005 x += lx[i]; | |
| 4006 y += ly[i]; | |
| 4007 len += pattern[i]; | |
| 4008 i = (i + 1) % pattern.length; | |
| 4009 } | |
| 4010 if (len < tlen) { | |
| 4011 ctx.moveTo(x, y); | |
| 4012 x += mulx * (tlen - len); | |
| 4013 y += muly * (tlen - len); | |
| 4014 ctx.lineTo(x, y); | |
| 4015 } | |
| 4016 ctx.stroke(); | |
| 4017 } | |
| 4018 | |
| 4019 function draw_trim_background(ctx, metrics, left_start, left_end, left_divider, right_start, right_end, right_divider) { | |
| 4020 "use strict"; | |
| 4021 var left_size = left_end - left_start; | |
| 4022 var right_size = right_end - right_start; | |
| 4023 var line_x; | |
| 4024 | |
| 4025 ctx.save();//s8 | |
| 4026 ctx.fillStyle = "rgb(240, 240, 240)"; | |
| 4027 if (left_size > 0) { | |
| 4028 ctx.fillRect(left_start * metrics.stack_width, 0, left_size * metrics.stack_width, metrics.stack_height); | |
| 4029 } | |
| 4030 if (right_size > 0) { | |
| 4031 ctx.fillRect(right_start * metrics.stack_width, 0, right_size * metrics.stack_width, metrics.stack_height); | |
| 4032 } | |
| 4033 ctx.fillStyle = "rgb(51, 51, 51)"; | |
| 4034 if (left_size > 0 && left_divider) { | |
| 4035 line_x = (left_end * metrics.stack_width) - 0.5; | |
| 4036 draw_dashed_line(ctx, [3], 0, line_x, 0, line_x, metrics.stack_height); | |
| 4037 } | |
| 4038 if (right_size > 0 && right_divider) { | |
| 4039 line_x = (right_start * metrics.stack_width) + 0.5; | |
| 4040 draw_dashed_line(ctx, [3], 0, line_x, 0, line_x, metrics.stack_height); | |
| 4041 } | |
| 4042 ctx.restore();//s8 | |
| 4043 } | |
| 4044 | |
| 4045 function size_logo_on_canvas(logo, canvas, show_names, scale) { | |
| 4046 "use strict"; | |
| 4047 var draw_name, draw_finetext, metrics; | |
| 4048 draw_name = (typeof show_names === "boolean" ? show_names : (logo.get_rows() > 1)); | |
| 4049 draw_finetext = (logo.fine_text.length > 0); | |
| 4050 if (canvas.width !== 0 && canvas.height !== 0) { | |
| 4051 return; | |
| 4052 } | |
| 4053 metrics = new LogoMetrics(canvas.getContext('2d'), | |
| 4054 logo.get_xlate_columns(), logo.get_rows(), draw_name, draw_finetext, logo.x_axis, logo.y_axis); | |
| 4055 if (typeof scale == "number") { | |
| 4056 //resize the canvas to fit the scaled logo | |
| 4057 canvas.width = metrics.summed_width * scale; | |
| 4058 canvas.height = metrics.summed_height * scale; | |
| 4059 } else { | |
| 4060 if (canvas.width === 0 && canvas.height === 0) { | |
| 4061 canvas.width = metrics.summed_width; | |
| 4062 canvas.height = metrics.summed_height; | |
| 4063 } else if (canvas.width === 0) { | |
| 4064 canvas.width = metrics.summed_width * (canvas.height / metrics.summed_height); | |
| 4065 } else if (canvas.height === 0) { | |
| 4066 canvas.height = metrics.summed_height * (canvas.width / metrics.summed_width); | |
| 4067 } | |
| 4068 } | |
| 4069 } | |
| 4070 | |
| 4071 function draw_logo_on_canvas(logo, canvas, show_names, scale) { | |
| 4072 "use strict"; | |
| 4073 var i, draw_name, draw_finetext, ctx, metrics, raster, pspm_i, pspm, | |
| 4074 offset, col_index, motif_position, ssc; | |
| 4075 ssc = false; | |
| 4076 draw_name = (typeof show_names === "boolean" ? show_names : (logo.get_rows() > 1)); | |
| 4077 draw_finetext = (logo.fine_text.length > 0); | |
| 4078 ctx = canvas.getContext('2d'); | |
| 4079 //assume that the user wants the canvas scaled equally so calculate what the best width for this image should be | |
| 4080 metrics = new LogoMetrics(ctx, logo.get_xlate_columns(), logo.get_rows(), draw_name, draw_finetext, logo.x_axis, logo.y_axis); | |
| 4081 if (typeof scale == "number") { | |
| 4082 //resize the canvas to fit the scaled logo | |
| 4083 canvas.width = metrics.summed_width * scale; | |
| 4084 canvas.height = metrics.summed_height * scale; | |
| 4085 } else { | |
| 4086 if (canvas.width === 0 && canvas.height === 0) { | |
| 4087 scale = 1; | |
| 4088 canvas.width = metrics.summed_width; | |
| 4089 canvas.height = metrics.summed_height; | |
| 4090 } else if (canvas.width === 0) { | |
| 4091 scale = canvas.height / metrics.summed_height; | |
| 4092 canvas.width = metrics.summed_width * scale; | |
| 4093 } else if (canvas.height === 0) { | |
| 4094 scale = canvas.width / metrics.summed_width; | |
| 4095 canvas.height = metrics.summed_height * scale; | |
| 4096 } else { | |
| 4097 scale = Math.min(canvas.width / metrics.summed_width, canvas.height / metrics.summed_height); | |
| 4098 } | |
| 4099 } | |
| 4100 // cache the raster based on the assumption that we will be drawing a lot | |
| 4101 // of logos the same size and alphabet | |
| 4102 if (typeof draw_logo_on_canvas.raster_cache === "undefined") { | |
| 4103 draw_logo_on_canvas.raster_cache = []; | |
| 4104 } | |
| 4105 for (i = 0; i < draw_logo_on_canvas.raster_cache.length; i++) { | |
| 4106 raster = draw_logo_on_canvas.raster_cache[i]; | |
| 4107 if (raster.get_alphabet().equals(logo.alphabet) && | |
| 4108 Math.abs(raster.get_scale() - scale) < 0.1) break; | |
| 4109 raster = null; | |
| 4110 } | |
| 4111 if (raster == null) { | |
| 4112 raster = new RasterizedAlphabet(logo.alphabet, scale, metrics.stack_font, metrics.stack_width); | |
| 4113 draw_logo_on_canvas.raster_cache.push(raster); | |
| 4114 } | |
| 4115 ctx = canvas.getContext('2d'); | |
| 4116 ctx.save();//s1 | |
| 4117 ctx.scale(scale, scale); | |
| 4118 ctx.save();//s2 | |
| 4119 ctx.save();//s7 | |
| 4120 //create margin | |
| 4121 ctx.translate(Math.round(metrics.pad_left), Math.round(metrics.pad_top)); | |
| 4122 for (pspm_i = 0; pspm_i < logo.get_rows(); ++pspm_i) { | |
| 4123 pspm = logo.get_pspm(pspm_i); | |
| 4124 offset = logo.get_offset(pspm_i); | |
| 4125 //optionally draw name if this isn't the last row or is the only row | |
| 4126 if (draw_name && (logo.get_rows() == 1 || pspm_i != (logo.get_rows()-1))) { | |
| 4127 ctx.save();//s4 | |
| 4128 ctx.translate(Math.round(metrics.summed_width/2), Math.round(metrics.name_height)); | |
| 4129 ctx.font = metrics.name_font; | |
| 4130 ctx.textAlign = "center"; | |
| 4131 ctx.fillText(pspm.name, 0, 0); | |
| 4132 ctx.restore();//s4 | |
| 4133 ctx.translate(0, Math.round(metrics.name_height + | |
| 4134 Math.min(0, metrics.name_spacer - metrics.y_num_height/2))); | |
| 4135 } | |
| 4136 //draw scale | |
| 4137 if (logo.y_axis) draw_scale(ctx, metrics, logo.alphabet.get_ic(), raster); | |
| 4138 ctx.save();//s5 | |
| 4139 //translate across past the scale | |
| 4140 if (logo.y_axis) { | |
| 4141 ctx.translate(Math.round(metrics.y_label_height + metrics.y_label_spacer + | |
| 4142 metrics.y_num_width + metrics.y_tic_width), Math.round(metrics.y_num_height / 2)); | |
| 4143 } | |
| 4144 //draw the trimming background | |
| 4145 if (pspm.get_left_trim() > 0 || pspm.get_right_trim() > 0) { | |
| 4146 var left_start = offset * logo.get_xlate_nsyms(); | |
| 4147 var left_end = (offset + pspm.get_left_trim()) * logo.get_xlate_nsyms(); | |
| 4148 var left_divider = true; | |
| 4149 if (left_end < logo.get_xlate_start() || left_start > logo.get_xlate_end()) { | |
| 4150 // no overlap | |
| 4151 left_start = 0; | |
| 4152 left_end = 0; | |
| 4153 left_divider = false; | |
| 4154 } else { | |
| 4155 if (left_start < logo.get_xlate_start()) { | |
| 4156 left_start = logo.get_xlate_start(); | |
| 4157 } | |
| 4158 if (left_end > logo.get_xlate_end()) { | |
| 4159 left_end = logo.get_xlate_end(); | |
| 4160 left_divider = false; | |
| 4161 } | |
| 4162 left_start -= logo.get_xlate_start(); | |
| 4163 left_end -= logo.get_xlate_start(); | |
| 4164 if (left_end < left_start) { | |
| 4165 left_start = 0; | |
| 4166 left_end = 0; | |
| 4167 left_divider = false; | |
| 4168 } | |
| 4169 } | |
| 4170 var right_end = (offset + pspm.get_motif_length()) * logo.get_xlate_nsyms(); | |
| 4171 //var right_start = right_end - (pspm.get_left_trim() * logo.get_xlate_nsyms()); | |
| 4172 var right_start = right_end - (pspm.get_right_trim() * logo.get_xlate_nsyms()); | |
| 4173 var right_divider = true; | |
| 4174 if (right_end < logo.get_xlate_start() || right_start > logo.get_xlate_end()) { | |
| 4175 // no overlap | |
| 4176 right_start = 0; | |
| 4177 right_end = 0; | |
| 4178 right_divider = false; | |
| 4179 } else { | |
| 4180 if (right_start < logo.get_xlate_start()) { | |
| 4181 right_start = logo.get_xlate_start(); | |
| 4182 right_divider = false; | |
| 4183 } | |
| 4184 if (right_end > logo.get_xlate_end()) { | |
| 4185 right_end = logo.get_xlate_end(); | |
| 4186 } | |
| 4187 right_start -= logo.get_xlate_start(); | |
| 4188 right_end -= logo.get_xlate_start(); | |
| 4189 if (right_end < right_start) { | |
| 4190 right_start = 0; | |
| 4191 right_end = 0; | |
| 4192 right_divider = false; | |
| 4193 } | |
| 4194 } | |
| 4195 draw_trim_background(ctx, metrics, left_start, left_end, left_divider, right_start, right_end, right_divider); | |
| 4196 } | |
| 4197 //draw letters | |
| 4198 var xlate_col; | |
| 4199 for (xlate_col = logo.get_xlate_start(); xlate_col < logo.get_xlate_end(); xlate_col++) { | |
| 4200 ctx.translate(metrics.stack_pad_left,0); | |
| 4201 col_index = Math.floor(xlate_col / logo.get_xlate_nsyms()); | |
| 4202 if (xlate_col % logo.get_xlate_nsyms() == 0) { | |
| 4203 if (col_index >= offset && col_index < (offset + pspm.get_motif_length())) { | |
| 4204 motif_position = col_index - offset; | |
| 4205 draw_stack_num(ctx, metrics, motif_position, raster); | |
| 4206 draw_stack(ctx, metrics, pspm.get_stack(motif_position, logo.alphabet, ssc), raster); | |
| 4207 } | |
| 4208 } else { | |
| 4209 if (col_index >= offset && col_index < (offset + pspm.get_motif_length())) { | |
| 4210 ctx.save();// s5.1 | |
| 4211 ctx.translate(0, Math.round(metrics.stack_height)); | |
| 4212 // TODO draw a dot or dash or something to indicate continuity of the motif | |
| 4213 ctx.restore(); //s5.1 | |
| 4214 } | |
| 4215 } | |
| 4216 ctx.translate(Math.round(metrics.stack_width), 0); | |
| 4217 } | |
| 4218 ctx.restore();//s5 | |
| 4219 ////optionally draw name if this is the last row but isn't the only row | |
| 4220 if (draw_name && (logo.get_rows() != 1 && pspm_i == (logo.get_rows()-1))) { | |
| 4221 //translate vertically past the stack and axis's | |
| 4222 ctx.translate(0, metrics.y_num_height/2 + metrics.stack_height + | |
| 4223 Math.max(metrics.y_num_height/2, metrics.x_num_above + metrics.x_num_width + metrics.name_spacer)); | |
| 4224 | |
| 4225 ctx.save();//s6 | |
| 4226 ctx.translate(metrics.summed_width/2, metrics.name_height); | |
| 4227 ctx.font = metrics.name_font; | |
| 4228 ctx.textAlign = "center"; | |
| 4229 ctx.fillText(pspm.name, 0, 0); | |
| 4230 ctx.restore();//s6 | |
| 4231 ctx.translate(0, metrics.name_height); | |
| 4232 } else { | |
| 4233 //translate vertically past the stack and axis's | |
| 4234 ctx.translate(0, metrics.y_num_height/2 + metrics.stack_height + | |
| 4235 Math.max(metrics.y_num_height/2, metrics.x_num_above + metrics.x_num_width)); | |
| 4236 } | |
| 4237 //if not the last row then add middle padding | |
| 4238 if (pspm_i != (logo.get_rows() -1)) { | |
| 4239 ctx.translate(0, metrics.pad_middle); | |
| 4240 } | |
| 4241 } | |
| 4242 ctx.restore();//s7 | |
| 4243 if (logo.fine_text.length > 0) { | |
| 4244 ctx.translate(metrics.summed_width - metrics.pad_right, metrics.summed_height - metrics.pad_bottom); | |
| 4245 ctx.font = metrics.fine_txt_font; | |
| 4246 ctx.textAlign = "right"; | |
| 4247 ctx.fillText(logo.fine_text, 0,0); | |
| 4248 } | |
| 4249 ctx.restore();//s2 | |
| 4250 ctx.restore();//s1 | |
| 4251 } | |
| 4252 | |
| 4253 function create_canvas(c_width, c_height, c_id, c_title, c_display) { | |
| 4254 "use strict"; | |
| 4255 var canvas = document.createElement("canvas"); | |
| 4256 //check for canvas support before attempting anything | |
| 4257 if (!canvas.getContext) { | |
| 4258 return null; | |
| 4259 } | |
| 4260 var ctx = canvas.getContext('2d'); | |
| 4261 //check for html5 text drawing support | |
| 4262 if (!supports_text(ctx)) { | |
| 4263 return null; | |
| 4264 } | |
| 4265 //size the canvas | |
| 4266 canvas.width = c_width; | |
| 4267 canvas.height = c_height; | |
| 4268 canvas.id = c_id; | |
| 4269 canvas.title = c_title; | |
| 4270 canvas.style.display = c_display; | |
| 4271 return canvas; | |
| 4272 } | |
| 4273 | |
| 4274 function logo_1(alphabet, fine_text, pspm) { | |
| 4275 "use strict"; | |
| 4276 var logo = new Logo(alphabet, fine_text); | |
| 4277 logo.add_pspm(pspm); | |
| 4278 return logo; | |
| 4279 } | |
| 4280 | |
| 4281 function logo_2(alphabet, fine_text, target, query, query_offset) { | |
| 4282 "use strict"; | |
| 4283 var logo = new Logo(alphabet, fine_text); | |
| 4284 if (query_offset < 0) { | |
| 4285 logo.add_pspm(target, -query_offset); | |
| 4286 logo.add_pspm(query); | |
| 4287 } else { | |
| 4288 logo.add_pspm(target); | |
| 4289 logo.add_pspm(query, query_offset); | |
| 4290 } | |
| 4291 return logo; | |
| 4292 } | |
| 4293 | |
| 4294 /* | |
| 4295 * Specifies an alternate source for an image. | |
| 4296 * If the image with the image_id specified has | |
| 4297 * not loaded then a generated logo will be used | |
| 4298 * to replace it. | |
| 4299 * | |
| 4300 * Note that the image must either have dimensions | |
| 4301 * or a scale must be set. | |
| 4302 */ | |
| 4303 function alternate_logo(logo, image_id, scale) { | |
| 4304 "use strict"; | |
| 4305 var image = document.getElementById(image_id); | |
| 4306 if (!image) { | |
| 4307 alert("Can't find specified image id (" + image_id + ")"); | |
| 4308 return; | |
| 4309 } | |
| 4310 //if the image has loaded then there is no reason to use the canvas | |
| 4311 if (image_ok(image)) { | |
| 4312 return; | |
| 4313 } | |
| 4314 //the image has failed to load so replace it with a canvas if we can. | |
| 4315 var canvas = create_canvas(image.width, image.height, image_id, image.title, image.style.display); | |
| 4316 if (canvas === null) { | |
| 4317 return; | |
| 4318 } | |
| 4319 //draw the logo on the canvas | |
| 4320 draw_logo_on_canvas(logo, canvas, null, scale); | |
| 4321 //replace the image with the canvas | |
| 4322 image.parentNode.replaceChild(canvas, image); | |
| 4323 } | |
| 4324 | |
| 4325 /* | |
| 4326 * Specifes that the element with the specified id | |
| 4327 * should be replaced with a generated logo. | |
| 4328 */ | |
| 4329 function replace_logo(logo, replace_id, scale, title_txt, display_style) { | |
| 4330 "use strict"; | |
| 4331 var element = document.getElementById(replace_id); | |
| 4332 if (!replace_id) { | |
| 4333 alert("Can't find specified id (" + replace_id + ")"); | |
| 4334 return; | |
| 4335 } | |
| 4336 //found the element! | |
| 4337 var canvas = create_canvas(50, 120, replace_id, title_txt, display_style); | |
| 4338 if (canvas === null) { | |
| 4339 return; | |
| 4340 } | |
| 4341 //draw the logo on the canvas | |
| 4342 draw_logo_on_canvas(logo, canvas, null, scale); | |
| 4343 //replace the element with the canvas | |
| 4344 element.parentNode.replaceChild(canvas, element); | |
| 4345 } | |
| 4346 | |
| 4347 /* | |
| 4348 * Fast string trimming implementation found at | |
| 4349 * http://blog.stevenlevithan.com/archives/faster-trim-javascript | |
| 4350 * | |
| 4351 * Note that regex is good at removing leading space but | |
| 4352 * bad at removing trailing space as it has to first go through | |
| 4353 * the whole string. | |
| 4354 */ | |
| 4355 function trim (str) { | |
| 4356 "use strict"; | |
| 4357 var ws, i; | |
| 4358 str = str.replace(/^\s\s*/, ''); | |
| 4359 ws = /\s/; i = str.length; | |
| 4360 while (ws.test(str.charAt(--i))); | |
| 4361 return str.slice(0, i + 1); | |
| 4362 } | |
| 4363 </script> | |
| 4364 <script> | |
| 4365 | |
| 4366 // PRIVATE GLOBAL (uhoh) | |
| 4367 var _block_colour_lookup = {}; | |
| 4368 | |
| 4369 function block_colour(index) { | |
| 4370 function hsl2rgb(hue, saturation, lightness) { | |
| 4371 "use strict"; | |
| 4372 function _hue(p, q, t) { | |
| 4373 "use strict"; | |
| 4374 if (t < 0) t += 1; | |
| 4375 else if (t > 1) t -= 1; | |
| 4376 if (t < (1.0 / 6.0)) { | |
| 4377 return p + ((q - p) * 6.0 * t); | |
| 4378 } else if (t < 0.5) { | |
| 4379 return q; | |
| 4380 } else if (t < (2.0 / 3.0)) { | |
| 4381 return p + ((q - p) * ((2.0 / 3.0) - t) * 6.0); | |
| 4382 } else { | |
| 4383 return p; | |
| 4384 } | |
| 4385 } | |
| 4386 function _pad_hex(value) { | |
| 4387 var hex = Math.round(value * 255).toString(16); | |
| 4388 if (hex.length < 2) hex = "0" + hex; | |
| 4389 return hex; | |
| 4390 } | |
| 4391 var r, g, b, p, q; | |
| 4392 if (saturation == 0) { | |
| 4393 // achromatic (grayscale) | |
| 4394 r = lightness; | |
| 4395 g = lightness; | |
| 4396 b = lightness; | |
| 4397 } else { | |
| 4398 if (lightness < 0.5) { | |
| 4399 q = lightness * (1 + saturation); | |
| 4400 } else { | |
| 4401 q = lightness + saturation - (lightness * saturation); | |
| 4402 } | |
| 4403 p = (2 * lightness) - q; | |
| 4404 r = _hue(p, q, hue + (1.0 / 3.0)); | |
| 4405 g = _hue(p, q, hue); | |
| 4406 b = _hue(p, q, hue - (1.0 / 3.0)); | |
| 4407 } | |
| 4408 return "#" + _pad_hex(r) + _pad_hex(g) + _pad_hex(b); | |
| 4409 } | |
| 4410 if (typeof index !== "number" || index % 1 !== 0 || index < 0) return "#000000"; | |
| 4411 // check for override | |
| 4412 if (_block_colour_lookup[index] == null) { | |
| 4413 var start = 0; //red | |
| 4414 var sat = 100; | |
| 4415 var light = 50; | |
| 4416 var divisions = 1 << Math.ceil(Math.log(index + 1) / Math.LN2); | |
| 4417 hue = start + (360 / divisions) * ((index - (divisions >> 1)) * 2 + 1); | |
| 4418 // colour input fields only support values in the form #RRGGBB | |
| 4419 _block_colour_lookup[index] = hsl2rgb(hue / 360, sat / 100, light / 100); | |
| 4420 } | |
| 4421 return _block_colour_lookup[index]; | |
| 4422 } | |
| 4423 | |
| 4424 function set_block_colour(index, new_colour) { | |
| 4425 _block_colour_lookup[index] = new_colour; | |
| 4426 var blocks = document.querySelectorAll("div.block_motif[data-colour-index=\"" + index + "\"]"); | |
| 4427 var i; | |
| 4428 for (i = 0; i < blocks.length; i++) { | |
| 4429 blocks[i].style.backgroundColor = new_colour; | |
| 4430 } | |
| 4431 var swatches = document.querySelectorAll("div.legend_swatch[data-colour-index=\"" + index + "\"]"); | |
| 4432 var picker; | |
| 4433 for (i = 0; i < swatches.length; i++) { | |
| 4434 swatches[i].style.backgroundColor = new_colour; | |
| 4435 picker = swatches[i].querySelector("input[type=\"color\"]"); | |
| 4436 if (picker != null) picker.value = new_colour; | |
| 4437 } | |
| 4438 } | |
| 4439 | |
| 4440 function make_block_legend_entry(motif_name, motif_colour_index) { | |
| 4441 if (typeof make_block_legend_entry.has_colour_picker !== "boolean") { | |
| 4442 // test if colour picker is supported, based off Modernizer | |
| 4443 // see http://stackoverflow.com/a/7787648/66387 | |
| 4444 make_block_legend_entry.has_colour_picker = (function() { | |
| 4445 var doc_ele = document.documentElement; | |
| 4446 // We first check to see if the type we give it sticks.. | |
| 4447 var input_ele = document.createElement('input'); | |
| 4448 input_ele.setAttribute('type', 'color'); | |
| 4449 var value_ok = input_ele.type !== 'text'; | |
| 4450 if (value_ok) { | |
| 4451 // If the type does, we feed it a textual value, which shouldn't be valid. | |
| 4452 // If the value doesn't stick, we know there's input sanitization which infers a custom UI | |
| 4453 var smile = ':)'; | |
| 4454 input_ele.value = smile; | |
| 4455 input_ele.style.cssText = 'position:absolute;visibility:hidden;'; | |
| 4456 // chuck into DOM and force reflow for Opera bug in 11.00 | |
| 4457 // github.com/Modernizr/Modernizr/issues#issue/159 | |
| 4458 doc_ele.appendChild(input_ele); | |
| 4459 doc_ele.offsetWidth; | |
| 4460 value_ok = input_ele.value != smile; | |
| 4461 doc_ele.removeChild(input_ele); | |
| 4462 } | |
| 4463 return value_ok; | |
| 4464 })(); | |
| 4465 } | |
| 4466 var entry = document.createElement("div"); | |
| 4467 entry.className = "legend_entry"; | |
| 4468 var swatch; | |
| 4469 swatch = document.createElement("div"); | |
| 4470 swatch.className = "legend_swatch"; | |
| 4471 swatch.setAttribute("data-colour-index", motif_colour_index); | |
| 4472 swatch.style.backgroundColor = block_colour(motif_colour_index); | |
| 4473 if (make_block_legend_entry.has_colour_picker) { | |
| 4474 var picker = document.createElement("input"); | |
| 4475 picker.type = "color"; | |
| 4476 picker.value = block_colour(motif_colour_index); | |
| 4477 picker.addEventListener("change", function(e) { | |
| 4478 set_block_colour(motif_colour_index, picker.value); | |
| 4479 }, false); | |
| 4480 swatch.addEventListener("click", function(e) { | |
| 4481 picker.click(); | |
| 4482 }, false); | |
| 4483 swatch.appendChild(picker); | |
| 4484 } | |
| 4485 entry.appendChild(swatch); | |
| 4486 var name = document.createElement("div"); | |
| 4487 name.className = "legend_text"; | |
| 4488 name.appendChild(document.createTextNode(motif_name)); | |
| 4489 entry.appendChild(name); | |
| 4490 return entry; | |
| 4491 } | |
| 4492 | |
| 4493 function make_block_ruler(max_len) { | |
| 4494 var container = document.createElement("div"); | |
| 4495 container.className = "block_container"; | |
| 4496 var step; | |
| 4497 if (max_len < 50) { | |
| 4498 step = 1; | |
| 4499 } else if (max_len < 100) { | |
| 4500 step = 2; | |
| 4501 } else if (max_len < 200) { | |
| 4502 step = 4; | |
| 4503 } else if (max_len < 500) { | |
| 4504 step = 10; | |
| 4505 } else if (max_len < 1000) { | |
| 4506 step = 20; | |
| 4507 } else if (max_len < 2000) { | |
| 4508 step = 40; | |
| 4509 } else if (max_len < 5000) { | |
| 4510 step = 100; | |
| 4511 } else if (max_len < 10000) { | |
| 4512 step = 200; | |
| 4513 } else if (max_len < 20000) { | |
| 4514 step = 400; | |
| 4515 } else { | |
| 4516 step = Math.floor(max_len / 20000) * 400; | |
| 4517 } | |
| 4518 var peroid; | |
| 4519 if (max_len < 10) { | |
| 4520 peroid = 1; | |
| 4521 } else if (max_len < 20) { | |
| 4522 peroid = 2; | |
| 4523 } else { | |
| 4524 peroid = 5; | |
| 4525 } | |
| 4526 var i, cycle, offset, tic, label; | |
| 4527 for (i = 0, cycle = 0; i < max_len; i += step, cycle = (cycle + 1) % peroid) { | |
| 4528 offset = "" + ((i / max_len) * 100) + "%"; | |
| 4529 tic = document.createElement("div"); | |
| 4530 tic.style.left = offset; | |
| 4531 tic.className = (cycle == 0 ? "tic_major" : "tic_minor"); | |
| 4532 container.appendChild(tic); | |
| 4533 if (cycle == 0) { | |
| 4534 label = document.createElement("div"); | |
| 4535 label.className = "tic_label"; | |
| 4536 label.style.left = offset; | |
| 4537 label.appendChild(document.createTextNode(i)); | |
| 4538 container.appendChild(label); | |
| 4539 } | |
| 4540 } | |
| 4541 return container; | |
| 4542 } | |
| 4543 | |
| 4544 function _calculate_block_needle_drag_pos(e, data) { | |
| 4545 var mouse; | |
| 4546 e = e || window.event; | |
| 4547 if (e.pageX || ev.pageY) { | |
| 4548 mouse = {"x": e.pageX, "y": e.pageY}; | |
| 4549 } else { | |
| 4550 mouse = { | |
| 4551 x:e.clientX + document.body.scrollLeft - document.body.clientLeft, | |
| 4552 y:e.clientY + document.body.scrollTop - document.body.clientTop | |
| 4553 }; | |
| 4554 } | |
| 4555 var cont = data.container; | |
| 4556 var dragable_length = cont.clientWidth - | |
| 4557 (cont.style.paddingLeft ? cont.style.paddingLeft : 0) - | |
| 4558 (cont.style.paddingRight ? cont.style.paddingRight : 0); | |
| 4559 //I believe that the offset parent is the body | |
| 4560 //otherwise I would need to make this recursive | |
| 4561 //maybe clientLeft would work, but the explanation of | |
| 4562 //it is hard to understand and it apparently doesn't work | |
| 4563 //in firefox 2. | |
| 4564 var diff = mouse.x - cont.offsetLeft; | |
| 4565 if (diff < 0) diff = 0; | |
| 4566 if (diff > dragable_length) diff = dragable_length; | |
| 4567 var pos = Math.round(diff / dragable_length * data.max); | |
| 4568 if (pos > data.len) pos = data.len; | |
| 4569 return pos; | |
| 4570 } | |
| 4571 | |
| 4572 function _update_block_needle_drag(e, data, done) { | |
| 4573 "use strict"; | |
| 4574 var pos = _calculate_block_needle_drag_pos(e, data); | |
| 4575 // read the needle positions | |
| 4576 var left = parseInt(data.llabel.textContent, 10) - data.off - 1; | |
| 4577 var right = parseInt(data.rlabel.textContent, 10) - data.off; | |
| 4578 // validate needle positions | |
| 4579 if (left >= data.len) left = data.len - 1; | |
| 4580 if (left < 0) left = 0; | |
| 4581 if (right > data.len) right = data.len; | |
| 4582 if (right <= left) right = left + 1; | |
| 4583 // calculate the new needle positions | |
| 4584 if (data.moveboth) { | |
| 4585 var size = right - left; | |
| 4586 if (data.isleft) { | |
| 4587 if ((pos + size) > data.len) pos = data.len - size; | |
| 4588 left = pos; | |
| 4589 right = pos + size; | |
| 4590 } else { | |
| 4591 if ((pos - size) < 0) pos = size; | |
| 4592 left = pos - size; | |
| 4593 right = pos; | |
| 4594 } | |
| 4595 } else { | |
| 4596 if (data.isleft) { | |
| 4597 if (pos >= right) pos = right - 1; | |
| 4598 left = pos; | |
| 4599 } else { | |
| 4600 if (pos <= left) pos = left + 1; | |
| 4601 right = pos; | |
| 4602 } | |
| 4603 } | |
| 4604 // update the needle positions | |
| 4605 data.lneedle.style.left = "" + (left / data.max * 100) + "%"; | |
| 4606 data.llabel.textContent = "" + (left + data.off + 1); | |
| 4607 data.rneedle.style.left = "" + (right / data.max * 100) + "%"; | |
| 4608 data.rlabel.textContent = "" + (right + data.off); | |
| 4609 data.handler(left, right, done); | |
| 4610 } | |
| 4611 | |
| 4612 function _make_block_needle_drag_start_handler(isleft, data) { | |
| 4613 return function (e) { | |
| 4614 data.isleft = isleft; | |
| 4615 data.moveboth = !(e.shiftKey); | |
| 4616 document.addEventListener("mousemove", data.drag_during, false); | |
| 4617 document.addEventListener("mouseup", data.drag_end, false); | |
| 4618 }; | |
| 4619 } | |
| 4620 | |
| 4621 function _make_block_needle_drag_end_handler(data) { | |
| 4622 return function (e) { | |
| 4623 document.removeEventListener("mousemove", data.drag_during, false); | |
| 4624 document.removeEventListener("mouseup", data.drag_end, false); | |
| 4625 _update_block_needle_drag(e, data, true); | |
| 4626 }; | |
| 4627 } | |
| 4628 | |
| 4629 function _make_block_needle_drag_during_handler(data) { | |
| 4630 return function (e) { | |
| 4631 _update_block_needle_drag(e, data, false); | |
| 4632 }; | |
| 4633 } | |
| 4634 | |
| 4635 // private function used by make_block_container | |
| 4636 function _make_block_needle(isleft, value, data) { | |
| 4637 var vbar = document.createElement('div'); | |
| 4638 vbar.className = "block_needle " + (isleft ? "left" : "right"); | |
| 4639 vbar.style.left = "" + (value / data.max * 100)+ "%"; | |
| 4640 var label = document.createElement('div'); | |
| 4641 label.className = "block_handle " + (isleft ? "left" : "right"); | |
| 4642 // The needles sit between the sequence positions, so the left one sits at the | |
| 4643 // start and the right at the end. This is why 1 is added to the displayed | |
| 4644 // value for a left handle as the user doesn't need to know about this detail | |
| 4645 label.textContent = "" + (isleft ? value + data.off + 1 : value + data.off); | |
| 4646 label.unselectable = "on"; // so IE and Opera don't select the text, others are done in css | |
| 4647 label.title = "Drag to move the displayed range. Hold shift and drag to change " + (isleft ? "lower" : "upper") + " bound of the range."; | |
| 4648 vbar.appendChild(label); | |
| 4649 if (isleft) { | |
| 4650 data.lneedle = vbar; | |
| 4651 data.llabel = label; | |
| 4652 } else { | |
| 4653 data.rneedle = vbar; | |
| 4654 data.rlabel = label; | |
| 4655 } | |
| 4656 label.addEventListener("mousedown", _make_block_needle_drag_start_handler(isleft, data), false); | |
| 4657 return vbar; | |
| 4658 } | |
| 4659 | |
| 4660 function make_block_container(is_stranded, has_both_strands, max_len, show_len, offset, range_handler) { | |
| 4661 offset = (offset != null ? offset : 0); | |
| 4662 // make the container for the block diagram | |
| 4663 var container = document.createElement("div"); | |
| 4664 container.className = "block_container"; | |
| 4665 container.setAttribute("data-max", max_len); | |
| 4666 container.setAttribute("data-off", offset); | |
| 4667 if (is_stranded) { | |
| 4668 var plus = document.createElement("div"); | |
| 4669 plus.appendChild(document.createTextNode("+")); | |
| 4670 plus.className = "block_plus_sym"; | |
| 4671 container.appendChild(plus); | |
| 4672 if (has_both_strands) { | |
| 4673 var minus = document.createElement("div"); | |
| 4674 minus.appendChild(document.createTextNode("-")); | |
| 4675 minus.className = "block_minus_sym"; | |
| 4676 container.appendChild(minus); | |
| 4677 } | |
| 4678 } | |
| 4679 var rule = document.createElement("div"); | |
| 4680 rule.className = "block_rule"; | |
| 4681 rule.style.width = ((show_len / max_len) * 100) + "%"; | |
| 4682 container.appendChild(rule); | |
| 4683 if (range_handler != null) { | |
| 4684 var range_data = { | |
| 4685 "max": max_len, | |
| 4686 "len": show_len, | |
| 4687 "off": offset, | |
| 4688 "handler": range_handler, | |
| 4689 "container": container, | |
| 4690 "lneedle": null, "llabel": null, | |
| 4691 "rneedle": null, "rlabel": null, | |
| 4692 "isleft": false, "moveboth" : false | |
| 4693 }; | |
| 4694 range_data.drag_during = _make_block_needle_drag_during_handler(range_data); | |
| 4695 range_data.drag_end = _make_block_needle_drag_end_handler(range_data); | |
| 4696 container.appendChild(_make_block_needle(false, 1, range_data)); // add right first so z-index works | |
| 4697 container.appendChild(_make_block_needle(true, 0, range_data)); | |
| 4698 } | |
| 4699 return container; | |
| 4700 } | |
| 4701 | |
| 4702 function make_block_label(container, max_len, pos, length, message) { | |
| 4703 "use strict"; | |
| 4704 var label = document.createElement("div"); | |
| 4705 label.className = "block_label"; | |
| 4706 label.style.left = (((pos + (length / 2)) / max_len) * 100) + "%"; | |
| 4707 label.appendChild(document.createTextNode(message)); | |
| 4708 container.appendChild(label); | |
| 4709 } | |
| 4710 | |
| 4711 function make_block(container, max_len, | |
| 4712 site_pos, site_len, site_pvalue, site_rc, site_colour_index, site_secondary) { | |
| 4713 "use strict"; | |
| 4714 var block_height, block, block_region1, block_region2; | |
| 4715 var max_block_height = 12; | |
| 4716 var max_pvalue = 1e-10; | |
| 4717 // calculate the height of the block | |
| 4718 block_height = (site_pvalue < max_pvalue ? max_block_height : | |
| 4719 (Math.log(site_pvalue) / Math.log(max_pvalue)) * max_block_height); | |
| 4720 if (block_height < 1) block_height = 1; | |
| 4721 // create a block to represent the motif | |
| 4722 block = document.createElement("div"); | |
| 4723 block.className = "block_motif" + (site_secondary ? " scanned_site" : "") + (site_rc ? " bottom" : " top"); | |
| 4724 block.style.left = ((site_pos / max_len) * 100) + "%"; | |
| 4725 block.style.top = (!site_rc ? max_block_height - block_height : | |
| 4726 max_block_height + 1) + "px"; | |
| 4727 block.style.width = ((site_len / max_len) * 100) + "%"; | |
| 4728 block.style.height = block_height + "px"; | |
| 4729 block.style.backgroundColor = block_colour(site_colour_index); | |
| 4730 block.setAttribute("data-colour-index", site_colour_index); | |
| 4731 // add to container | |
| 4732 container.appendChild(block); | |
| 4733 var activator = function (e) { | |
| 4734 toggle_class(block, "active", true); | |
| 4735 var new_e = new e.constructor(e.type, e); | |
| 4736 block.dispatchEvent(new_e); | |
| 4737 }; | |
| 4738 var deactivator = function (e) { | |
| 4739 toggle_class(block, "active", false); | |
| 4740 var new_e = new e.constructor(e.type, e); | |
| 4741 block.dispatchEvent(new_e); | |
| 4742 } | |
| 4743 // create a larger region to detect mouseover for the block | |
| 4744 block_region1 = document.createElement("div"); | |
| 4745 block_region1.className = "block_region top" + | |
| 4746 (site_secondary ? " scanned_site" : "") + (site_rc ? "" : " main"); | |
| 4747 block_region1.style.left = block.style.left; | |
| 4748 block_region1.style.width = block.style.width; | |
| 4749 block_region1.addEventListener('mouseover', activator, false); | |
| 4750 block_region1.addEventListener('mouseout', deactivator, false); | |
| 4751 container.appendChild(block_region1); | |
| 4752 block_region2 = document.createElement("div"); | |
| 4753 block_region2.className = "block_region bottom" + | |
| 4754 (site_secondary ? " scanned_site" : "") + (site_rc ? " main" : ""); | |
| 4755 block_region2.style.left = block.style.left; | |
| 4756 block_region2.style.width = block.style.width; | |
| 4757 block_region2.addEventListener('mouseover', activator, false); | |
| 4758 block_region2.addEventListener('mouseout', deactivator, false); | |
| 4759 container.appendChild(block_region2); | |
| 4760 return block; | |
| 4761 } | |
| 4762 | |
| 4763 function set_block_needle_positions(containingNode, start, end) { | |
| 4764 var container, lneedle, llabel, rneedle, rlabel, max, off, left, right; | |
| 4765 container = (/\bblock_container\b/.test(containingNode.className) ? containingNode : containingNode.querySelector(".block_container")); | |
| 4766 max = parseInt(container.getAttribute("data-max"), 10); | |
| 4767 off = parseInt(container.getAttribute("data-off"), 10); | |
| 4768 left = start - off; | |
| 4769 right = end - off; | |
| 4770 lneedle = containingNode.querySelector(".block_needle.left"); | |
| 4771 llabel = lneedle.querySelector(".block_handle.left"); | |
| 4772 rneedle = containingNode.querySelector(".block_needle.right"); | |
| 4773 rlabel = rneedle.querySelector(".block_handle.right"); | |
| 4774 // update the needle positions | |
| 4775 lneedle.style.left = "" + (left / max * 100) + "%"; | |
| 4776 llabel.textContent = "" + (left + off + 1); | |
| 4777 rneedle.style.left = "" + (right / max * 100) + "%"; | |
| 4778 rlabel.textContent = "" + (right + off); | |
| 4779 } | |
| 4780 | |
| 4781 function get_block_needle_positions(containingNode) { | |
| 4782 var container, llabel, rlabel, max, off, left, right; | |
| 4783 container = (/\bblock_container\b/.test(containingNode.className) ? containingNode : containingNode.querySelector(".block_container")); | |
| 4784 max = parseInt(container.getAttribute("data-max"), 10); | |
| 4785 off = parseInt(container.getAttribute("data-off"), 10); | |
| 4786 llabel = containingNode.querySelector(".block_needle.left > .block_handle.left"); | |
| 4787 rlabel = containingNode.querySelector(".block_needle.right > .block_handle.right"); | |
| 4788 left = parseInt(llabel.textContent, 10) - off - 1; | |
| 4789 right = parseInt(rlabel.textContent, 10) - off; | |
| 4790 return {"start": left + off, "end": right + off}; | |
| 4791 } | |
| 4792 </script> | |
| 4793 <script> | |
| 4794 function make_alpha_bg_table(alph, freqs) { | |
| 4795 function colour_symbol(index) { | |
| 4796 var span = document.createElement("span"); | |
| 4797 span.appendChild(document.createTextNode(alph.get_symbol(index))); | |
| 4798 span.style.color = alph.get_colour(index); | |
| 4799 span.className = "alpha_symbol"; | |
| 4800 return span; | |
| 4801 } | |
| 4802 var table, thead, tbody, row, th, span, i; | |
| 4803 // create table | |
| 4804 table = document.createElement("table"); | |
| 4805 table.className = "alpha_bg_table"; | |
| 4806 // create header | |
| 4807 thead = document.createElement("thead"); | |
| 4808 table.appendChild(thead); | |
| 4809 row = thead.insertRow(thead.rows.length); | |
| 4810 if (alph.has_complement()) { | |
| 4811 add_text_header_cell(row, "Name", "pop_alph_name"); | |
| 4812 if (freqs != null) add_text_header_cell(row, "Freq.", "pop_alph_freq"); | |
| 4813 if (alph.has_bg()) add_text_header_cell(row, "Bg.", "pop_alph_bg"); | |
| 4814 add_text_header_cell(row, ""); | |
| 4815 add_text_header_cell(row, ""); | |
| 4816 add_text_header_cell(row, ""); | |
| 4817 if (alph.has_bg()) add_text_header_cell(row, "Bg.", "pop_alph_bg"); | |
| 4818 if (freqs != null) add_text_header_cell(row, "Freq.", "pop_alph_freq"); | |
| 4819 add_text_header_cell(row, "Name", "pop_alph_name"); | |
| 4820 } else { | |
| 4821 add_text_header_cell(row, ""); | |
| 4822 add_text_header_cell(row, "Name", "pop_alph_name"); | |
| 4823 if (freqs != null) add_text_header_cell(row, "Freq.", "pop_alph_freq"); | |
| 4824 if (alph.has_bg()) add_text_header_cell(row, "Bg.", "pop_alph_bg"); | |
| 4825 } | |
| 4826 // add alphabet entries | |
| 4827 tbody = document.createElement("tbody"); | |
| 4828 table.appendChild(tbody); | |
| 4829 if (alph.has_complement()) { | |
| 4830 for (i = 0; i < alph.get_size_core(); i++) { | |
| 4831 var c = alph.get_complement(i); | |
| 4832 if (i > c) continue; | |
| 4833 row = tbody.insertRow(tbody.rows.length); | |
| 4834 add_text_cell(row, alph.get_name(i)); | |
| 4835 if (freqs != null) add_text_cell(row, "" + freqs[i].toFixed(3)); | |
| 4836 if (alph.has_bg()) add_text_cell(row, "" + alph.get_bg_freq(i).toFixed(3)); | |
| 4837 add_cell(row, colour_symbol(i)); | |
| 4838 add_text_cell(row, "~"); | |
| 4839 add_cell(row, colour_symbol(c)); | |
| 4840 if (alph.has_bg()) add_text_cell(row, "" + alph.get_bg_freq(c).toFixed(3)); | |
| 4841 if (freqs != null) add_text_cell(row, "" + freqs[c].toFixed(3)); | |
| 4842 add_text_cell(row, alph.get_name(c)); | |
| 4843 } | |
| 4844 } else { | |
| 4845 for (i = 0; i < alph.get_size_core(); i++) { | |
| 4846 row = tbody.insertRow(tbody.rows.length); | |
| 4847 add_cell(row, colour_symbol(i)); | |
| 4848 add_text_cell(row, alph.get_name(i)); | |
| 4849 if (freqs != null) add_text_cell(row, "" + freqs[i].toFixed(3)); | |
| 4850 if (alph.has_bg()) add_text_cell(row, "" + alph.get_bg_freq(i).toFixed(3)); | |
| 4851 } | |
| 4852 } | |
| 4853 return table; | |
| 4854 } | |
| 4855 | |
| 4856 </script> | |
| 4857 <script> | |
| 4858 var current_motif = 0; | |
| 4859 var meme_alphabet = new Alphabet(data.alphabet, data.background.freqs); | |
| 4860 | |
| 4861 var DelayLogoTask = function(logo, canvas) { | |
| 4862 this.logo = logo; | |
| 4863 this.canvas = canvas; | |
| 4864 }; | |
| 4865 | |
| 4866 DelayLogoTask.prototype.run = function () { | |
| 4867 draw_logo_on_canvas(this.logo, this.canvas, false); | |
| 4868 }; | |
| 4869 | |
| 4870 function motif_pspm(index) { | |
| 4871 var motif, pwm, psm, name, ltrim, rtrim, nsites, evalue; | |
| 4872 // get motif | |
| 4873 motif = data["motifs"][index]; | |
| 4874 // get motif paramters | |
| 4875 pwm = motif["pwm"]; | |
| 4876 psm = motif["psm"]; | |
| 4877 name = "" + (index + 1); ltrim = 0; rtrim = 0; | |
| 4878 nsites = motif["nsites"]; evalue = motif["evalue"]; | |
| 4879 // make pspm | |
| 4880 return new Pspm(pwm, name, ltrim, rtrim, nsites, evalue, psm); | |
| 4881 } | |
| 4882 | |
| 4883 function motif_count_matrix(index) { | |
| 4884 return motif_pspm(index).as_count_matrix(); | |
| 4885 } | |
| 4886 | |
| 4887 function motif_prob_matrix(index) { | |
| 4888 return motif_pspm(index).as_probability_matrix(); | |
| 4889 } | |
| 4890 | |
| 4891 function motif_minimal_meme(index) { | |
| 4892 return motif_pspm(index).as_meme({ | |
| 4893 "with_header": true, | |
| 4894 "with_pspm": true, | |
| 4895 "with_pssm": true, | |
| 4896 "version": data["version"], | |
| 4897 "alphabet": meme_alphabet, | |
| 4898 "strands": (meme_alphabet.has_complement() && data.options.revcomp ? 2 : 1) | |
| 4899 }); | |
| 4900 } | |
| 4901 | |
| 4902 function motif_fasta(index) { | |
| 4903 "use strict"; | |
| 4904 var motif, sites, site, seq, sequences, sequence, i, num, counter, out; | |
| 4905 counter = {}; | |
| 4906 sequences = data["sequence_db"]["sequences"]; | |
| 4907 motif = data["motifs"][index]; | |
| 4908 sites = motif["sites"]; | |
| 4909 out = ""; | |
| 4910 for (i = 0; i < sites.length; i++) { | |
| 4911 site = sites[i]; | |
| 4912 seq = site["seq"]; | |
| 4913 sequence = sequences[seq]; | |
| 4914 counter[seq] = (num = counter[seq]) ? (++num) : (num = 1); // inc counter | |
| 4915 if (i !== 0) {out += "\n";} | |
| 4916 out += ">" + sequence["name"] + "_site_" + num + " offset= " + site["pos"] + | |
| 4917 (site["rc"] ? " RC\n" : "\n"); | |
| 4918 out += site["match"]; | |
| 4919 } | |
| 4920 return out; | |
| 4921 } | |
| 4922 | |
| 4923 function motif_raw(index) { | |
| 4924 "use strict"; | |
| 4925 var sites, i, out; | |
| 4926 sites = data["motifs"][index]["sites"]; | |
| 4927 out = ""; | |
| 4928 for (i = 0; i < sites.length; i++) { | |
| 4929 if (i !== 0) {out += "\n";} | |
| 4930 out += sites[i]["match"]; | |
| 4931 } | |
| 4932 return out; | |
| 4933 } | |
| 4934 | |
| 4935 function clone_template(template) { | |
| 4936 "use strict"; | |
| 4937 var node, help_btns, i, button; | |
| 4938 node = $(template).cloneNode(true); | |
| 4939 toggle_class(node, "template", false); | |
| 4940 node.id = ""; | |
| 4941 help_btns = node.querySelectorAll(".help"); | |
| 4942 for (i = 0; i < help_btns.length; i++) { | |
| 4943 button = help_btns[i]; | |
| 4944 if (button.hasAttribute("data-topic")) { | |
| 4945 button.tabIndex = "0"; | |
| 4946 button.addEventListener("click", __toggle_help, false); | |
| 4947 button.addEventListener("keydown", __toggle_help, false); | |
| 4948 } | |
| 4949 } | |
| 4950 return node; | |
| 4951 } | |
| 4952 | |
| 4953 function set_tvar(template, tvar, value) { | |
| 4954 var node; | |
| 4955 node = find_child(template, tvar); | |
| 4956 if (node === null) { | |
| 4957 throw new Error("Template does not contain variable " + tvar); | |
| 4958 } | |
| 4959 node.innerHTML = ""; | |
| 4960 if (typeof value !== "object") { | |
| 4961 node.appendChild(document.createTextNode(value)); | |
| 4962 } else { | |
| 4963 node.appendChild(value); | |
| 4964 } | |
| 4965 } | |
| 4966 | |
| 4967 function make_logo(alphabet, pspm, rc, offset, className) { | |
| 4968 if (rc) pspm = pspm.copy().reverse_complement(alphabet); | |
| 4969 var logo = new Logo(alphabet, ""); | |
| 4970 logo.add_pspm(pspm, offset); | |
| 4971 var canvas = document.createElement('canvas'); | |
| 4972 canvas.height = 50; | |
| 4973 canvas.width = 0; | |
| 4974 canvas.className = className; | |
| 4975 size_logo_on_canvas(logo, canvas, false); | |
| 4976 add_draw_task(canvas, new DelayLogoTask(logo, canvas)); | |
| 4977 return canvas; | |
| 4978 } | |
| 4979 | |
| 4980 function make_small_logo(alphabet, pspm, options) { | |
| 4981 if (typeof options === "undefined") options = {}; | |
| 4982 if (options.rc) pspm = pspm.copy().reverse_complement(alphabet); | |
| 4983 var logo = new Logo(alphabet, {x_axis: false, y_axis: false}); | |
| 4984 logo.add_pspm(pspm, (typeof options.offset === "number" ? options.offset : 0)); | |
| 4985 var canvas = document.createElement('canvas'); | |
| 4986 if (typeof options.className === "string") canvas.className = options.className; | |
| 4987 if (typeof options.width === "number" && options.width > 0) { | |
| 4988 canvas.height = 0; | |
| 4989 canvas.width = options.width; | |
| 4990 draw_logo_on_canvas(logo, canvas, false); | |
| 4991 } else { | |
| 4992 draw_logo_on_canvas(logo, canvas, false, 1/3); | |
| 4993 } | |
| 4994 return canvas; | |
| 4995 } | |
| 4996 | |
| 4997 function make_large_logo(alphabet, pspm, rc, offset, className) { | |
| 4998 if (rc) pspm = pspm.copy().reverse_complement(alphabet); | |
| 4999 var logo = new Logo(alphabet, ""); | |
| 5000 logo.add_pspm(pspm, offset); | |
| 5001 var canvas = document.createElement('canvas'); | |
| 5002 canvas.height = 200; | |
| 5003 canvas.width = 0; | |
| 5004 canvas.className = className; | |
| 5005 size_logo_on_canvas(logo, canvas, false); | |
| 5006 add_draw_task(canvas, new DelayLogoTask(logo, canvas)); | |
| 5007 return canvas; | |
| 5008 } | |
| 5009 | |
| 5010 function make_sym_btn(symbol, title, action) { | |
| 5011 var box; | |
| 5012 box = document.createElement("div"); | |
| 5013 box.tabIndex = 0; | |
| 5014 box.className = "sym_btn"; | |
| 5015 box.appendChild(document.createTextNode(symbol)); | |
| 5016 box.title = title; | |
| 5017 box.addEventListener('click', action, false); | |
| 5018 box.addEventListener('keydown', action, false); | |
| 5019 return box; | |
| 5020 } | |
| 5021 | |
| 5022 function make_seq(alphabet, seq) { | |
| 5023 var i, j, letter, lbox, sbox; | |
| 5024 sbox = document.createElement("span"); | |
| 5025 for (i = 0; i < seq.length; i = j) { | |
| 5026 letter = seq.charAt(i); | |
| 5027 for (j = i+1; j < seq.length; j++) { | |
| 5028 if (seq.charAt(j) !== letter) { | |
| 5029 break; | |
| 5030 } | |
| 5031 } | |
| 5032 lbox = document.createElement("span"); | |
| 5033 lbox.style.color = alphabet.get_colour(alphabet.get_index(letter)); | |
| 5034 lbox.appendChild(document.createTextNode(seq.substring(i, j))); | |
| 5035 sbox.appendChild(lbox); | |
| 5036 } | |
| 5037 return sbox; | |
| 5038 } | |
| 5039 | |
| 5040 // | |
| 5041 // make_pv_text | |
| 5042 // | |
| 5043 // Returns the string p-value, with the p italicised. | |
| 5044 /// | |
| 5045 function make_pv_text() { | |
| 5046 var pv_text = document.createElement("span"); | |
| 5047 var pv_italic_text = document.createElement("span"); | |
| 5048 pv_italic_text.appendChild(document.createTextNode("p")); | |
| 5049 pv_italic_text.style.fontStyle = "italic"; | |
| 5050 pv_text.appendChild(pv_italic_text); | |
| 5051 pv_text.appendChild(document.createTextNode("-value")); | |
| 5052 return pv_text; | |
| 5053 } | |
| 5054 | |
| 5055 function append_site_entries(tbody, motif, site_index, count) { | |
| 5056 "use strict"; | |
| 5057 var i, end; | |
| 5058 var sites, site, sequences, sequence; | |
| 5059 var rbody; | |
| 5060 if (typeof count !== "number") { | |
| 5061 count = 20; | |
| 5062 } | |
| 5063 sequences = data["sequence_db"]["sequences"]; | |
| 5064 sites = motif["sites"]; | |
| 5065 end = Math.min(site_index + count, sites.length); | |
| 5066 for (i = site_index; i < end; i++) { | |
| 5067 site = sites[i]; | |
| 5068 sequence = sequences[site["seq"]]; | |
| 5069 | |
| 5070 rbody = tbody.insertRow(tbody.rows.length); | |
| 5071 add_text_cell(rbody, "" + (site["seq"] + 1) + ".", "site_num"); | |
| 5072 add_text_cell(rbody, sequence["name"], "site_name"); | |
| 5073 add_text_cell(rbody, site["rc"] ? "-" : "+", "site_strand"); | |
| 5074 add_text_cell(rbody, site["pos"] + 1, "site_start"); | |
| 5075 add_text_cell(rbody, site["pvalue"].toExponential(2), "site_pvalue"); | |
| 5076 add_text_cell(rbody, site["lflank"], "site lflank"); | |
| 5077 add_cell(rbody, make_seq(meme_alphabet, site["match"]), "site match"); | |
| 5078 add_text_cell(rbody, site["rflank"], "site rflank"); | |
| 5079 } | |
| 5080 return i; | |
| 5081 } | |
| 5082 | |
| 5083 function make_site_entries() { | |
| 5084 "use strict"; | |
| 5085 var region; | |
| 5086 region = this; | |
| 5087 if (region.data_site_index >= region.data_motif["sites"].length) { | |
| 5088 // all sites created | |
| 5089 region.removeEventListener('scroll', make_site_entries, false); | |
| 5090 return; | |
| 5091 } | |
| 5092 // if there's still 100 pixels to scroll than don't do anything yet | |
| 5093 if (region.scrollHeight - (region.scrollTop + region.offsetHeight) > 100) { | |
| 5094 return; | |
| 5095 } | |
| 5096 | |
| 5097 region.data_site_index = append_site_entries( | |
| 5098 find_child(region, "sites_tbl").tBodies[0], | |
| 5099 region.data_motif, region.data_site_index, 20 | |
| 5100 ); | |
| 5101 } | |
| 5102 | |
| 5103 function make_sites(motif) { | |
| 5104 "use strict"; | |
| 5105 function add_site_header(row, title, nopad, help_topic, tag_class) { | |
| 5106 var div, divcp, th; | |
| 5107 th = document.createElement("th"); | |
| 5108 div = document.createElement("div"); | |
| 5109 div.className = "sites_th_inner"; | |
| 5110 if (typeof title !== "object") { | |
| 5111 title = document.createTextNode("" + title); | |
| 5112 } | |
| 5113 div.appendChild(title); | |
| 5114 if (help_topic) { | |
| 5115 div.appendChild(document.createTextNode("\xA0")); | |
| 5116 div.appendChild(help_button(help_topic)); | |
| 5117 } | |
| 5118 divcp = div.cloneNode(true); | |
| 5119 divcp.className = "sites_th_hidden"; | |
| 5120 th.appendChild(div); | |
| 5121 th.appendChild(divcp); | |
| 5122 if (nopad) { | |
| 5123 th.className = "nopad"; | |
| 5124 } | |
| 5125 if (tag_class) { | |
| 5126 th.className += " " + tag_class; | |
| 5127 } | |
| 5128 row.appendChild(th); | |
| 5129 } | |
| 5130 var outer_tbl, inner_tbl, tbl, thead, tbody, rhead; | |
| 5131 | |
| 5132 outer_tbl = document.createElement("div"); | |
| 5133 outer_tbl.className = "sites_outer"; | |
| 5134 | |
| 5135 inner_tbl = document.createElement("div"); | |
| 5136 inner_tbl.className = "sites_inner"; | |
| 5137 outer_tbl.appendChild(inner_tbl); | |
| 5138 | |
| 5139 tbl = document.createElement("table"); | |
| 5140 tbl.className = "sites_tbl"; | |
| 5141 inner_tbl.appendChild(tbl); | |
| 5142 | |
| 5143 thead = document.createElement("thead"); | |
| 5144 tbl.appendChild(thead); | |
| 5145 tbody = document.createElement("tbody"); | |
| 5146 tbl.appendChild(tbody); | |
| 5147 | |
| 5148 rhead = thead.insertRow(thead.rows.length); | |
| 5149 add_site_header(rhead, "", true); | |
| 5150 add_site_header(rhead, "Name", false, "pop_seq_name"); | |
| 5151 add_site_header(rhead, "Strand", false, "pop_site_strand", "site_strand_title"); | |
| 5152 add_site_header(rhead, "Start", false, "pop_site_start"); | |
| 5153 add_site_header(rhead, make_pv_text(), false, "pop_site_pvalue"); | |
| 5154 add_site_header(rhead, "", false); | |
| 5155 add_site_header(rhead, "Sites", true, "pop_site_match"); | |
| 5156 add_site_header(rhead, "", false); | |
| 5157 | |
| 5158 inner_tbl.data_motif = motif; | |
| 5159 inner_tbl.data_site_index = append_site_entries(tbody, motif, 0, 20); | |
| 5160 if (inner_tbl.data_site_index < motif["sites"].length) { | |
| 5161 inner_tbl.addEventListener('scroll', make_site_entries, false); | |
| 5162 } | |
| 5163 return outer_tbl; | |
| 5164 } | |
| 5165 | |
| 5166 function make_motif_table_entry(row, alphabet, ordinal, motif, colw) { | |
| 5167 "use strict"; | |
| 5168 function ev_sig(evalue_str) { | |
| 5169 "use strict"; | |
| 5170 var ev_re, match, sig, exp, num; | |
| 5171 ev_re = /^(.*)e(.*)$/; | |
| 5172 if (match = ev_re.exec(evalue_str)) { | |
| 5173 sig = parseFloat(match[1]); | |
| 5174 exp = parseInt(match[2]); | |
| 5175 if (exp >= 0) { | |
| 5176 return false; | |
| 5177 } else if (exp <= -3) { | |
| 5178 return true; | |
| 5179 } else { | |
| 5180 return sig * Math.pow(10, exp) <= 0.05; | |
| 5181 } | |
| 5182 } | |
| 5183 return true; | |
| 5184 } | |
| 5185 function make_preview(alphabet, motif) { | |
| 5186 "use strict"; | |
| 5187 var pspm, preview, preview_rc; | |
| 5188 var box, btn_box, logo_box, btn_plus, btn_minus; | |
| 5189 if (motif["preview_logo"]) { | |
| 5190 preview = motif["preview_logo"]; | |
| 5191 preview_rc = motif["preview_logo_rc"]; | |
| 5192 } else { | |
| 5193 pspm = new Pspm(motif["pwm"]); | |
| 5194 preview = make_logo(alphabet, pspm); | |
| 5195 motif["preview_logo"] = preview; | |
| 5196 if (alphabet.has_complement()) { | |
| 5197 preview_rc = make_logo(alphabet, pspm, true, 0, "logo_rc"); | |
| 5198 motif["preview_logo_rc"] = preview_rc; | |
| 5199 } | |
| 5200 } | |
| 5201 if (preview_rc) { | |
| 5202 btn_plus = document.createElement("div"); | |
| 5203 btn_plus.appendChild(document.createTextNode("+")); | |
| 5204 btn_plus.className = "preview_btn plus"; | |
| 5205 btn_plus.tabIndex = "0"; | |
| 5206 btn_plus.addEventListener("click", action_btn_rc, false); | |
| 5207 btn_plus.addEventListener("keydown", action_btn_rc, false); | |
| 5208 btn_minus = document.createElement("div"); | |
| 5209 btn_minus.appendChild(document.createTextNode("-")); | |
| 5210 btn_minus.className = "preview_btn minus"; | |
| 5211 btn_minus.tabIndex = "0"; | |
| 5212 btn_minus.addEventListener("click", action_btn_rc, false); | |
| 5213 btn_minus.addEventListener("keydown", action_btn_rc, false); | |
| 5214 btn_box = document.createElement("div"); | |
| 5215 btn_box.className = "preview_btn_box"; | |
| 5216 btn_box.appendChild(btn_plus); | |
| 5217 btn_box.appendChild(btn_minus); | |
| 5218 } | |
| 5219 logo_box = document.createElement("div"); | |
| 5220 logo_box.className = "preview_logo_box"; | |
| 5221 logo_box.appendChild(preview); | |
| 5222 if (preview_rc) logo_box.appendChild(preview_rc); | |
| 5223 box = document.createElement("div"); | |
| 5224 box.className = "preview_box"; | |
| 5225 if (preview_rc) box.appendChild(btn_box); | |
| 5226 box.appendChild(logo_box); | |
| 5227 if (preview_rc) { | |
| 5228 if (motif["rc"]) { | |
| 5229 btn_minus.className += " active"; | |
| 5230 logo_box.className += " show_rc_logo"; | |
| 5231 } else { | |
| 5232 btn_plus.className += " active"; | |
| 5233 } | |
| 5234 } | |
| 5235 return box; | |
| 5236 } | |
| 5237 var pspm, preview, preview_rc, c; | |
| 5238 row.data_motif = motif; | |
| 5239 row.data_ordinal = ordinal; | |
| 5240 if (!ev_sig(motif["evalue"])) { | |
| 5241 row.style.opacity = 0.4; | |
| 5242 } | |
| 5243 add_text_cell(row, "" + ordinal + ".", "motif_ordinal"); | |
| 5244 add_cell(row, make_preview(alphabet, motif), "motif_logo"); | |
| 5245 add_text_cell(row, motif["evalue"], "motif_evalue"); | |
| 5246 add_text_cell(row, motif["nsites"], "motif_nsites"); | |
| 5247 add_text_cell(row, motif["len"], "motif_width"); | |
| 5248 add_cell(row, make_sym_btn("\u21A7", "Show more information.", | |
| 5249 action_show_more), "motif_more"); | |
| 5250 add_cell(row, | |
| 5251 make_sym_btn("\u21E2", | |
| 5252 "Submit the motif to another MEME Suite program or download it.", | |
| 5253 action_show_outpop), | |
| 5254 "motif_submit"); | |
| 5255 if (colw) { | |
| 5256 for (c = 0; c < row.cells.length; c++) { | |
| 5257 row.cells[c].style.minWidth = colw[c] + "px"; | |
| 5258 } | |
| 5259 } | |
| 5260 } | |
| 5261 | |
| 5262 function make_motifs_table(alphabet, start_ordinal, motifs, colw, stop_reason) { | |
| 5263 var i, j; | |
| 5264 var tbl, thead, tbody, tfoot, row, preview; | |
| 5265 var motif, pspm; | |
| 5266 | |
| 5267 tbl = document.createElement("table"); | |
| 5268 | |
| 5269 thead = document.createElement("thead"); | |
| 5270 tbl.appendChild(thead); | |
| 5271 tbody = document.createElement("tbody"); | |
| 5272 tbl.appendChild(tbody); | |
| 5273 tfoot = document.createElement("tfoot"); | |
| 5274 tbl.appendChild(tfoot); | |
| 5275 | |
| 5276 row = thead.insertRow(thead.rows.length); | |
| 5277 add_text_header_cell(row, "", "", "motif_ordinal"); | |
| 5278 add_text_header_cell(row, "Logo", "", "motif_logo"); | |
| 5279 add_text_header_cell(row, "E-value", "pop_ev", "motif_evalue"); | |
| 5280 add_text_header_cell(row, "Sites", "pop_sites", "motif_nsites"); | |
| 5281 add_text_header_cell(row, "Width", "pop_width", "motif_width"); | |
| 5282 add_text_header_cell(row, "More", "pop_more", "motif_more"); | |
| 5283 add_text_header_cell(row, "Submit/Download", "pop_submit_dl", "motif_submit"); | |
| 5284 | |
| 5285 for (i = 0; i < motifs.length; i++) { | |
| 5286 row = tbody.insertRow(tbody.rows.length); | |
| 5287 make_motif_table_entry(row, alphabet, start_ordinal + i, motifs[i], colw); | |
| 5288 } | |
| 5289 | |
| 5290 row = tfoot.insertRow(tfoot.rows.length); | |
| 5291 add_text_header_cell(row, stop_reason, "", "stop_reason", "", 6); | |
| 5292 | |
| 5293 return tbl; | |
| 5294 } | |
| 5295 | |
| 5296 function make_expanded_motif(alphabet, ordinal, motif, less_x, submit_x) { | |
| 5297 "use strict"; | |
| 5298 var box, pspm, logo_box, large_logo, large_logo_rc, tab_logo, tab_logo_rc; | |
| 5299 var btn, offset, norc; | |
| 5300 | |
| 5301 box = clone_template("tmpl_motif_expanded"); | |
| 5302 box.data_motif = motif; | |
| 5303 box.data_ordinal = ordinal; | |
| 5304 | |
| 5305 pspm = new Pspm(motif["pwm"]); | |
| 5306 if (typeof motif["rc"] !== "boolean") { | |
| 5307 motif["rc"] = false; | |
| 5308 } | |
| 5309 if (motif["large_logo"]) { | |
| 5310 large_logo = motif["large_logo"]; | |
| 5311 large_logo_rc = motif["large_logo_rc"]; | |
| 5312 } else { | |
| 5313 large_logo = make_large_logo(alphabet, pspm, false, 0); | |
| 5314 motif["large_logo"] = large_logo; | |
| 5315 if (alphabet.has_complement()) { | |
| 5316 large_logo_rc = make_large_logo(alphabet, pspm, true, 0, "logo_rc"); | |
| 5317 motif["large_logo_rc"] = large_logo_rc; | |
| 5318 } | |
| 5319 } | |
| 5320 norc = (large_logo_rc == null); | |
| 5321 toggle_class(box, "norc", norc); | |
| 5322 | |
| 5323 logo_box = find_child(box, "tvar_logo"); | |
| 5324 logo_box.appendChild(large_logo); | |
| 5325 if (large_logo_rc) logo_box.appendChild(large_logo_rc); | |
| 5326 toggle_class(logo_box, "show_rc_logo", motif["rc"]); | |
| 5327 | |
| 5328 tab_logo = find_child(box, "tvar_tab"); | |
| 5329 tab_logo_rc = find_child(box, "tvar_tab_rc"); | |
| 5330 | |
| 5331 toggle_class(tab_logo, "activeTab", !motif["rc"]); | |
| 5332 toggle_class(tab_logo_rc, "activeTab", motif["rc"]); | |
| 5333 | |
| 5334 tab_logo.addEventListener('click', action_rc_tab, false); | |
| 5335 tab_logo.addEventListener('keydown', action_rc_tab, false); | |
| 5336 tab_logo_rc.addEventListener('click', action_rc_tab, false); | |
| 5337 tab_logo_rc.addEventListener('keydown', action_rc_tab, false); | |
| 5338 | |
| 5339 set_tvar(box, "tvar_ordinal", ordinal); | |
| 5340 set_tvar(box, "tvar_evalue", motif["evalue"]); | |
| 5341 set_tvar(box, "tvar_width", motif["len"]); | |
| 5342 set_tvar(box, "tvar_site_count", motif["nsites"]); | |
| 5343 set_tvar(box, "tvar_llr", motif["llr"]); | |
| 5344 set_tvar(box, "tvar_ic", motif["ic"]); | |
| 5345 set_tvar(box, "tvar_re", motif["re"]); | |
| 5346 set_tvar(box, "tvar_bt", motif["bt"]); | |
| 5347 set_tvar(box, "tvar_sites", make_sites(motif)); | |
| 5348 | |
| 5349 offset = 32; // 1* 5px padding + 2 * 10px padding + 2 * 2px border + 3px ?? | |
| 5350 | |
| 5351 btn = find_child(box, "tvar_less"); | |
| 5352 btn.style.left = (less_x - offset) + "px"; | |
| 5353 btn.addEventListener('click', action_show_less, false); | |
| 5354 btn.addEventListener('keydown', action_show_less, false); | |
| 5355 btn = find_child(box, "tvar_submit"); | |
| 5356 btn.style.left = (submit_x - offset) + "px"; | |
| 5357 btn.addEventListener('click', action_show_outpop, false); | |
| 5358 btn.addEventListener('keydown', action_show_outpop, false); | |
| 5359 return box; | |
| 5360 } | |
| 5361 | |
| 5362 | |
| 5363 // | |
| 5364 // | |
| 5365 /// | |
| 5366 function make_motifs() { | |
| 5367 "use strict"; | |
| 5368 function pixel_value(str_in) { | |
| 5369 "use strict"; | |
| 5370 var px_re, match; | |
| 5371 px_re = /^(\d+)px$/; | |
| 5372 if (match = px_re.exec(str_in)) { | |
| 5373 return parseInt(match[1], 10); | |
| 5374 } | |
| 5375 return 0; | |
| 5376 } | |
| 5377 var container, tbl; | |
| 5378 var colw, r, row, c, cell, cell_style, pad_left, pad_right; | |
| 5379 | |
| 5380 // make the motifs table | |
| 5381 container = $("motifs"); | |
| 5382 container.innerHTML = ""; // clear content | |
| 5383 | |
| 5384 tbl = make_motifs_table(meme_alphabet, 1, data["motifs"], colw, data["stop_reason"]); | |
| 5385 container.appendChild(tbl); | |
| 5386 | |
| 5387 // measure table column widths | |
| 5388 colw = []; | |
| 5389 row = tbl.tBodies[0].rows[0]; | |
| 5390 for (c = 0; c < row.cells.length; c++) { | |
| 5391 var padLeft, padRight; | |
| 5392 cell = row.cells[c]; | |
| 5393 cell_style = window.getComputedStyle(cell, null); | |
| 5394 pad_left = pixel_value(cell_style.getPropertyValue("padding-left")); | |
| 5395 pad_right = pixel_value(cell_style.getPropertyValue("padding-right")); | |
| 5396 colw[c] = cell.clientWidth - pad_left - pad_right; | |
| 5397 if (typeof colw[c] !== "number" || colw[c] < 0) { | |
| 5398 colw[c] = 1; | |
| 5399 } | |
| 5400 } | |
| 5401 | |
| 5402 // set minimum table column widths on each row so later when we remove rows it still aligns | |
| 5403 for (r = 0; r < tbl.tBodies[0].rows.length; r++) { | |
| 5404 row = tbl.tBodies[0].rows[r]; | |
| 5405 for (c = 0; c < row.cells.length; c++) { | |
| 5406 row.cells[c].style.minWidth = colw[c] + "px"; | |
| 5407 } | |
| 5408 } | |
| 5409 | |
| 5410 // store the table column widths so we can create rows latter with the same minimums | |
| 5411 container.data_colw = colw; | |
| 5412 | |
| 5413 // calculate the x offset for the buttons | |
| 5414 row = tbl.tBodies[0].rows[0]; | |
| 5415 container.data_more_x = coords(find_child(find_child(row, "motif_more"), "sym_btn"))[0]; | |
| 5416 container.data_submit_x = coords(find_child(find_child(row, "motif_submit"), "sym_btn"))[0]; | |
| 5417 | |
| 5418 draw_on_screen(); | |
| 5419 } | |
| 5420 | |
| 5421 function make_meme_block(container, max_seq_len, is_scan, site) { | |
| 5422 "use strict"; | |
| 5423 var motif = data.motifs[site.motif]; | |
| 5424 var block = make_block(container, max_seq_len, site.pos, motif.len, | |
| 5425 site.pvalue, site.rc, site.motif, is_scan); | |
| 5426 var handler = (is_scan ? | |
| 5427 make_scan_popup(site, motif, block) : | |
| 5428 make_block_popup(site, motif, block)); | |
| 5429 block.addEventListener("mouseover", handler, false); | |
| 5430 block.addEventListener("mouseout", handler, false); | |
| 5431 } | |
| 5432 | |
| 5433 function append_blocks_entries(tbody, seq_index, count) { | |
| 5434 "use strict"; | |
| 5435 var i, end, j; | |
| 5436 var max_pvalue, max_block_height, max_seq_len, sequences; | |
| 5437 var sequence, sites, scans, scan; | |
| 5438 var container, plus, minus, rule, row; | |
| 5439 // define some constants | |
| 5440 max_seq_len = data.sequence_db.max_length; | |
| 5441 // determine how many to load | |
| 5442 end = Math.min(seq_index + count, data.sequence_db.sequences.length); | |
| 5443 for (i = seq_index; i < end; i++) { | |
| 5444 // get the sequence | |
| 5445 sequence = data.sequence_db.sequences[i]; | |
| 5446 // make the containers for the block diagram | |
| 5447 container = make_block_container(meme_alphabet.has_complement(), | |
| 5448 data.options.revcomp, max_seq_len, sequence.length); | |
| 5449 // create blocks for the motif sites | |
| 5450 sites = sequence["sites"]; | |
| 5451 for (j = 0; j < sites.length; j++) | |
| 5452 make_meme_block(container, max_seq_len, false, sites[j]); | |
| 5453 // create blocks for the scanned sites | |
| 5454 scan = data.scan[i]; | |
| 5455 for (j = 0; j < scan.sites.length; j++) | |
| 5456 make_meme_block(container, max_seq_len, true, scan.sites[j]); | |
| 5457 // create a row for the sequence | |
| 5458 row = tbody.insertRow(tbody.rows.length); | |
| 5459 toggle_class(row, "empty_seq", sites.length == 0 && scan.sites.length == 0); | |
| 5460 toggle_class(row, "only_scan", sites.length == 0 && scan.sites.length > 0); | |
| 5461 add_text_cell(row, (i + 1) + ".", "blockdiag_num"); | |
| 5462 add_text_cell(row, sequence["name"], "blockdiag_name"); | |
| 5463 add_text_cell(row, scan["pvalue"].toExponential(2), "blockdiag_pvalue"); | |
| 5464 add_cell(row, container, "block_td"); | |
| 5465 } | |
| 5466 return end; | |
| 5467 } | |
| 5468 | |
| 5469 function make_blocks_entries() { | |
| 5470 "use strict"; | |
| 5471 var region; | |
| 5472 region = this; | |
| 5473 if (region.data_blocks_index >= data["sequence_db"]["sequences"].length) { | |
| 5474 // all sites created | |
| 5475 region.removeEventListener('scroll', make_blocks_entries, false); | |
| 5476 return; | |
| 5477 } | |
| 5478 // if there's still 100 pixels to scroll than don't do anything yet | |
| 5479 if (region.scrollHeight - (region.scrollTop + region.offsetHeight) > 100) { | |
| 5480 return; | |
| 5481 } | |
| 5482 | |
| 5483 region.data_blocks_index = append_blocks_entries( | |
| 5484 find_child(region, "blocks_tbl").tBodies[0], | |
| 5485 region.data_blocks_index, 20 | |
| 5486 ); | |
| 5487 } | |
| 5488 | |
| 5489 function make_blocks() { | |
| 5490 "use strict"; | |
| 5491 function add_seqs_filter(container, id, checked, label_text, help_topic) { | |
| 5492 "use strict"; | |
| 5493 var label, radio; | |
| 5494 radio = document.createElement("input"); | |
| 5495 radio.type = "radio"; | |
| 5496 radio.name = "seqs_display"; | |
| 5497 radio.id = id; | |
| 5498 radio.checked = checked; | |
| 5499 radio.addEventListener('click', action_seqs_filter, false); | |
| 5500 label = document.createElement("label"); | |
| 5501 label.appendChild(document.createTextNode(label_text)); | |
| 5502 label.htmlFor = id; | |
| 5503 container.appendChild(radio); | |
| 5504 container.appendChild(label); | |
| 5505 if (help_topic) { | |
| 5506 container.appendChild(document.createTextNode("\xA0")); | |
| 5507 container.appendChild(help_button(help_topic)); | |
| 5508 } | |
| 5509 } | |
| 5510 function add_blocks_header(row, title, nopad, help_topic) { | |
| 5511 "use strict"; | |
| 5512 var div, divcp, th; | |
| 5513 th = document.createElement("th"); | |
| 5514 div = document.createElement("div"); | |
| 5515 div.className = "blocks_th_inner"; | |
| 5516 if (typeof title !== "object") { | |
| 5517 title = document.createTextNode("" + title); | |
| 5518 } | |
| 5519 div.appendChild(title); | |
| 5520 if (help_topic) { | |
| 5521 div.appendChild(document.createTextNode("\xA0")); | |
| 5522 div.appendChild(help_button(help_topic)); | |
| 5523 } | |
| 5524 divcp = div.cloneNode(true); | |
| 5525 divcp.className = "blocks_th_hidden"; | |
| 5526 th.appendChild(div); | |
| 5527 th.appendChild(divcp); | |
| 5528 if (nopad) { | |
| 5529 th.className = "nopad"; | |
| 5530 } | |
| 5531 row.appendChild(th); | |
| 5532 } | |
| 5533 var container; | |
| 5534 var page, view_height, outer_tbl, inner_tbl, tbl, thead, tbody, rhead; | |
| 5535 var in_view, i, seq_count; | |
| 5536 | |
| 5537 page = (document.compatMode === "CSS1Compat") ? document.documentElement : document.body; | |
| 5538 view_height = Math.max(page.clientHeight - 300, 300); | |
| 5539 | |
| 5540 container = $("blocks"); | |
| 5541 toggle_class(container, "hide_empty_seqs", true); | |
| 5542 toggle_class(container, "hide_only_scan", true); | |
| 5543 container.innerHTML = ""; | |
| 5544 add_seqs_filter(container, "rdo_sites_only", true, "Only Motif Sites", "pop_motif_sites"); | |
| 5545 add_seqs_filter(container, "rdo_sites_and_scan", false, "Motif Sites+Scanned Sites", "pop_scanned_sites"); | |
| 5546 add_seqs_filter(container, "rdo_all_seqs", false, "All Sequences", "pop_all_sequences"); | |
| 5547 | |
| 5548 outer_tbl = document.createElement("div"); | |
| 5549 outer_tbl.className = "blocks_outer"; | |
| 5550 | |
| 5551 inner_tbl = document.createElement("div"); | |
| 5552 inner_tbl.id = "blocks_scroll"; | |
| 5553 inner_tbl.className = "blocks_inner"; | |
| 5554 inner_tbl.style.maxHeight = view_height + "px"; | |
| 5555 outer_tbl.appendChild(inner_tbl); | |
| 5556 | |
| 5557 tbl = document.createElement("table"); | |
| 5558 tbl.className = "blocks_tbl"; | |
| 5559 inner_tbl.appendChild(tbl); | |
| 5560 | |
| 5561 thead = document.createElement("thead"); | |
| 5562 tbl.appendChild(thead); | |
| 5563 tbody = document.createElement("tbody"); | |
| 5564 tbl.appendChild(tbody); | |
| 5565 | |
| 5566 rhead = thead.insertRow(thead.rows.length); | |
| 5567 add_blocks_header(rhead, "", true); | |
| 5568 add_blocks_header(rhead, "Name", false, "pop_seq_name"); | |
| 5569 add_blocks_header(rhead, make_pv_text(), false, "pop_seq_pvalue"); | |
| 5570 add_blocks_header(rhead, "Motif Location", false, "pop_motif_location"); | |
| 5571 | |
| 5572 container.appendChild(outer_tbl); | |
| 5573 | |
| 5574 | |
| 5575 seq_count = data["sequence_db"]["sequences"].length; | |
| 5576 in_view = Math.max(Math.ceil(view_height / 25), 1); | |
| 5577 i = append_blocks_entries(tbody, 0, in_view); | |
| 5578 | |
| 5579 while (i < seq_count && inner_tbl.scrollHeight - (inner_tbl.scrollTop + inner_tbl.offsetHeight) < 400) { | |
| 5580 i = append_blocks_entries(tbody, i, 20); | |
| 5581 } | |
| 5582 inner_tbl.data_blocks_index = i; | |
| 5583 if (i < seq_count) { | |
| 5584 inner_tbl.addEventListener('scroll', make_blocks_entries, false); | |
| 5585 } | |
| 5586 } | |
| 5587 | |
| 5588 function make_scan_popup(site, motif) { | |
| 5589 return function (e) { | |
| 5590 "use strict"; | |
| 5591 var pop, xy, padding, edge_padding, pop_left, pop_top, page_width; | |
| 5592 var lflank, match, rflank, pspm; | |
| 5593 if (!e) var e = window.event; | |
| 5594 pop = make_scan_popup.pop; | |
| 5595 if (e.type === "mouseover") { | |
| 5596 if (pop) return; | |
| 5597 pop = clone_template("tmpl_scan_info"); | |
| 5598 pspm = new Pspm(motif.pwm); | |
| 5599 if (site.rc) pspm.reverse_complement(meme_alphabet); | |
| 5600 set_tvar(pop, "tvar_logo", make_small_logo(meme_alphabet, pspm, {"className": "scan_logo"})); | |
| 5601 set_tvar(pop, "tvar_motif", motif.id); | |
| 5602 set_tvar(pop, "tvar_pvalue", site.pvalue.toExponential(2)); | |
| 5603 set_tvar(pop, "tvar_start", site.pos + 1); | |
| 5604 set_tvar(pop, "tvar_end", site.pos + motif.len); | |
| 5605 | |
| 5606 document.body.appendChild(pop); | |
| 5607 position_popup(this, pop); | |
| 5608 make_scan_popup.pop = pop; | |
| 5609 } else if (e.type === "mouseout") { | |
| 5610 if (pop) { | |
| 5611 pop.parentNode.removeChild(pop); | |
| 5612 make_scan_popup.pop = null; | |
| 5613 } | |
| 5614 } | |
| 5615 }; | |
| 5616 } | |
| 5617 | |
| 5618 function make_block_popup(site, motif, block) { | |
| 5619 return function (e) { | |
| 5620 "use strict"; | |
| 5621 var pop; | |
| 5622 var lflank, match, rflank, pspm, ruler, match_seq, match_width; | |
| 5623 if (!e) var e = window.event; | |
| 5624 pop = make_block_popup.pop; | |
| 5625 if (e.type === "mouseover") { | |
| 5626 if (pop) return; | |
| 5627 pop = clone_template("tmpl_block_info"); | |
| 5628 pspm = new Pspm(motif.pwm); | |
| 5629 if (site.rc) { // must be dna | |
| 5630 pspm.reverse_complement(meme_alphabet); | |
| 5631 lflank = meme_alphabet.invcomp_seq(site.rflank); | |
| 5632 match = meme_alphabet.invcomp_seq(site.match); | |
| 5633 rflank = meme_alphabet.invcomp_seq(site.lflank); | |
| 5634 } else { | |
| 5635 lflank = site.lflank; | |
| 5636 match = site.match; | |
| 5637 rflank = site.rflank; | |
| 5638 } | |
| 5639 ruler = document.getElementById("measure_match"); | |
| 5640 match_seq = make_seq(meme_alphabet, match); | |
| 5641 ruler.innerHTML = ""; | |
| 5642 ruler.appendChild(match_seq); | |
| 5643 match_width = ruler.clientWidth; | |
| 5644 ruler.removeChild(match_seq); | |
| 5645 set_tvar(pop, "tvar_lflank", lflank); | |
| 5646 set_tvar(pop, "tvar_match", match_seq); | |
| 5647 set_tvar(pop, "tvar_rflank", rflank); | |
| 5648 set_tvar(pop, "tvar_logo_pad", lflank); | |
| 5649 set_tvar(pop, "tvar_logo", make_small_logo(meme_alphabet, pspm, {"width": match_width})); | |
| 5650 set_tvar(pop, "tvar_motif", motif.id); | |
| 5651 set_tvar(pop, "tvar_pvalue", site.pvalue.toExponential(2)); | |
| 5652 set_tvar(pop, "tvar_start", site.pos + 1); | |
| 5653 set_tvar(pop, "tvar_end", site.pos + motif.len); | |
| 5654 | |
| 5655 document.body.appendChild(pop); | |
| 5656 position_popup(block, pop); | |
| 5657 make_block_popup.pop = pop; | |
| 5658 } else if (e.type === "mouseout") { | |
| 5659 if (pop) { | |
| 5660 pop.parentNode.removeChild(pop); | |
| 5661 make_block_popup.pop = null; | |
| 5662 } | |
| 5663 } | |
| 5664 }; | |
| 5665 } | |
| 5666 | |
| 5667 function update_outpop_format(index) { | |
| 5668 switch(parseInt($("text_format").value)) { | |
| 5669 case 0: // count matrix | |
| 5670 $("outpop_text").value = motif_count_matrix(index); | |
| 5671 $("text_name").value = "motif_" + (index + 1) + "_counts.txt"; | |
| 5672 break; | |
| 5673 case 1: // prob matrix | |
| 5674 $("outpop_text").value = motif_prob_matrix(index); | |
| 5675 $("text_name").value = "motif_" + (index + 1) + "_freqs.txt"; | |
| 5676 break; | |
| 5677 case 2: // minimal meme | |
| 5678 $("outpop_text").value = motif_minimal_meme(index); | |
| 5679 $("text_name").value = "motif_" + (index + 1) + ".txt"; | |
| 5680 break; | |
| 5681 case 3: // fasta | |
| 5682 $("outpop_text").value = motif_fasta(index); | |
| 5683 $("text_name").value = "motif_" + (index + 1) + "_fasta.txt"; | |
| 5684 break; | |
| 5685 case 4: // raw | |
| 5686 $("outpop_text").value = motif_raw(index); | |
| 5687 $("text_name").value = "motif_" + (index + 1) + "_raw.txt"; | |
| 5688 break; | |
| 5689 default: | |
| 5690 throw new Error("Unknown motif format"); | |
| 5691 } | |
| 5692 } | |
| 5693 | |
| 5694 function update_outpop_motif(index) { | |
| 5695 "use strict"; | |
| 5696 var motifs, motif, pspm, logo, canvas, num; | |
| 5697 motifs = data["motifs"]; | |
| 5698 if (index < 0 || index >= motifs.length) {return;} | |
| 5699 current_motif = index; | |
| 5700 motif = motifs[index]; | |
| 5701 pspm = new Pspm(motif["pwm"]); | |
| 5702 logo = new Logo(meme_alphabet, ""); | |
| 5703 logo.add_pspm(pspm, 0); | |
| 5704 canvas = $("outpop_logo"); | |
| 5705 canvas.width = canvas.width; // clear canvas | |
| 5706 draw_logo_on_canvas(logo, canvas, false); | |
| 5707 if (meme_alphabet.has_complement()) { | |
| 5708 pspm.reverse_complement(meme_alphabet); | |
| 5709 logo = new Logo(meme_alphabet, ""); | |
| 5710 canvas = $("outpop_logo_rc"); | |
| 5711 canvas.width = canvas.width; // clear canvas | |
| 5712 draw_logo_on_canvas(logo, canvas, false); | |
| 5713 } | |
| 5714 num = $("outpop_num"); | |
| 5715 num.innerHTML = ""; | |
| 5716 num.appendChild(document.createTextNode("" + (index + 1))); | |
| 5717 update_outpop_format(index); | |
| 5718 } | |
| 5719 | |
| 5720 // | |
| 5721 // action_show_more | |
| 5722 // | |
| 5723 // Show more information on the motif. | |
| 5724 /// | |
| 5725 function action_show_more(e) { | |
| 5726 var node, tr, tbody, table, container, motif, ordinal; | |
| 5727 var expanded_motif; | |
| 5728 if (!e) e = window.event; | |
| 5729 if (e.type === "keydown") { | |
| 5730 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
| 5731 return; | |
| 5732 } | |
| 5733 // stop a submit or something like that | |
| 5734 e.preventDefault(); | |
| 5735 } | |
| 5736 // find the row that contains the cell | |
| 5737 node = this; | |
| 5738 do { | |
| 5739 if (node.tagName === "TR") break; | |
| 5740 } while (node = node.parentNode); | |
| 5741 if (!node) throw new Error("Expected to find row!?"); | |
| 5742 tr = node; | |
| 5743 // get info | |
| 5744 motif = tr.data_motif; | |
| 5745 ordinal = tr.data_ordinal; | |
| 5746 // find tbody | |
| 5747 do { | |
| 5748 if (node.tagName === "TBODY") break; | |
| 5749 } while (node = node.parentNode); | |
| 5750 if (!node) throw new Error("Expected to find tbody!?"); | |
| 5751 tbody = node; | |
| 5752 // find table | |
| 5753 do { | |
| 5754 if (node.tagName === "TABLE") break; | |
| 5755 } while (node = node.parentNode); | |
| 5756 if (!node) throw new Error("Expected to find table!?"); | |
| 5757 table = node; | |
| 5758 // find container | |
| 5759 container = node.parentNode; | |
| 5760 // make a expanded motif | |
| 5761 motif["expanded"] = true; | |
| 5762 expanded_motif = make_expanded_motif(meme_alphabet, ordinal, motif, | |
| 5763 container.data_more_x, container.data_submit_x); | |
| 5764 // now determine how to place it | |
| 5765 if (tbody.rows.length === 1) { | |
| 5766 // only us in the table so the table can be replaced | |
| 5767 container.replaceChild(expanded_motif, table); | |
| 5768 } else if (tbody.rows[0] === tr) { | |
| 5769 // first row, so remove and insert an expanded motif before | |
| 5770 table.deleteRow(tr.rowIndex); | |
| 5771 container.insertBefore(expanded_motif, table); | |
| 5772 } else if (tbody.rows[tbody.rows.length -1] === tr) { | |
| 5773 // last row, so remove and insert an expanded motif after | |
| 5774 table.deleteRow(tr.rowIndex); | |
| 5775 container.insertBefore(expanded_motif, table.nextSibling); | |
| 5776 } else { | |
| 5777 var table2, tbody2; | |
| 5778 table2 = table.cloneNode(false); | |
| 5779 table2.appendChild(table.tHead.cloneNode(true)); | |
| 5780 tbody2 = table.tBodies[0].cloneNode(false); | |
| 5781 table2.appendChild(tbody2); | |
| 5782 container.insertBefore(table2, table.nextSibling); | |
| 5783 for (i = tbody.rows.length - 1; i >= 0; i--) { | |
| 5784 row = tbody.rows[i]; | |
| 5785 row.parentNode.removeChild(row); | |
| 5786 if (row === tr) { | |
| 5787 break; | |
| 5788 } | |
| 5789 tbody2.insertBefore(row, tbody2.rows[0]); | |
| 5790 } | |
| 5791 container.insertBefore(expanded_motif, table2); | |
| 5792 } | |
| 5793 find_child(expanded_motif, "tvar_less").focus(); | |
| 5794 } | |
| 5795 | |
| 5796 // | |
| 5797 // action_show_less | |
| 5798 // | |
| 5799 // Show less information on the motif. | |
| 5800 /// | |
| 5801 function action_show_less(e) { | |
| 5802 var btn; | |
| 5803 var expanded_motif, container, motif, ordinal, colw, focus_target; | |
| 5804 var table, tbody, tbody2, row, table_before, table_after; | |
| 5805 if (!e) e = window.event; | |
| 5806 if (e.type === "keydown") { | |
| 5807 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
| 5808 return; | |
| 5809 } | |
| 5810 // stop a submit or something like that | |
| 5811 e.preventDefault(); | |
| 5812 } | |
| 5813 btn = this; | |
| 5814 // find expanded motif | |
| 5815 expanded_motif = find_parent(btn, "expanded_motif"); | |
| 5816 if (!expanded_motif) throw new Error("Expected expanded motif."); | |
| 5817 // find the container | |
| 5818 container = expanded_motif.parentNode; | |
| 5819 // get data | |
| 5820 motif = expanded_motif.data_motif; | |
| 5821 ordinal = expanded_motif.data_ordinal; | |
| 5822 colw = container.data_colw; | |
| 5823 // get the table before | |
| 5824 table_before = expanded_motif.previousSibling; | |
| 5825 if (table_before && table_before.tagName !== "TABLE") { | |
| 5826 table_before = null; | |
| 5827 } | |
| 5828 // get the table after | |
| 5829 table_after = expanded_motif.nextSibling; | |
| 5830 if (table_after && table_after.tagName !== "TABLE") { | |
| 5831 table_after = null; | |
| 5832 } | |
| 5833 // see if there is a table below or above that we can put this in. | |
| 5834 // if there is a table both below and above then add this motif and | |
| 5835 // all ones below to the above table | |
| 5836 motif["expanded"] = false; | |
| 5837 if (table_before && table_after) { | |
| 5838 tbody = table_before.tBodies[0]; | |
| 5839 row = tbody.insertRow(tbody.rows.length); | |
| 5840 make_motif_table_entry(row, meme_alphabet, ordinal, motif, colw); | |
| 5841 focus_target = find_child(row.cells[5], "sym_btn"); | |
| 5842 container.removeChild(expanded_motif); | |
| 5843 tbody2 = table_after.tBodies[0]; | |
| 5844 while (tbody2.rows.length > 0) { | |
| 5845 row = tbody2.rows[0]; | |
| 5846 row.parentNode.removeChild(row); | |
| 5847 tbody.appendChild(row); | |
| 5848 } | |
| 5849 container.removeChild(table_after); | |
| 5850 } else if (table_before) { | |
| 5851 tbody = table_before.tBodies[0]; | |
| 5852 row = tbody.insertRow(tbody.rows.length); | |
| 5853 make_motif_table_entry(row, meme_alphabet, ordinal, motif, colw); | |
| 5854 focus_target = find_child(row.cells[5], "sym_btn"); | |
| 5855 container.removeChild(expanded_motif); | |
| 5856 } else if (table_after) { | |
| 5857 tbody = table_after.tBodies[0]; | |
| 5858 row = tbody.insertRow(0); | |
| 5859 make_motif_table_entry(row, meme_alphabet, ordinal, motif, colw); | |
| 5860 focus_target = find_child(row.cells[5], "sym_btn"); | |
| 5861 container.removeChild(expanded_motif); | |
| 5862 } else { | |
| 5863 //no table above or below! | |
| 5864 // make a new table | |
| 5865 table = make_motifs_table(meme_alphabet, ordinal, [motif], colw, data["stop_reason"]); | |
| 5866 focus_target = find_child(table.tBodies[0].rows[0].cells[5], "sym_btn"); | |
| 5867 container.replaceChild(table, expanded_motif); | |
| 5868 } | |
| 5869 focus_target.focus(); | |
| 5870 } | |
| 5871 | |
| 5872 function action_show_outpop(e) { | |
| 5873 "use strict"; | |
| 5874 function init() { | |
| 5875 "use strict"; | |
| 5876 var close_btn, next_btn, prev_btn, cancel_btn, do_btn; | |
| 5877 var tab1, tab2, tab3; | |
| 5878 var pnl1, pnl2, pnl3; | |
| 5879 var format_list; | |
| 5880 var tbl_submit, inputs, i, default_prog; | |
| 5881 close_btn = $("outpop_close"); | |
| 5882 close_btn.addEventListener("click", action_hide_outpop, false); | |
| 5883 close_btn.addEventListener("keydown", action_hide_outpop, false); | |
| 5884 next_btn = $("outpop_next"); | |
| 5885 next_btn.addEventListener("click", action_outpop_next, false); | |
| 5886 next_btn.addEventListener("keydown", action_outpop_next, false); | |
| 5887 prev_btn = $("outpop_prev"); | |
| 5888 prev_btn.addEventListener("click", action_outpop_prev, false); | |
| 5889 prev_btn.addEventListener("keydown", action_outpop_prev, false); | |
| 5890 cancel_btn = $("outpop_cancel"); | |
| 5891 cancel_btn.addEventListener("click", action_hide_outpop, false); | |
| 5892 do_btn = $("outpop_do"); | |
| 5893 do_btn.addEventListener("click", action_outpop_submit, false); | |
| 5894 tab1 = $("outpop_tab_1"); | |
| 5895 tab1.tabIndex = 0; | |
| 5896 tab1.addEventListener("click", action_outpop_tab, false); | |
| 5897 tab1.addEventListener("keydown", action_outpop_tab, false); | |
| 5898 tab2 = $("outpop_tab_2"); | |
| 5899 tab2.tabIndex = 0; | |
| 5900 tab2.addEventListener("click", action_outpop_tab, false); | |
| 5901 tab2.addEventListener("keydown", action_outpop_tab, false); | |
| 5902 tab3 = $("outpop_tab_3"); | |
| 5903 tab3.tabIndex = 0; | |
| 5904 tab3.addEventListener("click", action_outpop_tab, false); | |
| 5905 tab3.addEventListener("keydown", action_outpop_tab, false); | |
| 5906 pnl1 = $("outpop_pnl_1"); | |
| 5907 pnl2 = $("outpop_pnl_2"); | |
| 5908 pnl3 = $("outpop_pnl_3"); | |
| 5909 toggle_class(tab1, "activeTab", true); | |
| 5910 toggle_class(tab2, "activeTab", false); | |
| 5911 toggle_class(tab3, "activeTab", false); | |
| 5912 pnl1.style.display = "block"; | |
| 5913 pnl2.style.display = "none"; | |
| 5914 pnl3.style.display = "none"; | |
| 5915 format_list = $("text_format"); | |
| 5916 format_list.addEventListener("change", action_outpop_format, false); | |
| 5917 // setup program selection | |
| 5918 tbl_submit = $("programs"); | |
| 5919 // when not dna, hide the inputs for programs that require dna motifs | |
| 5920 toggle_class(tbl_submit, "alphabet_dna", meme_alphabet.has_complement());//TODO FIXME alphabet_dna is a bad name for a field when allowing custom alphabets | |
| 5921 // add a click listener for the radio buttons | |
| 5922 inputs = tbl_submit.querySelectorAll("input[type='radio']"); | |
| 5923 for (i = 0; i < inputs.length; i++) { | |
| 5924 inputs[i].addEventListener("click", action_outpop_program, false); | |
| 5925 } | |
| 5926 // ensure that a default program option is selected for DNA and Protein | |
| 5927 default_prog = document.getElementById(meme_alphabet.has_complement() ? "submit_tomtom" : "submit_fimo"); //TODO FIXME Tomtom might require a more strict definition of DNA | |
| 5928 default_prog.checked = true; | |
| 5929 action_outpop_program.call(default_prog); | |
| 5930 // disable reverse-complement when not DNA | |
| 5931 $("logo_rc_option").disabled = !meme_alphabet.has_complement(); | |
| 5932 // set errorbars on when ssc is on | |
| 5933 $("logo_ssc").addEventListener("change", action_outpop_ssc, false); | |
| 5934 } | |
| 5935 var node; | |
| 5936 // store the focused element | |
| 5937 action_hide_outpop.last_active = document.activeElement; | |
| 5938 if (!e) e = window.event; | |
| 5939 if (e.type === "keydown") { | |
| 5940 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
| 5941 return; | |
| 5942 } | |
| 5943 // stop a submit or something like that | |
| 5944 e.preventDefault(); | |
| 5945 } | |
| 5946 // hide the help popup | |
| 5947 help_popup(); | |
| 5948 // on first load initilize the popup | |
| 5949 if (!action_show_outpop.ready) { | |
| 5950 init(); | |
| 5951 action_show_outpop.ready = true; | |
| 5952 } | |
| 5953 // load the motif logo | |
| 5954 node = this; | |
| 5955 do { | |
| 5956 if (/\bexpanded_motif\b/.test(node.className) || node.tagName === "TR") break; | |
| 5957 } while (node = node.parentNode); | |
| 5958 if (node === null) throw new Error("Expected node!"); | |
| 5959 update_outpop_motif(node.data_ordinal - 1); | |
| 5960 // display the download popup | |
| 5961 $("grey_out_page").style.display = "block"; | |
| 5962 $("download").style.display = "block"; | |
| 5963 $("outpop_close").focus(); | |
| 5964 } | |
| 5965 | |
| 5966 function action_hide_outpop(e) { | |
| 5967 if (!e) e = window.event; | |
| 5968 if (e.type === "keydown") { | |
| 5969 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
| 5970 return; | |
| 5971 } | |
| 5972 // stop a submit or something like that | |
| 5973 e.preventDefault(); | |
| 5974 } | |
| 5975 $("download").style.display = "none"; | |
| 5976 $("grey_out_page").style.display = "none"; | |
| 5977 if (typeof action_hide_outpop.last_active !== "undefined") { | |
| 5978 action_hide_outpop.last_active.focus(); | |
| 5979 } | |
| 5980 } | |
| 5981 | |
| 5982 function action_outpop_next(e) { | |
| 5983 if (!e) e = window.event; | |
| 5984 if (e.type === "keydown") { | |
| 5985 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
| 5986 return; | |
| 5987 } | |
| 5988 // stop a submit or something like that | |
| 5989 e.preventDefault(); | |
| 5990 } | |
| 5991 update_outpop_motif(current_motif + 1); | |
| 5992 } | |
| 5993 | |
| 5994 function action_outpop_prev(e) { | |
| 5995 if (!e) e = window.event; | |
| 5996 if (e.type === "keydown") { | |
| 5997 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
| 5998 return; | |
| 5999 } | |
| 6000 // stop a submit or something like that | |
| 6001 e.preventDefault(); | |
| 6002 } | |
| 6003 update_outpop_motif(current_motif - 1); | |
| 6004 } | |
| 6005 | |
| 6006 function action_outpop_program() { | |
| 6007 "use strict"; | |
| 6008 var table, tr, rows, i; | |
| 6009 tr = find_parent_tag(this, "TR"); | |
| 6010 table = find_parent_tag(tr, "TABLE"); | |
| 6011 rows = table.querySelectorAll("tr"); | |
| 6012 for (i = 0; i < rows.length; i++) { | |
| 6013 toggle_class(rows[i], "selected", rows[i] === tr); | |
| 6014 } | |
| 6015 } | |
| 6016 | |
| 6017 function action_outpop_ssc() { | |
| 6018 "use strict"; | |
| 6019 $("logo_err").value = $("logo_ssc").value; | |
| 6020 } | |
| 6021 | |
| 6022 function action_outpop_submit(e) { | |
| 6023 "use strict"; | |
| 6024 var form, input, program, motifs; | |
| 6025 // find out which program is selected | |
| 6026 var radios, i; | |
| 6027 radios = document.getElementsByName("program"); | |
| 6028 program = "fimo"; // default to fimo, since it works with all alphabet types | |
| 6029 for (i = 0; i < radios.length; i++) { | |
| 6030 if (radios[i].checked) program = radios[i].value; | |
| 6031 } | |
| 6032 | |
| 6033 motifs = motif_minimal_meme(current_motif); | |
| 6034 form = document.createElement("form"); | |
| 6035 form.setAttribute("method", "post"); | |
| 6036 form.setAttribute("action", site_url + "/tools/" + program); | |
| 6037 | |
| 6038 input = document.createElement("input"); | |
| 6039 input.setAttribute("type", "hidden"); | |
| 6040 input.setAttribute("name", "motifs_embed"); | |
| 6041 input.setAttribute("value", motifs); | |
| 6042 form.appendChild(input); | |
| 6043 | |
| 6044 document.body.appendChild(form); | |
| 6045 form.submit(); | |
| 6046 document.body.removeChild(form); | |
| 6047 } | |
| 6048 | |
| 6049 function action_outpop_download_motif(e) { | |
| 6050 $("text_form").submit(); | |
| 6051 } | |
| 6052 | |
| 6053 function action_outpop_download_logo(e) { | |
| 6054 "use strict"; | |
| 6055 $("logo_motifs").value = motif_minimal_meme(current_motif); | |
| 6056 $("logo_form").submit(); | |
| 6057 } | |
| 6058 | |
| 6059 function action_btn_rc(e) { | |
| 6060 "use strict"; | |
| 6061 var node, tr, motif, box, logo_box, tab_st, tab_rc, rc; | |
| 6062 if (!e) e = window.event; | |
| 6063 if (e.type === "keydown") { | |
| 6064 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
| 6065 return; | |
| 6066 } | |
| 6067 // stop a submit or something like that | |
| 6068 e.preventDefault(); | |
| 6069 } | |
| 6070 node = this; | |
| 6071 do { | |
| 6072 if (node.tagName === "TR") break; | |
| 6073 } while (node = node.parentNode); | |
| 6074 if (!node) throw new Error("Expected to find row!?"); | |
| 6075 tr = node; | |
| 6076 // get info | |
| 6077 motif = tr.data_motif; | |
| 6078 box = find_parent(this, "preview_box"); | |
| 6079 logo_box = find_child(box, "preview_logo_box"); | |
| 6080 tab_st = find_child(box, "plus"); | |
| 6081 tab_rc = find_child(box, "minus"); | |
| 6082 rc = (this === tab_rc); | |
| 6083 motif["rc"] = rc; | |
| 6084 toggle_class(logo_box, "show_rc_logo", rc); | |
| 6085 toggle_class(tab_st, "active", !rc); | |
| 6086 toggle_class(tab_rc, "active", rc); | |
| 6087 } | |
| 6088 | |
| 6089 function action_rc_tab(e) { | |
| 6090 "use strict"; | |
| 6091 var box, logo_box, tab_st, tab_rc, rc; | |
| 6092 if (!e) e = window.event; | |
| 6093 if (e.type === "keydown") { | |
| 6094 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
| 6095 return; | |
| 6096 } | |
| 6097 // stop a submit or something like that | |
| 6098 e.preventDefault(); | |
| 6099 } | |
| 6100 box = find_parent(this, "expanded_motif"); | |
| 6101 logo_box = find_child(box, "tvar_logo"); | |
| 6102 tab_st = find_child(box, "tvar_tab"); | |
| 6103 tab_rc = find_child(box, "tvar_tab_rc"); | |
| 6104 rc = (this === tab_rc); | |
| 6105 box.data_motif["rc"] = rc; | |
| 6106 toggle_class(logo_box, "show_rc_logo", rc); | |
| 6107 toggle_class(tab_st, "activeTab", !rc); | |
| 6108 toggle_class(tab_rc, "activeTab", rc); | |
| 6109 } | |
| 6110 | |
| 6111 function action_outpop_tab(e) { | |
| 6112 "use strict"; | |
| 6113 var tab1, tab2, tab3, pnl1, pnl2, pnl3, do_btn; | |
| 6114 if (!e) e = window.event; | |
| 6115 if (e.type === "keydown") { | |
| 6116 if (e.keyCode !== 13 && e.keyCode !== 32) { | |
| 6117 return; | |
| 6118 } | |
| 6119 // stop a submit or something like that | |
| 6120 e.preventDefault(); | |
| 6121 } | |
| 6122 tab1 = $("outpop_tab_1"); | |
| 6123 tab2 = $("outpop_tab_2"); | |
| 6124 tab3 = $("outpop_tab_3"); | |
| 6125 pnl1 = $("outpop_pnl_1"); | |
| 6126 pnl2 = $("outpop_pnl_2"); | |
| 6127 pnl3 = $("outpop_pnl_3"); | |
| 6128 do_btn = $("outpop_do"); | |
| 6129 | |
| 6130 toggle_class(tab1, "activeTab", (this === tab1)); | |
| 6131 toggle_class(tab2, "activeTab", (this === tab2)); | |
| 6132 toggle_class(tab3, "activeTab", (this === tab3)); | |
| 6133 pnl1.style.display = ((this === tab1) ? "block" : "none"); | |
| 6134 pnl2.style.display = ((this === tab2) ? "block" : "none"); | |
| 6135 pnl3.style.display = ((this === tab3) ? "block" : "none"); | |
| 6136 do_btn.value = ((this === tab1) ? "Submit" : "Download"); | |
| 6137 do_btn.removeEventListener("click", action_outpop_submit, false); | |
| 6138 do_btn.removeEventListener("click", action_outpop_download_logo, false); | |
| 6139 do_btn.removeEventListener("click", action_outpop_download_motif, false); | |
| 6140 if (this === tab1) { | |
| 6141 do_btn.addEventListener("click", action_outpop_submit, false); | |
| 6142 } else if (this === tab2) { | |
| 6143 do_btn.addEventListener("click", action_outpop_download_motif, false); | |
| 6144 } else { | |
| 6145 do_btn.addEventListener("click", action_outpop_download_logo, false); | |
| 6146 } | |
| 6147 } | |
| 6148 | |
| 6149 function action_seqs_filter() { | |
| 6150 "use strict"; | |
| 6151 var block_container; | |
| 6152 block_container = $("blocks"); | |
| 6153 if ($("rdo_all_seqs").checked) { | |
| 6154 toggle_class(block_container, "hide_empty_seqs", false); | |
| 6155 toggle_class(block_container, "hide_only_scan", false); | |
| 6156 } else if ($("rdo_sites_and_scan").checked) { | |
| 6157 toggle_class(block_container, "hide_empty_seqs", true); | |
| 6158 toggle_class(block_container, "hide_only_scan", false); | |
| 6159 } else if ($("rdo_sites_only").checked) { | |
| 6160 toggle_class(block_container, "hide_empty_seqs", true); | |
| 6161 toggle_class(block_container, "hide_only_scan", true); | |
| 6162 } | |
| 6163 } | |
| 6164 | |
| 6165 function action_outpop_format() { | |
| 6166 update_outpop_format(current_motif); | |
| 6167 } | |
| 6168 | |
| 6169 // | |
| 6170 // page_loaded | |
| 6171 // | |
| 6172 // Called when the page has loaded for the first time. | |
| 6173 /// | |
| 6174 function page_loaded() { | |
| 6175 post_load_setup(); | |
| 6176 } | |
| 6177 | |
| 6178 // | |
| 6179 // page_loaded | |
| 6180 // | |
| 6181 // Called when a cached page is reshown. | |
| 6182 /// | |
| 6183 function page_shown(e) { | |
| 6184 if (e.persisted) post_load_setup(); | |
| 6185 } | |
| 6186 | |
| 6187 // | |
| 6188 // page_loaded | |
| 6189 // | |
| 6190 // Called when the page is resized | |
| 6191 /// | |
| 6192 function page_resized() { | |
| 6193 var page, blocks_scroll; | |
| 6194 update_scroll_pad(); | |
| 6195 page = (document.compatMode === "CSS1Compat") ? document.documentElement : document.body; | |
| 6196 blocks_scroll = $("blocks_scroll"); | |
| 6197 if (blocks_scroll) { | |
| 6198 blocks_scroll.style.maxHeight = Math.max(page.clientHeight - 300, 300) + "px"; | |
| 6199 } | |
| 6200 } | |
| 6201 | |
| 6202 // | |
| 6203 // pre_load_setup | |
| 6204 // | |
| 6205 // Run before the page is displayed | |
| 6206 /// | |
| 6207 function pre_load_setup() { | |
| 6208 var start, hue, sat, light, divisions; | |
| 6209 var i, j, motifs, motif, sites, site, sequences, sequence; | |
| 6210 var max_seq_len; | |
| 6211 motifs = data["motifs"]; | |
| 6212 sequences = data["sequence_db"]["sequences"]; | |
| 6213 max_seq_len = 1; | |
| 6214 for (i = 0; i < sequences.length; i++) { | |
| 6215 sequence = sequences[i]; | |
| 6216 sequence["sites"] = []; | |
| 6217 if (sequence["length"] > max_seq_len) { | |
| 6218 max_seq_len = sequence["length"]; | |
| 6219 } | |
| 6220 } | |
| 6221 data["sequence_db"]["max_length"] = max_seq_len; | |
| 6222 // use hsl colours | |
| 6223 start = 0; //red | |
| 6224 sat = 100; | |
| 6225 light = 50; | |
| 6226 for (i = 0; i < motifs.length; i++) { | |
| 6227 motif = motifs[i]; | |
| 6228 // give the motif a colour | |
| 6229 divisions = 1 << Math.ceil(Math.log(i + 1) / Math.LN2); | |
| 6230 hue = start + (360 / divisions) * ((i - (divisions >> 1)) * 2 + 1); | |
| 6231 motif["colour"] = "hsl(" + hue + ", " + sat + "%, " + light + "%)"; | |
| 6232 // associate sites with sequences as well | |
| 6233 // to make generating the block diagram easier | |
| 6234 sites = motif["sites"]; | |
| 6235 for (j = 0; j < sites.length; j++) { | |
| 6236 site = sites[j]; | |
| 6237 sequence = sequences[site["seq"]]; | |
| 6238 // record the motif index | |
| 6239 site["motif"] = i; | |
| 6240 // add the site to the sequence | |
| 6241 sequence["sites"].push(site); | |
| 6242 } | |
| 6243 } | |
| 6244 } | |
| 6245 | |
| 6246 // | |
| 6247 // post_load_setup | |
| 6248 // | |
| 6249 // Run when the page has loaded, or been reloaded. | |
| 6250 // | |
| 6251 function post_load_setup() { | |
| 6252 update_scroll_pad(); | |
| 6253 if (data["motifs"].length > 0) { | |
| 6254 make_motifs(); | |
| 6255 make_blocks(); | |
| 6256 } else { | |
| 6257 $("motifs").innerHTML = "<p>No significant motifs found!</p>"; // clear content | |
| 6258 $("motifs").innerHTML += "<p><b>" + data["stop_reason"] + "</b></p>"; | |
| 6259 $("blocks").innerHTML = "<p>No significant motifs found!</p>"; | |
| 6260 } | |
| 6261 } | |
| 6262 | |
| 6263 pre_load_setup(); | |
| 6264 </script> | |
| 6265 <style> | |
| 6266 /* The following is the content of meme.css */ | |
| 6267 body { background-color:white; font-size: 12px; font-family: Verdana, Arial, Helvetica, sans-serif;} | |
| 6268 | |
| 6269 div.help { | |
| 6270 display: inline-block; | |
| 6271 margin: 0px; | |
| 6272 padding: 0px; | |
| 6273 width: 12px; | |
| 6274 height: 13px; | |
| 6275 cursor: pointer; | |
| 6276 background-image: url(data:image/gif;base64,R0lGODlhDAANAIABANR0AP///yH5BAEAAAEALAAAAAAMAA0AAAIdhI8Xy22MIFgv1DttrrJ7mlGNNo4c+aFg6SQuUAAAOw==); | |
| 6277 } | |
| 6278 | |
| 6279 div.help:hover { | |
| 6280 background-image: url(data:image/gif;base64,R0lGODlhDAANAKEAANR0AP///9R0ANR0ACH+EUNyZWF0ZWQgd2l0aCBHSU1QACH5BAEAAAIALAAAAAAMAA0AAAIdDGynCe3PgoxONntvwqz2/z2K2ImjR0KhmSIZUgAAOw==); | |
| 6281 } | |
| 6282 | |
| 6283 p.spaced { line-height: 1.8em;} | |
| 6284 | |
| 6285 span.citation { font-family: "Book Antiqua", "Palatino Linotype", serif; color: #004a4d;} | |
| 6286 | |
| 6287 p.pad { padding-left: 30px; padding-top: 5px; padding-bottom: 10px;} | |
| 6288 | |
| 6289 td.jump { font-size: 13px; color: #ffffff; background-color: #00666a; | |
| 6290 font-family: Georgia, "Times New Roman", Times, serif;} | |
| 6291 | |
| 6292 a.jump { margin: 15px 0 0; font-style: normal; font-variant: small-caps; | |
| 6293 font-weight: bolder; font-family: Georgia, "Times New Roman", Times, serif;} | |
| 6294 | |
| 6295 h2.mainh {font-size: 1.5em; font-style: normal; margin: 15px 0 0; | |
| 6296 font-variant: small-caps; font-family: Georgia, "Times New Roman", Times, serif;} | |
| 6297 | |
| 6298 h2.line {border-bottom: 1px solid #CCCCCC; font-size: 1.5em; font-style: normal; | |
| 6299 margin: 15px 0 0; padding-bottom: 3px; font-variant: small-caps; | |
| 6300 font-family: Georgia, "Times New Roman", Times, serif;} | |
| 6301 | |
| 6302 h4 {border-bottom: 1px solid #CCCCCC; font-size: 1.2em; font-style: normal; | |
| 6303 margin: 10px 0 0; padding-bottom: 3px; font-family: Georgia, "Times New Roman", Times, serif;} | |
| 6304 | |
| 6305 h5 {margin: 0px} | |
| 6306 | |
| 6307 a.help { font-size: 9px; font-style: normal; text-transform: uppercase; | |
| 6308 font-family: Georgia, "Times New Roman", Times, serif;} | |
| 6309 | |
| 6310 div.pad { padding-left: 30px; padding-top: 5px; padding-bottom: 10px;} | |
| 6311 | |
| 6312 div.pad1 { margin: 10px 5px;} | |
| 6313 | |
| 6314 div.pad2 { margin: 25px 5px 5px;} | |
| 6315 h2.pad2 { padding: 25px 5px 5px;} | |
| 6316 | |
| 6317 div.pad3 { padding: 5px 0px 10px 30px;} | |
| 6318 | |
| 6319 div.box { border: 2px solid #CCCCCC; padding:10px; overflow: hidden;} | |
| 6320 | |
| 6321 div.bar { border-left: 7px solid #00666a; padding:5px; margin-top:25px; } | |
| 6322 | |
| 6323 div.subsection {margin:25px 0px;} | |
| 6324 | |
| 6325 img {border:0px none;} | |
| 6326 | |
| 6327 th.majorth {text-align:left;} | |
| 6328 th.minorth {font-weight:normal; text-align:left; width:8em; padding: 3px 0px;} | |
| 6329 th.actionth {font-weight:normal; text-align:left;} | |
| 6330 | |
| 6331 .explain h5 {font-size:1em; margin-left: 1em;} | |
| 6332 | |
| 6333 div.doc {margin-left: 2em; margin-bottom: 3em;} | |
| 6334 | |
| 6335 th.trainingset { | |
| 6336 border-bottom: thin dashed black; | |
| 6337 font-weight:normal; | |
| 6338 padding:0px 10px; | |
| 6339 } | |
| 6340 div.pop_content { | |
| 6341 position:absolute; | |
| 6342 z-index:50; | |
| 6343 width:300px; | |
| 6344 padding: 5px; | |
| 6345 background: #E4ECEC; | |
| 6346 font-size: 12px; | |
| 6347 font-family: Arial; | |
| 6348 border-style: double; | |
| 6349 border-width: 3px; | |
| 6350 border-color: #AA2244; | |
| 6351 display:none; | |
| 6352 } | |
| 6353 | |
| 6354 div.pop_content > *:first-child { | |
| 6355 margin-top: 0px; | |
| 6356 } | |
| 6357 | |
| 6358 div.pop_content h1, div.pop_content h2, div.pop_content h3, div.pop_content h4, | |
| 6359 div.pop_content h5, div.pop_content h6, div.pop_content p { | |
| 6360 margin: 0px; | |
| 6361 } | |
| 6362 | |
| 6363 div.pop_content p + h1, div.pop_content p + h2, div.pop_content p + h3, | |
| 6364 div.pop_content p + h4, div.pop_content p + h5, div.pop_content p + h6 { | |
| 6365 margin-top: 5px; | |
| 6366 } | |
| 6367 | |
| 6368 div.pop_content p + p { | |
| 6369 margin-top: 5px; | |
| 6370 } | |
| 6371 | |
| 6372 div.pop_content > *:last-child { | |
| 6373 margin-bottom: 0px; | |
| 6374 } | |
| 6375 | |
| 6376 div.pop_content div.pop_close { | |
| 6377 /* old definition */ | |
| 6378 float:right; | |
| 6379 bottom: 0; | |
| 6380 } | |
| 6381 | |
| 6382 div.pop_content span.pop_close, div.pop_content span.pop_back { | |
| 6383 display: inline-block; | |
| 6384 border: 2px outset #661429; | |
| 6385 background-color: #CCC; | |
| 6386 padding-left: 1px; | |
| 6387 padding-right: 1px; | |
| 6388 padding-top: 0px; | |
| 6389 padding-bottom: 0px; | |
| 6390 cursor: pointer; | |
| 6391 color: #AA2244; /*#661429;*/ | |
| 6392 font-weight: bold; | |
| 6393 } | |
| 6394 | |
| 6395 div.pop_content span.pop_close:active, div.pop_content span.pop_back:active { | |
| 6396 border-style: inset; | |
| 6397 } | |
| 6398 | |
| 6399 div.pop_content span.pop_close { | |
| 6400 float:right; | |
| 6401 /*border: 2px outset #AA002B;*/ | |
| 6402 /*color: #AA2244;*/ | |
| 6403 } | |
| 6404 | |
| 6405 div.pop_content:not(.nested) .nested_only { | |
| 6406 display: none; | |
| 6407 } | |
| 6408 | |
| 6409 div.pop_back_sec { | |
| 6410 margin-bottom: 5px; | |
| 6411 } | |
| 6412 | |
| 6413 div.pop_close_sec { | |
| 6414 margin-top: 5px; | |
| 6415 } | |
| 6416 | |
| 6417 table.hide_advanced tr.advanced { | |
| 6418 display: none; | |
| 6419 } | |
| 6420 span.show_more { | |
| 6421 display: none; | |
| 6422 } | |
| 6423 table.hide_advanced span.show_more { | |
| 6424 display: inline; | |
| 6425 } | |
| 6426 table.hide_advanced span.show_less { | |
| 6427 display: none; | |
| 6428 } | |
| 6429 | |
| 6430 | |
| 6431 /***************************************************************************** | |
| 6432 * Program logo styling | |
| 6433 ****************************************************************************/ | |
| 6434 div.prog_logo { | |
| 6435 border-bottom: 0.25em solid #0f5f60; | |
| 6436 height: 4.5em; | |
| 6437 width: 24em; | |
| 6438 display:inline-block; | |
| 6439 } | |
| 6440 div.prog_logo img { | |
| 6441 float:left; | |
| 6442 width: 4em; | |
| 6443 border-style: none; | |
| 6444 margin-right: 0.2em; | |
| 6445 } | |
| 6446 div.prog_logo h1, div.prog_logo h1:hover, div.prog_logo h1:active, div.prog_logo h1:visited { | |
| 6447 margin:0; | |
| 6448 padding:0; | |
| 6449 font-family: Arial, Helvetica, sans-serif; | |
| 6450 font-size: 3.2em; | |
| 6451 line-height: 1em; | |
| 6452 vertical-align: top; | |
| 6453 display: block; | |
| 6454 color: #026666; | |
| 6455 letter-spacing: -0.06em; | |
| 6456 text-shadow: 0.04em 0.06em 0.05em #666; | |
| 6457 } | |
| 6458 div.prog_logo h2, div.prog_logo h2:hover, div.prog_logo h2:active, div.prog_logo h2:visited { | |
| 6459 display: block; | |
| 6460 margin:0; | |
| 6461 padding:0; | |
| 6462 font-family: Helvetica, sans-serif; | |
| 6463 font-size: 0.9em; | |
| 6464 line-height: 1em; | |
| 6465 letter-spacing: -0.06em; | |
| 6466 color: black; | |
| 6467 } | |
| 6468 | |
| 6469 div.big.prog_logo { | |
| 6470 font-size: 18px; | |
| 6471 } | |
| 6472 | |
| 6473 </style> | |
| 6474 <style> | |
| 6475 .block_td { | |
| 6476 height:25px; | |
| 6477 } | |
| 6478 .block_container { | |
| 6479 position:relative; | |
| 6480 box-sizing: border-box; | |
| 6481 height: 25px; | |
| 6482 padding: 0px; | |
| 6483 margin: 0px; | |
| 6484 margin-left: 1em; | |
| 6485 } | |
| 6486 .block_label { | |
| 6487 position: absolute; | |
| 6488 display: inline-block; | |
| 6489 padding: 3px; | |
| 6490 z-index: 4; | |
| 6491 top: 6px; | |
| 6492 height: 12px; | |
| 6493 line-height: 12px; | |
| 6494 font-size: 12px; | |
| 6495 background-color: white; | |
| 6496 border: 1px solid black; | |
| 6497 -moz-border-radius: 12px; | |
| 6498 -webkit-border-radius: 12px; | |
| 6499 border-radius: 12px; | |
| 6500 transform: translateX(-50%); | |
| 6501 } | |
| 6502 .block_motif { | |
| 6503 position: absolute; | |
| 6504 z-index: 3; | |
| 6505 top: 0px; | |
| 6506 box-sizing: border-box; | |
| 6507 border: 1px solid black; | |
| 6508 height: 12px; | |
| 6509 background-color: cyan; | |
| 6510 } | |
| 6511 .block_motif.top { | |
| 6512 border-bottom-width: 0; | |
| 6513 } | |
| 6514 .block_motif.bottom { | |
| 6515 border-top-width: 0; | |
| 6516 } | |
| 6517 .block_motif.scanned_site { | |
| 6518 opacity: 0.3; | |
| 6519 } | |
| 6520 .block_motif.scanned_site.active { | |
| 6521 opacity: 0.9; | |
| 6522 } | |
| 6523 .block_region { | |
| 6524 position:absolute; | |
| 6525 z-index:6; | |
| 6526 height:25px; | |
| 6527 top:0px; | |
| 6528 } | |
| 6529 .block_region.main { | |
| 6530 z-index:8; | |
| 6531 } | |
| 6532 .block_region.scanned_site { | |
| 6533 z-index:5; | |
| 6534 } | |
| 6535 .block_region.scanned_site.main { | |
| 6536 z-index:7; | |
| 6537 } | |
| 6538 .block_region.top { | |
| 6539 height:13px; | |
| 6540 } | |
| 6541 .block_region.bottom { | |
| 6542 height:13px; | |
| 6543 top:12px; | |
| 6544 } | |
| 6545 .block_rule { | |
| 6546 position:absolute; | |
| 6547 z-index:2; | |
| 6548 width:100%; | |
| 6549 height:1px; | |
| 6550 top:12px; | |
| 6551 left:0px; | |
| 6552 background-color:gray; | |
| 6553 } | |
| 6554 .block_plus_sym { | |
| 6555 position:absolute; | |
| 6556 z-index:4; | |
| 6557 line-height:12px; | |
| 6558 top:0px; | |
| 6559 left:-1em; | |
| 6560 } | |
| 6561 .block_minus_sym { | |
| 6562 position:absolute; | |
| 6563 z-index:4; | |
| 6564 line-height:12px; | |
| 6565 top:13px; | |
| 6566 left:-1em; | |
| 6567 } | |
| 6568 | |
| 6569 .tic_major { | |
| 6570 position:absolute; | |
| 6571 top:0em; | |
| 6572 height:0.5em; | |
| 6573 width: 2px; | |
| 6574 margin-left: -1px; | |
| 6575 background-color: blue; | |
| 6576 } | |
| 6577 .tic_minor { | |
| 6578 position:absolute; | |
| 6579 top:0em; | |
| 6580 height:0.2em; | |
| 6581 width: 1px; | |
| 6582 margin-left: -0.5px; | |
| 6583 background-color: blue; | |
| 6584 } | |
| 6585 .tic_label { | |
| 6586 position:absolute; | |
| 6587 display: inline-block; | |
| 6588 top:0.5em; | |
| 6589 height: 1em; | |
| 6590 color: blue; | |
| 6591 transform: translateX(-50%); | |
| 6592 } | |
| 6593 | |
| 6594 .block_needle { | |
| 6595 position:absolute; | |
| 6596 z-index:4; | |
| 6597 height:30px; | |
| 6598 width:1px; | |
| 6599 top:-2px; | |
| 6600 background-color:gray; | |
| 6601 } | |
| 6602 .block_needle.right { | |
| 6603 height: 60px; | |
| 6604 } | |
| 6605 .block_handle { | |
| 6606 position: absolute; | |
| 6607 display: inline-block; | |
| 6608 z-index: 5; | |
| 6609 top: 27px; | |
| 6610 min-width: 3ex; | |
| 6611 text-align: center; | |
| 6612 font-size: 12px; | |
| 6613 line-height: 12px; | |
| 6614 transform: translateX(-50%); | |
| 6615 background-color: LightGrey; | |
| 6616 border:3px outset grey; | |
| 6617 cursor: pointer; | |
| 6618 -webkit-user-select: none; /* Chrome/Safari */ | |
| 6619 -moz-user-select: none; /* Firefox */ | |
| 6620 -ms-user-select: none; /* IE10+ */ | |
| 6621 /* Rules below not implemented in browsers yet */ | |
| 6622 -o-user-select: none; | |
| 6623 user-select: none; | |
| 6624 } | |
| 6625 .block_handle.right { | |
| 6626 top: 47px; | |
| 6627 } | |
| 6628 | |
| 6629 .legend_container { | |
| 6630 text-align: right; | |
| 6631 } | |
| 6632 .legend_entry { | |
| 6633 display: inline-block; | |
| 6634 padding: 5px; | |
| 6635 } | |
| 6636 div.legend_swatch { | |
| 6637 box-sizing: border-box; | |
| 6638 width: 15px; | |
| 6639 height: 15px; | |
| 6640 border: 1px solid black; | |
| 6641 background-color: cyan; | |
| 6642 float: left; | |
| 6643 } | |
| 6644 div.legend_swatch input { | |
| 6645 display: none; | |
| 6646 } | |
| 6647 .legend_text { | |
| 6648 line-height: 15px; | |
| 6649 margin-left: 20px; | |
| 6650 } | |
| 6651 </style> | |
| 6652 <style> | |
| 6653 /* meme output specific css */ | |
| 6654 | |
| 6655 div.pop_block { | |
| 6656 position:absolute; | |
| 6657 z-index:5; | |
| 6658 padding: 5px; | |
| 6659 border: 1px solid black; | |
| 6660 display: inline-block; | |
| 6661 background-color: white; | |
| 6662 } | |
| 6663 | |
| 6664 #measure_match { | |
| 6665 position: absolute; | |
| 6666 visibility: hidden; | |
| 6667 height: auto; | |
| 6668 width: auto; | |
| 6669 white-space: nowrap; | |
| 6670 } | |
| 6671 | |
| 6672 div.template { | |
| 6673 position: absolute; | |
| 6674 z-index: 1; | |
| 6675 left: 0; | |
| 6676 top: 0; | |
| 6677 visibility: hidden; | |
| 6678 } | |
| 6679 | |
| 6680 table.block_information { | |
| 6681 margin-left: auto; | |
| 6682 margin-right: auto; | |
| 6683 } | |
| 6684 | |
| 6685 table.block_information * th { | |
| 6686 text-align: right; | |
| 6687 } | |
| 6688 | |
| 6689 *.hide_empty_seqs * tr.empty_seq { | |
| 6690 display: none; | |
| 6691 } | |
| 6692 | |
| 6693 *.hide_only_scan * tr.only_scan { | |
| 6694 display: none; | |
| 6695 } | |
| 6696 | |
| 6697 *.hide_only_scan * div.scanned_site { | |
| 6698 display: none; | |
| 6699 } | |
| 6700 | |
| 6701 td.symaction { | |
| 6702 text-align: center; | |
| 6703 text-decoration: underline; | |
| 6704 font-size: 20px; | |
| 6705 cursor: pointer; | |
| 6706 } | |
| 6707 div.sym_btn { | |
| 6708 display:inline-block; | |
| 6709 text-decoration: underline; | |
| 6710 cursor: pointer; | |
| 6711 font-size: 20px; | |
| 6712 line-height:20px; | |
| 6713 text-align: center; | |
| 6714 width: 20px; | |
| 6715 height: 20px; | |
| 6716 color: blue; | |
| 6717 } | |
| 6718 div.sym_btn:hover { | |
| 6719 color: white; | |
| 6720 background-color: blue; | |
| 6721 } | |
| 6722 | |
| 6723 div.sym_btn.positioned { | |
| 6724 position: absolute; | |
| 6725 top: 0px; | |
| 6726 } | |
| 6727 | |
| 6728 div.actionbutton { | |
| 6729 display:inline-block; | |
| 6730 cursor: pointer; | |
| 6731 font-size: 18px; | |
| 6732 line-height:20px; | |
| 6733 padding: 5px; | |
| 6734 margin: 10px 0; | |
| 6735 border: 1px solid black; | |
| 6736 } | |
| 6737 | |
| 6738 div.actionbutton:hover { | |
| 6739 color:#FFF; | |
| 6740 background-color:#000; | |
| 6741 } | |
| 6742 | |
| 6743 div.param_box { | |
| 6744 display: inline-block; | |
| 6745 margin-right: 20px; | |
| 6746 } | |
| 6747 | |
| 6748 span.param { | |
| 6749 font-weight: bold; | |
| 6750 } | |
| 6751 | |
| 6752 div.box + div.box { | |
| 6753 margin-top: 5px; | |
| 6754 } | |
| 6755 | |
| 6756 div.sites_outer { | |
| 6757 position: relative; | |
| 6758 padding-top: 20px; /* height of header */ | |
| 6759 display: inline-block; | |
| 6760 } | |
| 6761 | |
| 6762 div.sites_inner { | |
| 6763 overflow-x: hidden; | |
| 6764 overflow-y: auto; | |
| 6765 max-height: 200px; | |
| 6766 } | |
| 6767 table.sites_tbl { | |
| 6768 border-collapse: collapse; | |
| 6769 } | |
| 6770 | |
| 6771 div.sites_th_inner { | |
| 6772 position: absolute; | |
| 6773 top: 0; | |
| 6774 line-height: 20px; /* height of header */ | |
| 6775 text-align: left; | |
| 6776 padding-left: 5px; | |
| 6777 } | |
| 6778 th.nopad div.sites_th_inner { | |
| 6779 padding-left: 0; | |
| 6780 } | |
| 6781 div.sites_th_hidden { | |
| 6782 visibility: hidden; | |
| 6783 height: 0; | |
| 6784 padding: 0 10px; | |
| 6785 } | |
| 6786 th.nopad div.sites_th_hidden { | |
| 6787 padding: 0; | |
| 6788 } | |
| 6789 div.sites_inner * th { | |
| 6790 height: 0; | |
| 6791 } | |
| 6792 | |
| 6793 table.sites_tbl { | |
| 6794 overflow-x: hidden; | |
| 6795 overflow-y: auto; | |
| 6796 } | |
| 6797 | |
| 6798 .site_num { | |
| 6799 text-align: right; | |
| 6800 } | |
| 6801 .site_name { | |
| 6802 padding:0px 5px; | |
| 6803 text-align:left; | |
| 6804 } | |
| 6805 .site_strand { | |
| 6806 padding:0px 5px; | |
| 6807 text-align:center; | |
| 6808 } | |
| 6809 .norc .site_strand, .norc .site_strand_title { | |
| 6810 display: none; | |
| 6811 } | |
| 6812 .site_start { | |
| 6813 padding:0px 15px; | |
| 6814 text-align: right; | |
| 6815 } | |
| 6816 .site_pvalue { | |
| 6817 text-align:center; | |
| 6818 padding:0px 15px; | |
| 6819 text-align:right; | |
| 6820 white-space: nowrap; | |
| 6821 } | |
| 6822 .lflank, .rflank, .match, .alpha_symbol { | |
| 6823 font-weight:bold; | |
| 6824 font-size:15px; | |
| 6825 font-family: 'Courier New', Courier, monospace; | |
| 6826 color:gray; | |
| 6827 } | |
| 6828 | |
| 6829 .site.lflank { | |
| 6830 text-align:right; | |
| 6831 padding-right:5px; | |
| 6832 color:gray; | |
| 6833 } | |
| 6834 .site.match { | |
| 6835 text-align:center; | |
| 6836 } | |
| 6837 .site.rflank { | |
| 6838 text-align:left; | |
| 6839 padding-left:5px; | |
| 6840 padding-right: 20px; | |
| 6841 } | |
| 6842 | |
| 6843 th.stop_reason { | |
| 6844 text-align: left; | |
| 6845 padding-right: 10px; | |
| 6846 } | |
| 6847 | |
| 6848 th.motif_ordinal { | |
| 6849 | |
| 6850 } | |
| 6851 td.motif_ordinal { | |
| 6852 text-align: right; | |
| 6853 padding-right: 10px; | |
| 6854 } | |
| 6855 th.motif_logo { | |
| 6856 padding-right: 10px; | |
| 6857 } | |
| 6858 td.motif_logo { | |
| 6859 padding-right: 10px; | |
| 6860 } | |
| 6861 th.motif_evalue { | |
| 6862 text-align:right; | |
| 6863 padding-right: 10px; | |
| 6864 } | |
| 6865 td.motif_evalue { | |
| 6866 text-align: right; | |
| 6867 white-space: nowrap; | |
| 6868 padding-right: 20px; | |
| 6869 } | |
| 6870 th.motif_nsites { | |
| 6871 text-align: right; | |
| 6872 padding-right: 10px; | |
| 6873 } | |
| 6874 td.motif_nsites { | |
| 6875 text-align: right; | |
| 6876 padding-right: 20px; | |
| 6877 } | |
| 6878 th.motif_width { | |
| 6879 text-align: right; | |
| 6880 padding-right: 5px; | |
| 6881 } | |
| 6882 td.motif_width { | |
| 6883 text-align: right; | |
| 6884 padding-right: 15px; | |
| 6885 } | |
| 6886 th.motif_more { | |
| 6887 padding: 0 5px; | |
| 6888 } | |
| 6889 td.motif_more { | |
| 6890 text-align: center; | |
| 6891 padding: 0 5px; | |
| 6892 } | |
| 6893 th.motif_submit { | |
| 6894 padding: 0 5px; | |
| 6895 } | |
| 6896 td.motif_submit { | |
| 6897 text-align: center; | |
| 6898 padding: 0 5px; | |
| 6899 } | |
| 6900 th.motif_download { | |
| 6901 padding-left: 5px; | |
| 6902 } | |
| 6903 td.motif_download { | |
| 6904 text-align: center; | |
| 6905 padding-left: 5px; | |
| 6906 } | |
| 6907 | |
| 6908 | |
| 6909 div.tabArea { | |
| 6910 font-size: 80%; | |
| 6911 font-weight: bold; | |
| 6912 } | |
| 6913 | |
| 6914 .norc div.tabArea { | |
| 6915 display: none; | |
| 6916 } | |
| 6917 | |
| 6918 span.tab, span.tab:visited { | |
| 6919 cursor: pointer; | |
| 6920 color: #888; | |
| 6921 background-color: #ddd; | |
| 6922 border: 2px solid #ccc; | |
| 6923 padding: 2px 1em; | |
| 6924 text-decoration: none; | |
| 6925 } | |
| 6926 span.tab.middle { | |
| 6927 border-left-width: 0px; | |
| 6928 } | |
| 6929 div.tabArea.base span.tab { | |
| 6930 border-top-width: 0px; | |
| 6931 } | |
| 6932 div.tabArea.top span.tab { | |
| 6933 border-bottom-width: 0px; | |
| 6934 } | |
| 6935 | |
| 6936 span.tab:hover { | |
| 6937 background-color: #bbb; | |
| 6938 border-color: #bbb; | |
| 6939 color: #666; | |
| 6940 } | |
| 6941 span.tab.activeTab, span.tab.activeTab:hover, span.tab.activeTab:visited { | |
| 6942 background-color: white; | |
| 6943 color: black; | |
| 6944 cursor: default; | |
| 6945 } | |
| 6946 div.tabMain { | |
| 6947 border: 2px solid #ccc; | |
| 6948 background-color: white; | |
| 6949 padding: 10px; | |
| 6950 } | |
| 6951 div.tabMain.base { | |
| 6952 margin-top: 5px; | |
| 6953 display: inline-block; | |
| 6954 max-width: 98%; | |
| 6955 } | |
| 6956 | |
| 6957 div.tabMain.top { | |
| 6958 margin-bottom: 5px; | |
| 6959 } | |
| 6960 | |
| 6961 div.tabCenter { | |
| 6962 max-width: 100%; | |
| 6963 overflow-x: auto; | |
| 6964 height: 200px; | |
| 6965 overflow-y: hidden; | |
| 6966 } | |
| 6967 | |
| 6968 canvas.logo_rc { | |
| 6969 display:none; | |
| 6970 } | |
| 6971 .show_rc_logo > canvas { | |
| 6972 display: none; | |
| 6973 } | |
| 6974 .show_rc_logo > canvas.logo_rc { | |
| 6975 display: block; | |
| 6976 } | |
| 6977 | |
| 6978 canvas.scan_logo { | |
| 6979 margin-left: 10px; | |
| 6980 } | |
| 6981 | |
| 6982 div.blocks_outer { | |
| 6983 position: relative; | |
| 6984 padding-top: 20px; /* height of header */ | |
| 6985 } | |
| 6986 | |
| 6987 div.blocks_inner { | |
| 6988 overflow-x: hidden; | |
| 6989 overflow-y: auto; | |
| 6990 max-height: 200px; | |
| 6991 } | |
| 6992 table.blocks_tbl { | |
| 6993 border-collapse: collapse; | |
| 6994 width: 100%; | |
| 6995 } | |
| 6996 | |
| 6997 div.blocks_th_inner { | |
| 6998 position: absolute; | |
| 6999 top: 0; | |
| 7000 line-height: 20px; /* height of header */ | |
| 7001 text-align: left; | |
| 7002 padding-left: 5px; | |
| 7003 } | |
| 7004 th.nopad div.blocks_th_inner { | |
| 7005 padding-left: 0; | |
| 7006 } | |
| 7007 div.blocks_th_hidden { | |
| 7008 visibility: hidden; | |
| 7009 height: 0; | |
| 7010 padding: 0 10px; | |
| 7011 } | |
| 7012 th.nopad div.blocks_th_hidden { | |
| 7013 padding: 0; | |
| 7014 } | |
| 7015 div.blocks_inner * th { | |
| 7016 height: 0; | |
| 7017 } | |
| 7018 | |
| 7019 table.blocks_tbl { | |
| 7020 overflow-x: hidden; | |
| 7021 overflow-y: auto; | |
| 7022 } | |
| 7023 td.block_td { | |
| 7024 width: 99%; | |
| 7025 } | |
| 7026 | |
| 7027 *.blockdiag_num { | |
| 7028 text-align: right; | |
| 7029 } | |
| 7030 | |
| 7031 td.blockdiag_name { | |
| 7032 text-align: left; | |
| 7033 padding:0px 10px; | |
| 7034 } | |
| 7035 | |
| 7036 td.blockdiag_pvalue { | |
| 7037 padding:0px 10px; | |
| 7038 text-align:right; | |
| 7039 white-space: nowrap; | |
| 7040 } | |
| 7041 | |
| 7042 div.preview_btn { | |
| 7043 border: 2px solid white; | |
| 7044 height: 16px; | |
| 7045 width: 16px; | |
| 7046 font-size: 12px; | |
| 7047 line-height: 16px; | |
| 7048 text-align: center; | |
| 7049 cursor: pointer; | |
| 7050 } | |
| 7051 div.preview_btn + div.preview_btn { | |
| 7052 margin-top: 3px; | |
| 7053 } | |
| 7054 | |
| 7055 div.preview_btn.active { | |
| 7056 border: 2px solid black; | |
| 7057 cursor: default; | |
| 7058 } | |
| 7059 | |
| 7060 div.preview_btn:hover { | |
| 7061 background-color: black; | |
| 7062 color: white; | |
| 7063 border-color: black; | |
| 7064 } | |
| 7065 | |
| 7066 div.preview_btn.active:hover { | |
| 7067 background-color: white; | |
| 7068 color: black; | |
| 7069 border-color: black; | |
| 7070 } | |
| 7071 | |
| 7072 | |
| 7073 div.preview_btn_box { | |
| 7074 position: absolute; | |
| 7075 left: 0px; | |
| 7076 top: 0px; | |
| 7077 padding: 3px; | |
| 7078 } | |
| 7079 | |
| 7080 div.preview_logo_box { | |
| 7081 height: 50px; | |
| 7082 overflow-y: hidden; | |
| 7083 } | |
| 7084 | |
| 7085 div.preview_btn_box + div.preview_logo_box { | |
| 7086 margin-left: 25px; | |
| 7087 } | |
| 7088 | |
| 7089 div.preview_box { | |
| 7090 position: relative; | |
| 7091 } | |
| 7092 | |
| 7093 div.grey_background { | |
| 7094 position:fixed; | |
| 7095 z-index: 8; | |
| 7096 background-color: #000; | |
| 7097 -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; | |
| 7098 opacity: 0.5; | |
| 7099 left: 0; | |
| 7100 top: 0; | |
| 7101 width: 100%; | |
| 7102 height: 100%; | |
| 7103 } | |
| 7104 | |
| 7105 div.popup_wrapper { | |
| 7106 position:fixed; | |
| 7107 z-index:9; | |
| 7108 width:100%; | |
| 7109 height:0; | |
| 7110 top:50%; | |
| 7111 left:0; | |
| 7112 } | |
| 7113 | |
| 7114 div.popup { | |
| 7115 width: 600px; | |
| 7116 z-index:9; | |
| 7117 margin-left: auto; | |
| 7118 margin-right: auto; | |
| 7119 padding: 5px; | |
| 7120 background-color: #FFF; | |
| 7121 border-style: double; | |
| 7122 border-width: 5px; | |
| 7123 border-color: #00666a; | |
| 7124 position:relative; | |
| 7125 } | |
| 7126 div.close { | |
| 7127 cursor: pointer; | |
| 7128 border: 1px solid black; | |
| 7129 width:15px; | |
| 7130 height:15px; | |
| 7131 line-height:15px; /* this causes vertical centering */ | |
| 7132 text-align:center; | |
| 7133 background-color:#FFF; | |
| 7134 color:#000; | |
| 7135 font-size:15px; | |
| 7136 font-family:monospace; | |
| 7137 } | |
| 7138 | |
| 7139 div.close:hover { | |
| 7140 color:#FFF; | |
| 7141 background-color:#000; | |
| 7142 } | |
| 7143 | |
| 7144 div.navnum { | |
| 7145 width:100%; | |
| 7146 height:20px; | |
| 7147 line-height:20px; | |
| 7148 text-align:center; | |
| 7149 font-size:medium; | |
| 7150 } | |
| 7151 | |
| 7152 div.navarrow { | |
| 7153 font-size: 30px; | |
| 7154 text-decoration:none; | |
| 7155 cursor: pointer; | |
| 7156 -moz-user-select: none; | |
| 7157 -webkit-user-select: none; | |
| 7158 -ms-user-select: none; | |
| 7159 } | |
| 7160 | |
| 7161 div.navarrow > span.inactive { | |
| 7162 display: inline; | |
| 7163 } | |
| 7164 div.navarrow > span.active { | |
| 7165 display: none; | |
| 7166 } | |
| 7167 | |
| 7168 div.navarrow:hover > span.active { | |
| 7169 display: inline; | |
| 7170 } | |
| 7171 div.navarrow:hover > span.inactive { | |
| 7172 display: none; | |
| 7173 } | |
| 7174 | |
| 7175 table.programs { | |
| 7176 width: 100%; | |
| 7177 } | |
| 7178 | |
| 7179 table.programs tr { | |
| 7180 background-color: #EFE; | |
| 7181 } | |
| 7182 | |
| 7183 table.programs tr.selected { | |
| 7184 background-color: #262; | |
| 7185 color: #FFF; | |
| 7186 } | |
| 7187 | |
| 7188 table.programs tr.dna_only { | |
| 7189 display: none; | |
| 7190 } | |
| 7191 | |
| 7192 table.programs.alphabet_dna tr.dna_only { | |
| 7193 display: table-row; | |
| 7194 } | |
| 7195 | |
| 7196 div.programs_scroll { | |
| 7197 width: 100%; | |
| 7198 height: 90px; | |
| 7199 overflow-y: auto; | |
| 7200 overflow-x: hidden; | |
| 7201 margin: 0 auto; | |
| 7202 } | |
| 7203 table.inputs, table.alpha_bg_table { | |
| 7204 margin-top: 20px; | |
| 7205 border-collapse:collapse; | |
| 7206 } | |
| 7207 table.inputs * td, table.inputs * th, table.alpha_bg_table * td, table.alpha_bg_table * th { | |
| 7208 padding-left: 15px; | |
| 7209 padding-right: 15px; | |
| 7210 padding-top: 1px; | |
| 7211 padding-bottom: 1px; | |
| 7212 } | |
| 7213 | |
| 7214 table.hide_psp td.col_psp, table.hide_psp th.col_psp { | |
| 7215 display: none; | |
| 7216 } | |
| 7217 | |
| 7218 /* program settings */ | |
| 7219 span.mod_oops, span.mod_zoops, span.mod_anr { | |
| 7220 display: none; | |
| 7221 } | |
| 7222 td.oops span.mod_oops,td.zoops span.mod_zoops, td.anr span.mod_anr { | |
| 7223 display: inline; | |
| 7224 } | |
| 7225 span.strand_none, span.strand_given, span.strand_both { | |
| 7226 display: none; | |
| 7227 } | |
| 7228 td.none span.strand_none, td.given span.strand_given, td.both span.strand_both { | |
| 7229 display: inline; | |
| 7230 } | |
| 7231 span.spmap_uni, span.spmap_pam { | |
| 7232 display: none; | |
| 7233 } | |
| 7234 td.uni span.spmap_uni, td.pam span.spmap_pam { | |
| 7235 display: inline; | |
| 7236 } | |
| 7237 span.prior_dirichlet, span.prior_dmix, span.prior_mega, span.prior_megap, span.prior_addone { | |
| 7238 display: none; | |
| 7239 } | |
| 7240 td.dirichlet span.prior_dirichlet, td.dmix span.prior_dmix, td.mega span.prior_mega, | |
| 7241 td.megap span.prior_megap, td.addone span.prior_addone { | |
| 7242 display: inline; | |
| 7243 } | |
| 7244 span.noendgaps_on, span.noendgaps_off { | |
| 7245 display: none; | |
| 7246 } | |
| 7247 td.on span.noendgaps_on, td.off span.noendgaps_off { | |
| 7248 display: inline; | |
| 7249 } | |
| 7250 span.substring_on, span.substring_off { | |
| 7251 display: none; | |
| 7252 } | |
| 7253 td.on span.substring_on, td.off span.substring_off { | |
| 7254 display: inline; | |
| 7255 } | |
| 7256 </style> | |
| 7257 </head> | |
| 7258 <body onload="page_loaded()" onpageshow="page_shown(event)" onresize="page_resized()"> | |
| 7259 <!-- --> | |
| 7260 <div id="grey_out_page" class="grey_background" style="display:none;"> | |
| 7261 </div> | |
| 7262 <!-- Help popups --> | |
| 7263 <div class="pop_content" id="pop_"> | |
| 7264 <p>Help poup.</p> | |
| 7265 <div style="float:right; bottom:0px;">[ | |
| 7266 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7267 </div> | |
| 7268 <div class="pop_content" id="pop_ev"> | |
| 7269 <p>The statistical significance of the motif. MEME usually finds the most | |
| 7270 statistically significant (low E-value) motifs first. It is unusual to | |
| 7271 consider a motif with an E-value larger than 0.05 significant so, as an | |
| 7272 additional indicator, MEME displays these partially transparent.</p> | |
| 7273 <p>The E-value of a motif is based on its log likelihood ratio, width, | |
| 7274 sites, the background letter frequencies (given in the command line | |
| 7275 summary), and the size of the training set.</p> | |
| 7276 <p>The E-value is an estimate of the expected number of motifs with the | |
| 7277 given log likelihood ratio (or higher), and with the same width and site | |
| 7278 count, that one would find in a similarly sized set of random | |
| 7279 sequences (sequences where each position is independent and letters are | |
| 7280 chosen according to the background letter frequencies).</p> | |
| 7281 <div style="float:right; bottom:0px;">[ | |
| 7282 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7283 </div> | |
| 7284 <div class="pop_content" id="pop_sites"> | |
| 7285 <p>The number of sites contributing to the construction of the motif.</p> | |
| 7286 <div style="float:right; bottom:0px;">[ | |
| 7287 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7288 </div> | |
| 7289 <div class="pop_content" id="pop_width"> | |
| 7290 <p>The width of the motif. Each motif describes a pattern of a fixed | |
| 7291 width, as no gaps are allowed in MEME motifs.</p> | |
| 7292 <div style="float:right; bottom:0px;">[ | |
| 7293 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7294 </div> | |
| 7295 <div class="pop_content" id="pop_more"> | |
| 7296 <p>Click on the blue symbol below to reveal more information about this motif.</p> | |
| 7297 <div style="float:right; bottom:0px;">[ | |
| 7298 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7299 </div> | |
| 7300 <div class="pop_content" id="pop_submit_dl"> | |
| 7301 <p>Click on the blue symbol below to reveal options allowing you | |
| 7302 to submit this motif to another MEME Suite motif analysis program, to download this | |
| 7303 motif in various text formats, or to download a sequence "logo" of | |
| 7304 this motif PNG or EPS format.</p> | |
| 7305 <h5>Supported Programs</h5> | |
| 7306 <dl> | |
| 7307 <dt>Tomtom</dt> | |
| 7308 <dd>Tomtom is a tool for searching for similar known motifs. | |
| 7309 [<a href="http://meme-suite.org/doc/tomtom.html?man_type=web">manual</a>]</dd> | |
| 7310 <dt>MAST</dt> | |
| 7311 <dd>MAST is a tool for searching biological sequence databases for | |
| 7312 sequences that contain one or more of a group of known motifs. | |
| 7313 [<a href="http://meme-suite.org/doc/mast.html?man_type=web">manual</a>]</dd> | |
| 7314 <dt>FIMO</dt> | |
| 7315 <dd>FIMO is a tool for searching biological sequence databases for | |
| 7316 sequences that contain one or more known motifs. | |
| 7317 [<a href="http://meme-suite.org/doc/fimo.html?man_type=web">manual</a>]</dd> | |
| 7318 <dt>GOMO</dt> | |
| 7319 <dd>GOMO is a tool for identifying possible roles (Gene Ontology | |
| 7320 terms) for DNA binding motifs. | |
| 7321 [<a href="http://meme-suite.org/doc/gomo.html?man_type=web">manual</a>]</dd> | |
| 7322 <dt>SpaMo</dt> | |
| 7323 <dd>SpaMo is a tool for inferring possible transcription factor | |
| 7324 complexes by finding motifs with enriched spacings. | |
| 7325 [<a href="http://meme-suite.org/doc/spamo.html?man_type=web">manual</a>]</dd> | |
| 7326 </dl> | |
| 7327 <div style="float:right; bottom:0px;">[ | |
| 7328 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7329 </div> | |
| 7330 <div class="pop_content" id="pop_llr"> | |
| 7331 <p>The log likelihood ratio of the motif.The log likelihood ratio is the | |
| 7332 logarithm of the ratio of the probability of the occurrences of the motif | |
| 7333 given the motif model (likelihood given the motif) versus their | |
| 7334 probability given the background model (likelihood given the null model). | |
| 7335 (Normally the background model is a 0-order Markov model using the | |
| 7336 background letter frequencies, but higher order Markov models may be | |
| 7337 specified via the -bfile option to MEME.).</p> | |
| 7338 <div style="float:right; bottom:0px;">[ | |
| 7339 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7340 </div> | |
| 7341 <div class="pop_content" id="pop_ic"> | |
| 7342 <p>The information content of the motif in bits. It is equal to the sum | |
| 7343 of the uncorrected information content, R(), in the columns of the pwm. | |
| 7344 This is equal relative entropy of the motif relative to a uniform | |
| 7345 background frequency model.</p> | |
| 7346 <div style="float:right; bottom:0px;">[ | |
| 7347 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7348 </div> | |
| 7349 <div class="pop_content" id="pop_re"> | |
| 7350 <p>The relative entropy of the motif.</p> | |
| 7351 | |
| 7352 <p style="font-family: monospace;">re = llr / (sites * ln(2))</p> | |
| 7353 <div style="float:right; bottom:0px;">[ | |
| 7354 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7355 </div> | |
| 7356 <div class="pop_content" id="pop_bt"> | |
| 7357 <p>The Bayes Threshold.</p> | |
| 7358 <div style="float:right; bottom:0px;">[ | |
| 7359 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7360 </div> | |
| 7361 <div class="pop_content" id="pop_site_strand"> | |
| 7362 <p>The strand used for the motif site.</p> | |
| 7363 <dl> | |
| 7364 <dt>+</dt> | |
| 7365 <dd>The motif site was found in the sequence as it was supplied.</dd> | |
| 7366 <dt>-</dt> | |
| 7367 <dd>The motif site was found in the reverse complement of the supplied sequence.</dd> | |
| 7368 </dl> | |
| 7369 <div style="float:right; bottom:0px;">[ | |
| 7370 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7371 </div> | |
| 7372 <div class="pop_content" id="pop_site_start"> | |
| 7373 <p>The position in the sequence where the motif site starts. If a motif | |
| 7374 started right at the begining of a sequence it would be described as | |
| 7375 starting at position 1.</p> | |
| 7376 <div style="float:right; bottom:0px;">[ | |
| 7377 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7378 </div> | |
| 7379 <div class="pop_content" id="pop_site_pvalue"> | |
| 7380 <p>The probability that an equal or better site would be found in a | |
| 7381 random sequence of the same length conforming to the background letter | |
| 7382 frequencies.</p> | |
| 7383 <div style="float:right; bottom:0px;">[ | |
| 7384 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7385 </div> | |
| 7386 <div class="pop_content" id="pop_site_match"> | |
| 7387 <p>A motif site with the 10 flanking letters on either side.</p> | |
| 7388 <p>When the site is not on the given strand then the site | |
| 7389 and both flanks are reverse complemented so they align.</p> | |
| 7390 <div style="float:right; bottom:0px;">[ | |
| 7391 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7392 </div> | |
| 7393 | |
| 7394 <div class="pop_content" id="pop_seq_name"> | |
| 7395 <p>The name of the sequences as given in the FASTA file.</p> | |
| 7396 <p>The number to the left of the sequence name is the ordinal | |
| 7397 of the sequence.</p> | |
| 7398 <div style="float:right; bottom:0px;">[ | |
| 7399 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7400 </div> | |
| 7401 | |
| 7402 <div class="pop_content" id="pop_motif_sites"> | |
| 7403 <p>These are the motif sites predicted by MEME and used to build the motif.</p> | |
| 7404 <p>These sites are shown in solid color and hovering the cursor | |
| 7405 over a site will reveal details about the site. Only sequences | |
| 7406 that contain a motif site are shown.</p> | |
| 7407 <div style="float:right; bottom:0px;">[ | |
| 7408 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7409 </div> | |
| 7410 | |
| 7411 <div class="pop_content" id="pop_scanned_sites"> | |
| 7412 <p>These are the motif sites predicted by MEME plus | |
| 7413 any additional sites detected using a motif scanning | |
| 7414 algorithm.</p> | |
| 7415 <p>These MEME sites are shown in solid color and | |
| 7416 additional scanned sites are shown in transparent color. | |
| 7417 Hovering the cursor over a site will reveal details about the site. | |
| 7418 Only sequences containing a predicted or scanned motif site are shown.</p> | |
| 7419 <p>The scanned sites are predicted using a | |
| 7420 log-odds scoring matrix constructed from the MEME sites. | |
| 7421 Only scanned sites with position <i>p</i>-values less | |
| 7422 than 0.0001 are shown.</p> | |
| 7423 <div style="float:right; bottom:0px;">[ | |
| 7424 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7425 </div> | |
| 7426 | |
| 7427 <div class="pop_content" id="pop_all_sequences"> | |
| 7428 <p>These are the same sites as shown by selecting the | |
| 7429 "Motif Sites + Scanned Sites" button except that all | |
| 7430 sequences, including those with no sites, are included | |
| 7431 in the diagram.</p> | |
| 7432 <div style="float:right; bottom:0px;">[ | |
| 7433 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7434 </div> | |
| 7435 | |
| 7436 <div class="pop_content" id="pop_seq_pvalue"> | |
| 7437 <p>This is the combined match <i>p</i>-value.</p> | |
| 7438 <p>The combined match <i>p</i>-value is defined as the probability that a | |
| 7439 random sequence (with the same length and conforming to the background) | |
| 7440 would have position <i>p</i>-values such that the product is smaller | |
| 7441 or equal to the value calulated for the sequence under test.</p> | |
| 7442 <p>The position <i>p</i>-value is defined as the probability that a | |
| 7443 random sequence (with the same length and conforming to the background) | |
| 7444 would have a match to the motif under test with a score greater or equal | |
| 7445 to the largest found in the sequence under test.</p> | |
| 7446 <p>Hovering your mouse over a motif site in the motif location | |
| 7447 block diagram will show its position <i>p</i>-value and other information | |
| 7448 about the site.</p> | |
| 7449 | |
| 7450 <div style="float:right; bottom:0px;">[ | |
| 7451 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7452 </div> | |
| 7453 <div class="pop_content" id="pop_motif_location"> | |
| 7454 <p>This diagram shows the location of motif sites.</p> | |
| 7455 <p>Each block shows the position and strength of a motif | |
| 7456 site. The height of a block gives an indication of the | |
| 7457 significance of the site as taller blocks are more significant. | |
| 7458 The height is calculated to be proportional to the negative | |
| 7459 logarithm of the <i>p</i>-value of the site, truncated at | |
| 7460 the height for a <i>p</i>-value of 1e-10.</p> | |
| 7461 <p>For complementable alphabets (like DNA), sites on the | |
| 7462 positive strand are shown above the line, | |
| 7463 sites on the negative strand are shown below.</p> | |
| 7464 <p>Placing the cursor | |
| 7465 over a motif site will reveal more information about the site | |
| 7466 including its position <i>p</i>-value. (See the help | |
| 7467 for the <i>p</i>-value column for an explanation of position | |
| 7468 <i>p</i>-values.)</p> | |
| 7469 <div style="float:right; bottom:0px;">[ | |
| 7470 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7471 </div> | |
| 7472 | |
| 7473 <div class="pop_content" id="pop_seq_source"> | |
| 7474 <p>The name of the file of sequences input to MEME.</p> | |
| 7475 <div style="float:right; bottom:0px;">[ | |
| 7476 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7477 </div> | |
| 7478 <div class="pop_content" id="pop_psp_source"> | |
| 7479 <p>The position specific priors file used by MEME to find the motifs.</p> | |
| 7480 <div style="float:right; bottom:0px;">[ | |
| 7481 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7482 </div> | |
| 7483 <div class="pop_content" id="pop_seq_alph"> | |
| 7484 <p>The alphabet used by the sequences.</p> | |
| 7485 <div style="float:right; bottom:0px;">[ | |
| 7486 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7487 </div> | |
| 7488 <div class="pop_content" id="pop_seq_count"> | |
| 7489 <p>The number of sequences provided as input to MEME.</p> | |
| 7490 <div style="float:right; bottom:0px;">[ | |
| 7491 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7492 </div> | |
| 7493 | |
| 7494 <div class="pop_content" id="pop_alph_name"> | |
| 7495 <p>The name of the alphabet symbol.</p> | |
| 7496 <div style="float:right; bottom:0px;">[ | |
| 7497 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7498 </div> | |
| 7499 <div class="pop_content" id="pop_alph_freq"> | |
| 7500 <p>The frequency of the alphabet symbol in the dataset with a pseudocount | |
| 7501 so it is never zero.</p> | |
| 7502 <div style="float:right; bottom:0px;">[ | |
| 7503 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7504 </div> | |
| 7505 <div class="pop_content" id="pop_alph_bg"> | |
| 7506 <p>The frequency of the alphabet symbol as defined by the background model.</p> | |
| 7507 <div style="float:right; bottom:0px;">[ | |
| 7508 <a href="javascript:help_popup()">close</a> ]</div> | |
| 7509 </div> | |
| 7510 | |
| 7511 <!-- templates --> | |
| 7512 <div id="measure_match" class="match"></div> | |
| 7513 <div class="template pop_block" id="tmpl_block_info"> | |
| 7514 <div> | |
| 7515 <span class="tvar_logo_pad lflank" style="visibility:hidden;"></span> | |
| 7516 <span class="tvar_logo"></span> | |
| 7517 </div> | |
| 7518 <div class="block_sequence_fragment"> | |
| 7519 <span class="tvar_lflank lflank"></span> | |
| 7520 <span class="tvar_match match"></span> | |
| 7521 <span class="tvar_rflank rflank"></span> | |
| 7522 </div> | |
| 7523 <table class="block_information"> | |
| 7524 <tr><th>Motif</th><td class="tvar_motif">1</td></tr> | |
| 7525 <tr><th><i>p</i>-value</th><td class="tvar_pvalue">8.23e-7</td></tr> | |
| 7526 <tr><th>Start</th><td class="tvar_start">23</td></tr> | |
| 7527 <tr><th>End</th><td class="tvar_end">33</td></tr> | |
| 7528 </table> | |
| 7529 </div> | |
| 7530 | |
| 7531 <div class="template pop_block" id="tmpl_scan_info"> | |
| 7532 <h5>Scanned Site</h5> | |
| 7533 <div class="tvar_logo"></div> | |
| 7534 <table class="block_information"> | |
| 7535 <tr><th>Motif</th><td class="tvar_motif">1</td></tr> | |
| 7536 <tr><th><i>p</i>-value</th><td class="tvar_pvalue">8.23e-7</td></tr> | |
| 7537 <tr><th>Start</th><td class="tvar_start">23</td></tr> | |
| 7538 <tr><th>End</th><td class="tvar_end">33</td></tr> | |
| 7539 </table> | |
| 7540 </div> | |
| 7541 | |
| 7542 <div class="template box expanded_motif" id="tmpl_motif_expanded"> | |
| 7543 <div style="position: relative; min-height: 20px"> | |
| 7544 <div class="param_box"> | |
| 7545 <span class="param"><span class="tvar_ordinal"></span>.</span> | |
| 7546 </div> | |
| 7547 <div class="sym_btn positioned tvar_less" tabindex="0" | |
| 7548 title="Show less information.">↥</div> | |
| 7549 <div class="sym_btn positioned tvar_submit" tabindex="0" | |
| 7550 title="Submit the motif to another MEME Suite program or download it.">⇢</div> | |
| 7551 </div> | |
| 7552 <div> | |
| 7553 <div class="param_box"> | |
| 7554 <span class="param"><i>E</i>-value:</span> | |
| 7555 <span class="tvar_evalue"></span> | |
| 7556 <div class="help" data-topic="pop_ev"></div> | |
| 7557 </div> | |
| 7558 <div class="param_box"> | |
| 7559 <span class="param">Site Count:</span> | |
| 7560 <span class="tvar_site_count"></span> | |
| 7561 <div class="help" data-topic="pop_sites"></div> | |
| 7562 </div> | |
| 7563 <div class="param_box"> | |
| 7564 <span class="param">Width:</span> | |
| 7565 <span class="tvar_width"></span> | |
| 7566 <div class="help" data-topic="pop_width"></div> | |
| 7567 </div> | |
| 7568 </div> | |
| 7569 <div class="tabMain base"> | |
| 7570 <div class="tabCenter tvar_logo"></div> | |
| 7571 </div> | |
| 7572 <div class="tabArea base"> | |
| 7573 <span class="tvar_tab tab" tabindex="0">Standard</span><span | |
| 7574 class="tvar_tab_rc tab middle" tabindex="0">Reverse | |
| 7575 Complement</span> | |
| 7576 </div> | |
| 7577 <div style="padding: 10px 0"> | |
| 7578 <div class="param_box"> | |
| 7579 <span class="param">Log Likelihood Ratio:</span> | |
| 7580 <span class="tvar_llr"></span> | |
| 7581 <div class="help" data-topic="pop_llr"></div> | |
| 7582 </div> | |
| 7583 <div class="param_box"> | |
| 7584 <span class="param">Information Content:</span> | |
| 7585 <span class="tvar_ic"></span> | |
| 7586 <div class="help" data-topic="pop_ic"></div> | |
| 7587 </div> | |
| 7588 <div class="param_box"> | |
| 7589 <span class="param">Relative Entropy:</span> | |
| 7590 <span class="tvar_re"></span> | |
| 7591 <div class="help" data-topic="pop_re"></div> | |
| 7592 </div> | |
| 7593 <div class="param_box"> | |
| 7594 <span class="param">Bayes Threshold:</span> | |
| 7595 <span class="tvar_bt"></span> | |
| 7596 <div class="help" data-topic="pop_bt"></div> | |
| 7597 </div> | |
| 7598 </div> | |
| 7599 <div class="tvar_sites"></div> | |
| 7600 </div> | |
| 7601 | |
| 7602 | |
| 7603 <div class="popup_wrapper"> | |
| 7604 <div class="popup" style="display:none; top: -150px;" id="download"> | |
| 7605 <div> | |
| 7606 <div style="float:right; "> | |
| 7607 <div id="outpop_close" class="close" tabindex="0">x</div> | |
| 7608 </div> | |
| 7609 <h2 class="mainh" style="margin:0; padding:0;">Submit or Download</h2> | |
| 7610 <div style="clear:both"></div> | |
| 7611 </div> | |
| 7612 <div style="height:100px"> | |
| 7613 <div style="float:right; width: 30px;"> | |
| 7614 <div id="outpop_prev" class="navarrow" tabindex="0"> | |
| 7615 <span class="inactive">⇧</span><span class="active">⬆</span> | |
| 7616 </div> | |
| 7617 <div id="outpop_num" class="navnum"></div> | |
| 7618 <div id="outpop_next" class="navarrow" tabindex="0"> | |
| 7619 <span class="inactive">⇩</span><span class="active">⬇</span> | |
| 7620 </div> | |
| 7621 </div> | |
| 7622 <div id="logo_box" style="height: 100px; margin-right: 40px;"> | |
| 7623 <canvas id="outpop_logo" height="100" width="580"></canvas> | |
| 7624 <canvas id="outpop_logo_rc" class="logo_rc" height="100" width="580"></canvas> | |
| 7625 </div> | |
| 7626 </div> | |
| 7627 <div> | |
| 7628 <!-- tabs start --> | |
| 7629 <div class="tabArea top"> | |
| 7630 <span id="outpop_tab_1" class="tab">Submit Motif</span><span | |
| 7631 id="outpop_tab_2" class="tab middle">Download Motif</span><span | |
| 7632 id="outpop_tab_3" class="tab middle">Download Logo</span> | |
| 7633 </div> | |
| 7634 <div class="tabMain top"> | |
| 7635 <!-- Submit to another program --> | |
| 7636 <div id="outpop_pnl_1"> | |
| 7637 <h4 class="compact">Submit to program</h4> | |
| 7638 <table id="programs" class="programs"> | |
| 7639 <tr class="dna_only"> | |
| 7640 <td><input type="radio" name="program" value="tomtom" id="submit_tomtom"></td> | |
| 7641 <td><label for="submit_tomtom">Tomtom</label></td> | |
| 7642 <td><label for="submit_tomtom">Find similar motifs in | |
| 7643 published libraries or a library you supply.</label></td> | |
| 7644 </tr> | |
| 7645 <tr> | |
| 7646 <td><input type="radio" name="program" value="fimo" id="submit_fimo"></td> | |
| 7647 <td><label for="submit_fimo">FIMO</label></td> | |
| 7648 <td><label for="submit_fimo">Find motif occurrences in | |
| 7649 sequence data.</label></td> | |
| 7650 </tr> | |
| 7651 <tr> | |
| 7652 <td><input type="radio" name="program" value="mast" id="submit_mast"></td> | |
| 7653 <td><label for="submit_mast">MAST</label></td> | |
| 7654 <td><label for="submit_mast">Rank sequences by affinity to | |
| 7655 groups of motifs.</label></td> | |
| 7656 </tr> | |
| 7657 <tr class="dna_only"> | |
| 7658 <td><input type="radio" name="program" value="gomo" id="submit_gomo"></td> | |
| 7659 <td><label for="submit_gomo">GOMo</label></td> | |
| 7660 <td><label for="submit_gomo">Identify possible roles (Gene | |
| 7661 Ontology terms) for motifs.</label></td> | |
| 7662 </tr> | |
| 7663 <tr class="dna_only"> | |
| 7664 <td><input type="radio" name="program" value="spamo" id="submit_spamo"></td> | |
| 7665 <td><label for="submit_spamo">SpaMo</label></td> | |
| 7666 <td><label for="submit_spamo">Find other motifs that are | |
| 7667 enriched at specific close spacings which might imply the existance of a complex.</label></td> | |
| 7668 </tr> | |
| 7669 </table> | |
| 7670 </div> | |
| 7671 <!-- download text format --> | |
| 7672 <div id="outpop_pnl_2"> | |
| 7673 <div> | |
| 7674 <label for="text_format">Format:</label> | |
| 7675 <select id="text_format"> | |
| 7676 <option value="0">Count Matrix</option> | |
| 7677 <option value="1">Probability Matrix</option> | |
| 7678 <option value="2">Minimal MEME</option> | |
| 7679 <option value="3">FASTA</option> | |
| 7680 <option value="4">Raw</option> | |
| 7681 </select> | |
| 7682 </div> | |
| 7683 <form id="text_form" method="post" action=""> | |
| 7684 <script>$("text_form").action = site_url + "/utilities/save_generated_file";</script> | |
| 7685 <input type="hidden" id="text_name" name="name" value="motif.txt"> | |
| 7686 <input type="hidden" name="mime_type" value="text/plain"> | |
| 7687 <textarea id="outpop_text" name="content" | |
| 7688 style="width:99%; white-space: pre; word-wrap: normal; overflow-x: scroll;" | |
| 7689 rows="8" readonly="readonly" wrap="off"></textarea> | |
| 7690 </form> | |
| 7691 </div> | |
| 7692 <!-- download logo format --> | |
| 7693 <div id="outpop_pnl_3"> | |
| 7694 <form id="logo_form" method="post" action=""> | |
| 7695 <script>$("logo_form").action = site_url + "/utilities/generate_logo";</script> | |
| 7696 <input type="hidden" name="program" value="MEME"/> | |
| 7697 <input type="hidden" id="logo_motifs" name="motifs" value=""/> | |
| 7698 <table> | |
| 7699 <tr> | |
| 7700 <td><label for="logo_format">Format:</label></td> | |
| 7701 <td> | |
| 7702 <select id="logo_format" name="png"> | |
| 7703 <option value="1">PNG (for web)</option> | |
| 7704 <option value="0">EPS (for publication)</option> | |
| 7705 </select> | |
| 7706 </td> | |
| 7707 </tr> | |
| 7708 <tr> | |
| 7709 <td><label for="logo_rc">Orientation:</label></td> | |
| 7710 <td> | |
| 7711 <select id="logo_rc" name="rc1"> | |
| 7712 <option value="0">Normal</option> | |
| 7713 <option value="1" id="logo_rc_option">Reverse Complement</option> | |
| 7714 </select> | |
| 7715 </td> | |
| 7716 </tr> | |
| 7717 <tr> | |
| 7718 <td><label for="logo_ssc">Small Sample Correction:</label></td> | |
| 7719 <td> | |
| 7720 <input type="hidden" id="logo_err" name="errbars" value="0"/> | |
| 7721 <select id="logo_ssc" name="ssc"> | |
| 7722 <option value="0">Off</option> | |
| 7723 <option value="1">On</option> | |
| 7724 </select> | |
| 7725 </td> | |
| 7726 </tr> | |
| 7727 <tr> | |
| 7728 <td><label for="logo_width">Width:</label></td> | |
| 7729 <td> | |
| 7730 <input type="text" id="logo_width" size="4" placeholder="default" name="width"/> cm | |
| 7731 </td> | |
| 7732 </tr> | |
| 7733 <tr> | |
| 7734 <td><label for="logo_height">Height:</label></td> | |
| 7735 <td> | |
| 7736 <input type="text" id="logo_height" size="4" placeholder="default" name="height"/> cm | |
| 7737 </td> | |
| 7738 </tr> | |
| 7739 </table> | |
| 7740 </form> | |
| 7741 </div> | |
| 7742 <!-- Buttons --> | |
| 7743 <div> | |
| 7744 <div style="float:left;"> | |
| 7745 <input type="button" id="outpop_do" value="Submit" /> | |
| 7746 </div> | |
| 7747 <div style="float:right;"> | |
| 7748 <input id="outpop_cancel" type="button" value="Cancel" /> | |
| 7749 </div> | |
| 7750 <div style="clear:both;"></div> | |
| 7751 </div> | |
| 7752 </div> | |
| 7753 </div> | |
| 7754 </div> | |
| 7755 </div> | |
| 7756 | |
| 7757 | |
| 7758 | |
| 7759 <!-- Page starts here --> | |
| 7760 <div id="top" class="pad1"> | |
| 7761 <div class="prog_logo big"> | |
| 7762 <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABGCAYAAACUsCfoAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9wLHAInL7an9JAAAA8eSURBVHja7ZpZbxv3ucZ/s3AZ7qQkypZELZS3WHKiRJbTFnHqOjZcGzCQBf0A7cUB8glOb89dz30vChRp7xK0aZo4TYq6dtKqSew6iuJWpmPJlrVFFCmKI+7LLJw5F81MFZyec5rTILJaP8AAnAty+Pzf933ebeAhHuIhHuIhHmJPo6TpaeGLfimTydhLS0sUCgWazSbVahXDMOh0Ong8HiKRCAMDAxw+fJhHH31UeFDJ/91/bHp62r558ya6rmOaJuvr6+TzeYrFIoZhAOD1epFlmWAwSDqdZnR0lCNHjjA+Ps7+/fuFPUU8k8nYV69epVKpEA6HuXPnDrOzs7RaLbxeL93d3fj9foLBIB6Ph0ajQaVSAUBRFNLpNI888ggHDhzg3Llzwp4g/vbbb9szMzPE43FyuRwffPAB2WyWnp4ehoaGiMVi2LZNvV6n3W7j8/mIRqN4vV4ajQa1Wo2trS0OHTqEaZo89dRTfO973xMeaOKvvfaaffv2bcLhMCsrK/z+979HVVWOHz/O0NAQxWIRVVVRVRW/348oihiGgSiKxGIxurq6CAQCBINB3n//fcbGxiiXyxw7dowXX3yx1Nvbm3igiBcKhY9u3rw5OTMzQzgc5vbt23zwwQfIsszExAS2bZPP55EkiVAoRCQSIRwOI8sy5XKZ7e1tWq0WnU6HTqfD4OAggUAAVVXpdDo0m01GRkb44Q9/KDxQxH/729/as7Oz+Hw+Pv30U37zm9/g9Xrp6emht7eXYDCI3+/H6/UiCALtdhvLsuh0OkiSRCAQQJZl6vU65XKZ1dVV+vv7SSQS5PN5vF4vhUKBgwcP8qMf/WjXyIs7b+7cuWMvLi4iCAL1ep133nkHXdcZHh4mlUoRDofp7+8nHo9jGAaCIBCPx+nr6yOdTtPX14fH40HTNGRZpqenh76+PrLZLMVikYGBARRFwTRN5ubm+PGPf2zvFnF5583c3BzlchlZlrl16xa1Wo2xsTGi0SiDg4OutUzTJBKJIIoiXq+XQCBAIpEgFAphmiaqqlIoFKjVaoyOjhKJRFhfXycajRKNRunp6WFhYYG33nqLQqHwUTKZPP5VE5ecD5cvX7bv37+Poijkcjl++ctfMjo6ytDQEMlkEo/HQ7lcpt1u4/F4kGUZQRDw+Xz09fVx4MABRkZGSKVSdHV10el0KJVK1Ot14vE4kiRRKpVQFIV4PI5t23z66ad0Op2+K1eu/MeuWVxVVUzTRNd17t27RzKZJJFIEI1GEUWRdruNaZqIoogkSYiiiCiK+P1+AoEA0WiUQ4cOCQCbm5vb5XI5Xi6XWVtbw7ZtZFnG7/e7D1YUhWAwSLVaJZvN2v39/cJXHuOLi4t2sVhEEAS2t7eZn59n//79JBIJwuEwlmXRbDbRdR1BEBAEAcuysCwL2/5LmIriX+Wit7c3EY/HSSQSeDweDMPA4/EQCoWwbRvbtgmFQoTDYUqlErlcbnfE7f79+64gbWxs0G63icViRCIRBEHANE0Mw0CSJLxer0vSUfVKpUKxWGRtbc12UmKr1cI0TQD3t4PBoHtwgUAAv99Ps9kkn8/vjrjlcjlkWabdbrO8vEx3dzfhcJhoNEq9XkfTNERRxOfz4fV6sW0bSZJcBS+VSqytrdFqtbh+/bq9sLBALpdje3sbXddd4jutLwh/8WzLslBVdXeI12o1RFFkc3PTLTFjsRixWAxVVbEsC1mWkSTJdVXnMgyDarWKrusUi0X8fj+WZVGtVimXyxiGgW3bblh4PB78fj/tdhvbthFF0a3tv3Liuq4jiiKFQgFZlolEInR3d6MoConEXytLp1Bx0Ol0sG0bXdfRdZ1arYYgCNi2jaZptFot1zOcQ3LSnxMGzsHvCnHH/RqNBtFoFEmSCIfDAAwNDWFZFu12m0ajgaZpWJbl/oDH4/ncoTii5xBz1N+2bTqdDrIs4/P53MxgWRaapu2exQOBgHsAnU6HdrvN5uYmgUCASCRCJBIhkUhgmibNZpNarUaj0XAt71jfET1RFN1YliTJfUa73SaZTLK1tUWtVkPTNKampnaHuFNGyrKM1+t141bTNGq1GrVazS1EIpEI8XjcLWJqtdrnYthNF58pv23beL1eJEly1VzXder1Oq1Wi2AwiK7ru0PcSSs73bBYLBIMBpEkCdM0qVQq6LpOq9UiHA673Vmn08E0TfdyRM85CNM08Xq9bkoMhULugRqGgd/v3z1Xl2X5c24aDodRVZV4PO7W406/raoqtVqNYDCIz+dDURQ3vp3LuXeEz4nlTqdDOBxG13U3TBRF2b0mJRAI0Gg0EAQBTdPw+/2Uy2VXoJzRkkPEifNWq0UgEHCLEsedLcty1X1nzIdCIRRFoVQqUSqVsCyLYDBIPB7fncotlUq5JaWu6xiGgWmabG1tuanINE0EQXAPwSlk6vU6zWaTdruNpmnud3eWsk6fnkwmMU2Tzc1NVFVFURSi0SjpdHp3iB89ehRRFOnt7XWHCNFolFwu58ar08AYhuEWNH6/H4/H8zlL71R4J5XJskwgECAWi5HP51lZWaHVajE8PEw8Hufw4cO7Q3zfvn0C4E5MNU2jq6uLarVKPp//nPA5hYgzcYlEIoRCIfcQHLd3SDvEPR4PHo+HfD5PPp9HEARGRkYIhUIMDQ0Ju0Ic4NixY3g8Hnp7e8lms8RiMcLhMNlsFk3TXHW3bZtgMOjmfScEvF6vW8s7qczxgGazSSAQ4M9//jOqqlKpVHj88cfx+XyMjY3t7ujp1KlTQrlcdicupVKJkZER1tbWuHfvHqqqEolEiMVitNtt6vW6q+iNRoNms4kkSfh8PtfC0WgURVHo7+9nc3OTjY0N3n33XQYGBkilUiSTSU6ePCnsKnGA559/nkqlwtGjR8nn8/j9fh5//HEsy+LWrVvMz8+j6zqhUAifz4dhGG7z0mq1UFUVXdeJRCIEg0F32loqlbh37x53796lq6sLRVGIRCJMTEzs2pT1c8Qfe+wxYWpqyv1j2WyWVCpFIpGgUqkwNzfHnTt33JTnDCUlSaK7u5v+/n66u7vxeDxun16r1SgUCly/fp3bt29z+vRpBgcHqdVqRKPRB2uh8LOf/cyemZlhYWGBYDBIJBIBoFgs0mw2CYfDxONxfD4fg4ODros7vXWhUKDT6bg5/v3332dlZYWhoSHS6TSnTp1i3759VKtVzpw5w1c9dvpfNymvvPKKff36dbLZLIqiuBVWs9mk0WhgWZbbn4fDYURRRNM0AoEAvb29+Hw+Go0Gly9fZmNjg4mJCcbGxti/f787mJyfn6darTI5OcmJEyeEB4J4sVj8wfT09L/Pzs6SzWbdpWEikXBJGoZBs9kkGo0iyzKmabrLhtXVVTKZDJubm5w9e5YjR44wMDDAd7/7XWF2dtZeXFzkyJEj7pZm//79pFIpenp6vhIP+D8f8NZbb9nr6+ssLy+ztbXl1t5er9fdhxeLRSRJoquri0qlQiaTYXt7m0gkwpkzZ5BlmbGxMV544QX3eR9//LE9Pz/PsWPHuHHjBouLi0iSxMDAAMePH2dqakrYVeIAKysr9u3bt1leXnZn65qmoeu6W9AYhkGj0aBYLGKaJocOHeLRRx8lkUgwOTnpjp4d5HI5++OPP6ZcLjM+Ps61a9dYWFig2Wzi9Xp5/vnnOX36tLCrxHfi1q1b9tLSkuv+9XrdbTEVRSEWi5FMJhkdHWV4eJiDBw/+j8/Y2tr6+WuvvfYdwzBIpVJIkoSqqszPz1Ov17lw4QJf+9rXziYSiau7TvxvoVQqpUul0n2n2/oibz+899579k9/+lPC4TCnTp3i61//Orlcjp/85CdomsbTTz/NiRMn/pvH/CMotrQfyF/GD8Xj8aX/7yEePnx4dnx8fPJ3v/sdiqIwODjI5OSkcOPGDfvNN9/kypUr5PN5MpmMPT4+/qWQ71Z835fZZSSTyeMrKyt2vV7n7t27vPrqq1y7ds1+8sknhT/+8Y/2pUuXuHnzJs1mk6WlJTudTn8p5EUeAAwPDwvPPfccBw4cYHV1lc+KJ3t0dPTVixcvcvDgQebn53n55ZeZmZn5h1fLalv/twfqTaRMJmP/4he/YH19nSNHjnDhwgVisRj37t3jnXfeYWFhgQMHDnD+/HmeeuopYc9b3MH4+LjwrW99C0EQuHXrFtPT09RqNfr7+zlx4gTpdJqNjQ3efPNN3njjDbtYLP5gV1X9y8bly5ft119/nUqlwsmTJzl9+jQej4ePPvqITz75hLW1NYLBIJOTk5w7d46+vr4vzEN+EImfO3dOuHr1qv3666/z3nvvoWkaZ8+e5YknnnBXU5qmcfPmTQzDYG1tzR4cHBT2vMUdTE9P25cuXaJQKDA5OcmFCxfQdZ3Z2VkWFhbY2NhAURRSqRTPPvssY2Njwp62uINvfvObwp/+9Cf7V7/6FTdu3KDT6XD+/HmmpqbcoaaqqszOzmIYxhfK9Q80cYCJiQlhbm7OFgSBubk5vF4vzzzzDBMTE+7CMRgMsrCwwEsvvcS1a9fsb3zjG8KedvWd+OSTT+y3336bubk5JicnOXnyJJZl8eGHH7K2tkahUKDRaLBv3z4uXrzI2bNnhT1tcQdHjx4VMpmM3el0WFxcJBQKMTU1xbFjx6hWqwC0221WVlb49a9/zY0bN+wnn3xS2BN5/O/J88899xzDw8NkMhnm5uaIx+M8/fTT9PT0YFkWg4ODrK6u8sorrzA/P2/veVffidXVVfvdd99lenqa8+fPMzo6iqZp/OEPf2BhYYFWq4Usy4yMjHDx4kX+luXlvUh8aGhImJmZsS3L4vr165imSSqVYt++fbTbbWq1GtVqlWq1yt27d7l//749Ojoq7HniAFNTU8LS0pJdLpe5e/cu6+vrRCIRhoeHqVarrK6uous66+vrZLNZSqVS+rP2eW8TB0in00I2m3XVHqCvr49YLEYikXBfRiqXy+Ryufs7Q1tkj6O/v1/49re/zTPPPIMgCMzPz7sraJ/Ph9/vd/d3pVIp/U9hcQdOnX7p0iU7k8kgiqK76lIUxX19dKerC/wTYXt7+8zm5uaV5eVlNjY2iMfj+P1+hoeH6enpmd35evg/FXEHm1uF7ZXltXgg6EcSPSR7u/+zO9H1ff6VsFWq/pyHeIiHeIh/FfwXjVDdIW9O2PAAAAAASUVORK5CYII=" alt="MEME Logo"> | |
| 7763 <h1>MEME</h1> | |
| 7764 <h2>Multiple Em for Motif Elicitation</h2> | |
| 7765 </div> | |
| 7766 <p> | |
| 7767 For further information on how to interpret these results or to get a | |
| 7768 copy of the MEME software please access | |
| 7769 <a href="http://meme-suite.org/">http://meme-suite.org</a>. | |
| 7770 </p> | |
| 7771 <p>If you use MEME in your research, please cite the following paper:<br /> | |
| 7772 <span class="citation"> | |
| 7773 Timothy L. Bailey and Charles Elkan, | |
| 7774 "Fitting a mixture model by expectation maximization to discover motifs in biopolymers", | |
| 7775 <em>Proceedings of the Second International Conference on Intelligent Systems | |
| 7776 for Molecular Biology</em>, pp. 28-36, AAAI Press, Menlo Park, California, 1994. | |
| 7777 <a href="http://meme-suite.org/doc/ismb94.pdf">[pdf]</a> | |
| 7778 </span> | |
| 7779 </p> | |
| 7780 </div> | |
| 7781 <!-- navigation --> | |
| 7782 <div class="pad2"> | |
| 7783 <a class="jump" href="#motifs_sec">Discovered Motifs</a> | |
| 7784 | | |
| 7785 <a class="jump" href="#sites_sec">Motif Locations</a> | |
| 7786 | | |
| 7787 <a class="jump" href="#inputs_sec">Inputs & Settings</a> | |
| 7788 | | |
| 7789 <a class="jump" href="#info_sec">Program information</a> | |
| 7790 </div> | |
| 7791 <!-- alert the user when their browser is not up to the task --> | |
| 7792 <noscript><h1 style="color:red">Javascript is required to view these results!</h1></noscript> | |
| 7793 <h1 id="html5_warning" style="color:red; display:none;">Your browser does not support canvas!</h1> | |
| 7794 <script> | |
| 7795 if (!window.HTMLCanvasElement) $("html5_warning").style.display = "block"; | |
| 7796 </script> | |
| 7797 <h2 class="mainh pad2" id="motifs_sec">Discovered Motifs</h2> | |
| 7798 <div id="motifs" class="box"> | |
| 7799 <p>Please wait... Loading...</p> | |
| 7800 <p>If the page has fully loaded and this message does not disappear then an error may have occurred.</p> | |
| 7801 </div> | |
| 7802 <h2 class="mainh pad2" id="sites_sec">Motif Locations</h2> | |
| 7803 <div id="blocks" class="box"> | |
| 7804 <p>Please wait... Loading...</p> | |
| 7805 <p>If the page has fully loaded and this message does not disappear then an error may have occurred.</p> | |
| 7806 </div> | |
| 7807 <h2 class="mainh pad2" id="inputs_sec">Inputs & Settings</h2> | |
| 7808 <div class="box"> | |
| 7809 <h4>Sequences</h4> | |
| 7810 <table id="seq_info" class="inputs"> | |
| 7811 <tr><th>Source <div class="help" data-topic="pop_seq_source"></div></th> | |
| 7812 <th class="col_psp">PSP Source <div class="help" data-topic="pop_psp_source"></div></th> | |
| 7813 <th>Alphabet <div class="help" data-topic="pop_seq_alph"></div></th> | |
| 7814 <th>Sequence Count <div class="help" data-topic="pop_seq_count"></div></th> | |
| 7815 </tr> | |
| 7816 <tr> | |
| 7817 <td id="ins_seq_source"></td> | |
| 7818 <td id="ins_seq_psp" class="col_psp"></td> | |
| 7819 <td id="ins_seq_alphabet"></td> | |
| 7820 <td id="ins_seq_count"></td> | |
| 7821 </tr> | |
| 7822 </table> | |
| 7823 <script> | |
| 7824 { | |
| 7825 var db = data.sequence_db; | |
| 7826 $("ins_seq_source").innerHTML = db.source; | |
| 7827 $("ins_seq_alphabet").innerHTML = meme_alphabet.get_alphabet_name(); | |
| 7828 $("ins_seq_count").innerHTML = db.sequences.length; | |
| 7829 if (db.psp) { | |
| 7830 $("ins_seq_psp").innerHTML = db.psp; | |
| 7831 } | |
| 7832 toggle_class($("seq_info"), "hide_psp", !(db.psp)); | |
| 7833 } | |
| 7834 </script> | |
| 7835 <h4>Background</h4> | |
| 7836 <span id="alpha_bg"></span> | |
| 7837 <script> | |
| 7838 { | |
| 7839 $("alpha_bg").appendChild(make_alpha_bg_table(meme_alphabet, data.sequence_db.freqs)); | |
| 7840 } | |
| 7841 </script> | |
| 7842 <h4>Other Settings</h4> | |
| 7843 <table id="tbl_settings" class="inputs hide_advanced"> | |
| 7844 <tr> | |
| 7845 <th>Motif Site Distribution</th> | |
| 7846 <td id="opt_mod"> | |
| 7847 <span class="mod_zoops">ZOOPS: Zero or one site per sequence</span> | |
| 7848 <span class="mod_oops">OOPS: Exactly one site per sequence</span> | |
| 7849 <span class="mod_anr">ANR: Any number of sites per sequence</span> | |
| 7850 </td> | |
| 7851 </tr> | |
| 7852 <tr> | |
| 7853 <th>Site Strand Handling</th> | |
| 7854 <td id="opt_strand"> | |
| 7855 <span class="strand_none">This alphabet only has one strand</span> | |
| 7856 <span class="strand_given">Sites must be on the given strand</span> | |
| 7857 <span class="strand_both">Sites may be on either strand</span> | |
| 7858 </td> | |
| 7859 </tr> | |
| 7860 <tr> | |
| 7861 <th>Maximum Number of Motifs</th> | |
| 7862 <td id="opt_nmotifs"></td> | |
| 7863 </tr> | |
| 7864 <tr> | |
| 7865 <th>Motif E-value Threshold</th> | |
| 7866 <td id="opt_evt"></td> | |
| 7867 </tr> | |
| 7868 <tr> | |
| 7869 <th>Minimum Motif Width</th> | |
| 7870 <td id="opt_minw"></td> | |
| 7871 </tr> | |
| 7872 <tr> | |
| 7873 <th>Maximum Motif Width</th> | |
| 7874 <td id="opt_maxw"></td> | |
| 7875 </tr> | |
| 7876 <tr> | |
| 7877 <th>Minimum Sites per Motif</th> | |
| 7878 <td id="opt_minsites"></td> | |
| 7879 </tr> | |
| 7880 <tr> | |
| 7881 <th>Maximum Sites per Motif</th> | |
| 7882 <td id="opt_maxsites"></td> | |
| 7883 </tr> | |
| 7884 <tr class="advanced"> | |
| 7885 <th>Bias on Number of Sites</th> | |
| 7886 <td id="opt_wnsites"></td> | |
| 7887 </tr> | |
| 7888 <tr class="advanced"> | |
| 7889 <th>Sequence Prior</th> | |
| 7890 <td id="opt_prior"> | |
| 7891 <span class="prior_dirichlet">Simple Dirichlet</span> | |
| 7892 <span class="prior_dmix">Dirichlets Mix</span> | |
| 7893 <span class="prior_mega">Mega-weight Dirichlets Mix</span> | |
| 7894 <span class="prior_megap">Mega-weight Dirichlets Mix Plus</span> | |
| 7895 <span class="prior_addone">Add One</span> | |
| 7896 </td> | |
| 7897 </tr> | |
| 7898 <tr class="advanced"> | |
| 7899 <th>Sequence Prior Strength</th> | |
| 7900 <td id="opt_b"></td> | |
| 7901 </tr> | |
| 7902 <tr class="advanced"> | |
| 7903 <th>EM Starting Point Source</th> | |
| 7904 <td id="opt_substring"> | |
| 7905 <span class="substring_on">From substrings in input sequences</span> | |
| 7906 <span class="substring_off">From strings on command line (-cons)</span> | |
| 7907 </td> | |
| 7908 </tr> | |
| 7909 <tr class="advanced"> | |
| 7910 <th>EM Starting Point Map Type</th> | |
| 7911 <td id="opt_spmap"> | |
| 7912 <span class="spmap_uni">Uniform</span> | |
| 7913 <span class="spmap_pam">Point Accepted Mutation</span> | |
| 7914 </td> | |
| 7915 </tr> | |
| 7916 <tr class="advanced"> | |
| 7917 <th>EM Starting Point Fuzz</th> | |
| 7918 <td id="opt_spfuzz"></td> | |
| 7919 </tr> | |
| 7920 <tr class="advanced"> | |
| 7921 <th>EM Maximum Iterations</th> | |
| 7922 <td id="opt_maxiter"></td> | |
| 7923 </tr> | |
| 7924 <tr class="advanced"> | |
| 7925 <th>EM Improvement Threshold</th> | |
| 7926 <td id="opt_distance"></td> | |
| 7927 </tr> | |
| 7928 <tr class="advanced"> | |
| 7929 <th>Trim Gap Open Cost</th> | |
| 7930 <td id="opt_wg"></td> | |
| 7931 </tr> | |
| 7932 <tr class="advanced"> | |
| 7933 <th>Trim Gap Extend Cost</th> | |
| 7934 <td id="opt_ws"></td> | |
| 7935 </tr> | |
| 7936 <tr class="advanced"> | |
| 7937 <th>End Gap Treatment</th> | |
| 7938 <td id="opt_noendgaps"> | |
| 7939 <span class="noendgaps_on">No cost</span> | |
| 7940 <span class="noendgaps_off">Same cost as other gaps</span> | |
| 7941 </td> | |
| 7942 </tr> | |
| 7943 <tr> | |
| 7944 <td colspan="2" style="text-align: center"> | |
| 7945 <a href="javascript:toggle_class(document.getElementById('tbl_settings'), 'hide_advanced')"> | |
| 7946 <span class="show_more">Show Advanced Settings</span> | |
| 7947 <span class="show_less">Hide Advanced Settings</span> | |
| 7948 </a> | |
| 7949 </td> | |
| 7950 </tr> | |
| 7951 </table> | |
| 7952 <script> | |
| 7953 { | |
| 7954 $("opt_mod").className = data.options.mod; | |
| 7955 $("opt_strand").className = (meme_alphabet.has_complement() ? (data.options.revcomp ? "both" : "given") : "none"); | |
| 7956 $("opt_nmotifs").textContent = data.options.nmotifs; | |
| 7957 $("opt_evt").textContent = (typeof data.options.evt === "number" ? data.options.evt : "no limit"); | |
| 7958 $("opt_minw").textContent = data.options.minw; | |
| 7959 $("opt_maxw").textContent = data.options.maxw; | |
| 7960 $("opt_minsites").textContent = data.options.minsites; | |
| 7961 $("opt_maxsites").textContent = data.options.maxsites; | |
| 7962 $("opt_wnsites").textContent = data.options.wnsites; | |
| 7963 $("opt_spmap").className = data.options.spmap; | |
| 7964 $("opt_spfuzz").textContent = data.options.spfuzz; | |
| 7965 $("opt_prior").className = data.options.prior; | |
| 7966 $("opt_b").textContent = data.options.b; | |
| 7967 $("opt_maxiter").textContent = data.options.maxiter; | |
| 7968 $("opt_distance").textContent = data.options.distance; | |
| 7969 $("opt_wg").textContent = data.options.wg; | |
| 7970 $("opt_ws").textContent = data.options.ws; | |
| 7971 $("opt_noendgaps").className = (data.options.noendgaps ? "on" : "off"); | |
| 7972 $("opt_substring").className = (data.options.substring ? "on" : "off"); | |
| 7973 } | |
| 7974 </script> | |
| 7975 </div> | |
| 7976 <!-- list information on this program --> | |
| 7977 <div id="info_sec" class="bar"> | |
| 7978 <div class="subsection"> | |
| 7979 <h5 id="version">MEME version</h5> | |
| 7980 <span id="ins_version"></span> | |
| 7981 (Release date: <span id="ins_release"></span>)<br> | |
| 7982 </div> | |
| 7983 <script> | |
| 7984 $("ins_version").innerHTML = data["version"]; | |
| 7985 $("ins_release").innerHTML = data["release"]; | |
| 7986 </script> | |
| 7987 <div class="subsection"> | |
| 7988 <h5 id="reference">Reference</h5> | |
| 7989 <span class="citation"> | |
| 7990 Timothy L. Bailey and Charles Elkan, | |
| 7991 "Fitting a mixture model by expectation maximization to discover motifs in biopolymers", | |
| 7992 <em>Proceedings of the Second International Conference on Intelligent Systems | |
| 7993 for Molecular Biology</em>, pp. 28-36, AAAI Press, Menlo Park, California, 1994. | |
| 7994 </span> | |
| 7995 </div> | |
| 7996 <div class="subsection"> | |
| 7997 <h5 id="command">Command line</h5> | |
| 7998 <textarea id="cmd" rows="5" style="width:100%;" readonly="readonly"> | |
| 7999 </textarea> | |
| 8000 <script>$("cmd").value = data["cmd"].join(" ");</script> | |
| 8001 </div> | |
| 8002 </div> | |
| 8003 | |
| 8004 </body> | |
| 8005 </html> |
