2 new commits in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/changeset/98cf8f250649/ changeset: 98cf8f250649 user: jgoecks date: 2012-05-12 00:43:51 summary: Fix bug so that reference track cannot be resized. affected #: 1 file diff -r 1744124f8ee4fa3441642823b96c21262d219b14 -r 98cf8f2506493a468135f3d00e92233f5bfbf387 static/scripts/trackster.js --- a/static/scripts/trackster.js +++ b/static/scripts/trackster.js @@ -4334,7 +4334,7 @@ }); var ReferenceTrack = function (view) { - TiledTrack.call(this, view, { content_div: view.top_labeltrack, resize: false }, {}); + TiledTrack.call(this, view, { content_div: view.top_labeltrack }, { resize: false }); view.reference_track = this; this.left_offset = 200; https://bitbucket.org/galaxy/galaxy-central/changeset/c22bb0df586a/ changeset: c22bb0df586a user: jgoecks date: 2012-05-12 01:27:30 summary: Refactor genome build status and information out of tracks controllers and into own object. affected #: 2 files diff -r 98cf8f2506493a468135f3d00e92233f5bfbf387 -r c22bb0df586a95eae52701a7b44a678aed002b8e lib/galaxy/visualization/tracks/genomes.py --- /dev/null +++ b/lib/galaxy/visualization/tracks/genomes.py @@ -0,0 +1,268 @@ +import os, re +from bx.seq.twobit import TwoBitFile +from galaxy.util.json import from_json_string +from galaxy import model +from galaxy.util.bunch import Bunch + +# FIXME: copied from tracks.py +# Message strings returned to browser +messages = Bunch( + PENDING = "pending", + NO_DATA = "no data", + NO_CHROMOSOME = "no chromosome", + NO_CONVERTER = "no converter", + NO_TOOL = "no tool", + DATA = "data", + ERROR = "error", + OK = "ok" +) + +def decode_dbkey( dbkey ): + """ Decodes dbkey and returns tuple ( username, dbkey )""" + if ':' in dbkey: + return dbkey.split( ':' ) + else: + return None, dbkey + + +class Genomes( object ): + """ + Provides information about available genome data and methods for manipulating that data. + """ + + def __init__( self, app ): + # Create list of available genomes. + self.available_genomes = None + avail_genomes = {} + for line in open( os.path.join( app.config.tool_data_path, "twobit.loc" ) ): + if line.startswith("#"): continue + val = line.split() + if len( val ) == 2: + key, path = val + avail_genomes[ key ] = path + self.available_genomes = avail_genomes + + def chroms( self, trans, dbkey=None, num=None, chrom=None, low=None ): + """ + Returns a naturally sorted list of chroms/contigs for a given dbkey. + Use either chrom or low to specify the starting chrom in the return list. + """ + def check_int(s): + if s.isdigit(): + return int(s) + else: + return s + + def split_by_number(s): + return [ check_int(c) for c in re.split('([0-9]+)', s) ] + + # + # Parameter check, setting. + # + if num: + num = int( num ) + else: + num = sys.maxint + + if low: + low = int( low ) + if low < 0: + low = 0 + else: + low = 0 + + # If there is no dbkey owner, default to current user. + dbkey_owner, dbkey = decode_dbkey( dbkey ) + if dbkey_owner: + dbkey_user = trans.sa_session.query( trans.app.model.User ).filter_by( username=dbkey_owner ).first() + else: + dbkey_user = trans.user + + # + # Get len file. + # + len_file = None + len_ds = None + user_keys = {} + if dbkey_user and 'dbkeys' in dbkey_user.preferences: + user_keys = from_json_string( dbkey_user.preferences['dbkeys'] ) + if dbkey in user_keys: + dbkey_attributes = user_keys[ dbkey ] + if 'fasta' in dbkey_attributes: + build_fasta = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( dbkey_attributes[ 'fasta' ] ) + len_file = build_fasta.get_converted_dataset( trans, 'len' ).file_name + # Backwards compatibility: look for len file directly. + elif 'len' in dbkey_attributes: + len_file = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( user_keys[ dbkey ][ 'len' ] ).file_name + + if not len_file: + len_ds = trans.db_dataset_for( dbkey ) + if not len_ds: + len_file = os.path.join( trans.app.config.len_file_path, "%s.len" % dbkey ) + else: + len_file = len_ds.file_name + + # + # Get chroms data: + # (a) chrom name, len; + # (b) whether there are previous, next chroms; + # (c) index of start chrom. + # + len_file_enumerate = enumerate( open( len_file ) ) + chroms = {} + prev_chroms = False + start_index = 0 + if chrom: + # Use starting chrom to start list. + found = False + count = 0 + for line_num, line in len_file_enumerate: + if line.startswith("#"): + continue + name, len = line.split("\t") + if found: + chroms[ name ] = int( len ) + count += 1 + elif name == chrom: + # Found starting chrom. + chroms[ name ] = int ( len ) + count += 1 + found = True + start_index = line_num + if line_num != 0: + prev_chroms = True + if count >= num: + break + else: + # Use low to start list. + high = low + int( num ) + prev_chroms = ( low != 0 ) + start_index = low + + # Read chrom data from len file. + # TODO: this may be too slow for very large numbers of chroms/contigs, + # but try it out for now. + if not os.path.exists( len_file ): + return None + + for line_num, line in len_file_enumerate: + if line_num < low: + continue + if line_num >= high: + break + if line.startswith("#"): + continue + # LEN files have format: + # <chrom_name><tab><chrom_length> + fields = line.split("\t") + chroms[ fields[0] ] = int( fields[1] ) + + # Set flag to indicate whether there are more chroms after list. + next_chroms = False + try: + len_file_enumerate.next() + next_chroms = True + except: + # No more chroms to read. + pass + + to_sort = [{ 'chrom': chrom, 'len': length } for chrom, length in chroms.iteritems()] + to_sort.sort(lambda a,b: cmp( split_by_number(a['chrom']), split_by_number(b['chrom']) )) + return { 'reference': self.has_reference_data( trans, dbkey, dbkey_user ), 'chrom_info': to_sort, + 'prev_chroms' : prev_chroms, 'next_chroms' : next_chroms, 'start_index' : start_index } + + def has_reference_data( self, trans, dbkey, dbkey_owner=None ): + """ + Returns true if there is reference data for the specified dbkey. If dbkey is custom, + dbkey_owner is needed to determine if there is reference data. + """ + # Initialize built-in builds if necessary. + if not self.available_genomes: + self._init_references( trans ) + + # Look for key in built-in builds. + if dbkey in self.available_genomes: + # There is built-in reference data. + return True + + # Look for key in owner's custom builds. + if dbkey_owner and 'dbkeys' in dbkey_owner.preferences: + user_keys = from_json_string( dbkey_owner.preferences[ 'dbkeys' ] ) + if dbkey in user_keys: + dbkey_attributes = user_keys[ dbkey ] + if 'fasta' in dbkey_attributes: + # Fasta + converted datasets can provide reference data. + return True + + return False + + def reference( self, trans, dbkey, chrom, low, high, **kwargs ): + """ + Return reference data for a build. + """ + + # If there is no dbkey owner, default to current user. + dbkey_owner, dbkey = decode_dbkey( dbkey ) + if dbkey_owner: + dbkey_user = trans.sa_session.query( trans.app.model.User ).filter_by( username=dbkey_owner ).first() + else: + dbkey_user = trans.user + + if not self.has_reference_data( trans, dbkey, dbkey_user ): + return None + + # + # Get twobit file with reference data. + # + twobit_file_name = None + if dbkey in self.available_genomes: + # Built-in twobit. + twobit_file_name = self.available_genomes[dbkey] + else: + user_keys = from_json_string( dbkey_user.preferences['dbkeys'] ) + dbkey_attributes = user_keys[ dbkey ] + fasta_dataset = trans.app.model.HistoryDatasetAssociation.get( dbkey_attributes[ 'fasta' ] ) + error = self._convert_dataset( trans, fasta_dataset, 'twobit' ) + if error: + return error + else: + twobit_dataset = fasta_dataset.get_converted_dataset( trans, 'twobit' ) + twobit_file_name = twobit_dataset.file_name + + # Read and return reference data. + try: + twobit = TwoBitFile( open( twobit_file_name ) ) + if chrom in twobit: + seq_data = twobit[chrom].get( int(low), int(high) ) + return { 'dataset_type': 'refseq', 'data': seq_data } + except IOError: + return None + + ## FIXME: copied from tracks.py (tracks controller) - this should be consolidated when possible. + def _convert_dataset( self, trans, dataset, target_type ): + """ + Converts a dataset to the target_type and returns a message indicating + status of the conversion. None is returned to indicate that dataset + was converted successfully. + """ + + # Get converted dataset; this will start the conversion if necessary. + try: + converted_dataset = dataset.get_converted_dataset( trans, target_type ) + except NoConverterException: + return messages.NO_CONVERTER + except ConverterDependencyException, dep_error: + return { 'kind': messages.ERROR, 'message': dep_error.value } + + # Check dataset state and return any messages. + msg = None + if converted_dataset and converted_dataset.state == model.Dataset.states.ERROR: + job_id = trans.sa_session.query( trans.app.model.JobToOutputDatasetAssociation ) \ + .filter_by( dataset_id=converted_dataset.id ).first().job_id + job = trans.sa_session.query( trans.app.model.Job ).get( job_id ) + msg = { 'kind': messages.ERROR, 'message': job.stderr } + elif not converted_dataset or converted_dataset.state != model.Dataset.states.OK: + msg = messages.PENDING + + return msg + \ No newline at end of file diff -r 98cf8f2506493a468135f3d00e92233f5bfbf387 -r c22bb0df586a95eae52701a7b44a678aed002b8e lib/galaxy/web/controllers/tracks.py --- a/lib/galaxy/web/controllers/tracks.py +++ b/lib/galaxy/web/controllers/tracks.py @@ -5,7 +5,6 @@ import re, pkg_resources pkg_resources.require( "bx-python" ) -from bx.seq.twobit import TwoBitFile from galaxy import model from galaxy.util.json import to_json_string, from_json_string from galaxy.web.base.controller import * @@ -16,6 +15,7 @@ from galaxy.datatypes.interval import Gff, Bed from galaxy.model import NoConverterException, ConverterDependencyException from galaxy.visualization.tracks.data_providers import * +from galaxy.visualization.tracks.genomes import decode_dbkey, Genomes from galaxy.visualization.tracks.visual_analytics import get_tool_def, get_dataset_job # Message strings returned to browser @@ -30,13 +30,6 @@ OK = "ok" ) -def _decode_dbkey( dbkey ): - """ Decodes dbkey and returns tuple ( username, dbkey )""" - if ':' in dbkey: - return dbkey.split( ':' ) - else: - return None, dbkey - class NameColumn( grids.TextColumn ): def get_value( self, trans, grid, history ): return history.get_display_name() @@ -99,7 +92,7 @@ def filter( self, trans, user, query, dbkey ): """ Filter by dbkey; datasets without a dbkey are returned as well. """ # use raw SQL b/c metadata is a BLOB - dbkey_user, dbkey = _decode_dbkey( dbkey ) + dbkey_user, dbkey = decode_dbkey( dbkey ) dbkey = dbkey.replace("'", "\\'") return query.filter( or_( \ or_( "metadata like '%%\"dbkey\": [\"%s\"]%%'" % dbkey, "metadata like '%%\"dbkey\": \"%s\"%%'" % dbkey ), \ @@ -180,48 +173,11 @@ histories_grid = HistorySelectionGrid() history_datasets_grid = HistoryDatasetsSelectionGrid() tracks_grid = TracksterSelectionGrid() - - available_tracks = None - available_genomes = None - def _init_references( self, trans ): - """ - Create a list of builds that have reference data specified in twobit.loc file. - """ - avail_genomes = {} - for line in open( os.path.join( trans.app.config.tool_data_path, "twobit.loc" ) ): - if line.startswith("#"): continue - val = line.split() - if len(val) == 2: - key, path = val - avail_genomes[key] = path - self.available_genomes = avail_genomes - - def _has_reference_data( self, trans, dbkey, dbkey_owner=None ): - """ - Returns true if there is reference data for the specified dbkey. If dbkey is custom, - dbkey_owner is needed to determine if there is reference data. - """ - # Initialize built-in builds if necessary. - if not self.available_genomes: - self._init_references( trans ) - - # Look for key in built-in builds. - if dbkey in self.available_genomes: - # There is built-in reference data. - return True - - # Look for key in owner's custom builds. - if dbkey_owner and 'dbkeys' in dbkey_owner.preferences: - user_keys = from_json_string( dbkey_owner.preferences[ 'dbkeys' ] ) - if dbkey in user_keys: - dbkey_attributes = user_keys[ dbkey ] - if 'fasta' in dbkey_attributes: - # Fasta + converted datasets can provide reference data. - return True - - return False - + def __init__(self, app ): + BaseUIController.__init__( self, app ) + self.genomes = Genomes( self.app ) + @web.expose @web.require_login() def index( self, trans, **kwargs ): @@ -296,177 +252,11 @@ @web.json def chroms( self, trans, dbkey=None, num=None, chrom=None, low=None ): - """ - Returns a naturally sorted list of chroms/contigs for either a given visualization or a given dbkey. - Use either chrom or low to specify the starting chrom in the return list. - """ - def check_int(s): - if s.isdigit(): - return int(s) - else: - return s - - def split_by_number(s): - return [ check_int(c) for c in re.split('([0-9]+)', s) ] - - # - # Parameter check, setting. - # - if num: - num = int( num ) - else: - num = sys.maxint - - if low: - low = int( low ) - if low < 0: - low = 0 - else: - low = 0 - - # If there is no dbkey owner, default to current user. - dbkey_owner, dbkey = _decode_dbkey( dbkey ) - if dbkey_owner: - dbkey_user = trans.sa_session.query( trans.app.model.User ).filter_by( username=dbkey_owner ).first() - else: - dbkey_user = trans.user - - # - # Get len file. - # - len_file = None - len_ds = None - user_keys = {} - if dbkey_user and 'dbkeys' in dbkey_user.preferences: - user_keys = from_json_string( dbkey_user.preferences['dbkeys'] ) - if dbkey in user_keys: - dbkey_attributes = user_keys[ dbkey ] - if 'fasta' in dbkey_attributes: - build_fasta = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( dbkey_attributes[ 'fasta' ] ) - len_file = build_fasta.get_converted_dataset( trans, 'len' ).file_name - # Backwards compatibility: look for len file directly. - elif 'len' in dbkey_attributes: - len_file = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( user_keys[ dbkey ][ 'len' ] ).file_name - - if not len_file: - len_ds = trans.db_dataset_for( dbkey ) - if not len_ds: - len_file = os.path.join( trans.app.config.len_file_path, "%s.len" % dbkey ) - else: - len_file = len_ds.file_name - - # - # Get chroms data: - # (a) chrom name, len; - # (b) whether there are previous, next chroms; - # (c) index of start chrom. - # - len_file_enumerate = enumerate( open( len_file ) ) - chroms = {} - prev_chroms = False - start_index = 0 - if chrom: - # Use starting chrom to start list. - found = False - count = 0 - for line_num, line in len_file_enumerate: - if line.startswith("#"): - continue - name, len = line.split("\t") - if found: - chroms[ name ] = int( len ) - count += 1 - elif name == chrom: - # Found starting chrom. - chroms[ name ] = int ( len ) - count += 1 - found = True - start_index = line_num - if line_num != 0: - prev_chroms = True - if count >= num: - break - else: - # Use low to start list. - high = low + int( num ) - prev_chroms = ( low != 0 ) - start_index = low - - # Read chrom data from len file. - # TODO: this may be too slow for very large numbers of chroms/contigs, - # but try it out for now. - if not os.path.exists( len_file ): - return None - - for line_num, line in len_file_enumerate: - if line_num < low: - continue - if line_num >= high: - break - if line.startswith("#"): - continue - # LEN files have format: - # <chrom_name><tab><chrom_length> - fields = line.split("\t") - chroms[ fields[0] ] = int( fields[1] ) - - # Set flag to indicate whether there are more chroms after list. - next_chroms = False - try: - len_file_enumerate.next() - next_chroms = True - except: - # No more chroms to read. - pass - - to_sort = [{ 'chrom': chrom, 'len': length } for chrom, length in chroms.iteritems()] - to_sort.sort(lambda a,b: cmp( split_by_number(a['chrom']), split_by_number(b['chrom']) )) - return { 'reference': self._has_reference_data( trans, dbkey, dbkey_user ), 'chrom_info': to_sort, - 'prev_chroms' : prev_chroms, 'next_chroms' : next_chroms, 'start_index' : start_index } + return self.genomes.chroms( trans, dbkey=dbkey, num=num, chrom=chrom, low=low ) @web.json def reference( self, trans, dbkey, chrom, low, high, **kwargs ): - """ - Return reference data for a build. - """ - - # If there is no dbkey owner, default to current user. - dbkey_owner, dbkey = _decode_dbkey( dbkey ) - if dbkey_owner: - dbkey_user = trans.sa_session.query( trans.app.model.User ).filter_by( username=dbkey_owner ).first() - else: - dbkey_user = trans.user - - if not self._has_reference_data( trans, dbkey, dbkey_user ): - return None - - # - # Get twobit file with reference data. - # - twobit_file_name = None - if dbkey in self.available_genomes: - # Built-in twobit. - twobit_file_name = self.available_genomes[dbkey] - else: - # From custom build. - user_keys = from_json_string( dbkey_user.preferences['dbkeys'] ) - dbkey_attributes = user_keys[ dbkey ] - fasta_dataset = trans.app.model.HistoryDatasetAssociation.get( dbkey_attributes[ 'fasta' ] ) - error = self._convert_dataset( trans, fasta_dataset, 'twobit' ) - if error: - return error - else: - twobit_dataset = fasta_dataset.get_converted_dataset( trans, 'twobit' ) - twobit_file_name = twobit_dataset.file_name - - # Read and return reference data. - try: - twobit = TwoBitFile( open( twobit_file_name ) ) - if chrom in twobit: - seq_data = twobit[chrom].get( int(low), int(high) ) - return { 'dataset_type': 'refseq', 'data': seq_data } - except IOError: - return None + return self.genomes.reference( trans, dbkey, chrom, low, high, **kwargs ) @web.json def raw_data( self, trans, dataset_id, chrom, low, high, **kwargs ): Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.