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 |