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          # 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