Bio::G...kerplot(3pm)

πŸ“¦
version 2.40 Β· 2 versions
, in debian bookworm, debian trixie, ubuntu jammy, ubuntu noble

πŸ’– Bio::Graphics::Glyph::whiskerplot β€” the whiskerplot glyph πŸ’–

okay bestie, sit down, hydrate, because we're about to talk about the whiskerplot glyph from the Bio::Graphics family. this is Bio::G...kerplot(3pm) from the User Contributed Perl Documentation, and it's literally the plot that goes boing πŸ“Šβœ¨


✨ NAME ✨

Bio::Graphics::Glyph::whiskerplot β€” the whiskerplot glyph πŸŽ€


🌸 SYNOPSIS 🌸

  See L<Bio::Graphics::Panel> and L<Bio::Graphics::Glyph>.

πŸ¦‹ DESCRIPTION πŸ¦‹

so this glyph? it's the one you use when you wanna draw features that come with numeric data, using "box and whisker" style data points. it shows you the mean value, the extreme ranges, and the first and third quartiles (or standard deviation, your call bestie). πŸ’…

the boxes this glyph draws are basically the same vibe as the ones at <http://www.abs.gov.au/websitedbs/D3310116.NSF/0/3c35ac1e828c23ef4a2567ac0020ec8a?OpenDocument> β€” except plot twist, they're oriented vertically, so the position and height of the box tells you the mean value and the spread of the data, and the width tells you the genomic extent of the value. no cap. πŸ“

like the xyplot glyph (which it inherits from), whiskerplot is designed to work on a single feature group that contains subfeatures. the subfeatures are the ones carrying the score info, periodt. the best way to arrange this is to make an aggregator for the feature. 🫢

let's take a glow-up example: a histogram of repeat density, where intervals are spaced every megabase and the score indicates the number of repeats in that interval. we're assuming the database was loaded in such a way that each interval is its own distinct feature with the method name "density" and the source name "repeat". and β€” key detail β€” all the repeat features are grouped together into a single group (the name of the group literally doesn't matter, it's just vibes). 🌈

if you're using Bio::DB::GFF and Bio::Graphics directly, the sequence of events would look like this:

  my $agg = Bio::DB::GFF::Aggregator->new(-method    => 'repeat_density',
                                          -sub_parts => 'density:repeat');
  my $db  = Bio::DB::GFF->new(-dsn=>'my_database',
                              -aggregators => $agg);
  my $segment  = $db->segment('Chr1');
  my @features = $segment->features('repeat_density');

  my $panel = Bio::Graphics::Panel->new;
  $panel->add_track(\@features,
                    -glyph => 'xyplot',
                    -scale => 'both',
  );

and if you're using Generic Genome Browser, you'd add this to the configuration file instead:

  aggregators = repeat_density{density:repeat}
                clone alignment etc
πŸ’‘ little tip from me to you: it's a good idea to add some padding to the left and right of the panel. otherwise the scale will get partially cut off by the edge of the image and that's not the serve we're going for. 😭

the mean (or median) of the data gets taken from the feature score. the range and quartile data has to either come from a feature tag named "range", or be generated on the fly by a -range callback option passed to add_track. the data returned by that tag or option should be an array reference holding these five fields:

 [$median,$range_low,$range_high,$quartile_low,$quartile_high]

where $range_low and $range_high correspond to the low and high value of the "whiskers" and $quartile_low and $quartile_high correspond to the low and high value of the "box." πŸ“¦

if $median is undef or just straight up missing, then the score field of the feature gets used instead. and honestly? it may be useful to repeat the median in the score field in any case, so that the minimum and maximum range calculations of the graph itself can actually happen. iykyk. πŸ€“

see Examples for three ways of generating an image. πŸ–ΌοΈ


πŸŽ€ OPTIONS πŸŽ€

