Bio-Graphics

 view release on metacpan or  search on metacpan

lib/Bio/Graphics/FeatureFile.pm  view on Meta::CPAN

appears.

=head2 Feature Tags

Tags can be added to features by adding a fourth column consisting of
"tag=value" pairs:

 Gene  B0511.1  Chr1:516..619,3185..3294 Note="Putative primase"

Tags and their values take any form you want, and multiple tags can be
separated by semicolons. You can also repeat tags multiple times:

 Gene  B0511.1  Chr1:516..619,3185..3294 GO_Term=GO:100;GO_Term=GO:2087

Several tags have special meanings:

 Tag     Meaning
 ---     -------

 Type    The primary tag for a subfeature.
 Score   The score of a feature or subfeature.
 Phase   The phase of a feature or subfeature.
 URL     A URL to link to (via the Bio::Graphics library).
 Note    A note to attach to the feature for display by the Bio::Graphics library.

For example, in the common case of an mRNA, you can use the "Type" tag
to distinguish the parts of the mRNA into UTR and CDS:

 mRNA B0511.1 Chr1:1..100 Type=UTR
 mRNA B0511.1 Chr1:101..200,300..400,500..800 Type=CDS
 mRNA B0511.1 Chr1:801..1000 Type=UTR

The top level feature's primary tag will be "mRNA", and its subparts
will have types UTR and CDS as indicated. Additional tags that are
placed in the first line of the feature will be applied to the top
level. In this example, the note "Putative primase" will be applied to
the mRNA at the top level of the feature:

 mRNA B0511.1 Chr1:1..100 Type=UTR;Note="Putative primase"
 mRNA B0511.1 Chr1:101..200,300..400,500..800 Type=CDS
 mRNA B0511.1 Chr1:801..1000 Type=UTR

=head2 Feature Groups

Features can be grouped so that they are rendered by the "group"
glyph.  To start a group, create a two-column feature entry showing
the group type and a name for the group.  Follow this with a list of
feature entries with a blank type.  For example:

 EST	yk53c10
 	yk53c10.3	15000-15500,15700-15800
 	yk53c10.5	18892-19154

This example is declaring that the ESTs named yk53c10.3 and yk53c10.5
belong to the same group named yk53c10.

=head2 Comments

Lines that begin with the # sign are treated as comments and
ignored. When a # sign appears within a line, everything to the right
of the symbol is also ignored, unless it looks like an HTML fragment or
an HTML color, e.g.:

 # this is ignored
 [Example]
 glyph   = generic   # this comment is ignored
 bgcolor = #FF0000
 link    = http://www.google.com/search?q=$name#results

Be careful, because the processing of # signs uses a regexp heuristic. To be safe, 
always put a space after the # sign to make sure it is treated as a comment.

=head2 The #include and #exec Directives

The special comment "#include 'filename'" acts like the C preprocessor
directive and will insert the comments of a named file into the
position at which it occurs. Relative paths will be treated relative
to the file in which the #include occurs. Nested #include directives
(a #include located in a file that is itself an include file) are
#allowed. You may also use one of the shell wildcard characters * and
#? to include all matching files in a directory.

The following are examples of valid #include directives:

 #include "/usr/local/share/my_directives.txt"
 #include 'my_directives.txt'
 #include chromosome3_features.gff3
 #include gff.d/*.conf
 
You can enclose the file path in single or double quotes as shown
above. If there are no spaces in the filename the quotes are optional.
The #include directive is case insensitive, allowing you to use
#INCLUDE or #Include if you prefer.

Include file processing is not very smart and will not catch all
circular #include references. You have been warned!

The special comment "#exec 'command'" will spawn a shell and
incorporate the output of the command into the configuration
file. This command will be executed quite frequently, so it is
suggested that any time-consuming processing that does not need to be
performed on the fly each time should be cached in a local file.

=cut

use strict;
use Bio::Graphics::Feature;
use Bio::DB::GFF::Util::Rearrange;
use Carp 'cluck','carp','croak';
use IO::File;
use File::Glob ':glob';
use Text::ParseWords 'shellwords';
use Bio::DB::SeqFeature::Store;
use File::Basename 'dirname';
use File::Spec;
use Cwd 'getcwd';

# default colors for unconfigured features
my @COLORS = qw(cyan blue red yellow green wheat turquoise orange);

# package variable which holds the limited set of libraries accessible

lib/Bio/Graphics/FeatureFile.pm  view on Meta::CPAN

  }

  if (/^#exec\s+(.+)/i) {  # #exec directive
      my ($command,@args) = shellwords($1);
      open (my $fh,'-|') || exec $command,@args;
      $self->parse_fh($fh);
      return 1;
  }

  return 1 if $line =~ /^\s*\#[^\#]?$/;   # comment line

  # Are we in a configuration section or a data section?
  # We start out in 'config' state, and are triggered to
  # reenter config state whenever we see a /^\[ pattern (config section)
  my $old_state = $self->{state};
  my $new_state = $self->_state_transition($line);

  if ($new_state ne $old_state) {
      delete $self->{current_config};
      delete $self->{current_tag};
  }

  if ($new_state eq 'config') {
      $self->parse_config_line($line);
  } elsif ($new_state eq 'data') {
      $self->parse_data_line($line);
  }
  $self->{state} = $new_state;
  1;
}

