weblogolib._cli

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          def is_cgi(self) :
    100              if self.path == "/create.cgi":
    101                  self.cgi_info = '', 'create.cgi'
    102                  return True
    103              return False
    104
    105      # Add current directory to PYTHONPATH. This is
    106      # so that we can run the standalone server
    107      # without having to run the install script.
    108      pythonpath = os.getenv("PYTHONPATH", '')
    109      pythonpath += ":" + os.path.abspath(sys.path[0]).split()[0]
    110      os.environ["PYTHONPATH"] = pythonpath
    111
    112      htdocs = resource_filename(__name__, 'htdocs', __file__)
    113      os.chdir(htdocs)
    114
    115      HandlerClass = __HTTPRequestHandler
    116      ServerClass = BaseHTTPServer.HTTPServer
    117      httpd = ServerClass(('', port), HandlerClass)
    118      print "WebLogo server running at http://localhost:%d/" % port
    119
    120      try :
    121          httpd.serve_forever()
    122      except KeyboardInterrupt:
    123          sys.exit(0)
    124  # end httpd_serve_forever()
    125
    126
    127
    128 -def _build_logodata(options) :
    129
    130      if options.input_parser != "transfac":
    131          seqs = read_seq_data(options.fin,
    132              options.input_parser.read,
    133              alphabet=options.alphabet,
    134              ignore_lower_case = options.ignore_lower_case)
    135
    136          if options.reverse:
    137              seqs = SeqList([s.reverse() for s in seqs], seqs.alphabet)
    138
    139          if options.complement :
    140              seqs= SeqList( [Seq(s,seqs.alphabet).complement() for s in seqs], seqs.alphabet)
    141
    142
    143
    144          prior = parse_prior( options.composition,seqs.alphabet, options.weight)
    145          data = LogoData.from_seqs(seqs, prior)
    146
    147      else :
    148          from corebio.matrix import Motif
    149
    150          if options.ignore_lower_case:
    151              raise ValueError("error: option --ignore-lower-case incompatible with matrix input")
    152
    153          #FIXME : implement
    154          if options.reverse:
    155              raise ValueError("error: option --reverse incompatible with matrix input")
    156
    157          #FIXME : implement
    158          if options.complement:
    159              raise ValueError("error: option --complement incompatible with matrix input")
    160
    161          motif = Motif.read_transfac(options.fin, alphabet=options.alphabet)
    162          prior = parse_prior( options.composition,motif.alphabet, options.weight)
    163          data = LogoData.from_counts(motif.alphabet, motif, prior)
    164
    165      return data
    166
    167
    168 -def _build_logoformat( logodata, opts) :
    169      """ Extract and process relevant option values and return a
    170      LogoFormat object."""
    171
    172      args = {}
    173      direct_from_opts = [
    174          "stacks_per_line",
    175          "logo_title",
    176          "yaxis_label",
    177          "show_xaxis",
    178          "show_yaxis",
    179          "xaxis_label",
    180          "show_ends",
    181          "fineprint",
    182          "show_errorbars",
    183          "show_boxes",
    184          "yaxis_tic_interval",
    185          "resolution",
    186          "alphabet",
    187          "debug",
    188          "show_ends",
    189          "default_color",
    190          #"show_color_key",
    191          "color_scheme",
    192          "unit_name",
    193          "logo_label",
    194          "yaxis_scale",
    195          "first_index",
    196          "logo_start",
    197          "logo_end",
    198          "scale_width",
    199          "annotate",
    200          "stack_width",
    201          "stack_aspect_ratio"
    202          ]
    203
    204      for k in direct_from_opts:
    205          args[k] = opts.__dict__[k]
    206
    207  #    logo_size = copy.copy(opts.__dict__['logo_size'])
    208  #    size_from_opts = ["stack_width", "stack_height"]
    209  #    for k in size_from_opts :
    210  #        length = getattr(opts, k)
    211  #        if length : setattr( logo_size, k, length )
    212  #   args["size"] = logo_size
    213
    214
    215      if opts.colors:
    216          color_scheme = ColorScheme()
    217          for color, symbols, desc in opts.colors:
    218              try :
    219                  #c = Color.from_string(color)
    220                  color_scheme.groups.append( ColorGroup(symbols, color, desc)  )
    221              except ValueError :
    222                  raise ValueError(
    223                       "error: option --color: invalid value: '%s'" % color )
    224
    225          args["color_scheme"] = color_scheme
    226
    227
    228      if opts.annotate:
    229          args["annotate"] = opts.annotate.split(',')
    230
    231
    232      logooptions = LogoOptions()
    233      for a, v in args.iteritems() :
    234          setattr(logooptions,a,v)
    235
    236
    237      theformat =  LogoFormat(logodata, logooptions )
    238      return theformat
    239
    240
    241
    242
    243
    244
    245  # ========================== OPTIONS ==========================
    246 -def _build_option_parser() :
    247      defaults = LogoOptions()
    248      parser = DeOptionParser(usage="%prog [options]  < sequence_data.fa > sequence_logo.eps",
    249          description = description,
    250          version     = release_description,
    251          add_verbose_options = False
    252          )
    253
    254      io_grp = OptionGroup(parser, "Input/Output Options",)
    255      data_grp = OptionGroup(parser, "Logo Data Options",)
    256      trans_grp = OptionGroup(parser, "Transformations", "Optional transformations of the sequence data.")
    257
    258
    259      format_grp = OptionGroup(parser, "Logo Format Options",
    260          "These options control the format and display of the logo.")
    261      color_grp = OptionGroup(parser, "Color Options",
    262          "Colors can be specified using CSS2 syntax. e.g. 'red', '#FF0000', etc.")
    263      advanced_grp = OptionGroup(parser, "Advanced Format Options",
    264          "These options provide fine control over the display of the logo. ")
    265      server_grp = OptionGroup(parser, "WebLogo Server",
    266          "Run a standalone webserver on a local port.")
    267
    268
    269      parser.add_option_group(io_grp)
    270      parser.add_option_group(data_grp)
    271      parser.add_option_group(trans_grp)
    272      parser.add_option_group(format_grp)
    273      parser.add_option_group(color_grp)
    274      parser.add_option_group(advanced_grp)
    275      parser.add_option_group(server_grp)
    276
    277      # ========================== IO OPTIONS ==========================
    278
    279      io_grp.add_option( "-f", "--fin",
    280          dest="fin",
    281          action="store",
    282          type="file_in",
    283          default=sys.stdin,
    284          help="Sequence input file (default: stdin)",
    285          metavar="FILENAME")
    286
    287      # Add position weight matrix formats to input parsers by hand
    288      fin_choices = dict(seq_io.format_names())
    289      fin_choices['transfac'] = 'transfac'
    290
    291      io_grp.add_option("-D", "--datatype",
    292          dest="input_parser",
    293          action="store", type ="dict",
    294          default = seq_io,
    295          choices = fin_choices,       # seq_io.format_names(),
    296          help="Type of multiple sequence alignment or position weight matrix file: (%s, transfac)" %
    297             ', '.join([ f.names[0] for f in seq_io.formats]),
    298          metavar="FORMAT")
    299
    300      io_grp.add_option("-o", "--fout", dest="fout",
    301          type="file_out",
    302          default=sys.stdout,
    303          help="Output file (default: stdout)",
    304          metavar="FILENAME")
    305
    306      io_grp.add_option( "-F", "--format",
    307          dest="formatter",
    308          action="store",
    309          type="dict",
    310          choices = formatters,
    311          metavar= "FORMAT",
    312          help="Format of output: eps (default), png, png_print, pdf, jpeg, svg, logodata",
    313          default = default_formatter)
    314
    315
    316      # ========================== Data OPTIONS ==========================
    317
    318
    319
    320      data_grp.add_option( "-A", "--sequence-type",
    321          dest="alphabet",
    322          action="store",
    323          type="dict",
    324          choices = std_alphabets,
    325          help="The type of sequence data: 'protein', 'rna' or 'dna'.",
    326          metavar="TYPE")
    327
    328      data_grp.add_option( "-a", "--alphabet",
    329          dest="alphabet",
    330          action="store",
    331          help="The set of symbols to count, e.g. 'AGTC'. "
    332               "All characters not in the alphabet are ignored. "
    333               "If neither the alphabet nor sequence-type are specified then weblogo will examine the input data and make an educated guess. "
    334               "See also --sequence-type, --ignore-lower-case" )
    335
    336
    337      data_grp.add_option( "-U", "--units",
    338          dest="unit_name",
    339          action="store",
    340          choices = std_units.keys(),
    341          type="choice",
    342          default = defaults.unit_name,
    343          help="A unit of entropy ('bits' (default), 'nats', 'digits'), or a unit of free energy ('kT', 'kJ/mol', 'kcal/mol'), or 'probability' for probabilities",
    344          metavar = "NUMBER")
    345
    346
    347      data_grp.add_option( "", "--composition",
    348          dest="composition",
    349          action="store",
    350          type="string",
    351          default = "auto",
    352          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. ",
    353          metavar="COMP.")
    354
    355      data_grp.add_option( "", "--weight",
    356          dest="weight",
    357          action="store",
    358          type="float",
    359          default = None,
    360          help="The weight of prior data.  Default: total pseudocounts equal to the number of monomer types.",
    361          metavar="NUMBER")
    362
    363      data_grp.add_option( "-i", "--first-index",
    364          dest="first_index",
    365          action="store",
    366          type="int",
    367          default = 1,
    368          help="Index of first position in sequence data (default: 1)",
    369          metavar="INDEX")
    370
    371      data_grp.add_option( "-l", "--lower",
    372          dest="logo_start",
    373          action="store",
    374          type="int",
    375          help="Lower bound of sequence to display",
    376          metavar="INDEX")
    377
    378      data_grp.add_option( "-u", "--upper",
    379          dest="logo_end",
    380          action="store",
    381          type="int",
    382          help="Upper bound of sequence to display",
    383          metavar="INDEX")
    384
    385      # ========================== Transformation OPTIONS ==========================
    386
    387
    388      # FIXME Add test?
    389      trans_grp.add_option( "", "--ignore-lower-case",
    390          dest="ignore_lower_case",
    391          action="store_true",
    392          default=False,
    393          help="Disregard lower case letters and only count upper case letters in sequences."
    394         )
    395
    396      trans_grp.add_option( "", "--reverse",
    397          dest="reverse",
    398          action="store_true",
    399          default=False,
    400          help="reverse sequences",
    401          )
    402
    403      trans_grp.add_option( "", "--complement",
    404          dest="complement",
    405          action="store_true",
    406          default=False,
    407          help="complement DNA sequences",
    408          )
    409
    410
    411
    412      # ========================== FORMAT OPTIONS ==========================
    413
    414      format_grp.add_option( "-s", "--size",
    415          dest="stack_width",
    416          action="store",
    417          type ="dict",
    418          choices = std_sizes,
    419          metavar = "LOGOSIZE",
    420          default = defaults.stack_width,
    421          help="Specify a standard logo size (small, medium (default), large)" )
    422
    423      format_grp.add_option( "-n", "--stacks-per-line",
    424          dest="stacks_per_line",
    425          action="store",
    426          type="int",
    427          help="Maximum number of logo stacks per logo line. (default: %default)",
    428          default = defaults.stacks_per_line,
    429          metavar="COUNT")
    430
    431      format_grp.add_option( "-t", "--title",
    432          dest="logo_title",
    433          action="store",
    434          type="string",
    435          help="Logo title text.",
    436          default = defaults.logo_title,
    437          metavar="TEXT")
    438
    439      format_grp.add_option( "", "--label",
    440          dest="logo_label",
    441          action="store",
    442          type="string",
    443          help="A figure label, e.g. '2a'",
    444          default = defaults.logo_label,
    445          metavar="TEXT")
    446
    447      format_grp.add_option( "-X", "--show-xaxis",
    448          action="store",
    449          type = "boolean",
    450          default= defaults.show_xaxis,
    451          metavar = "YES/NO",
    452          help="Display sequence numbers along x-axis? (default: %default)")
    453
    454      format_grp.add_option( "-x", "--xlabel",
    455          dest="xaxis_label",
    456          action="store",
    457          type="string",
    458          default = defaults.xaxis_label,
    459          help="X-axis label",
    460          metavar="TEXT")
    461
    462      format_grp.add_option( "", "--annotate",
    463              dest="annotate",
    464              action="store",
    465              type="string",
    466              default = None,
    467              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.",
    468              metavar="TEXT")
    469
    470      format_grp.add_option( "-S", "--yaxis",
    471          dest="yaxis_scale",
    472          action="store",
    473          type="float",
    474          help="Height of yaxis in units. (Default: Maximum value with uninformative prior.)",
    475          metavar = "UNIT")
    476
    477      format_grp.add_option( "-Y", "--show-yaxis",
    478          action="store",
    479          type = "boolean",
    480          dest = "show_yaxis",
    481          default= defaults.show_yaxis,
    482          metavar = "YES/NO",
    483          help="Display entropy scale along y-axis? (default: %default)")
    484
    485      format_grp.add_option( "-y", "--ylabel",
    486          dest="yaxis_label",
    487          action="store",
    488          type="string",
    489          help="Y-axis label (default depends on plot type and units)",
    490          metavar="TEXT")
    491
    492      format_grp.add_option( "-E", "--show-ends",
    493          action="store",
    494          type = "boolean",
    495          default= defaults.show_ends,
    496          metavar = "YES/NO",
    497          help="Label the ends of the sequence? (default: %default)")
    498
    499      format_grp.add_option( "-P", "--fineprint",
    500          dest="fineprint",
    501          action="store",
    502          type="string",
    503          default= defaults.fineprint,
    504          help="The fine print (default: weblogo version)",
    505          metavar="TEXT")
    506
    507      format_grp.add_option( "", "--ticmarks",
    508          dest="yaxis_tic_interval",
    509          action="store",
    510          type="float",
    511          default= defaults.yaxis_tic_interval,
    512          help="Distance between ticmarks (default: %default)",
    513          metavar = "NUMBER")
    514
    515
    516      format_grp.add_option( "", "--errorbars",
    517          dest = "show_errorbars",
    518          action="store",
    519          type = "boolean",
    520          default= defaults.show_errorbars,
    521          metavar = "YES/NO",
    522          help="Display error bars? (default: %default)")
    523
    524
    525
    526      # ========================== Color OPTIONS ==========================
    527      # TODO: Future Feature
    528      # color_grp.add_option( "-K", "--color-key",
    529      #    dest= "show_color_key",
    530      #    action="store",
    531      #    type = "boolean",
    532      #    default= defaults.show_color_key,
    533      #    metavar = "YES/NO",
    534      #    help="Display a color key (default: %default)")
    535
    536
    537      color_scheme_choices = std_color_schemes.keys()
    538      color_scheme_choices.sort()
    539      color_grp.add_option( "-c", "--color-scheme",
    540          dest="color_scheme",
    541          action="store",
    542          type ="dict",
    543          choices = std_color_schemes,
    544          metavar = "SCHEME",
    545          default = None, # Auto
    546          help="Specify a standard color scheme (%s)" % \
    547              ", ".join(color_scheme_choices) )
    548
    549      color_grp.add_option( "-C", "--color",
    550          dest="colors",
    551          action="append",
    552          metavar="COLOR SYMBOLS DESCRIPTION ",
    553          nargs = 3,
    554          default=[],
    555          help="Specify symbol colors, e.g. --color black AG 'Purine' --color red TC 'Pyrimidine' ")
    556
    557      color_grp.add_option( "", "--default-color",
    558          dest="default_color",
    559          action="store",
    560          metavar="COLOR",
    561          default= defaults.default_color,
    562          help="Symbol color if not otherwise specified.")
    563
    564
    565      # ========================== Advanced options =========================
    566
    567      advanced_grp.add_option( "-W", "--stack-width",
    568          dest="stack_width",
    569          action="store",
    570          type="float",
    571          default= defaults.stack_width,
    572          help="Width of a logo stack (default: %s)"% defaults.stack_width,
    573          metavar="POINTS" )
    574
    575      advanced_grp.add_option( "", "--aspect-ratio",
    576          dest="stack_aspect_ratio",
    577          action="store",
    578          type="float",
    579          default= defaults.stack_aspect_ratio ,
    580          help="Ratio of stack height to width (default: %s)"%defaults.stack_aspect_ratio,
    581          metavar="POINTS" )
    582
    583      advanced_grp.add_option( "", "--box",
    584          dest="show_boxes",
    585          action="store",
    586          type = "boolean",
    587          default=False,
    588          metavar = "YES/NO",
    589          help="Draw boxes around symbols? (default: no)")
    590
    591      advanced_grp.add_option( "", "--resolution",
    592          dest="resolution",
    593          action="store",
    594          type="float",
    595          default=96,
    596          help="Bitmap resolution in dots per inch (DPI).  (Default: 96 DPI, except png_print, 600 DPI) Low resolution bitmaps (DPI<300) are antialiased.",
    597          metavar="DPI")
    598
    599      advanced_grp.add_option( "", "--scale-width",
    600          dest="scale_width",
    601          action="store",
    602          type = "boolean",
    603          default= True,
    604          metavar = "YES/NO",
    605          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)")
    606
    607      advanced_grp.add_option( "", "--debug",
    608          action="store",
    609          type = "boolean",
    610          default= defaults.debug,
    611          metavar = "YES/NO",
    612          help="Output additional diagnostic information. (Default: %default)")
    613
    614
    615      # ========================== Server options =========================
    616      server_grp.add_option( "", "--serve",
    617          dest="serve",
    618          action="store_true",
    619          default= False,
    620          help="Start a standalone WebLogo server for creating sequence logos.")
    621
    622      server_grp.add_option( "", "--port",
    623          dest="port",
    624          action="store",
    625          type="int",
    626          default= 8080,
    627          help="Listen to this local port. (Default: %default)",
    628          metavar="PORT")
    629
    630      return parser
    631
    632      # END _build_option_parser
    633
    634
    635  ##############################################################
    636