the following options are standard among all Glyphs. see Bio::Graphics::Glyph for a full explanation. πŸ‘‘

  • -fgcolor β€” foreground color. default: black πŸ–€
  • -outlinecolor β€” synonym for -fgcolor
  • -bgcolor β€” background color. default: turquoise πŸ’™
  • -fillcolor β€” synonym for -bgcolor
  • -linewidth β€” line width. default: 1
  • -height β€” height of glyph. default: 10
  • -font β€” glyph font. default: gdSmallFont
  • -label β€” whether to draw a label. default: 0 (false)
  • -description β€” whether to draw a description. default: 0 (false)
  • -hilite β€” highlight color. default: undef (no color)

on top of all that, the alignment glyph recognizes all the options of the xyplot glyph, plus this one glyph-specific option right here: ✨

  • -range β€” callback to return median, range and quartiles for each sub feature. default: none β€” data comes from feature "range" tag

πŸ’– EXAMPLES πŸ’–

okay bestie, buckle up, because we have three whole examples and each one is a different flavor of iconic πŸ“. pick your fighter, they all render the same beautiful whiskers at the end, no cap.


🌈 Example 1: Incorporating the numeric data in each subfeature 🌈

so in this one, every single subfeature is carrying its own little bundle of range data, tucked away in a -tag hash under the key range. the glyph goes digging for it. very self-sufficient of it πŸ’…

#!/usr/bin/perl
use strict;

use Bio::Graphics;
use Bio::SeqFeature::Generic;

my $bsg = 'Bio::SeqFeature::Generic';

my $feature = $bsg->new(-start=>0,-end=>1000);

for (my $i=0;$i<1000;$i+=20) {
  my $y = (($i-500)/10)**2;
  my $range = make_range($y);
  my $part = $bsg->new(-start=>$i,-end=>$i+16,
                      -score=>$y,-tag => { range=>$range });
  $feature->add_SeqFeature($part);
}

my $panel = Bio::Graphics::Panel->new(-length=>1000,-width=>800,-key_style=>'between',
                                     -pad_left=>40,-pad_right=>40);
$panel->add_track($feature,
                 -glyph=>'arrow',
                 -double=>1,
                 -tick=>2);

$panel->add_track($feature,
                 -glyph=>'whiskerplot',
                 -scale=>'both',
                 -height=>200,
                 -min_score => -500,
                 -key  =>'Whiskers',
                 -bgcolor => 'orange',
                );
print $panel->png;

sub make_range {
  my $score        = shift;
  my $range_top    = $score + 5*sqrt($score) + rand(50);
  my $range_bottom = $score - 5*sqrt($score) - rand(50);
  my $quartile_top    = $score + 2*sqrt($score) + rand(50);
  my $quartile_bottom = $score - 2*sqrt($score) - rand(50);
  return [$score,$range_bottom,$range_top,$quartile_bottom,$quartile_top];
}

see how make_range hands back a list ref? <pink>score, range bottom, range top, quartile bottom, quartile top</pink> β€” that's the exact order, don't shuffle it πŸ™ˆ


πŸ¦‹ Example 2: Generating the range data with a callback πŸ¦‹

same energy, except now instead of pre-stuffing the tags we pass a coderef to -range and let the glyph call it per feature. main character behavior honestly πŸ‘‘

#!/usr/bin/perl
use strict;

use Bio::Graphics;
use Bio::SeqFeature::Generic;

my $bsg = 'Bio::SeqFeature::Generic';
my $feature = $bsg->new(-start=>0,-end=>1000);

for (my $i=0;$i<1000;$i+=20) {
  my $y = (($i-500)/10)**2;
  my $part = $bsg->new(-start=>$i,-end=>$i+16,-score=>$y);
  $feature->add_SeqFeature($part);
}

my $panel = Bio::Graphics::Panel->new(-length=>1000,-width=>800,-key_style=>'between',
                                     -pad_left=>40,-pad_right=>40);
