Package weblogolib :: Module _cli

Source Code for Module weblogolib._cli

  1  #!/usr/bin/env python 
  2   
  3  # -------------------------------- WebLogo -------------------------------- 
  4   
  5  #  Copyright (c) 2003-2004 The Regents of the University of California. 
  6  #  Copyright (c) 2005 Gavin E. Crooks 
  7  #  Copyright (c) 2006-2011, The Regents of the University of California, through  
  8  #  Lawrence Berkeley National Laboratory (subject to receipt of any required 
  9  #  approvals from the U.S. Dept. of Energy).  All rights reserved. 
 10   
 11  #  This software is distributed under the new BSD Open Source License. 
 12  #  <http://www.opensource.org/licenses/bsd-license.html> 
 13  # 
 14  #  Redistribution and use in source and binary forms, with or without  
 15  #  modification, are permitted provided that the following conditions are met:  
 16  # 
 17  #  (1) Redistributions of source code must retain the above copyright notice,  
 18  #  this list of conditions and the following disclaimer.  
 19  # 
 20  #  (2) Redistributions in binary form must reproduce the above copyright  
 21  #  notice, this list of conditions and the following disclaimer in the  
 22  #  documentation and or other materials provided with the distribution.  
 23  # 
 24  #  (3) Neither the name of the University of California, Lawrence Berkeley  
 25  #  National Laboratory, U.S. Dept. of Energy nor the names of its contributors  
 26  #  may be used to endorse or promote products derived from this software  
 27  #  without specific prior written permission.  
 28  # 
 29  #  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"  
 30  #  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  
 31  #  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  
 32  #  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE  
 33  #  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR  
 34  #  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF  
 35  #  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  
 36  #  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  
 37  #  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)  
 38  #  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  
 39  #  POSSIBILITY OF SUCH DAMAGE.  
 40   
 41  # WebLogo Command Line Interface 
 42   
 43  import sys 
 44   
 45  from color import * 
 46  from colorscheme import ColorScheme, ColorGroup 
 47  from corebio.utils import * 
 48  from string import Template 
 49   
 50  from corebio import seq_io 
 51   
 52   
 53   
 54  import os  
 55  from corebio.utils.deoptparse import DeOptionParser 
 56  from optparse import OptionGroup 
 57   
 58  from weblogolib import LogoOptions, LogoData, LogoFormat 
 59  from weblogolib import parse_prior, description, release_description, formatters, default_formatter 
 60  from weblogolib import std_alphabets, std_units, std_sizes, std_color_schemes 
 61  from weblogolib import read_seq_data 
 62   
 63  # ====================== Main: Parse Command line ============================= 