sub _state_transition {
    my $self = shift;
    my $line = shift;
    my $current_state = $self->{state};

    if ($current_state eq 'data') {
	return 'config' if $line =~ m/^\s*\[([^\]]+)\]/;  # start of a configuration section
    }

    elsif ($current_state eq 'config') {
	return 'data'   if $line =~ /^\#\#(\w+)/;     # GFF3 meta instruction
	return 'data'   if $line =~ /^reference\s*=/; # feature-file reference sequence directive
	
	return 'config' if $line =~ /^\s*$/;                             #empty line
	return 'config' if $line =~ m/^\[(.+)\]/;                    # section beginning
	return 'config' if $line =~ m/^[\w:\s]+=/ 
	    && $self->{current_config};                                  # configuration line
	return 'config' if $line =~ m/^\s+(.+)/
	    && $self->{current_tag};                                     # continuation section
	return 'config' if $line =~ /^\#/;                               # comment -not a meta
	return 'data';
    }
    return $current_state;
}

sub parse_config_line {
    my $self = shift;
    local $_ = shift;

    # strip right-column comments unless they look like colors or html fragments
    s/\s*\#.*$// unless /\#[0-9a-f]{6,8}\s*$/i || /\w+\#\w+/ || /\w+\"*\s*\#\d+$/;   

    if (/^\s+(.+)/ && $self->{current_tag}) { # configuration continuation line
	my $value = $1;
	my $cc = $self->{current_config} ||= 'general';       # in case no configuration named
	$self->{config}{$cc}{$self->{current_tag}} .= ' ' . $value;
	# respect newlines in code subs
	$self->{config}{$cc}{$self->{current_tag}} .= "\n"
	    if $self->{config}{$cc}{$self->{current_tag}}=~ /^sub\s*\{/;
	return 1;
    }

    elsif (/^\[(.+)\]/) {  # beginning of a configuration section
	my $label = $1;
	my $cc = $label =~ /^(general|default)$/i ? 'general' : $label;  # normalize
	push @{$self->{types}},$cc unless $cc eq 'general';
	$self->{current_config} = $cc;
	return 1;
    }

    elsif (/^([\w: -]+?)\s*=\s*(.*)/) {   # key value pair within a configuration section
	my $tag = lc $1;
	my $cc = $self->{current_config} ||= 'general';       # in case no configuration named
	my $value = defined $2 ? $2 : '';
	$self->{config}{$cc}{$tag} = $value;
	$self->{current_tag} = $tag;
	return 1;
    }


    elsif (/^$/) { # empty line
     # no longer required -- new sections are indicated by the start of a [stanza]
     # line and not by termination with a blank line
     #	undef $self->{current_tag}; 
	return 1;
    }

}

sub parse_data_line {
    my $self = shift;
    my $line = shift;
    $self->{loader} ||= $self->_make_loader($line) or return;
    $self->{loader}->load_line($line);
}

sub _make_loader {
    my $self = shift;
    local $_ = shift;
    my $db   = $self->db;

    my $type;

    # we support gff2, gff3 and featurefile formats
    if (/^\#\#gff-version\s+([23])/) {
	$type = "Bio::DB::SeqFeature::Store::GFF$1Loader";
    }
    elsif (/^reference\s*=.+/) {
	$type = "Bio::DB::SeqFeature::Store::FeatureFileLoader";
    }



( run in 0.635 second using v1.01-cache-2.11-cpan-364913b4093 )