File Coverage

blib/lib/Bio/MUST/Core/Taxonomy/ColorScheme.pm
Criterion Covered Total %
statement 39 89 43.8
branch 0 8 0.0
condition 0 5 0.0
subroutine 13 21 61.9
pod 2 4 50.0
total 54 127 42.5


line stmt bran cond sub pod time code
1             package Bio::MUST::Core::Taxonomy::ColorScheme;
2             # ABSTRACT: Helper class providing color scheme for taxonomic annotations
3             # CONTRIBUTOR: Valerian LUPO <valerian.lupo@doct.uliege.be>
4             $Bio::MUST::Core::Taxonomy::ColorScheme::VERSION = '0.212670';
5 17     17   10895 use Moose;
  17         52  
  17         127  
6 17     17   123092 use namespace::autoclean;
  17         53  
  17         164  
7              
8 17     17   1627 use Smart::Comments '###';
  17         45  
  17         213  
9              
10 17     17   55371 use autodie;
  17         55  
  17         233  
11 17     17   91111 use feature qw(say);
  17         51  
  17         1566  
12              
13 17     17   130 use Carp;
  17         45  
  17         1196  
14             # use Color::Spectrum::Multi;
15 17     17   151 use Const::Fast;
  17         50  
  17         162  
16 17     17   10695 use Graphics::ColorNames;
  17         116263  
  17         909  
17 17     17   8121 use Graphics::ColorNames::WWW;
  17         17900  
  17         702  
18 17     17   142 use List::AllUtils qw(mesh uniq each_array);
  17         55  
  17         1225  
19              
20 17     17   141 use Bio::MUST::Core::Types;
  17         42  
  17         438  
21 17     17   139 use Bio::MUST::Core::Constants qw(:files);
  17         41  
  17         3339  
22 17     17   134 use aliased 'Bio::MUST::Core::SeqId';
  17         45  
  17         135  