64 -def main():
65 """WebLogo command line interface """ 66 67 # ------ Parse Command line ------ 68 parser = _build_option_parser() 69 (opts, args) = parser.parse_args(sys.argv[1:]) 70 if args : parser.error("Unparsable arguments: %s " % args) 71 72 if opts.serve: 73 httpd_serve_forever(opts.port) # Never returns? 74 sys.exit(0) 75 76 77 # ------ Create Logo ------ 78 try: 79 data = _build_logodata(opts) 80 format = _build_logoformat(data, opts) 81 82 formatter = opts.formatter 83 formatter(data, format, opts.fout) 84 85 except ValueError, err : 86 print >>sys.stderr, 'Error:', err 87 sys.exit(2) 88 except KeyboardInterrupt, err: 89 sys.exit(0) 90 # End main() 91 92
93 -def httpd_serve_forever(port=8080) :
94 """ Start a webserver on a local port.""" 95 import BaseHTTPServer 96 import CGIHTTPServer 97 98 class __HTTPRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler): 99 # Modify CGIHTTPRequestHandler so that it will run the cgi script directly, instead of exec'ing 100 # This bypasses the need for the cgi script to have execute permissions set, 101 # since distutils install does not preserve permissions. 102 def is_cgi(self) : 103 self.have_fork = False # Prevent CGIHTTPRequestHandler from using fork 104 if self.path == "/create.cgi": 105 self.cgi_info = '', 'create.cgi' 106 return True 107 return False
108 def is_python(self,path): # Let CGIHTTPRequestHandler know that cgi script is python 109 return True 110 111 112 # Add current directory to PYTHONPATH. This is 113 # so that we can run the standalone server 114 # without having to run the install script. 115 pythonpath = os.getenv("PYTHONPATH", '') 116 pythonpath += ":" + os.path.abspath(sys.path[0]).split()[0] 117 os.environ["PYTHONPATH"] = pythonpath 118 119 htdocs = resource_filename(__name__, 'htdocs', __file__) 120 os.chdir(htdocs) 121 122 HandlerClass = __HTTPRequestHandler 123 ServerClass = BaseHTTPServer.HTTPServer 124 httpd = ServerClass(('', port), HandlerClass) 125 print "WebLogo server running at http://localhost:%d/" % port 126 127 try : 128 httpd.serve_forever() 129 except KeyboardInterrupt: 130 sys.exit(0) 131 # end httpd_serve_forever() 132 133 134
135 -def _build_logodata(options) :
136 137 if options.input_parser != "transfac": 138 seqs = read_seq_data(options.fin, 139 options.input_parser.read, 140 alphabet=options.alphabet, 141 ignore_lower_case = options.ignore_lower_case) 142 143 if options.reverse: 144 seqs = SeqList([s.reverse() for s in seqs], seqs.alphabet) 145 146 if options.complement : 147 seqs= SeqList( [Seq(s,seqs.alphabet).complement() for s in seqs], seqs.alphabet) 148 149 150 151 prior = parse_prior( options.composition,seqs.alphabet, options.weight) 152 data = LogoData.from_seqs(seqs, prior) 153 154 else : 155 from corebio.matrix import Motif 156 157 if options.ignore_lower_case: 158 raise ValueError("error: option --ignore-lower-case incompatible with matrix input") 159 160 #FIXME : implement 161 if options.reverse: 162 raise ValueError("error: option --reverse incompatible with matrix input") 163 164 #FIXME : implement 165 if options.complement: 166 raise ValueError("error: option --complement incompatible with matrix input") 167 168 motif = Motif.read_transfac(options.fin, alphabet=options.alphabet) 169 prior = parse_prior( options.composition,motif.alphabet, options.weight) 170 data = LogoData.from_counts(motif.alphabet, motif, prior) 171 172 return data
173 174
175 -def _build_logoformat( logodata, opts) :
176 """ Extract and process relevant option values and return a 177 LogoFormat object.""" 178 179 args = {} 180 direct_from_opts = [ 181 "stacks_per_line", 182 "logo_title", 183 "yaxis_label", 184 "show_xaxis", 185 "show_yaxis", 186 "xaxis_label", 187 "show_ends", 188 "fineprint", 189 "show_errorbars", 190 "show_boxes", 191 "yaxis_tic_interval", 192 "resolution", 193 "alphabet", 194 "debug", 195 "show_ends", 196 "default_color", 197 #"show_color_key", 198 "color_scheme", 199 "unit_name", 200 "logo_label", 201 "yaxis_scale", 202 "first_index", 203 "logo_start", 204 "logo_end", 205 "scale_width", 206 "annotate", 207 "stack_width", 208 "stack_aspect_ratio" 209 ] 210 211 for k in direct_from_opts: 212 args[k] = opts.__dict__[k] 213 214 # logo_size = copy.copy(opts.__dict__['logo_size']) 215 # size_from_opts = ["stack_width", "stack_height"] 216 # for k in size_from_opts : 217 # length = getattr(opts, k) 218 # if length : setattr( logo_size, k, length ) 219 # args["size"] = logo_size 220 221 222 if opts.colors: 223 color_scheme = ColorScheme() 224 for color, symbols, desc in opts.colors: 225 try : 226 #c = Color.from_string(color) 227 color_scheme.groups.append( ColorGroup(symbols, color, desc) ) 228 except ValueError : 229 raise ValueError( 230 "error: option --color: invalid value: '%s'" % color ) 231 232 args["color_scheme"] = color_scheme 233 234 235 if opts.annotate: 236 args["annotate"] = opts.annotate.split(',') 237 238 239 logooptions = LogoOptions() 240 for a, v in args.iteritems() : 241 setattr(logooptions,a,v) 242 243 244 theformat = LogoFormat(logodata, logooptions ) 245 return theformat
246 247 248 249 250 251 252 # ========================== OPTIONS ==========================
253 -def _build_option_parser() :
254 defaults = LogoOptions() 255 parser = DeOptionParser(usage="%prog [options] < sequence_data.fa > sequence_logo.eps", 256 description = description, 257 version = release_description, 258 add_verbose_options = False 259 ) 260 261 io_grp = OptionGroup(parser, "Input/Output Options",) 262 data_grp = OptionGroup(parser, "Logo Data Options",) 263 trans_grp = OptionGroup(parser, "Transformations", "Optional transformations of the sequence data.") 264 265 266 format_grp = OptionGroup(parser, "Logo Format Options", 267 "These options control the format and display of the logo.") 268 color_grp = OptionGroup(parser, "Color Options", 269 "Colors can be specified using CSS2 syntax. e.g. 'red', '#FF0000', etc.") 270 advanced_grp = OptionGroup(parser, "Advanced Format Options", 271 "These options provide fine control over the display of the logo. ") 272 server_grp = OptionGroup(parser, "WebLogo Server", 273 "Run a standalone webserver on a local port.") 274 275 276 parser.add_option_group(io_grp) 277 parser.add_option_group(data_grp) 278 parser.add_option_group(trans_grp) 279 parser.add_option_group(format_grp) 280 parser.add_option_group(color_grp) 281 parser.add_option_group(advanced_grp) 282 parser.add_option_group(server_grp) 283 284 # ========================== IO OPTIONS ========================== 285 286 io_grp.add_option( "-f", "--fin", 287 dest="fin", 288 action="store", 289 type="file_in", 290 default=sys.stdin, 291 help="Sequence input file (default: stdin)", 292 metavar="FILENAME") 293 294 # Add position weight matrix formats to input parsers by hand 295 fin_choices = dict(seq_io.format_names()) 296 fin_choices['transfac'] = 'transfac' 297 298 io_grp.add_option("-D", "--datatype", 299 dest="input_parser", 300 action="store", type ="dict", 301 default = seq_io, 302 choices = fin_choices, # seq_io.format_names(), 303 help="Type of multiple sequence alignment or position weight matrix file: (%s, transfac)" % 304 ', '.join([ f.names[0] for f in seq_io.formats]), 305 metavar="FORMAT") 306 307 io_grp.add_option("-o", "--fout", dest="fout", 308 type="file_out", 309 default=sys.stdout, 310 help="Output file (default: stdout)", 311 metavar="FILENAME") 312 313 io_grp.add_option( "-F", "--format", 314 dest="formatter", 315 action="store", 316 type="dict", 317 choices = formatters, 318 metavar= "FORMAT", 319 help="Format of output: eps (default), png, png_print, pdf, jpeg, svg, logodata", 320 default = default_formatter) 321 322 323 # ========================== Data OPTIONS ========================== 324 325 326 327 data_grp.add_option( "-A", "--sequence-type", 328 dest="alphabet", 329 action="store", 330 type="dict", 331 choices = std_alphabets, 332 help="The type of sequence data: 'protein', 'rna' or 'dna'.", 333 metavar="TYPE") 334 335 data_grp.add_option( "-a", "--alphabet", 336 dest="alphabet", 337 action="store", 338 help="The set of symbols to count, e.g. 'AGTC'. " 339 "All characters not in the alphabet are ignored. " 340 "If neither the alphabet nor sequence-type are specified then weblogo will examine the input data and make an educated guess. " 341 "See also --sequence-type, --ignore-lower-case" ) 342 343 344 data_grp.add_option( "-U", "--units", 345 dest="unit_name", 346 action="store", 347 choices = std_units.keys(), 348 type="choice", 349 default = defaults.unit_name, 350 help="A unit of entropy ('bits' (default), 'nats', 'digits'), or a unit of free energy ('kT', 'kJ/mol', 'kcal/mol'), or 'probability' for probabilities", 351 metavar = "NUMBER") 352 353 354 data_grp.add_option( "", "--composition", 355 dest="composition", 356 action="store", 357 type="string", 358 default = "auto", 359 help="The expected composition of the sequences: 'auto' (default), 'equiprobable', 'none' (do not perform any compositional adjustment), a CG percentage, a species name (e.g. 'E. coli', 'H. sapiens'), or an explicit distribution (e.g. \"{'A':10, 'C':40, 'G':40, 'T':10}\"). The automatic option uses a typical distribution for proteins and equiprobable distribution for everything else. ", 360 metavar="COMP.") 361 362 data_grp.add_option( "", "--weight", 363 dest="weight", 364 action="store", 365 type="float", 366 default = None, 367 help="The weight of prior data. Default: total pseudocounts equal to the number of monomer types.", 368 metavar="NUMBER") 369 370 data_grp.add_option( "-i", "--first-index", 371 dest="first_index", 372 action="store", 373 type="int", 374 default = 1, 375 help="Index of first position in sequence data (default: 1)", 376 metavar="INDEX") 377 378 data_grp.add_option( "-l", "--lower", 379 dest="logo_start", 380 action="store", 381 type="int", 382 help="Lower bound of sequence to display", 383 metavar="INDEX") 384 385 data_grp.add_option( "-u", "--upper", 386 dest="logo_end", 387 action="store", 388 type="int", 389 help="Upper bound of sequence to display", 390 metavar="INDEX") 391 392 # ========================== Transformation OPTIONS ========================== 393 394 395 # FIXME Add test? 396 trans_grp.add_option( "", "--ignore-lower-case", 397 dest="ignore_lower_case", 398 action="store_true", 399 default=False, 400 help="Disregard lower case letters and only count upper case letters in sequences." 401 ) 402 403 trans_grp.add_option( "", "--reverse", 404 dest="reverse", 405 action="store_true", 406 default=False, 407 help="reverse sequences", 408 ) 409 410 trans_grp.add_option( "", "--complement", 411 dest="complement", 412 action="store_true", 413 default=False, 414 help="complement DNA sequences", 415 ) 416 417 418 419 # ========================== FORMAT OPTIONS ========================== 420 421 format_grp.add_option( "-s", "--size", 422 dest="stack_width", 423 action="store", 424 type ="dict", 425 choices = std_sizes, 426 metavar = "LOGOSIZE", 427 default = defaults.stack_width, 428 help="Specify a standard logo size (small, medium (default), large)" ) 429 430 format_grp.add_option( "-n", "--stacks-per-line", 431 dest="stacks_per_line", 432 action="store", 433 type="int", 434 help="Maximum number of logo stacks per logo line. (default: %default)", 435 default = defaults.stacks_per_line, 436 metavar="COUNT") 437 438 format_grp.add_option( "-t", "--title", 439 dest="logo_title", 440 action="store", 441 type="string", 442 help="Logo title text.", 443 default = defaults.logo_title, 444 metavar="TEXT") 445 446 format_grp.add_option( "", "--label", 447 dest="logo_label", 448 action="store", 449 type="string", 450 help="A figure label, e.g. '2a'", 451 default = defaults.logo_label, 452 metavar="TEXT") 453 454 format_grp.add_option( "-X", "--show-xaxis", 455 action="store", 456 type = "boolean", 457 default= defaults.show_xaxis, 458 metavar = "YES/NO", 459 help="Display sequence numbers along x-axis? (default: %default)") 460 461 format_grp.add_option( "-x", "--xlabel", 462 dest="xaxis_label", 463 action="store", 464 type="string", 465 default = defaults.xaxis_label, 466 help="X-axis label", 467 metavar="TEXT") 468 469 format_grp.add_option( "", "--annotate", 470 dest="annotate", 471 action="store", 472 type="string", 473 default = None, 474 help="A comma separated list of custom stack annotations, e.g. '1,3,4,5,6,7'. Annotation list must be same length as sequences.", 475 metavar="TEXT") 476 477 format_grp.add_option( "-S", "--yaxis", 478 dest="yaxis_scale", 479 action="store", 480 type="float", 481 help="Height of yaxis in units. (Default: Maximum value with uninformative prior.)", 482 metavar = "UNIT") 483 484 format_grp.add_option( "-Y", "--show-yaxis", 485 action="store", 486 type = "boolean", 487 dest = "show_yaxis", 488 default= defaults.show_yaxis, 489 metavar = "YES/NO", 490 help="Display entropy scale along y-axis? (default: %default)") 491 492 format_grp.add_option( "-y", "--ylabel", 493 dest="yaxis_label", 494 action="store", 495 type="string", 496 help="Y-axis label (default depends on plot type and units)", 497 metavar="TEXT") 498 499 format_grp.add_option( "-E", "--show-ends", 500 action="store", 501 type = "boolean", 502 default= defaults.show_ends, 503 metavar = "YES/NO", 504 help="Label the ends of the sequence? (default: %default)") 505 506 format_grp.add_option( "-P", "--fineprint", 507 dest="fineprint", 508 action="store", 509 type="string", 510 default= defaults.fineprint, 511 help="The fine print (default: weblogo version)", 512 metavar="TEXT") 513 514 format_grp.add_option( "", "--ticmarks", 515 dest="yaxis_tic_interval", 516 action="store", 517 type="float", 518 default= defaults.yaxis_tic_interval, 519 help="Distance between ticmarks (default: %default)", 520 metavar = "NUMBER") 521 522 523 format_grp.add_option( "", "--errorbars", 524 dest = "show_errorbars", 525 action="store", 526 type = "boolean", 527 default= defaults.show_errorbars, 528 metavar = "YES/NO", 529 help="Display error bars? (default: %default)") 530 531 532 533 # ========================== Color OPTIONS ========================== 534 # TODO: Future Feature 535 # color_grp.add_option( "-K", "--color-key", 536 # dest= "show_color_key", 537 # action="store", 538 # type = "boolean", 539 # default= defaults.show_color_key, 540 # metavar = "YES/NO", 541 # help="Display a color key (default: %default)") 542 543 544 color_scheme_choices = std_color_schemes.keys() 545 color_scheme_choices.sort() 546 color_grp.add_option( "-c", "--color-scheme", 547 dest="color_scheme", 548 action="store", 549 type ="dict", 550 choices = std_color_schemes, 551 metavar = "SCHEME", 552 default = None, # Auto 553 help="Specify a standard color scheme (%s)" % \ 554 ", ".join(color_scheme_choices) ) 555 556 color_grp.add_option( "-C", "--color", 557 dest="colors", 558 action="append", 559 metavar="COLOR SYMBOLS DESCRIPTION ", 560 nargs = 3, 561 default=[], 562 help="Specify symbol colors, e.g. --color black AG 'Purine' --color red TC 'Pyrimidine' ") 563 564 color_grp.add_option( "", "--default-color", 565 dest="default_color", 566 action="store", 567 metavar="COLOR", 568 default= defaults.default_color, 569 help="Symbol color if not otherwise specified.") 570 571 572 # ========================== Advanced options ========================= 573 574 advanced_grp.add_option( "-W", "--stack-width", 575 dest="stack_width", 576 action="store", 577 type="float", 578 default= defaults.stack_width, 579 help="Width of a logo stack (default: %s)"% defaults.stack_width, 580 metavar="POINTS" ) 581 582 advanced_grp.add_option( "", "--aspect-ratio", 583 dest="stack_aspect_ratio", 584 action="store", 585 type="float", 586 default= defaults.stack_aspect_ratio , 587 help="Ratio of stack height to width (default: %s)"%defaults.stack_aspect_ratio, 588 metavar="POINTS" ) 589 590 advanced_grp.add_option( "", "--box", 591 dest="show_boxes", 592 action="store", 593 type = "boolean", 594 default=False, 595 metavar = "YES/NO", 596 help="Draw boxes around symbols? (default: no)") 597 598 advanced_grp.add_option( "", "--resolution", 599 dest="resolution", 600 action="store", 601 type="float", 602 default=96, 603 help="Bitmap resolution in dots per inch (DPI). (Default: 96 DPI, except png_print, 600 DPI) Low resolution bitmaps (DPI<300) are antialiased.", 604 metavar="DPI") 605 606 advanced_grp.add_option( "", "--scale-width", 607 dest="scale_width", 608 action="store", 609 type = "boolean", 610 default= True, 611 metavar = "YES/NO", 612 help="Scale the visible stack width by the fraction of symbols in the column? (I.e. columns with many gaps of unknowns are narrow.) (Default: yes)") 613 614 advanced_grp.add_option( "", "--debug", 615 action="store", 616 type = "boolean", 617 default= defaults.debug, 618 metavar = "YES/NO", 619 help="Output additional diagnostic information. (Default: %default)") 620 621 622 # ========================== Server options ========================= 623 server_grp.add_option( "", "--serve", 624 dest="serve", 625 action="store_true", 626 default= False, 627 help="Start a standalone WebLogo server for creating sequence logos.") 628 629 server_grp.add_option( "", "--port", 630 dest="port", 631 action="store", 632 type="int", 633 default= 8080, 634 help="Listen to this local port. (Default: %default)", 635 metavar="PORT") 636 637 return parser
638 639 # END _build_option_parser 640 641 642 ############################################################## 643