galaxy-commits
Threads by month
- ----- 2026 -----
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 15302 discussions
commit/galaxy-central: dan: Fix for detecting Data Manager tool dependencies when installed from a tool shed.
by commits-noreply@bitbucket.org 21 May '13
by commits-noreply@bitbucket.org 21 May '13
21 May '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d8259d7fcba0/
Changeset: d8259d7fcba0
User: dan
Date: 2013-05-21 22:21:17
Summary: Fix for detecting Data Manager tool dependencies when installed from a tool shed.
Affected #: 2 files
diff -r 856800d4c91546d51948176f4b78a7bd4b1a1b8b -r d8259d7fcba011f1d97eb808d7812346d0ef8739 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -952,6 +952,8 @@
self.version = None
# Enable easy access to this tool's version lineage.
self.lineage_ids = []
+ #populate toolshed repository info, if available
+ self.populate_tool_shed_info()
# Parse XML element containing configuration
self.parse( root, guid=guid )
self.external_runJob_script = app.config.drmaa_external_runjob_script
@@ -1775,6 +1777,17 @@
version = requirement_elem.get( "version", None )
requirement = ToolRequirement( name=name, type=type, version=version )
self.requirements.append( requirement )
+
+ def populate_tool_shed_info( self ):
+ if self.repository_id is not None and 'ToolShedRepository' in self.app.model:
+ repository_id = self.app.security.decode_id( self.repository_id )
+ tool_shed_repository = self.sa_session.query( self.app.model.ToolShedRepository ).get( repository_id )
+ if tool_shed_repository:
+ self.tool_shed = tool_shed_repository.tool_shed
+ self.repository_name = tool_shed_repository.name
+ self.repository_owner = tool_shed_repository.owner
+ self.installed_changeset_revision = tool_shed_repository.installed_changeset_revision
+
def check_workflow_compatible( self, root ):
"""
Determine if a tool can be used in workflows. External tools and the
diff -r 856800d4c91546d51948176f4b78a7bd4b1a1b8b -r d8259d7fcba011f1d97eb808d7812346d0ef8739 lib/galaxy/tools/data_manager/manager.py
--- a/lib/galaxy/tools/data_manager/manager.py
+++ b/lib/galaxy/tools/data_manager/manager.py
@@ -9,6 +9,7 @@
from galaxy.util.odict import odict
from galaxy.util.template import fill_template
from galaxy.tools.data import TabularToolDataTable
+import tool_shed.util.shed_util_common as suc
#set up logger
import logging
@@ -113,12 +114,20 @@
self.guid = elem.get( 'guid', None )
path = elem.get( 'tool_file', None )
self.version = elem.get( 'version', self.version )
+ tool_shed_repository_id = None
tool_guid = None
if path is None:
tool_elem = elem.find( 'tool' )
assert tool_elem is not None, "Error loading tool for data manager. Make sure that a tool_file attribute or a tool tag set has been defined:\n%s" % ( util.xml_to_string( elem ) )
path = tool_elem.get( "file", None )
tool_guid = tool_elem.get( "guid", None )
+ #need to determine repository info so that dependencies will work correctly
+ tool_shed = tool_elem.find( 'tool_shed' ).text
+ repository_name = tool_elem.find( 'repository_name' ).text
+ repository_owner = tool_elem.find( 'repository_owner' ).text
+ installed_changeset_revision = tool_elem.find( 'installed_changeset_revision' ).text
+ tool_shed_repository = suc.get_tool_shed_repository_by_shed_name_owner_installed_changeset_revision( self.data_managers.app, tool_shed, repository_name, repository_owner, installed_changeset_revision )
+ tool_shed_repository_id = self.data_managers.app.security.encode_id( tool_shed_repository.id )
#use shed_conf_file to determine tool_path
shed_conf_file = elem.get( "shed_conf_file", None )
if shed_conf_file:
@@ -126,7 +135,7 @@
if shed_conf:
tool_path = shed_conf.get( "tool_path", tool_path )
assert path is not None, "A tool file path could not be determined:\n%s" % ( util.xml_to_string( elem ) )
- self.load_tool( os.path.join( tool_path, path ), guid=tool_guid, data_manager_id=self.id )
+ self.load_tool( os.path.join( tool_path, path ), guid=tool_guid, data_manager_id=self.id, tool_shed_repository_id=tool_shed_repository_id )
self.name = elem.get( 'name', self.tool.name )
self.description = elem.get( 'description', self.tool.description )
@@ -180,8 +189,8 @@
@property
def id( self ):
return self.guid or self.declared_id #if we have a guid, we will use that as the data_manager id
- def load_tool( self, tool_filename, guid=None, data_manager_id=None ):
- tool = self.data_managers.app.toolbox.load_tool( tool_filename, guid=guid, data_manager_id=data_manager_id )
+ def load_tool( self, tool_filename, guid=None, data_manager_id=None, tool_shed_repository_id=None ):
+ tool = self.data_managers.app.toolbox.load_tool( tool_filename, guid=guid, data_manager_id=data_manager_id, repository_id=tool_shed_repository_id )
self.data_managers.app.toolbox.data_manager_tools[ tool.id ] = tool
self.data_managers.app.toolbox.tools_by_id[ tool.id ] = tool
self.tool = tool
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.
1
0
commit/galaxy-central: Dave Bouvier: Add the ability to define a list of repositories or changeset revisions of repositories that should not be tested by the automated testing framework.
by commits-noreply@bitbucket.org 21 May '13
by commits-noreply@bitbucket.org 21 May '13
21 May '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/856800d4c915/
Changeset: 856800d4c915
User: Dave Bouvier
Date: 2013-05-21 22:02:21
Summary: Add the ability to define a list of repositories or changeset revisions of repositories that should not be tested by the automated testing framework.
Affected #: 1 file
diff -r fe0905ea52874c451303f5e60d5158387695aaef -r 856800d4c91546d51948176f4b78a7bd4b1a1b8b test/install_and_test_tool_shed_repositories/functional_tests.py
--- a/test/install_and_test_tool_shed_repositories/functional_tests.py
+++ b/test/install_and_test_tool_shed_repositories/functional_tests.py
@@ -129,6 +129,7 @@
galaxy_tool_shed_url = os.environ.get( 'GALAXY_INSTALL_TEST_TOOL_SHED_URL', None )
tool_shed_api_key = os.environ.get( 'GALAXY_INSTALL_TEST_TOOL_SHED_API_KEY', None )
+exclude_list_file = os.environ.get( 'GALAXY_INSTALL_TEST_EXCLUDE_REPOSITORIES', 'install_test_exclude.xml' )
if tool_shed_api_key is None:
print "This script requires the GALAXY_INSTALL_TEST_TOOL_SHED_API_KEY environment variable to be set and non-empty."
@@ -243,6 +244,13 @@
extended_dict[ 'latest_revision' ] = str( latest_changeset_revision )
return extended_dict
+def get_repository_tuple_from_elem( elem ):
+ attributes = elem.attrib
+ name = attributes.get( 'name', None )
+ owner = attributes.get( 'owner', None )
+ changeset_revision = attributes.get( 'changeset_revision', None )
+ return ( name, owner, changeset_revision )
+
def get_repositories_to_install( tool_shed_url, latest_revision_only=True ):
'''
Get a list of repository info dicts to install. This method expects a json list of dicts with the following structure:
@@ -266,6 +274,7 @@
skip_tool_test='false' ) )
api_url = get_api_url( base=tool_shed_url, parts=[ 'repository_revisions' ], params=params )
base_repository_list = json_from_url( api_url )
+ log.info( 'The api returned %d metadata revisions.', len( base_repository_list ) )
known_repository_ids = {}
detailed_repository_list = []
for repository_to_install_dict in base_repository_list:
@@ -336,6 +345,49 @@
raise
return parsed_json
+def parse_exclude_list( xml_filename ):
+ '''
+ This method should return a list with the following structure:
+ [
+ {
+ 'reason': The default reason or the reason specified in this section,
+ 'repositories':
+ [
+ ( name, owner, changeset revision if changeset revision else None ),
+ ( name, owner, changeset revision if changeset revision else None )
+ ]
+ },
+ {
+ 'reason': The default reason or the reason specified in this section,
+ 'repositories':
+ [
+ ( name, owner, changeset revision if changeset revision else None ),
+ ( name, owner, changeset revision if changeset revision else None )
+ ]
+ },
+ ]
+ '''
+ exclude_list = []
+ xml_tree = parse_xml( xml_filename )
+ tool_sheds = xml_tree.findall( 'repositories' )
+ xml_element = None
+ for tool_shed in tool_sheds:
+ if galaxy_tool_shed_url != tool_shed.attrib[ 'tool_shed' ]:
+ continue
+ else:
+ xml_element = tool_shed
+ for reason_section in xml_element:
+ print reason_section
+ reason_text = reason_section.find( 'text' ).text
+ repositories = reason_section.findall( 'repository' )
+ exclude_dict = dict( reason=reason_text, repositories=[] )
+ for repository in repositories:
+ repository_tuple = get_repository_tuple_from_elem( repository )
+ if repository_tuple not in exclude_dict[ 'repositories' ]:
+ exclude_dict[ 'repositories' ].append( repository_tuple )
+ exclude_list.append( exclude_dict )
+ return exclude_list
+
def register_test_result( url, metadata_id, test_results_dict, repository_info_dict, params ):
'''
Update the repository metadata tool_test_results and appropriate flags using the API.
@@ -566,6 +618,10 @@
repositories_passed = []
repositories_failed = []
repositories_failed_install = []
+ exclude_list = []
+ if os.path.exists( exclude_list_file ):
+ exclude_list = parse_exclude_list( exclude_list_file )
+ log.info( exclude_list )
try:
# Get a list of repositories to test from the tool shed specified in the GALAXY_INSTALL_TEST_TOOL_SHED_URL environment variable.
log.info( "Retrieving repositories to install from the URL:\n%s\n", str( galaxy_tool_shed_url ) )
@@ -623,8 +679,43 @@
# Get the name and owner out of the repository info dict.
name = str( repository_info_dict[ 'name' ] )
owner = str( repository_info_dict[ 'owner' ] )
- log.info( "Installing and testing revision %s of repository id %s (%s/%s)...",
- str( changeset_revision ), str( repository_id ), owner, name )
+ # Populate the repository_status dict now.
+ repository_status = get_tool_test_results_from_api( galaxy_tool_shed_url, metadata_revision_id )
+ if 'test_environment' not in repository_status:
+ repository_status[ 'test_environment' ] = {}
+ test_environment = get_test_environment( repository_status[ 'test_environment' ] )
+ test_environment[ 'galaxy_database_version' ] = get_database_version( app )
+ test_environment[ 'galaxy_revision'] = get_repository_current_revision( os.getcwd() )
+ repository_status[ 'test_environment' ] = test_environment
+ repository_status[ 'passed_tests' ] = []
+ repository_status[ 'failed_tests' ] = []
+ repository_status[ 'skip_reason' ] = None
+ # Iterate through the list of repositories defined not to be installed. This should be a list of dicts in the following format:
+ # {
+ # 'reason': The default reason or the reason specified in this section,
+ # 'repositories':
+ # [
+ # ( name, owner, changeset revision if changeset revision else None ),
+ # ( name, owner, changeset revision if changeset revision else None )
+ # ]
+ # },
+ # If changeset revision is None, that means the entire repository is excluded from testing, otherwise only the specified
+ # revision should be skipped.
+ # TODO: When a repository is selected to be skipped, use the API to update the tool shed with the defined skip reason.
+ skip_this_repository = False
+ skip_because = None
+ for exclude_by_reason in exclude_list:
+ reason = exclude_by_reason[ 'reason' ]
+ exclude_repositories = exclude_by_reason[ 'repositories' ]
+ if ( name, owner, changeset_revision ) in exclude_repositories or ( name, owner, None ) in exclude_repositories:
+ skip_this_repository = True
+ skip_because = reason
+ break
+ if skip_this_repository:
+ log.info( "Not testing revision %s of repository %s owned by %s.", changeset_revision, name, owner )
+ continue
+ else:
+ log.info( "Installing and testing revision %s of repository %s owned by %s...", changeset_revision, name, owner )
# Explicitly clear tests from twill's test environment.
remove_generated_tests( app )
# Use the repository information dict to generate an install method that will install the repository into the embedded
@@ -638,15 +729,6 @@
# repository, with tool and repository dependencies also selected for installation.
result, _ = run_tests( test_config )
success = result.wasSuccessful()
- repository_status = get_tool_test_results_from_api( galaxy_tool_shed_url, metadata_revision_id )
- if 'test_environment' not in repository_status:
- repository_status[ 'test_environment' ] = {}
- test_environment = get_test_environment( repository_status[ 'test_environment' ] )
- test_environment[ 'galaxy_database_version' ] = get_database_version( app )
- test_environment[ 'galaxy_revision'] = get_repository_current_revision( os.getcwd() )
- repository_status[ 'test_environment' ] = test_environment
- repository_status[ 'passed_tests' ] = []
- repository_status[ 'failed_tests' ] = []
repository_status[ 'installation_errors' ] = dict( current_repository=[], repository_dependencies=[], tool_dependencies=[] )
try:
repository = test_db_util.get_installed_repository_by_name_owner_changeset_revision( name, owner, changeset_revision )
@@ -750,16 +832,19 @@
# If the repository does not have a test-data directory, any functional tests in the tool configuration will
# fail. Mark the repository as failed and skip installation.
log.error( 'Test data is missing for this repository. Updating repository and skipping functional tests.' )
- # Record the lack of test data.
- for tool in repository.metadata[ 'tools' ]:
- tool_id = tool[ 'id' ]
- tool_version = tool[ 'version' ]
- tool_guid = tool[ 'guid' ]
- # In keeping with the standard display layout, add the error message to the dict for each tool individually.
- missing_components = dict( tool_id=tool_id, tool_version=tool_version, tool_guid=tool_guid,
- missing_components="Repository %s is missing a test-data directory." % name )
- if missing_components not in repository_status[ 'missing_test_components' ]:
- repository_status[ 'missing_test_components' ].append( missing_components )
+ # Record the lack of test data if the repository metadata defines tools.
+ if 'tools' in repository.metadata:
+ for tool in repository.metadata[ 'tools' ]:
+ tool_id = tool[ 'id' ]
+ tool_version = tool[ 'version' ]
+ tool_guid = tool[ 'guid' ]
+ # In keeping with the standard display layout, add the error message to the dict for each tool individually.
+ missing_components = dict( tool_id=tool_id, tool_version=tool_version, tool_guid=tool_guid,
+ missing_components="Repository %s is missing a test-data directory." % name )
+ if missing_components not in repository_status[ 'missing_test_components' ]:
+ repository_status[ 'missing_test_components' ].append( missing_components )
+ else:
+ continue
# Record the status of this repository in the tool shed.
set_do_not_test = not is_latest_downloadable_revision( galaxy_tool_shed_url, repository_info_dict )
params[ 'tools_functionally_correct' ] = False
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.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/00e6a69ed1c4/
Changeset: 00e6a69ed1c4
Branch: next-stable
User: Dave Bouvier
Date: 2013-05-21 21:53:42
Summary: Fix for repositories incorrectly being displayed in the list of repositories with failing tool tests.
Affected #: 1 file
diff -r ea8d92515d42321592e77842387290dcc1190a2b -r 00e6a69ed1c4f34e68ab89ca03462e47c23b71c4 lib/tool_shed/grids/repository_grids.py
--- a/lib/tool_shed/grids/repository_grids.py
+++ b/lib/tool_shed/grids/repository_grids.py
@@ -1650,6 +1650,7 @@
tip_ctx = str( repo.changectx( repo.changelog.tip() ) )
repository_metadata = get_latest_installable_repository_metadata_if_it_includes_tools( trans, repository )
if repository_metadata \
+ and repository_metadata.tool_test_results is not None \
and not repository_metadata.missing_test_components \
and not repository_metadata.tools_functionally_correct \
and not repository_metadata.test_install_error:
https://bitbucket.org/galaxy/galaxy-central/commits/fe0905ea5287/
Changeset: fe0905ea5287
User: Dave Bouvier
Date: 2013-05-21 21:54:20
Summary: Merge in fix from next-stable.
Affected #: 1 file
diff -r 342617fcad86f6948dabaf136fe0c04a83212aad -r fe0905ea52874c451303f5e60d5158387695aaef lib/tool_shed/grids/repository_grids.py
--- a/lib/tool_shed/grids/repository_grids.py
+++ b/lib/tool_shed/grids/repository_grids.py
@@ -1650,6 +1650,7 @@
tip_ctx = str( repo.changectx( repo.changelog.tip() ) )
repository_metadata = get_latest_installable_repository_metadata_if_it_includes_tools( trans, repository )
if repository_metadata \
+ and repository_metadata.tool_test_results is not None \
and not repository_metadata.missing_test_components \
and not repository_metadata.tools_functionally_correct \
and not repository_metadata.test_install_error:
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.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/ea8d92515d42/
Changeset: ea8d92515d42
Branch: next-stable
User: carlfeberhard
Date: 2013-05-21 21:19:33
Summary: History: add simple profiling method
Affected #: 3 files
diff -r 6b59809541ce4766efd1d044fbdee86a954746c4 -r ea8d92515d42321592e77842387290dcc1190a2b lib/galaxy/util/debugging.py
--- a/lib/galaxy/util/debugging.py
+++ b/lib/galaxy/util/debugging.py
@@ -1,6 +1,7 @@
import inspect
import pprint
+import time
import logging
log = logging.getLogger( __name__ )
@@ -27,3 +28,39 @@
stack_list.append( line_format.format( **caller_data ) )
return '\n'.join( stack_list )
+
+
+class SimpleProfiler( object ):
+ """
+ Simple profiler that captures the duration between calls to `report`
+ and stores the results in a list.
+ """
+ REPORT_FORMAT = '%20f: %s'
+
+ def __init__( self, log=None ):
+ self.log = log
+ self.start_time = 0
+ self.reports = []
+
+ def start( self, msg=None ):
+ msg = msg or 'Start'
+ self.start_time = time.time()
+ report = self.REPORT_FORMAT %( self.start_time, msg )
+ self.reports.append( report )
+ if self.log:
+ self.log( report )
+
+ def report( self, msg ):
+ if not self.start_time:
+ self.start()
+ duration = time.time() - self.start_time
+ report = self.REPORT_FORMAT %( duration, msg )
+ self.reports.append( report )
+ if self.log:
+ self.log( report )
+
+ def get_reports( self ):
+ return self.reports
+
+ def __str__( self ):
+ return '\n'.join( self.reports )
diff -r 6b59809541ce4766efd1d044fbdee86a954746c4 -r ea8d92515d42321592e77842387290dcc1190a2b lib/galaxy/webapps/galaxy/controllers/root.py
--- a/lib/galaxy/webapps/galaxy/controllers/root.py
+++ b/lib/galaxy/webapps/galaxy/controllers/root.py
@@ -2,7 +2,6 @@
Contains the main interface in the Universe class
"""
import cgi
-import logging
import os
import urllib
@@ -15,6 +14,9 @@
from galaxy.web.base.controller import BaseUIController, UsesHistoryDatasetAssociationMixin, UsesHistoryMixin
from galaxy.util.json import to_json_string
+from galaxy.util.debugging import SimpleProfiler
+
+import logging
log = logging.getLogger( __name__ )
class RootController( BaseUIController, UsesHistoryMixin, UsesHistoryDatasetAssociationMixin, UsesAnnotations ):
@@ -176,6 +178,73 @@
history_json = to_json_string( history_dictionary ), hda_json = to_json_string( hda_dictionaries ),
show_deleted=show_deleted, show_hidden=show_hidden, hda_id=hda_id, log=log, message=message, status=status )
+ @web.expose
+ def profile_history( self, trans, as_xml=False, show_deleted=None, show_hidden=None, hda_id=None, **kwd ):
+ """
+ Same as above but adds SimpleProfiler to get some
+ profiling times for the operations done.
+ """
+ if as_xml:
+ return self.history_as_xml( trans,
+ show_deleted=string_as_bool( show_deleted ), show_hidden=string_as_bool( show_hidden ) )
+
+ # get all datasets server-side, client-side will get flags and render appropriately
+ show_deleted = string_as_bool_or_none( show_deleted )
+ show_purged = show_deleted
+ show_hidden = string_as_bool_or_none( show_hidden )
+ params = Params( kwd )
+ message = params.get( 'message', '' )
+ #TODO: ugh...
+ message = message if message != 'None' else ''
+ status = params.get( 'status', 'done' )
+
+ if trans.app.config.require_login and not trans.user:
+ return trans.fill_template( '/no_access.mako', message = 'Please log in to access Galaxy histories.' )
+
+ def err_msg( where=None ):
+ where = where if where else 'getting the history data from the server'
+ err_msg = ( 'An error occurred %s. '
+ + 'Please contact a Galaxy administrator if the problem persists.' ) %( where )
+ return err_msg, 'error'
+
+ profiler = SimpleProfiler()
+ profiler.start()
+
+ history_dictionary = {}
+ hda_dictionaries = []
+ try:
+ history = trans.get_history( create=True )
+ profiler.report( 'trans.get_history' )
+ hdas = self.get_history_datasets( trans, history,
+ show_deleted=True, show_hidden=True, show_purged=True )
+ profiler.report( 'get_history_datasets' )
+
+ for hda in hdas:
+ try:
+ hda_dictionaries.append( self.get_hda_dict( trans, hda ) )
+ profiler.report( '\t hda -> dictionary (%s)' %( hda.name ) )
+
+ except Exception, exc:
+ # don't fail entire list if hda err's, record and move on
+ log.error( 'Error bootstrapping hda %d: %s', hda.id, str( exc ), exc_info=True )
+ hda_dictionaries.append( self.get_hda_dict_with_error( trans, hda, str( exc ) ) )
+ profiler.report( 'hdas -> dictionaries' )
+
+ # re-use the hdas above to get the history data...
+ history_dictionary = self.get_history_dict( trans, history, hda_dictionaries=hda_dictionaries )
+ profiler.report( 'history -> dictionary' )
+
+ except Exception, exc:
+ user_id = str( trans.user.id ) if trans.user else '(anonymous)'
+ log.error( 'Error bootstrapping history for user %s: %s', user_id, str( exc ), exc_info=True )
+ message, status = err_msg()
+ history_dictionary[ 'error' ] = message
+
+ return trans.stream_template_mako( "root/history.mako",
+ history_json = to_json_string( history_dictionary ), hda_json = to_json_string( hda_dictionaries ),
+ show_deleted=show_deleted, show_hidden=show_hidden, hda_id=hda_id, log=log, message=message, status=status,
+ profiling=profiler.get_reports() )
+
## ---- Dataset display / editing ----------------------------------------
@web.expose
def display( self, trans, id=None, hid=None, tofile=None, toext=".txt", **kwd ):
diff -r 6b59809541ce4766efd1d044fbdee86a954746c4 -r ea8d92515d42321592e77842387290dcc1190a2b templates/webapps/galaxy/root/history.mako
--- a/templates/webapps/galaxy/root/history.mako
+++ b/templates/webapps/galaxy/root/history.mako
@@ -213,6 +213,10 @@
galaxyPageSetUp();
// ostensibly, this is the App
+ %if 'profiling' in self.context.kwargs:
+ Galaxy.profiling = ${h.to_json_string( profiling )}.join( '\n' );
+ %endif
+
//NOTE: for debugging on non-local instances (main/test)
// 1. load history panel in own tab
// 2. from console: new PersistantStorage( '__history_panel' ).set( 'debugging', true )
https://bitbucket.org/galaxy/galaxy-central/commits/342617fcad86/
Changeset: 342617fcad86
User: carlfeberhard
Date: 2013-05-21 21:20:03
Summary: merge next-stable
Affected #: 3 files
diff -r cbc1808b261b662f8dc9682b31f86c9b6c429bbd -r 342617fcad86f6948dabaf136fe0c04a83212aad lib/galaxy/util/debugging.py
--- a/lib/galaxy/util/debugging.py
+++ b/lib/galaxy/util/debugging.py
@@ -1,6 +1,7 @@
import inspect
import pprint
+import time
import logging
log = logging.getLogger( __name__ )
@@ -27,3 +28,39 @@
stack_list.append( line_format.format( **caller_data ) )
return '\n'.join( stack_list )
+
+
+class SimpleProfiler( object ):
+ """
+ Simple profiler that captures the duration between calls to `report`
+ and stores the results in a list.
+ """
+ REPORT_FORMAT = '%20f: %s'
+
+ def __init__( self, log=None ):
+ self.log = log
+ self.start_time = 0
+ self.reports = []
+
+ def start( self, msg=None ):
+ msg = msg or 'Start'
+ self.start_time = time.time()
+ report = self.REPORT_FORMAT %( self.start_time, msg )
+ self.reports.append( report )
+ if self.log:
+ self.log( report )
+
+ def report( self, msg ):
+ if not self.start_time:
+ self.start()
+ duration = time.time() - self.start_time
+ report = self.REPORT_FORMAT %( duration, msg )
+ self.reports.append( report )
+ if self.log:
+ self.log( report )
+
+ def get_reports( self ):
+ return self.reports
+
+ def __str__( self ):
+ return '\n'.join( self.reports )
diff -r cbc1808b261b662f8dc9682b31f86c9b6c429bbd -r 342617fcad86f6948dabaf136fe0c04a83212aad lib/galaxy/webapps/galaxy/controllers/root.py
--- a/lib/galaxy/webapps/galaxy/controllers/root.py
+++ b/lib/galaxy/webapps/galaxy/controllers/root.py
@@ -2,7 +2,6 @@
Contains the main interface in the Universe class
"""
import cgi
-import logging
import os
import urllib
@@ -15,6 +14,9 @@
from galaxy.web.base.controller import BaseUIController, UsesHistoryDatasetAssociationMixin, UsesHistoryMixin
from galaxy.util.json import to_json_string
+from galaxy.util.debugging import SimpleProfiler
+
+import logging
log = logging.getLogger( __name__ )
class RootController( BaseUIController, UsesHistoryMixin, UsesHistoryDatasetAssociationMixin, UsesAnnotations ):
@@ -176,6 +178,73 @@
history_json = to_json_string( history_dictionary ), hda_json = to_json_string( hda_dictionaries ),
show_deleted=show_deleted, show_hidden=show_hidden, hda_id=hda_id, log=log, message=message, status=status )
+ @web.expose
+ def profile_history( self, trans, as_xml=False, show_deleted=None, show_hidden=None, hda_id=None, **kwd ):
+ """
+ Same as above but adds SimpleProfiler to get some
+ profiling times for the operations done.
+ """
+ if as_xml:
+ return self.history_as_xml( trans,
+ show_deleted=string_as_bool( show_deleted ), show_hidden=string_as_bool( show_hidden ) )
+
+ # get all datasets server-side, client-side will get flags and render appropriately
+ show_deleted = string_as_bool_or_none( show_deleted )
+ show_purged = show_deleted
+ show_hidden = string_as_bool_or_none( show_hidden )
+ params = Params( kwd )
+ message = params.get( 'message', '' )
+ #TODO: ugh...
+ message = message if message != 'None' else ''
+ status = params.get( 'status', 'done' )
+
+ if trans.app.config.require_login and not trans.user:
+ return trans.fill_template( '/no_access.mako', message = 'Please log in to access Galaxy histories.' )
+
+ def err_msg( where=None ):
+ where = where if where else 'getting the history data from the server'
+ err_msg = ( 'An error occurred %s. '
+ + 'Please contact a Galaxy administrator if the problem persists.' ) %( where )
+ return err_msg, 'error'
+
+ profiler = SimpleProfiler()
+ profiler.start()
+
+ history_dictionary = {}
+ hda_dictionaries = []
+ try:
+ history = trans.get_history( create=True )
+ profiler.report( 'trans.get_history' )
+ hdas = self.get_history_datasets( trans, history,
+ show_deleted=True, show_hidden=True, show_purged=True )
+ profiler.report( 'get_history_datasets' )
+
+ for hda in hdas:
+ try:
+ hda_dictionaries.append( self.get_hda_dict( trans, hda ) )
+ profiler.report( '\t hda -> dictionary (%s)' %( hda.name ) )
+
+ except Exception, exc:
+ # don't fail entire list if hda err's, record and move on
+ log.error( 'Error bootstrapping hda %d: %s', hda.id, str( exc ), exc_info=True )
+ hda_dictionaries.append( self.get_hda_dict_with_error( trans, hda, str( exc ) ) )
+ profiler.report( 'hdas -> dictionaries' )
+
+ # re-use the hdas above to get the history data...
+ history_dictionary = self.get_history_dict( trans, history, hda_dictionaries=hda_dictionaries )
+ profiler.report( 'history -> dictionary' )
+
+ except Exception, exc:
+ user_id = str( trans.user.id ) if trans.user else '(anonymous)'
+ log.error( 'Error bootstrapping history for user %s: %s', user_id, str( exc ), exc_info=True )
+ message, status = err_msg()
+ history_dictionary[ 'error' ] = message
+
+ return trans.stream_template_mako( "root/history.mako",
+ history_json = to_json_string( history_dictionary ), hda_json = to_json_string( hda_dictionaries ),
+ show_deleted=show_deleted, show_hidden=show_hidden, hda_id=hda_id, log=log, message=message, status=status,
+ profiling=profiler.get_reports() )
+
## ---- Dataset display / editing ----------------------------------------
@web.expose
def display( self, trans, id=None, hid=None, tofile=None, toext=".txt", **kwd ):
diff -r cbc1808b261b662f8dc9682b31f86c9b6c429bbd -r 342617fcad86f6948dabaf136fe0c04a83212aad templates/webapps/galaxy/root/history.mako
--- a/templates/webapps/galaxy/root/history.mako
+++ b/templates/webapps/galaxy/root/history.mako
@@ -213,6 +213,10 @@
galaxyPageSetUp();
// ostensibly, this is the App
+ %if 'profiling' in self.context.kwargs:
+ Galaxy.profiling = ${h.to_json_string( profiling )}.join( '\n' );
+ %endif
+
//NOTE: for debugging on non-local instances (main/test)
// 1. load history panel in own tab
// 2. from console: new PersistantStorage( '__history_panel' ).set( 'debugging', true )
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.
1
0
21 May '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/cbc1808b261b/
Changeset: cbc1808b261b
User: jgoecks
Date: 2013-05-21 20:38:30
Summary: Merge in next-stable.
Affected #: 7 files
diff -r 9065758599a411615e24ffd9374a18d302f95a09 -r cbc1808b261b662f8dc9682b31f86c9b6c429bbd lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -1662,6 +1662,7 @@
# other model classes.
hda = self
rval = dict( id = hda.id,
+ hda_ldda = 'hda',
uuid = ( lambda uuid: str( uuid ) if uuid else None )( hda.dataset.uuid ),
hid = hda.hid,
file_ext = hda.ext,
@@ -2078,6 +2079,7 @@
except OSError:
file_size = 0
rval = dict( id = ldda.id,
+ hda_ldda = 'ldda',
model_class = self.__class__.__name__,
name = ldda.name,
deleted = ldda.deleted,
diff -r 9065758599a411615e24ffd9374a18d302f95a09 -r cbc1808b261b662f8dc9682b31f86c9b6c429bbd lib/galaxy/webapps/galaxy/controllers/visualization.py
--- a/lib/galaxy/webapps/galaxy/controllers/visualization.py
+++ b/lib/galaxy/webapps/galaxy/controllers/visualization.py
@@ -832,7 +832,8 @@
# Add genome-wide data to each track in viz.
tracks = viz_config.get( 'tracks', [] )
for track in tracks:
- dataset = self.get_hda_or_ldda( trans, track[ 'hda_ldda'], track[ 'dataset_id' ] )
+ dataset_dict = track[ 'dataset' ]
+ dataset = self.get_hda_or_ldda( trans, dataset_dict[ 'hda_ldda'], dataset_dict[ 'id' ] )
genome_data = self._get_genome_data( trans, dataset, dbkey )
if not isinstance( genome_data, str ):
diff -r 9065758599a411615e24ffd9374a18d302f95a09 -r cbc1808b261b662f8dc9682b31f86c9b6c429bbd static/scripts/packed/viz/circster.js
--- a/static/scripts/packed/viz/circster.js
+++ b/static/scripts/packed/viz/circster.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","libs/d3","viz/visualization"],function(g,l,i){var m=Backbone.Model.extend({is_visible:function(q,n){var o=q.getBoundingClientRect(),p=$("svg")[0].getBoundingClientRect();if(o.right<0||o.left>p.right||o.bottom<0||o.top>p.bottom){return false}return true}});var h={drawTicks:function(r,q,v,p,n){var u=r.append("g").selectAll("g").data(q).enter().append("g").selectAll("g").data(v).enter().append("g").attr("class","tick").attr("transform",function(w){return"rotate("+(w.angle*180/Math.PI-90)+")translate("+w.radius+",0)"});var t=[],s=[],o=function(w){return w.angle>Math.PI?"end":null};if(n){t=[0,0,0,-4];s=[4,0,"",".35em"];o=null}else{t=[1,0,4,0];s=[0,4,".35em",""]}u.append("line").attr("x1",t[0]).attr("y1",t[1]).attr("x2",t[2]).attr("y1",t[3]).style("stroke","#000");u.append("text").attr("x",s[0]).attr("y",s[1]).attr("dx",s[2]).attr("dy",s[3]).attr("text-anchor",o).attr("transform",p).text(function(w){return w.label})},formatNum:function(o,n){if(n===undefined){n=2}var q=null;if(o<1){q=o.toPrecision(n)}else{var p=Math.round(o.toPrecision(n));if(o<1000){q=p}else{if(o<1000000){q=Math.round((p/1000).toPrecision(3)).toFixed(0)+"K"}else{if(o<1000000000){q=Math.round((p/1000000).toPrecision(3)).toFixed(0)+"M"}}}}return q}};var c=Backbone.Model.extend({});var a=Backbone.View.extend({className:"circster",initialize:function(n){this.total_gap=n.total_gap;this.genome=n.genome;this.dataset_arc_height=n.dataset_arc_height;this.track_gap=10;this.label_arc_height=50;this.scale=1;this.circular_views=null;this.chords_views=null;this.model.get("tracks").on("add",this.add_track,this);this.model.get("tracks").on("remove",this.remove_track,this);this.get_circular_tracks()},get_circular_tracks:function(){return this.model.get("tracks").filter(function(n){return n.get("track_type")!=="DiagonalHeatmapTrack"})},get_chord_tracks:function(){return this.model.get("tracks").filter(function(n){return n.get("track_type")==="DiagonalHeatmapTrack"})},get_tracks_bounds:function(){var o=this.get_circular_tracks();dataset_arc_height=this.dataset_arc_height,min_dimension=Math.min(this.$el.width(),this.$el.height()),radius_start=min_dimension/2-o.length*(this.dataset_arc_height+this.track_gap)-(this.label_arc_height+this.track_gap),tracks_start_radii=l.range(radius_start,min_dimension/2,this.dataset_arc_height+this.track_gap);var n=this;return g.map(tracks_start_radii,function(p){return[p,p+n.dataset_arc_height]})},render:function(){var w=this,q=this.dataset_arc_height,n=w.$el.width(),v=w.$el.height(),s=this.get_circular_tracks(),p=this.get_chord_tracks(),r=this.get_tracks_bounds(),o=l.select(w.$el[0]).append("svg").attr("width",n).attr("height",v).attr("pointer-events","all").append("svg:g").call(l.behavior.zoom().on("zoom",function(){var x=l.event.scale;o.attr("transform","translate("+l.event.translate+") scale("+x+")");if(w.scale!==x){if(w.zoom_drag_timeout){clearTimeout(w.zoom_drag_timeout)}w.zoom_drag_timeout=setTimeout(function(){},400)}})).attr("transform","translate("+n/2+","+v/2+")").append("svg:g").attr("class","tracks");this.circular_views=s.map(function(y,z){var A=(y.get("track_type")==="LineTrack"?d:e),x=new A({el:o.append("g")[0],track:y,radius_bounds:r[z],genome:w.genome,total_gap:w.total_gap});x.render();return x});this.chords_views=p.map(function(y){var x=new j({el:o.append("g")[0],track:y,radius_bounds:r[0],genome:w.genome,total_gap:w.total_gap});x.render();return x});var u=this.circular_views[this.circular_views.length-1].radius_bounds[1],t=[u,u+this.label_arc_height];this.label_track_view=new b({el:o.append("g")[0],track:new c(),radius_bounds:t,genome:w.genome,total_gap:w.total_gap});this.label_track_view.render()},add_track:function(t){if(t.get("track_type")==="DiagonalHeatmapTrack"){var p=this.circular_views[0].radius_bounds,s=new j({el:l.select("g.tracks").append("g")[0],track:t,radius_bounds:p,genome:this.genome,total_gap:this.total_gap});s.render();this.chords_views.push(s)}else{var r=this.get_tracks_bounds();g.each(this.circular_views,function(v,w){v.update_radius_bounds(r[w])});g.each(this.chords_views,function(v){v.update_radius_bounds(r[0])});var q=this.circular_views.length,u=(t.get("track_type")==="LineTrack"?d:e),n=new u({el:l.select("g.tracks").append("g")[0],track:t,radius_bounds:r[q],genome:this.genome,total_gap:this.total_gap});n.render();this.circular_views.push(n);var o=r[r.length-1];o[1]=o[0];this.label_track_view.update_radius_bounds(o)}},remove_track:function(o,q,p){var n=this.circular_views[p.index];this.circular_views.splice(p.index,1);n.$el.remove();var r=this.get_tracks_bounds();g.each(this.circular_views,function(s,t){s.update_radius_bounds(r[t])})}});var k=Backbone.View.extend({tagName:"g",initialize:function(n){this.bg_stroke="ccc";this.loading_bg_fill="000";this.bg_fill="ccc";this.total_gap=n.total_gap;this.track=n.track;this.radius_bounds=n.radius_bounds;this.genome=n.genome;this.chroms_layout=this._chroms_layout();this.data_bounds=[];this.scale=1;this.parent_elt=l.select(this.$el[0])},get_fill_color:function(){var n=this.track.get("config").get_value("block_color");if(!n){n=this.track.get("config").get_value("color")}return n},render:function(){var r=this.parent_elt;if(!r){console.log("no parent elt")}var q=this.chroms_layout,t=l.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]),n=r.selectAll("g").data(q).enter().append("svg:g"),p=n.append("path").attr("d",t).attr("class","chrom-background").style("stroke",this.bg_stroke).style("fill",this.loading_bg_fill);p.append("title").text(function(v){return v.data.chrom});var o=this,s=o.track.get("data_manager"),u=(s?s.data_is_ready():true);$.when(u).then(function(){$.when(o._render_data(r)).then(function(){p.style("fill",o.bg_fill);o.render_labels()})})},render_labels:function(){},update_radius_bounds:function(o){this.radius_bounds=o;var n=l.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]);this.parent_elt.selectAll("g>path.chrom-background").transition().duration(1000).attr("d",n);this._transition_chrom_data();this._transition_labels()},update_scale:function(q){var p=this.scale;this.scale=q;if(q<=p){return}var o=this,n=new m();this.parent_elt.selectAll("path.chrom-data").filter(function(s,r){return n.is_visible(this)}).each(function(x,t){var w=l.select(this),s=w.attr("chrom"),v=o.genome.get_chrom_region(s),u=o.track.get("data_manager"),r;if(!u.can_get_more_detailed_data(v)){return}r=o.track.get("data_manager").get_more_detailed_data(v,"Coverage",0,q);$.when(r).then(function(A){w.remove();o._update_data_bounds();var z=g.find(o.chroms_layout,function(B){return B.data.chrom===s});var y=o.get_fill_color();o._render_chrom_data(o.parent_elt,z,A).style("stroke",y).style("fill",y)})});return o},_transition_chrom_data:function(){var o=this.track,q=this.chroms_layout,n=this.parent_elt.selectAll("g>path.chrom-data"),r=n[0].length;if(r>0){var p=this;$.when(o.get("data_manager").get_genome_wide_data(this.genome)).then(function(t){var s=g.reject(g.map(t,function(u,v){var w=null,x=p._get_path_function(q[v],u);if(x){w=x(u.data)}return w}),function(u){return u===null});n.each(function(v,u){l.select(this).transition().duration(1000).attr("d",s[u])})})}},_transition_labels:function(){},_update_data_bounds:function(){var n=this.data_bounds;this.data_bounds=this.get_data_bounds(this.track.get("data_manager").get_genome_wide_data(this.genome));if(this.data_bounds[0]<n[0]||this.data_bounds[1]>n[1]){this._transition_chrom_data()}},_render_data:function(q){var p=this,o=this.chroms_layout,n=this.track,r=$.Deferred();$.when(n.get("data_manager").get_genome_wide_data(this.genome)).then(function(t){p.data_bounds=p.get_data_bounds(t);layout_and_data=g.zip(o,t),chroms_data_layout=g.map(layout_and_data,function(u){var v=u[0],w=u[1];return p._render_chrom_data(q,v,w)});var s=p.get_fill_color();p.parent_elt.selectAll("path.chrom-data").style("stroke",s).style("fill",s);r.resolve(q)});return r},_render_chrom_data:function(n,o,p){},_get_path_function:function(o,n){},_chroms_layout:function(){var o=this.genome.get_chroms_info(),q=l.layout.pie().value(function(s){return s.len}).sort(null),r=q(o),n=this.total_gap/o.length,p=g.map(r,function(u,t){var s=u.endAngle-n;u.endAngle=(s>u.startAngle?s:u.startAngle);return u});return p}});var b=k.extend({initialize:function(n){k.prototype.initialize.call(this,n);this.innerRadius=this.radius_bounds[0];this.radius_bounds[0]=this.radius_bounds[1];this.bg_stroke="fff";this.bg_fill="fff";this.min_arc_len=0.08},_render_data:function(p){var o=this,n=p.selectAll("g");n.selectAll("path").attr("id",function(t){return"label-"+t.data.chrom});n.append("svg:text").filter(function(t){return t.endAngle-t.startAngle>o.min_arc_len}).attr("text-anchor","middle").append("svg:textPath").attr("xlink:href",function(t){return"#label-"+t.data.chrom}).attr("startOffset","25%").attr("font-weight","bold").text(function(t){return t.data.chrom});var q=function(v){var t=(v.endAngle-v.startAngle)/v.value,u=l.range(0,v.value,25000000).map(function(w,x){return{radius:o.innerRadius,angle:w*t+v.startAngle,label:x===0?0:(x%3?null:o.formatNum(w))}});if(u.length<4){u[u.length-1].label=o.formatNum(Math.round((u[u.length-1].angle-v.startAngle)/t))}return u};var s=function(t){return t.angle>Math.PI?"rotate(180)translate(-16)":null};var r=g.filter(this.chroms_layout,function(t){return t.endAngle-t.startAngle>o.min_arc_len});this.drawTicks(this.parent_elt,r,q,s)}});g.extend(b.prototype,h);var f=k.extend({_quantile:function(o,n){o.sort(l.ascending);return l.quantile(o,n)},_render_chrom_data:function(n,q,o){var r=this._get_path_function(q,o);if(!r){return null}var p=n.datum(o.data),s=p.append("path").attr("class","chrom-data").attr("chrom",q.data.chrom).attr("d",r);return s},_get_path_function:function(q,p){if(typeof p==="string"||!p.data||p.data.length===0){return null}var n=l.scale.linear().domain(this.data_bounds).range(this.radius_bounds).clamp(true);var r=l.scale.linear().domain([0,p.data.length]).range([q.startAngle,q.endAngle]);var o=l.svg.line.radial().interpolate("linear").radius(function(s){return n(s[1])}).angle(function(t,s){return r(s)});return l.svg.area.radial().interpolate(o.interpolate()).innerRadius(n(0)).outerRadius(o.radius()).angle(o.angle())},render_labels:function(){var n=this,q=function(){return"rotate(90)"};var p=g.filter(this.chroms_layout,function(r){return r.endAngle-r.startAngle>0.08}),o=g.filter(p,function(s,r){return r%3===0});this.drawTicks(this.parent_elt,o,this._data_bounds_ticks_fn(),q,true)},_transition_labels:function(){if(this.data_bounds.length===0){return}var o=this,q=g.filter(this.chroms_layout,function(r){return r.endAngle-r.startAngle>0.08}),p=g.filter(q,function(s,r){return r%3===0}),n=g.flatten(g.map(p,function(r){return o._data_bounds_ticks_fn()(r)}));this.parent_elt.selectAll("g.tick").data(n).transition().attr("transform",function(r){return"rotate("+(r.angle*180/Math.PI-90)+")translate("+r.radius+",0)"})},_data_bounds_ticks_fn:function(){var n=this;visibleChroms=0;return function(o){return[{radius:n.radius_bounds[0],angle:o.startAngle,label:n.formatNum(n.data_bounds[0])},{radius:n.radius_bounds[1],angle:o.startAngle,label:n.formatNum(n.data_bounds[1])}]}},get_data_bounds:function(n){}});g.extend(f.prototype,h);var e=f.extend({get_data_bounds:function(o){var n=g.map(o,function(p){if(typeof p==="string"||!p.max){return 0}return p.max});return[0,(n&&typeof n!=="string"?this._quantile(n,0.98):0)]}});var d=f.extend({get_data_bounds:function(o){var n=g.flatten(g.map(o,function(p){if(p){return g.map(p.data,function(q){return q[1]})}else{return 0}}));return[g.min(n),this._quantile(n,0.98)]}});var j=k.extend({render:function(){var n=this;$.when(n.track.get("data_manager").data_is_ready()).then(function(){$.when(n.track.get("data_manager").get_genome_wide_data(n.genome)).then(function(q){var p=[],o=n.genome.get_chroms_info();g.each(q,function(u,t){var r=o[t].chrom;var s=g.map(u.data,function(w){var v=n._get_region_angle(r,w[1]),x=n._get_region_angle(w[3],w[4]);return{source:{startAngle:v,endAngle:v+0.01},target:{startAngle:x,endAngle:x+0.01}}});p=p.concat(s)});n.parent_elt.append("g").attr("class","chord").selectAll("path").data(p).enter().append("path").style("fill",n.get_fill_color()).attr("d",l.svg.chord().radius(n.radius_bounds[0])).style("opacity",1)})})},update_radius_bounds:function(n){this.radius_bounds=n;this.parent_elt.selectAll("path").transition().attr("d",l.svg.chord().radius(this.radius_bounds[0]))},_get_region_angle:function(p,n){var o=g.find(this.chroms_layout,function(q){return q.data.chrom===p});return o.endAngle-((o.endAngle-o.startAngle)*(o.data.len-n)/o.data.len)}});return{CircsterView:a}});
\ No newline at end of file
+define(["libs/underscore","libs/d3","viz/visualization"],function(f,k,h){var l=Backbone.Model.extend({is_visible:function(p,m){var n=p.getBoundingClientRect(),o=$("svg")[0].getBoundingClientRect();if(n.right<0||n.left>o.right||n.bottom<0||n.top>o.bottom){return false}return true}});var g={drawTicks:function(q,p,u,o,m){var t=q.append("g").selectAll("g").data(p).enter().append("g").selectAll("g").data(u).enter().append("g").attr("class","tick").attr("transform",function(v){return"rotate("+(v.angle*180/Math.PI-90)+")translate("+v.radius+",0)"});var s=[],r=[],n=function(v){return v.angle>Math.PI?"end":null};if(m){s=[0,0,0,-4];r=[4,0,"",".35em"];n=null}else{s=[1,0,4,0];r=[0,4,".35em",""]}t.append("line").attr("x1",s[0]).attr("y1",s[1]).attr("x2",s[2]).attr("y1",s[3]).style("stroke","#000");t.append("text").attr("x",r[0]).attr("y",r[1]).attr("dx",r[2]).attr("dy",r[3]).attr("text-anchor",n).attr("transform",o).text(function(v){return v.label})},formatNum:function(n,m){if(m===undefined){m=2}var p=null;if(n<1){p=n.toPrecision(m)}else{var o=Math.round(n.toPrecision(m));if(n<1000){p=o}else{if(n<1000000){p=Math.round((o/1000).toPrecision(3)).toFixed(0)+"K"}else{if(n<1000000000){p=Math.round((o/1000000).toPrecision(3)).toFixed(0)+"M"}}}}return p}};var c=Backbone.Model.extend({});var a=Backbone.View.extend({className:"circster",initialize:function(m){this.total_gap=m.total_gap;this.genome=m.genome;this.dataset_arc_height=m.dataset_arc_height;this.track_gap=10;this.label_arc_height=50;this.scale=1;this.circular_views=null;this.chords_views=null;this.model.get("tracks").on("add",this.add_track,this);this.model.get("tracks").on("remove",this.remove_track,this);this.get_circular_tracks()},get_circular_tracks:function(){return this.model.get("tracks").filter(function(m){return m.get("track_type")!=="DiagonalHeatmapTrack"})},get_chord_tracks:function(){return this.model.get("tracks").filter(function(m){return m.get("track_type")==="DiagonalHeatmapTrack"})},get_tracks_bounds:function(){var n=this.get_circular_tracks();dataset_arc_height=this.dataset_arc_height,min_dimension=Math.min(this.$el.width(),this.$el.height()),radius_start=min_dimension/2-n.length*(this.dataset_arc_height+this.track_gap)-(this.label_arc_height+this.track_gap),tracks_start_radii=k.range(radius_start,min_dimension/2,this.dataset_arc_height+this.track_gap);var m=this;return f.map(tracks_start_radii,function(o){return[o,o+m.dataset_arc_height]})},render:function(){var v=this,p=this.dataset_arc_height,m=v.$el.width(),u=v.$el.height(),r=this.get_circular_tracks(),o=this.get_chord_tracks(),q=this.get_tracks_bounds(),n=k.select(v.$el[0]).append("svg").attr("width",m).attr("height",u).attr("pointer-events","all").append("svg:g").call(k.behavior.zoom().on("zoom",function(){var w=k.event.scale;n.attr("transform","translate("+k.event.translate+") scale("+w+")");if(v.scale!==w){if(v.zoom_drag_timeout){clearTimeout(v.zoom_drag_timeout)}v.zoom_drag_timeout=setTimeout(function(){},400)}})).attr("transform","translate("+m/2+","+u/2+")").append("svg:g").attr("class","tracks");this.circular_views=r.map(function(x,y){var w=new d({el:n.append("g")[0],track:x,radius_bounds:q[y],genome:v.genome,total_gap:v.total_gap});w.render();return w});this.chords_views=o.map(function(x){var w=new i({el:n.append("g")[0],track:x,radius_bounds:q[0],genome:v.genome,total_gap:v.total_gap});w.render();return w});var t=this.circular_views[this.circular_views.length-1].radius_bounds[1],s=[t,t+this.label_arc_height];this.label_track_view=new b({el:n.append("g")[0],track:new c(),radius_bounds:s,genome:v.genome,total_gap:v.total_gap});this.label_track_view.render()},add_track:function(s){if(s.get("track_type")==="DiagonalHeatmapTrack"){var o=this.circular_views[0].radius_bounds,r=new i({el:k.select("g.tracks").append("g")[0],track:s,radius_bounds:o,genome:this.genome,total_gap:this.total_gap});r.render();this.chords_views.push(r)}else{var q=this.get_tracks_bounds();f.each(this.circular_views,function(t,u){t.update_radius_bounds(q[u])});f.each(this.chords_views,function(t){t.update_radius_bounds(q[0])});var p=this.circular_views.length,m=new d({el:k.select("g.tracks").append("g")[0],track:s,radius_bounds:q[p],genome:this.genome,total_gap:this.total_gap});m.render();this.circular_views.push(m);var n=q[q.length-1];n[1]=n[0];this.label_track_view.update_radius_bounds(n)}},remove_track:function(n,p,o){var m=this.circular_views[o.index];this.circular_views.splice(o.index,1);m.$el.remove();var q=this.get_tracks_bounds();f.each(this.circular_views,function(r,s){r.update_radius_bounds(q[s])})}});var j=Backbone.View.extend({tagName:"g",initialize:function(m){this.bg_stroke="ccc";this.loading_bg_fill="000";this.bg_fill="ccc";this.total_gap=m.total_gap;this.track=m.track;this.radius_bounds=m.radius_bounds;this.genome=m.genome;this.chroms_layout=this._chroms_layout();this.data_bounds=[];this.scale=1;this.parent_elt=k.select(this.$el[0])},get_fill_color:function(){var m=this.track.get("config").get_value("block_color");if(!m){m=this.track.get("config").get_value("color")}return m},render:function(){var q=this.parent_elt;if(!q){console.log("no parent elt")}var p=this.chroms_layout,s=k.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]),m=q.selectAll("g").data(p).enter().append("svg:g"),o=m.append("path").attr("d",s).attr("class","chrom-background").style("stroke",this.bg_stroke).style("fill",this.loading_bg_fill);o.append("title").text(function(u){return u.data.chrom});var n=this,r=n.track.get("data_manager"),t=(r?r.data_is_ready():true);$.when(t).then(function(){$.when(n._render_data(q)).then(function(){o.style("fill",n.bg_fill);n.render_labels()})})},render_labels:function(){},update_radius_bounds:function(n){this.radius_bounds=n;var m=k.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]);this.parent_elt.selectAll("g>path.chrom-background").transition().duration(1000).attr("d",m);this._transition_chrom_data();this._transition_labels()},update_scale:function(p){var o=this.scale;this.scale=p;if(p<=o){return}var n=this,m=new l();this.parent_elt.selectAll("path.chrom-data").filter(function(r,q){return m.is_visible(this)}).each(function(w,s){var v=k.select(this),r=v.attr("chrom"),u=n.genome.get_chrom_region(r),t=n.track.get("data_manager"),q;if(!t.can_get_more_detailed_data(u)){return}q=n.track.get("data_manager").get_more_detailed_data(u,"Coverage",0,p);$.when(q).then(function(z){v.remove();n._update_data_bounds();var y=f.find(n.chroms_layout,function(A){return A.data.chrom===r});var x=n.get_fill_color();n._render_chrom_data(n.parent_elt,y,z).style("stroke",x).style("fill",x)})});return n},_transition_chrom_data:function(){var n=this.track,p=this.chroms_layout,m=this.parent_elt.selectAll("g>path.chrom-data"),q=m[0].length;if(q>0){var o=this;$.when(n.get("data_manager").get_genome_wide_data(this.genome)).then(function(s){var r=f.reject(f.map(s,function(t,u){var v=null,w=o._get_path_function(p[u],t);if(w){v=w(t.data)}return v}),function(t){return t===null});m.each(function(u,t){k.select(this).transition().duration(1000).attr("d",r[t])})})}},_transition_labels:function(){},_update_data_bounds:function(){var m=this.data_bounds;this.data_bounds=this.get_data_bounds(this.track.get("data_manager").get_genome_wide_data(this.genome));if(this.data_bounds[0]<m[0]||this.data_bounds[1]>m[1]){this._transition_chrom_data()}},_render_data:function(p){var o=this,n=this.chroms_layout,m=this.track,q=$.Deferred();$.when(m.get("data_manager").get_genome_wide_data(this.genome)).then(function(s){o.data_bounds=o.get_data_bounds(s);layout_and_data=f.zip(n,s),chroms_data_layout=f.map(layout_and_data,function(t){var u=t[0],v=t[1];return o._render_chrom_data(p,u,v)});var r=o.get_fill_color();o.parent_elt.selectAll("path.chrom-data").style("stroke",r).style("fill",r);q.resolve(p)});return q},_render_chrom_data:function(m,n,o){},_get_path_function:function(n,m){},_chroms_layout:function(){var n=this.genome.get_chroms_info(),p=k.layout.pie().value(function(r){return r.len}).sort(null),q=p(n),m=this.total_gap/n.length,o=f.map(q,function(t,s){var r=t.endAngle-m;t.endAngle=(r>t.startAngle?r:t.startAngle);return t});return o}});var b=j.extend({initialize:function(m){j.prototype.initialize.call(this,m);this.innerRadius=this.radius_bounds[0];this.radius_bounds[0]=this.radius_bounds[1];this.bg_stroke="fff";this.bg_fill="fff";this.min_arc_len=0.08},_render_data:function(o){var n=this,m=o.selectAll("g");m.selectAll("path").attr("id",function(s){return"label-"+s.data.chrom});m.append("svg:text").filter(function(s){return s.endAngle-s.startAngle>n.min_arc_len}).attr("text-anchor","middle").append("svg:textPath").attr("xlink:href",function(s){return"#label-"+s.data.chrom}).attr("startOffset","25%").attr("font-weight","bold").text(function(s){return s.data.chrom});var p=function(u){var s=(u.endAngle-u.startAngle)/u.value,t=k.range(0,u.value,25000000).map(function(w,x){return{radius:n.innerRadius,angle:w*s+u.startAngle,label:x===0?0:(x%3?null:n.formatNum(w))}});if(t.length<4){t[t.length-1].label=n.formatNum(Math.round((t[t.length-1].angle-u.startAngle)/s))}return t};var r=function(s){return s.angle>Math.PI?"rotate(180)translate(-16)":null};var q=f.filter(this.chroms_layout,function(s){return s.endAngle-s.startAngle>n.min_arc_len});this.drawTicks(this.parent_elt,q,p,r)}});f.extend(b.prototype,g);var e=j.extend({_quantile:function(n,m){n.sort(k.ascending);return k.quantile(n,m)},_render_chrom_data:function(m,p,n){var q=this._get_path_function(p,n);if(!q){return null}var o=m.datum(n.data),r=o.append("path").attr("class","chrom-data").attr("chrom",p.data.chrom).attr("d",q);return r},_get_path_function:function(p,o){if(typeof o==="string"||!o.data||o.data.length===0){return null}var m=k.scale.linear().domain(this.data_bounds).range(this.radius_bounds).clamp(true);var q=k.scale.linear().domain([0,o.data.length]).range([p.startAngle,p.endAngle]);var n=k.svg.line.radial().interpolate("linear").radius(function(r){return m(r[1])}).angle(function(s,r){return q(r)});return k.svg.area.radial().interpolate(n.interpolate()).innerRadius(m(0)).outerRadius(n.radius()).angle(n.angle())},render_labels:function(){var m=this,p=function(){return"rotate(90)"};var o=f.filter(this.chroms_layout,function(q){return q.endAngle-q.startAngle>0.08}),n=f.filter(o,function(r,q){return q%3===0});this.drawTicks(this.parent_elt,n,this._data_bounds_ticks_fn(),p,true)},_transition_labels:function(){if(this.data_bounds.length===0){return}var n=this,p=f.filter(this.chroms_layout,function(q){return q.endAngle-q.startAngle>0.08}),o=f.filter(p,function(r,q){return q%3===0}),m=f.flatten(f.map(o,function(q){return n._data_bounds_ticks_fn()(q)}));this.parent_elt.selectAll("g.tick").data(m).transition().attr("transform",function(q){return"rotate("+(q.angle*180/Math.PI-90)+")translate("+q.radius+",0)"})},_data_bounds_ticks_fn:function(){var m=this;visibleChroms=0;return function(n){return[{radius:m.radius_bounds[0],angle:n.startAngle,label:m.formatNum(m.data_bounds[0])},{radius:m.radius_bounds[1],angle:n.startAngle,label:m.formatNum(m.data_bounds[1])}]}},get_data_bounds:function(m){}});f.extend(e.prototype,g);var d=e.extend({get_data_bounds:function(n){var m=f.flatten(f.map(n,function(o){if(o){return f.map(o.data,function(q){return q[1]})}else{return 0}}));return[f.min(m),this._quantile(m,0.98)]}});var i=j.extend({render:function(){var m=this;$.when(m.track.get("data_manager").data_is_ready()).then(function(){$.when(m.track.get("data_manager").get_genome_wide_data(m.genome)).then(function(p){var o=[],n=m.genome.get_chroms_info();f.each(p,function(t,s){var q=n[s].chrom;var r=f.map(t.data,function(v){var u=m._get_region_angle(q,v[1]),w=m._get_region_angle(v[3],v[4]);return{source:{startAngle:u,endAngle:u+0.01},target:{startAngle:w,endAngle:w+0.01}}});o=o.concat(r)});m.parent_elt.append("g").attr("class","chord").selectAll("path").data(o).enter().append("path").style("fill",m.get_fill_color()).attr("d",k.svg.chord().radius(m.radius_bounds[0])).style("opacity",1)})})},update_radius_bounds:function(m){this.radius_bounds=m;this.parent_elt.selectAll("path").transition().attr("d",k.svg.chord().radius(this.radius_bounds[0]))},_get_region_angle:function(o,m){var n=f.find(this.chroms_layout,function(p){return p.data.chrom===o});return n.endAngle-((n.endAngle-n.startAngle)*(n.data.len-m)/n.data.len)}});return{CircsterView:a}});
\ No newline at end of file
diff -r 9065758599a411615e24ffd9374a18d302f95a09 -r cbc1808b261b662f8dc9682b31f86c9b6c429bbd static/scripts/packed/viz/visualization.js
--- a/static/scripts/packed/viz/visualization.js
+++ b/static/scripts/packed/viz/visualization.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","mvc/data","viz/trackster/util","utils/config"],function(s,i,l,o){var a=function(u,x,w,v){$.ajax({url:u,data:w,error:function(){alert("Grid failed")},success:function(y){show_modal("Select datasets for new tracks",y,{Cancel:function(){hide_modal()},Add:function(){var z=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var A={data_type:"track_config",hda_ldda:"hda"},B=$(this).val();if($(this).attr("name")!=="id"){A.hda_ldda="ldda"}z[z.length]=$.ajax({url:x+"/"+B,data:A,dataType:"json"})});$.when.apply($,z).then(function(){var A=(arguments[0] instanceof Array?$.map(arguments,function(B){return B[0]}):[arguments[0]]);v(A)});hide_modal()}})}})};var j=function(u){return("isResolved" in u)};var f=function(u){this.default_font=u!==undefined?u:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};s.extend(f.prototype,{load_pattern:function(u,y){var v=this.patterns,w=this.dummy_context,x=new Image();x.src=galaxy_paths.attributes.image_path+y;x.onload=function(){v[u]=w.createPattern(x,"repeat")}},get_pattern:function(u){return this.patterns[u]},new_canvas:function(){var u=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(u)}u.manager=this;return u}});var q=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(u){this.clear()},get_elt:function(v){var w=this.attributes.obj_cache,x=this.attributes.key_ary,u=x.indexOf(v);if(u!==-1){if(w[v].stale){x.splice(u,1);delete w[v]}else{this.move_key_to_end(v,u)}}return w[v]},set_elt:function(v,x){var y=this.attributes.obj_cache,z=this.attributes.key_ary,w=this.attributes.num_elements;if(!y[v]){if(z.length>=w){var u=z.shift();delete y[u]}z.push(v)}y[v]=x;return x},move_key_to_end:function(v,u){this.attributes.key_ary.splice(u,1);this.attributes.key_ary.push(v)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length},most_recently_added:function(){return this.size()===0?null:this.attributes.key_ary[this.attributes.key_ary.length-1]}});var d=q.extend({defaults:s.extend({},q.prototype.defaults,{dataset:null,genome:null,init_data:null,min_region_size:200,filters_manager:null,data_type:"data",data_mode_compatible:function(u,v){return true},can_subset:function(u){return false}}),initialize:function(u){q.prototype.initialize.call(this);var v=this.get("init_data");if(v){this.add_data(v)}},add_data:function(u){if(this.get("num_elements")<u.length){this.set("num_elements",u.length)}var v=this;s.each(u,function(w){v.set_data(w.region,w)})},data_is_ready:function(){var x=this.get("dataset"),w=$.Deferred(),u=(this.get("data_type")==="raw_data"?"state":this.get("data_type")==="data"?"converted_datasets_state":"error"),v=new l.ServerStateDeferred({ajax_settings:{url:this.get("dataset").url(),data:{hda_ldda:x.get("hda_ldda"),data_type:u},dataType:"json"},interval:5000,success_fn:function(y){return y!=="pending"}});$.when(v.go()).then(function(y){w.resolve(y==="ok"||y==="data")});return w},search_features:function(u){var v=this.get("dataset"),w={query:u,hda_ldda:v.get("hda_ldda"),data_type:"features"};return $.getJSON(v.url(),w)},load_data:function(C,B,v,A){var y=this.get("dataset"),x={data_type:this.get("data_type"),chrom:C.get("chrom"),low:C.get("start"),high:C.get("end"),mode:B,resolution:v,hda_ldda:y.get("hda_ldda")};$.extend(x,A);var E=this.get("filters_manager");if(E){var F=[];var u=E.filters;for(var z=0;z<u.length;z++){F.push(u[z].name)}x.filter_cols=JSON.stringify(F)}var w=this,D=$.getJSON(y.url(),x,function(G){G.region=C;w.set_data(C,G)});this.set_data(C,D);return D},get_data:function(B,A,w,y){var C=this.get_elt(B);if(C&&(j(C)||this.get("data_mode_compatible")(C,A))){return C}var D=this.get("key_ary"),v=this.get("obj_cache"),E,u,z;for(var x=0;x<D.length;x++){E=D[x];u=new g({from_str:E});if(u.contains(B)){z=true;C=v[E];if(j(C)||(this.get("data_mode_compatible")(C,A)&&this.get("can_subset")(C))){this.move_key_to_end(E,x);if(!j(C)){var G=this.subset_entry(C,B);this.set(B,G);C=G}return C}}}if(!z&&B.length()<this.attributes.min_region_size){var F=new g({from_str:this.most_recently_added()});if(!F||(B.get("start")>F.get("start"))){B.set("end",B.get("start")+this.attributes.min_region_size)}else{B.set("start",B.get("end")-this.attributes.min_region_size)}B.set("genome",this.attributes.genome);B.trim()}return this.load_data(B,A,w,y)},set_data:function(v,u){this.set_elt(v,u)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(C,B,x,A,y){var E=this._mark_stale(C);if(!(E&&this.get("data_mode_compatible")(E,B))){console.log("ERROR: problem with getting more data: current data is not compatible");return}var w=C.get("start");if(y===this.DEEP_DATA_REQ){$.extend(A,{start_val:E.data.length+1})}else{if(y===this.BROAD_DATA_REQ){w=(E.max_high?E.max_high:E.data[E.data.length-1][2])+1}}var D=C.copy().set("start",w);var v=this,z=this.load_data(D,B,x,A),u=$.Deferred();this.set_data(C,u);$.when(z).then(function(F){if(F.data){F.data=E.data.concat(F.data);if(F.max_low){F.max_low=E.max_low}if(F.message){F.message=F.message.replace(/[0-9]+/,F.data.length)}}v.set_data(C,F);u.resolve(F)});return u},can_get_more_detailed_data:function(v){var u=this.get_elt(v);return(u.dataset_type==="bigwig"&&u.data.length<8000)},get_more_detailed_data:function(x,z,v,y,w){var u=this._mark_stale(x);if(!u){console.log("ERROR getting more detailed data: no current data");return}if(!w){w={}}if(u.dataset_type==="bigwig"){w.num_samples=1000*y}return this.load_data(x,z,v,w)},_mark_stale:function(v){var u=this.get_elt(v);if(!u){console.log("ERROR: no data to mark as stale: ",this.get("dataset"),v.toString())}u.stale=true;return u},get_genome_wide_data:function(u){var w=this,y=true,x=s.map(u.get("chroms_info").chrom_info,function(A){var z=w.get_elt(new g({chrom:A.chrom,start:0,end:A.len}));if(!z){y=false}return z});if(y){return x}var v=$.Deferred();$.getJSON(this.get("dataset").url(),{data_type:"genome_data"},function(z){w.add_data(z.data);v.resolve(z.data)});return v},subset_entry:function(w,x){var u={bigwig:function(y,z){return s.filter(y,function(A){return A[0]>=z.get("start")&&A[0]<=z.get("end")})},refseq:function(z,A){var B=A.get("start")-w.region.get("start"),y=w.data.length-(w.region.get("end")-A.get("end"));return w.data.slice(B,y)}};var v=w.data;if(!w.region.same(x)&&w.dataset_type in u){v=u[w.dataset_type](w.data,x)}return{region:x,data:v,dataset_type:w.dataset_type}},get_elt:function(u){return q.prototype.get_elt.call(this,u.toString())},set_elt:function(v,u){return q.prototype.set_elt.call(this,v.toString(),u)}});var p=d.extend({initialize:function(u){var v=new Backbone.Model();v.urlRoot=u.data_url;this.set("dataset",v)},load_data:function(w,x,u,v){return(w.length()<=100000?d.prototype.load_data.call(this,w,x,u,v):{data:null,region:w})}});var c=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},initialize:function(u){this.id=u.dbkey},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info},get_chrom_region:function(u){var v=s.find(this.get_chroms_info(),function(w){return w.chrom===u});return new g({chrom:v.chrom,end:v.len})},get_chrom_len:function(u){return s.find(this.get_chroms_info(),function(v){return v.chrom===u}).len}});var g=Backbone.RelationalModel.extend({defaults:{chrom:null,start:0,end:0,genome:null},same:function(u){return this.attributes.chrom===u.get("chrom")&&this.attributes.start===u.get("start")&&this.attributes.end===u.get("end")},initialize:function(v){if(v.from_str){var x=v.from_str.split(":"),w=x[0],u=x[1].split("-");this.set({chrom:w,start:parseInt(u[0],10),end:parseInt(u[1],10)})}},copy:function(){return new g({chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")})},length:function(){return this.get("end")-this.get("start")},toString:function(){return this.get("chrom")+":"+this.get("start")+"-"+this.get("end")},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(B){var v=this.get("chrom"),A=B.get("chrom"),z=this.get("start"),x=B.get("start"),y=this.get("end"),w=B.get("end"),u;if(v&&A&&v!==A){return g.overlap_results.DIF_CHROMS}if(z<x){if(y<x){u=g.overlap_results.BEFORE}else{if(y<w){u=g.overlap_results.OVERLAP_START}else{u=g.overlap_results.CONTAINS}}}else{if(z>x){if(z>w){u=g.overlap_results.AFTER}else{if(y<=w){u=g.overlap_results.CONTAINED_BY}else{u=g.overlap_results.OVERLAP_END}}}else{u=(y>=w?g.overlap_results.CONTAINS:g.overlap_results.CONTAINED_BY)}}return u},trim:function(u){if(this.attributes.start<0){this.attributes.start=0}if(this.attributes.genome){var v=this.attributes.genome.get_chrom_len(this.attributes.chrom);if(this.attributes.end>v){this.attributes.end=v-1}}return this},contains:function(u){return this.compute_overlap(u)===g.overlap_results.CONTAINS},overlaps:function(u){return s.intersection([this.compute_overlap(u)],[g.overlap_results.DIF_CHROMS,g.overlap_results.BEFORE,g.overlap_results.AFTER]).length===0}},{overlap_results:{DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006}});var m=Backbone.Collection.extend({model:g});var e=Backbone.RelationalModel.extend({defaults:{region:null,note:""},relations:[{type:Backbone.HasOne,key:"region",relatedModel:g}]});var r=Backbone.Collection.extend({model:e});var t=i.Dataset.extend({initialize:function(u){this.set("id",u.dataset_id);this.set("config",o.ConfigSettingCollection.from_config_dict(u.prefs));this.get("config").add([{key:"name",value:this.get("name")},{key:"color"}]);var v=this.get("preloaded_data");if(v){v=v.data}else{v=[]}this.set("data_manager",new d({dataset:this,init_data:v}))}});var n=Backbone.RelationalModel.extend({defaults:{title:"",type:""},url:galaxy_paths.get("visualization_url"),save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var k=n.extend({defaults:s.extend({},n.prototype.defaults,{dbkey:"",tracks:null,bookmarks:null,viewport:null}),relations:[{type:Backbone.HasMany,key:"tracks",relatedModel:t}],add_tracks:function(u){this.get("tracks").add(u)}});var b=Backbone.Model.extend({});var h=Backbone.Router.extend({initialize:function(v){this.view=v.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var u=this;u.view.on("navigate",function(w){u.navigate(w)})},change_location:function(u){this.view.go_to(u)}});return{BackboneTrack:t,BrowserBookmark:e,BrowserBookmarkCollection:r,Cache:q,CanvasManager:f,Genome:c,GenomeDataManager:d,GenomeRegion:g,GenomeRegionCollection:m,GenomeVisualization:k,GenomeReferenceDataManager:p,TrackBrowserRouter:h,TrackConfig:b,Visualization:n,select_datasets:a}});
\ No newline at end of file
+define(["libs/underscore","mvc/data","viz/trackster/util","utils/config"],function(s,i,l,o){var a=function(u,x,w,v){$.ajax({url:u,data:w,error:function(){alert("Grid failed")},success:function(y){show_modal("Select datasets for new tracks",y,{Cancel:function(){hide_modal()},Add:function(){var z=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var A={data_type:"track_config",hda_ldda:"hda"},B=$(this).val();if($(this).attr("name")!=="id"){A.hda_ldda="ldda"}z[z.length]=$.ajax({url:x+"/"+B,data:A,dataType:"json"})});$.when.apply($,z).then(function(){var A=(arguments[0] instanceof Array?$.map(arguments,function(B){return B[0]}):[arguments[0]]);v(A)});hide_modal()}})}})};var j=function(u){return("isResolved" in u)};var f=function(u){this.default_font=u!==undefined?u:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};s.extend(f.prototype,{load_pattern:function(u,y){var v=this.patterns,w=this.dummy_context,x=new Image();x.src=galaxy_paths.attributes.image_path+y;x.onload=function(){v[u]=w.createPattern(x,"repeat")}},get_pattern:function(u){return this.patterns[u]},new_canvas:function(){var u=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(u)}u.manager=this;return u}});var q=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(u){this.clear()},get_elt:function(v){var w=this.attributes.obj_cache,x=this.attributes.key_ary,u=x.indexOf(v);if(u!==-1){if(w[v].stale){x.splice(u,1);delete w[v]}else{this.move_key_to_end(v,u)}}return w[v]},set_elt:function(v,x){var y=this.attributes.obj_cache,z=this.attributes.key_ary,w=this.attributes.num_elements;if(!y[v]){if(z.length>=w){var u=z.shift();delete y[u]}z.push(v)}y[v]=x;return x},move_key_to_end:function(v,u){this.attributes.key_ary.splice(u,1);this.attributes.key_ary.push(v)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length},most_recently_added:function(){return this.size()===0?null:this.attributes.key_ary[this.attributes.key_ary.length-1]}});var d=q.extend({defaults:s.extend({},q.prototype.defaults,{dataset:null,genome:null,init_data:null,min_region_size:200,filters_manager:null,data_type:"data",data_mode_compatible:function(u,v){return true},can_subset:function(u){return false}}),initialize:function(u){q.prototype.initialize.call(this);var v=this.get("init_data");if(v){this.add_data(v)}},add_data:function(u){if(this.get("num_elements")<u.length){this.set("num_elements",u.length)}var v=this;s.each(u,function(w){v.set_data(w.region,w)})},data_is_ready:function(){var x=this.get("dataset"),w=$.Deferred(),u=(this.get("data_type")==="raw_data"?"state":this.get("data_type")==="data"?"converted_datasets_state":"error"),v=new l.ServerStateDeferred({ajax_settings:{url:this.get("dataset").url(),data:{hda_ldda:x.get("hda_ldda"),data_type:u},dataType:"json"},interval:5000,success_fn:function(y){return y!=="pending"}});$.when(v.go()).then(function(y){w.resolve(y==="ok"||y==="data")});return w},search_features:function(u){var v=this.get("dataset"),w={query:u,hda_ldda:v.get("hda_ldda"),data_type:"features"};return $.getJSON(v.url(),w)},load_data:function(C,B,v,A){var y=this.get("dataset"),x={data_type:this.get("data_type"),chrom:C.get("chrom"),low:C.get("start"),high:C.get("end"),mode:B,resolution:v,hda_ldda:y.get("hda_ldda")};$.extend(x,A);var E=this.get("filters_manager");if(E){var F=[];var u=E.filters;for(var z=0;z<u.length;z++){F.push(u[z].name)}x.filter_cols=JSON.stringify(F)}var w=this,D=$.getJSON(y.url(),x,function(G){G.region=C;w.set_data(C,G)});this.set_data(C,D);return D},get_data:function(B,A,w,y){var C=this.get_elt(B);if(C&&(j(C)||this.get("data_mode_compatible")(C,A))){return C}var D=this.get("key_ary"),v=this.get("obj_cache"),E,u,z;for(var x=0;x<D.length;x++){E=D[x];u=new g({from_str:E});if(u.contains(B)){z=true;C=v[E];if(j(C)||(this.get("data_mode_compatible")(C,A)&&this.get("can_subset")(C))){this.move_key_to_end(E,x);if(!j(C)){var G=this.subset_entry(C,B);this.set(B,G);C=G}return C}}}if(!z&&B.length()<this.attributes.min_region_size){var F=new g({from_str:this.most_recently_added()});if(!F||(B.get("start")>F.get("start"))){B.set("end",B.get("start")+this.attributes.min_region_size)}else{B.set("start",B.get("end")-this.attributes.min_region_size)}B.set("genome",this.attributes.genome);B.trim()}return this.load_data(B,A,w,y)},set_data:function(v,u){this.set_elt(v,u)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(C,B,x,A,y){var E=this._mark_stale(C);if(!(E&&this.get("data_mode_compatible")(E,B))){console.log("ERROR: problem with getting more data: current data is not compatible");return}var w=C.get("start");if(y===this.DEEP_DATA_REQ){$.extend(A,{start_val:E.data.length+1})}else{if(y===this.BROAD_DATA_REQ){w=(E.max_high?E.max_high:E.data[E.data.length-1][2])+1}}var D=C.copy().set("start",w);var v=this,z=this.load_data(D,B,x,A),u=$.Deferred();this.set_data(C,u);$.when(z).then(function(F){if(F.data){F.data=E.data.concat(F.data);if(F.max_low){F.max_low=E.max_low}if(F.message){F.message=F.message.replace(/[0-9]+/,F.data.length)}}v.set_data(C,F);u.resolve(F)});return u},can_get_more_detailed_data:function(v){var u=this.get_elt(v);return(u.dataset_type==="bigwig"&&u.data.length<8000)},get_more_detailed_data:function(x,z,v,y,w){var u=this._mark_stale(x);if(!u){console.log("ERROR getting more detailed data: no current data");return}if(!w){w={}}if(u.dataset_type==="bigwig"){w.num_samples=1000*y}return this.load_data(x,z,v,w)},_mark_stale:function(v){var u=this.get_elt(v);if(!u){console.log("ERROR: no data to mark as stale: ",this.get("dataset"),v.toString())}u.stale=true;return u},get_genome_wide_data:function(u){var w=this,y=true,x=s.map(u.get("chroms_info").chrom_info,function(A){var z=w.get_elt(new g({chrom:A.chrom,start:0,end:A.len}));if(!z){y=false}return z});if(y){return x}var v=$.Deferred();$.getJSON(this.get("dataset").url(),{data_type:"genome_data"},function(z){w.add_data(z.data);v.resolve(z.data)});return v},subset_entry:function(w,x){var u={bigwig:function(y,z){return s.filter(y,function(A){return A[0]>=z.get("start")&&A[0]<=z.get("end")})},refseq:function(z,A){var B=A.get("start")-w.region.get("start"),y=w.data.length-(w.region.get("end")-A.get("end"));return w.data.slice(B,y)}};var v=w.data;if(!w.region.same(x)&&w.dataset_type in u){v=u[w.dataset_type](w.data,x)}return{region:x,data:v,dataset_type:w.dataset_type}},get_elt:function(u){return q.prototype.get_elt.call(this,u.toString())},set_elt:function(v,u){return q.prototype.set_elt.call(this,v.toString(),u)}});var p=d.extend({initialize:function(u){var v=new Backbone.Model();v.urlRoot=u.data_url;this.set("dataset",v)},load_data:function(w,x,u,v){return(w.length()<=100000?d.prototype.load_data.call(this,w,x,u,v):{data:null,region:w})}});var c=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},initialize:function(u){this.id=u.dbkey},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info},get_chrom_region:function(u){var v=s.find(this.get_chroms_info(),function(w){return w.chrom===u});return new g({chrom:v.chrom,end:v.len})},get_chrom_len:function(u){return s.find(this.get_chroms_info(),function(v){return v.chrom===u}).len}});var g=Backbone.RelationalModel.extend({defaults:{chrom:null,start:0,end:0,genome:null},same:function(u){return this.attributes.chrom===u.get("chrom")&&this.attributes.start===u.get("start")&&this.attributes.end===u.get("end")},initialize:function(v){if(v.from_str){var x=v.from_str.split(":"),w=x[0],u=x[1].split("-");this.set({chrom:w,start:parseInt(u[0],10),end:parseInt(u[1],10)})}},copy:function(){return new g({chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")})},length:function(){return this.get("end")-this.get("start")},toString:function(){return this.get("chrom")+":"+this.get("start")+"-"+this.get("end")},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(B){var v=this.get("chrom"),A=B.get("chrom"),z=this.get("start"),x=B.get("start"),y=this.get("end"),w=B.get("end"),u;if(v&&A&&v!==A){return g.overlap_results.DIF_CHROMS}if(z<x){if(y<x){u=g.overlap_results.BEFORE}else{if(y<w){u=g.overlap_results.OVERLAP_START}else{u=g.overlap_results.CONTAINS}}}else{if(z>x){if(z>w){u=g.overlap_results.AFTER}else{if(y<=w){u=g.overlap_results.CONTAINED_BY}else{u=g.overlap_results.OVERLAP_END}}}else{u=(y>=w?g.overlap_results.CONTAINS:g.overlap_results.CONTAINED_BY)}}return u},trim:function(u){if(this.attributes.start<0){this.attributes.start=0}if(this.attributes.genome){var v=this.attributes.genome.get_chrom_len(this.attributes.chrom);if(this.attributes.end>v){this.attributes.end=v-1}}return this},contains:function(u){return this.compute_overlap(u)===g.overlap_results.CONTAINS},overlaps:function(u){return s.intersection([this.compute_overlap(u)],[g.overlap_results.DIF_CHROMS,g.overlap_results.BEFORE,g.overlap_results.AFTER]).length===0}},{overlap_results:{DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006}});var m=Backbone.Collection.extend({model:g});var e=Backbone.RelationalModel.extend({defaults:{region:null,note:""},relations:[{type:Backbone.HasOne,key:"region",relatedModel:g}]});var r=Backbone.Collection.extend({model:e});var t=Backbone.RelationalModel.extend({relations:[{type:Backbone.HasOne,key:"dataset",relatedModel:i.Dataset}],initialize:function(u){this.set("config",o.ConfigSettingCollection.from_config_dict(u.prefs));this.get("config").add([{key:"name",value:this.get("name")},{key:"color"}]);var v=this.get("preloaded_data");if(v){v=v.data}else{v=[]}this.set("data_manager",new d({dataset:this.get("dataset"),init_data:v}))}});var n=Backbone.RelationalModel.extend({defaults:{title:"",type:""},url:galaxy_paths.get("visualization_url"),save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var k=n.extend({defaults:s.extend({},n.prototype.defaults,{dbkey:"",tracks:null,bookmarks:null,viewport:null}),relations:[{type:Backbone.HasMany,key:"tracks",relatedModel:t}],add_tracks:function(u){this.get("tracks").add(u)}});var b=Backbone.Model.extend({});var h=Backbone.Router.extend({initialize:function(v){this.view=v.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var u=this;u.view.on("navigate",function(w){u.navigate(w)})},change_location:function(u){this.view.go_to(u)}});return{BackboneTrack:t,BrowserBookmark:e,BrowserBookmarkCollection:r,Cache:q,CanvasManager:f,Genome:c,GenomeDataManager:d,GenomeRegion:g,GenomeRegionCollection:m,GenomeVisualization:k,GenomeReferenceDataManager:p,TrackBrowserRouter:h,TrackConfig:b,Visualization:n,select_datasets:a}});
\ No newline at end of file
diff -r 9065758599a411615e24ffd9374a18d302f95a09 -r cbc1808b261b662f8dc9682b31f86c9b6c429bbd static/scripts/viz/circster.js
--- a/static/scripts/viz/circster.js
+++ b/static/scripts/viz/circster.js
@@ -238,10 +238,7 @@
// Create a view for each track in the visualiation and render.
this.circular_views = circular_tracks.map(function(track, index) {
- var track_view_class = (track.get('track_type') === 'LineTrack' ?
- CircsterBigWigTrackView :
- CircsterSummaryTreeTrackView ),
- view = new track_view_class({
+ var view = new CircsterBigWigTrackView({
el: svg.append('g')[0],
track: track,
radius_bounds: tracks_bounds[index],
@@ -324,10 +321,7 @@
// Render new track.
var track_index = this.circular_views.length,
- track_view_class = (new_track.get('track_type') === 'LineTrack' ?
- CircsterBigWigTrackView :
- CircsterSummaryTreeTrackView ),
- track_view = new track_view_class({
+ track_view = new CircsterBigWigTrackView({
el: d3.select('g.tracks').append('g')[0],
track: new_track,
radius_bounds: new_track_bounds[track_index],
@@ -859,22 +853,6 @@
});
_.extend(CircsterQuantitativeTrackView.prototype, UsesTicks);
-
-/**
- * Layout for summary tree data in a circster visualization.
- */
-var CircsterSummaryTreeTrackView = CircsterQuantitativeTrackView.extend({
-
- get_data_bounds: function(data) {
- // Get max across data.
- var max_data = _.map(data, function(d) {
- if (typeof d === 'string' || !d.max) { return 0; }
- return d.max;
- });
- return [ 0, (max_data && typeof max_data !== 'string' ? this._quantile(max_data, 0.98) : 0) ];
- }
-});
-
/**
* Bigwig track view in Circster.
*/
diff -r 9065758599a411615e24ffd9374a18d302f95a09 -r cbc1808b261b662f8dc9682b31f86c9b6c429bbd static/scripts/viz/visualization.js
--- a/static/scripts/viz/visualization.js
+++ b/static/scripts/viz/visualization.js
@@ -861,11 +861,17 @@
* A track of data in a genome visualization.
*/
// TODO: rename to Track and merge with Trackster's Track object.
-var BackboneTrack = data_mod.Dataset.extend({
+var BackboneTrack = Backbone.RelationalModel.extend({
+
+ relations: [
+ {
+ type: Backbone.HasOne,
+ key: 'dataset',
+ relatedModel: data_mod.Dataset
+ }
+ ],
initialize: function(options) {
- // Dataset id is unique ID for now.
- this.set('id', options.dataset_id);
// -- Set up config settings. --
@@ -886,7 +892,7 @@
preloaded_data = [];
}
this.set('data_manager', new GenomeDataManager({
- dataset: this,
+ dataset: this.get('dataset'),
init_data: preloaded_data
}));
}
diff -r 9065758599a411615e24ffd9374a18d302f95a09 -r cbc1808b261b662f8dc9682b31f86c9b6c429bbd templates/webapps/galaxy/visualization/circster.mako
--- a/templates/webapps/galaxy/visualization/circster.mako
+++ b/templates/webapps/galaxy/visualization/circster.mako
@@ -42,8 +42,8 @@
$(function() {
// -- Viz set up. --
- var genome = new visualization_mod.Genome(JSON.parse('${ h.to_json_string( genome ) }'))
- vis = new visualization_mod.GenomeVisualization(JSON.parse('${ h.to_json_string( viz_config ) }')),
+ var genome = new visualization_mod.Genome( ${ h.to_json_string( genome ) } )
+ vis = new visualization_mod.GenomeVisualization( ${ h.to_json_string( viz_config ) } ),
viz_view = new circster.CircsterView({
el: $('#vis'),
// Gap is difficult to set because it very dependent on chromosome size and organization.
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.
1
0
commit/galaxy-central: jgoecks: Viz framework fixes: (a) add hda_ldda attribute to API dicts of HDAs and LDDAs; (b) remove summary tree from Circster; (c) make Circster compatible with recent change to get HDAs from API. Pack scripts.
by commits-noreply@bitbucket.org 21 May '13
by commits-noreply@bitbucket.org 21 May '13
21 May '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/6b59809541ce/
Changeset: 6b59809541ce
Branch: next-stable
User: jgoecks
Date: 2013-05-21 20:37:51
Summary: Viz framework fixes: (a) add hda_ldda attribute to API dicts of HDAs and LDDAs; (b) remove summary tree from Circster; (c) make Circster compatible with recent change to get HDAs from API. Pack scripts.
Affected #: 7 files
diff -r 227dcabcaf83f569c2adf5740acc3c04339c759b -r 6b59809541ce4766efd1d044fbdee86a954746c4 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -1662,6 +1662,7 @@
# other model classes.
hda = self
rval = dict( id = hda.id,
+ hda_ldda = 'hda',
uuid = ( lambda uuid: str( uuid ) if uuid else None )( hda.dataset.uuid ),
hid = hda.hid,
file_ext = hda.ext,
@@ -2078,6 +2079,7 @@
except OSError:
file_size = 0
rval = dict( id = ldda.id,
+ hda_ldda = 'ldda',
model_class = self.__class__.__name__,
name = ldda.name,
deleted = ldda.deleted,
diff -r 227dcabcaf83f569c2adf5740acc3c04339c759b -r 6b59809541ce4766efd1d044fbdee86a954746c4 lib/galaxy/webapps/galaxy/controllers/visualization.py
--- a/lib/galaxy/webapps/galaxy/controllers/visualization.py
+++ b/lib/galaxy/webapps/galaxy/controllers/visualization.py
@@ -832,7 +832,8 @@
# Add genome-wide data to each track in viz.
tracks = viz_config.get( 'tracks', [] )
for track in tracks:
- dataset = self.get_hda_or_ldda( trans, track[ 'hda_ldda'], track[ 'dataset_id' ] )
+ dataset_dict = track[ 'dataset' ]
+ dataset = self.get_hda_or_ldda( trans, dataset_dict[ 'hda_ldda'], dataset_dict[ 'id' ] )
genome_data = self._get_genome_data( trans, dataset, dbkey )
if not isinstance( genome_data, str ):
diff -r 227dcabcaf83f569c2adf5740acc3c04339c759b -r 6b59809541ce4766efd1d044fbdee86a954746c4 static/scripts/packed/viz/circster.js
--- a/static/scripts/packed/viz/circster.js
+++ b/static/scripts/packed/viz/circster.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","libs/d3","viz/visualization"],function(g,l,i){var m=Backbone.Model.extend({is_visible:function(q,n){var o=q.getBoundingClientRect(),p=$("svg")[0].getBoundingClientRect();if(o.right<0||o.left>p.right||o.bottom<0||o.top>p.bottom){return false}return true}});var h={drawTicks:function(r,q,v,p,n){var u=r.append("g").selectAll("g").data(q).enter().append("g").selectAll("g").data(v).enter().append("g").attr("class","tick").attr("transform",function(w){return"rotate("+(w.angle*180/Math.PI-90)+")translate("+w.radius+",0)"});var t=[],s=[],o=function(w){return w.angle>Math.PI?"end":null};if(n){t=[0,0,0,-4];s=[4,0,"",".35em"];o=null}else{t=[1,0,4,0];s=[0,4,".35em",""]}u.append("line").attr("x1",t[0]).attr("y1",t[1]).attr("x2",t[2]).attr("y1",t[3]).style("stroke","#000");u.append("text").attr("x",s[0]).attr("y",s[1]).attr("dx",s[2]).attr("dy",s[3]).attr("text-anchor",o).attr("transform",p).text(function(w){return w.label})},formatNum:function(o,n){if(n===undefined){n=2}var q=null;if(o<1){q=o.toPrecision(n)}else{var p=Math.round(o.toPrecision(n));if(o<1000){q=p}else{if(o<1000000){q=Math.round((p/1000).toPrecision(3)).toFixed(0)+"K"}else{if(o<1000000000){q=Math.round((p/1000000).toPrecision(3)).toFixed(0)+"M"}}}}return q}};var c=Backbone.Model.extend({});var a=Backbone.View.extend({className:"circster",initialize:function(n){this.total_gap=n.total_gap;this.genome=n.genome;this.dataset_arc_height=n.dataset_arc_height;this.track_gap=10;this.label_arc_height=50;this.scale=1;this.circular_views=null;this.chords_views=null;this.model.get("tracks").on("add",this.add_track,this);this.model.get("tracks").on("remove",this.remove_track,this);this.get_circular_tracks()},get_circular_tracks:function(){return this.model.get("tracks").filter(function(n){return n.get("track_type")!=="DiagonalHeatmapTrack"})},get_chord_tracks:function(){return this.model.get("tracks").filter(function(n){return n.get("track_type")==="DiagonalHeatmapTrack"})},get_tracks_bounds:function(){var o=this.get_circular_tracks();dataset_arc_height=this.dataset_arc_height,min_dimension=Math.min(this.$el.width(),this.$el.height()),radius_start=min_dimension/2-o.length*(this.dataset_arc_height+this.track_gap)-(this.label_arc_height+this.track_gap),tracks_start_radii=l.range(radius_start,min_dimension/2,this.dataset_arc_height+this.track_gap);var n=this;return g.map(tracks_start_radii,function(p){return[p,p+n.dataset_arc_height]})},render:function(){var w=this,q=this.dataset_arc_height,n=w.$el.width(),v=w.$el.height(),s=this.get_circular_tracks(),p=this.get_chord_tracks(),r=this.get_tracks_bounds(),o=l.select(w.$el[0]).append("svg").attr("width",n).attr("height",v).attr("pointer-events","all").append("svg:g").call(l.behavior.zoom().on("zoom",function(){var x=l.event.scale;o.attr("transform","translate("+l.event.translate+") scale("+x+")");if(w.scale!==x){if(w.zoom_drag_timeout){clearTimeout(w.zoom_drag_timeout)}w.zoom_drag_timeout=setTimeout(function(){},400)}})).attr("transform","translate("+n/2+","+v/2+")").append("svg:g").attr("class","tracks");this.circular_views=s.map(function(y,z){var A=(y.get("track_type")==="LineTrack"?d:e),x=new A({el:o.append("g")[0],track:y,radius_bounds:r[z],genome:w.genome,total_gap:w.total_gap});x.render();return x});this.chords_views=p.map(function(y){var x=new j({el:o.append("g")[0],track:y,radius_bounds:r[0],genome:w.genome,total_gap:w.total_gap});x.render();return x});var u=this.circular_views[this.circular_views.length-1].radius_bounds[1],t=[u,u+this.label_arc_height];this.label_track_view=new b({el:o.append("g")[0],track:new c(),radius_bounds:t,genome:w.genome,total_gap:w.total_gap});this.label_track_view.render()},add_track:function(t){if(t.get("track_type")==="DiagonalHeatmapTrack"){var p=this.circular_views[0].radius_bounds,s=new j({el:l.select("g.tracks").append("g")[0],track:t,radius_bounds:p,genome:this.genome,total_gap:this.total_gap});s.render();this.chords_views.push(s)}else{var r=this.get_tracks_bounds();g.each(this.circular_views,function(v,w){v.update_radius_bounds(r[w])});g.each(this.chords_views,function(v){v.update_radius_bounds(r[0])});var q=this.circular_views.length,u=(t.get("track_type")==="LineTrack"?d:e),n=new u({el:l.select("g.tracks").append("g")[0],track:t,radius_bounds:r[q],genome:this.genome,total_gap:this.total_gap});n.render();this.circular_views.push(n);var o=r[r.length-1];o[1]=o[0];this.label_track_view.update_radius_bounds(o)}},remove_track:function(o,q,p){var n=this.circular_views[p.index];this.circular_views.splice(p.index,1);n.$el.remove();var r=this.get_tracks_bounds();g.each(this.circular_views,function(s,t){s.update_radius_bounds(r[t])})}});var k=Backbone.View.extend({tagName:"g",initialize:function(n){this.bg_stroke="ccc";this.loading_bg_fill="000";this.bg_fill="ccc";this.total_gap=n.total_gap;this.track=n.track;this.radius_bounds=n.radius_bounds;this.genome=n.genome;this.chroms_layout=this._chroms_layout();this.data_bounds=[];this.scale=1;this.parent_elt=l.select(this.$el[0])},get_fill_color:function(){var n=this.track.get("config").get_value("block_color");if(!n){n=this.track.get("config").get_value("color")}return n},render:function(){var r=this.parent_elt;if(!r){console.log("no parent elt")}var q=this.chroms_layout,t=l.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]),n=r.selectAll("g").data(q).enter().append("svg:g"),p=n.append("path").attr("d",t).attr("class","chrom-background").style("stroke",this.bg_stroke).style("fill",this.loading_bg_fill);p.append("title").text(function(v){return v.data.chrom});var o=this,s=o.track.get("data_manager"),u=(s?s.data_is_ready():true);$.when(u).then(function(){$.when(o._render_data(r)).then(function(){p.style("fill",o.bg_fill);o.render_labels()})})},render_labels:function(){},update_radius_bounds:function(o){this.radius_bounds=o;var n=l.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]);this.parent_elt.selectAll("g>path.chrom-background").transition().duration(1000).attr("d",n);this._transition_chrom_data();this._transition_labels()},update_scale:function(q){var p=this.scale;this.scale=q;if(q<=p){return}var o=this,n=new m();this.parent_elt.selectAll("path.chrom-data").filter(function(s,r){return n.is_visible(this)}).each(function(x,t){var w=l.select(this),s=w.attr("chrom"),v=o.genome.get_chrom_region(s),u=o.track.get("data_manager"),r;if(!u.can_get_more_detailed_data(v)){return}r=o.track.get("data_manager").get_more_detailed_data(v,"Coverage",0,q);$.when(r).then(function(A){w.remove();o._update_data_bounds();var z=g.find(o.chroms_layout,function(B){return B.data.chrom===s});var y=o.get_fill_color();o._render_chrom_data(o.parent_elt,z,A).style("stroke",y).style("fill",y)})});return o},_transition_chrom_data:function(){var o=this.track,q=this.chroms_layout,n=this.parent_elt.selectAll("g>path.chrom-data"),r=n[0].length;if(r>0){var p=this;$.when(o.get("data_manager").get_genome_wide_data(this.genome)).then(function(t){var s=g.reject(g.map(t,function(u,v){var w=null,x=p._get_path_function(q[v],u);if(x){w=x(u.data)}return w}),function(u){return u===null});n.each(function(v,u){l.select(this).transition().duration(1000).attr("d",s[u])})})}},_transition_labels:function(){},_update_data_bounds:function(){var n=this.data_bounds;this.data_bounds=this.get_data_bounds(this.track.get("data_manager").get_genome_wide_data(this.genome));if(this.data_bounds[0]<n[0]||this.data_bounds[1]>n[1]){this._transition_chrom_data()}},_render_data:function(q){var p=this,o=this.chroms_layout,n=this.track,r=$.Deferred();$.when(n.get("data_manager").get_genome_wide_data(this.genome)).then(function(t){p.data_bounds=p.get_data_bounds(t);layout_and_data=g.zip(o,t),chroms_data_layout=g.map(layout_and_data,function(u){var v=u[0],w=u[1];return p._render_chrom_data(q,v,w)});var s=p.get_fill_color();p.parent_elt.selectAll("path.chrom-data").style("stroke",s).style("fill",s);r.resolve(q)});return r},_render_chrom_data:function(n,o,p){},_get_path_function:function(o,n){},_chroms_layout:function(){var o=this.genome.get_chroms_info(),q=l.layout.pie().value(function(s){return s.len}).sort(null),r=q(o),n=this.total_gap/o.length,p=g.map(r,function(u,t){var s=u.endAngle-n;u.endAngle=(s>u.startAngle?s:u.startAngle);return u});return p}});var b=k.extend({initialize:function(n){k.prototype.initialize.call(this,n);this.innerRadius=this.radius_bounds[0];this.radius_bounds[0]=this.radius_bounds[1];this.bg_stroke="fff";this.bg_fill="fff";this.min_arc_len=0.08},_render_data:function(p){var o=this,n=p.selectAll("g");n.selectAll("path").attr("id",function(t){return"label-"+t.data.chrom});n.append("svg:text").filter(function(t){return t.endAngle-t.startAngle>o.min_arc_len}).attr("text-anchor","middle").append("svg:textPath").attr("xlink:href",function(t){return"#label-"+t.data.chrom}).attr("startOffset","25%").attr("font-weight","bold").text(function(t){return t.data.chrom});var q=function(v){var t=(v.endAngle-v.startAngle)/v.value,u=l.range(0,v.value,25000000).map(function(w,x){return{radius:o.innerRadius,angle:w*t+v.startAngle,label:x===0?0:(x%3?null:o.formatNum(w))}});if(u.length<4){u[u.length-1].label=o.formatNum(Math.round((u[u.length-1].angle-v.startAngle)/t))}return u};var s=function(t){return t.angle>Math.PI?"rotate(180)translate(-16)":null};var r=g.filter(this.chroms_layout,function(t){return t.endAngle-t.startAngle>o.min_arc_len});this.drawTicks(this.parent_elt,r,q,s)}});g.extend(b.prototype,h);var f=k.extend({_quantile:function(o,n){o.sort(l.ascending);return l.quantile(o,n)},_render_chrom_data:function(n,q,o){var r=this._get_path_function(q,o);if(!r){return null}var p=n.datum(o.data),s=p.append("path").attr("class","chrom-data").attr("chrom",q.data.chrom).attr("d",r);return s},_get_path_function:function(q,p){if(typeof p==="string"||!p.data||p.data.length===0){return null}var n=l.scale.linear().domain(this.data_bounds).range(this.radius_bounds).clamp(true);var r=l.scale.linear().domain([0,p.data.length]).range([q.startAngle,q.endAngle]);var o=l.svg.line.radial().interpolate("linear").radius(function(s){return n(s[1])}).angle(function(t,s){return r(s)});return l.svg.area.radial().interpolate(o.interpolate()).innerRadius(n(0)).outerRadius(o.radius()).angle(o.angle())},render_labels:function(){var n=this,q=function(){return"rotate(90)"};var p=g.filter(this.chroms_layout,function(r){return r.endAngle-r.startAngle>0.08}),o=g.filter(p,function(s,r){return r%3===0});this.drawTicks(this.parent_elt,o,this._data_bounds_ticks_fn(),q,true)},_transition_labels:function(){if(this.data_bounds.length===0){return}var o=this,q=g.filter(this.chroms_layout,function(r){return r.endAngle-r.startAngle>0.08}),p=g.filter(q,function(s,r){return r%3===0}),n=g.flatten(g.map(p,function(r){return o._data_bounds_ticks_fn()(r)}));this.parent_elt.selectAll("g.tick").data(n).transition().attr("transform",function(r){return"rotate("+(r.angle*180/Math.PI-90)+")translate("+r.radius+",0)"})},_data_bounds_ticks_fn:function(){var n=this;visibleChroms=0;return function(o){return[{radius:n.radius_bounds[0],angle:o.startAngle,label:n.formatNum(n.data_bounds[0])},{radius:n.radius_bounds[1],angle:o.startAngle,label:n.formatNum(n.data_bounds[1])}]}},get_data_bounds:function(n){}});g.extend(f.prototype,h);var e=f.extend({get_data_bounds:function(o){var n=g.map(o,function(p){if(typeof p==="string"||!p.max){return 0}return p.max});return[0,(n&&typeof n!=="string"?this._quantile(n,0.98):0)]}});var d=f.extend({get_data_bounds:function(o){var n=g.flatten(g.map(o,function(p){if(p){return g.map(p.data,function(q){return q[1]})}else{return 0}}));return[g.min(n),this._quantile(n,0.98)]}});var j=k.extend({render:function(){var n=this;$.when(n.track.get("data_manager").data_is_ready()).then(function(){$.when(n.track.get("data_manager").get_genome_wide_data(n.genome)).then(function(q){var p=[],o=n.genome.get_chroms_info();g.each(q,function(u,t){var r=o[t].chrom;var s=g.map(u.data,function(w){var v=n._get_region_angle(r,w[1]),x=n._get_region_angle(w[3],w[4]);return{source:{startAngle:v,endAngle:v+0.01},target:{startAngle:x,endAngle:x+0.01}}});p=p.concat(s)});n.parent_elt.append("g").attr("class","chord").selectAll("path").data(p).enter().append("path").style("fill",n.get_fill_color()).attr("d",l.svg.chord().radius(n.radius_bounds[0])).style("opacity",1)})})},update_radius_bounds:function(n){this.radius_bounds=n;this.parent_elt.selectAll("path").transition().attr("d",l.svg.chord().radius(this.radius_bounds[0]))},_get_region_angle:function(p,n){var o=g.find(this.chroms_layout,function(q){return q.data.chrom===p});return o.endAngle-((o.endAngle-o.startAngle)*(o.data.len-n)/o.data.len)}});return{CircsterView:a}});
\ No newline at end of file
+define(["libs/underscore","libs/d3","viz/visualization"],function(f,k,h){var l=Backbone.Model.extend({is_visible:function(p,m){var n=p.getBoundingClientRect(),o=$("svg")[0].getBoundingClientRect();if(n.right<0||n.left>o.right||n.bottom<0||n.top>o.bottom){return false}return true}});var g={drawTicks:function(q,p,u,o,m){var t=q.append("g").selectAll("g").data(p).enter().append("g").selectAll("g").data(u).enter().append("g").attr("class","tick").attr("transform",function(v){return"rotate("+(v.angle*180/Math.PI-90)+")translate("+v.radius+",0)"});var s=[],r=[],n=function(v){return v.angle>Math.PI?"end":null};if(m){s=[0,0,0,-4];r=[4,0,"",".35em"];n=null}else{s=[1,0,4,0];r=[0,4,".35em",""]}t.append("line").attr("x1",s[0]).attr("y1",s[1]).attr("x2",s[2]).attr("y1",s[3]).style("stroke","#000");t.append("text").attr("x",r[0]).attr("y",r[1]).attr("dx",r[2]).attr("dy",r[3]).attr("text-anchor",n).attr("transform",o).text(function(v){return v.label})},formatNum:function(n,m){if(m===undefined){m=2}var p=null;if(n<1){p=n.toPrecision(m)}else{var o=Math.round(n.toPrecision(m));if(n<1000){p=o}else{if(n<1000000){p=Math.round((o/1000).toPrecision(3)).toFixed(0)+"K"}else{if(n<1000000000){p=Math.round((o/1000000).toPrecision(3)).toFixed(0)+"M"}}}}return p}};var c=Backbone.Model.extend({});var a=Backbone.View.extend({className:"circster",initialize:function(m){this.total_gap=m.total_gap;this.genome=m.genome;this.dataset_arc_height=m.dataset_arc_height;this.track_gap=10;this.label_arc_height=50;this.scale=1;this.circular_views=null;this.chords_views=null;this.model.get("tracks").on("add",this.add_track,this);this.model.get("tracks").on("remove",this.remove_track,this);this.get_circular_tracks()},get_circular_tracks:function(){return this.model.get("tracks").filter(function(m){return m.get("track_type")!=="DiagonalHeatmapTrack"})},get_chord_tracks:function(){return this.model.get("tracks").filter(function(m){return m.get("track_type")==="DiagonalHeatmapTrack"})},get_tracks_bounds:function(){var n=this.get_circular_tracks();dataset_arc_height=this.dataset_arc_height,min_dimension=Math.min(this.$el.width(),this.$el.height()),radius_start=min_dimension/2-n.length*(this.dataset_arc_height+this.track_gap)-(this.label_arc_height+this.track_gap),tracks_start_radii=k.range(radius_start,min_dimension/2,this.dataset_arc_height+this.track_gap);var m=this;return f.map(tracks_start_radii,function(o){return[o,o+m.dataset_arc_height]})},render:function(){var v=this,p=this.dataset_arc_height,m=v.$el.width(),u=v.$el.height(),r=this.get_circular_tracks(),o=this.get_chord_tracks(),q=this.get_tracks_bounds(),n=k.select(v.$el[0]).append("svg").attr("width",m).attr("height",u).attr("pointer-events","all").append("svg:g").call(k.behavior.zoom().on("zoom",function(){var w=k.event.scale;n.attr("transform","translate("+k.event.translate+") scale("+w+")");if(v.scale!==w){if(v.zoom_drag_timeout){clearTimeout(v.zoom_drag_timeout)}v.zoom_drag_timeout=setTimeout(function(){},400)}})).attr("transform","translate("+m/2+","+u/2+")").append("svg:g").attr("class","tracks");this.circular_views=r.map(function(x,y){var w=new d({el:n.append("g")[0],track:x,radius_bounds:q[y],genome:v.genome,total_gap:v.total_gap});w.render();return w});this.chords_views=o.map(function(x){var w=new i({el:n.append("g")[0],track:x,radius_bounds:q[0],genome:v.genome,total_gap:v.total_gap});w.render();return w});var t=this.circular_views[this.circular_views.length-1].radius_bounds[1],s=[t,t+this.label_arc_height];this.label_track_view=new b({el:n.append("g")[0],track:new c(),radius_bounds:s,genome:v.genome,total_gap:v.total_gap});this.label_track_view.render()},add_track:function(s){if(s.get("track_type")==="DiagonalHeatmapTrack"){var o=this.circular_views[0].radius_bounds,r=new i({el:k.select("g.tracks").append("g")[0],track:s,radius_bounds:o,genome:this.genome,total_gap:this.total_gap});r.render();this.chords_views.push(r)}else{var q=this.get_tracks_bounds();f.each(this.circular_views,function(t,u){t.update_radius_bounds(q[u])});f.each(this.chords_views,function(t){t.update_radius_bounds(q[0])});var p=this.circular_views.length,m=new d({el:k.select("g.tracks").append("g")[0],track:s,radius_bounds:q[p],genome:this.genome,total_gap:this.total_gap});m.render();this.circular_views.push(m);var n=q[q.length-1];n[1]=n[0];this.label_track_view.update_radius_bounds(n)}},remove_track:function(n,p,o){var m=this.circular_views[o.index];this.circular_views.splice(o.index,1);m.$el.remove();var q=this.get_tracks_bounds();f.each(this.circular_views,function(r,s){r.update_radius_bounds(q[s])})}});var j=Backbone.View.extend({tagName:"g",initialize:function(m){this.bg_stroke="ccc";this.loading_bg_fill="000";this.bg_fill="ccc";this.total_gap=m.total_gap;this.track=m.track;this.radius_bounds=m.radius_bounds;this.genome=m.genome;this.chroms_layout=this._chroms_layout();this.data_bounds=[];this.scale=1;this.parent_elt=k.select(this.$el[0])},get_fill_color:function(){var m=this.track.get("config").get_value("block_color");if(!m){m=this.track.get("config").get_value("color")}return m},render:function(){var q=this.parent_elt;if(!q){console.log("no parent elt")}var p=this.chroms_layout,s=k.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]),m=q.selectAll("g").data(p).enter().append("svg:g"),o=m.append("path").attr("d",s).attr("class","chrom-background").style("stroke",this.bg_stroke).style("fill",this.loading_bg_fill);o.append("title").text(function(u){return u.data.chrom});var n=this,r=n.track.get("data_manager"),t=(r?r.data_is_ready():true);$.when(t).then(function(){$.when(n._render_data(q)).then(function(){o.style("fill",n.bg_fill);n.render_labels()})})},render_labels:function(){},update_radius_bounds:function(n){this.radius_bounds=n;var m=k.svg.arc().innerRadius(this.radius_bounds[0]).outerRadius(this.radius_bounds[1]);this.parent_elt.selectAll("g>path.chrom-background").transition().duration(1000).attr("d",m);this._transition_chrom_data();this._transition_labels()},update_scale:function(p){var o=this.scale;this.scale=p;if(p<=o){return}var n=this,m=new l();this.parent_elt.selectAll("path.chrom-data").filter(function(r,q){return m.is_visible(this)}).each(function(w,s){var v=k.select(this),r=v.attr("chrom"),u=n.genome.get_chrom_region(r),t=n.track.get("data_manager"),q;if(!t.can_get_more_detailed_data(u)){return}q=n.track.get("data_manager").get_more_detailed_data(u,"Coverage",0,p);$.when(q).then(function(z){v.remove();n._update_data_bounds();var y=f.find(n.chroms_layout,function(A){return A.data.chrom===r});var x=n.get_fill_color();n._render_chrom_data(n.parent_elt,y,z).style("stroke",x).style("fill",x)})});return n},_transition_chrom_data:function(){var n=this.track,p=this.chroms_layout,m=this.parent_elt.selectAll("g>path.chrom-data"),q=m[0].length;if(q>0){var o=this;$.when(n.get("data_manager").get_genome_wide_data(this.genome)).then(function(s){var r=f.reject(f.map(s,function(t,u){var v=null,w=o._get_path_function(p[u],t);if(w){v=w(t.data)}return v}),function(t){return t===null});m.each(function(u,t){k.select(this).transition().duration(1000).attr("d",r[t])})})}},_transition_labels:function(){},_update_data_bounds:function(){var m=this.data_bounds;this.data_bounds=this.get_data_bounds(this.track.get("data_manager").get_genome_wide_data(this.genome));if(this.data_bounds[0]<m[0]||this.data_bounds[1]>m[1]){this._transition_chrom_data()}},_render_data:function(p){var o=this,n=this.chroms_layout,m=this.track,q=$.Deferred();$.when(m.get("data_manager").get_genome_wide_data(this.genome)).then(function(s){o.data_bounds=o.get_data_bounds(s);layout_and_data=f.zip(n,s),chroms_data_layout=f.map(layout_and_data,function(t){var u=t[0],v=t[1];return o._render_chrom_data(p,u,v)});var r=o.get_fill_color();o.parent_elt.selectAll("path.chrom-data").style("stroke",r).style("fill",r);q.resolve(p)});return q},_render_chrom_data:function(m,n,o){},_get_path_function:function(n,m){},_chroms_layout:function(){var n=this.genome.get_chroms_info(),p=k.layout.pie().value(function(r){return r.len}).sort(null),q=p(n),m=this.total_gap/n.length,o=f.map(q,function(t,s){var r=t.endAngle-m;t.endAngle=(r>t.startAngle?r:t.startAngle);return t});return o}});var b=j.extend({initialize:function(m){j.prototype.initialize.call(this,m);this.innerRadius=this.radius_bounds[0];this.radius_bounds[0]=this.radius_bounds[1];this.bg_stroke="fff";this.bg_fill="fff";this.min_arc_len=0.08},_render_data:function(o){var n=this,m=o.selectAll("g");m.selectAll("path").attr("id",function(s){return"label-"+s.data.chrom});m.append("svg:text").filter(function(s){return s.endAngle-s.startAngle>n.min_arc_len}).attr("text-anchor","middle").append("svg:textPath").attr("xlink:href",function(s){return"#label-"+s.data.chrom}).attr("startOffset","25%").attr("font-weight","bold").text(function(s){return s.data.chrom});var p=function(u){var s=(u.endAngle-u.startAngle)/u.value,t=k.range(0,u.value,25000000).map(function(w,x){return{radius:n.innerRadius,angle:w*s+u.startAngle,label:x===0?0:(x%3?null:n.formatNum(w))}});if(t.length<4){t[t.length-1].label=n.formatNum(Math.round((t[t.length-1].angle-u.startAngle)/s))}return t};var r=function(s){return s.angle>Math.PI?"rotate(180)translate(-16)":null};var q=f.filter(this.chroms_layout,function(s){return s.endAngle-s.startAngle>n.min_arc_len});this.drawTicks(this.parent_elt,q,p,r)}});f.extend(b.prototype,g);var e=j.extend({_quantile:function(n,m){n.sort(k.ascending);return k.quantile(n,m)},_render_chrom_data:function(m,p,n){var q=this._get_path_function(p,n);if(!q){return null}var o=m.datum(n.data),r=o.append("path").attr("class","chrom-data").attr("chrom",p.data.chrom).attr("d",q);return r},_get_path_function:function(p,o){if(typeof o==="string"||!o.data||o.data.length===0){return null}var m=k.scale.linear().domain(this.data_bounds).range(this.radius_bounds).clamp(true);var q=k.scale.linear().domain([0,o.data.length]).range([p.startAngle,p.endAngle]);var n=k.svg.line.radial().interpolate("linear").radius(function(r){return m(r[1])}).angle(function(s,r){return q(r)});return k.svg.area.radial().interpolate(n.interpolate()).innerRadius(m(0)).outerRadius(n.radius()).angle(n.angle())},render_labels:function(){var m=this,p=function(){return"rotate(90)"};var o=f.filter(this.chroms_layout,function(q){return q.endAngle-q.startAngle>0.08}),n=f.filter(o,function(r,q){return q%3===0});this.drawTicks(this.parent_elt,n,this._data_bounds_ticks_fn(),p,true)},_transition_labels:function(){if(this.data_bounds.length===0){return}var n=this,p=f.filter(this.chroms_layout,function(q){return q.endAngle-q.startAngle>0.08}),o=f.filter(p,function(r,q){return q%3===0}),m=f.flatten(f.map(o,function(q){return n._data_bounds_ticks_fn()(q)}));this.parent_elt.selectAll("g.tick").data(m).transition().attr("transform",function(q){return"rotate("+(q.angle*180/Math.PI-90)+")translate("+q.radius+",0)"})},_data_bounds_ticks_fn:function(){var m=this;visibleChroms=0;return function(n){return[{radius:m.radius_bounds[0],angle:n.startAngle,label:m.formatNum(m.data_bounds[0])},{radius:m.radius_bounds[1],angle:n.startAngle,label:m.formatNum(m.data_bounds[1])}]}},get_data_bounds:function(m){}});f.extend(e.prototype,g);var d=e.extend({get_data_bounds:function(n){var m=f.flatten(f.map(n,function(o){if(o){return f.map(o.data,function(q){return q[1]})}else{return 0}}));return[f.min(m),this._quantile(m,0.98)]}});var i=j.extend({render:function(){var m=this;$.when(m.track.get("data_manager").data_is_ready()).then(function(){$.when(m.track.get("data_manager").get_genome_wide_data(m.genome)).then(function(p){var o=[],n=m.genome.get_chroms_info();f.each(p,function(t,s){var q=n[s].chrom;var r=f.map(t.data,function(v){var u=m._get_region_angle(q,v[1]),w=m._get_region_angle(v[3],v[4]);return{source:{startAngle:u,endAngle:u+0.01},target:{startAngle:w,endAngle:w+0.01}}});o=o.concat(r)});m.parent_elt.append("g").attr("class","chord").selectAll("path").data(o).enter().append("path").style("fill",m.get_fill_color()).attr("d",k.svg.chord().radius(m.radius_bounds[0])).style("opacity",1)})})},update_radius_bounds:function(m){this.radius_bounds=m;this.parent_elt.selectAll("path").transition().attr("d",k.svg.chord().radius(this.radius_bounds[0]))},_get_region_angle:function(o,m){var n=f.find(this.chroms_layout,function(p){return p.data.chrom===o});return n.endAngle-((n.endAngle-n.startAngle)*(n.data.len-m)/n.data.len)}});return{CircsterView:a}});
\ No newline at end of file
diff -r 227dcabcaf83f569c2adf5740acc3c04339c759b -r 6b59809541ce4766efd1d044fbdee86a954746c4 static/scripts/packed/viz/visualization.js
--- a/static/scripts/packed/viz/visualization.js
+++ b/static/scripts/packed/viz/visualization.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","mvc/data","viz/trackster/util","utils/config"],function(s,i,l,o){var a=function(u,x,w,v){$.ajax({url:u,data:w,error:function(){alert("Grid failed")},success:function(y){show_modal("Select datasets for new tracks",y,{Cancel:function(){hide_modal()},Add:function(){var z=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var A={data_type:"track_config",hda_ldda:"hda"},B=$(this).val();if($(this).attr("name")!=="id"){A.hda_ldda="ldda"}z[z.length]=$.ajax({url:x+"/"+B,data:A,dataType:"json"})});$.when.apply($,z).then(function(){var A=(arguments[0] instanceof Array?$.map(arguments,function(B){return B[0]}):[arguments[0]]);v(A)});hide_modal()}})}})};var j=function(u){return("isResolved" in u)};var f=function(u){this.default_font=u!==undefined?u:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};s.extend(f.prototype,{load_pattern:function(u,y){var v=this.patterns,w=this.dummy_context,x=new Image();x.src=galaxy_paths.attributes.image_path+y;x.onload=function(){v[u]=w.createPattern(x,"repeat")}},get_pattern:function(u){return this.patterns[u]},new_canvas:function(){var u=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(u)}u.manager=this;return u}});var q=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(u){this.clear()},get_elt:function(v){var w=this.attributes.obj_cache,x=this.attributes.key_ary,u=x.indexOf(v);if(u!==-1){if(w[v].stale){x.splice(u,1);delete w[v]}else{this.move_key_to_end(v,u)}}return w[v]},set_elt:function(v,x){var y=this.attributes.obj_cache,z=this.attributes.key_ary,w=this.attributes.num_elements;if(!y[v]){if(z.length>=w){var u=z.shift();delete y[u]}z.push(v)}y[v]=x;return x},move_key_to_end:function(v,u){this.attributes.key_ary.splice(u,1);this.attributes.key_ary.push(v)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length},most_recently_added:function(){return this.size()===0?null:this.attributes.key_ary[this.attributes.key_ary.length-1]}});var d=q.extend({defaults:s.extend({},q.prototype.defaults,{dataset:null,genome:null,init_data:null,min_region_size:200,filters_manager:null,data_type:"data",data_mode_compatible:function(u,v){return true},can_subset:function(u){return false}}),initialize:function(u){q.prototype.initialize.call(this);var v=this.get("init_data");if(v){this.add_data(v)}},add_data:function(u){if(this.get("num_elements")<u.length){this.set("num_elements",u.length)}var v=this;s.each(u,function(w){v.set_data(w.region,w)})},data_is_ready:function(){var x=this.get("dataset"),w=$.Deferred(),u=(this.get("data_type")==="raw_data"?"state":this.get("data_type")==="data"?"converted_datasets_state":"error"),v=new l.ServerStateDeferred({ajax_settings:{url:this.get("dataset").url(),data:{hda_ldda:x.get("hda_ldda"),data_type:u},dataType:"json"},interval:5000,success_fn:function(y){return y!=="pending"}});$.when(v.go()).then(function(y){w.resolve(y==="ok"||y==="data")});return w},search_features:function(u){var v=this.get("dataset"),w={query:u,hda_ldda:v.get("hda_ldda"),data_type:"features"};return $.getJSON(v.url(),w)},load_data:function(C,B,v,A){var y=this.get("dataset"),x={data_type:this.get("data_type"),chrom:C.get("chrom"),low:C.get("start"),high:C.get("end"),mode:B,resolution:v,hda_ldda:y.get("hda_ldda")};$.extend(x,A);var E=this.get("filters_manager");if(E){var F=[];var u=E.filters;for(var z=0;z<u.length;z++){F.push(u[z].name)}x.filter_cols=JSON.stringify(F)}var w=this,D=$.getJSON(y.url(),x,function(G){G.region=C;w.set_data(C,G)});this.set_data(C,D);return D},get_data:function(B,A,w,y){var C=this.get_elt(B);if(C&&(j(C)||this.get("data_mode_compatible")(C,A))){return C}var D=this.get("key_ary"),v=this.get("obj_cache"),E,u,z;for(var x=0;x<D.length;x++){E=D[x];u=new g({from_str:E});if(u.contains(B)){z=true;C=v[E];if(j(C)||(this.get("data_mode_compatible")(C,A)&&this.get("can_subset")(C))){this.move_key_to_end(E,x);if(!j(C)){var G=this.subset_entry(C,B);this.set(B,G);C=G}return C}}}if(!z&&B.length()<this.attributes.min_region_size){var F=new g({from_str:this.most_recently_added()});if(!F||(B.get("start")>F.get("start"))){B.set("end",B.get("start")+this.attributes.min_region_size)}else{B.set("start",B.get("end")-this.attributes.min_region_size)}B.set("genome",this.attributes.genome);B.trim()}return this.load_data(B,A,w,y)},set_data:function(v,u){this.set_elt(v,u)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(C,B,x,A,y){var E=this._mark_stale(C);if(!(E&&this.get("data_mode_compatible")(E,B))){console.log("ERROR: problem with getting more data: current data is not compatible");return}var w=C.get("start");if(y===this.DEEP_DATA_REQ){$.extend(A,{start_val:E.data.length+1})}else{if(y===this.BROAD_DATA_REQ){w=(E.max_high?E.max_high:E.data[E.data.length-1][2])+1}}var D=C.copy().set("start",w);var v=this,z=this.load_data(D,B,x,A),u=$.Deferred();this.set_data(C,u);$.when(z).then(function(F){if(F.data){F.data=E.data.concat(F.data);if(F.max_low){F.max_low=E.max_low}if(F.message){F.message=F.message.replace(/[0-9]+/,F.data.length)}}v.set_data(C,F);u.resolve(F)});return u},can_get_more_detailed_data:function(v){var u=this.get_elt(v);return(u.dataset_type==="bigwig"&&u.data.length<8000)},get_more_detailed_data:function(x,z,v,y,w){var u=this._mark_stale(x);if(!u){console.log("ERROR getting more detailed data: no current data");return}if(!w){w={}}if(u.dataset_type==="bigwig"){w.num_samples=1000*y}return this.load_data(x,z,v,w)},_mark_stale:function(v){var u=this.get_elt(v);if(!u){console.log("ERROR: no data to mark as stale: ",this.get("dataset"),v.toString())}u.stale=true;return u},get_genome_wide_data:function(u){var w=this,y=true,x=s.map(u.get("chroms_info").chrom_info,function(A){var z=w.get_elt(new g({chrom:A.chrom,start:0,end:A.len}));if(!z){y=false}return z});if(y){return x}var v=$.Deferred();$.getJSON(this.get("dataset").url(),{data_type:"genome_data"},function(z){w.add_data(z.data);v.resolve(z.data)});return v},subset_entry:function(w,x){var u={bigwig:function(y,z){return s.filter(y,function(A){return A[0]>=z.get("start")&&A[0]<=z.get("end")})},refseq:function(z,A){var B=A.get("start")-w.region.get("start"),y=w.data.length-(w.region.get("end")-A.get("end"));return w.data.slice(B,y)}};var v=w.data;if(!w.region.same(x)&&w.dataset_type in u){v=u[w.dataset_type](w.data,x)}return{region:x,data:v,dataset_type:w.dataset_type}},get_elt:function(u){return q.prototype.get_elt.call(this,u.toString())},set_elt:function(v,u){return q.prototype.set_elt.call(this,v.toString(),u)}});var p=d.extend({initialize:function(u){var v=new Backbone.Model();v.urlRoot=u.data_url;this.set("dataset",v)},load_data:function(w,x,u,v){return(w.length()<=100000?d.prototype.load_data.call(this,w,x,u,v):{data:null,region:w})}});var c=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},initialize:function(u){this.id=u.dbkey},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info},get_chrom_region:function(u){var v=s.find(this.get_chroms_info(),function(w){return w.chrom===u});return new g({chrom:v.chrom,end:v.len})},get_chrom_len:function(u){return s.find(this.get_chroms_info(),function(v){return v.chrom===u}).len}});var g=Backbone.RelationalModel.extend({defaults:{chrom:null,start:0,end:0,genome:null},same:function(u){return this.attributes.chrom===u.get("chrom")&&this.attributes.start===u.get("start")&&this.attributes.end===u.get("end")},initialize:function(v){if(v.from_str){var x=v.from_str.split(":"),w=x[0],u=x[1].split("-");this.set({chrom:w,start:parseInt(u[0],10),end:parseInt(u[1],10)})}},copy:function(){return new g({chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")})},length:function(){return this.get("end")-this.get("start")},toString:function(){return this.get("chrom")+":"+this.get("start")+"-"+this.get("end")},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(B){var v=this.get("chrom"),A=B.get("chrom"),z=this.get("start"),x=B.get("start"),y=this.get("end"),w=B.get("end"),u;if(v&&A&&v!==A){return g.overlap_results.DIF_CHROMS}if(z<x){if(y<x){u=g.overlap_results.BEFORE}else{if(y<w){u=g.overlap_results.OVERLAP_START}else{u=g.overlap_results.CONTAINS}}}else{if(z>x){if(z>w){u=g.overlap_results.AFTER}else{if(y<=w){u=g.overlap_results.CONTAINED_BY}else{u=g.overlap_results.OVERLAP_END}}}else{u=(y>=w?g.overlap_results.CONTAINS:g.overlap_results.CONTAINED_BY)}}return u},trim:function(u){if(this.attributes.start<0){this.attributes.start=0}if(this.attributes.genome){var v=this.attributes.genome.get_chrom_len(this.attributes.chrom);if(this.attributes.end>v){this.attributes.end=v-1}}return this},contains:function(u){return this.compute_overlap(u)===g.overlap_results.CONTAINS},overlaps:function(u){return s.intersection([this.compute_overlap(u)],[g.overlap_results.DIF_CHROMS,g.overlap_results.BEFORE,g.overlap_results.AFTER]).length===0}},{overlap_results:{DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006}});var m=Backbone.Collection.extend({model:g});var e=Backbone.RelationalModel.extend({defaults:{region:null,note:""},relations:[{type:Backbone.HasOne,key:"region",relatedModel:g}]});var r=Backbone.Collection.extend({model:e});var t=i.Dataset.extend({initialize:function(u){this.set("id",u.dataset_id);this.set("config",o.ConfigSettingCollection.from_config_dict(u.prefs));this.get("config").add([{key:"name",value:this.get("name")},{key:"color"}]);var v=this.get("preloaded_data");if(v){v=v.data}else{v=[]}this.set("data_manager",new d({dataset:this,init_data:v}))}});var n=Backbone.RelationalModel.extend({defaults:{title:"",type:""},url:galaxy_paths.get("visualization_url"),save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var k=n.extend({defaults:s.extend({},n.prototype.defaults,{dbkey:"",tracks:null,bookmarks:null,viewport:null}),relations:[{type:Backbone.HasMany,key:"tracks",relatedModel:t}],add_tracks:function(u){this.get("tracks").add(u)}});var b=Backbone.Model.extend({});var h=Backbone.Router.extend({initialize:function(v){this.view=v.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var u=this;u.view.on("navigate",function(w){u.navigate(w)})},change_location:function(u){this.view.go_to(u)}});return{BackboneTrack:t,BrowserBookmark:e,BrowserBookmarkCollection:r,Cache:q,CanvasManager:f,Genome:c,GenomeDataManager:d,GenomeRegion:g,GenomeRegionCollection:m,GenomeVisualization:k,GenomeReferenceDataManager:p,TrackBrowserRouter:h,TrackConfig:b,Visualization:n,select_datasets:a}});
\ No newline at end of file
+define(["libs/underscore","mvc/data","viz/trackster/util","utils/config"],function(s,i,l,o){var a=function(u,x,w,v){$.ajax({url:u,data:w,error:function(){alert("Grid failed")},success:function(y){show_modal("Select datasets for new tracks",y,{Cancel:function(){hide_modal()},Add:function(){var z=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var A={data_type:"track_config",hda_ldda:"hda"},B=$(this).val();if($(this).attr("name")!=="id"){A.hda_ldda="ldda"}z[z.length]=$.ajax({url:x+"/"+B,data:A,dataType:"json"})});$.when.apply($,z).then(function(){var A=(arguments[0] instanceof Array?$.map(arguments,function(B){return B[0]}):[arguments[0]]);v(A)});hide_modal()}})}})};var j=function(u){return("isResolved" in u)};var f=function(u){this.default_font=u!==undefined?u:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};s.extend(f.prototype,{load_pattern:function(u,y){var v=this.patterns,w=this.dummy_context,x=new Image();x.src=galaxy_paths.attributes.image_path+y;x.onload=function(){v[u]=w.createPattern(x,"repeat")}},get_pattern:function(u){return this.patterns[u]},new_canvas:function(){var u=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(u)}u.manager=this;return u}});var q=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(u){this.clear()},get_elt:function(v){var w=this.attributes.obj_cache,x=this.attributes.key_ary,u=x.indexOf(v);if(u!==-1){if(w[v].stale){x.splice(u,1);delete w[v]}else{this.move_key_to_end(v,u)}}return w[v]},set_elt:function(v,x){var y=this.attributes.obj_cache,z=this.attributes.key_ary,w=this.attributes.num_elements;if(!y[v]){if(z.length>=w){var u=z.shift();delete y[u]}z.push(v)}y[v]=x;return x},move_key_to_end:function(v,u){this.attributes.key_ary.splice(u,1);this.attributes.key_ary.push(v)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length},most_recently_added:function(){return this.size()===0?null:this.attributes.key_ary[this.attributes.key_ary.length-1]}});var d=q.extend({defaults:s.extend({},q.prototype.defaults,{dataset:null,genome:null,init_data:null,min_region_size:200,filters_manager:null,data_type:"data",data_mode_compatible:function(u,v){return true},can_subset:function(u){return false}}),initialize:function(u){q.prototype.initialize.call(this);var v=this.get("init_data");if(v){this.add_data(v)}},add_data:function(u){if(this.get("num_elements")<u.length){this.set("num_elements",u.length)}var v=this;s.each(u,function(w){v.set_data(w.region,w)})},data_is_ready:function(){var x=this.get("dataset"),w=$.Deferred(),u=(this.get("data_type")==="raw_data"?"state":this.get("data_type")==="data"?"converted_datasets_state":"error"),v=new l.ServerStateDeferred({ajax_settings:{url:this.get("dataset").url(),data:{hda_ldda:x.get("hda_ldda"),data_type:u},dataType:"json"},interval:5000,success_fn:function(y){return y!=="pending"}});$.when(v.go()).then(function(y){w.resolve(y==="ok"||y==="data")});return w},search_features:function(u){var v=this.get("dataset"),w={query:u,hda_ldda:v.get("hda_ldda"),data_type:"features"};return $.getJSON(v.url(),w)},load_data:function(C,B,v,A){var y=this.get("dataset"),x={data_type:this.get("data_type"),chrom:C.get("chrom"),low:C.get("start"),high:C.get("end"),mode:B,resolution:v,hda_ldda:y.get("hda_ldda")};$.extend(x,A);var E=this.get("filters_manager");if(E){var F=[];var u=E.filters;for(var z=0;z<u.length;z++){F.push(u[z].name)}x.filter_cols=JSON.stringify(F)}var w=this,D=$.getJSON(y.url(),x,function(G){G.region=C;w.set_data(C,G)});this.set_data(C,D);return D},get_data:function(B,A,w,y){var C=this.get_elt(B);if(C&&(j(C)||this.get("data_mode_compatible")(C,A))){return C}var D=this.get("key_ary"),v=this.get("obj_cache"),E,u,z;for(var x=0;x<D.length;x++){E=D[x];u=new g({from_str:E});if(u.contains(B)){z=true;C=v[E];if(j(C)||(this.get("data_mode_compatible")(C,A)&&this.get("can_subset")(C))){this.move_key_to_end(E,x);if(!j(C)){var G=this.subset_entry(C,B);this.set(B,G);C=G}return C}}}if(!z&&B.length()<this.attributes.min_region_size){var F=new g({from_str:this.most_recently_added()});if(!F||(B.get("start")>F.get("start"))){B.set("end",B.get("start")+this.attributes.min_region_size)}else{B.set("start",B.get("end")-this.attributes.min_region_size)}B.set("genome",this.attributes.genome);B.trim()}return this.load_data(B,A,w,y)},set_data:function(v,u){this.set_elt(v,u)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(C,B,x,A,y){var E=this._mark_stale(C);if(!(E&&this.get("data_mode_compatible")(E,B))){console.log("ERROR: problem with getting more data: current data is not compatible");return}var w=C.get("start");if(y===this.DEEP_DATA_REQ){$.extend(A,{start_val:E.data.length+1})}else{if(y===this.BROAD_DATA_REQ){w=(E.max_high?E.max_high:E.data[E.data.length-1][2])+1}}var D=C.copy().set("start",w);var v=this,z=this.load_data(D,B,x,A),u=$.Deferred();this.set_data(C,u);$.when(z).then(function(F){if(F.data){F.data=E.data.concat(F.data);if(F.max_low){F.max_low=E.max_low}if(F.message){F.message=F.message.replace(/[0-9]+/,F.data.length)}}v.set_data(C,F);u.resolve(F)});return u},can_get_more_detailed_data:function(v){var u=this.get_elt(v);return(u.dataset_type==="bigwig"&&u.data.length<8000)},get_more_detailed_data:function(x,z,v,y,w){var u=this._mark_stale(x);if(!u){console.log("ERROR getting more detailed data: no current data");return}if(!w){w={}}if(u.dataset_type==="bigwig"){w.num_samples=1000*y}return this.load_data(x,z,v,w)},_mark_stale:function(v){var u=this.get_elt(v);if(!u){console.log("ERROR: no data to mark as stale: ",this.get("dataset"),v.toString())}u.stale=true;return u},get_genome_wide_data:function(u){var w=this,y=true,x=s.map(u.get("chroms_info").chrom_info,function(A){var z=w.get_elt(new g({chrom:A.chrom,start:0,end:A.len}));if(!z){y=false}return z});if(y){return x}var v=$.Deferred();$.getJSON(this.get("dataset").url(),{data_type:"genome_data"},function(z){w.add_data(z.data);v.resolve(z.data)});return v},subset_entry:function(w,x){var u={bigwig:function(y,z){return s.filter(y,function(A){return A[0]>=z.get("start")&&A[0]<=z.get("end")})},refseq:function(z,A){var B=A.get("start")-w.region.get("start"),y=w.data.length-(w.region.get("end")-A.get("end"));return w.data.slice(B,y)}};var v=w.data;if(!w.region.same(x)&&w.dataset_type in u){v=u[w.dataset_type](w.data,x)}return{region:x,data:v,dataset_type:w.dataset_type}},get_elt:function(u){return q.prototype.get_elt.call(this,u.toString())},set_elt:function(v,u){return q.prototype.set_elt.call(this,v.toString(),u)}});var p=d.extend({initialize:function(u){var v=new Backbone.Model();v.urlRoot=u.data_url;this.set("dataset",v)},load_data:function(w,x,u,v){return(w.length()<=100000?d.prototype.load_data.call(this,w,x,u,v):{data:null,region:w})}});var c=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},initialize:function(u){this.id=u.dbkey},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info},get_chrom_region:function(u){var v=s.find(this.get_chroms_info(),function(w){return w.chrom===u});return new g({chrom:v.chrom,end:v.len})},get_chrom_len:function(u){return s.find(this.get_chroms_info(),function(v){return v.chrom===u}).len}});var g=Backbone.RelationalModel.extend({defaults:{chrom:null,start:0,end:0,genome:null},same:function(u){return this.attributes.chrom===u.get("chrom")&&this.attributes.start===u.get("start")&&this.attributes.end===u.get("end")},initialize:function(v){if(v.from_str){var x=v.from_str.split(":"),w=x[0],u=x[1].split("-");this.set({chrom:w,start:parseInt(u[0],10),end:parseInt(u[1],10)})}},copy:function(){return new g({chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")})},length:function(){return this.get("end")-this.get("start")},toString:function(){return this.get("chrom")+":"+this.get("start")+"-"+this.get("end")},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(B){var v=this.get("chrom"),A=B.get("chrom"),z=this.get("start"),x=B.get("start"),y=this.get("end"),w=B.get("end"),u;if(v&&A&&v!==A){return g.overlap_results.DIF_CHROMS}if(z<x){if(y<x){u=g.overlap_results.BEFORE}else{if(y<w){u=g.overlap_results.OVERLAP_START}else{u=g.overlap_results.CONTAINS}}}else{if(z>x){if(z>w){u=g.overlap_results.AFTER}else{if(y<=w){u=g.overlap_results.CONTAINED_BY}else{u=g.overlap_results.OVERLAP_END}}}else{u=(y>=w?g.overlap_results.CONTAINS:g.overlap_results.CONTAINED_BY)}}return u},trim:function(u){if(this.attributes.start<0){this.attributes.start=0}if(this.attributes.genome){var v=this.attributes.genome.get_chrom_len(this.attributes.chrom);if(this.attributes.end>v){this.attributes.end=v-1}}return this},contains:function(u){return this.compute_overlap(u)===g.overlap_results.CONTAINS},overlaps:function(u){return s.intersection([this.compute_overlap(u)],[g.overlap_results.DIF_CHROMS,g.overlap_results.BEFORE,g.overlap_results.AFTER]).length===0}},{overlap_results:{DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006}});var m=Backbone.Collection.extend({model:g});var e=Backbone.RelationalModel.extend({defaults:{region:null,note:""},relations:[{type:Backbone.HasOne,key:"region",relatedModel:g}]});var r=Backbone.Collection.extend({model:e});var t=Backbone.RelationalModel.extend({relations:[{type:Backbone.HasOne,key:"dataset",relatedModel:i.Dataset}],initialize:function(u){this.set("config",o.ConfigSettingCollection.from_config_dict(u.prefs));this.get("config").add([{key:"name",value:this.get("name")},{key:"color"}]);var v=this.get("preloaded_data");if(v){v=v.data}else{v=[]}this.set("data_manager",new d({dataset:this.get("dataset"),init_data:v}))}});var n=Backbone.RelationalModel.extend({defaults:{title:"",type:""},url:galaxy_paths.get("visualization_url"),save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var k=n.extend({defaults:s.extend({},n.prototype.defaults,{dbkey:"",tracks:null,bookmarks:null,viewport:null}),relations:[{type:Backbone.HasMany,key:"tracks",relatedModel:t}],add_tracks:function(u){this.get("tracks").add(u)}});var b=Backbone.Model.extend({});var h=Backbone.Router.extend({initialize:function(v){this.view=v.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var u=this;u.view.on("navigate",function(w){u.navigate(w)})},change_location:function(u){this.view.go_to(u)}});return{BackboneTrack:t,BrowserBookmark:e,BrowserBookmarkCollection:r,Cache:q,CanvasManager:f,Genome:c,GenomeDataManager:d,GenomeRegion:g,GenomeRegionCollection:m,GenomeVisualization:k,GenomeReferenceDataManager:p,TrackBrowserRouter:h,TrackConfig:b,Visualization:n,select_datasets:a}});
\ No newline at end of file
diff -r 227dcabcaf83f569c2adf5740acc3c04339c759b -r 6b59809541ce4766efd1d044fbdee86a954746c4 static/scripts/viz/circster.js
--- a/static/scripts/viz/circster.js
+++ b/static/scripts/viz/circster.js
@@ -238,10 +238,7 @@
// Create a view for each track in the visualiation and render.
this.circular_views = circular_tracks.map(function(track, index) {
- var track_view_class = (track.get('track_type') === 'LineTrack' ?
- CircsterBigWigTrackView :
- CircsterSummaryTreeTrackView ),
- view = new track_view_class({
+ var view = new CircsterBigWigTrackView({
el: svg.append('g')[0],
track: track,
radius_bounds: tracks_bounds[index],
@@ -324,10 +321,7 @@
// Render new track.
var track_index = this.circular_views.length,
- track_view_class = (new_track.get('track_type') === 'LineTrack' ?
- CircsterBigWigTrackView :
- CircsterSummaryTreeTrackView ),
- track_view = new track_view_class({
+ track_view = new CircsterBigWigTrackView({
el: d3.select('g.tracks').append('g')[0],
track: new_track,
radius_bounds: new_track_bounds[track_index],
@@ -859,22 +853,6 @@
});
_.extend(CircsterQuantitativeTrackView.prototype, UsesTicks);
-
-/**
- * Layout for summary tree data in a circster visualization.
- */
-var CircsterSummaryTreeTrackView = CircsterQuantitativeTrackView.extend({
-
- get_data_bounds: function(data) {
- // Get max across data.
- var max_data = _.map(data, function(d) {
- if (typeof d === 'string' || !d.max) { return 0; }
- return d.max;
- });
- return [ 0, (max_data && typeof max_data !== 'string' ? this._quantile(max_data, 0.98) : 0) ];
- }
-});
-
/**
* Bigwig track view in Circster.
*/
diff -r 227dcabcaf83f569c2adf5740acc3c04339c759b -r 6b59809541ce4766efd1d044fbdee86a954746c4 static/scripts/viz/visualization.js
--- a/static/scripts/viz/visualization.js
+++ b/static/scripts/viz/visualization.js
@@ -861,11 +861,17 @@
* A track of data in a genome visualization.
*/
// TODO: rename to Track and merge with Trackster's Track object.
-var BackboneTrack = data_mod.Dataset.extend({
+var BackboneTrack = Backbone.RelationalModel.extend({
+
+ relations: [
+ {
+ type: Backbone.HasOne,
+ key: 'dataset',
+ relatedModel: data_mod.Dataset
+ }
+ ],
initialize: function(options) {
- // Dataset id is unique ID for now.
- this.set('id', options.dataset_id);
// -- Set up config settings. --
@@ -886,7 +892,7 @@
preloaded_data = [];
}
this.set('data_manager', new GenomeDataManager({
- dataset: this,
+ dataset: this.get('dataset'),
init_data: preloaded_data
}));
}
diff -r 227dcabcaf83f569c2adf5740acc3c04339c759b -r 6b59809541ce4766efd1d044fbdee86a954746c4 templates/webapps/galaxy/visualization/circster.mako
--- a/templates/webapps/galaxy/visualization/circster.mako
+++ b/templates/webapps/galaxy/visualization/circster.mako
@@ -42,8 +42,8 @@
$(function() {
// -- Viz set up. --
- var genome = new visualization_mod.Genome(JSON.parse('${ h.to_json_string( genome ) }'))
- vis = new visualization_mod.GenomeVisualization(JSON.parse('${ h.to_json_string( viz_config ) }')),
+ var genome = new visualization_mod.Genome( ${ h.to_json_string( genome ) } )
+ vis = new visualization_mod.GenomeVisualization( ${ h.to_json_string( viz_config ) } ),
viz_view = new circster.CircsterView({
el: $('#vis'),
// Gap is difficult to set because it very dependent on chromosome size and organization.
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.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/227dcabcaf83/
Changeset: 227dcabcaf83
Branch: next-stable
User: carlfeberhard
Date: 2013-05-21 18:54:21
Summary: Scatterplot: use named data provider, fix encoding of ids; pack scripts
Affected #: 6 files
diff -r d13c2f41bff1a19cd996bdcf3457b070e668edae -r 227dcabcaf83f569c2adf5740acc3c04339c759b lib/galaxy/datatypes/tabular.py
--- a/lib/galaxy/datatypes/tabular.py
+++ b/lib/galaxy/datatypes/tabular.py
@@ -328,7 +328,6 @@
"""
Returns a list of visualizations for datatype.
"""
-
# Can visualize tabular data as scatterplot if there are 2+ numerical
# columns.
num_numerical_cols = 0
diff -r d13c2f41bff1a19cd996bdcf3457b070e668edae -r 227dcabcaf83f569c2adf5740acc3c04339c759b lib/galaxy/visualization/data_providers/basic.py
--- a/lib/galaxy/visualization/data_providers/basic.py
+++ b/lib/galaxy/visualization/data_providers/basic.py
@@ -67,11 +67,14 @@
# allow throttling
self.max_lines_returned = max_lines_returned
- def get_data( self, columns, start_val=0, max_vals=None, skip_comments=True, **kwargs ):
+ def get_data( self, columns=None, start_val=0, max_vals=None, skip_comments=True, **kwargs ):
"""
Returns data from specified columns in dataset. Format is list of lists
where each list is a line of data.
"""
+ if not columns:
+ raise TypeError( 'parameter required: columns' )
+
#TODO: validate kwargs
try:
max_vals = int( max_vals )
@@ -88,11 +91,10 @@
# skip comment lines (if any/avail)
# pre: should have original_dataset and
if( skip_comments
- and start_val == 0
- and self.original_dataset.metadata.comment_lines ):
- start_val = int( self.original_dataset.metadata.comment_lines ) + 1
+ and self.original_dataset.metadata.comment_lines
+ and start_val < self.original_dataset.metadata.comment_lines ):
+ start_val = int( self.original_dataset.metadata.comment_lines )
- #TODO bail if columns None, not parsable, not within meta.columns
# columns is an array of ints for now (should handle column names later)
columns = from_json_string( columns )
for column in columns:
diff -r d13c2f41bff1a19cd996bdcf3457b070e668edae -r 227dcabcaf83f569c2adf5740acc3c04339c759b static/scripts/mvc/visualizations/scatterplotControlForm.js
--- a/static/scripts/mvc/visualizations/scatterplotControlForm.js
+++ b/static/scripts/mvc/visualizations/scatterplotControlForm.js
@@ -562,6 +562,7 @@
var params = {
data_type : 'raw_data',
+ provider : 'column',
columns : '[' + columns + ']'
};
this.log( '\t data settings (url params):', params );
diff -r d13c2f41bff1a19cd996bdcf3457b070e668edae -r 227dcabcaf83f569c2adf5740acc3c04339c759b static/scripts/packed/mvc/visualizations/scatterplotControlForm.js
--- a/static/scripts/packed/mvc/visualizations/scatterplotControlForm.js
+++ b/static/scripts/packed/mvc/visualizations/scatterplotControlForm.js
@@ -1,1 +1,1 @@
-var ScatterplotControlForm=BaseView.extend(LoggableMixin).extend({className:"scatterplot-control-form",dataLoadDelay:4000,dataLoadSize:5000,loadingIndicatorImage:"loading_small_white_bg.gif",fetchMsg:"Fetching data...",renderMsg:"Rendering...",initialize:function(a){this.log(this+".initialize, attributes:",a);this.dataset=null;this.chartConfig=null;this.chart=null;this.loader=null;this.$dataControl=null;this.$chartControl=null;this.$statsDisplay=null;this.$chartDisplay=null;this.dataFetch=null;this.initializeFromAttributes(a);this.initializeChart(a);this.initializeDataLoader(a)},initializeFromAttributes:function(a){if(!a||!a.dataset){throw ("ScatterplotView requires a dataset")}else{this.dataset=a.dataset}if(jQuery.type(this.dataset.metadata_column_types)==="string"){this.dataset.metadata_column_types=this.dataset.metadata_column_types.split(", ")}this.log("\t dataset:",this.dataset);if(this.dataset.comment_lines&&this.dataset.comment_lines.length){var b=this.dataset.comment_lines[0],c=b.split("\t");if(c.length===this.dataset.metadata_column_types.length){this.possibleHeaders=c}}if(!a.apiDatasetsURL){throw ("ScatterplotView requires a apiDatasetsURL")}else{this.dataURL=a.apiDatasetsURL+"/"+this.dataset.id+"?"}this.log("\t dataURL:",this.dataURL)},initializeChart:function(a){this.chartConfig=a.chartConfig||{};this.log("\t initial chartConfig:",this.chartConfig);this.chart=new TwoVarScatterplot(this.chartConfig);this.chartConfig=this.chart.config},initializeDataLoader:function(b){var a=this;this.loader=new LazyDataLoader({url:null,start:b.start||0,total:b.total||this.dataset.metadata_data_lines,delay:this.dataLoadDelay,size:this.dataLoadSize,buildUrl:function(d,c){return this.url+"&"+jQuery.param({start_val:d,max_vals:c})}});$(this.loader).bind("error",function(e,c,d){a.log("ERROR:",c,d);alert("ERROR fetching data:\n"+c+"\n"+d);a.hideLoadingIndicator()})},render:function(){this.log(this+".render");this.$el.append(ScatterplotControlForm.templates.mainLayout({loadingIndicatorImagePath:galaxy_paths.get("image_path")+"/"+this.loadingIndicatorImage,message:""}));this.$dataControl=this._render_dataControl();this.$chartControl=this._render_chartControl();this.$statsDisplay=this.$el.find(".tab-pane#stats-display");this.$chartDisplay=this._render_chartDisplay();if(this.chartConfig.xColumn&&this.chartConfig.yColumn){this.renderChart()}this.$el.find(".tooltip").tooltip();return this},_render_dataControl:function(){var b=this,a=[],e=[],c=(this.possibleHeaders&&this.$dataControl)?(this.$dataControl.find("#first-line-header-checkbox").is(":checked")):(false);_.each(this.dataset.metadata_column_types,function(i,g){var h=g+1,f="column "+h;if(b.dataset.metadata_column_names){f=b.dataset.metadata_column_names[g]}else{if(c){f=b.possibleHeaders[g]}}a.push({index:h,name:f});if(i==="int"||i==="float"){e.push({index:h,name:f})}});var d=this.$el.find(".tab-pane#data-control");d.html(ScatterplotControlForm.templates.dataControl({allColumns:a,numericColumns:e,possibleHeaders:(this.possibleHeaders)?(this.possibleHeaders.join(", ")):(""),usePossibleHeaders:c}));if(!this.dataset.metadata_column_names&&this.possibleHeaders){d.find("#first-line-header").show()}d.find("#X-select").val(this.chartConfig.xColumn);d.find("#Y-select").val(this.chartConfig.yColumn);if(this.chartConfig.idColumn!==undefined){d.find("#include-id-checkbox").attr("checked",true).trigger("change");d.find("#ID-select").val(this.chartConfig.idColumn)}return d},_render_chartControl:function(){var a=this,b=this.$el.find(".tab-pane#chart-control"),c={datapointSize:{min:2,max:10,step:1},width:{min:200,max:800,step:20},height:{min:200,max:800,step:20}};b.append(ScatterplotControlForm.templates.chartControl(this.chartConfig));b.find(".numeric-slider-input").each(function(){var f=$(this),e=f.find(".slider-output"),g=f.find(".slider"),h=f.attr("id");function d(){var j=$(this),i=j.slider("value");e.text(i)}g.slider(_.extend(c[h],{value:a.chartConfig[h],change:d,slide:d}))});return b},_render_chartDisplay:function(){var a=this.$el.find(".tab-pane#chart-display");a.append(ScatterplotControlForm.templates.chartDisplay(this.chartConfig));return a},events:{"change #include-id-checkbox":"toggleThirdColumnSelector","change #first-line-header-checkbox":"rerenderDataControl","click #data-control #render-button":"renderChart","click #chart-control #render-button":"changeChartSettings"},toggleThirdColumnSelector:function(){this.$el.find('select[name="ID"]').parent().toggle()},rerenderDataControl:function(){this.$dataControl=this._render_dataControl()},showLoadingIndicator:function(b,c){b=b||"";var a=this.$el.find("div#loading-indicator");messageBox=a.find(".loading-message");if(a.is(":visible")){if(b){messageBox.fadeOut("fast",function(){messageBox.text(b);messageBox.fadeIn("fast",c)})}else{c()}}else{if(b){messageBox.text(b)}a.fadeIn("fast",c)}},hideLoadingIndicator:function(a){this.$el.find("div#loading-indicator").fadeOut("fast",a)},renderChart:function(){this.log(this+".renderChart");this.data=null;this.meta=null;_.extend(this.chartConfig,this.getChartSettings());this.log("\t chartConfig:",this.chartConfig);this.chart.updateConfig(this.chartConfig,false);this.loader.url=this.dataURL+"&"+jQuery.param(this.getDataSettings());this.log("\t loader: total lines:",this.loader.total," url:",this.loader.url);var a=this;$(this.loader).bind("loaded.new",function(c,b){a.log(a+" loaded.new",b);a.postProcessDataFetchResponse(b);a.log("\t postprocessed data:",a.data);a.log("\t postprocessed meta:",a.meta);a.showLoadingIndicator(a.renderMsg,function(){a.chart.render(a.data,a.meta);a.renderStats(a.data,a.meta);a.hideLoadingIndicator()})});$(this.loader).bind("complete",function(b,c){a.log(a+" complete",c);$(a.loader).unbind()});a.showLoadingIndicator(a.fetchMsg,function(){a.$el.find("ul.nav").find('a[href="#chart-display"]').tab("show");a.loader.load()})},renderStats:function(){this.log(this+".renderStats");this.$statsDisplay.html(ScatterplotControlForm.templates.statsDisplay({stats:[{name:"Count",xval:this.meta[0].count,yval:this.meta[1].count},{name:"Min",xval:this.meta[0].min,yval:this.meta[1].min},{name:"Max",xval:this.meta[0].max,yval:this.meta[1].max},{name:"Sum",xval:this.meta[0].sum,yval:this.meta[1].sum},{name:"Mean",xval:this.meta[0].mean,yval:this.meta[1].mean},{name:"Median",xval:this.meta[0].median,yval:this.meta[1].median}]}))},changeChartSettings:function(){var a=this;newChartSettings=this.getChartSettings();_.extend(this.chartConfig,newChartSettings);this.log("this.chartConfig:",this.chartConfig);this.chart.updateConfig(this.chartConfig,false);if(a.data&&a.meta){a.showLoadingIndicator(a.renderMsg,function(){a.$el.find("ul.nav").find('a[href="#chart-display"]').tab("show");a.chart.render(a.data,a.meta);a.hideLoadingIndicator()})}else{this.renderChart()}},postProcessDataFetchResponse:function(a){this.postProcessData(a.data);this.postProcessMeta(a.meta)},postProcessData:function(b){var a=this;if(a.data){_.each(b,function(d,c){a.data[c]=a.data[c].concat(d)})}else{a.data=b}},postProcessMeta:function(c){var a=this,b=this.dataset.metadata_column_types;if(a.meta){_.each(c,function(e,d){var i=a.meta[d],g=b[d];i.count+=(e.count)?(e.count):(0);if((g==="int")||(g==="float")){i.min=Math.min(e.min,i.min);i.max=Math.max(e.max,i.max);i.sum=e.sum+i.sum;i.mean=(i.count)?(i.sum/i.count):(null);var f=a.data[d].slice().sort(),h=Math.floor(f.length/2);if(f.length%2===0){i.median=((f[h]+f[(h+1)])/2)}else{i.median=f[h]}}})}else{a.meta=c}},getDataSettings:function(){var b=this.getColumnSelections(),a=[];this.log("\t columnSelections:",b);a=[b.X.colIndex-1,b.Y.colIndex-1];if(this.$dataControl.find("#include-id-checkbox").attr("checked")){a.push(b.ID.colIndex-1)}var c={data_type:"raw_data",columns:"["+a+"]"};this.log("\t data settings (url params):",c);return c},getColumnSelections:function(){var a={};this.$dataControl.find("div.column-select select").each(function(){var b=$(this),c=b.val();a[b.attr("name")]={colIndex:c,colName:b.children('[value="'+c+'"]').text()}});return a},getChartSettings:function(){var c={},d=this.getColumnSelections();c.datapointSize=this.$chartControl.find("#datapointSize.numeric-slider-input").find(".slider").slider("value");c.width=this.$chartControl.find("#width.numeric-slider-input").find(".slider").slider("value");c.height=this.$chartControl.find("#height.numeric-slider-input").find(".slider").slider("value");var b=this.$chartControl.find("input#X-axis-label").val(),a=this.$chartControl.find("input#Y-axis-label").val();c.xLabel=(b==="X")?(d.X.colName):(b);c.yLabel=(a==="Y")?(d.Y.colName):(a);c.animDuration=(this.$chartControl.find("#animate-chart").is(":checked"))?(this.chart.defaults.animDuration):(0);this.log("\t chartSettings:",c);return c},toString:function(){return"ScatterplotControlForm("+((this.dataset)?(this.dataset.id):(""))+")"}});ScatterplotControlForm.templates={mainLayout:Handlebars.templates["template-visualization-scatterplotControlForm"],dataControl:Handlebars.templates["template-visualization-dataControl"],chartControl:Handlebars.templates["template-visualization-chartControl"],statsDisplay:Handlebars.templates["template-visualization-statsDisplay"],chartDisplay:Handlebars.templates["template-visualization-chartDisplay"]};
\ No newline at end of file
+var ScatterplotControlForm=BaseView.extend(LoggableMixin).extend({className:"scatterplot-control-form",dataLoadDelay:4000,dataLoadSize:5000,loadingIndicatorImage:"loading_small_white_bg.gif",fetchMsg:"Fetching data...",renderMsg:"Rendering...",initialize:function(a){this.log(this+".initialize, attributes:",a);this.dataset=null;this.chartConfig=null;this.chart=null;this.loader=null;this.$dataControl=null;this.$chartControl=null;this.$statsDisplay=null;this.$chartDisplay=null;this.dataFetch=null;this.initializeFromAttributes(a);this.initializeChart(a);this.initializeDataLoader(a)},initializeFromAttributes:function(a){if(!a||!a.dataset){throw ("ScatterplotView requires a dataset")}else{this.dataset=a.dataset}if(jQuery.type(this.dataset.metadata_column_types)==="string"){this.dataset.metadata_column_types=this.dataset.metadata_column_types.split(", ")}this.log("\t dataset:",this.dataset);if(this.dataset.comment_lines&&this.dataset.comment_lines.length){var b=this.dataset.comment_lines[0],c=b.split("\t");if(c.length===this.dataset.metadata_column_types.length){this.possibleHeaders=c}}if(!a.apiDatasetsURL){throw ("ScatterplotView requires a apiDatasetsURL")}else{this.dataURL=a.apiDatasetsURL+"/"+this.dataset.id+"?"}this.log("\t dataURL:",this.dataURL)},initializeChart:function(a){this.chartConfig=a.chartConfig||{};this.log("\t initial chartConfig:",this.chartConfig);this.chart=new TwoVarScatterplot(this.chartConfig);this.chartConfig=this.chart.config},initializeDataLoader:function(b){var a=this;this.loader=new LazyDataLoader({url:null,start:b.start||0,total:b.total||this.dataset.metadata_data_lines,delay:this.dataLoadDelay,size:this.dataLoadSize,buildUrl:function(d,c){return this.url+"&"+jQuery.param({start_val:d,max_vals:c})}});$(this.loader).bind("error",function(e,c,d){a.log("ERROR:",c,d);alert("ERROR fetching data:\n"+c+"\n"+d);a.hideLoadingIndicator()})},render:function(){this.log(this+".render");this.$el.append(ScatterplotControlForm.templates.mainLayout({loadingIndicatorImagePath:galaxy_paths.get("image_path")+"/"+this.loadingIndicatorImage,message:""}));this.$dataControl=this._render_dataControl();this.$chartControl=this._render_chartControl();this.$statsDisplay=this.$el.find(".tab-pane#stats-display");this.$chartDisplay=this._render_chartDisplay();if(this.chartConfig.xColumn&&this.chartConfig.yColumn){this.renderChart()}this.$el.find(".tooltip").tooltip();return this},_render_dataControl:function(){var b=this,a=[],e=[],c=(this.possibleHeaders&&this.$dataControl)?(this.$dataControl.find("#first-line-header-checkbox").is(":checked")):(false);_.each(this.dataset.metadata_column_types,function(i,g){var h=g+1,f="column "+h;if(b.dataset.metadata_column_names){f=b.dataset.metadata_column_names[g]}else{if(c){f=b.possibleHeaders[g]}}a.push({index:h,name:f});if(i==="int"||i==="float"){e.push({index:h,name:f})}});var d=this.$el.find(".tab-pane#data-control");d.html(ScatterplotControlForm.templates.dataControl({allColumns:a,numericColumns:e,possibleHeaders:(this.possibleHeaders)?(this.possibleHeaders.join(", ")):(""),usePossibleHeaders:c}));if(!this.dataset.metadata_column_names&&this.possibleHeaders){d.find("#first-line-header").show()}d.find("#X-select").val(this.chartConfig.xColumn);d.find("#Y-select").val(this.chartConfig.yColumn);if(this.chartConfig.idColumn!==undefined){d.find("#include-id-checkbox").attr("checked",true).trigger("change");d.find("#ID-select").val(this.chartConfig.idColumn)}return d},_render_chartControl:function(){var a=this,b=this.$el.find(".tab-pane#chart-control"),c={datapointSize:{min:2,max:10,step:1},width:{min:200,max:800,step:20},height:{min:200,max:800,step:20}};b.append(ScatterplotControlForm.templates.chartControl(this.chartConfig));b.find(".numeric-slider-input").each(function(){var f=$(this),e=f.find(".slider-output"),g=f.find(".slider"),h=f.attr("id");function d(){var j=$(this),i=j.slider("value");e.text(i)}g.slider(_.extend(c[h],{value:a.chartConfig[h],change:d,slide:d}))});return b},_render_chartDisplay:function(){var a=this.$el.find(".tab-pane#chart-display");a.append(ScatterplotControlForm.templates.chartDisplay(this.chartConfig));return a},events:{"change #include-id-checkbox":"toggleThirdColumnSelector","change #first-line-header-checkbox":"rerenderDataControl","click #data-control #render-button":"renderChart","click #chart-control #render-button":"changeChartSettings"},toggleThirdColumnSelector:function(){this.$el.find('select[name="ID"]').parent().toggle()},rerenderDataControl:function(){this.$dataControl=this._render_dataControl()},showLoadingIndicator:function(b,c){b=b||"";var a=this.$el.find("div#loading-indicator");messageBox=a.find(".loading-message");if(a.is(":visible")){if(b){messageBox.fadeOut("fast",function(){messageBox.text(b);messageBox.fadeIn("fast",c)})}else{c()}}else{if(b){messageBox.text(b)}a.fadeIn("fast",c)}},hideLoadingIndicator:function(a){this.$el.find("div#loading-indicator").fadeOut("fast",a)},renderChart:function(){this.log(this+".renderChart");this.data=null;this.meta=null;_.extend(this.chartConfig,this.getChartSettings());this.log("\t chartConfig:",this.chartConfig);this.chart.updateConfig(this.chartConfig,false);this.loader.url=this.dataURL+"&"+jQuery.param(this.getDataSettings());this.log("\t loader: total lines:",this.loader.total," url:",this.loader.url);var a=this;$(this.loader).bind("loaded.new",function(c,b){a.log(a+" loaded.new",b);a.postProcessDataFetchResponse(b);a.log("\t postprocessed data:",a.data);a.log("\t postprocessed meta:",a.meta);a.showLoadingIndicator(a.renderMsg,function(){a.chart.render(a.data,a.meta);a.renderStats(a.data,a.meta);a.hideLoadingIndicator()})});$(this.loader).bind("complete",function(b,c){a.log(a+" complete",c);$(a.loader).unbind()});a.showLoadingIndicator(a.fetchMsg,function(){a.$el.find("ul.nav").find('a[href="#chart-display"]').tab("show");a.loader.load()})},renderStats:function(){this.log(this+".renderStats");this.$statsDisplay.html(ScatterplotControlForm.templates.statsDisplay({stats:[{name:"Count",xval:this.meta[0].count,yval:this.meta[1].count},{name:"Min",xval:this.meta[0].min,yval:this.meta[1].min},{name:"Max",xval:this.meta[0].max,yval:this.meta[1].max},{name:"Sum",xval:this.meta[0].sum,yval:this.meta[1].sum},{name:"Mean",xval:this.meta[0].mean,yval:this.meta[1].mean},{name:"Median",xval:this.meta[0].median,yval:this.meta[1].median}]}))},changeChartSettings:function(){var a=this;newChartSettings=this.getChartSettings();_.extend(this.chartConfig,newChartSettings);this.log("this.chartConfig:",this.chartConfig);this.chart.updateConfig(this.chartConfig,false);if(a.data&&a.meta){a.showLoadingIndicator(a.renderMsg,function(){a.$el.find("ul.nav").find('a[href="#chart-display"]').tab("show");a.chart.render(a.data,a.meta);a.hideLoadingIndicator()})}else{this.renderChart()}},postProcessDataFetchResponse:function(a){this.postProcessData(a.data);this.postProcessMeta(a.meta)},postProcessData:function(b){var a=this;if(a.data){_.each(b,function(d,c){a.data[c]=a.data[c].concat(d)})}else{a.data=b}},postProcessMeta:function(c){var a=this,b=this.dataset.metadata_column_types;if(a.meta){_.each(c,function(e,d){var i=a.meta[d],g=b[d];i.count+=(e.count)?(e.count):(0);if((g==="int")||(g==="float")){i.min=Math.min(e.min,i.min);i.max=Math.max(e.max,i.max);i.sum=e.sum+i.sum;i.mean=(i.count)?(i.sum/i.count):(null);var f=a.data[d].slice().sort(),h=Math.floor(f.length/2);if(f.length%2===0){i.median=((f[h]+f[(h+1)])/2)}else{i.median=f[h]}}})}else{a.meta=c}},getDataSettings:function(){var b=this.getColumnSelections(),a=[];this.log("\t columnSelections:",b);a=[b.X.colIndex-1,b.Y.colIndex-1];if(this.$dataControl.find("#include-id-checkbox").attr("checked")){a.push(b.ID.colIndex-1)}var c={data_type:"raw_data",provider:"column",columns:"["+a+"]"};this.log("\t data settings (url params):",c);return c},getColumnSelections:function(){var a={};this.$dataControl.find("div.column-select select").each(function(){var b=$(this),c=b.val();a[b.attr("name")]={colIndex:c,colName:b.children('[value="'+c+'"]').text()}});return a},getChartSettings:function(){var c={},d=this.getColumnSelections();c.datapointSize=this.$chartControl.find("#datapointSize.numeric-slider-input").find(".slider").slider("value");c.width=this.$chartControl.find("#width.numeric-slider-input").find(".slider").slider("value");c.height=this.$chartControl.find("#height.numeric-slider-input").find(".slider").slider("value");var b=this.$chartControl.find("input#X-axis-label").val(),a=this.$chartControl.find("input#Y-axis-label").val();c.xLabel=(b==="X")?(d.X.colName):(b);c.yLabel=(a==="Y")?(d.Y.colName):(a);c.animDuration=(this.$chartControl.find("#animate-chart").is(":checked"))?(this.chart.defaults.animDuration):(0);this.log("\t chartSettings:",c);return c},toString:function(){return"ScatterplotControlForm("+((this.dataset)?(this.dataset.id):(""))+")"}});ScatterplotControlForm.templates={mainLayout:Handlebars.templates["template-visualization-scatterplotControlForm"],dataControl:Handlebars.templates["template-visualization-dataControl"],chartControl:Handlebars.templates["template-visualization-chartControl"],statsDisplay:Handlebars.templates["template-visualization-statsDisplay"],chartDisplay:Handlebars.templates["template-visualization-chartDisplay"]};
\ No newline at end of file
diff -r d13c2f41bff1a19cd996bdcf3457b070e668edae -r 227dcabcaf83f569c2adf5740acc3c04339c759b static/scripts/viz/scatterplot.js
--- a/static/scripts/viz/scatterplot.js
+++ b/static/scripts/viz/scatterplot.js
@@ -138,16 +138,16 @@
bottom = bottom || 0;
left = left || 0;
this.svg
- .attr( "width", this.config.width + ( this.config.marginRight + right ) +
- ( this.config.marginLeft + left ) )
- .attr( "height", this.config.height + ( this.config.marginTop + top ) +
- ( this.config.marginBottom + bottom ) )
+ .attr( "width", this.config.width + ( this.config.marginRight + right )
+ + ( this.config.marginLeft + left ) )
+ .attr( "height", this.config.height + ( this.config.marginTop + top )
+ + ( this.config.marginBottom + bottom ) )
// initial is hidden - show it
.style( 'display', 'block' );
// move content group away from margins
//TODO: allow top, right axis
- this.content = this.svg.select( "g.content" )
+ this.content = this.svg.select( "g.content" )
.attr( "transform", this.translateStr( this.config.marginLeft + left, this.config.marginTop + top ) );
};
@@ -260,7 +260,7 @@
.attr( 'text-anchor', 'middle' )
.attr( 'transform', this.rotateStr( -90, this.config.yAxisLabelBumpX, this.config.height / 2 ) )
.text( this.config.yLabel );
- //this.log( 'yAxisLabel:', this.yAxisLabel );
+ //this.log( 'yAxisLabel:', this.yAxisLabel );
};
// ........................................................ grid lines
@@ -284,7 +284,7 @@
// remove unneeded (less ticks)
this.vGridLines.exit().remove();
- //this.log( 'vGridLines:', this.vGridLines );
+ //this.log( 'vGridLines:', this.vGridLines );
// HORIZONTAL
this.hGridLines = this.content.selectAll( 'line.h-grid-line' )
diff -r d13c2f41bff1a19cd996bdcf3457b070e668edae -r 227dcabcaf83f569c2adf5740acc3c04339c759b templates/webapps/galaxy/visualization/scatterplot.mako
--- a/templates/webapps/galaxy/visualization/scatterplot.mako
+++ b/templates/webapps/galaxy/visualization/scatterplot.mako
@@ -222,8 +222,7 @@
<script type="text/javascript">
$(function(){
- var hda = ${h.to_json_string( hda.get_api_value() )},
- historyID = '${trans.security.encode_id( hda.history.id )}',
+ var hda = ${h.to_json_string( trans.security.encode_dict_ids( hda.get_api_value() ) )},
querySettings = ${h.to_json_string( query_args )},
chartConfig = _.extend( querySettings, {
containerSelector : '#chart',
https://bitbucket.org/galaxy/galaxy-central/commits/9065758599a4/
Changeset: 9065758599a4
User: carlfeberhard
Date: 2013-05-21 18:54:49
Summary: merge next-stable
Affected #: 6 files
diff -r 61dd8d5c33e566b8ec28fb3cbd22de50226dbbd9 -r 9065758599a411615e24ffd9374a18d302f95a09 lib/galaxy/datatypes/tabular.py
--- a/lib/galaxy/datatypes/tabular.py
+++ b/lib/galaxy/datatypes/tabular.py
@@ -328,7 +328,6 @@
"""
Returns a list of visualizations for datatype.
"""
-
# Can visualize tabular data as scatterplot if there are 2+ numerical
# columns.
num_numerical_cols = 0
diff -r 61dd8d5c33e566b8ec28fb3cbd22de50226dbbd9 -r 9065758599a411615e24ffd9374a18d302f95a09 lib/galaxy/visualization/data_providers/basic.py
--- a/lib/galaxy/visualization/data_providers/basic.py
+++ b/lib/galaxy/visualization/data_providers/basic.py
@@ -67,11 +67,14 @@
# allow throttling
self.max_lines_returned = max_lines_returned
- def get_data( self, columns, start_val=0, max_vals=None, skip_comments=True, **kwargs ):
+ def get_data( self, columns=None, start_val=0, max_vals=None, skip_comments=True, **kwargs ):
"""
Returns data from specified columns in dataset. Format is list of lists
where each list is a line of data.
"""
+ if not columns:
+ raise TypeError( 'parameter required: columns' )
+
#TODO: validate kwargs
try:
max_vals = int( max_vals )
@@ -88,11 +91,10 @@
# skip comment lines (if any/avail)
# pre: should have original_dataset and
if( skip_comments
- and start_val == 0
- and self.original_dataset.metadata.comment_lines ):
- start_val = int( self.original_dataset.metadata.comment_lines ) + 1
+ and self.original_dataset.metadata.comment_lines
+ and start_val < self.original_dataset.metadata.comment_lines ):
+ start_val = int( self.original_dataset.metadata.comment_lines )
- #TODO bail if columns None, not parsable, not within meta.columns
# columns is an array of ints for now (should handle column names later)
columns = from_json_string( columns )
for column in columns:
diff -r 61dd8d5c33e566b8ec28fb3cbd22de50226dbbd9 -r 9065758599a411615e24ffd9374a18d302f95a09 static/scripts/mvc/visualizations/scatterplotControlForm.js
--- a/static/scripts/mvc/visualizations/scatterplotControlForm.js
+++ b/static/scripts/mvc/visualizations/scatterplotControlForm.js
@@ -562,6 +562,7 @@
var params = {
data_type : 'raw_data',
+ provider : 'column',
columns : '[' + columns + ']'
};
this.log( '\t data settings (url params):', params );
diff -r 61dd8d5c33e566b8ec28fb3cbd22de50226dbbd9 -r 9065758599a411615e24ffd9374a18d302f95a09 static/scripts/packed/mvc/visualizations/scatterplotControlForm.js
--- a/static/scripts/packed/mvc/visualizations/scatterplotControlForm.js
+++ b/static/scripts/packed/mvc/visualizations/scatterplotControlForm.js
@@ -1,1 +1,1 @@
-var ScatterplotControlForm=BaseView.extend(LoggableMixin).extend({className:"scatterplot-control-form",dataLoadDelay:4000,dataLoadSize:5000,loadingIndicatorImage:"loading_small_white_bg.gif",fetchMsg:"Fetching data...",renderMsg:"Rendering...",initialize:function(a){this.log(this+".initialize, attributes:",a);this.dataset=null;this.chartConfig=null;this.chart=null;this.loader=null;this.$dataControl=null;this.$chartControl=null;this.$statsDisplay=null;this.$chartDisplay=null;this.dataFetch=null;this.initializeFromAttributes(a);this.initializeChart(a);this.initializeDataLoader(a)},initializeFromAttributes:function(a){if(!a||!a.dataset){throw ("ScatterplotView requires a dataset")}else{this.dataset=a.dataset}if(jQuery.type(this.dataset.metadata_column_types)==="string"){this.dataset.metadata_column_types=this.dataset.metadata_column_types.split(", ")}this.log("\t dataset:",this.dataset);if(this.dataset.comment_lines&&this.dataset.comment_lines.length){var b=this.dataset.comment_lines[0],c=b.split("\t");if(c.length===this.dataset.metadata_column_types.length){this.possibleHeaders=c}}if(!a.apiDatasetsURL){throw ("ScatterplotView requires a apiDatasetsURL")}else{this.dataURL=a.apiDatasetsURL+"/"+this.dataset.id+"?"}this.log("\t dataURL:",this.dataURL)},initializeChart:function(a){this.chartConfig=a.chartConfig||{};this.log("\t initial chartConfig:",this.chartConfig);this.chart=new TwoVarScatterplot(this.chartConfig);this.chartConfig=this.chart.config},initializeDataLoader:function(b){var a=this;this.loader=new LazyDataLoader({url:null,start:b.start||0,total:b.total||this.dataset.metadata_data_lines,delay:this.dataLoadDelay,size:this.dataLoadSize,buildUrl:function(d,c){return this.url+"&"+jQuery.param({start_val:d,max_vals:c})}});$(this.loader).bind("error",function(e,c,d){a.log("ERROR:",c,d);alert("ERROR fetching data:\n"+c+"\n"+d);a.hideLoadingIndicator()})},render:function(){this.log(this+".render");this.$el.append(ScatterplotControlForm.templates.mainLayout({loadingIndicatorImagePath:galaxy_paths.get("image_path")+"/"+this.loadingIndicatorImage,message:""}));this.$dataControl=this._render_dataControl();this.$chartControl=this._render_chartControl();this.$statsDisplay=this.$el.find(".tab-pane#stats-display");this.$chartDisplay=this._render_chartDisplay();if(this.chartConfig.xColumn&&this.chartConfig.yColumn){this.renderChart()}this.$el.find(".tooltip").tooltip();return this},_render_dataControl:function(){var b=this,a=[],e=[],c=(this.possibleHeaders&&this.$dataControl)?(this.$dataControl.find("#first-line-header-checkbox").is(":checked")):(false);_.each(this.dataset.metadata_column_types,function(i,g){var h=g+1,f="column "+h;if(b.dataset.metadata_column_names){f=b.dataset.metadata_column_names[g]}else{if(c){f=b.possibleHeaders[g]}}a.push({index:h,name:f});if(i==="int"||i==="float"){e.push({index:h,name:f})}});var d=this.$el.find(".tab-pane#data-control");d.html(ScatterplotControlForm.templates.dataControl({allColumns:a,numericColumns:e,possibleHeaders:(this.possibleHeaders)?(this.possibleHeaders.join(", ")):(""),usePossibleHeaders:c}));if(!this.dataset.metadata_column_names&&this.possibleHeaders){d.find("#first-line-header").show()}d.find("#X-select").val(this.chartConfig.xColumn);d.find("#Y-select").val(this.chartConfig.yColumn);if(this.chartConfig.idColumn!==undefined){d.find("#include-id-checkbox").attr("checked",true).trigger("change");d.find("#ID-select").val(this.chartConfig.idColumn)}return d},_render_chartControl:function(){var a=this,b=this.$el.find(".tab-pane#chart-control"),c={datapointSize:{min:2,max:10,step:1},width:{min:200,max:800,step:20},height:{min:200,max:800,step:20}};b.append(ScatterplotControlForm.templates.chartControl(this.chartConfig));b.find(".numeric-slider-input").each(function(){var f=$(this),e=f.find(".slider-output"),g=f.find(".slider"),h=f.attr("id");function d(){var j=$(this),i=j.slider("value");e.text(i)}g.slider(_.extend(c[h],{value:a.chartConfig[h],change:d,slide:d}))});return b},_render_chartDisplay:function(){var a=this.$el.find(".tab-pane#chart-display");a.append(ScatterplotControlForm.templates.chartDisplay(this.chartConfig));return a},events:{"change #include-id-checkbox":"toggleThirdColumnSelector","change #first-line-header-checkbox":"rerenderDataControl","click #data-control #render-button":"renderChart","click #chart-control #render-button":"changeChartSettings"},toggleThirdColumnSelector:function(){this.$el.find('select[name="ID"]').parent().toggle()},rerenderDataControl:function(){this.$dataControl=this._render_dataControl()},showLoadingIndicator:function(b,c){b=b||"";var a=this.$el.find("div#loading-indicator");messageBox=a.find(".loading-message");if(a.is(":visible")){if(b){messageBox.fadeOut("fast",function(){messageBox.text(b);messageBox.fadeIn("fast",c)})}else{c()}}else{if(b){messageBox.text(b)}a.fadeIn("fast",c)}},hideLoadingIndicator:function(a){this.$el.find("div#loading-indicator").fadeOut("fast",a)},renderChart:function(){this.log(this+".renderChart");this.data=null;this.meta=null;_.extend(this.chartConfig,this.getChartSettings());this.log("\t chartConfig:",this.chartConfig);this.chart.updateConfig(this.chartConfig,false);this.loader.url=this.dataURL+"&"+jQuery.param(this.getDataSettings());this.log("\t loader: total lines:",this.loader.total," url:",this.loader.url);var a=this;$(this.loader).bind("loaded.new",function(c,b){a.log(a+" loaded.new",b);a.postProcessDataFetchResponse(b);a.log("\t postprocessed data:",a.data);a.log("\t postprocessed meta:",a.meta);a.showLoadingIndicator(a.renderMsg,function(){a.chart.render(a.data,a.meta);a.renderStats(a.data,a.meta);a.hideLoadingIndicator()})});$(this.loader).bind("complete",function(b,c){a.log(a+" complete",c);$(a.loader).unbind()});a.showLoadingIndicator(a.fetchMsg,function(){a.$el.find("ul.nav").find('a[href="#chart-display"]').tab("show");a.loader.load()})},renderStats:function(){this.log(this+".renderStats");this.$statsDisplay.html(ScatterplotControlForm.templates.statsDisplay({stats:[{name:"Count",xval:this.meta[0].count,yval:this.meta[1].count},{name:"Min",xval:this.meta[0].min,yval:this.meta[1].min},{name:"Max",xval:this.meta[0].max,yval:this.meta[1].max},{name:"Sum",xval:this.meta[0].sum,yval:this.meta[1].sum},{name:"Mean",xval:this.meta[0].mean,yval:this.meta[1].mean},{name:"Median",xval:this.meta[0].median,yval:this.meta[1].median}]}))},changeChartSettings:function(){var a=this;newChartSettings=this.getChartSettings();_.extend(this.chartConfig,newChartSettings);this.log("this.chartConfig:",this.chartConfig);this.chart.updateConfig(this.chartConfig,false);if(a.data&&a.meta){a.showLoadingIndicator(a.renderMsg,function(){a.$el.find("ul.nav").find('a[href="#chart-display"]').tab("show");a.chart.render(a.data,a.meta);a.hideLoadingIndicator()})}else{this.renderChart()}},postProcessDataFetchResponse:function(a){this.postProcessData(a.data);this.postProcessMeta(a.meta)},postProcessData:function(b){var a=this;if(a.data){_.each(b,function(d,c){a.data[c]=a.data[c].concat(d)})}else{a.data=b}},postProcessMeta:function(c){var a=this,b=this.dataset.metadata_column_types;if(a.meta){_.each(c,function(e,d){var i=a.meta[d],g=b[d];i.count+=(e.count)?(e.count):(0);if((g==="int")||(g==="float")){i.min=Math.min(e.min,i.min);i.max=Math.max(e.max,i.max);i.sum=e.sum+i.sum;i.mean=(i.count)?(i.sum/i.count):(null);var f=a.data[d].slice().sort(),h=Math.floor(f.length/2);if(f.length%2===0){i.median=((f[h]+f[(h+1)])/2)}else{i.median=f[h]}}})}else{a.meta=c}},getDataSettings:function(){var b=this.getColumnSelections(),a=[];this.log("\t columnSelections:",b);a=[b.X.colIndex-1,b.Y.colIndex-1];if(this.$dataControl.find("#include-id-checkbox").attr("checked")){a.push(b.ID.colIndex-1)}var c={data_type:"raw_data",columns:"["+a+"]"};this.log("\t data settings (url params):",c);return c},getColumnSelections:function(){var a={};this.$dataControl.find("div.column-select select").each(function(){var b=$(this),c=b.val();a[b.attr("name")]={colIndex:c,colName:b.children('[value="'+c+'"]').text()}});return a},getChartSettings:function(){var c={},d=this.getColumnSelections();c.datapointSize=this.$chartControl.find("#datapointSize.numeric-slider-input").find(".slider").slider("value");c.width=this.$chartControl.find("#width.numeric-slider-input").find(".slider").slider("value");c.height=this.$chartControl.find("#height.numeric-slider-input").find(".slider").slider("value");var b=this.$chartControl.find("input#X-axis-label").val(),a=this.$chartControl.find("input#Y-axis-label").val();c.xLabel=(b==="X")?(d.X.colName):(b);c.yLabel=(a==="Y")?(d.Y.colName):(a);c.animDuration=(this.$chartControl.find("#animate-chart").is(":checked"))?(this.chart.defaults.animDuration):(0);this.log("\t chartSettings:",c);return c},toString:function(){return"ScatterplotControlForm("+((this.dataset)?(this.dataset.id):(""))+")"}});ScatterplotControlForm.templates={mainLayout:Handlebars.templates["template-visualization-scatterplotControlForm"],dataControl:Handlebars.templates["template-visualization-dataControl"],chartControl:Handlebars.templates["template-visualization-chartControl"],statsDisplay:Handlebars.templates["template-visualization-statsDisplay"],chartDisplay:Handlebars.templates["template-visualization-chartDisplay"]};
\ No newline at end of file
+var ScatterplotControlForm=BaseView.extend(LoggableMixin).extend({className:"scatterplot-control-form",dataLoadDelay:4000,dataLoadSize:5000,loadingIndicatorImage:"loading_small_white_bg.gif",fetchMsg:"Fetching data...",renderMsg:"Rendering...",initialize:function(a){this.log(this+".initialize, attributes:",a);this.dataset=null;this.chartConfig=null;this.chart=null;this.loader=null;this.$dataControl=null;this.$chartControl=null;this.$statsDisplay=null;this.$chartDisplay=null;this.dataFetch=null;this.initializeFromAttributes(a);this.initializeChart(a);this.initializeDataLoader(a)},initializeFromAttributes:function(a){if(!a||!a.dataset){throw ("ScatterplotView requires a dataset")}else{this.dataset=a.dataset}if(jQuery.type(this.dataset.metadata_column_types)==="string"){this.dataset.metadata_column_types=this.dataset.metadata_column_types.split(", ")}this.log("\t dataset:",this.dataset);if(this.dataset.comment_lines&&this.dataset.comment_lines.length){var b=this.dataset.comment_lines[0],c=b.split("\t");if(c.length===this.dataset.metadata_column_types.length){this.possibleHeaders=c}}if(!a.apiDatasetsURL){throw ("ScatterplotView requires a apiDatasetsURL")}else{this.dataURL=a.apiDatasetsURL+"/"+this.dataset.id+"?"}this.log("\t dataURL:",this.dataURL)},initializeChart:function(a){this.chartConfig=a.chartConfig||{};this.log("\t initial chartConfig:",this.chartConfig);this.chart=new TwoVarScatterplot(this.chartConfig);this.chartConfig=this.chart.config},initializeDataLoader:function(b){var a=this;this.loader=new LazyDataLoader({url:null,start:b.start||0,total:b.total||this.dataset.metadata_data_lines,delay:this.dataLoadDelay,size:this.dataLoadSize,buildUrl:function(d,c){return this.url+"&"+jQuery.param({start_val:d,max_vals:c})}});$(this.loader).bind("error",function(e,c,d){a.log("ERROR:",c,d);alert("ERROR fetching data:\n"+c+"\n"+d);a.hideLoadingIndicator()})},render:function(){this.log(this+".render");this.$el.append(ScatterplotControlForm.templates.mainLayout({loadingIndicatorImagePath:galaxy_paths.get("image_path")+"/"+this.loadingIndicatorImage,message:""}));this.$dataControl=this._render_dataControl();this.$chartControl=this._render_chartControl();this.$statsDisplay=this.$el.find(".tab-pane#stats-display");this.$chartDisplay=this._render_chartDisplay();if(this.chartConfig.xColumn&&this.chartConfig.yColumn){this.renderChart()}this.$el.find(".tooltip").tooltip();return this},_render_dataControl:function(){var b=this,a=[],e=[],c=(this.possibleHeaders&&this.$dataControl)?(this.$dataControl.find("#first-line-header-checkbox").is(":checked")):(false);_.each(this.dataset.metadata_column_types,function(i,g){var h=g+1,f="column "+h;if(b.dataset.metadata_column_names){f=b.dataset.metadata_column_names[g]}else{if(c){f=b.possibleHeaders[g]}}a.push({index:h,name:f});if(i==="int"||i==="float"){e.push({index:h,name:f})}});var d=this.$el.find(".tab-pane#data-control");d.html(ScatterplotControlForm.templates.dataControl({allColumns:a,numericColumns:e,possibleHeaders:(this.possibleHeaders)?(this.possibleHeaders.join(", ")):(""),usePossibleHeaders:c}));if(!this.dataset.metadata_column_names&&this.possibleHeaders){d.find("#first-line-header").show()}d.find("#X-select").val(this.chartConfig.xColumn);d.find("#Y-select").val(this.chartConfig.yColumn);if(this.chartConfig.idColumn!==undefined){d.find("#include-id-checkbox").attr("checked",true).trigger("change");d.find("#ID-select").val(this.chartConfig.idColumn)}return d},_render_chartControl:function(){var a=this,b=this.$el.find(".tab-pane#chart-control"),c={datapointSize:{min:2,max:10,step:1},width:{min:200,max:800,step:20},height:{min:200,max:800,step:20}};b.append(ScatterplotControlForm.templates.chartControl(this.chartConfig));b.find(".numeric-slider-input").each(function(){var f=$(this),e=f.find(".slider-output"),g=f.find(".slider"),h=f.attr("id");function d(){var j=$(this),i=j.slider("value");e.text(i)}g.slider(_.extend(c[h],{value:a.chartConfig[h],change:d,slide:d}))});return b},_render_chartDisplay:function(){var a=this.$el.find(".tab-pane#chart-display");a.append(ScatterplotControlForm.templates.chartDisplay(this.chartConfig));return a},events:{"change #include-id-checkbox":"toggleThirdColumnSelector","change #first-line-header-checkbox":"rerenderDataControl","click #data-control #render-button":"renderChart","click #chart-control #render-button":"changeChartSettings"},toggleThirdColumnSelector:function(){this.$el.find('select[name="ID"]').parent().toggle()},rerenderDataControl:function(){this.$dataControl=this._render_dataControl()},showLoadingIndicator:function(b,c){b=b||"";var a=this.$el.find("div#loading-indicator");messageBox=a.find(".loading-message");if(a.is(":visible")){if(b){messageBox.fadeOut("fast",function(){messageBox.text(b);messageBox.fadeIn("fast",c)})}else{c()}}else{if(b){messageBox.text(b)}a.fadeIn("fast",c)}},hideLoadingIndicator:function(a){this.$el.find("div#loading-indicator").fadeOut("fast",a)},renderChart:function(){this.log(this+".renderChart");this.data=null;this.meta=null;_.extend(this.chartConfig,this.getChartSettings());this.log("\t chartConfig:",this.chartConfig);this.chart.updateConfig(this.chartConfig,false);this.loader.url=this.dataURL+"&"+jQuery.param(this.getDataSettings());this.log("\t loader: total lines:",this.loader.total," url:",this.loader.url);var a=this;$(this.loader).bind("loaded.new",function(c,b){a.log(a+" loaded.new",b);a.postProcessDataFetchResponse(b);a.log("\t postprocessed data:",a.data);a.log("\t postprocessed meta:",a.meta);a.showLoadingIndicator(a.renderMsg,function(){a.chart.render(a.data,a.meta);a.renderStats(a.data,a.meta);a.hideLoadingIndicator()})});$(this.loader).bind("complete",function(b,c){a.log(a+" complete",c);$(a.loader).unbind()});a.showLoadingIndicator(a.fetchMsg,function(){a.$el.find("ul.nav").find('a[href="#chart-display"]').tab("show");a.loader.load()})},renderStats:function(){this.log(this+".renderStats");this.$statsDisplay.html(ScatterplotControlForm.templates.statsDisplay({stats:[{name:"Count",xval:this.meta[0].count,yval:this.meta[1].count},{name:"Min",xval:this.meta[0].min,yval:this.meta[1].min},{name:"Max",xval:this.meta[0].max,yval:this.meta[1].max},{name:"Sum",xval:this.meta[0].sum,yval:this.meta[1].sum},{name:"Mean",xval:this.meta[0].mean,yval:this.meta[1].mean},{name:"Median",xval:this.meta[0].median,yval:this.meta[1].median}]}))},changeChartSettings:function(){var a=this;newChartSettings=this.getChartSettings();_.extend(this.chartConfig,newChartSettings);this.log("this.chartConfig:",this.chartConfig);this.chart.updateConfig(this.chartConfig,false);if(a.data&&a.meta){a.showLoadingIndicator(a.renderMsg,function(){a.$el.find("ul.nav").find('a[href="#chart-display"]').tab("show");a.chart.render(a.data,a.meta);a.hideLoadingIndicator()})}else{this.renderChart()}},postProcessDataFetchResponse:function(a){this.postProcessData(a.data);this.postProcessMeta(a.meta)},postProcessData:function(b){var a=this;if(a.data){_.each(b,function(d,c){a.data[c]=a.data[c].concat(d)})}else{a.data=b}},postProcessMeta:function(c){var a=this,b=this.dataset.metadata_column_types;if(a.meta){_.each(c,function(e,d){var i=a.meta[d],g=b[d];i.count+=(e.count)?(e.count):(0);if((g==="int")||(g==="float")){i.min=Math.min(e.min,i.min);i.max=Math.max(e.max,i.max);i.sum=e.sum+i.sum;i.mean=(i.count)?(i.sum/i.count):(null);var f=a.data[d].slice().sort(),h=Math.floor(f.length/2);if(f.length%2===0){i.median=((f[h]+f[(h+1)])/2)}else{i.median=f[h]}}})}else{a.meta=c}},getDataSettings:function(){var b=this.getColumnSelections(),a=[];this.log("\t columnSelections:",b);a=[b.X.colIndex-1,b.Y.colIndex-1];if(this.$dataControl.find("#include-id-checkbox").attr("checked")){a.push(b.ID.colIndex-1)}var c={data_type:"raw_data",provider:"column",columns:"["+a+"]"};this.log("\t data settings (url params):",c);return c},getColumnSelections:function(){var a={};this.$dataControl.find("div.column-select select").each(function(){var b=$(this),c=b.val();a[b.attr("name")]={colIndex:c,colName:b.children('[value="'+c+'"]').text()}});return a},getChartSettings:function(){var c={},d=this.getColumnSelections();c.datapointSize=this.$chartControl.find("#datapointSize.numeric-slider-input").find(".slider").slider("value");c.width=this.$chartControl.find("#width.numeric-slider-input").find(".slider").slider("value");c.height=this.$chartControl.find("#height.numeric-slider-input").find(".slider").slider("value");var b=this.$chartControl.find("input#X-axis-label").val(),a=this.$chartControl.find("input#Y-axis-label").val();c.xLabel=(b==="X")?(d.X.colName):(b);c.yLabel=(a==="Y")?(d.Y.colName):(a);c.animDuration=(this.$chartControl.find("#animate-chart").is(":checked"))?(this.chart.defaults.animDuration):(0);this.log("\t chartSettings:",c);return c},toString:function(){return"ScatterplotControlForm("+((this.dataset)?(this.dataset.id):(""))+")"}});ScatterplotControlForm.templates={mainLayout:Handlebars.templates["template-visualization-scatterplotControlForm"],dataControl:Handlebars.templates["template-visualization-dataControl"],chartControl:Handlebars.templates["template-visualization-chartControl"],statsDisplay:Handlebars.templates["template-visualization-statsDisplay"],chartDisplay:Handlebars.templates["template-visualization-chartDisplay"]};
\ No newline at end of file
diff -r 61dd8d5c33e566b8ec28fb3cbd22de50226dbbd9 -r 9065758599a411615e24ffd9374a18d302f95a09 static/scripts/viz/scatterplot.js
--- a/static/scripts/viz/scatterplot.js
+++ b/static/scripts/viz/scatterplot.js
@@ -138,16 +138,16 @@
bottom = bottom || 0;
left = left || 0;
this.svg
- .attr( "width", this.config.width + ( this.config.marginRight + right ) +
- ( this.config.marginLeft + left ) )
- .attr( "height", this.config.height + ( this.config.marginTop + top ) +
- ( this.config.marginBottom + bottom ) )
+ .attr( "width", this.config.width + ( this.config.marginRight + right )
+ + ( this.config.marginLeft + left ) )
+ .attr( "height", this.config.height + ( this.config.marginTop + top )
+ + ( this.config.marginBottom + bottom ) )
// initial is hidden - show it
.style( 'display', 'block' );
// move content group away from margins
//TODO: allow top, right axis
- this.content = this.svg.select( "g.content" )
+ this.content = this.svg.select( "g.content" )
.attr( "transform", this.translateStr( this.config.marginLeft + left, this.config.marginTop + top ) );
};
@@ -260,7 +260,7 @@
.attr( 'text-anchor', 'middle' )
.attr( 'transform', this.rotateStr( -90, this.config.yAxisLabelBumpX, this.config.height / 2 ) )
.text( this.config.yLabel );
- //this.log( 'yAxisLabel:', this.yAxisLabel );
+ //this.log( 'yAxisLabel:', this.yAxisLabel );
};
// ........................................................ grid lines
@@ -284,7 +284,7 @@
// remove unneeded (less ticks)
this.vGridLines.exit().remove();
- //this.log( 'vGridLines:', this.vGridLines );
+ //this.log( 'vGridLines:', this.vGridLines );
// HORIZONTAL
this.hGridLines = this.content.selectAll( 'line.h-grid-line' )
diff -r 61dd8d5c33e566b8ec28fb3cbd22de50226dbbd9 -r 9065758599a411615e24ffd9374a18d302f95a09 templates/webapps/galaxy/visualization/scatterplot.mako
--- a/templates/webapps/galaxy/visualization/scatterplot.mako
+++ b/templates/webapps/galaxy/visualization/scatterplot.mako
@@ -222,8 +222,7 @@
<script type="text/javascript">
$(function(){
- var hda = ${h.to_json_string( hda.get_api_value() )},
- historyID = '${trans.security.encode_id( hda.history.id )}',
+ var hda = ${h.to_json_string( trans.security.encode_dict_ids( hda.get_api_value() ) )},
querySettings = ${h.to_json_string( query_args )},
chartConfig = _.extend( querySettings, {
containerSelector : '#chart',
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.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d13c2f41bff1/
Changeset: d13c2f41bff1
Branch: next-stable
User: greg
Date: 2013-05-21 18:26:55
Summary: Fixes for complext repository dependency definitions that do not include a changeset_revision attribute. A fix for indenting the updates XML file is also included.
Affected #: 2 files
diff -r d8b3dc823978835f0b2105635990f310fa619c1c -r d13c2f41bff1a19cd996bdcf3457b070e668edae lib/galaxy/webapps/tool_shed/controllers/upload.py
--- a/lib/galaxy/webapps/tool_shed/controllers/upload.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/upload.py
@@ -131,7 +131,7 @@
# Inspect the contents of the file to see if changeset_revision values are missing and if so, set them appropriately.
altered, root = commit_util.handle_repository_dependencies_definition( trans, uploaded_file_name )
if altered:
- tmp_filename = commit_util.create_and_write_tmp_file( util.xml_to_string( root, pretty=True ) )
+ tmp_filename = commit_util.create_and_write_tmp_file( root )
shutil.move( tmp_filename, full_path )
else:
shutil.move( uploaded_file_name, full_path )
@@ -140,7 +140,7 @@
# are missing and if so, set them appropriately.
altered, root = commit_util.handle_tool_dependencies_definition( trans, uploaded_file_name )
if altered:
- tmp_filename = commit_util.create_and_write_tmp_file( util.xml_to_string( root, pretty=True ) )
+ tmp_filename = commit_util.create_and_write_tmp_file( root )
shutil.move( tmp_filename, full_path )
else:
shutil.move( uploaded_file_name, full_path )
@@ -268,13 +268,13 @@
# Inspect the contents of the file to see if changeset_revision values are missing and if so, set them appropriately.
altered, root = commit_util.handle_repository_dependencies_definition( trans, uploaded_file_name )
if altered:
- tmp_filename = commit_util.create_and_write_tmp_file( util.xml_to_string( root, pretty=True ) )
+ tmp_filename = commit_util.create_and_write_tmp_file( root )
shutil.move( tmp_filename, uploaded_file_name )
elif os.path.split( uploaded_file_name )[ -1 ] == 'tool_dependencies.xml':
# Inspect the contents of the file to see if changeset_revision values are missing and if so, set them appropriately.
altered, root = commit_util.handle_tool_dependencies_definition( trans, uploaded_file_name )
if altered:
- tmp_filename = commit_util.create_and_write_tmp_file( util.xml_to_string( root, pretty=True ) )
+ tmp_filename = commit_util.create_and_write_tmp_file( root )
shutil.move( tmp_filename, uploaded_file_name )
if ok:
repo_path = os.path.join( full_path, relative_path )
@@ -330,13 +330,13 @@
# Inspect the contents of the file to see if changeset_revision values are missing and if so, set them appropriately.
altered, root = commit_util.handle_repository_dependencies_definition( trans, uploaded_file_name )
if altered:
- tmp_filename = commit_util.create_and_write_tmp_file( util.xml_to_string( root, pretty=True ) )
+ tmp_filename = commit_util.create_and_write_tmp_file( root )
shutil.move( tmp_filename, uploaded_file_name )
elif os.path.split( uploaded_file_name )[ -1 ] == 'tool_dependencies.xml':
# Inspect the contents of the file to see if changeset_revision values are missing and if so, set them appropriately.
altered, root = commit_util.handle_tool_dependencies_definition( trans, uploaded_file_name )
if altered:
- tmp_filename = commit_util.create_and_write_tmp_file( util.xml_to_string( root, pretty=True ) )
+ tmp_filename = commit_util.create_and_write_tmp_file( root )
shutil.move( tmp_filename, uploaded_file_name )
return commit_util.handle_directory_changes( trans,
repository,
diff -r d8b3dc823978835f0b2105635990f310fa619c1c -r d13c2f41bff1a19cd996bdcf3457b070e668edae lib/tool_shed/util/commit_util.py
--- a/lib/tool_shed/util/commit_util.py
+++ b/lib/tool_shed/util/commit_util.py
@@ -1,5 +1,6 @@
import logging
import os
+import pkg_resources
import shutil
import tempfile
from galaxy import util
@@ -9,11 +10,15 @@
from tool_shed.util import tool_util
from galaxy import eggs
+
eggs.require( 'mercurial' )
from mercurial import commands
from mercurial import hg
from mercurial import ui
+pkg_resources.require( 'elementtree' )
+from elementtree.ElementTree import tostring
+
log = logging.getLogger( __name__ )
UNDESIRABLE_DIRS = [ '.hg', '.svn', '.git', '.cvs' ]
@@ -57,13 +62,13 @@
message = 'The file "%s" contains image content.\n' % str( file_path )
return message
-def create_and_write_tmp_file( text ):
+def create_and_write_tmp_file( root ):
fh = tempfile.NamedTemporaryFile( 'wb' )
tmp_filename = fh.name
fh.close()
fh = open( tmp_filename, 'wb' )
fh.write( '<?xml version="1.0"?>\n' )
- fh.write( text )
+ fh.write( tostring( root, 'utf-8' ) )
fh.close()
return tmp_filename
@@ -255,7 +260,6 @@
package_altered = True
if not altered:
altered = True
-
elif package_elem.tag == 'install':
# <install version="1.0">
for actions_index, actions_elem in enumerate( package_elem ):
@@ -277,8 +281,9 @@
if package_altered:
actions_elem[ action_index ] = action_elem
if package_altered:
- root_elem[ actions_index ] = actions_elem
-
+ package_elem[ actions_index ] = actions_elem
+ if package_altered:
+ root_elem[ package_index ] = package_elem
if package_altered:
root[ root_index ] = root_elem
return altered, root
https://bitbucket.org/galaxy/galaxy-central/commits/61dd8d5c33e5/
Changeset: 61dd8d5c33e5
User: greg
Date: 2013-05-21 18:27:54
Summary: Merged from next-stable
Affected #: 2 files
diff -r 0b9bd1fdc765d18d0831aa2ecbf419e16bbfd15b -r 61dd8d5c33e566b8ec28fb3cbd22de50226dbbd9 lib/galaxy/webapps/tool_shed/controllers/upload.py
--- a/lib/galaxy/webapps/tool_shed/controllers/upload.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/upload.py
@@ -131,7 +131,7 @@
# Inspect the contents of the file to see if changeset_revision values are missing and if so, set them appropriately.
altered, root = commit_util.handle_repository_dependencies_definition( trans, uploaded_file_name )
if altered:
- tmp_filename = commit_util.create_and_write_tmp_file( util.xml_to_string( root, pretty=True ) )
+ tmp_filename = commit_util.create_and_write_tmp_file( root )
shutil.move( tmp_filename, full_path )
else:
shutil.move( uploaded_file_name, full_path )
@@ -140,7 +140,7 @@
# are missing and if so, set them appropriately.
altered, root = commit_util.handle_tool_dependencies_definition( trans, uploaded_file_name )
if altered:
- tmp_filename = commit_util.create_and_write_tmp_file( util.xml_to_string( root, pretty=True ) )
+ tmp_filename = commit_util.create_and_write_tmp_file( root )
shutil.move( tmp_filename, full_path )
else:
shutil.move( uploaded_file_name, full_path )
@@ -268,13 +268,13 @@
# Inspect the contents of the file to see if changeset_revision values are missing and if so, set them appropriately.
altered, root = commit_util.handle_repository_dependencies_definition( trans, uploaded_file_name )
if altered:
- tmp_filename = commit_util.create_and_write_tmp_file( util.xml_to_string( root, pretty=True ) )
+ tmp_filename = commit_util.create_and_write_tmp_file( root )
shutil.move( tmp_filename, uploaded_file_name )
elif os.path.split( uploaded_file_name )[ -1 ] == 'tool_dependencies.xml':
# Inspect the contents of the file to see if changeset_revision values are missing and if so, set them appropriately.
altered, root = commit_util.handle_tool_dependencies_definition( trans, uploaded_file_name )
if altered:
- tmp_filename = commit_util.create_and_write_tmp_file( util.xml_to_string( root, pretty=True ) )
+ tmp_filename = commit_util.create_and_write_tmp_file( root )
shutil.move( tmp_filename, uploaded_file_name )
if ok:
repo_path = os.path.join( full_path, relative_path )
@@ -330,13 +330,13 @@
# Inspect the contents of the file to see if changeset_revision values are missing and if so, set them appropriately.
altered, root = commit_util.handle_repository_dependencies_definition( trans, uploaded_file_name )
if altered:
- tmp_filename = commit_util.create_and_write_tmp_file( util.xml_to_string( root, pretty=True ) )
+ tmp_filename = commit_util.create_and_write_tmp_file( root )
shutil.move( tmp_filename, uploaded_file_name )
elif os.path.split( uploaded_file_name )[ -1 ] == 'tool_dependencies.xml':
# Inspect the contents of the file to see if changeset_revision values are missing and if so, set them appropriately.
altered, root = commit_util.handle_tool_dependencies_definition( trans, uploaded_file_name )
if altered:
- tmp_filename = commit_util.create_and_write_tmp_file( util.xml_to_string( root, pretty=True ) )
+ tmp_filename = commit_util.create_and_write_tmp_file( root )
shutil.move( tmp_filename, uploaded_file_name )
return commit_util.handle_directory_changes( trans,
repository,
diff -r 0b9bd1fdc765d18d0831aa2ecbf419e16bbfd15b -r 61dd8d5c33e566b8ec28fb3cbd22de50226dbbd9 lib/tool_shed/util/commit_util.py
--- a/lib/tool_shed/util/commit_util.py
+++ b/lib/tool_shed/util/commit_util.py
@@ -1,5 +1,6 @@
import logging
import os
+import pkg_resources
import shutil
import tempfile
from galaxy import util
@@ -9,11 +10,15 @@
from tool_shed.util import tool_util
from galaxy import eggs
+
eggs.require( 'mercurial' )
from mercurial import commands
from mercurial import hg
from mercurial import ui
+pkg_resources.require( 'elementtree' )
+from elementtree.ElementTree import tostring
+
log = logging.getLogger( __name__ )
UNDESIRABLE_DIRS = [ '.hg', '.svn', '.git', '.cvs' ]
@@ -57,13 +62,13 @@
message = 'The file "%s" contains image content.\n' % str( file_path )
return message
-def create_and_write_tmp_file( text ):
+def create_and_write_tmp_file( root ):
fh = tempfile.NamedTemporaryFile( 'wb' )
tmp_filename = fh.name
fh.close()
fh = open( tmp_filename, 'wb' )
fh.write( '<?xml version="1.0"?>\n' )
- fh.write( text )
+ fh.write( tostring( root, 'utf-8' ) )
fh.close()
return tmp_filename
@@ -255,7 +260,6 @@
package_altered = True
if not altered:
altered = True
-
elif package_elem.tag == 'install':
# <install version="1.0">
for actions_index, actions_elem in enumerate( package_elem ):
@@ -277,8 +281,9 @@
if package_altered:
actions_elem[ action_index ] = action_elem
if package_altered:
- root_elem[ actions_index ] = actions_elem
-
+ package_elem[ actions_index ] = actions_elem
+ if package_altered:
+ root_elem[ package_index ] = package_elem
if package_altered:
root[ root_index ] = root_elem
return altered, root
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.
1
0
commit/galaxy-central: Dave Bouvier: Add an option to install and test every installable changeset revision of every repository returned by the tool shed API call. Default behavior changed to only install and test the most recent installable changeset revision of each repository.
by commits-noreply@bitbucket.org 21 May '13
by commits-noreply@bitbucket.org 21 May '13
21 May '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/0b9bd1fdc765/
Changeset: 0b9bd1fdc765
User: Dave Bouvier
Date: 2013-05-21 18:15:17
Summary: Add an option to install and test every installable changeset revision of every repository returned by the tool shed API call. Default behavior changed to only install and test the most recent installable changeset revision of each repository.
Affected #: 1 file
diff -r 82f83d00dfd419c035c76b100ec0e88a10bb900c -r 0b9bd1fdc765d18d0831aa2ecbf419e16bbfd15b test/install_and_test_tool_shed_repositories/functional_tests.py
--- a/test/install_and_test_tool_shed_repositories/functional_tests.py
+++ b/test/install_and_test_tool_shed_repositories/functional_tests.py
@@ -225,13 +225,25 @@
url += '&%s' % params
return url
+def get_latest_downloadable_changeset_revision( url, name, owner ):
+ api_url_parts = [ 'api', 'repositories', 'get_ordered_installable_revisions' ]
+ params = urllib.urlencode( dict( name=name, owner=owner ) )
+ api_url = get_api_url( url, api_url_parts, params )
+ changeset_revisions = json_from_url( api_url )
+ if changeset_revisions:
+ return changeset_revisions[ -1 ]
+ else:
+ return '000000000000'
+
def get_repository_info_from_api( url, repository_info_dict ):
parts = [ 'api', 'repositories', repository_info_dict[ 'repository_id' ] ]
api_url = get_api_url( base=url, parts=parts )
extended_dict = json_from_url( api_url )
+ latest_changeset_revision = get_latest_downloadable_changeset_revision( url, extended_dict[ 'name' ], extended_dict[ 'owner' ] )
+ extended_dict[ 'latest_revision' ] = str( latest_changeset_revision )
return extended_dict
-def get_repositories_to_install( location, source='file', format='json' ):
+def get_repositories_to_install( tool_shed_url, latest_revision_only=True ):
'''
Get a list of repository info dicts to install. This method expects a json list of dicts with the following structure:
[
@@ -246,24 +258,49 @@
]
NOTE: If the tool shed URL specified in any dict is not present in the tool_sheds_conf.xml, the installation will fail.
'''
- if source == 'file':
- listing = file( location, 'r' ).read()
- elif source == 'url':
- assert tool_shed_api_key is not None, 'Cannot proceed without tool shed API key.'
- params = urllib.urlencode( dict( do_not_test='false',
- downloadable='true',
- malicious='false',
- includes_tools='true',
- skip_tool_test='false' ) )
- api_url = get_api_url( base=location, parts=[ 'repository_revisions' ], params=params )
- if format == 'json':
- return json_from_url( api_url )
+ assert tool_shed_api_key is not None, 'Cannot proceed without tool shed API key.'
+ params = urllib.urlencode( dict( do_not_test='false',
+ downloadable='true',
+ malicious='false',
+ includes_tools='true',
+ skip_tool_test='false' ) )
+ api_url = get_api_url( base=tool_shed_url, parts=[ 'repository_revisions' ], params=params )
+ base_repository_list = json_from_url( api_url )
+ known_repository_ids = {}
+ detailed_repository_list = []
+ for repository_to_install_dict in base_repository_list:
+ # We need to get some details from the tool shed API, such as repository name and owner, to pass on to the
+ # module that will generate the install methods.
+ repository_info_dict = get_repository_info_from_api( galaxy_tool_shed_url, repository_to_install_dict )
+ if repository_info_dict[ 'latest_revision' ] == '000000000000':
+ continue
+ owner = repository_info_dict[ 'owner' ]
+ name = repository_info_dict[ 'name' ]
+ changeset_revision = repository_to_install_dict[ 'changeset_revision' ]
+ repository_id = repository_to_install_dict[ 'repository_id' ]
+ # We are testing deprecated repositories, because it is possible that a deprecated repository contains valid
+ # and functionally correct tools that someone has previously installed. Deleted repositories have never been installed,
+ # and therefore do not need to be checked. If they are undeleted, this script will then test them the next time it runs.
+ if repository_info_dict[ 'deleted' ]:
+ log.info( "Skipping revision %s of repository id %s (%s/%s) since the repository is deleted...",
+ changeset_revision,
+ repository_id,
+ name,
+ owner )
+ continue
+ # Now merge the dict returned from /api/repository_revisions with the detailed dict we just retrieved.
+ if latest_revision_only:
+ if changeset_revision == repository_info_dict[ 'latest_revision' ]:
+ detailed_repository_list.append( dict( repository_info_dict.items() + repository_to_install_dict.items() ) )
+ else:
+ detailed_repository_list.append( dict( repository_info_dict.items() + repository_to_install_dict.items() ) )
+ repositories_tested = len( detailed_repository_list )
+ if latest_revision_only:
+ skipped_previous = ' and metadata revisions that are not the most recent'
else:
- raise AssertionError( 'Do not know how to handle source type %s.' % source )
- if format == 'json':
- return from_json_string( listing )
- else:
- raise AssertonError( 'Unknown format %s.' % format )
+ skipped_previous = ''
+ log.info( 'After removing deleted repositories%s from the list, %d remain to be tested.', skipped_previous, repositories_tested )
+ return detailed_repository_list
def get_tool_info_from_test_id( test_id ):
'''
@@ -286,13 +323,7 @@
return tool_test_results
def is_latest_downloadable_revision( url, repository_info_dict ):
- api_url_parts = [ 'api', 'repositories', 'get_ordered_installable_revisions' ]
- params = urllib.urlencode( dict( name=repository_info_dict[ 'name' ], owner=repository_info_dict[ 'owner' ] ) )
- api_url = get_api_url( url, api_url_parts, params )
- changeset_revisions = json_from_url( api_url )
- # The get_ordered_installable_revisions returns a list of changeset hashes, with the last hash in the list
- # being the most recent installable revision.
- latest_revision = changeset_revisions.pop()
+ latest_revision = get_latest_downloadable_changeset_revision( url, name=repository_info_dict[ 'name' ], owner=repository_info_dict[ 'owner' ] )
return str( repository_info_dict[ 'changeset_revision' ] ) == str( latest_revision )
def json_from_url( url ):
@@ -532,41 +563,25 @@
shed_tool_data_table_config=None,
persist=False )
# Initialize some variables for the summary that will be printed to stdout.
- repositories_tested = 0
repositories_passed = []
repositories_failed = []
repositories_failed_install = []
try:
- detailed_repository_list = []
# Get a list of repositories to test from the tool shed specified in the GALAXY_INSTALL_TEST_TOOL_SHED_URL environment variable.
log.info( "Retrieving repositories to install from the URL:\n%s\n", str( galaxy_tool_shed_url ) )
- repositories_to_install = get_repositories_to_install( galaxy_tool_shed_url, source='url' )
+ if '-check_all_revisions' not in sys.argv:
+ repositories_to_install = get_repositories_to_install( galaxy_tool_shed_url, latest_revision_only=True )
+ else:
+ repositories_to_install = get_repositories_to_install( galaxy_tool_shed_url, latest_revision_only=False )
log.info( "Retrieved %d repositories from the API.", len( repositories_to_install ) )
- for repository_to_install_dict in repositories_to_install:
- # We need to get some details from the tool shed API, such as repository name and owner, to pass on to the
- # module that will generate the install methods.
- repository_info_dict = get_repository_info_from_api( galaxy_tool_shed_url, repository_to_install_dict )
- # We are testing deprecated repositories, because it is possible that a deprecated repository contains valid
- # and functionally correct tools that someone has previously installed. Deleted repositories have never been installed,
- # and therefore do not need to be checked. If they are undeleted, this script will then test them the next time it runs.
- if repository_info_dict[ 'deleted' ]:
- log.info( "Skipping revision %s of repository id %s (%s/%s) since the repository is deleted...",
- repository_to_install_dict[ 'changeset_revision' ],
- repository_to_install_dict[ 'repository_id' ],
- repository_info_dict[ 'owner' ],
- repository_info_dict[ 'name' ] )
- continue
- # Now merge the dict returned from /api/repository_revisions with the detailed dict we just retrieved.
- detailed_repository_list.append( dict( repository_info_dict.items() + repository_to_install_dict.items() ) )
- repositories_tested = len( detailed_repository_list )
- log.info( 'After removing deleted repositories from the list, %d remain to be tested.', repositories_tested )
if '-list_repositories' in sys.argv:
log.info( "The API returned the following repositories, not counting deleted:" )
- for repository_info_dict in detailed_repository_list:
+ for repository_info_dict in repositories_to_install:
log.info( "%s owned by %s changeset revision %s",
repository_info_dict.get( 'name', None ),
repository_info_dict.get( 'owner', None ),
repository_info_dict.get( 'changeset_revision', None ) )
+ repositories_tested = len( repositories_to_install )
# This loop will iterate through the list of repositories generated by the above code, having already filtered out any
# that were marked as deleted. For each repository, it will generate a test method that will use Twill to install that
# repository into the embedded Galaxy application that was started up, selecting to install repository and tool
@@ -575,7 +590,7 @@
# it will record the result of the tests, and if any failed, the traceback and captured output of the tool that was run.
# After all tests have completed, the repository is uninstalled, so that the previous test cases don't interfere with
# the next repository's functional tests.
- for repository_info_dict in detailed_repository_list:
+ for repository_info_dict in repositories_to_install:
"""
Each repository_info_dict looks something like:
{
@@ -600,8 +615,8 @@
"""
repository_status = dict()
params = dict()
- repository_id = repository_info_dict.get( 'repository_id', None )
- changeset_revision = repository_info_dict.get( 'changeset_revision', None )
+ repository_id = str( repository_info_dict.get( 'repository_id', None ) )
+ changeset_revision = str( repository_info_dict.get( 'changeset_revision', None ) )
metadata_revision_id = repository_info_dict.get( 'id', None )
# Add the URL for the tool shed we're installing from, so the automated installation methods go to the right place.
repository_info_dict[ 'tool_shed_url' ] = galaxy_tool_shed_url
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.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d8b3dc823978/
Changeset: d8b3dc823978
Branch: next-stable
User: carlfeberhard
Date: 2013-05-21 17:15:10
Summary: Fixes to phyloviz
Affected #: 6 files
diff -r 9bb23c38aeec1f26ec1c22fbcad8a098fd6ae015 -r d8b3dc823978835f0b2105635990f310fa619c1c lib/galaxy/visualization/data_providers/phyloviz/__init__.py
--- a/lib/galaxy/visualization/data_providers/phyloviz/__init__.py
+++ b/lib/galaxy/visualization/data_providers/phyloviz/__init__.py
@@ -1,3 +1,4 @@
+
""" Data providers code for PhyloViz """
from galaxy.visualization.data_providers.basic import BaseDataProvider
@@ -40,4 +41,3 @@
rval[ "msg"] = parseMsg
return rval
-
diff -r 9bb23c38aeec1f26ec1c22fbcad8a098fd6ae015 -r d8b3dc823978835f0b2105635990f310fa619c1c lib/galaxy/visualization/data_providers/phyloviz/newickparser.py
--- a/lib/galaxy/visualization/data_providers/phyloviz/newickparser.py
+++ b/lib/galaxy/visualization/data_providers/phyloviz/newickparser.py
@@ -77,8 +77,6 @@
childrenNodes += [node]
return childrenNodes
-
-
def _mapName(self, newickString, nameMap):
"""
Necessary to replace names of terms inside nexus representation
@@ -108,9 +106,9 @@
newString += newickString[start:]
return newString
-
def parseNode(self, string, depth):
- """ Recursive method for parsing newick string, works by stripping down the string into substring
+ """
+ Recursive method for parsing newick string, works by stripping down the string into substring
of newick contained with brackers, which is used to call itself.
Eg ... ( A, B, (D, E)C, F, G ) ...
diff -r 9bb23c38aeec1f26ec1c22fbcad8a098fd6ae015 -r d8b3dc823978835f0b2105635990f310fa619c1c lib/galaxy/visualization/data_providers/registry.py
--- a/lib/galaxy/visualization/data_providers/registry.py
+++ b/lib/galaxy/visualization/data_providers/registry.py
@@ -53,7 +53,7 @@
elif isinstance( original_dataset.datatype, Tabular ):
data_provider_class = ColumnDataProvider
elif isinstance( original_dataset.datatype, ( Nexus, Newick, Phyloxml ) ):
- data_provider_class = genome.PhylovizDataProvider
+ data_provider_class = PhylovizDataProvider
data_provider = data_provider_class( original_dataset=original_dataset )
diff -r 9bb23c38aeec1f26ec1c22fbcad8a098fd6ae015 -r d8b3dc823978835f0b2105635990f310fa619c1c static/scripts/packed/viz/phyloviz.js
--- a/static/scripts/packed/viz/phyloviz.js
+++ b/static/scripts/packed/viz/phyloviz.js
@@ -1,1 +1,1 @@
-define(["libs/d3","viz/visualization","mvc/data"],function(m,f,g){var l=Backbone.View.extend({className:"UserMenuBase",isAcceptableValue:function(r,p,n){var o=this,s=r.val(),t=r.attr("displayLabel")||r.attr("id").replace("phyloViz","");function q(u){return !isNaN(parseFloat(u))&&isFinite(u)}if(!q(s)){alert(t+" is not a number!");return false}if(s>n){alert(t+" is too large.");return false}else{if(s<p){alert(t+" is too small.");return false}}return true},hasIllegalJsonCharacters:function(n){if(n.val().search(/"|'|\\/)!==-1){alert("Named fields cannot contain these illegal characters: double quote(\"), single guote('), or back slash(\\). ");return true}return false}});function h(){var w=this,r=m.layout.hierarchy().sort(null).value(null),v=360,q="Linear",u=18,s=200,t=0,p=0.5,n=50;w.leafHeight=function(x){if(typeof x==="undefined"){return u}else{u=x;return w}};w.layoutMode=function(x){if(typeof x==="undefined"){return q}else{q=x;return w}};w.layoutAngle=function(x){if(typeof x==="undefined"){return v}if(isNaN(x)||x<0||x>360){return w}else{v=x;return w}};w.separation=function(x){if(typeof x==="undefined"){return s}else{s=x;return w}};w.links=function(x){return m.layout.tree().links(x)};w.nodes=function(A,y){var z=r.call(w,A,y),x=[],C=0,B=0;z.forEach(function(D){var E=D.data;E.depth=D.depth;C=E.depth>C?E.depth:C;x.push(E)});x.forEach(function(D){if(!D.children){B+=1;D.depth=C}});u=q==="Circular"?v/B:u;t=0;o(x[0],C,u,null);return x};function o(B,D,A,z){var y=B.children,x=0;var C=B.dist||p;C=C>1?1:C;B.dist=C;if(z!==null){B.y0=z.y0+C*s}else{B.y0=n}if(!y){B.x0=t++*A}else{y.forEach(function(E){E.parent=B;x+=o(E,D,A,B)});B.x0=x/y.length}B.x=B.x0;B.y=B.y0;return B.x0}return w}var b=f.Visualization.extend({defaults:{layout:"Linear",separation:250,leafHeight:18,type:"phyloviz",title:"Title",scaleFactor:1,translate:[0,0],fontSize:12,selectedNode:null,nodeAttrChangedTime:0},initialize:function(n){this.set("dataset",new g.Dataset({id:n.dataset_id}))},root:{},toggle:function(n){if(typeof n==="undefined"){return}if(n.children){n._children=n.children;n.children=null}else{n.children=n._children;n._children=null}},toggleAll:function(n){if(n.children&&n.children.length!==0){n.children.forEach(this.toggleAll);toggle(n)}},getData:function(){return this.root},save:function(){var n=this.root;o(n);this.set("root",n);function o(q){delete q.parent;if(q._selected){delete q._selected}if(q.children){q.children.forEach(o)}if(q._children){q._children.forEach(o)}}var p=jQuery.extend(true,{},this.attributes);p.selectedNode=null;show_message("Saving to Galaxy","progress");return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(p)},success:function(q){var r=q.url.split("id=")[1].split("&")[0],s="/visualization?id="+r;window.history.pushState({},"",s+window.location.hash);hide_modal()}})}});var d=Backbone.View.extend({defaults:{nodeRadius:4.5},stdInit:function(o){var n=this;n.model.on("change:separation change:leafHeight change:fontSize change:nodeAttrChangedTime",n.updateAndRender,n);n.vis=o.vis;n.i=0;n.maxDepth=-1;n.width=o.width;n.height=o.height},updateAndRender:function(p){var o=m.select(".vis"),n=this;p=p||n.model.root;n.renderNodes(p);n.renderLinks(p);n.addTooltips()},renderLinks:function(n){var w=this;var o=w.diagonal;var p=w.duration;var r=w.layoutMode;var t=w.vis.selectAll("g.completeLink").data(w.tree.links(w.nodes),function(x){return x.target.id});var v=function(x){x.pos0=x.source.y0+" "+x.source.x0;x.pos1=x.source.y0+" "+x.target.x0;x.pos2=x.target.y0+" "+x.target.x0};var u=t.enter().insert("svg:g","g.node").attr("class","completeLink");u.append("svg:path").attr("class","link").attr("d",function(x){v(x);return"M "+x.pos0+" L "+x.pos1});var s=t.transition().duration(500);s.select("path.link").attr("d",function(x){v(x);return"M "+x.pos0+" L "+x.pos1+" L "+x.pos2});var q=t.exit().remove()},selectNode:function(o){var n=this;m.selectAll("g.node").classed("selectedHighlight",function(p){if(o.id===p.id){if(o._selected){delete o._selected;return false}else{o._selected=true;return true}}return false});n.model.set("selectedNode",o);$("#phyloVizSelectedNodeName").val(o.name);$("#phyloVizSelectedNodeDist").val(o.dist);$("#phyloVizSelectedNodeAnnotation").val(o.annotation||"")},addTooltips:function(){$(".bs-tooltip").remove();$(".node").attr("data-original-title",function(){var o=this.__data__,n=o.annotation||"None";return o?(o.name?o.name+"<br/>":"")+"Dist: "+o.dist+" <br/>Annotation: "+n:""}).tooltip({placement:"top",trigger:"hover"})}});var a=d.extend({initialize:function(o){var n=this;n.margins=o.margins;n.layoutMode="Linear";n.stdInit(o);n.layout();n.updateAndRender(n.model.root)},layout:function(){var n=this;n.tree=new h().layoutMode("Linear");n.diagonal=m.svg.diagonal().projection(function(o){return[o.y,o.x]})},renderNodes:function(n){var u=this,v=u.model.get("fontSize")+"px";u.tree.separation(u.model.get("separation")).leafHeight(u.model.get("leafHeight"));var q=500,o=u.tree.separation(u.model.get("separation")).nodes(u.model.root);var p=u.vis.selectAll("g.node").data(o,function(w){return w.name+w.id||(w.id=++u.i)});u.nodes=o;u.duration=q;var r=p.enter().append("svg:g").attr("class","node").on("dblclick",function(){m.event.stopPropagation()}).on("click",function(w){if(m.event.altKey){u.selectNode(w)}else{if(w.children&&w.children.length===0){return}u.model.toggle(w);u.updateAndRender(w)}});r.attr("transform",function(w){return"translate("+n.y0+","+n.x0+")"});r.append("svg:circle").attr("r",0.000001).style("fill",function(w){return w._children?"lightsteelblue":"#fff"});r.append("svg:text").attr("class","nodeLabel").attr("x",function(w){return w.children||w._children?-10:10}).attr("dy",".35em").attr("text-anchor",function(w){return w.children||w._children?"end":"start"}).style("fill-opacity",0.000001);var s=p.transition().duration(q);s.attr("transform",function(w){return"translate("+w.y+","+w.x+")"});s.select("circle").attr("r",u.defaults.nodeRadius).style("fill",function(w){return w._children?"lightsteelblue":"#fff"});s.select("text").style("fill-opacity",1).style("font-size",v).text(function(w){return w.name});var t=p.exit().transition().duration(q).remove();t.select("circle").attr("r",0.000001);t.select("text").style("fill-opacity",0.000001);o.forEach(function(w){w.x0=w.x;w.y0=w.y})}});var j=Backbone.View.extend({className:"phyloviz",initialize:function(o){var n=this;n.MIN_SCALE=0.05;n.MAX_SCALE=5;n.MAX_DISPLACEMENT=500;n.margins=[10,60,10,80];n.width=$("#PhyloViz").width();n.height=$("#PhyloViz").height();n.radius=n.width;n.data=o.data;$(window).resize(function(){n.width=$("#PhyloViz").width();n.height=$("#PhyloViz").height();n.render()});n.phyloTree=new b(o.config);n.phyloTree.root=n.data;n.zoomFunc=m.behavior.zoom().scaleExtent([n.MIN_SCALE,n.MAX_SCALE]);n.zoomFunc.translate(n.phyloTree.get("translate"));n.zoomFunc.scale(n.phyloTree.get("scaleFactor"));n.navMenu=new c(n);n.settingsMenu=new i({phyloTree:n.phyloTree});n.nodeSelectionView=new e({phyloTree:n.phyloTree});n.search=new k();setTimeout(function(){n.zoomAndPan()},1000)},render:function(){var o=this;$("#PhyloViz").empty();o.mainSVG=m.select("#PhyloViz").append("svg:svg").attr("width",o.width).attr("height",o.height).attr("pointer-events","all").call(o.zoomFunc.on("zoom",function(){o.zoomAndPan()}));o.boundingRect=o.mainSVG.append("svg:rect").attr("class","boundingRect").attr("width",o.width).attr("height",o.height).attr("stroke","black").attr("fill","white");o.vis=o.mainSVG.append("svg:g").attr("class","vis");o.layoutOptions={model:o.phyloTree,width:o.width,height:o.height,vis:o.vis,margins:o.margins};$("#title").text("Phylogenetic Tree from "+o.phyloTree.get("title")+":");var n=new a(o.layoutOptions)},zoomAndPan:function(n){var t,p;if(typeof n!=="undefined"){t=n.zoom;p=n.translate}var w=this,r=w.zoomFunc.scale(),v=w.zoomFunc.translate(),s="",u="";switch(t){case"reset":r=1;v=[0,0];break;case"+":r*=1.1;break;case"-":r*=0.9;break;default:if(typeof t==="number"){r=t}else{if(m.event!==null){r=m.event.scale}}}if(r<w.MIN_SCALE||r>w.MAX_SCALE){return}w.zoomFunc.scale(r);s="translate("+w.margins[3]+","+w.margins[0]+") scale("+r+")";if(m.event!==null){u="translate("+m.event.translate+")"}else{if(typeof p!=="undefined"){var q=p.split(",")[0];var o=p.split(",")[1];if(!isNaN(q)&&!isNaN(o)){v=[v[0]+parseFloat(q),v[1]+parseFloat(o)]}}w.zoomFunc.translate(v);u="translate("+v+")"}w.phyloTree.set("scaleFactor",r);w.phyloTree.set("translate",v);w.vis.attr("transform",u+s)},reloadViz:function(){var n=this,o=$("#phylovizNexSelector :selected").val();$.getJSON(n.phyloTree.get("dataset").url(),{tree_index:o,data_type:"raw_data"},function(p){n.data=p.data;n.config=p;n.render()})}});var c=Backbone.View.extend({initialize:function(o){var n=this;n.phylovizView=o;$("#panelHeaderRightBtns").empty();$("#phyloVizNavBtns").empty();$("#phylovizNexSelector").off();n.initNavBtns();n.initRightHeaderBtns();$("#phylovizNexSelector").off().on("change",function(){n.phylovizView.reloadViz()})},initRightHeaderBtns:function(){var n=this;rightMenu=create_icon_buttons_menu([{icon_class:"gear",title:"PhyloViz Settings",on_click:function(){$("#SettingsMenu").show();n.settingsMenu.updateUI()}},{icon_class:"disk",title:"Save visualization",on_click:function(){var o=$("#phylovizNexSelector option:selected").text();if(o){n.phylovizView.phyloTree.set("title",o)}n.phylovizView.phyloTree.save()}},{icon_class:"chevron-expand",title:"Search / Edit Nodes",on_click:function(){$("#nodeSelectionView").show()}},{icon_class:"information",title:"Phyloviz Help",on_click:function(){window.open("http://wiki.g2.bx.psu.edu/Learn/Visualization/PhylogeneticTree")}}],{tooltip_config:{placement:"bottom"}});$("#panelHeaderRightBtns").append(rightMenu.$el)},initNavBtns:function(){var n=this,o=create_icon_buttons_menu([{icon_class:"zoom-in",title:"Zoom in",on_click:function(){n.phylovizView.zoomAndPan({zoom:"+"})}},{icon_class:"zoom-out",title:"Zoom out",on_click:function(){n.phylovizView.zoomAndPan({zoom:"-"})}},{icon_class:"arrow-circle",title:"Reset Zoom/Pan",on_click:function(){n.phylovizView.zoomAndPan({zoom:"reset"})}}],{tooltip_config:{placement:"bottom"}});$("#phyloVizNavBtns").append(o.$el)}});var i=l.extend({className:"Settings",initialize:function(o){var n=this;n.phyloTree=o.phyloTree;n.el=$("#SettingsMenu");n.inputs={separation:$("#phyloVizTreeSeparation"),leafHeight:$("#phyloVizTreeLeafHeight"),fontSize:$("#phyloVizTreeFontSize")};$("#settingsCloseBtn").off().on("click",function(){n.el.hide()});$("#phylovizResetSettingsBtn").off().on("click",function(){n.resetToDefaults()});$("#phylovizApplySettingsBtn").off().on("click",function(){n.apply()})},apply:function(){var n=this;if(!n.isAcceptableValue(n.inputs.separation,50,2500)||!n.isAcceptableValue(n.inputs.leafHeight,5,30)||!n.isAcceptableValue(n.inputs.fontSize,5,20)){return}$.each(n.inputs,function(o,p){n.phyloTree.set(o,p.val())})},updateUI:function(){var n=this;$.each(n.inputs,function(o,p){p.val(n.phyloTree.get(o))})},resetToDefaults:function(){$(".bs-tooltip").remove();var n=this;$.each(n.phyloTree.defaults,function(o,p){n.phyloTree.set(o,p)});n.updateUI()},render:function(){}});var e=l.extend({className:"Settings",initialize:function(o){var n=this;n.el=$("#nodeSelectionView");n.phyloTree=o.phyloTree;n.UI={enableEdit:$("#phylovizEditNodesCheck"),saveChanges:$("#phylovizNodeSaveChanges"),cancelChanges:$("#phylovizNodeCancelChanges"),name:$("#phyloVizSelectedNodeName"),dist:$("#phyloVizSelectedNodeDist"),annotation:$("#phyloVizSelectedNodeAnnotation")};n.valuesOfConcern={name:null,dist:null,annotation:null};$("#nodeSelCloseBtn").off().on("click",function(){n.el.hide()});n.UI.saveChanges.off().on("click",function(){n.updateNodes()});n.UI.cancelChanges.off().on("click",function(){n.cancelChanges()});(function(p){p.fn.enable=function(q){return p(this).each(function(){if(q){p(this).removeAttr("disabled")}else{p(this).attr("disabled","disabled")}})}})(jQuery);n.UI.enableEdit.off().on("click",function(){n.toggleUI()})},toggleUI:function(){var n=this,o=n.UI.enableEdit.is(":checked");if(!o){n.cancelChanges()}$.each(n.valuesOfConcern,function(p,q){n.UI[p].enable(o)});if(o){n.UI.saveChanges.show();n.UI.cancelChanges.show()}else{n.UI.saveChanges.hide();n.UI.cancelChanges.hide()}},cancelChanges:function(){var n=this,o=n.phyloTree.get("selectedNode");if(o){$.each(n.valuesOfConcern,function(p,q){n.UI[p].val(o[p])})}},updateNodes:function(){var n=this,o=n.phyloTree.get("selectedNode");if(o){if(!n.isAcceptableValue(n.UI.dist,0,1)||n.hasIllegalJsonCharacters(n.UI.name)||n.hasIllegalJsonCharacters(n.UI.annotation)){return}$.each(n.valuesOfConcern,function(p,q){(o[p])=n.UI[p].val()});n.phyloTree.set("nodeAttrChangedTime",new Date())}else{alert("No node selected")}}});var k=l.extend({initialize:function(){var n=this;$("#phyloVizSearchBtn").on("click",function(){var p=$("#phyloVizSearchTerm"),q=$("#phyloVizSearchCondition").val().split("-"),o=q[0],r=q[1];n.hasIllegalJsonCharacters(p);if(o==="dist"){n.isAcceptableValue(p,0,1)}n.searchTree(o,r,p.val())})},searchTree:function(n,p,o){m.selectAll("g.node").classed("searchHighlight",function(r){var q=r[n];if(typeof q!=="undefined"&&q!==null){if(n==="dist"){switch(p){case"greaterEqual":return q>=+o;case"lesserEqual":return q<=+o;default:return}}else{if(n==="name"||n==="annotation"){return q.toLowerCase().indexOf(o.toLowerCase())!==-1}}}})}});return{PhylovizView:j}});
\ No newline at end of file
+define(["libs/d3","viz/visualization","mvc/data"],function(m,f,g){var l=Backbone.View.extend({className:"UserMenuBase",isAcceptableValue:function(q,o,n){var r=q.val(),s=q.attr("displayLabel")||q.attr("id").replace("phyloViz","");function p(t){return !isNaN(parseFloat(t))&&isFinite(t)}if(!p(r)){alert(s+" is not a number!");return false}if(r>n){alert(s+" is too large.");return false}else{if(r<o){alert(s+" is too small.");return false}}return true},hasIllegalJsonCharacters:function(n){if(n.val().search(/"|'|\\/)!==-1){alert("Named fields cannot contain these illegal characters: double quote(\"), single guote('), or back slash(\\). ");return true}return false}});function h(){var w=this,r=m.layout.hierarchy().sort(null).value(null),v=360,q="Linear",u=18,s=200,t=0,p=0.5,n=50;w.leafHeight=function(x){if(typeof x==="undefined"){return u}else{u=x;return w}};w.layoutMode=function(x){if(typeof x==="undefined"){return q}else{q=x;return w}};w.layoutAngle=function(x){if(typeof x==="undefined"){return v}if(isNaN(x)||x<0||x>360){return w}else{v=x;return w}};w.separation=function(x){if(typeof x==="undefined"){return s}else{s=x;return w}};w.links=function(x){return m.layout.tree().links(x)};w.nodes=function(A,y){if(toString.call(A)==="[object Array]"){A=A[0]}var z=r.call(w,A,y),x=[],C=0,B=0;window._d=A;window._nodes=z;z.forEach(function(D){C=D.depth>C?D.depth:C;x.push(D)});x.forEach(function(D){if(!D.children){B+=1;D.depth=C}});u=q==="Circular"?v/B:u;t=0;o(x[0],C,u,null);return x};function o(B,D,A,z){var y=B.children,x=0;var C=B.dist||p;C=C>1?1:C;B.dist=C;if(z!==null){B.y0=z.y0+C*s}else{B.y0=n}if(!y){B.x0=t*A;t+=1}else{y.forEach(function(E){E.parent=B;x+=o(E,D,A,B)});B.x0=x/y.length}B.x=B.x0;B.y=B.y0;return B.x0}return w}var b=f.Visualization.extend({defaults:{layout:"Linear",separation:250,leafHeight:18,type:"phyloviz",title:"Title",scaleFactor:1,translate:[0,0],fontSize:12,selectedNode:null,nodeAttrChangedTime:0},initialize:function(n){this.set("dataset",new g.Dataset({id:n.dataset_id}))},root:{},toggle:function(n){if(typeof n==="undefined"){return}if(n.children){n._children=n.children;n.children=null}else{n.children=n._children;n._children=null}},toggleAll:function(n){if(n.children&&n.children.length!==0){n.children.forEach(this.toggleAll);toggle(n)}},getData:function(){return this.root},save:function(){var n=this.root;o(n);this.set("root",n);function o(q){delete q.parent;if(q._selected){delete q._selected}if(q.children){q.children.forEach(o)}if(q._children){q._children.forEach(o)}}var p=jQuery.extend(true,{},this.attributes);p.selectedNode=null;show_message("Saving to Galaxy","progress");return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(p)},success:function(q){var r=q.url.split("id=")[1].split("&")[0],s="/visualization?id="+r;window.history.pushState({},"",s+window.location.hash);hide_modal()}})}});var d=Backbone.View.extend({defaults:{nodeRadius:4.5},stdInit:function(o){var n=this;n.model.on("change:separation change:leafHeight change:fontSize change:nodeAttrChangedTime",n.updateAndRender,n);n.vis=o.vis;n.i=0;n.maxDepth=-1;n.width=o.width;n.height=o.height},updateAndRender:function(p){var o=m.select(".vis"),n=this;p=p||n.model.root;n.renderNodes(p);n.renderLinks(p);n.addTooltips()},renderLinks:function(n){var w=this;var o=w.diagonal;var p=w.duration;var r=w.layoutMode;var t=w.vis.selectAll("g.completeLink").data(w.tree.links(w.nodes),function(x){return x.target.id});var v=function(x){x.pos0=x.source.y0+" "+x.source.x0;x.pos1=x.source.y0+" "+x.target.x0;x.pos2=x.target.y0+" "+x.target.x0};var u=t.enter().insert("svg:g","g.node").attr("class","completeLink");u.append("svg:path").attr("class","link").attr("d",function(x){v(x);return"M "+x.pos0+" L "+x.pos1});var s=t.transition().duration(500);s.select("path.link").attr("d",function(x){v(x);return"M "+x.pos0+" L "+x.pos1+" L "+x.pos2});var q=t.exit().remove()},selectNode:function(o){var n=this;m.selectAll("g.node").classed("selectedHighlight",function(p){if(o.id===p.id){if(o._selected){delete o._selected;return false}else{o._selected=true;return true}}return false});n.model.set("selectedNode",o);$("#phyloVizSelectedNodeName").val(o.name);$("#phyloVizSelectedNodeDist").val(o.dist);$("#phyloVizSelectedNodeAnnotation").val(o.annotation||"")},addTooltips:function(){$(".bs-tooltip").remove();$(".node").attr("data-original-title",function(){var o=this.__data__,n=o.annotation||"None";return o?(o.name?o.name+"<br/>":"")+"Dist: "+o.dist+" <br/>Annotation: "+n:""}).tooltip({placement:"top",trigger:"hover"})}});var a=d.extend({initialize:function(o){var n=this;n.margins=o.margins;n.layoutMode="Linear";n.stdInit(o);n.layout();n.updateAndRender(n.model.root)},layout:function(){var n=this;n.tree=new h().layoutMode("Linear");n.diagonal=m.svg.diagonal().projection(function(o){return[o.y,o.x]})},renderNodes:function(n){var u=this,v=u.model.get("fontSize")+"px";u.tree.separation(u.model.get("separation")).leafHeight(u.model.get("leafHeight"));var q=500,o=u.tree.separation(u.model.get("separation")).nodes(u.model.root);var p=u.vis.selectAll("g.node").data(o,function(w){return w.name+w.id||(w.id=++u.i)});u.nodes=o;u.duration=q;var r=p.enter().append("svg:g").attr("class","node").on("dblclick",function(){m.event.stopPropagation()}).on("click",function(w){if(m.event.altKey){u.selectNode(w)}else{if(w.children&&w.children.length===0){return}u.model.toggle(w);u.updateAndRender(w)}});console.debug("source:",n);if(toString.call(n)==="[object Array]"){n=n[0]}r.attr("transform",function(w){return"translate("+n.y0+","+n.x0+")"});r.append("svg:circle").attr("r",0.000001).style("fill",function(w){return w._children?"lightsteelblue":"#fff"});r.append("svg:text").attr("class","nodeLabel").attr("x",function(w){return w.children||w._children?-10:10}).attr("dy",".35em").attr("text-anchor",function(w){return w.children||w._children?"end":"start"}).style("fill-opacity",0.000001);var s=p.transition().duration(q);s.attr("transform",function(w){return"translate("+w.y+","+w.x+")"});s.select("circle").attr("r",u.defaults.nodeRadius).style("fill",function(w){return w._children?"lightsteelblue":"#fff"});s.select("text").style("fill-opacity",1).style("font-size",v).text(function(w){return w.name});var t=p.exit().transition().duration(q).remove();t.select("circle").attr("r",0.000001);t.select("text").style("fill-opacity",0.000001);o.forEach(function(w){w.x0=w.x;w.y0=w.y})}});var j=Backbone.View.extend({className:"phyloviz",initialize:function(o){var n=this;n.MIN_SCALE=0.05;n.MAX_SCALE=5;n.MAX_DISPLACEMENT=500;n.margins=[10,60,10,80];n.width=$("#PhyloViz").width();n.height=$("#PhyloViz").height();n.radius=n.width;n.data=o.data;$(window).resize(function(){n.width=$("#PhyloViz").width();n.height=$("#PhyloViz").height();n.render()});n.phyloTree=new b(o.config);n.phyloTree.root=n.data;n.zoomFunc=m.behavior.zoom().scaleExtent([n.MIN_SCALE,n.MAX_SCALE]);n.zoomFunc.translate(n.phyloTree.get("translate"));n.zoomFunc.scale(n.phyloTree.get("scaleFactor"));n.navMenu=new c(n);n.settingsMenu=new i({phyloTree:n.phyloTree});n.nodeSelectionView=new e({phyloTree:n.phyloTree});n.search=new k();setTimeout(function(){n.zoomAndPan()},1000)},render:function(){var o=this;$("#PhyloViz").empty();o.mainSVG=m.select("#PhyloViz").append("svg:svg").attr("width",o.width).attr("height",o.height).attr("pointer-events","all").call(o.zoomFunc.on("zoom",function(){o.zoomAndPan()}));o.boundingRect=o.mainSVG.append("svg:rect").attr("class","boundingRect").attr("width",o.width).attr("height",o.height).attr("stroke","black").attr("fill","white");o.vis=o.mainSVG.append("svg:g").attr("class","vis");o.layoutOptions={model:o.phyloTree,width:o.width,height:o.height,vis:o.vis,margins:o.margins};$("#title").text("Phylogenetic Tree from "+o.phyloTree.get("title")+":");var n=new a(o.layoutOptions)},zoomAndPan:function(n){var t,p;if(typeof n!=="undefined"){t=n.zoom;p=n.translate}var w=this,r=w.zoomFunc.scale(),v=w.zoomFunc.translate(),s="",u="";switch(t){case"reset":r=1;v=[0,0];break;case"+":r*=1.1;break;case"-":r*=0.9;break;default:if(typeof t==="number"){r=t}else{if(m.event!==null){r=m.event.scale}}}if(r<w.MIN_SCALE||r>w.MAX_SCALE){return}w.zoomFunc.scale(r);s="translate("+w.margins[3]+","+w.margins[0]+") scale("+r+")";if(m.event!==null){u="translate("+m.event.translate+")"}else{if(typeof p!=="undefined"){var q=p.split(",")[0];var o=p.split(",")[1];if(!isNaN(q)&&!isNaN(o)){v=[v[0]+parseFloat(q),v[1]+parseFloat(o)]}}w.zoomFunc.translate(v);u="translate("+v+")"}w.phyloTree.set("scaleFactor",r);w.phyloTree.set("translate",v);w.vis.attr("transform",u+s)},reloadViz:function(){var n=this,o=$("#phylovizNexSelector :selected").val();$.getJSON(n.phyloTree.get("dataset").url(),{tree_index:o,data_type:"raw_data"},function(p){n.data=p.data;n.config=p;n.render()})}});var c=Backbone.View.extend({initialize:function(o){var n=this;n.phylovizView=o;$("#panelHeaderRightBtns").empty();$("#phyloVizNavBtns").empty();$("#phylovizNexSelector").off();n.initNavBtns();n.initRightHeaderBtns();$("#phylovizNexSelector").off().on("change",function(){n.phylovizView.reloadViz()})},initRightHeaderBtns:function(){var n=this;rightMenu=create_icon_buttons_menu([{icon_class:"gear",title:"PhyloViz Settings",on_click:function(){$("#SettingsMenu").show();n.settingsMenu.updateUI()}},{icon_class:"disk",title:"Save visualization",on_click:function(){var o=$("#phylovizNexSelector option:selected").text();if(o){n.phylovizView.phyloTree.set("title",o)}n.phylovizView.phyloTree.save()}},{icon_class:"chevron-expand",title:"Search / Edit Nodes",on_click:function(){$("#nodeSelectionView").show()}},{icon_class:"information",title:"Phyloviz Help",on_click:function(){window.open("http://wiki.g2.bx.psu.edu/Learn/Visualization/PhylogeneticTree")}}],{tooltip_config:{placement:"bottom"}});$("#panelHeaderRightBtns").append(rightMenu.$el)},initNavBtns:function(){var n=this,o=create_icon_buttons_menu([{icon_class:"zoom-in",title:"Zoom in",on_click:function(){n.phylovizView.zoomAndPan({zoom:"+"})}},{icon_class:"zoom-out",title:"Zoom out",on_click:function(){n.phylovizView.zoomAndPan({zoom:"-"})}},{icon_class:"arrow-circle",title:"Reset Zoom/Pan",on_click:function(){n.phylovizView.zoomAndPan({zoom:"reset"})}}],{tooltip_config:{placement:"bottom"}});$("#phyloVizNavBtns").append(o.$el)}});var i=l.extend({className:"Settings",initialize:function(o){var n=this;n.phyloTree=o.phyloTree;n.el=$("#SettingsMenu");n.inputs={separation:$("#phyloVizTreeSeparation"),leafHeight:$("#phyloVizTreeLeafHeight"),fontSize:$("#phyloVizTreeFontSize")};$("#settingsCloseBtn").off().on("click",function(){n.el.hide()});$("#phylovizResetSettingsBtn").off().on("click",function(){n.resetToDefaults()});$("#phylovizApplySettingsBtn").off().on("click",function(){n.apply()})},apply:function(){var n=this;if(!n.isAcceptableValue(n.inputs.separation,50,2500)||!n.isAcceptableValue(n.inputs.leafHeight,5,30)||!n.isAcceptableValue(n.inputs.fontSize,5,20)){return}$.each(n.inputs,function(o,p){n.phyloTree.set(o,p.val())})},updateUI:function(){var n=this;$.each(n.inputs,function(o,p){p.val(n.phyloTree.get(o))})},resetToDefaults:function(){$(".bs-tooltip").remove();var n=this;$.each(n.phyloTree.defaults,function(o,p){n.phyloTree.set(o,p)});n.updateUI()},render:function(){}});var e=l.extend({className:"Settings",initialize:function(o){var n=this;n.el=$("#nodeSelectionView");n.phyloTree=o.phyloTree;n.UI={enableEdit:$("#phylovizEditNodesCheck"),saveChanges:$("#phylovizNodeSaveChanges"),cancelChanges:$("#phylovizNodeCancelChanges"),name:$("#phyloVizSelectedNodeName"),dist:$("#phyloVizSelectedNodeDist"),annotation:$("#phyloVizSelectedNodeAnnotation")};n.valuesOfConcern={name:null,dist:null,annotation:null};$("#nodeSelCloseBtn").off().on("click",function(){n.el.hide()});n.UI.saveChanges.off().on("click",function(){n.updateNodes()});n.UI.cancelChanges.off().on("click",function(){n.cancelChanges()});(function(p){p.fn.enable=function(q){return p(this).each(function(){if(q){p(this).removeAttr("disabled")}else{p(this).attr("disabled","disabled")}})}})(jQuery);n.UI.enableEdit.off().on("click",function(){n.toggleUI()})},toggleUI:function(){var n=this,o=n.UI.enableEdit.is(":checked");if(!o){n.cancelChanges()}$.each(n.valuesOfConcern,function(p,q){n.UI[p].enable(o)});if(o){n.UI.saveChanges.show();n.UI.cancelChanges.show()}else{n.UI.saveChanges.hide();n.UI.cancelChanges.hide()}},cancelChanges:function(){var n=this,o=n.phyloTree.get("selectedNode");if(o){$.each(n.valuesOfConcern,function(p,q){n.UI[p].val(o[p])})}},updateNodes:function(){var n=this,o=n.phyloTree.get("selectedNode");if(o){if(!n.isAcceptableValue(n.UI.dist,0,1)||n.hasIllegalJsonCharacters(n.UI.name)||n.hasIllegalJsonCharacters(n.UI.annotation)){return}$.each(n.valuesOfConcern,function(p,q){(o[p])=n.UI[p].val()});n.phyloTree.set("nodeAttrChangedTime",new Date())}else{alert("No node selected")}}});var k=l.extend({initialize:function(){var n=this;$("#phyloVizSearchBtn").on("click",function(){var p=$("#phyloVizSearchTerm"),q=$("#phyloVizSearchCondition").val().split("-"),o=q[0],r=q[1];n.hasIllegalJsonCharacters(p);if(o==="dist"){n.isAcceptableValue(p,0,1)}n.searchTree(o,r,p.val())})},searchTree:function(n,p,o){m.selectAll("g.node").classed("searchHighlight",function(r){var q=r[n];if(typeof q!=="undefined"&&q!==null){if(n==="dist"){switch(p){case"greaterEqual":return q>=+o;case"lesserEqual":return q<=+o;default:return}}else{if(n==="name"||n==="annotation"){return q.toLowerCase().indexOf(o.toLowerCase())!==-1}}}})}});return{PhylovizView:j}});
\ No newline at end of file
diff -r 9bb23c38aeec1f26ec1c22fbcad8a098fd6ae015 -r d8b3dc823978835f0b2105635990f310fa619c1c static/scripts/viz/phyloviz.js
--- a/static/scripts/viz/phyloviz.js
+++ b/static/scripts/viz/phyloviz.js
@@ -1,18 +1,18 @@
define(['libs/d3', 'viz/visualization', 'mvc/data'], function(d3, visualization_mod, data_mod) {
+/**
+ * Base class of any menus that takes in user interaction. Contains checking methods.
+ */
var UserMenuBase = Backbone.View.extend({
- /**
- * Base class of any menus that takes in user interaction. Contains checking methods.
- */
className: 'UserMenuBase',
+ /**
+ * Check if an input value is a number and falls within max min.
+ */
isAcceptableValue : function ($inputKey, min, max) {
- /**
- * Check if an input value is a number and falls within max min.
- */
- var self = this,
- value = $inputKey.val(),
+ //TODO: use better feedback than alert
+ var value = $inputKey.val(),
fieldName = $inputKey.attr("displayLabel") || $inputKey.attr("id").replace("phyloViz", "");
function isNumeric(n) {
@@ -34,12 +34,13 @@
return true;
},
+ /**
+ * Check if any user string inputs has illegal characters that json cannot accept
+ */
hasIllegalJsonCharacters : function($inputKey) {
- /**
- * Check if any user string inputs has illegal characters that json cannot accept
- */
if ($inputKey.val().search(/"|'|\\/) !== -1){
- alert("Named fields cannot contain these illegal characters: double quote(\"), single guote(\'), or back slash(\\). ");
+ alert("Named fields cannot contain these illegal characters: "
+ + "double quote(\"), single guote(\'), or back slash(\\). ");
return true;
}
return false;
@@ -47,12 +48,12 @@
});
+/**
+ * -- Custom Layout call for phyloViz to suit the needs of a phylogenetic tree.
+ * -- Specifically: 1) Nodes have a display display of (= evo dist X depth separation) from their parent
+ * 2) Nodes must appear in other after they have expand and contracted
+ */
function PhyloTreeLayout() {
- /**
- * -- Custom Layout call for phyloViz to suit the needs of a phylogenetic tree.
- * -- Specifically: 1) Nodes have a display display of (= evo dist X depth separation) from their parent
- * 2) Nodes must appear in other after they have expand and contracted
- */
var self = this,
hierarchy = d3.layout.hierarchy().sort(null).value(null),
@@ -75,9 +76,11 @@
else { layoutMode = mode; return self;}
};
- self.layoutAngle = function(angle) { // changes the layout angle of the display, which is really changing the height
+ // changes the layout angle of the display, which is really changing the height
+ self.layoutAngle = function(angle) {
if (typeof angle === "undefined"){ return height; }
- if (isNaN(angle) || angle < 0 || angle > 360) { return self; } // to use default if the user puts in strange values
+ // to use default if the user puts in strange values
+ if (isNaN(angle) || angle < 0 || angle > 360) { return self; }
else { height = angle; return self;}
};
@@ -92,19 +95,28 @@
// -- Custom method for laying out phylogeny tree in a linear fashion
self.nodes = function (d, i) {
- var _nodes = hierarchy.call(self, d, i), // self is to find the depth of all the nodes, assumes root is passed in
+ //TODO: newick and phyloxml return arrays. where should this go (client (here, else), server)?
+ if( toString.call( d ) === '[object Array]' ){
+ // if d is an array, replate with the first object (newick, phyloxml)
+ d = d[0];
+ }
+ // self is to find the depth of all the nodes, assumes root is passed in
+ var _nodes = hierarchy.call(self, d, i),
nodes = [],
maxDepth = 0,
numLeaves = 0;
+ //console.debug( JSON.stringify( _nodes, null, 2 ) )
+ window._d = d;
+ window._nodes = _nodes;
+ //TODO: remove dbl-touch loop
// changing from hierarchy's custom format for data to usable format
- _nodes.forEach(function (_node){
- var node = _node.data;
- node.depth = _node.depth;
+ _nodes.forEach(function (node){
maxDepth = node.depth > maxDepth ? node.depth : maxDepth; //finding max depth of tree
nodes.push(node);
});
- // counting the number of leaf nodes and assigning max depth to nodes that do not have children to flush all the leave nodes
+ // counting the number of leaf nodes and assigning max depth
+ // to nodes that do not have children to flush all the leave nodes
nodes.forEach(function(node){
if ( !node.children ) { //&& !node._children
numLeaves += 1;
@@ -120,15 +132,16 @@
};
+ /**
+ * -- Function with side effect of adding x0, y0 to all child; take in the root as starting point
+ * assuming that the leave nodes would be sorted in presented order
+ * horizontal(y0) is calculated according to (= evo dist X depth separation) from their parent
+ * vertical (x0) - if leave node: find its order in all of the leave node === node.id,
+ * then multiply by verticalSeparation
+ * - if parent node: is place in the mid point all of its children nodes
+ * -- The layout will first calculate the y0 field going towards the leaves, and x0 when returning
+ */
function layout (node, maxDepth, vertSeparation, parent) {
- /**
- * -- Function with side effect of adding x0, y0 to all child; take in the root as starting point
- * assuming that the leave nodes would be sorted in presented order
- * horizontal(y0) is calculated according to (= evo dist X depth separation) from their parent
- * vertical (x0) - if leave node: find its order in all of the leave node === node.id, then multiply by verticalSeparation
- * - if parent node: is place in the mid point all of its children nodes
- * -- The layout will first calculate the y0 field going towards the leaves, and x0 when returning
- */
var children = node.children,
sumChildVertSeparation = 0;
@@ -145,7 +158,8 @@
// if a node have no children, we will treat it as a leaf and start laying it out first
if (!children) {
- node.x0 = leafIndex++ * vertSeparation;
+ node.x0 = leafIndex * vertSeparation;
+ leafIndex += 1;
} else {
// if it has children, we will visit all its children and calculate its position from its children
children.forEach( function (child) {
@@ -189,12 +203,12 @@
root : {}, // Root has to be its own independent object because it is not part of the viz_config
+ /**
+ * Mechanism to expand or contract a single node. Expanded nodes have a children list, while for
+ * contracted nodes the list is stored in _children. Nodes with their children data stored in _children will not
+ * have their children rendered.
+ */
toggle : function (d) {
- /**
- * Mechanism to expand or contract a single node. Expanded nodes have a children list, while for
- * contracted nodes the list is stored in _children. Nodes with their children data stored in _children will not have their
- * children rendered.
- */
if(typeof d === "undefined") {return ;}
if (d.children ) {
d._children = d.children;
@@ -205,29 +219,29 @@
}
},
+ /**
+ * Contracts the phylotree to a single node by repeatedly calling itself to place all the list
+ * of children under _children.
+ */
toggleAll : function(d) {
- /**
- * Contracts the phylotree to a single node by repeatedly calling itself to place all the list
- * of children under _children.
- */
if (d.children && d.children.length !== 0) {
d.children.forEach(this.toggleAll);
toggle(d);
}
},
+ /**
+ * Return the data of the tree. Used for preserving state.
+ */
getData : function (){
- /**
- * Return the data of the tree. Used for preserving state.
- */
return this.root;
},
+ /**
+ * Overriding the default save mechanism to do some clean of circular reference of the
+ * phyloTree and to include phyloTree in the saved json
+ */
save: function() {
- /**
- * Overriding the default save mechanism to do some clean of circular reference of the
- * phyloTree and to include phyloTree in the saved json
- */
var root = this.root;
cleanTree(root);
this.set("root", root);
@@ -240,7 +254,7 @@
if (node._selected){ delete node._selected;}
if (node.children) {
- node.children.forEach(cleanTree);
+ node.children.forEach(cleanTree);
}
if (node._children) {
node._children.forEach(cleanTree);
@@ -270,26 +284,24 @@
});
-
+// -- Views --
/**
- * -- Views --
+ * Stores the default variable for setting up the visualization
*/
var PhylovizLayoutBase = Backbone.View.extend({
- /**
- * Stores the default variable for setting up the visualization
- */
defaults : {
nodeRadius : 4.5 // radius of each node in the diagram
},
+ /**
+ * Common initialization in layouts
+ */
stdInit : function (options) {
- /**
- * Common initialization in layouts
- */
var self = this;
- self.model.on("change:separation change:leafHeight change:fontSize change:nodeAttrChangedTime", self.updateAndRender, self);
+ self.model.on("change:separation change:leafHeight change:fontSize change:nodeAttrChangedTime",
+ self.updateAndRender, self);
self.vis = options.vis;
self.i = 0;
@@ -300,11 +312,11 @@
},
+ /**
+ * Updates the visualization whenever there are changes in the expansion and contraction of nodes
+ * AND possibly when the tree is edited.
+ */
updateAndRender : function(source) {
- /**
- * Updates the visualization whenever there are changes in the expansion and contraction of nodes
- * AND possibly when the tree is edited.
- */
var vis = d3.select(".vis"),
self = this;
source = source || self.model.root;
@@ -315,10 +327,10 @@
},
+ /**
+ * Renders the links for the visualization.
+ */
renderLinks : function(source) {
- /**
- * Renders the links for the visualization.
- */
var self = this;
var diagonal = self.diagonal;
var duration = self.duration;
@@ -327,15 +339,17 @@
.data(self.tree.links(self.nodes), function(d) { return d.target.id; });
var calcalateLinePos = function(d) {
- d.pos0 = d.source.y0 + " " + d.source.x0; // position of the source node <=> starting location of the line drawn
- d.pos1 = d.source.y0 + " " + d.target.x0; // position where the line makes a right angle bend
- d.pos2 = d.target.y0 + " " + d.target.x0; // point where the horizontal line becomes a dotted line
+ // position of the source node <=> starting location of the line drawn
+ d.pos0 = d.source.y0 + " " + d.source.x0;
+ // position where the line makes a right angle bend
+ d.pos1 = d.source.y0 + " " + d.target.x0;
+ // point where the horizontal line becomes a dotted line
+ d.pos2 = d.target.y0 + " " + d.target.x0;
};
var linkEnter = link.enter().insert("svg:g","g.node")
.attr("class", "completeLink");
-
linkEnter.append("svg:path")
.attr("class", "link")
.attr("d", function(d) {
@@ -357,10 +371,10 @@
// User Interaction methods below
+ /**
+ * Displays the information for editing
+ */
selectNode : function(node){
- /**
- * Displays the information for editting
- */
var self = this;
d3.selectAll("g.node")
.classed("selectedHighlight", function(d){
@@ -382,11 +396,11 @@
$("#phyloVizSelectedNodeAnnotation").val(node.annotation || "");
},
+ /**
+ * Creates bootstrap tooltip for the visualization. Has to be called repeatedly due to newly generated
+ * enterNodes
+ */
addTooltips : function (){
- /**
- * Creates bootstrap tooltip for the visualization. Has to be called repeatedly due to newly generated
- * enterNodes
- */
$(".bs-tooltip").remove(); //clean up tooltip, just in case its listeners are removed by d3
$(".node")
.attr("data-original-title", function(){
@@ -400,13 +414,11 @@
});
-
-
+/**
+ * Linea layout class of Phyloviz, is responsible for rendering the nodes
+ * calls PhyloTreeLayout to determine the positions of the nodes
+ */
var PhylovizLinearView = PhylovizLayoutBase.extend({
- /**
- * Linea layout class of Phyloviz, is responsible for rendering the nodes
- * calls PhyloTreeLayout to determine the positions of the nodes
- */
initialize : function(options){
// Default values of linear layout
var self = this;
@@ -419,23 +431,21 @@
self.updateAndRender(self.model.root);
},
+ /**
+ * Creates the basic layout of a linear tree by precalculating fixed values.
+ * One of calculations are also made here
+ */
layout : function() {
- /**
- * Creates the basic layout of a linear tree by precalculating fixed values.
- * One of calculations are also made here
- */
-
var self = this;
-
self.tree = new PhyloTreeLayout().layoutMode("Linear");
self.diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x ]; });
},
+ /**
+ * Renders the nodes base on Linear layout.
+ */
renderNodes : function (source) {
- /**
- * Renders the nodes base on Linear layout.
- */
var self = this,
fontSize = self.model.get("fontSize") + "px";
@@ -446,7 +456,9 @@
nodes = self.tree.separation(self.model.get("separation")).nodes(self.model.root);
var node = self.vis.selectAll("g.node")
- .data(nodes, function(d) { return d.name + d.id || (d.id = ++self.i); });
+ .data(nodes, function(d) {
+ return d.name + d.id || (d.id = ++self.i);
+ });
// These variables has to be passed into update links which are in the base methods
self.nodes = nodes;
@@ -466,7 +478,12 @@
self.updateAndRender(d); // re-render the tree
}
});
-
+ console.debug( 'source:', source )
+ //TODO: newick and phyloxml return arrays. where should this go (client (here, else), server)?
+ if( toString.call( source ) === '[object Array]' ){
+ // if d is an array, replate with the first object (newick, phyloxml)
+ source = source[0];
+ }
nodeEnter.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; });
nodeEnter.append("svg:circle")
@@ -557,8 +574,8 @@
self.nodeSelectionView = new NodeSelectionView({phyloTree : self.phyloTree});
self.search = new PhyloVizSearch();
-
- setTimeout(function(){ // using settimeout to call the zoomAndPan function according to the stored attributes in viz_config
+ // using settimeout to call the zoomAndPan function according to the stored attributes in viz_config
+ setTimeout(function(){
self.zoomAndPan();
}, 1000);
},
@@ -603,11 +620,11 @@
var linearView = new PhylovizLinearView(self.layoutOptions);
},
+ /**
+ * Function to zoom and pan the svg element which the entire tree is contained within
+ * Uses d3.zoom events, and extend them to allow manual updates and keeping states in model
+ */
zoomAndPan : function(event){
- /**
- * Function to zoom and pan the svg element which the entire tree is contained within
- * Uses d3.zoom events, and extend them to allow manual updates and keeping states in model
- */
var zoomParams,
translateParams;
if (typeof event !== "undefined") {
@@ -659,21 +676,26 @@
self.phyloTree.set("scaleFactor", scaleFactor);
self.phyloTree.set("translate", translationCoor);
- self.vis.attr("transform", translateStatement + zoomStatement); //refers to the view that we are actually zooming
+ //refers to the view that we are actually zooming
+ self.vis.attr("transform", translateStatement + zoomStatement);
},
+ /**
+ * Primes the Ajax URL to load another Nexus tree
+ */
reloadViz : function() {
- /**
- * Primes the Ajax URL to load another Nexus tree
- */
var self = this,
treeIndex = $("#phylovizNexSelector :selected").val();
- $.getJSON(self.phyloTree.get("dataset").url(), { tree_index: treeIndex, data_type: 'raw_data' }, function(packedJson){
- self.data = packedJson.data;
- self.config = packedJson;
- self.render();
- });
+ $.getJSON(self.phyloTree.get("dataset").url(), {
+ tree_index: treeIndex,
+ data_type: 'raw_data'
+ },
+ function(packedJson){
+ self.data = packedJson.data;
+ self.config = packedJson;
+ self.render();
+ });
}
});
@@ -768,10 +790,10 @@
$("#phylovizApplySettingsBtn").off().on("click", function() { self.apply(); });
},
+ /**
+ * Applying user values to phylotree model.
+ */
apply : function(){
- /**
- * Applying user values to phylotree model.
- */
var self = this;
if (!self.isAcceptableValue(self.inputs.separation, 50, 2500) ||
!self.isAcceptableValue(self.inputs.leafHeight, 5, 30) ||
@@ -782,19 +804,19 @@
self.phyloTree.set(key, $input.val());
});
},
+ /**
+ * Called to update the values input to that stored in the model
+ */
updateUI : function(){
- /**
- * Called to update the values input to that stored in the model
- */
var self = this;
$.each(self.inputs, function(key, $input){
$input.val(self.phyloTree.get(key));
});
},
+ /**
+ * Resets the value of the phyloTree model to its default
+ */
resetToDefaults : function(){
- /**
- * Resets the value of the phyloTree model to its default
- */
$(".bs-tooltip").remove(); // just in case the tool tip was not removed
var self = this;
$.each(self.phyloTree.defaults, function(key, value) {
@@ -810,10 +832,11 @@
});
+/**
+ * View for inspecting node properties and editing them
+ */
var NodeSelectionView = UserMenuBase.extend({
- /**
- * View for inspecting node properties and editing them
- */
+
className: 'Settings',
initialize : function (options){
@@ -830,11 +853,12 @@
annotation : $("#phyloVizSelectedNodeAnnotation")
};
+ // temporarily stores the values in case user change their mind
self.valuesOfConcern = {
name : null,
dist : null,
annotation : null
- }; // temporarily stores the values in case user change their mind
+ };
//init UI buttons
$("#nodeSelCloseBtn").off().on("click", function() { self.el.hide(); });
@@ -859,10 +883,10 @@
});
},
+ /**
+ * For turning on and off the child elements
+ */
toggleUI : function(){
- /**
- * For turning on and off the child elements
- */
var self = this,
checked = self.UI.enableEdit.is(':checked');
@@ -881,10 +905,10 @@
},
+ /**
+ * Reverting to previous values in case user change their minds
+ */
cancelChanges : function() {
- /**
- * Reverting to previous values in case user change their minds
- */
var self = this,
node = self.phyloTree.get("selectedNode");
if (node){
@@ -894,10 +918,10 @@
}
},
+ /**
+ * Changing the data in the underlying tree with user-specified values
+ */
updateNodes : function (){
- /**
- * Changing the data in the underlying tree with user-specified values
- */
var self = this,
node = self.phyloTree.get("selectedNode");
if (node){
@@ -914,17 +938,15 @@
alert("No node selected");
}
}
-
-
});
+/**
+ * Initializes the search panel on phyloviz and handles its user interaction
+ * It allows user to search the entire free based on some qualifer, like dist <= val.
+ */
var PhyloVizSearch = UserMenuBase.extend({
- /**
- * Initializes the search panel on phyloviz and handles its user interaction
- * It allows user to search the entire free based on some qualifer, like dist <= val.
- */
initialize : function () {
var self = this;
@@ -942,10 +964,10 @@
});
},
+ /**
+ * Searches the entire tree and will highlight the nodes that match the condition in green
+ */
searchTree : function (attr, condition, val){
- /**
- * Searches the entire tree and will highlight the nodes that match the condition in green
- */
d3.selectAll("g.node")
.classed("searchHighlight", function(d){
var attrVal = d[attr];
@@ -972,4 +994,4 @@
PhylovizView: PhylovizView
};
-});
\ No newline at end of file
+});
diff -r 9bb23c38aeec1f26ec1c22fbcad8a098fd6ae015 -r d8b3dc823978835f0b2105635990f310fa619c1c templates/webapps/galaxy/visualization/phyloviz.mako
--- a/templates/webapps/galaxy/visualization/phyloviz.mako
+++ b/templates/webapps/galaxy/visualization/phyloviz.mako
@@ -81,7 +81,7 @@
position: fixed;
## Borrowed from galaxy modal_dialogues
- background-color: white;
+ background-color: white;
border: 1px solid #999;
border: 1px solid rgba(0, 0, 0, 0.3);
-webkit-border-radius: 6px;
@@ -157,9 +157,9 @@
// -- Initialization code |-->
phyloviz = new phyloviz_mod.PhylovizView({
- data: data,
- layout : "Linear",
- config : config
+ data : data,
+ layout : "Linear",
+ config : config
});
// -- Render viz. --
@@ -169,7 +169,9 @@
$(function firstVizLoad(){ // calls when viz is loaded for the first time
var config = JSON.parse( '${ h.to_json_string( config )}');
+ window.config = config;
var data = JSON.parse('${h.to_json_string(data)}');
+ window.data = data;
initPhyloViz(data, config);
});
});
@@ -189,7 +191,6 @@
<div style="clear: both"></div></div>
-
<div id="phyloVizNavContainer"><div id="phyloVizNav">
%if config["ext"] == "nex" and not config["saved_visualization"]:
@@ -208,10 +209,7 @@
<div class="navControl"><p> | Alt+click to select nodes</p></div>
-
-
</div>
-
</div>
## Node Selection Menu
@@ -284,11 +282,6 @@
</div></div>
-
-
-
-
-
<div class="Panel" id="FloatingMenu" style="display: None;"><h2>PhyloViz (<a onclick="displayHelp()" href="javascript:void(0);">?</a>)</h2>
@@ -300,14 +293,12 @@
<div class="hint">4. Minimap: Currently displays an exact but scaled down replicate of the tree, orange bounding box is correct for linear only<br/>
Can be switched on or off</div><div class="hint">5. Changing Layouts: Able to change between circular and linear layouts.</div>
-
</div><h5>Scaling & Rotation:</h5><button id="phylovizZoomInBtn" class="" > + </button><button id="phylovizZoomOutBtn" class="" > - </button>
-
<h5>Translation:</h5><button id="phylovizTranslateUpBtn" > Up </button><button id="phylovizTranslateDownBtn" > Down </button>
@@ -315,8 +306,6 @@
<button id="phylovizTranslateLeftBtn" > Left </button><button id="phylovizTranslateRightBtn" > Right </button>
-
-
<h5>Others:</h5><button id="phylovizResetBtn" > Reset Zoom/Translate </button><button id="phylovizSaveBtn" > Save vizualization </button>
https://bitbucket.org/galaxy/galaxy-central/commits/82f83d00dfd4/
Changeset: 82f83d00dfd4
User: carlfeberhard
Date: 2013-05-21 17:16:05
Summary: merge next-stable
Affected #: 6 files
diff -r 137dc44f21782c771879af1febfe962a2ea9ae6a -r 82f83d00dfd419c035c76b100ec0e88a10bb900c lib/galaxy/visualization/data_providers/phyloviz/__init__.py
--- a/lib/galaxy/visualization/data_providers/phyloviz/__init__.py
+++ b/lib/galaxy/visualization/data_providers/phyloviz/__init__.py
@@ -1,3 +1,4 @@
+
""" Data providers code for PhyloViz """
from galaxy.visualization.data_providers.basic import BaseDataProvider
@@ -40,4 +41,3 @@
rval[ "msg"] = parseMsg
return rval
-
diff -r 137dc44f21782c771879af1febfe962a2ea9ae6a -r 82f83d00dfd419c035c76b100ec0e88a10bb900c lib/galaxy/visualization/data_providers/phyloviz/newickparser.py
--- a/lib/galaxy/visualization/data_providers/phyloviz/newickparser.py
+++ b/lib/galaxy/visualization/data_providers/phyloviz/newickparser.py
@@ -77,8 +77,6 @@
childrenNodes += [node]
return childrenNodes
-
-
def _mapName(self, newickString, nameMap):
"""
Necessary to replace names of terms inside nexus representation
@@ -108,9 +106,9 @@
newString += newickString[start:]
return newString
-
def parseNode(self, string, depth):
- """ Recursive method for parsing newick string, works by stripping down the string into substring
+ """
+ Recursive method for parsing newick string, works by stripping down the string into substring
of newick contained with brackers, which is used to call itself.
Eg ... ( A, B, (D, E)C, F, G ) ...
diff -r 137dc44f21782c771879af1febfe962a2ea9ae6a -r 82f83d00dfd419c035c76b100ec0e88a10bb900c lib/galaxy/visualization/data_providers/registry.py
--- a/lib/galaxy/visualization/data_providers/registry.py
+++ b/lib/galaxy/visualization/data_providers/registry.py
@@ -53,7 +53,7 @@
elif isinstance( original_dataset.datatype, Tabular ):
data_provider_class = ColumnDataProvider
elif isinstance( original_dataset.datatype, ( Nexus, Newick, Phyloxml ) ):
- data_provider_class = genome.PhylovizDataProvider
+ data_provider_class = PhylovizDataProvider
data_provider = data_provider_class( original_dataset=original_dataset )
diff -r 137dc44f21782c771879af1febfe962a2ea9ae6a -r 82f83d00dfd419c035c76b100ec0e88a10bb900c static/scripts/packed/viz/phyloviz.js
--- a/static/scripts/packed/viz/phyloviz.js
+++ b/static/scripts/packed/viz/phyloviz.js
@@ -1,1 +1,1 @@
-define(["libs/d3","viz/visualization","mvc/data"],function(m,f,g){var l=Backbone.View.extend({className:"UserMenuBase",isAcceptableValue:function(r,p,n){var o=this,s=r.val(),t=r.attr("displayLabel")||r.attr("id").replace("phyloViz","");function q(u){return !isNaN(parseFloat(u))&&isFinite(u)}if(!q(s)){alert(t+" is not a number!");return false}if(s>n){alert(t+" is too large.");return false}else{if(s<p){alert(t+" is too small.");return false}}return true},hasIllegalJsonCharacters:function(n){if(n.val().search(/"|'|\\/)!==-1){alert("Named fields cannot contain these illegal characters: double quote(\"), single guote('), or back slash(\\). ");return true}return false}});function h(){var w=this,r=m.layout.hierarchy().sort(null).value(null),v=360,q="Linear",u=18,s=200,t=0,p=0.5,n=50;w.leafHeight=function(x){if(typeof x==="undefined"){return u}else{u=x;return w}};w.layoutMode=function(x){if(typeof x==="undefined"){return q}else{q=x;return w}};w.layoutAngle=function(x){if(typeof x==="undefined"){return v}if(isNaN(x)||x<0||x>360){return w}else{v=x;return w}};w.separation=function(x){if(typeof x==="undefined"){return s}else{s=x;return w}};w.links=function(x){return m.layout.tree().links(x)};w.nodes=function(A,y){var z=r.call(w,A,y),x=[],C=0,B=0;z.forEach(function(D){var E=D.data;E.depth=D.depth;C=E.depth>C?E.depth:C;x.push(E)});x.forEach(function(D){if(!D.children){B+=1;D.depth=C}});u=q==="Circular"?v/B:u;t=0;o(x[0],C,u,null);return x};function o(B,D,A,z){var y=B.children,x=0;var C=B.dist||p;C=C>1?1:C;B.dist=C;if(z!==null){B.y0=z.y0+C*s}else{B.y0=n}if(!y){B.x0=t++*A}else{y.forEach(function(E){E.parent=B;x+=o(E,D,A,B)});B.x0=x/y.length}B.x=B.x0;B.y=B.y0;return B.x0}return w}var b=f.Visualization.extend({defaults:{layout:"Linear",separation:250,leafHeight:18,type:"phyloviz",title:"Title",scaleFactor:1,translate:[0,0],fontSize:12,selectedNode:null,nodeAttrChangedTime:0},initialize:function(n){this.set("dataset",new g.Dataset({id:n.dataset_id}))},root:{},toggle:function(n){if(typeof n==="undefined"){return}if(n.children){n._children=n.children;n.children=null}else{n.children=n._children;n._children=null}},toggleAll:function(n){if(n.children&&n.children.length!==0){n.children.forEach(this.toggleAll);toggle(n)}},getData:function(){return this.root},save:function(){var n=this.root;o(n);this.set("root",n);function o(q){delete q.parent;if(q._selected){delete q._selected}if(q.children){q.children.forEach(o)}if(q._children){q._children.forEach(o)}}var p=jQuery.extend(true,{},this.attributes);p.selectedNode=null;show_message("Saving to Galaxy","progress");return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(p)},success:function(q){var r=q.url.split("id=")[1].split("&")[0],s="/visualization?id="+r;window.history.pushState({},"",s+window.location.hash);hide_modal()}})}});var d=Backbone.View.extend({defaults:{nodeRadius:4.5},stdInit:function(o){var n=this;n.model.on("change:separation change:leafHeight change:fontSize change:nodeAttrChangedTime",n.updateAndRender,n);n.vis=o.vis;n.i=0;n.maxDepth=-1;n.width=o.width;n.height=o.height},updateAndRender:function(p){var o=m.select(".vis"),n=this;p=p||n.model.root;n.renderNodes(p);n.renderLinks(p);n.addTooltips()},renderLinks:function(n){var w=this;var o=w.diagonal;var p=w.duration;var r=w.layoutMode;var t=w.vis.selectAll("g.completeLink").data(w.tree.links(w.nodes),function(x){return x.target.id});var v=function(x){x.pos0=x.source.y0+" "+x.source.x0;x.pos1=x.source.y0+" "+x.target.x0;x.pos2=x.target.y0+" "+x.target.x0};var u=t.enter().insert("svg:g","g.node").attr("class","completeLink");u.append("svg:path").attr("class","link").attr("d",function(x){v(x);return"M "+x.pos0+" L "+x.pos1});var s=t.transition().duration(500);s.select("path.link").attr("d",function(x){v(x);return"M "+x.pos0+" L "+x.pos1+" L "+x.pos2});var q=t.exit().remove()},selectNode:function(o){var n=this;m.selectAll("g.node").classed("selectedHighlight",function(p){if(o.id===p.id){if(o._selected){delete o._selected;return false}else{o._selected=true;return true}}return false});n.model.set("selectedNode",o);$("#phyloVizSelectedNodeName").val(o.name);$("#phyloVizSelectedNodeDist").val(o.dist);$("#phyloVizSelectedNodeAnnotation").val(o.annotation||"")},addTooltips:function(){$(".bs-tooltip").remove();$(".node").attr("data-original-title",function(){var o=this.__data__,n=o.annotation||"None";return o?(o.name?o.name+"<br/>":"")+"Dist: "+o.dist+" <br/>Annotation: "+n:""}).tooltip({placement:"top",trigger:"hover"})}});var a=d.extend({initialize:function(o){var n=this;n.margins=o.margins;n.layoutMode="Linear";n.stdInit(o);n.layout();n.updateAndRender(n.model.root)},layout:function(){var n=this;n.tree=new h().layoutMode("Linear");n.diagonal=m.svg.diagonal().projection(function(o){return[o.y,o.x]})},renderNodes:function(n){var u=this,v=u.model.get("fontSize")+"px";u.tree.separation(u.model.get("separation")).leafHeight(u.model.get("leafHeight"));var q=500,o=u.tree.separation(u.model.get("separation")).nodes(u.model.root);var p=u.vis.selectAll("g.node").data(o,function(w){return w.name+w.id||(w.id=++u.i)});u.nodes=o;u.duration=q;var r=p.enter().append("svg:g").attr("class","node").on("dblclick",function(){m.event.stopPropagation()}).on("click",function(w){if(m.event.altKey){u.selectNode(w)}else{if(w.children&&w.children.length===0){return}u.model.toggle(w);u.updateAndRender(w)}});r.attr("transform",function(w){return"translate("+n.y0+","+n.x0+")"});r.append("svg:circle").attr("r",0.000001).style("fill",function(w){return w._children?"lightsteelblue":"#fff"});r.append("svg:text").attr("class","nodeLabel").attr("x",function(w){return w.children||w._children?-10:10}).attr("dy",".35em").attr("text-anchor",function(w){return w.children||w._children?"end":"start"}).style("fill-opacity",0.000001);var s=p.transition().duration(q);s.attr("transform",function(w){return"translate("+w.y+","+w.x+")"});s.select("circle").attr("r",u.defaults.nodeRadius).style("fill",function(w){return w._children?"lightsteelblue":"#fff"});s.select("text").style("fill-opacity",1).style("font-size",v).text(function(w){return w.name});var t=p.exit().transition().duration(q).remove();t.select("circle").attr("r",0.000001);t.select("text").style("fill-opacity",0.000001);o.forEach(function(w){w.x0=w.x;w.y0=w.y})}});var j=Backbone.View.extend({className:"phyloviz",initialize:function(o){var n=this;n.MIN_SCALE=0.05;n.MAX_SCALE=5;n.MAX_DISPLACEMENT=500;n.margins=[10,60,10,80];n.width=$("#PhyloViz").width();n.height=$("#PhyloViz").height();n.radius=n.width;n.data=o.data;$(window).resize(function(){n.width=$("#PhyloViz").width();n.height=$("#PhyloViz").height();n.render()});n.phyloTree=new b(o.config);n.phyloTree.root=n.data;n.zoomFunc=m.behavior.zoom().scaleExtent([n.MIN_SCALE,n.MAX_SCALE]);n.zoomFunc.translate(n.phyloTree.get("translate"));n.zoomFunc.scale(n.phyloTree.get("scaleFactor"));n.navMenu=new c(n);n.settingsMenu=new i({phyloTree:n.phyloTree});n.nodeSelectionView=new e({phyloTree:n.phyloTree});n.search=new k();setTimeout(function(){n.zoomAndPan()},1000)},render:function(){var o=this;$("#PhyloViz").empty();o.mainSVG=m.select("#PhyloViz").append("svg:svg").attr("width",o.width).attr("height",o.height).attr("pointer-events","all").call(o.zoomFunc.on("zoom",function(){o.zoomAndPan()}));o.boundingRect=o.mainSVG.append("svg:rect").attr("class","boundingRect").attr("width",o.width).attr("height",o.height).attr("stroke","black").attr("fill","white");o.vis=o.mainSVG.append("svg:g").attr("class","vis");o.layoutOptions={model:o.phyloTree,width:o.width,height:o.height,vis:o.vis,margins:o.margins};$("#title").text("Phylogenetic Tree from "+o.phyloTree.get("title")+":");var n=new a(o.layoutOptions)},zoomAndPan:function(n){var t,p;if(typeof n!=="undefined"){t=n.zoom;p=n.translate}var w=this,r=w.zoomFunc.scale(),v=w.zoomFunc.translate(),s="",u="";switch(t){case"reset":r=1;v=[0,0];break;case"+":r*=1.1;break;case"-":r*=0.9;break;default:if(typeof t==="number"){r=t}else{if(m.event!==null){r=m.event.scale}}}if(r<w.MIN_SCALE||r>w.MAX_SCALE){return}w.zoomFunc.scale(r);s="translate("+w.margins[3]+","+w.margins[0]+") scale("+r+")";if(m.event!==null){u="translate("+m.event.translate+")"}else{if(typeof p!=="undefined"){var q=p.split(",")[0];var o=p.split(",")[1];if(!isNaN(q)&&!isNaN(o)){v=[v[0]+parseFloat(q),v[1]+parseFloat(o)]}}w.zoomFunc.translate(v);u="translate("+v+")"}w.phyloTree.set("scaleFactor",r);w.phyloTree.set("translate",v);w.vis.attr("transform",u+s)},reloadViz:function(){var n=this,o=$("#phylovizNexSelector :selected").val();$.getJSON(n.phyloTree.get("dataset").url(),{tree_index:o,data_type:"raw_data"},function(p){n.data=p.data;n.config=p;n.render()})}});var c=Backbone.View.extend({initialize:function(o){var n=this;n.phylovizView=o;$("#panelHeaderRightBtns").empty();$("#phyloVizNavBtns").empty();$("#phylovizNexSelector").off();n.initNavBtns();n.initRightHeaderBtns();$("#phylovizNexSelector").off().on("change",function(){n.phylovizView.reloadViz()})},initRightHeaderBtns:function(){var n=this;rightMenu=create_icon_buttons_menu([{icon_class:"gear",title:"PhyloViz Settings",on_click:function(){$("#SettingsMenu").show();n.settingsMenu.updateUI()}},{icon_class:"disk",title:"Save visualization",on_click:function(){var o=$("#phylovizNexSelector option:selected").text();if(o){n.phylovizView.phyloTree.set("title",o)}n.phylovizView.phyloTree.save()}},{icon_class:"chevron-expand",title:"Search / Edit Nodes",on_click:function(){$("#nodeSelectionView").show()}},{icon_class:"information",title:"Phyloviz Help",on_click:function(){window.open("http://wiki.g2.bx.psu.edu/Learn/Visualization/PhylogeneticTree")}}],{tooltip_config:{placement:"bottom"}});$("#panelHeaderRightBtns").append(rightMenu.$el)},initNavBtns:function(){var n=this,o=create_icon_buttons_menu([{icon_class:"zoom-in",title:"Zoom in",on_click:function(){n.phylovizView.zoomAndPan({zoom:"+"})}},{icon_class:"zoom-out",title:"Zoom out",on_click:function(){n.phylovizView.zoomAndPan({zoom:"-"})}},{icon_class:"arrow-circle",title:"Reset Zoom/Pan",on_click:function(){n.phylovizView.zoomAndPan({zoom:"reset"})}}],{tooltip_config:{placement:"bottom"}});$("#phyloVizNavBtns").append(o.$el)}});var i=l.extend({className:"Settings",initialize:function(o){var n=this;n.phyloTree=o.phyloTree;n.el=$("#SettingsMenu");n.inputs={separation:$("#phyloVizTreeSeparation"),leafHeight:$("#phyloVizTreeLeafHeight"),fontSize:$("#phyloVizTreeFontSize")};$("#settingsCloseBtn").off().on("click",function(){n.el.hide()});$("#phylovizResetSettingsBtn").off().on("click",function(){n.resetToDefaults()});$("#phylovizApplySettingsBtn").off().on("click",function(){n.apply()})},apply:function(){var n=this;if(!n.isAcceptableValue(n.inputs.separation,50,2500)||!n.isAcceptableValue(n.inputs.leafHeight,5,30)||!n.isAcceptableValue(n.inputs.fontSize,5,20)){return}$.each(n.inputs,function(o,p){n.phyloTree.set(o,p.val())})},updateUI:function(){var n=this;$.each(n.inputs,function(o,p){p.val(n.phyloTree.get(o))})},resetToDefaults:function(){$(".bs-tooltip").remove();var n=this;$.each(n.phyloTree.defaults,function(o,p){n.phyloTree.set(o,p)});n.updateUI()},render:function(){}});var e=l.extend({className:"Settings",initialize:function(o){var n=this;n.el=$("#nodeSelectionView");n.phyloTree=o.phyloTree;n.UI={enableEdit:$("#phylovizEditNodesCheck"),saveChanges:$("#phylovizNodeSaveChanges"),cancelChanges:$("#phylovizNodeCancelChanges"),name:$("#phyloVizSelectedNodeName"),dist:$("#phyloVizSelectedNodeDist"),annotation:$("#phyloVizSelectedNodeAnnotation")};n.valuesOfConcern={name:null,dist:null,annotation:null};$("#nodeSelCloseBtn").off().on("click",function(){n.el.hide()});n.UI.saveChanges.off().on("click",function(){n.updateNodes()});n.UI.cancelChanges.off().on("click",function(){n.cancelChanges()});(function(p){p.fn.enable=function(q){return p(this).each(function(){if(q){p(this).removeAttr("disabled")}else{p(this).attr("disabled","disabled")}})}})(jQuery);n.UI.enableEdit.off().on("click",function(){n.toggleUI()})},toggleUI:function(){var n=this,o=n.UI.enableEdit.is(":checked");if(!o){n.cancelChanges()}$.each(n.valuesOfConcern,function(p,q){n.UI[p].enable(o)});if(o){n.UI.saveChanges.show();n.UI.cancelChanges.show()}else{n.UI.saveChanges.hide();n.UI.cancelChanges.hide()}},cancelChanges:function(){var n=this,o=n.phyloTree.get("selectedNode");if(o){$.each(n.valuesOfConcern,function(p,q){n.UI[p].val(o[p])})}},updateNodes:function(){var n=this,o=n.phyloTree.get("selectedNode");if(o){if(!n.isAcceptableValue(n.UI.dist,0,1)||n.hasIllegalJsonCharacters(n.UI.name)||n.hasIllegalJsonCharacters(n.UI.annotation)){return}$.each(n.valuesOfConcern,function(p,q){(o[p])=n.UI[p].val()});n.phyloTree.set("nodeAttrChangedTime",new Date())}else{alert("No node selected")}}});var k=l.extend({initialize:function(){var n=this;$("#phyloVizSearchBtn").on("click",function(){var p=$("#phyloVizSearchTerm"),q=$("#phyloVizSearchCondition").val().split("-"),o=q[0],r=q[1];n.hasIllegalJsonCharacters(p);if(o==="dist"){n.isAcceptableValue(p,0,1)}n.searchTree(o,r,p.val())})},searchTree:function(n,p,o){m.selectAll("g.node").classed("searchHighlight",function(r){var q=r[n];if(typeof q!=="undefined"&&q!==null){if(n==="dist"){switch(p){case"greaterEqual":return q>=+o;case"lesserEqual":return q<=+o;default:return}}else{if(n==="name"||n==="annotation"){return q.toLowerCase().indexOf(o.toLowerCase())!==-1}}}})}});return{PhylovizView:j}});
\ No newline at end of file
+define(["libs/d3","viz/visualization","mvc/data"],function(m,f,g){var l=Backbone.View.extend({className:"UserMenuBase",isAcceptableValue:function(q,o,n){var r=q.val(),s=q.attr("displayLabel")||q.attr("id").replace("phyloViz","");function p(t){return !isNaN(parseFloat(t))&&isFinite(t)}if(!p(r)){alert(s+" is not a number!");return false}if(r>n){alert(s+" is too large.");return false}else{if(r<o){alert(s+" is too small.");return false}}return true},hasIllegalJsonCharacters:function(n){if(n.val().search(/"|'|\\/)!==-1){alert("Named fields cannot contain these illegal characters: double quote(\"), single guote('), or back slash(\\). ");return true}return false}});function h(){var w=this,r=m.layout.hierarchy().sort(null).value(null),v=360,q="Linear",u=18,s=200,t=0,p=0.5,n=50;w.leafHeight=function(x){if(typeof x==="undefined"){return u}else{u=x;return w}};w.layoutMode=function(x){if(typeof x==="undefined"){return q}else{q=x;return w}};w.layoutAngle=function(x){if(typeof x==="undefined"){return v}if(isNaN(x)||x<0||x>360){return w}else{v=x;return w}};w.separation=function(x){if(typeof x==="undefined"){return s}else{s=x;return w}};w.links=function(x){return m.layout.tree().links(x)};w.nodes=function(A,y){if(toString.call(A)==="[object Array]"){A=A[0]}var z=r.call(w,A,y),x=[],C=0,B=0;window._d=A;window._nodes=z;z.forEach(function(D){C=D.depth>C?D.depth:C;x.push(D)});x.forEach(function(D){if(!D.children){B+=1;D.depth=C}});u=q==="Circular"?v/B:u;t=0;o(x[0],C,u,null);return x};function o(B,D,A,z){var y=B.children,x=0;var C=B.dist||p;C=C>1?1:C;B.dist=C;if(z!==null){B.y0=z.y0+C*s}else{B.y0=n}if(!y){B.x0=t*A;t+=1}else{y.forEach(function(E){E.parent=B;x+=o(E,D,A,B)});B.x0=x/y.length}B.x=B.x0;B.y=B.y0;return B.x0}return w}var b=f.Visualization.extend({defaults:{layout:"Linear",separation:250,leafHeight:18,type:"phyloviz",title:"Title",scaleFactor:1,translate:[0,0],fontSize:12,selectedNode:null,nodeAttrChangedTime:0},initialize:function(n){this.set("dataset",new g.Dataset({id:n.dataset_id}))},root:{},toggle:function(n){if(typeof n==="undefined"){return}if(n.children){n._children=n.children;n.children=null}else{n.children=n._children;n._children=null}},toggleAll:function(n){if(n.children&&n.children.length!==0){n.children.forEach(this.toggleAll);toggle(n)}},getData:function(){return this.root},save:function(){var n=this.root;o(n);this.set("root",n);function o(q){delete q.parent;if(q._selected){delete q._selected}if(q.children){q.children.forEach(o)}if(q._children){q._children.forEach(o)}}var p=jQuery.extend(true,{},this.attributes);p.selectedNode=null;show_message("Saving to Galaxy","progress");return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(p)},success:function(q){var r=q.url.split("id=")[1].split("&")[0],s="/visualization?id="+r;window.history.pushState({},"",s+window.location.hash);hide_modal()}})}});var d=Backbone.View.extend({defaults:{nodeRadius:4.5},stdInit:function(o){var n=this;n.model.on("change:separation change:leafHeight change:fontSize change:nodeAttrChangedTime",n.updateAndRender,n);n.vis=o.vis;n.i=0;n.maxDepth=-1;n.width=o.width;n.height=o.height},updateAndRender:function(p){var o=m.select(".vis"),n=this;p=p||n.model.root;n.renderNodes(p);n.renderLinks(p);n.addTooltips()},renderLinks:function(n){var w=this;var o=w.diagonal;var p=w.duration;var r=w.layoutMode;var t=w.vis.selectAll("g.completeLink").data(w.tree.links(w.nodes),function(x){return x.target.id});var v=function(x){x.pos0=x.source.y0+" "+x.source.x0;x.pos1=x.source.y0+" "+x.target.x0;x.pos2=x.target.y0+" "+x.target.x0};var u=t.enter().insert("svg:g","g.node").attr("class","completeLink");u.append("svg:path").attr("class","link").attr("d",function(x){v(x);return"M "+x.pos0+" L "+x.pos1});var s=t.transition().duration(500);s.select("path.link").attr("d",function(x){v(x);return"M "+x.pos0+" L "+x.pos1+" L "+x.pos2});var q=t.exit().remove()},selectNode:function(o){var n=this;m.selectAll("g.node").classed("selectedHighlight",function(p){if(o.id===p.id){if(o._selected){delete o._selected;return false}else{o._selected=true;return true}}return false});n.model.set("selectedNode",o);$("#phyloVizSelectedNodeName").val(o.name);$("#phyloVizSelectedNodeDist").val(o.dist);$("#phyloVizSelectedNodeAnnotation").val(o.annotation||"")},addTooltips:function(){$(".bs-tooltip").remove();$(".node").attr("data-original-title",function(){var o=this.__data__,n=o.annotation||"None";return o?(o.name?o.name+"<br/>":"")+"Dist: "+o.dist+" <br/>Annotation: "+n:""}).tooltip({placement:"top",trigger:"hover"})}});var a=d.extend({initialize:function(o){var n=this;n.margins=o.margins;n.layoutMode="Linear";n.stdInit(o);n.layout();n.updateAndRender(n.model.root)},layout:function(){var n=this;n.tree=new h().layoutMode("Linear");n.diagonal=m.svg.diagonal().projection(function(o){return[o.y,o.x]})},renderNodes:function(n){var u=this,v=u.model.get("fontSize")+"px";u.tree.separation(u.model.get("separation")).leafHeight(u.model.get("leafHeight"));var q=500,o=u.tree.separation(u.model.get("separation")).nodes(u.model.root);var p=u.vis.selectAll("g.node").data(o,function(w){return w.name+w.id||(w.id=++u.i)});u.nodes=o;u.duration=q;var r=p.enter().append("svg:g").attr("class","node").on("dblclick",function(){m.event.stopPropagation()}).on("click",function(w){if(m.event.altKey){u.selectNode(w)}else{if(w.children&&w.children.length===0){return}u.model.toggle(w);u.updateAndRender(w)}});console.debug("source:",n);if(toString.call(n)==="[object Array]"){n=n[0]}r.attr("transform",function(w){return"translate("+n.y0+","+n.x0+")"});r.append("svg:circle").attr("r",0.000001).style("fill",function(w){return w._children?"lightsteelblue":"#fff"});r.append("svg:text").attr("class","nodeLabel").attr("x",function(w){return w.children||w._children?-10:10}).attr("dy",".35em").attr("text-anchor",function(w){return w.children||w._children?"end":"start"}).style("fill-opacity",0.000001);var s=p.transition().duration(q);s.attr("transform",function(w){return"translate("+w.y+","+w.x+")"});s.select("circle").attr("r",u.defaults.nodeRadius).style("fill",function(w){return w._children?"lightsteelblue":"#fff"});s.select("text").style("fill-opacity",1).style("font-size",v).text(function(w){return w.name});var t=p.exit().transition().duration(q).remove();t.select("circle").attr("r",0.000001);t.select("text").style("fill-opacity",0.000001);o.forEach(function(w){w.x0=w.x;w.y0=w.y})}});var j=Backbone.View.extend({className:"phyloviz",initialize:function(o){var n=this;n.MIN_SCALE=0.05;n.MAX_SCALE=5;n.MAX_DISPLACEMENT=500;n.margins=[10,60,10,80];n.width=$("#PhyloViz").width();n.height=$("#PhyloViz").height();n.radius=n.width;n.data=o.data;$(window).resize(function(){n.width=$("#PhyloViz").width();n.height=$("#PhyloViz").height();n.render()});n.phyloTree=new b(o.config);n.phyloTree.root=n.data;n.zoomFunc=m.behavior.zoom().scaleExtent([n.MIN_SCALE,n.MAX_SCALE]);n.zoomFunc.translate(n.phyloTree.get("translate"));n.zoomFunc.scale(n.phyloTree.get("scaleFactor"));n.navMenu=new c(n);n.settingsMenu=new i({phyloTree:n.phyloTree});n.nodeSelectionView=new e({phyloTree:n.phyloTree});n.search=new k();setTimeout(function(){n.zoomAndPan()},1000)},render:function(){var o=this;$("#PhyloViz").empty();o.mainSVG=m.select("#PhyloViz").append("svg:svg").attr("width",o.width).attr("height",o.height).attr("pointer-events","all").call(o.zoomFunc.on("zoom",function(){o.zoomAndPan()}));o.boundingRect=o.mainSVG.append("svg:rect").attr("class","boundingRect").attr("width",o.width).attr("height",o.height).attr("stroke","black").attr("fill","white");o.vis=o.mainSVG.append("svg:g").attr("class","vis");o.layoutOptions={model:o.phyloTree,width:o.width,height:o.height,vis:o.vis,margins:o.margins};$("#title").text("Phylogenetic Tree from "+o.phyloTree.get("title")+":");var n=new a(o.layoutOptions)},zoomAndPan:function(n){var t,p;if(typeof n!=="undefined"){t=n.zoom;p=n.translate}var w=this,r=w.zoomFunc.scale(),v=w.zoomFunc.translate(),s="",u="";switch(t){case"reset":r=1;v=[0,0];break;case"+":r*=1.1;break;case"-":r*=0.9;break;default:if(typeof t==="number"){r=t}else{if(m.event!==null){r=m.event.scale}}}if(r<w.MIN_SCALE||r>w.MAX_SCALE){return}w.zoomFunc.scale(r);s="translate("+w.margins[3]+","+w.margins[0]+") scale("+r+")";if(m.event!==null){u="translate("+m.event.translate+")"}else{if(typeof p!=="undefined"){var q=p.split(",")[0];var o=p.split(",")[1];if(!isNaN(q)&&!isNaN(o)){v=[v[0]+parseFloat(q),v[1]+parseFloat(o)]}}w.zoomFunc.translate(v);u="translate("+v+")"}w.phyloTree.set("scaleFactor",r);w.phyloTree.set("translate",v);w.vis.attr("transform",u+s)},reloadViz:function(){var n=this,o=$("#phylovizNexSelector :selected").val();$.getJSON(n.phyloTree.get("dataset").url(),{tree_index:o,data_type:"raw_data"},function(p){n.data=p.data;n.config=p;n.render()})}});var c=Backbone.View.extend({initialize:function(o){var n=this;n.phylovizView=o;$("#panelHeaderRightBtns").empty();$("#phyloVizNavBtns").empty();$("#phylovizNexSelector").off();n.initNavBtns();n.initRightHeaderBtns();$("#phylovizNexSelector").off().on("change",function(){n.phylovizView.reloadViz()})},initRightHeaderBtns:function(){var n=this;rightMenu=create_icon_buttons_menu([{icon_class:"gear",title:"PhyloViz Settings",on_click:function(){$("#SettingsMenu").show();n.settingsMenu.updateUI()}},{icon_class:"disk",title:"Save visualization",on_click:function(){var o=$("#phylovizNexSelector option:selected").text();if(o){n.phylovizView.phyloTree.set("title",o)}n.phylovizView.phyloTree.save()}},{icon_class:"chevron-expand",title:"Search / Edit Nodes",on_click:function(){$("#nodeSelectionView").show()}},{icon_class:"information",title:"Phyloviz Help",on_click:function(){window.open("http://wiki.g2.bx.psu.edu/Learn/Visualization/PhylogeneticTree")}}],{tooltip_config:{placement:"bottom"}});$("#panelHeaderRightBtns").append(rightMenu.$el)},initNavBtns:function(){var n=this,o=create_icon_buttons_menu([{icon_class:"zoom-in",title:"Zoom in",on_click:function(){n.phylovizView.zoomAndPan({zoom:"+"})}},{icon_class:"zoom-out",title:"Zoom out",on_click:function(){n.phylovizView.zoomAndPan({zoom:"-"})}},{icon_class:"arrow-circle",title:"Reset Zoom/Pan",on_click:function(){n.phylovizView.zoomAndPan({zoom:"reset"})}}],{tooltip_config:{placement:"bottom"}});$("#phyloVizNavBtns").append(o.$el)}});var i=l.extend({className:"Settings",initialize:function(o){var n=this;n.phyloTree=o.phyloTree;n.el=$("#SettingsMenu");n.inputs={separation:$("#phyloVizTreeSeparation"),leafHeight:$("#phyloVizTreeLeafHeight"),fontSize:$("#phyloVizTreeFontSize")};$("#settingsCloseBtn").off().on("click",function(){n.el.hide()});$("#phylovizResetSettingsBtn").off().on("click",function(){n.resetToDefaults()});$("#phylovizApplySettingsBtn").off().on("click",function(){n.apply()})},apply:function(){var n=this;if(!n.isAcceptableValue(n.inputs.separation,50,2500)||!n.isAcceptableValue(n.inputs.leafHeight,5,30)||!n.isAcceptableValue(n.inputs.fontSize,5,20)){return}$.each(n.inputs,function(o,p){n.phyloTree.set(o,p.val())})},updateUI:function(){var n=this;$.each(n.inputs,function(o,p){p.val(n.phyloTree.get(o))})},resetToDefaults:function(){$(".bs-tooltip").remove();var n=this;$.each(n.phyloTree.defaults,function(o,p){n.phyloTree.set(o,p)});n.updateUI()},render:function(){}});var e=l.extend({className:"Settings",initialize:function(o){var n=this;n.el=$("#nodeSelectionView");n.phyloTree=o.phyloTree;n.UI={enableEdit:$("#phylovizEditNodesCheck"),saveChanges:$("#phylovizNodeSaveChanges"),cancelChanges:$("#phylovizNodeCancelChanges"),name:$("#phyloVizSelectedNodeName"),dist:$("#phyloVizSelectedNodeDist"),annotation:$("#phyloVizSelectedNodeAnnotation")};n.valuesOfConcern={name:null,dist:null,annotation:null};$("#nodeSelCloseBtn").off().on("click",function(){n.el.hide()});n.UI.saveChanges.off().on("click",function(){n.updateNodes()});n.UI.cancelChanges.off().on("click",function(){n.cancelChanges()});(function(p){p.fn.enable=function(q){return p(this).each(function(){if(q){p(this).removeAttr("disabled")}else{p(this).attr("disabled","disabled")}})}})(jQuery);n.UI.enableEdit.off().on("click",function(){n.toggleUI()})},toggleUI:function(){var n=this,o=n.UI.enableEdit.is(":checked");if(!o){n.cancelChanges()}$.each(n.valuesOfConcern,function(p,q){n.UI[p].enable(o)});if(o){n.UI.saveChanges.show();n.UI.cancelChanges.show()}else{n.UI.saveChanges.hide();n.UI.cancelChanges.hide()}},cancelChanges:function(){var n=this,o=n.phyloTree.get("selectedNode");if(o){$.each(n.valuesOfConcern,function(p,q){n.UI[p].val(o[p])})}},updateNodes:function(){var n=this,o=n.phyloTree.get("selectedNode");if(o){if(!n.isAcceptableValue(n.UI.dist,0,1)||n.hasIllegalJsonCharacters(n.UI.name)||n.hasIllegalJsonCharacters(n.UI.annotation)){return}$.each(n.valuesOfConcern,function(p,q){(o[p])=n.UI[p].val()});n.phyloTree.set("nodeAttrChangedTime",new Date())}else{alert("No node selected")}}});var k=l.extend({initialize:function(){var n=this;$("#phyloVizSearchBtn").on("click",function(){var p=$("#phyloVizSearchTerm"),q=$("#phyloVizSearchCondition").val().split("-"),o=q[0],r=q[1];n.hasIllegalJsonCharacters(p);if(o==="dist"){n.isAcceptableValue(p,0,1)}n.searchTree(o,r,p.val())})},searchTree:function(n,p,o){m.selectAll("g.node").classed("searchHighlight",function(r){var q=r[n];if(typeof q!=="undefined"&&q!==null){if(n==="dist"){switch(p){case"greaterEqual":return q>=+o;case"lesserEqual":return q<=+o;default:return}}else{if(n==="name"||n==="annotation"){return q.toLowerCase().indexOf(o.toLowerCase())!==-1}}}})}});return{PhylovizView:j}});
\ No newline at end of file
diff -r 137dc44f21782c771879af1febfe962a2ea9ae6a -r 82f83d00dfd419c035c76b100ec0e88a10bb900c static/scripts/viz/phyloviz.js
--- a/static/scripts/viz/phyloviz.js
+++ b/static/scripts/viz/phyloviz.js
@@ -1,18 +1,18 @@
define(['libs/d3', 'viz/visualization', 'mvc/data'], function(d3, visualization_mod, data_mod) {
+/**
+ * Base class of any menus that takes in user interaction. Contains checking methods.
+ */
var UserMenuBase = Backbone.View.extend({
- /**
- * Base class of any menus that takes in user interaction. Contains checking methods.
- */
className: 'UserMenuBase',
+ /**
+ * Check if an input value is a number and falls within max min.
+ */
isAcceptableValue : function ($inputKey, min, max) {
- /**
- * Check if an input value is a number and falls within max min.
- */
- var self = this,
- value = $inputKey.val(),
+ //TODO: use better feedback than alert
+ var value = $inputKey.val(),
fieldName = $inputKey.attr("displayLabel") || $inputKey.attr("id").replace("phyloViz", "");
function isNumeric(n) {
@@ -34,12 +34,13 @@
return true;
},
+ /**
+ * Check if any user string inputs has illegal characters that json cannot accept
+ */
hasIllegalJsonCharacters : function($inputKey) {
- /**
- * Check if any user string inputs has illegal characters that json cannot accept
- */
if ($inputKey.val().search(/"|'|\\/) !== -1){
- alert("Named fields cannot contain these illegal characters: double quote(\"), single guote(\'), or back slash(\\). ");
+ alert("Named fields cannot contain these illegal characters: "
+ + "double quote(\"), single guote(\'), or back slash(\\). ");
return true;
}
return false;
@@ -47,12 +48,12 @@
});
+/**
+ * -- Custom Layout call for phyloViz to suit the needs of a phylogenetic tree.
+ * -- Specifically: 1) Nodes have a display display of (= evo dist X depth separation) from their parent
+ * 2) Nodes must appear in other after they have expand and contracted
+ */
function PhyloTreeLayout() {
- /**
- * -- Custom Layout call for phyloViz to suit the needs of a phylogenetic tree.
- * -- Specifically: 1) Nodes have a display display of (= evo dist X depth separation) from their parent
- * 2) Nodes must appear in other after they have expand and contracted
- */
var self = this,
hierarchy = d3.layout.hierarchy().sort(null).value(null),
@@ -75,9 +76,11 @@
else { layoutMode = mode; return self;}
};
- self.layoutAngle = function(angle) { // changes the layout angle of the display, which is really changing the height
+ // changes the layout angle of the display, which is really changing the height
+ self.layoutAngle = function(angle) {
if (typeof angle === "undefined"){ return height; }
- if (isNaN(angle) || angle < 0 || angle > 360) { return self; } // to use default if the user puts in strange values
+ // to use default if the user puts in strange values
+ if (isNaN(angle) || angle < 0 || angle > 360) { return self; }
else { height = angle; return self;}
};
@@ -92,19 +95,28 @@
// -- Custom method for laying out phylogeny tree in a linear fashion
self.nodes = function (d, i) {
- var _nodes = hierarchy.call(self, d, i), // self is to find the depth of all the nodes, assumes root is passed in
+ //TODO: newick and phyloxml return arrays. where should this go (client (here, else), server)?
+ if( toString.call( d ) === '[object Array]' ){
+ // if d is an array, replate with the first object (newick, phyloxml)
+ d = d[0];
+ }
+ // self is to find the depth of all the nodes, assumes root is passed in
+ var _nodes = hierarchy.call(self, d, i),
nodes = [],
maxDepth = 0,
numLeaves = 0;
+ //console.debug( JSON.stringify( _nodes, null, 2 ) )
+ window._d = d;
+ window._nodes = _nodes;
+ //TODO: remove dbl-touch loop
// changing from hierarchy's custom format for data to usable format
- _nodes.forEach(function (_node){
- var node = _node.data;
- node.depth = _node.depth;
+ _nodes.forEach(function (node){
maxDepth = node.depth > maxDepth ? node.depth : maxDepth; //finding max depth of tree
nodes.push(node);
});
- // counting the number of leaf nodes and assigning max depth to nodes that do not have children to flush all the leave nodes
+ // counting the number of leaf nodes and assigning max depth
+ // to nodes that do not have children to flush all the leave nodes
nodes.forEach(function(node){
if ( !node.children ) { //&& !node._children
numLeaves += 1;
@@ -120,15 +132,16 @@
};
+ /**
+ * -- Function with side effect of adding x0, y0 to all child; take in the root as starting point
+ * assuming that the leave nodes would be sorted in presented order
+ * horizontal(y0) is calculated according to (= evo dist X depth separation) from their parent
+ * vertical (x0) - if leave node: find its order in all of the leave node === node.id,
+ * then multiply by verticalSeparation
+ * - if parent node: is place in the mid point all of its children nodes
+ * -- The layout will first calculate the y0 field going towards the leaves, and x0 when returning
+ */
function layout (node, maxDepth, vertSeparation, parent) {
- /**
- * -- Function with side effect of adding x0, y0 to all child; take in the root as starting point
- * assuming that the leave nodes would be sorted in presented order
- * horizontal(y0) is calculated according to (= evo dist X depth separation) from their parent
- * vertical (x0) - if leave node: find its order in all of the leave node === node.id, then multiply by verticalSeparation
- * - if parent node: is place in the mid point all of its children nodes
- * -- The layout will first calculate the y0 field going towards the leaves, and x0 when returning
- */
var children = node.children,
sumChildVertSeparation = 0;
@@ -145,7 +158,8 @@
// if a node have no children, we will treat it as a leaf and start laying it out first
if (!children) {
- node.x0 = leafIndex++ * vertSeparation;
+ node.x0 = leafIndex * vertSeparation;
+ leafIndex += 1;
} else {
// if it has children, we will visit all its children and calculate its position from its children
children.forEach( function (child) {
@@ -189,12 +203,12 @@
root : {}, // Root has to be its own independent object because it is not part of the viz_config
+ /**
+ * Mechanism to expand or contract a single node. Expanded nodes have a children list, while for
+ * contracted nodes the list is stored in _children. Nodes with their children data stored in _children will not
+ * have their children rendered.
+ */
toggle : function (d) {
- /**
- * Mechanism to expand or contract a single node. Expanded nodes have a children list, while for
- * contracted nodes the list is stored in _children. Nodes with their children data stored in _children will not have their
- * children rendered.
- */
if(typeof d === "undefined") {return ;}
if (d.children ) {
d._children = d.children;
@@ -205,29 +219,29 @@
}
},
+ /**
+ * Contracts the phylotree to a single node by repeatedly calling itself to place all the list
+ * of children under _children.
+ */
toggleAll : function(d) {
- /**
- * Contracts the phylotree to a single node by repeatedly calling itself to place all the list
- * of children under _children.
- */
if (d.children && d.children.length !== 0) {
d.children.forEach(this.toggleAll);
toggle(d);
}
},
+ /**
+ * Return the data of the tree. Used for preserving state.
+ */
getData : function (){
- /**
- * Return the data of the tree. Used for preserving state.
- */
return this.root;
},
+ /**
+ * Overriding the default save mechanism to do some clean of circular reference of the
+ * phyloTree and to include phyloTree in the saved json
+ */
save: function() {
- /**
- * Overriding the default save mechanism to do some clean of circular reference of the
- * phyloTree and to include phyloTree in the saved json
- */
var root = this.root;
cleanTree(root);
this.set("root", root);
@@ -240,7 +254,7 @@
if (node._selected){ delete node._selected;}
if (node.children) {
- node.children.forEach(cleanTree);
+ node.children.forEach(cleanTree);
}
if (node._children) {
node._children.forEach(cleanTree);
@@ -270,26 +284,24 @@
});
-
+// -- Views --
/**
- * -- Views --
+ * Stores the default variable for setting up the visualization
*/
var PhylovizLayoutBase = Backbone.View.extend({
- /**
- * Stores the default variable for setting up the visualization
- */
defaults : {
nodeRadius : 4.5 // radius of each node in the diagram
},
+ /**
+ * Common initialization in layouts
+ */
stdInit : function (options) {
- /**
- * Common initialization in layouts
- */
var self = this;
- self.model.on("change:separation change:leafHeight change:fontSize change:nodeAttrChangedTime", self.updateAndRender, self);
+ self.model.on("change:separation change:leafHeight change:fontSize change:nodeAttrChangedTime",
+ self.updateAndRender, self);
self.vis = options.vis;
self.i = 0;
@@ -300,11 +312,11 @@
},
+ /**
+ * Updates the visualization whenever there are changes in the expansion and contraction of nodes
+ * AND possibly when the tree is edited.
+ */
updateAndRender : function(source) {
- /**
- * Updates the visualization whenever there are changes in the expansion and contraction of nodes
- * AND possibly when the tree is edited.
- */
var vis = d3.select(".vis"),
self = this;
source = source || self.model.root;
@@ -315,10 +327,10 @@
},
+ /**
+ * Renders the links for the visualization.
+ */
renderLinks : function(source) {
- /**
- * Renders the links for the visualization.
- */
var self = this;
var diagonal = self.diagonal;
var duration = self.duration;
@@ -327,15 +339,17 @@
.data(self.tree.links(self.nodes), function(d) { return d.target.id; });
var calcalateLinePos = function(d) {
- d.pos0 = d.source.y0 + " " + d.source.x0; // position of the source node <=> starting location of the line drawn
- d.pos1 = d.source.y0 + " " + d.target.x0; // position where the line makes a right angle bend
- d.pos2 = d.target.y0 + " " + d.target.x0; // point where the horizontal line becomes a dotted line
+ // position of the source node <=> starting location of the line drawn
+ d.pos0 = d.source.y0 + " " + d.source.x0;
+ // position where the line makes a right angle bend
+ d.pos1 = d.source.y0 + " " + d.target.x0;
+ // point where the horizontal line becomes a dotted line
+ d.pos2 = d.target.y0 + " " + d.target.x0;
};
var linkEnter = link.enter().insert("svg:g","g.node")
.attr("class", "completeLink");
-
linkEnter.append("svg:path")
.attr("class", "link")
.attr("d", function(d) {
@@ -357,10 +371,10 @@
// User Interaction methods below
+ /**
+ * Displays the information for editing
+ */
selectNode : function(node){
- /**
- * Displays the information for editting
- */
var self = this;
d3.selectAll("g.node")
.classed("selectedHighlight", function(d){
@@ -382,11 +396,11 @@
$("#phyloVizSelectedNodeAnnotation").val(node.annotation || "");
},
+ /**
+ * Creates bootstrap tooltip for the visualization. Has to be called repeatedly due to newly generated
+ * enterNodes
+ */
addTooltips : function (){
- /**
- * Creates bootstrap tooltip for the visualization. Has to be called repeatedly due to newly generated
- * enterNodes
- */
$(".bs-tooltip").remove(); //clean up tooltip, just in case its listeners are removed by d3
$(".node")
.attr("data-original-title", function(){
@@ -400,13 +414,11 @@
});
-
-
+/**
+ * Linea layout class of Phyloviz, is responsible for rendering the nodes
+ * calls PhyloTreeLayout to determine the positions of the nodes
+ */
var PhylovizLinearView = PhylovizLayoutBase.extend({
- /**
- * Linea layout class of Phyloviz, is responsible for rendering the nodes
- * calls PhyloTreeLayout to determine the positions of the nodes
- */
initialize : function(options){
// Default values of linear layout
var self = this;
@@ -419,23 +431,21 @@
self.updateAndRender(self.model.root);
},
+ /**
+ * Creates the basic layout of a linear tree by precalculating fixed values.
+ * One of calculations are also made here
+ */
layout : function() {
- /**
- * Creates the basic layout of a linear tree by precalculating fixed values.
- * One of calculations are also made here
- */
-
var self = this;
-
self.tree = new PhyloTreeLayout().layoutMode("Linear");
self.diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x ]; });
},
+ /**
+ * Renders the nodes base on Linear layout.
+ */
renderNodes : function (source) {
- /**
- * Renders the nodes base on Linear layout.
- */
var self = this,
fontSize = self.model.get("fontSize") + "px";
@@ -446,7 +456,9 @@
nodes = self.tree.separation(self.model.get("separation")).nodes(self.model.root);
var node = self.vis.selectAll("g.node")
- .data(nodes, function(d) { return d.name + d.id || (d.id = ++self.i); });
+ .data(nodes, function(d) {
+ return d.name + d.id || (d.id = ++self.i);
+ });
// These variables has to be passed into update links which are in the base methods
self.nodes = nodes;
@@ -466,7 +478,12 @@
self.updateAndRender(d); // re-render the tree
}
});
-
+ console.debug( 'source:', source )
+ //TODO: newick and phyloxml return arrays. where should this go (client (here, else), server)?
+ if( toString.call( source ) === '[object Array]' ){
+ // if d is an array, replate with the first object (newick, phyloxml)
+ source = source[0];
+ }
nodeEnter.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; });
nodeEnter.append("svg:circle")
@@ -557,8 +574,8 @@
self.nodeSelectionView = new NodeSelectionView({phyloTree : self.phyloTree});
self.search = new PhyloVizSearch();
-
- setTimeout(function(){ // using settimeout to call the zoomAndPan function according to the stored attributes in viz_config
+ // using settimeout to call the zoomAndPan function according to the stored attributes in viz_config
+ setTimeout(function(){
self.zoomAndPan();
}, 1000);
},
@@ -603,11 +620,11 @@
var linearView = new PhylovizLinearView(self.layoutOptions);
},
+ /**
+ * Function to zoom and pan the svg element which the entire tree is contained within
+ * Uses d3.zoom events, and extend them to allow manual updates and keeping states in model
+ */
zoomAndPan : function(event){
- /**
- * Function to zoom and pan the svg element which the entire tree is contained within
- * Uses d3.zoom events, and extend them to allow manual updates and keeping states in model
- */
var zoomParams,
translateParams;
if (typeof event !== "undefined") {
@@ -659,21 +676,26 @@
self.phyloTree.set("scaleFactor", scaleFactor);
self.phyloTree.set("translate", translationCoor);
- self.vis.attr("transform", translateStatement + zoomStatement); //refers to the view that we are actually zooming
+ //refers to the view that we are actually zooming
+ self.vis.attr("transform", translateStatement + zoomStatement);
},
+ /**
+ * Primes the Ajax URL to load another Nexus tree
+ */
reloadViz : function() {
- /**
- * Primes the Ajax URL to load another Nexus tree
- */
var self = this,
treeIndex = $("#phylovizNexSelector :selected").val();
- $.getJSON(self.phyloTree.get("dataset").url(), { tree_index: treeIndex, data_type: 'raw_data' }, function(packedJson){
- self.data = packedJson.data;
- self.config = packedJson;
- self.render();
- });
+ $.getJSON(self.phyloTree.get("dataset").url(), {
+ tree_index: treeIndex,
+ data_type: 'raw_data'
+ },
+ function(packedJson){
+ self.data = packedJson.data;
+ self.config = packedJson;
+ self.render();
+ });
}
});
@@ -768,10 +790,10 @@
$("#phylovizApplySettingsBtn").off().on("click", function() { self.apply(); });
},
+ /**
+ * Applying user values to phylotree model.
+ */
apply : function(){
- /**
- * Applying user values to phylotree model.
- */
var self = this;
if (!self.isAcceptableValue(self.inputs.separation, 50, 2500) ||
!self.isAcceptableValue(self.inputs.leafHeight, 5, 30) ||
@@ -782,19 +804,19 @@
self.phyloTree.set(key, $input.val());
});
},
+ /**
+ * Called to update the values input to that stored in the model
+ */
updateUI : function(){
- /**
- * Called to update the values input to that stored in the model
- */
var self = this;
$.each(self.inputs, function(key, $input){
$input.val(self.phyloTree.get(key));
});
},
+ /**
+ * Resets the value of the phyloTree model to its default
+ */
resetToDefaults : function(){
- /**
- * Resets the value of the phyloTree model to its default
- */
$(".bs-tooltip").remove(); // just in case the tool tip was not removed
var self = this;
$.each(self.phyloTree.defaults, function(key, value) {
@@ -810,10 +832,11 @@
});
+/**
+ * View for inspecting node properties and editing them
+ */
var NodeSelectionView = UserMenuBase.extend({
- /**
- * View for inspecting node properties and editing them
- */
+
className: 'Settings',
initialize : function (options){
@@ -830,11 +853,12 @@
annotation : $("#phyloVizSelectedNodeAnnotation")
};
+ // temporarily stores the values in case user change their mind
self.valuesOfConcern = {
name : null,
dist : null,
annotation : null
- }; // temporarily stores the values in case user change their mind
+ };
//init UI buttons
$("#nodeSelCloseBtn").off().on("click", function() { self.el.hide(); });
@@ -859,10 +883,10 @@
});
},
+ /**
+ * For turning on and off the child elements
+ */
toggleUI : function(){
- /**
- * For turning on and off the child elements
- */
var self = this,
checked = self.UI.enableEdit.is(':checked');
@@ -881,10 +905,10 @@
},
+ /**
+ * Reverting to previous values in case user change their minds
+ */
cancelChanges : function() {
- /**
- * Reverting to previous values in case user change their minds
- */
var self = this,
node = self.phyloTree.get("selectedNode");
if (node){
@@ -894,10 +918,10 @@
}
},
+ /**
+ * Changing the data in the underlying tree with user-specified values
+ */
updateNodes : function (){
- /**
- * Changing the data in the underlying tree with user-specified values
- */
var self = this,
node = self.phyloTree.get("selectedNode");
if (node){
@@ -914,17 +938,15 @@
alert("No node selected");
}
}
-
-
});
+/**
+ * Initializes the search panel on phyloviz and handles its user interaction
+ * It allows user to search the entire free based on some qualifer, like dist <= val.
+ */
var PhyloVizSearch = UserMenuBase.extend({
- /**
- * Initializes the search panel on phyloviz and handles its user interaction
- * It allows user to search the entire free based on some qualifer, like dist <= val.
- */
initialize : function () {
var self = this;
@@ -942,10 +964,10 @@
});
},
+ /**
+ * Searches the entire tree and will highlight the nodes that match the condition in green
+ */
searchTree : function (attr, condition, val){
- /**
- * Searches the entire tree and will highlight the nodes that match the condition in green
- */
d3.selectAll("g.node")
.classed("searchHighlight", function(d){
var attrVal = d[attr];
@@ -972,4 +994,4 @@
PhylovizView: PhylovizView
};
-});
\ No newline at end of file
+});
diff -r 137dc44f21782c771879af1febfe962a2ea9ae6a -r 82f83d00dfd419c035c76b100ec0e88a10bb900c templates/webapps/galaxy/visualization/phyloviz.mako
--- a/templates/webapps/galaxy/visualization/phyloviz.mako
+++ b/templates/webapps/galaxy/visualization/phyloviz.mako
@@ -81,7 +81,7 @@
position: fixed;
## Borrowed from galaxy modal_dialogues
- background-color: white;
+ background-color: white;
border: 1px solid #999;
border: 1px solid rgba(0, 0, 0, 0.3);
-webkit-border-radius: 6px;
@@ -157,9 +157,9 @@
// -- Initialization code |-->
phyloviz = new phyloviz_mod.PhylovizView({
- data: data,
- layout : "Linear",
- config : config
+ data : data,
+ layout : "Linear",
+ config : config
});
// -- Render viz. --
@@ -169,7 +169,9 @@
$(function firstVizLoad(){ // calls when viz is loaded for the first time
var config = JSON.parse( '${ h.to_json_string( config )}');
+ window.config = config;
var data = JSON.parse('${h.to_json_string(data)}');
+ window.data = data;
initPhyloViz(data, config);
});
});
@@ -189,7 +191,6 @@
<div style="clear: both"></div></div>
-
<div id="phyloVizNavContainer"><div id="phyloVizNav">
%if config["ext"] == "nex" and not config["saved_visualization"]:
@@ -208,10 +209,7 @@
<div class="navControl"><p> | Alt+click to select nodes</p></div>
-
-
</div>
-
</div>
## Node Selection Menu
@@ -284,11 +282,6 @@
</div></div>
-
-
-
-
-
<div class="Panel" id="FloatingMenu" style="display: None;"><h2>PhyloViz (<a onclick="displayHelp()" href="javascript:void(0);">?</a>)</h2>
@@ -300,14 +293,12 @@
<div class="hint">4. Minimap: Currently displays an exact but scaled down replicate of the tree, orange bounding box is correct for linear only<br/>
Can be switched on or off</div><div class="hint">5. Changing Layouts: Able to change between circular and linear layouts.</div>
-
</div><h5>Scaling & Rotation:</h5><button id="phylovizZoomInBtn" class="" > + </button><button id="phylovizZoomOutBtn" class="" > - </button>
-
<h5>Translation:</h5><button id="phylovizTranslateUpBtn" > Up </button><button id="phylovizTranslateDownBtn" > Down </button>
@@ -315,8 +306,6 @@
<button id="phylovizTranslateLeftBtn" > Left </button><button id="phylovizTranslateRightBtn" > Right </button>
-
-
<h5>Others:</h5><button id="phylovizResetBtn" > Reset Zoom/Translate </button><button id="phylovizSaveBtn" > Save vizualization </button>
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.
1
0