Merge pull request #5 from solgenomics/topic/fix_il_maps
[cview.git] / lib / CXGN / Cview / MapFactory / SGN.pm
blob277f3d224b88e01e525d60fd9163d735c74e8a0b
2 =head1 NAME
4 CXGN::Cview::MapFactory - a factory object for CXGN::Cview::Map objects
6 =head1 SYNOPSYS
8 my $map_factory = CXGN::Cview::MapFactory->new($dbh);
9 $map = $map_factory->create({map_version_id=>"u1"});
11 =head1 DESCRIPTION
13 see L<CXGN::Cview::MapFactory>.
15 The MapFactory constructor takes a database handle (preferably constructed using CXGN::DB::Connection object). The map objects can then be constructed using the create function, which takes a hashref as a parameter, containing either map_id or map_version_id as a key (but not both). map_ids will be converted to map_version_ids immediately. Map_version_ids are then analyzed and depending on its format, CXGN::Cview::Map object of the proper type is returned.
17 The function get_all_maps returns all maps as list of appropriate CXGN::Cview::Map::* objects.
19 For the current SGN implementation, the following identifier formats are defined and yield following corresponding map objects
21 \d+ refers to a map id in the database and yields either a
22 CXGN::Cview::Map::SGN::Genetic (type genetic)
23 CXGN::Cview::Map::SGN::FISH (type fish)
24 CXGN::Cview::Map::SGN::Sequence (type sequence)
25 u\d+ refers to a user defined map and returns:
26 CXGN::Cview::Map::SGN::User object
27 filepath refers to a map defined in a file and returns a
28 CXGN::Cview::Map::SGN::File object
29 il\d+ refers to a population id in the phenome.population table
30 (which must be of type IL) and returns a
31 CXGN::Cview::Map::SGN::IL object
32 p\d+ CXGN::Cview::Map::SGN::Physical
33 c\d+ CXGN::Cview::Map::SGN::Contig
34 o CXGN::Cview::Map::SGN::ProjectStats map object
36 The actual map objects returned are defined in the CXGN::Cview::Maps namespace. Because this is really a compatibility layer, an additional namespace of the resource is appended, such that a genetic map at SGN could be defined as CXGN::Cview::Maps::SGN::Genetic . If no corresponding map is found, undef is returned.
38 =head1 AUTHOR(S)
40 Lukas Mueller (lam87@cornell.edu)
42 =head1 VERSION
44 1.0, March 2007
46 =head1 LICENSE
48 Refer to the L<CXGN::LICENSE> file.
50 =head1 FUNCTIONS
52 This class implements the following functions:
54 =cut
56 use strict;
58 package CXGN::Cview::MapFactory::SGN;
60 use base qw| CXGN::DB::Object |;
62 use Scalar::Util qw/blessed/;
64 use CXGN::Cview::Map::SGN::Genetic;
65 #use CXGN::Cview::Map::SGN::User;
66 use CXGN::Cview::Map::SGN::Fish;
67 use CXGN::Cview::Map::SGN::Sequence;
68 use CXGN::Cview::Map::SGN::IL;
69 use CXGN::Cview::Map::SGN::Physical;
70 use CXGN::Cview::Map::SGN::ProjectStats;
71 use CXGN::Cview::Map::SGN::AGP;
72 #use CXGN::Cview::Map::SGN::ITAG;
73 use CXGN::Cview::Map::SGN::Contig;
74 use CXGN::Cview::Map::SGN::Scaffold;
75 use CXGN::Cview::Map::SGN::Image;
76 use CXGN::Cview::Map::SGN::QTL;
78 =head2 function new()
80 Synopsis: constructor
81 Arguments: a database handle
82 Returns: a CXGN::Cview::MapFactory::SGN object
83 Side effects: none
84 Description: none
86 =cut
88 sub new {
89 my $class = shift;
90 my $dbh = shift;
91 my $context = shift;
93 unless( blessed($context) && $context->isa('SGN::Context') ) {
94 require SGN::Context;
95 $context = SGN::Context->new();
97 my $self = $class->SUPER::new($dbh);
99 $self->{context}=$context;
102 return $self;
105 =head2 function create()
107 Description: creates a map based on the hashref given, which
108 should either contain the key map_id or map_version_id
109 and an appropriate identifier. The function returns undef
110 if a map of the given id cannot be found/created.
111 Example:
113 =cut
115 sub create {
116 my $self = shift;
117 my $hashref = shift;
118 #print STDERR "Hashref = map_id => $hashref->{map_id}, map_version_id => $hashref->{map_version_id}\n";
120 my $c = $self->{context};
121 my $temp_dir = $c->path_to( $c->config->{tempfiles_subdir} );
123 if (!exists($hashref->{map_id}) && !exists($hashref->{map_version_id})) {
124 die "[CXGN::Cview::MapFactory] Need either a map_id or map_version_id.\n";
126 if ($hashref->{map_id} && $hashref->{map_version_id}) {
127 die "[CXGN::Cview::MapFactory] Need either a map_id or map_version_id - not both.\n";
129 if ($hashref->{map_id}) {
130 $hashref->{map_version_id}=CXGN::Cview::Map::Tools::find_current_version($self->get_dbh(), $hashref->{map_id});
133 # now, we only deal with map_versions...
135 my $id = $hashref->{map_version_id};
137 #print STDERR "MapFactory: dealing with id = $id\n";
139 # if the map_version_id is purely numeric,
140 # check if the map is in the maps table and generate the
141 # appropriate map
143 if ($id=~/^\d+$/) {
144 my $query = "SELECT map_version_id, map_type, map_id, short_name FROM sgn.map join sgn.map_version using(map_id) WHERE map_version_id=?";
145 my $sth = $self->get_dbh()->prepare($query);
146 $sth->execute($id);
147 my ($id, $map_type) = $sth->fetchrow_array();
148 $map_type ||= '';
149 if ($map_type =~ /genetic/i) {
150 return CXGN::Cview::Map::SGN::Genetic->new($self->get_dbh(), $id);
153 elsif ($map_type =~ /fish/) {
154 #print STDERR "Creating a fish map...\n";
155 return CXGN::Cview::Map::SGN::Fish->new($self->get_dbh(), $id, { pachytene_file => $c->config->{'basepath'}."/documents/cview/pachytene/pachytene_stack.txt", });
157 elsif ($map_type =~ /seq/) {
158 #print STDERR "Creating a seq map...\n";
159 return CXGN::Cview::Map::SGN::Sequence->new($self->get_dbh(), $id);
161 elsif ($map_type =~ /qtl/i) {
163 my $qtl = CXGN::Cview::Map::SGN::QTL->new($self->get_dbh(), $id);
165 return $qtl;
168 elsif ($id =~ /^u/i) {
169 #return CXGN::Cview::Map::SGN::User->new($self->get_dbh(), $id);
171 elsif ($id =~ /^il/i) {
172 my $abstract =
173 "The tomato Introgression lines (ILs) are a set of nearly isogenic lines (NILs) developed by Dani Zamir through a succession of backcrosses, where each line carries a single genetically defined chromosome segment from a divergent genome. The ILs, representing whole-genome coverage of S. pennellii in overlapping segments in the genetic background of S. lycopersicum cv. M82, were first phenotyped in 1993, and presently this library consists of 76 genotypes. ";
175 my ($population_id, $map_id) = $self->get_db_ids($id);
176 if ($map_id == 9) {
177 $abstract .= " This IL map is based on markers of the F2-2000 map. ILs have also been mapped <a href=\"map.pl?map_id=il6.5&amp;show_ruler=1&amp;show_offsets=1\" >with the ExPEN1992 map as a reference</a>.";
179 elsif ($map_id ==5) {
180 $abstract .= " The IL lines on this map have been characterized based on the markers on the 1992 tomato map. ILs have also been mapped <a href=\"map.pl?map_id=il6.9&amp;show_ruler=1&amp;show_offsets=1\" >with the ExPEN2000 map as a reference</a>. ";
183 my $ref_map = "ExPEN2000";
184 if ($id==5) { $ref_map = "ExPEN1992";}
185 my $long_name =qq | Solanum lycopersicum Zamir Introgression Lines (IL) based on $ref_map |;
187 return CXGN::Cview::Map::SGN::IL->new($self->get_dbh(), $id,
188 { short_name => "Tomato IL map",
189 long_name => $long_name,
190 abstract => $abstract,
195 elsif ($id =~ /^\//) {
196 #return CXGN::Cview::Map::SGN::File->new($dbh, $id);
198 elsif ($id =~ /^p\d+/) {
199 return CXGN::Cview::Map::SGN::Physical->new($self->get_dbh(), $id);
201 elsif ($id =~ /^o$/i) {
203 return CXGN::Cview::Map::SGN::ProjectStats->new($self->get_dbh(), {
204 short_name=>"Tomato Sequencing Progress",
205 long_name=>"Tomato Sequencing Statistics by Chromosome",
206 abstract => $self->get_abstract(),
211 elsif ($id =~ /^agp$/i) {
212 my $map;
213 eval { $map = CXGN::Cview::Map::SGN::AGP->new($self->get_dbh(), $id, {
214 short_name => "Tomato AGP map",
215 long_name => "Tomato (Solanum lycopersicum) Accessioned Golden Path map",
216 abstract => "<p>The AGP map shows the sequencing progress of the international tomato genome sequencing project by listing all finished clones by estimated physical map position . Each sequencing center generates one or more AGP (Accessioned Golden Path) files and uploads them to SGN. These files contain all the sequenced BACs, their position on the chromosome, the overlaps with other BACs and other information. For a complete specification, please refer to the <a href=\"http://www.sanger.ac.uk/Projects/C_elegans/DOCS/agp_files.shtml\">Sanger AGP specification</a>. The AGP files can also be downloaded from the SGN FTP site, at <a href=\"ftp://ftp.sgn.cornell.edu/tomato_genome/agp/\">ftp://ftp.sgn.cornell.edu/tomato_genome/agp/</a>.</p> <p>Note that this map is in testing (beta), and not all features may be functional.</p>" ,
217 temp_dir => $temp_dir ,
218 basedir => $c->config->{"basepath"},
219 documents_subdir => $c->config->{"tempfiles_subdir"},
220 file => $c->config->{"static_content_path"}."/cview/agp/scaffolds/S_lycopersicum_chromosomes_from_scaffolds.2.40.agp",
221 cache_dir => $c->config->{"basepath"}."/".$c->config->{tempfiles_subdir}."/cview/cache_file/",
226 if ($@) { print STDERR "Map agp could not be created\n"; return undef; }
227 else { return $map; }
230 # elsif ($id =~ /^itag$/i) {
232 # my (@sources) = map $_->data_sources(), $c->enabled_feature('gbrowse2');
233 # my ($gbrowse_itag) = grep $_->description()=~/ITAG_devel.+genomic/i, @sources;
234 # my @dbs;
235 # if ($gbrowse_itag) {
236 # @dbs = $gbrowse_itag->databases();
237 # @dbs > 1 and die "I can handle only one db!";
240 # return unless $gbrowse_itag;
242 # my $gbrowse_view_link = $gbrowse_itag->view_url;
244 # my $marker_link = sub { my $id = shift; return "$gbrowse_view_link?name=$id"; };
245 # return CXGN::Cview::Map::SGN::ITAG->new($self->get_dbh(), $id, {
246 # short_name => "Tomato ITAG map",
247 # long_name=>"Tomato (Solanum lycopersicum) ITAG map",
248 # abstract=>"<p>The ITAG map shows the contig assembly and the corresponding BACs as used by the most recent annotation from the International Tomato Annotation Group (ITAG, see <a href=\"http://www.ab.wur.nl/TomatoWiki\">ITAG Wiki</a>). Clicking on the contigs will show the ITAG annotation in the genome browser.",
249 # temp_dir => $temp_dir,
250 # marker_link => $marker_link,
253 # );
256 # elsif ($id =~ /scaffold103/) {
258 # return CXGN::Cview::Map::SGN::Scaffold->new($self->get_dbh(), $id, {
259 # file=> '/data/prod/public/tomato_genome/wgs/chromosomes/assembly_1.03/chromosome_defs_v1.03_sorted.txt',
260 # abstract=>'test abstract',
261 # temp_dir=>$temp_dir,
262 # short_name=>'Tomato scaffold map V1.03',
263 # long_name=>'Solanum lycopersicum scaffold map V1.03',
264 # marker_link => sub {},
266 # } );
269 # elsif ($id =~ /scaffold100/) {
270 # my (@sources) = map $_->data_sources(), $c->enabled_feature('gbrowse2');
271 # my ($gbrowse) = grep $_->description()=~/ITAG1.+genomic/i, @sources;
272 # if (!$gbrowse) { die "No such map in GBrowse."; }
273 # my @dbs;
274 # if ($gbrowse) {
275 # @dbs = $gbrowse->databases();
276 # @dbs > 1 and die "I can handle only one db!";
279 # return unless $gbrowse;
281 # my $gbrowse_view_link = $gbrowse->view_url;
283 # my $marker_link = sub { my $id = shift; return "$gbrowse_view_link?name=$id"; };
285 # return CXGN::Cview::Map::SGN::Scaffold->new($self->get_dbh(), $id, {
286 # file=> '/data/prod/public/tomato_genome/wgs/chromosomes/assembly_1.00/chromosome_defs_v1.00_sorted.txt',
287 # abstract=>'test abstract',
288 # temp_dir=>$temp_dir,
289 # short_name=>'Tomato scaffold map V1.00',
290 # long_name=>'Solanum lycopersicum scaffold map V1.00',
291 # marker_link => $marker_link,
292 # } );
294 elsif ($id =~ /^u\d+$/i) {
295 return CXGN::Cview::Map::SGN::User->new($self->get_dbh(), $id);
297 elsif ($id =~ /pachy/i) {
298 my $image_dir = $c->config->{'image_path'};
299 #print STDERR "**** IMAGE DIR = $image_dir\n";
300 my $map = CXGN::Cview::Map::SGN::Image->new(
301 $self->get_dbh(),
302 $id,
303 $image_dir.'/maps/tomato_pachytene_images/chr1.png',
304 $image_dir.'/maps/tomato_pachytene_images/chr2.png',
305 $image_dir.'/maps/tomato_pachytene_images/chr3.png',
306 $image_dir.'/maps/tomato_pachytene_images/chr4.png',
307 $image_dir.'/maps/tomato_pachytene_images/chr5.png',
308 $image_dir.'/maps/tomato_pachytene_images/chr6.png',
309 $image_dir.'/maps/tomato_pachytene_images/chr7.png',
310 $image_dir.'/maps/tomato_pachytene_images/chr8.png',
311 $image_dir.'/maps/tomato_pachytene_images/chr9.png',
312 $image_dir.'/maps/tomato_pachytene_images/chr10.png',
313 $image_dir.'/maps/tomato_pachytene_images/chr11.png',
314 $image_dir.'/maps/tomato_pachytene_images/chr12.png',
316 $map->set_abstract('This map shows the pachytene chromosomes of tomato. It is only for illustrative purposes and does not contain any markers. <br /><br />Images courtesy of Prof. Stephen Stack, Colorado State University.');
317 $map->set_short_name('Tomato Pachytene Chromosomes');
319 return $map;
322 elsif ($id =~ /^c\d+$/i) {
323 my ($gbrowse_fpc) = map $_->fpc_data_sources, $c->enabled_feature('gbrowse2');
324 my @dbs;
325 if ($gbrowse_fpc) {
326 @dbs = $gbrowse_fpc->databases();
327 @dbs > 1 and die "I can handle only one db!";
328 } else {
329 warn "no GBrowse FPC data sources available, cannot open map $id";
330 return;
334 my $gbrowse_view_link = $gbrowse_fpc->view_url;
335 return CXGN::Cview::Map::SGN::Contig->new($self->get_dbh(), $id, {
336 gbrowse_fpc => $gbrowse_fpc,
337 short_name => $gbrowse_fpc->description,
338 long_name => '',
339 temp_dir => $temp_dir,
341 #marker_link => $gbrowse_fpc->xrefs(),
342 abstract => $gbrowse_fpc->extended_description."\n". qq{
343 <p>This overview shows the counts of contigs along the chromosome. Click on any chromosome to view the individual contigs. More information on each contig can be obtained by by clicking on a specific contig.</p>
344 <p>Specific contig IDs, including contigs that are not mapped, can be searched on the <a href="$gbrowse_view_link">FPC viewer page</a>.</p>
354 return;
358 =head2 function get_all_maps()
360 Synopsis:
361 Arguments: none
362 Returns: a list of all maps currently defined, as
363 CXGN::Cview::Map objects (and subclasses)
364 Side effects: Queries the database for certain maps
365 Description:
367 =cut
369 sub get_all_maps {
370 my $self = shift;
372 my @system_maps = $self->get_system_maps();
373 my @user_maps = $self->get_user_maps();
374 my @maps = (@system_maps, @user_maps);
375 return @maps;
380 =head2 get_system_maps
382 Usage: my @system_maps = $map_factory->get_system_maps();
383 Desc: retrieves a list of system maps (from the sgn
384 database) as a list of CXGN::Cview::Map objects
385 Ret:
386 Args:
387 Side Effects:
388 Example:
390 =cut
392 sub get_system_maps {
393 my $self = shift;
395 my @maps = ();
397 my $query = "SELECT map.map_id FROM sgn.map LEFT JOIN sgn.map_version USING(map_id) LEFT JOIN sgn.accession on(parent_1=accession.accession_id) LEFT JOIN sgn.organism USING(organism_id) LEFT JOIN common_name USING(common_name_id) WHERE current_version='t' ORDER by common_name.common_name";
398 my $sth = $self->get_dbh()->prepare($query);
399 $sth->execute();
401 while (my ($map_id) = $sth->fetchrow_array()) {
402 my $map = $self->create({ map_id => $map_id });
403 if ($map) { push @maps, $map; }
406 # push il, physical, contig, and agp map
408 foreach my $id ("il6.5", "il6.9", "p9", "c9", "agp", "pachy") {
409 my $map = $self->create( {map_id=>$id} );
410 if ($map) { push @maps, $map; }
413 return @maps;
418 =head2 get_user_maps
420 Status: DEPRECATED. Does nothing now, as user maps have been disabled.
421 Usage:
422 Desc: retrieves the current user maps of the logged in user.
423 Ret: a list of CXGN::Cview::Map objects
424 Args: none
425 Side Effects: none
426 Example:
428 =cut
430 sub get_user_maps {
431 my $self = shift;
432 # push the maps that are specific to that user and not public, if somebody is logged in...
434 my @maps = ();
435 # my $login = CXGN::Login->new($self->get_dbh());
436 # my $user_id = $login->has_session();
437 # if ($user_id) {
438 # my $q3 = "SELECT user_map_id FROM sgn_people.user_map WHERE obsolete='f' AND sp_person_id=?";
439 # my $h3 = $self->get_dbh()->prepare($q3);
440 # $h3->execute($user_id);
441 # while (my ($user_map_id) = $h3->fetchrow_array()) {
442 # my $map = $self->create( {map_id=>"u".$user_map_id} );
444 # if ($map) { push @maps, $map; }
447 return @maps;
451 sub get_db_ids {
452 my $self = shift;
453 my $id = shift;
455 my $population_id = 6;
456 my $reference_map_id=5;
458 if ($id=~/il(\d+)\.?(\d*)?/) {
459 $population_id=$1;
460 $reference_map_id=$2;
462 if (!$reference_map_id) { $reference_map_id=5; }
463 if (!$population_id) { $population_id=6; }
464 #print STDERR "Population ID: $population_id, reference_map_id = $reference_map_id\n";
466 return ($population_id, $reference_map_id);
469 return 1;