| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Bio::Das::Stylesheet; |
|
2
|
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
5
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
32
|
|
|
4
|
|
|
|
|
|
|
|
|
5
|
1
|
|
|
1
|
|
6
|
use Carp 'croak'; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
47
|
|
|
6
|
1
|
|
|
1
|
|
1198
|
use Memoize; |
|
|
1
|
|
|
|
|
2621
|
|
|
|
1
|
|
|
|
|
48
|
|
|
7
|
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
8
|
use vars qw($VERSION); |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
977
|
|
|
9
|
|
|
|
|
|
|
$VERSION = '1.00'; |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
memoize('_glyph'); |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
# |
|
15
|
|
|
|
|
|
|
# Bio::Das::Stylesheet->new(); |
|
16
|
|
|
|
|
|
|
# |
|
17
|
|
|
|
|
|
|
sub new { |
|
18
|
1
|
|
|
1
|
0
|
4
|
my $class = shift; |
|
19
|
1
|
50
|
|
|
|
4
|
$class = ref($class) if ref($class); |
|
20
|
|
|
|
|
|
|
|
|
21
|
1
|
|
|
|
|
8
|
return bless { categories => {}, |
|
22
|
|
|
|
|
|
|
lowzoom => 500_000, |
|
23
|
|
|
|
|
|
|
highzoom => 200, |
|
24
|
|
|
|
|
|
|
},$class; |
|
25
|
|
|
|
|
|
|
} |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
sub categories { |
|
28
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
29
|
0
|
|
|
|
|
0
|
keys %{$self->{categories}}; |
|
|
0
|
|
|
|
|
0
|
|
|
30
|
|
|
|
|
|
|
} |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
# in a scalar context, return name of glyph |
|
33
|
|
|
|
|
|
|
# in array context, return name of glyph followed by attribute/value pairs |
|
34
|
|
|
|
|
|
|
sub glyph { |
|
35
|
1
|
|
|
1
|
1
|
639
|
my $self = shift; |
|
36
|
1
|
|
|
|
|
3
|
my $feature = shift; |
|
37
|
1
|
|
50
|
|
|
7
|
my $length = shift || 0; |
|
38
|
|
|
|
|
|
|
|
|
39
|
1
|
|
|
|
|
7
|
local $^W = 0; |
|
40
|
|
|
|
|
|
|
|
|
41
|
1
|
50
|
|
|
|
8
|
unless ($length =~ /^\d+$/) { |
|
42
|
0
|
0
|
|
|
|
0
|
$length = $length eq 'low' ? $self->lowzoom : $self->highzoom; |
|
43
|
|
|
|
|
|
|
} |
|
44
|
|
|
|
|
|
|
|
|
45
|
1
|
50
|
|
|
|
7
|
$feature = $feature->[0] |
|
46
|
|
|
|
|
|
|
if ref($feature) eq 'ARRAY'; # hack to prevent common error |
|
47
|
|
|
|
|
|
|
|
|
48
|
1
|
|
|
|
|
2
|
my ($category,$type); |
|
49
|
1
|
50
|
|
|
|
5
|
if (ref $feature) { |
|
50
|
1
|
|
|
|
|
2
|
$category = eval {lc $feature->category}; |
|
|
1
|
|
|
|
|
7
|
|
|
51
|
1
|
|
|
|
|
4
|
$type = eval {lc $feature->type}; |
|
|
1
|
|
|
|
|
3
|
|
|
52
|
|
|
|
|
|
|
} else { |
|
53
|
0
|
|
|
|
|
0
|
$type = $feature; |
|
54
|
|
|
|
|
|
|
} |
|
55
|
|
|
|
|
|
|
|
|
56
|
1
|
|
|
|
|
43
|
return $self->_glyph($category,$type,$length); |
|
57
|
|
|
|
|
|
|
} |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub _glyph { |
|
60
|
|
|
|
|
|
|
my $self = shift; |
|
61
|
|
|
|
|
|
|
my ($category,$type,$length) = @_; |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
$category = 'default' unless $self->{categories}{$category}; |
|
64
|
|
|
|
|
|
|
$type ||= 'default'; |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
(my $base = $type) =~ s/:.+$//; |
|
67
|
|
|
|
|
|
|
my $zoom = $self->{categories}{$category}{$type}; |
|
68
|
|
|
|
|
|
|
$zoom ||= $self->{categories}{$category}{$base}; |
|
69
|
|
|
|
|
|
|
$zoom ||= $self->{categories}{'default'}{$type}; |
|
70
|
|
|
|
|
|
|
$zoom ||= $self->{categories}{'default'}{$base}; |
|
71
|
|
|
|
|
|
|
$zoom ||= $self->{categories}{'default'}{'default'}; |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
my $glyph; |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
# find the best zoom level -- this is a Schwartzian Transform |
|
76
|
|
|
|
|
|
|
my @zoomlevels = map {$_->[0]} |
|
77
|
|
|
|
|
|
|
sort {$b->[1]<=>$a->[1]} |
|
78
|
|
|
|
|
|
|
grep {!$length or $_->[1] <= $length} |
|
79
|
|
|
|
|
|
|
map { $_ eq 'low' ? [$_ => $self->lowzoom] |
|
80
|
|
|
|
|
|
|
: $_ eq 'high' ? [$_ => $self->highzoom] |
|
81
|
|
|
|
|
|
|
: [$_ => $_ || 0] } keys %$zoom; |
|
82
|
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
my ($base_glyph,@base_attributes) = _format_glyph($zoom->{$zoomlevels[-1]}); |
|
85
|
|
|
|
|
|
|
my ($zoom_glyph,@zoom_attributes) = _format_glyph($zoom->{$zoomlevels[0]}) if $length; |
|
86
|
|
|
|
|
|
|
my %attributes = (@base_attributes,@zoom_attributes); |
|
87
|
|
|
|
|
|
|
$glyph = $zoom_glyph || $base_glyph; |
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
# MUNGES!!! |
|
91
|
|
|
|
|
|
|
if ($glyph eq 'anchored_arrow') { # because the default looks ugly |
|
92
|
|
|
|
|
|
|
$glyph = 'box'; |
|
93
|
|
|
|
|
|
|
push @base_attributes,(-stranded=>1, |
|
94
|
|
|
|
|
|
|
-arrowhead=>'filled'); |
|
95
|
|
|
|
|
|
|
} |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
if ($glyph eq 'line') { |
|
98
|
|
|
|
|
|
|
my $line_type = $attributes{line_style} || $attributes{style}; |
|
99
|
|
|
|
|
|
|
$glyph = 'hat' if $line_type eq 'hat'; |
|
100
|
|
|
|
|
|
|
$glyph = 'dashed_line' if $line_type eq 'dashed'; |
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
# warn "stylesheet for $feature returning $glyph ",join ' ',%attributes; |
|
105
|
|
|
|
|
|
|
# warn "category=$category, type=$type, glyph=$glyph"; |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
return wantarray ? ($glyph,%attributes) : $glyph; |
|
108
|
|
|
|
|
|
|
} |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
# turn configuration into a set of -name=>value pairs suitable for add_track() |
|
111
|
|
|
|
|
|
|
sub style { |
|
112
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
|
113
|
0
|
|
|
|
|
0
|
my ($glyph,%attributes) = $self->glyph(@_); |
|
114
|
0
|
|
|
|
|
0
|
return ($glyph,map {("-$_" => $attributes{$_})} keys %attributes); |
|
|
0
|
|
|
|
|
0
|
|
|
115
|
|
|
|
|
|
|
} |
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
# warning: not a method |
|
118
|
|
|
|
|
|
|
sub _format_glyph { |
|
119
|
1
|
|
|
1
|
|
1
|
my $glyph = shift; |
|
120
|
1
|
50
|
|
|
|
4
|
return unless $glyph; |
|
121
|
1
|
|
|
|
|
2
|
my $name = $glyph->{name}; |
|
122
|
1
|
50
|
|
|
|
4
|
return $name unless wantarray; |
|
123
|
1
|
|
|
|
|
2
|
return ($name,%{$glyph->{attr}}); |
|
|
1
|
|
|
|
|
6
|
|
|
124
|
|
|
|
|
|
|
} |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
sub add_type { |
|
127
|
1292
|
|
|
1292
|
0
|
1508
|
my $self = shift; |
|
128
|
1292
|
|
|
|
|
2069
|
my ($category,$type,$zoom,$glyph_name,$attributes) = @_; |
|
129
|
1292
|
|
50
|
|
|
4148
|
$zoom ||= 0; |
|
130
|
1292
|
|
|
|
|
8030
|
$self->{categories}{lc $category}{lc $type}{lc $zoom} = { name => $glyph_name, # a string |
|
131
|
|
|
|
|
|
|
attr => $attributes, # a hashref |
|
132
|
|
|
|
|
|
|
}; |
|
133
|
1292
|
|
|
|
|
5086
|
$self->{categories}{'default'}{lc $type}{lc $zoom} = $self->{categories}{lc $category}{lc $type}{lc $zoom}; |
|
134
|
|
|
|
|
|
|
# this works around the bug of gff types with no category |
|
135
|
1292
|
|
|
|
|
5090
|
$self->{categories}{''}{lc $type} = $self->{categories}{lc $category}{lc $type}; |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub lowzoom { |
|
139
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
140
|
0
|
|
|
|
|
|
my $d = $self->{lowzoom}; |
|
141
|
0
|
0
|
|
|
|
|
$self->{lowzoom} = shift if @_; |
|
142
|
0
|
|
|
|
|
|
$d; |
|
143
|
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
sub highzoom { |
|
146
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
147
|
0
|
|
|
|
|
|
my $d = $self->{highzoom}; |
|
148
|
0
|
0
|
|
|
|
|
$self->{highzoom} = shift if @_; |
|
149
|
0
|
|
|
|
|
|
$d; |
|
150
|
|
|
|
|
|
|
} |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
1; |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
__END__ |
|
155
|
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=head1 NAME |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
Bio::Das::Stylesheet - Access to DAS stylesheets |
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
161
|
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
use Bio::Das; |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# contact the DAS server at wormbase.org (0.18 version API) |
|
165
|
|
|
|
|
|
|
my $das = Bio::Das->new('http://www.wormbase.org/db/das'=>'elegans'); |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
# get the stylesheet |
|
168
|
|
|
|
|
|
|
my $style = $das->stylesheet; |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
# get features |
|
171
|
|
|
|
|
|
|
my @features = $das->segment(-ref=>'Locus:unc-9')->features; |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# for each feature, ask the stylesheet what glyph to use |
|
174
|
|
|
|
|
|
|
for my $f (@features) { |
|
175
|
|
|
|
|
|
|
my ($glyph_name,@attributes) = $style->glyph($f); |
|
176
|
|
|
|
|
|
|
} |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
The Bio::Das::Stylesheet class contains information about a remote DAS |
|
182
|
|
|
|
|
|
|
server's preferred visualization style for sequence features. Each |
|
183
|
|
|
|
|
|
|
server has zero or one stylesheets for each of the data sources it is |
|
184
|
|
|
|
|
|
|
responsible for. Stylesheets can provide stylistic guidelines for |
|
185
|
|
|
|
|
|
|
broad feature categories (such as "transcription"), or strict |
|
186
|
|
|
|
|
|
|
guidelines for particular feature types (such as "Prosite motif"). |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
The glyph names and attributes are broadly compatible with the |
|
189
|
|
|
|
|
|
|
Bio::Graphics library. |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=head2 OBJECT CREATION |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
Bio::Das::Stylesheets are created by the Bio::Das object in response |
|
194
|
|
|
|
|
|
|
to a call to the stylesheet() method. The Bio::Das object must |
|
195
|
|
|
|
|
|
|
previously have been associated with a data source. |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
=head2 METHODS |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
=over 4 |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
=item ($glyph,@attributes) = $stylesheet->glyph($feature) |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
The glyph() method takes a Bio::Das::Segment::Feature object and |
|
204
|
|
|
|
|
|
|
returns the name of a suggested glyph to use, plus zero or more |
|
205
|
|
|
|
|
|
|
attributes to apply to the glyph. Glyphs names are described in the |
|
206
|
|
|
|
|
|
|
DAS specification, and include terms like "box" and "arrow". |
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
Attributes are name/value pairs, for instance: |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
(-width => '10', -outlinecolor => 'black') |
|
211
|
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
The initial "-" is added to the attribute names to be consistent with |
|
213
|
|
|
|
|
|
|
the Perl name/value calling style. The attribute list can be passed |
|
214
|
|
|
|
|
|
|
directly to the Ace::Panel->add_track() method. |
|
215
|
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
In a scalar context, glyph() will return just the name of the glyph |
|
217
|
|
|
|
|
|
|
without the attribute list. |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
=item @categories = $stylesheet->categories |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
Return a list of all the categories known to the stylesheet. |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=item $source = $stylesheet->source |
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
Return the Bio::Das object associated with the stylesheet. |
|
226
|
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
=head2 HOW GLYPH() RESOLVES FEATURES |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
When a feature is passed to glyph(), the method checks the feature's |
|
230
|
|
|
|
|
|
|
type ID and category against the stylesheet. If an exact match is |
|
231
|
|
|
|
|
|
|
found, then the method returns the corresponding glyph name and |
|
232
|
|
|
|
|
|
|
attributes. Otherwise, glyph() looks for a default style for the |
|
233
|
|
|
|
|
|
|
category and returns the glyph and attributes for that. If no |
|
234
|
|
|
|
|
|
|
category default is found, then glyph() returns its global default. |
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
=head2 USING Bio::Das::Stylesheet WITH Bio::Graphics::Panel |
|
237
|
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
The stylesheet class was designed to work hand-in-glove with |
|
239
|
|
|
|
|
|
|
Bio::Graphics::Panel. You can rely entirely on the stylesheet to |
|
240
|
|
|
|
|
|
|
provide the glyph name and attributes, or provide your own default |
|
241
|
|
|
|
|
|
|
attributes to fill in those missing from the stylesheet. |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
It is important to bear in mind that Bio::Graphics::Panel only allows |
|
244
|
|
|
|
|
|
|
a single glyph type to occupy a horizontal track. This means that you |
|
245
|
|
|
|
|
|
|
must sort the different features by type, determine the suggested |
|
246
|
|
|
|
|
|
|
glyph for each type, and then create the tracks. |
|
247
|
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
The following code fragment illustrates the idiom. After sorting the |
|
249
|
|
|
|
|
|
|
features by type, we pass the first instance of each type to glyph() |
|
250
|
|
|
|
|
|
|
in order to recover a glyph name and attributes applicable to the |
|
251
|
|
|
|
|
|
|
entire track. |
|
252
|
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
use Bio::Das; |
|
254
|
|
|
|
|
|
|
use Bio::Graphics::Panel; |
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
my $das = Bio::Das->new('http://www.wormbase.org/db/das'=>'elegans'); |
|
257
|
|
|
|
|
|
|
my $stylesheet = $das->stylesheet; |
|
258
|
|
|
|
|
|
|
my $segment = $das->segment(-ref=>'Locus:unc-9'); |
|
259
|
|
|
|
|
|
|
@features = $segment->features; |
|
260
|
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
my %sort; |
|
262
|
|
|
|
|
|
|
for my $f (@features) { |
|
263
|
|
|
|
|
|
|
my $type = $f->type; |
|
264
|
|
|
|
|
|
|
# sort features by their type, and push them onto anonymous |
|
265
|
|
|
|
|
|
|
# arrays in the %sort hash. |
|
266
|
|
|
|
|
|
|
push @{$sort{$type}},$f; |
|
267
|
|
|
|
|
|
|
} |
|
268
|
|
|
|
|
|
|
my $panel = Bio::Graphics::Panel->new( -segment => $segment, |
|
269
|
|
|
|
|
|
|
-width => 800 ); |
|
270
|
|
|
|
|
|
|
for my $type (keys %sort) { |
|
271
|
|
|
|
|
|
|
my $features = $sort{$type}; |
|
272
|
|
|
|
|
|
|
my ($glyph,@attributes) = $stylesheet->glyph($features->[0]); |
|
273
|
|
|
|
|
|
|
$panel->add_track($features=>$glyph,@attributes); |
|
274
|
|
|
|
|
|
|
} |
|
275
|
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
To provide your own default attributes to be used in place of those |
|
277
|
|
|
|
|
|
|
omitted by the stylesheet, just change the last line so that your |
|
278
|
|
|
|
|
|
|
own attributes follow those provided by the stylesheet: |
|
279
|
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
$panel->add_track($features=>$glyph, |
|
281
|
|
|
|
|
|
|
@attributes, |
|
282
|
|
|
|
|
|
|
-connectgroups => 1, |
|
283
|
|
|
|
|
|
|
-key => 1, |
|
284
|
|
|
|
|
|
|
-labelcolor => 'chartreuse' |
|
285
|
|
|
|
|
|
|
); |
|
286
|
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
=head1 AUTHOR |
|
288
|
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
Lincoln Stein <lstein@cshl.org>. |
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
Copyright (c) 2001 Cold Spring Harbor Laboratory |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify |
|
294
|
|
|
|
|
|
|
it under the same terms as Perl itself. See DISCLAIMER.txt for |
|
295
|
|
|
|
|
|
|
disclaimers of warranty. |
|
296
|
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
298
|
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
L<Bio::Das>, L<Bio::Graphics::Panel>, L<Bio::Graphics::Track> |
|
300
|
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
=cut |