23             with 'Bio::MUST::Core::Roles::Commentable',
24             'Bio::MUST::Core::Roles::Taxable';
25              
26              
27             # names and colors public arrays
28             has $_ . 's' => (
29             traits => ['Array'],
30             is => 'ro',
31             isa => 'ArrayRef[Str]',
32             default => sub { [] },
33             handles => {
34             'count_' . $_ . 's' => 'count',
35             'all_' . $_ . 's' => 'elements',
36             'add_' . $_ => 'push',
37             },
38             ) for qw(name color);
39              
40              
41             # _color_for private hash for faster mapping
42             has '_color_for' => (
43             traits => ['Hash'],
44             is => 'ro',
45             isa => 'HashRef[Str]',
46             init_arg => undef,
47             lazy => 1,
48             builder => '_build_color_for',
49             handles => {
50             color_for => 'get',
51             },
52             );
53              
54              
55             # private Graphics::ColorNames object for named colors
56             has '_gcn' => (
57             is => 'ro',
58             isa => 'Graphics::ColorNames',
59             init_arg => undef,
60             lazy => 1,
61             builder => '_build_gcn',
62             handles => qr{hex|rgb}xms,
63             );
64              
65              
66             # private hash for indexed colors (e.g., gnuplot colors)
67             has '_icol_for' => (
68             traits => ['Hash'],
69             is => 'ro',
70             isa => 'HashRef[Str]',
71             init_arg => undef,
72             lazy => 1,
73             builder => '_build_icol_for',
74             handles => {
75             icol => 'get',
76             icol_for => 'get',
77             all_icols => 'elements',
78             }, # Note: should be index_for but this makes more sense
79             );
80              
81              
82             # private labeler
83             has '_labeler' => (
84             is => 'ro',
85             isa => 'Bio::MUST::Core::Taxonomy::Labeler',
86             init_arg => undef,
87             lazy => 1,
88             builder => '_build_labeler',
89             handles => [ qw(classify) ],
90             );
91              
92             ## no critic (ProhibitUnusedPrivateSubroutines)
93              
94             # "magic" name used when a lineage has no colored taxon
95             const my $NOCOLOR => '_NOCOLOR_';
96              
97             sub _build_color_for {
98 0     0     my $self = shift;
99             return {
100             $NOCOLOR => 'black', # default color
101 0           mesh @{ $self->names }, @{ $self->colors } # scheme colors
  0            
  0            
102             };
103             }
104              
105              
106             sub _build_gcn {
107 0     0     return Graphics::ColorNames->new('WWW');
108             }
109              
110             sub _build_icol_for {
111 0     0     my $self = shift;
112              
113 0           my %icol_for;
114 0           my $index = 0;
115              
116 0           my @colors = uniq $self->all_colors;
117 0           for my $color (@colors) {
118 0           $icol_for{$color} = ++$index;
119             }
120              
121 0           return \%icol_for;
122             }
123              
124             sub _build_labeler {
125 0     0     my $self = shift;
126 0           return $self->tax->tax_labeler_from_list( $self->names );
127             }
128              
129             ## use critic
130              
131              
132             sub BUILD {
133 0     0 0   my $self = shift;
134              
135             # TODO: check that is has any effect at all!
136 0 0         carp '[BMC] Warning: name and color list sizes differ!'
137             unless $self->count_names == $self->count_colors;
138             carp '[BMC] Warning: non unique names!'
139 0 0         unless $self->count_names == uniq @{ $self->names };
  0            
140              
141 0           return;
142             }
143              
144              
145             around qw(hex rgb icol) => sub {
146             my $method = shift;
147             my $self = shift;
148             my $seq_id = shift;
149              
150             # intercept delegated method calls and translate color names on the fly
151              
152             # consider input as a SeqId object (or NCBI lineage)
153             # ... and select the lowest taxon to which a color is associated
154             # if a lineage has no colored taxon then it will be black
155             my $label = $self->classify($seq_id) // $NOCOLOR;
156              
157             # return color (possibly doubly translated)
158             # ... e.g., taxon => color-name => color-hex-code
159             my $color = $self->$method( $self->color_for($label), @_ );
160             return wantarray ? ($color, $label) : $color;
161             };
162              
163              
164              
165             sub attach_colors_to_entities {
166 0     0 0   my $self = shift;
167 0           my $tree = shift;
168 0   0       my $key = shift // 'taxonomy';
169              
170 0           for my $node ( @{ $tree->tree->get_entities } ) {
  0            
171 0           my ($color, $label) = $self->hex( $node->get_generic($key), '#' );
172 0           $node->set_generic( '!color' => $color );
173 0 0         $node->set_generic( taxon_label => $label ) unless $label eq $NOCOLOR;
174             }
175              
176 0           return;
177             }
178              
179             # class methods
180              
181              
182             # TODO: implement auto spectrum methods (based on name list?)
183              
184             # sub spectrum {
185             # my $class = shift;
186             # my $steps = shift;
187             #
188             # my $spectrum = Color::Spectrum::Multi->new();
189             # my @colors = $spectrum->generate($steps, '#FF0000', '#00FF00', '#0000FF');
190             #
191             # }
192              
193              
194             # I/O methods
195              
196              
197             sub load {
198 0     0 1   my $self = shift;
199 0           my $infile = shift;
200              
201 0           open my $in, '<', $infile;
202              
203             LINE:
204 0           while (my $line = <$in>) {
205 0           chomp $line;
206              
207             # skip empty lines and comment lines
208 0 0 0       next LINE if $line =~ $EMPTY_LINE
209             || $self->is_comment($line);
210              
211             # extract name and color
212 0           my ($name, $color) = split /\t/xms, $line;
213 0           $self->add_name( $name );
214 0           $self->add_color($color);
215             }
216              
217 0           return $self;
218             }
219              
220              
221              
222             sub store {
223 0     0 1   my $self = shift;
224 0           my $outfile = shift;
225              
226 0           open my $out, '>', $outfile;
227              
228             # note the use of a twin array iterator
229 0           print {$out} $self->header;
  0            
230 0           my $ea = each_array @{ $self->names }, @{ $self->colors };
  0            
  0            
231 0           while (my ($name, $color) = $ea->() ) {
232 0           say {$out} join "\t", $name, $color;
  0            
233             }
234              
235 0           return;
236             }
237              
238             __PACKAGE__->meta->make_immutable;
239             1;
240              
241             __END__
242              
243             =pod
244              
245             =head1 NAME
246              
247             Bio::MUST::Core::Taxonomy::ColorScheme - Helper class providing color scheme for taxonomic annotations
248              
249             =head1 VERSION
250              
251             version 0.212670
252              
253             =head1 SYNOPSIS
254              
255             # TODO
256              
257             =head1 DESCRIPTION
258              
259             # TODO
260              
261             =head1 METHODS
262              
263             =head2 attach_color_to_entities
264              
265             =head2 spectrum
266              
267             =head2 load
268              
269             =head2 store
270              
271             =head1 AUTHOR
272              
273             Denis BAURAIN <denis.baurain@uliege.be>
274              
275             =head1 CONTRIBUTOR
276              
277             =for stopwords Valerian LUPO
278              
279             Valerian LUPO <valerian.lupo@doct.uliege.be>
280              
281             =head1 COPYRIGHT AND LICENSE
282              
283             This software is copyright (c) 2013 by University of Liege / Unit of Eukaryotic Phylogenomics / Denis BAURAIN.
284              
285             This is free software; you can redistribute it and/or modify it under
286             the same terms as the Perl 5 programming language system itself.
287              
288             =cut