7
Circos::Rule - routines for handling rules in Circos
11
This module is not meant to be used directly.
15
Circos is an application for the generation of publication-quality,
16
circularly composited renditions of genomic data and related
19
Circos is particularly suited for visualizing alignments, conservation
20
and intra and inter-chromosomal relationships. However, Circos can be
21
used to plot any kind of 2D data in a circular layout - its use is not
22
limited to genomics. Circos' use of lines to relate position pairs
23
(ribbons add a thickness parameter to each end) is effective to
24
display relationships between objects or positions on one or more
27
All documentation is in the form of tutorials at L<http://www.circos.ca>.
31
# -------------------------------------------------------------------
39
use Carp qw( carp confess croak );
43
use Params::Validate qw(:all);
45
use lib "$FindBin::RealBin";
46
use lib "$FindBin::RealBin/../lib";
47
use lib "$FindBin::RealBin/lib";
49
use Circos::Configuration; # qw(%CONF $DIMS);
50
use Circos::Constants;
53
use Circos::Expression;
63
my $conf_leaf = shift;
64
my @rules = make_list( $conf_leaf );
65
# first, grep out rules that have an importance value
66
my @rules_ordered = sort { $b->{importance} <=> $a->{importance} } grep(defined $_->{importance}, @rules);
67
# then add all remaining rules without importance
68
push @rules_ordered, grep(! defined $_->{importance}, @rules);
69
@rules = @rules_ordered;
71
# - condition must exist
72
# - assign tag automatically, if does not exist
73
# - create a list of parameters that are being readjusted
74
for my $i (0..@rules-1) {
75
my $rule = $rules[$i];
76
if(! defined $rule->{condition} && ! defined $rule->{flow}) {
77
$Data::Dumper::Sortkeys = 1;
78
$Data::Dumper::Terse = 1;
79
fatal_error("rule","no_condition_no_flow",Dumper($rule));
81
if(! defined $rule->{tag}) {
83
printdebug_group("rule","assigning auto rule tag [$tag]");
86
$rule->{__param} ||= {};
87
for my $key (keys %$rule) {
88
next if grep($key eq $_, qw(condition importance tag flow __param));
89
$rule->{__param}{$key}++;
95
sub apply_rules_to_track {
96
my ($track, $rules, $param_path) = @_;
101
for my $point ( @{ $track->{__data} } ) {
103
for my $rule ( @$rules ) {
104
if(defined $goto_rule_tag) {
105
if($rule->{tag} ne $goto_rule_tag) {
106
printdebug_group("rule","going to rule [$goto_rule_tag] and skipping rule [$rule->{tag}]");
109
printdebug_group("rule","found rule [$goto_rule_tag]");
110
$goto_rule_tag = undef;
114
my $condition = $rule->{condition};
115
my @flows = make_list(seek_parameter( "flow", $rule, $track->{rules} ));
116
my $pass = test_rule( $point, $condition, [ $point, @$param_path ] ) if defined $condition;
118
apply_rule_to_point($point,$rule,$param_path) if $pass;
119
# if flow is not defined
123
printdebug_group("rule","quitting rule chain");
126
printdebug_group("rule","trying next rule");
130
for my $flow (@flows) {
131
my @flow_tok = split(" ",$flow);
132
# if the flow string ends with "if true" or "if false" register
133
# whether the flow command should be executed based on whether
134
# the rule has passed
135
printdebug_group("rule","parsing flow",$flow);
137
if($flow =~ /\s+if\s+/) {
138
if($flow =~ /\s+true\s*$/) {
139
$toggle_flow = $pass ? 1 : 0;
140
} elsif ($flow =~ /\s+false\s*$/) {
141
$toggle_flow = !$pass ? 1 : 0;
143
fatal_error("rules","flow_syntax_error",$flow);
146
# by default the flow will trigger
149
printdebug_group("rule","rule pass",$pass,"flow",$toggle_flow);
151
if($flow =~ /^stop/) {
155
} elsif ($flow =~ /^goto/) {
156
my (undef,$tag,$if,$ifcond) = @flow_tok;
158
$goto_rule_tag = $tag;
159
printdebug_group("rule","goto to rule [$tag]");
162
} elsif ($flow =~ /^restart/) {
164
if(!$rule->{restart}) {
165
$rule->{restart} = 1;
167
printdebug_group("rule","restarting rule chain");
170
printdebug_group("rule","cannot restart from rule more than once - quitting rule chain");
174
} elsif ($flow =~ /^continue/) {
176
printdebug_group("rule","continuing to next rule");
180
fatal_error("rules","flow_syntax_error",$flow,$rule->{tag});
186
if(defined $goto_rule_tag) {
187
fatal_error("rule","bad_tag",$goto_rule_tag);
189
# clear restart flags
190
if($have_restarted) {
191
map { delete $_->{restart} } @$rules;
196
sub apply_rule_to_point {
197
my ($point,$rule,$param_path) = @_;
198
for my $param ( keys %{ $rule->{__param} } ) {
199
my $value = $rule->{$param};
200
printdebug_group("rule","applying rule var",$param,"value",$value);
201
if ( $value =~ /^eval\(\s*(.*)\s*\)\s*$/ ) {
203
$value = Circos::Expression::eval_expression( $point, $expr, [ $point, @$param_path ] );
206
if ( $param eq "value" || $param eq "start" || $param eq "end" ) {
207
if($value eq "undef") {
208
delete $point->{data}[0]{ $param };
210
$point->{data}[0]{ $param } = $value;
213
if ( not_defined_or_one( $rule->{overwrite} ) ) {
214
# overwrite is default
215
if($value eq "undef") {
216
delete $point->{param}{ $param };
218
$point->{param}{ $param } = $value;
220
} elsif ( ! exists $point->{param}{$param} ) {
221
# overwrite only if parameter doesn't exist
222
if($value ne "undef") {
223
$point->{param}{$param} = $value;
230
# -------------------------------------------------------------------
232
my ( $point, $condition, $param_path ) = @_;
233
for my $c (make_list($condition)) {
234
my $cfmt = Circos::Expression::format_condition($c);
235
my $pass = Circos::Expression::eval_expression($point,$cfmt,$param_path);
236
printdebug_group("rule","condition [$condition] pass",$pass ? "PASS" : "FAIL");