$panel->add_track($feature,
                 -glyph=>'arrow',
                 -double=>1,
                 -tick=>2);

$panel->add_track($feature,
                 -glyph=>'whiskerplot',
                 -scale=>'both',
                 -height=>200,
                 -min_score => -500,
                 -key  =>'Whiskers',
                 -bgcolor => 'orange',
                 -range => \&make_range,
                );
print $panel->png;

sub make_range {
  my $feature = shift;
  my $score        = $feature->score;
  my $range_top    = $score + 5*sqrt($score) + rand(50);
  my $range_bottom = $score - 5*sqrt($score) - rand(50);
  my $quartile_top    = $score + 2*sqrt($score) + rand(50);
  my $quartile_bottom = $score - 2*sqrt($score) - rand(50);
  return [$score,$range_bottom,$range_top,$quartile_bottom,$quartile_top];
}

notice make_range gets handed the $feature itself this time, so it can pull $feature->score on its own. glow-up fr fr ✨


πŸ’… Example 3: Generating the image from a FeatureFile πŸ’…

this one is the slay-est of all, because the whole thing β€” options AND data β€” lives in a plain text file. no perl required, just vibes.

The file:

[general]
pixels = 840
pad_left = 40
pad_right = 40

[contig]
glyph     = arrow
double    = 1
tick      = 2

[data]
glyph     = whiskerplot
scale     = both
height    = 200
min_score = -500
max_score = 2800
key       = Whiskers
bgcolor   = orange

chr1   .       contig  1       1000    .       .       .       Contig chr1
chr1   .       data    0       16      2500    .       .       Dataset data1; range 2209,2769,2368,2619
chr1   .       data    20      36      2304    .       .       Dataset data1; range 2051,2553,2163,2435
chr1   .       data    40      56      2116    .       .       Dataset data1; range 1861,2384,1983,2253
chr1   .       data    60      76      1936    .       .       Dataset data1; range 1706,2181,1819,2059
chr1   .       data    80      96      1764    .       .       Dataset data1; range 1516,1995,1646,1849
chr1   .       data    100     116     1600    .       .       Dataset data1; range 1359,1834,1513,1699
chr1   .       data    120     136     1444    .       .       Dataset data1; range 1228,1654,1330,1565
chr1   .       data    140     156     1296    .       .       Dataset data1; range 1105,1520,1198,1385
chr1   .       data    160     176     1156    .       .       Dataset data1; range 983,1373,1062,1270
chr1   .       data    180     196     1024    .       .       Dataset data1; range 853,1184,914,1116
chr1   .       data    200     216     900     .       .       Dataset data1; range 722,1093,801,965
chr1   .       data    220     236     784     .       .       Dataset data1; range 621,945,724,859
chr1   .       data    240     256     676     .       .       Dataset data1; range 532,833,605,742
chr1   .       data    260     276     576     .       .       Dataset data1; range 433,714,485,653
chr1   .       data    280     296     484     .       .       Dataset data1; range 331,600,418,545
chr1   .       data    300     316     400     .       .       Dataset data1; range 275,535,336,459
chr1   .       data    320     336     324     .       .       Dataset data1; range 198,434,270,374
chr1   .       data    340     356     256     .       .       Dataset data1; range 167,378,219,322
chr1   .       data    360     376     196     .       .       Dataset data1; range 114,303,118,249
chr1   .       data    380     396     144     .       .       Dataset data1; range 39,248,87,197
chr1   .       data    400     416     100     .       .       Dataset data1; range 17,173,68,141
chr1   .       data    420     436     64      .       .       Dataset data1; range -14,125,18,84
chr1   .       data    440     456     36      .       .       Dataset data1; range -8,74,11,64
chr1   .       data    460     476     16      .       .       Dataset data1; range -46,77,0,43
chr1   .       data    480     496     4       .       .       Dataset data1; range -40,43,-7,36
chr1   .       data    500     516     0       .       .       Dataset data1; range -43,0,-43,22
chr1   .       data    520     536     4       .       .       Dataset data1; range -6,52,-4,54
chr1   .       data    540     556     16      .       .       Dataset data1; range -5,38,-27,52
chr1   .       data    560     576     36      .       .       Dataset data1; range -43,109,18,66
chr1   .       data    580     596     64      .       .       Dataset data1; range -1,134,3,112
chr1   .       data    600     616     100     .       .       Dataset data1; range 49,186,69,124
chr1   .       data    620     636     144     .       .       Dataset data1; range 79,225,71,169
chr1   .       data    640     656     196     .       .       Dataset data1; range 124,289,120,266
chr1   .       data    660     676     256     .       .       Dataset data1; range 154,378,197,320
chr1   .       data    680     696     324     .       .       Dataset data1; range 220,439,249,396
chr1   .       data    700     716     400     .       .       Dataset data1; range 291,511,331,458
chr1   .       data    720     736     484     .       .       Dataset data1; range 350,627,400,572
chr1   .       data    740     756     576     .       .       Dataset data1; range 446,718,502,633
chr1   .       data    760     776     676     .       .       Dataset data1; range 515,833,576,777
chr1   .       data    780     796     784     .       .       Dataset data1; range 606,959,724,856
chr1   .       data    800     816     900     .       .       Dataset data1; range 747,1058,799,1004
chr1   .       data    820     836     1024    .       .       Dataset data1; range 817,1231,958,1089
chr1   .       data    840     856     1156    .       .       Dataset data1; range 961,1341,1069,1225
chr1   .       data    860     876     1296    .       .       Dataset data1; range 1103,1511,1219,1385
chr1   .       data    880     896     1444    .       .       Dataset data1; range 1218,1660,1338,1535
chr1   .       data    900     916     1600    .       .       Dataset data1; range 1377,1828,1496,1703
chr1   .       data    920     936     1764    .       .       Dataset data1; range 1547,2020,1674,1858
chr1   .       data    940     956     1936    .       .       Dataset data1; range 1691,2188,1824,2043
chr1   .       data    960     976     2116    .       .       Dataset data1; range 1869,2376,2019,2225
chr1   .       data    980     996     2304    .       .       Dataset data1; range 2040,2554,2178,2418

The script to render it

#!/usr/bin/perl

use strict;
use Bio::Graphics::FeatureFile;

my $data = Bio::Graphics::FeatureFile->new(-file=>'test.gff');

my(undef,$panel) = $data->render;
print $panel->png;

see the my(undef,$panel) thing? <hotpink>the render method hands back two values and you only want the second one</hotpink>, so we just yeet the first into the void. periodt πŸ’€


πŸ’€ BUGS πŸ’€

Please report them.

like seriously bestie, if something's broken, tell someone. don't just suffer in silence 🫢


🌸 SEE ALSO 🌸

the whole girl gang, in order:

  • Bio::Graphics::Panel
  • Bio::Graphics::Track
  • Bio::Graphics::Glyph::transcript2
  • Bio::Graphics::Glyph::anchored_arrow
  • Bio::Graphics::Glyph::arrow
  • Bio::Graphics::Glyph::box
  • Bio::Graphics::Glyph::primers
  • Bio::Graphics::Glyph::segments
  • Bio::Graphics::Glyph::toomany
  • Bio::Graphics::Glyph::transcript

πŸ‘‘ AUTHOR πŸ‘‘

Lincoln Stein <lstein@cshl.org>

Copyright (c) 2001 Cold Spring Harbor Laboratory

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See DISCLAIMER.txt for disclaimers of warranty.


and that's the whole page bestie πŸŽ€ this doc came from perl v5.30.0, dated 2019-11-25, and it lives under the name Bio::G...kerplot(3pm) β€” go forth and plot those whiskers, you absolute icon πŸ’–βœ¨

πŸ“¦ where this page comes from