diff --git a/gotrack/etc/scripts/update/resources.py b/gotrack/etc/scripts/update/resources.py index 080fe11..74b5d42 100755 --- a/gotrack/etc/scripts/update/resources.py +++ b/gotrack/etc/scripts/update/resources.py @@ -42,7 +42,6 @@ def __init__(self, directory, database_state, check_ftp=True): self.missing_go = {} self.missing_goa = defaultdict(dict) self.ftp_checked = False - self.missing_data = False if check_ftp: self.populate_missing_data() @@ -80,7 +79,6 @@ def populate_missing_data(self): self.missing_go = {} self.missing_goa = defaultdict(dict) self.ftp_checked = False - self.missing_data = False go = self.fetch_go_dates() self.missing_go = {d: f for d, f in go.iteritems() if d not in self.go and d not in self.db_go} @@ -91,11 +89,11 @@ def populate_missing_data(self): missing = {ed: f for ed, f in goa.iteritems() if ed not in self.goa[sp] and ed not in self.db_goa[sp_id]} self.missing_goa[sp] = missing - if self.missing_go or sum([len(goa_sp) for goa_sp in self.missing_goa.values()]) or not self.sec_ac: - self.missing_data = True - self.ftp_checked = True + def is_missing_data(self): + return self.missing_go or sum([len(goa_sp) for goa_sp in self.missing_goa.values()]) or not self.sec_ac + @staticmethod def match_file_patterns(files, pattern): matches = [] @@ -168,7 +166,7 @@ def ftp_list(host, directory): if ftp is not None: ftp.close() - def ftp_files(self, host, directory, files): + def ftp_files(self, host, directory, files, skip_if_exists=True): ftp = None fname_list = [] if files: @@ -188,7 +186,7 @@ def ftp_files(self, host, directory, files): ftp.login() ftp.cwd(directory) full_path = os.path.join(self.directory, fname) - if os.path.isfile(full_path): + if skip_if_exists and os.path.isfile(full_path): log.warn('%s already exists, skipping...', full_path) continue @@ -223,20 +221,23 @@ def fetch_go_dates(self): files = Resources.ftp_list(Resources.go_ftp_host, Resources.go_ftp_directory) return self.search_files_for_go(files) - def download_missing_goa_data(self): + def download_missing_goa_data(self, skip_if_exists=True): for sp, goa_eds in self.missing_goa.iteritems(): files = goa_eds.values() - self.ftp_files(Resources.goa_ftp_host, Resources.goa_ftp_directory_template.format(sp.upper()), files) + self.ftp_files(Resources.goa_ftp_host, Resources.goa_ftp_directory_template.format(sp.upper()), files, + skip_if_exists) # GPI Files gpi_files = [Resources.goa_gpi_template.format(sp, ed) for ed in goa_eds] - self.ftp_files(Resources.goa_ftp_host, Resources.goa_ftp_directory_template.format(sp.upper()), gpi_files) + self.ftp_files(Resources.goa_ftp_host, Resources.goa_ftp_directory_template.format(sp.upper()), gpi_files, + skip_if_exists) - def download_missing_go_data(self): - self.ftp_files(Resources.go_ftp_host, Resources.go_ftp_directory, self.missing_go.values()) + def download_missing_go_data(self, skip_if_exists=True): + self.ftp_files(Resources.go_ftp_host, Resources.go_ftp_directory, self.missing_go.values(), skip_if_exists) - def download_accession_history(self): - return self.ftp_files(Resources.uniprot_ftp_host, Resources.uniprot_ftp_directory, ['sec_ac.txt']) + def download_accession_history(self, skip_if_exists=True): + return self.ftp_files(Resources.uniprot_ftp_host, Resources.uniprot_ftp_directory, ['sec_ac.txt'], + skip_if_exists) def get_new_go(self): return {d: f for d, f in self.go.iteritems() if d not in self.db_go} diff --git a/gotrack/etc/scripts/update/update.py b/gotrack/etc/scripts/update/update.py index 4504a5f..47f4376 100755 --- a/gotrack/etc/scripts/update/update.py +++ b/gotrack/etc/scripts/update/update.py @@ -47,8 +47,11 @@ def main(resource_directory=None, cron=False, no_download=False): # Display current state of resource directory, database, and ftp site LOG.info(res) + # if cron, force download of accession history file + res.sec_ac = None if cron else res.sec_ac + # Deal with missing data - if res.ftp_checked and res.missing_data: + if res.ftp_checked and res.is_missing_data(): missing_cnt = len(res.missing_go) if missing_cnt: LOG.warn("Missing %s GO Versions from FTP", missing_cnt) @@ -64,14 +67,14 @@ def main(resource_directory=None, cron=False, no_download=False): if not res.sec_ac: LOG.warn("Missing secondary accession file (sec_ac.txt)") if cron or query_yes_no("Download missing secondary accession file?"): - res.download_accession_history() + res.download_accession_history(skip_if_exists=not cron) LOG.info("Re-checking state of resource directory") res.populate_existing_files() res.populate_missing_data() LOG.info(res) - if res.missing_data or not (cron or query_yes_no("Continue with updates?")): + if res.is_missing_data() or not (cron or query_yes_no("Continue with updates?")): return # Insert new GO data diff --git a/gotrack/pom.xml b/gotrack/pom.xml index bead0cf..80d7f98 100644 --- a/gotrack/pom.xml +++ b/gotrack/pom.xml @@ -4,7 +4,7 @@ ubc.pavlab gotrack war - 1.0 + 1.1 gotrack http://maven.apache.org @@ -321,7 +321,7 @@ com.amashchenko.maven.plugin gitflow-maven-plugin - 1.6.0 + 1.9.0 false diff --git a/gotrack/src/main/java/ubc/pavlab/gotrack/beans/Cache.java b/gotrack/src/main/java/ubc/pavlab/gotrack/beans/Cache.java index cf06d3a..a50fc0f 100644 --- a/gotrack/src/main/java/ubc/pavlab/gotrack/beans/Cache.java +++ b/gotrack/src/main/java/ubc/pavlab/gotrack/beans/Cache.java @@ -112,7 +112,7 @@ public class Cache implements Serializable { private Map accessionToGene = new ConcurrentHashMap<>(); // Useful derived constants - private ImmutableSet availableYears; + private ImmutableList availableYears; // These are used for autocompletion // ********************************* @@ -218,7 +218,7 @@ public AnnotationType[] getAnnotationTypes() { return AnnotationType.values(); } - public ImmutableSet getAvailableYears() { + public ImmutableList getAvailableYears() { return availableYears; } @@ -293,7 +293,7 @@ private void createEditions( CacheDAO cacheDAO ) { } // Populate derived constants - ImmutableSet.Builder availableYearsBuilder = ImmutableSet.builder(); + Set availableYearsBuilder = Sets.newHashSet(); // Create Edition objects for ( EditionDTO dto : cacheDAO.getAllEditions( speciesRestrictions ) ) { @@ -349,7 +349,12 @@ private void createEditions( CacheDAO cacheDAO ) { } } - availableYears = availableYearsBuilder.build(); + List sortedYears = Lists.newArrayList(availableYearsBuilder); + Collections.sort(sortedYears); + + availableYears = ImmutableList.copyOf( sortedYears ); + + // ImmutableSet.Builder availableYearsBuilder = ImmutableSet.builder(); currentGOEdition = Collections.max( allGOEditions.values() ); diff --git a/gotrack/src/main/java/ubc/pavlab/gotrack/beans/EnrichmentView.java b/gotrack/src/main/java/ubc/pavlab/gotrack/beans/EnrichmentView.java index 4d4d325..94f960d 100644 --- a/gotrack/src/main/java/ubc/pavlab/gotrack/beans/EnrichmentView.java +++ b/gotrack/src/main/java/ubc/pavlab/gotrack/beans/EnrichmentView.java @@ -110,6 +110,9 @@ public String getLabel() { @Inject private EnrichmentService enrichmentService; + @Inject + private SessionManager session; + // View parameters private Gene queryGene; // LEE_LIVER_CANCER @@ -217,7 +220,7 @@ public EnrichmentView() { @PostConstruct public void postConstruct() { log.info( "postConstruct" ); - currentSpecies = cache.getSpecies( 7 ); + currentSpecies = session.getSpecies(); for ( Species species : cache.getSpeciesList() ) { speciesToSelectedGenes.put( currentSpecies, Lists.newArrayList() ); diff --git a/gotrack/src/main/java/ubc/pavlab/gotrack/beans/SessionManager.java b/gotrack/src/main/java/ubc/pavlab/gotrack/beans/SessionManager.java index e161a43..5c4dbf2 100644 --- a/gotrack/src/main/java/ubc/pavlab/gotrack/beans/SessionManager.java +++ b/gotrack/src/main/java/ubc/pavlab/gotrack/beans/SessionManager.java @@ -63,6 +63,9 @@ public void init() { // You can do here your initialization thing based on managed properties, if necessary. log.info( "SessionManager init" ); species = cache.getSpecies( 7 ); + if ( species == null) { + species = cache.getSpeciesList().iterator().next(); + } } @PreDestroy diff --git a/gotrack/src/main/java/ubc/pavlab/gotrack/beans/Trends.java b/gotrack/src/main/java/ubc/pavlab/gotrack/beans/Trends.java index d6b84ba..5a7497a 100644 --- a/gotrack/src/main/java/ubc/pavlab/gotrack/beans/Trends.java +++ b/gotrack/src/main/java/ubc/pavlab/gotrack/beans/Trends.java @@ -130,6 +130,7 @@ public void postConstruct() { } public void loadCharts( Species species ) { + RequestContext.getCurrentInstance().addCallbackParam( "species", species ); RequestContext.getCurrentInstance().addCallbackParam( "HC_map", allChartsJSON.get( species ) ); } diff --git a/gotrack/src/main/java/ubc/pavlab/gotrack/dao/AnnotationDAOImpl.java b/gotrack/src/main/java/ubc/pavlab/gotrack/dao/AnnotationDAOImpl.java index 7ae5d69..9da562b 100644 --- a/gotrack/src/main/java/ubc/pavlab/gotrack/dao/AnnotationDAOImpl.java +++ b/gotrack/src/main/java/ubc/pavlab/gotrack/dao/AnnotationDAOImpl.java @@ -27,19 +27,14 @@ import ubc.pavlab.gotrack.model.dto.*; import ubc.pavlab.gotrack.utilities.Tuples; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; +import java.sql.*; import java.util.ArrayList; -import java.sql.Date; import java.util.List; import java.util.Set; import static ubc.pavlab.gotrack.dao.DAOUtil.close; /** - * * @author mjacobson */ public class AnnotationDAOImpl implements AnnotationDAO { @@ -56,25 +51,24 @@ public class AnnotationDAOImpl implements AnnotationDAO { // Get information from single gene, should be fast < 0.2s // species, symbol,species - private static final String SQL_FULL_ANNOTATION_RANGE_EDITIONS_SINGLE_GENE = "select distinct edition, go_id, qualifier, evidence, reference from " + SQL_ACCESSION + " acc " + "inner join " + SQL_ACCESSION_HISTORY + " ppah on acc.db_object_id = ppah.sec " + "inner join " + SQL_ANNOTATION + " ann on acc.id=ann.accession_id " + - "where ppah.ac = ? AND edition between ? and ? " + + "where ppah.ac = ? AND species_id= ? AND edition between ? and ? " + "order by edition"; // Get information from multiple genes for running enrichment, should be quite fast and scale sublinearly private static final String SQL_SIMPLE_ANNOTATION_RANGE_EDITIONS_MULTIPLE_GENES = "select distinct edition, go_id, ac from " + SQL_ACCESSION + " acc " + "inner join " + SQL_ACCESSION_HISTORY + " ppah on acc.db_object_id = ppah.sec " + "inner join " + SQL_ANNOTATION + " ann on acc.id=ann.accession_id " + - "where ppah.ac in (%s) AND edition between ? and ? " + + "where ppah.ac in (%s) AND species_id= ? AND edition between ? and ? " + "order by NULL"; // Get information from multiple genes for running enrichment in a single edition, should be extremely fast private static final String SQL_SIMPLE_ANNOTATION_SINGLE_EDITION_MULTIPLE_GENES = "select distinct go_id, ac from " + SQL_ACCESSION + " acc " + "inner join " + SQL_ACCESSION_HISTORY + " ppah on acc.db_object_id = ppah.sec " + "inner join " + SQL_ANNOTATION + " ann on acc.id=ann.accession_id " + - "where ppah.ac in (%s) AND edition = ? " + + "where ppah.ac in (%s) AND species_id= ? AND edition = ? " + "order by NULL"; // Collect evidence breakdown for a specific term, should be not horribly slow, try and keep under 5s for slowest queries (ones for root level terms) @@ -106,7 +100,7 @@ public class AnnotationDAOImpl implements AnnotationDAO { /** * Construct an User DAO for the given DAOFactory. Package private so that it can be constructed inside the DAO * package only. - * + * * @param daoFactory The DAOFactory to construct this User DAO for. */ AnnotationDAOImpl( DAOFactory daoFactory ) { @@ -121,6 +115,7 @@ public List fullAnnotationRangeEditions( Gene g, Integer minimum, List params = new ArrayList<>(); params.add( g.getAccession().getAccession() ); + params.add( g.getSpecies().getId() ); // See Issue #32 params.add( minimum ); params.add( maximum ); @@ -138,7 +133,7 @@ public List fullAnnotationRangeEditions( Gene g, Integer minimum, long startTime = System.currentTimeMillis(); connection = daoFactory.getConnection(); long endTime = System.currentTimeMillis(); - log.debug( "daoFactory.getConnection(): " + ( endTime - startTime ) + "ms" ); + log.debug( "daoFactory.getConnection(): " + (endTime - startTime) + "ms" ); statement = connection.prepareStatement( sql ); DAOUtil.setValues( statement, params.toArray() ); @@ -147,16 +142,16 @@ public List fullAnnotationRangeEditions( Gene g, Integer minimum, startTime = System.currentTimeMillis(); resultSet = statement.executeQuery(); endTime = System.currentTimeMillis(); - log.debug( "statement.executeQuery(): " + ( endTime - startTime ) + "ms" ); + log.debug( "statement.executeQuery(): " + (endTime - startTime) + "ms" ); startTime = System.currentTimeMillis(); - while ( resultSet.next() ) { + while (resultSet.next()) { results.add( new AnnotationDTO( resultSet.getInt( 1 ), resultSet.getString( 2 ), resultSet.getString( 3 ), resultSet.getString( 4 ), resultSet.getString( 5 ) ) ); } endTime = System.currentTimeMillis(); - log.debug( "while ( resultSet.next() ): " + ( endTime - startTime ) + "ms" ); - } catch ( SQLException e ) { + log.debug( "while ( resultSet.next() ): " + (endTime - startTime) + "ms" ); + } catch (SQLException e) { throw new DAOException( e ); } finally { close( connection, statement, resultSet ); @@ -172,6 +167,8 @@ public List simpleAnnotationRangeEditions( Set genes, Integ return Lists.newArrayList(); } + Species species = genes.iterator().next().getSpecies(); + List params = Lists.newArrayList(); String sql = String.format( SQL_SIMPLE_ANNOTATION_RANGE_EDITIONS_MULTIPLE_GENES, DAOUtil.preparePlaceHolders( genes.size() ) ); @@ -180,6 +177,8 @@ public List simpleAnnotationRangeEditions( Set genes, Integ params.add( g.getAccession().getAccession() ); } + + params.add( species.getId() ); // See Issue #32 params.add( minEdition ); params.add( maxEdition ); @@ -196,7 +195,7 @@ public List simpleAnnotationRangeEditions( Set genes, Integ long startTime = System.currentTimeMillis(); connection = daoFactory.getConnection(); long endTime = System.currentTimeMillis(); - log.debug( "daoFactory.getConnection(): " + ( endTime - startTime ) + "ms" ); + log.debug( "daoFactory.getConnection(): " + (endTime - startTime) + "ms" ); statement = connection.prepareStatement( sql ); DAOUtil.setValues( statement, params.toArray() ); @@ -205,17 +204,17 @@ public List simpleAnnotationRangeEditions( Set genes, Integ startTime = System.currentTimeMillis(); resultSet = statement.executeQuery(); endTime = System.currentTimeMillis(); - log.debug( "statement.executeQuery(): " + ( endTime - startTime ) + "ms" ); + log.debug( "statement.executeQuery(): " + (endTime - startTime) + "ms" ); startTime = System.currentTimeMillis(); - while ( resultSet.next() ) { + while (resultSet.next()) { results.add( enrichmentMap( resultSet ) ); } endTime = System.currentTimeMillis(); - log.debug( "while ( resultSet.next() ): " + ( endTime - startTime ) + "ms" ); - } catch ( SQLException e ) { + log.debug( "while ( resultSet.next() ): " + (endTime - startTime) + "ms" ); + } catch (SQLException e) { throw new DAOException( e ); } finally { close( connection, statement, resultSet ); @@ -231,6 +230,8 @@ public List simpleAnnotationSingleEdition( Edition ed, Set< return Lists.newArrayList(); } + Species species = genes.iterator().next().getSpecies(); + List params = new ArrayList(); String sql = String.format( SQL_SIMPLE_ANNOTATION_SINGLE_EDITION_MULTIPLE_GENES, DAOUtil.preparePlaceHolders( genes.size() ) ); @@ -239,6 +240,7 @@ public List simpleAnnotationSingleEdition( Edition ed, Set< params.add( g.getAccession().getAccession() ); } + params.add( species.getId() ); // See Issue #32 params.add( ed.getEdition() ); Connection connection = null; @@ -254,7 +256,7 @@ public List simpleAnnotationSingleEdition( Edition ed, Set< long startTime = System.currentTimeMillis(); connection = daoFactory.getConnection(); long endTime = System.currentTimeMillis(); - log.debug( "daoFactory.getConnection(): " + ( endTime - startTime ) + "ms" ); + log.debug( "daoFactory.getConnection(): " + (endTime - startTime) + "ms" ); statement = connection.prepareStatement( sql ); DAOUtil.setValues( statement, params.toArray() ); @@ -263,17 +265,17 @@ public List simpleAnnotationSingleEdition( Edition ed, Set< startTime = System.currentTimeMillis(); resultSet = statement.executeQuery(); endTime = System.currentTimeMillis(); - log.debug( "statement.executeQuery(): " + ( endTime - startTime ) + "ms" ); + log.debug( "statement.executeQuery(): " + (endTime - startTime) + "ms" ); startTime = System.currentTimeMillis(); - while ( resultSet.next() ) { + while (resultSet.next()) { results.add( simpleEnrichmentMap( resultSet ) ); } endTime = System.currentTimeMillis(); - log.debug( "while ( resultSet.next() ): " + ( endTime - startTime ) + "ms" ); - } catch ( SQLException e ) { + log.debug( "while ( resultSet.next() ): " + (endTime - startTime) + "ms" ); + } catch (SQLException e) { throw new DAOException( e ); } finally { close( connection, statement, resultSet ); @@ -283,7 +285,7 @@ public List simpleAnnotationSingleEdition( Edition ed, Set< } @Override - public List categoryCountsRangeDates( String goId, Date min, Date max ) throws DAOException { + public List categoryCountsRangeDates( String goId, Date min, Date max ) throws DAOException { // TODO This method of collecting the data is not robust, // If editions across species in the same 'release' are have slightly differing dates, // they will not be grouped appropriately @@ -313,7 +315,7 @@ public List categoryCountsRangeDates( String goId, Date min, D long startTime = System.currentTimeMillis(); connection = daoFactory.getConnection(); long endTime = System.currentTimeMillis(); - log.debug( "daoFactory.getConnection(): " + ( endTime - startTime ) + "ms" ); + log.debug( "daoFactory.getConnection(): " + (endTime - startTime) + "ms" ); statement = connection.prepareStatement( sql ); DAOUtil.setValues( statement, params.toArray() ); @@ -322,16 +324,16 @@ public List categoryCountsRangeDates( String goId, Date min, D startTime = System.currentTimeMillis(); resultSet = statement.executeQuery(); endTime = System.currentTimeMillis(); - log.debug( "statement.executeQuery(): " + ( endTime - startTime ) + "ms" ); + log.debug( "statement.executeQuery(): " + (endTime - startTime) + "ms" ); startTime = System.currentTimeMillis(); - while ( resultSet.next() ) { + while (resultSet.next()) { results.add( new CategoryCountDTO( resultSet.getDate( "date" ), resultSet.getString( "category" ), resultSet.getInt( "count" ) ) ); } endTime = System.currentTimeMillis(); - log.debug( "while ( resultSet.next() ): " + ( endTime - startTime ) + "ms" ); - } catch ( SQLException e ) { + log.debug( "while ( resultSet.next() ): " + (endTime - startTime) + "ms" ); + } catch (SQLException e) { throw new DAOException( e ); } finally { close( connection, statement, resultSet ); @@ -366,7 +368,7 @@ public List directGeneCountsAllEditions( String goId ) long startTime = System.currentTimeMillis(); connection = daoFactory.getConnection(); long endTime = System.currentTimeMillis(); - log.debug( "daoFactory.getConnection(): " + ( endTime - startTime ) + "ms" ); + log.debug( "daoFactory.getConnection(): " + (endTime - startTime) + "ms" ); statement = connection.prepareStatement( sql ); DAOUtil.setValues( statement, params.toArray() ); @@ -375,16 +377,16 @@ public List directGeneCountsAllEditions( String goId ) startTime = System.currentTimeMillis(); resultSet = statement.executeQuery(); endTime = System.currentTimeMillis(); - log.debug( "statement.executeQuery(): " + ( endTime - startTime ) + "ms" ); + log.debug( "statement.executeQuery(): " + (endTime - startTime) + "ms" ); startTime = System.currentTimeMillis(); - while ( resultSet.next() ) { + while (resultSet.next()) { results.add( new DirectAnnotationCountDTO( resultSet.getInt( "species_id" ), resultSet.getInt( "edition" ), "", resultSet.getInt( "count" ) ) ); } endTime = System.currentTimeMillis(); - log.debug( "while ( resultSet.next() ): " + ( endTime - startTime ) + "ms" ); - } catch ( SQLException e ) { + log.debug( "while ( resultSet.next() ): " + (endTime - startTime) + "ms" ); + } catch (SQLException e) { throw new DAOException( e ); } finally { close( connection, statement, resultSet ); @@ -394,7 +396,7 @@ public List directGeneCountsAllEditions( String goId ) } @Override - public List> simpleAnnotationSingleEditionCompleteSpecies( Species species, Edition edition ) throws DAOException { + public List> simpleAnnotationSingleEditionCompleteSpecies( Species species, Edition edition ) throws DAOException { List params = new ArrayList<>(); @@ -405,7 +407,7 @@ public List> simpleAnnotationSingleEditionCompleteS PreparedStatement statement = null; ResultSet resultSet = null; - List> results = new ArrayList<>(); + List> results = new ArrayList<>(); String sql = SQL_SIMPLE_ANNOTATION_SINGLE_EDITION; log.debug( sql ); @@ -415,7 +417,7 @@ public List> simpleAnnotationSingleEditionCompleteS long startTime = System.currentTimeMillis(); connection = daoFactory.getConnection(); long endTime = System.currentTimeMillis(); - log.debug( "daoFactory.getConnection(): " + ( endTime - startTime ) + "ms" ); + log.debug( "daoFactory.getConnection(): " + (endTime - startTime) + "ms" ); statement = connection.prepareStatement( sql ); DAOUtil.setValues( statement, params.toArray() ); @@ -424,15 +426,15 @@ public List> simpleAnnotationSingleEditionCompleteS startTime = System.currentTimeMillis(); resultSet = statement.executeQuery(); endTime = System.currentTimeMillis(); - log.debug( "statement.executeQuery(): " + ( endTime - startTime ) + "ms" ); + log.debug( "statement.executeQuery(): " + (endTime - startTime) + "ms" ); startTime = System.currentTimeMillis(); - while ( resultSet.next() ) { + while (resultSet.next()) { results.add( new Tuples.Tuple2<>( resultSet.getString( "ac" ), resultSet.getString( "go_id" ) ) ); } endTime = System.currentTimeMillis(); - log.debug( "while ( resultSet.next() ): " + ( endTime - startTime ) + "ms" ); - } catch ( SQLException e ) { + log.debug( "while ( resultSet.next() ): " + (endTime - startTime) + "ms" ); + } catch (SQLException e) { throw new DAOException( e ); } finally { close( connection, statement, resultSet ); diff --git a/gotrack/src/main/java/ubc/pavlab/gotrack/model/visualization/Graph.java b/gotrack/src/main/java/ubc/pavlab/gotrack/model/visualization/Graph.java index bb4a312..fee9af0 100644 --- a/gotrack/src/main/java/ubc/pavlab/gotrack/model/visualization/Graph.java +++ b/gotrack/src/main/java/ubc/pavlab/gotrack/model/visualization/Graph.java @@ -20,8 +20,8 @@ package ubc.pavlab.gotrack.model.visualization; import com.google.common.collect.Maps; -import org.json.JSONArray; -import org.json.JSONObject; +import com.google.gson.Gson; +import com.google.gson.JsonObject; import ubc.pavlab.gotrack.model.go.GeneOntologyTerm; import ubc.pavlab.gotrack.model.go.Relation; @@ -190,9 +190,10 @@ public Collection getEdges() { public String getJsonString() { - JSONObject jsonObject = new JSONObject(); - jsonObject.put( "nodes", new JSONArray(this.getNodes()) ); - jsonObject.put( "edges", new JSONArray(this.getEdges()) ); - return jsonObject.toString(); + Gson gson = new Gson(); + JsonObject obj = new JsonObject(); + obj.add( "nodes", gson.toJsonTree( this.nodes.values() ) ); + obj.add( "edges", gson.toJsonTree( this.edges ) ); + return gson.toJson(obj); } } diff --git a/gotrack/src/main/webapp/genes.xhtml b/gotrack/src/main/webapp/genes.xhtml index a4c5fc6..9541f80 100644 --- a/gotrack/src/main/webapp/genes.xhtml +++ b/gotrack/src/main/webapp/genes.xhtml @@ -27,10 +27,10 @@ - + - + @@ -80,31 +80,36 @@ - - + + - + - - + - + - + - + @@ -116,7 +121,8 @@ - + @@ -146,12 +152,13 @@ - + - - + + @@ -323,7 +330,7 @@ width="800px;" style="max-width:80%;max-height:80%;" closeOnEscape="true" - > + > @@ -349,40 +356,75 @@ widgetVar="viewAnnotationsDlgWdg" modal="false" showEffect="fade" hideEffect="fade" width="900" fitViewport="true" closeOnEscape="true"> - - - + + + +
+

Description:

The - annotation plot shows distinct counts of both direct and inferred GO annotations connected to this gene. + annotation plot shows distinct counts of both direct and inferred GO annotations associated with this gene. A distinct annotation is defined as being both unique in GO Term and Evidence.

-

Direct Annotation Count: Distinct count of directly applied annotations.

+

Legend Descriptions:

+

Direct Annotation Count: Distinct count of directly applied annotations.

- Inferred Annotation Count: Distinct count of directly applied annotations as well as their GO ancestors. + Inferred Annotation Count: Distinct count of directly applied annotations as well as their GO ancestors. Example: A gene directly annotated with directional locomotion is also implicitly annotated with its parents (locomotion).

-

Click on the graph to bring up options to view existing, newly added, or - newly removed terms at that timepoint.

+

Controls:

+

<Click> any edition to view the annotations at that point in time in the right panel.

+

<Ctrl/Command> + <Click> any edition to compare the annotations at that point in time to the currently selected edition. + This is done through coloured tags on each GO annotation. If a tag is present it means the annotation existed in some form in the edition that colour represents.

+

<Ctrl/Command> + <Shift> + <Click> will let you compare up to four editions at once.

+

<Click> a legend item to toggle that series.

+

<Ctrl/Command> + <Click> a legend item to show only that series.

+ +
-

The - similarity plot shows the semantic similarity of the set of annotated GO terms from previous dates as compared to the most current set. - Semantic similarity is measured using the Jaccard Index.

-

Direct Similarity: Similarity of directly annotated GO terms.

-

Inferred Similarity: Similarity of directly annotated GO terms as well as their ancestors.

+
+

Description:

+

The + similarity plot shows the semantic similarity of the set of annotated GO terms from previous dates as compared to the most current set. + Semantic similarity is measured using the Jaccard Index.

+

Legend Descriptions:

+

Direct Similarity: Similarity of directly annotated GO terms.

+

Inferred Similarity: Similarity of directly annotated GO terms as well as their ancestors.

+

Controls:

+

<Click> any edition to view the annotations at that point in time in the right panel.

+

<Ctrl/Command> + <Click> any edition to compare the annotations at that point in time to the currently selected edition. + This is done through coloured tags on each GO annotation. If a tag is present it means the annotation existed in some form in the edition that colour represents.

+

<Ctrl/Command> + <Shift> + <Click> will let you compare up to four editions at once.

+

<Click> a legend item to toggle that series.

+

<Ctrl/Command> + <Click> a legend item to show only that series.

+
-

The multifunctionality plot shows the multifunctionality of the selected gene. - Gene multifunctionality is measured as per +

Description:

+

The multifunctionality plot shows the multifunctionality of the selected gene. + Gene multifunctionality is measured as per Gillis J, Pavlidis P (2011) The Impact of Multifunctional Genes on "Guilt by Association" Analysis.

+

Legend Descriptions:

+

Multifunctionality: A measure of the number of functions a gene is involved in. For a more precise definition, see Gillis and Pavlidis, 2011.

+ class="underline" target="_blank">Gillis and Pavlidis, 2011.

+

Controls:

+

<Click> any edition to view the annotations at that point in time in the right panel.

+

<Ctrl/Command> + <Click> any edition to compare the annotations at that point in time to the currently selected edition. + This is done through coloured tags on each GO annotation. If a tag is present it means the annotation existed in some form in the edition that colour represents.

+

<Ctrl/Command> + <Shift> + <Click> will let you compare up to four editions at once.

+

<Click> a legend item to toggle that series.

+

<Ctrl/Command> + <Click> a legend item to show only that series.

+
-

The Following is the Evidence Timeline of the selected GO terms.

-

For each GO term horizontal bars represent the existence of specific types of evidence for a given GO Annotation Edition.

+

The following is the Evidence Timeline of the selected GO terms.

+

Each selected GO term has its own timeline where coloured bars show the existence of the term at that point in time. Different colours + represent different evidence code categories.

See the following for an explanation of Evidence Codes:

-

The following table shows all GO Terms that have ever been annotated to this gene.

-

You may select GO terms for use with the following functionalities by clicking on their checkmark in the leftmost column.

-

View Terms: View the Evidence Code timeline of selected GO terms.

-

Filter Charts: Filter the various plots on this page to use a selected subset of GO terms.

-

Reset Charts: Reset your filtered GO term subsets.

+
+

Description:

+

The following table shows all GO Terms that are annotated in the selected edition(s).

+

Controls:

+

<Click> on leftmost column () to show the specific annotations associated with this term.

+

<Click> or <Ctrl/Command/Shift> + <Click> to select rows.

+

<Click> to view the annotation history of the selected GO terms. Shows when these terms were annotated to this gene split by evidence code category.

+

<Click> to view the ancestors graph of the selected GO terms.

+
diff --git a/gotrack/src/main/webapp/index.xhtml b/gotrack/src/main/webapp/index.xhtml index 6df0d87..5efe037 100644 --- a/gotrack/src/main/webapp/index.xhtml +++ b/gotrack/src/main/webapp/index.xhtml @@ -62,82 +62,88 @@
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + +
+ + + + + + + + + - - - - - - - - - - - - - - - - - +
+ +
+
+ + + + + + + + + + +
+ + + + +
+
+
+ + + + + + + + + + +
+ + + + +
+
+
+ +
+
- + diff --git a/gotrack/src/main/webapp/resources/css/common.css b/gotrack/src/main/webapp/resources/css/common.css index 64e8e5a..3d0c1d3 100644 --- a/gotrack/src/main/webapp/resources/css/common.css +++ b/gotrack/src/main/webapp/resources/css/common.css @@ -121,9 +121,7 @@ button.ui-button.no-value > span.ui-button-text { } button.ui-button.fa-fix { - top:2px; - width: 1.4em; - height:14px; + vertical-align: middle; } button.ui-button.fa-fix > span.ui-icon { @@ -264,4 +262,28 @@ div.inline { border-radius: 5px; box-shadow: inset 0 0 5px black, 0 0 5px black; padding: 5px; +} + +.overlay-help { + padding: 0.5em 0; +} + +.overlay-help p { + margin: 0.2em 1em; + padding-left: 1.5em; + text-indent:-1.5em; +} + +.overlay-help h3 { + text-decoration: underline; +} + +.overlay-help span.ui-icon { + display: inline-block; + vertical-align: text-bottom; +} + +.ui-rowgroup-header.ui-datatable-headerrow.ui-widget-header > td { + padding-top: 10px; + padding-bottom: 10px; } \ No newline at end of file diff --git a/gotrack/src/main/webapp/resources/css/style.css b/gotrack/src/main/webapp/resources/css/style.css index 5ee0048..6e44532 100644 --- a/gotrack/src/main/webapp/resources/css/style.css +++ b/gotrack/src/main/webapp/resources/css/style.css @@ -3,196 +3,286 @@ Reset ------------------------------------------------------------------- */ -html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, textarea, input, select {margin: 0; padding: 0; border: 0; font-weight: inherit; font-style: inherit; font-size: 100%; font-family: inherit; vertical-align: baseline;} -table {border-collapse: collapse; border-spacing: 0;} -caption, th, td {text-align: left; font-weight: normal;} -table, td, th {vertical-align: middle;} -blockquote:before, blockquote:after, q:before, q:after {content: "";} -blockquote, q {quotes: "" "";} -a img {border: none;} -:focus {outline: 0;} +html, body, div, span, object, iframe, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, textarea, input, select { + margin: 0; + padding: 0; + border: 0; + font-weight: inherit; + font-style: inherit; + font-size: 100%; + font-family: inherit; + vertical-align: baseline; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +caption, th, td { + text-align: left; + font-weight: normal; +} + +table, td, th { + vertical-align: middle; +} + +blockquote:before, blockquote:after, q:before, q:after { + content: ""; +} + +blockquote, q { + quotes: "" ""; +} + +a img { + border: none; +} + +:focus { + outline: 0; +} /* General ------------------------------------------------------------------- */ html { - height: 100%; - /* padding-bottom: 1px; force scrollbars */ + height: 100%; + /* padding-bottom: 1px; force scrollbars */ } body { - height: 100%; - background: rgba(247, 242, 224, 0.19); - color: #444; - font: normal 75% sans-serif; - /* line-height: 1.5; */ + height: 100%; + background: rgba(247, 242, 224, 0.19); + color: #444; + font: normal 75% sans-serif; + /* line-height: 1.5; */ } td { - padding: 2px 4px 2px 4px; + padding: 2px 4px 2px 4px; } /* Wrapper, whole webpage */ #site-wrapper { - min-height: 100%; - height: auto !important; - height: 100%; - margin: 0 auto -50px; + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -50px; } /* Header website*/ #header { - background: white; - height: 100px; + background: white; + height: 100px; } /*!* Top space between menu, logo and description, explore...*!*/ /*#top {padding-bottom: 25px;margin: 0 25px 0 25px;}*/ - /*#content {*/ /*margin:0 50px 0 50px;*/ /*}*/ - .center { - display: block; - margin-left: auto; - margin-right: auto; + display: block; + margin-left: auto; + margin-right: auto; +} + +.left { + float: left; } -.left {float: left;} -.right {float: right;} +.right { + float: right; +} div.fitted { - display: table; - width: 1px; + display: table; + width: 1px; } .frame { - height: 100px; - width: 100px; - position: relative; + height: 100px; + width: 100px; + position: relative; } .vertical-center { - max-height: 100%; - max-width: 100%; - /*width: auto;*/ - /*height: auto;*/ - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - margin: auto; + max-height: 100%; + max-width: 100%; + /*width: auto;*/ + /*height: auto;*/ + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + margin: auto; } .eased { - -webkit-transition: all .3s ease-out; - -moz-transition: all .3s ease-out; - -ms-transition: all .3s ease-out; - transition: all .3s ease-out; + -webkit-transition: all .3s ease-out; + -moz-transition: all .3s ease-out; + -ms-transition: all .3s ease-out; + transition: all .3s ease-out; } /* Footer */ #footer { - height: 29px; - /*border-top: 1px solid #DDD;*/ - color: #777; - padding: 16px 0 4px; + height: 29px; + /*border-top: 1px solid #DDD;*/ + color: #777; + padding: 16px 0 4px; } + /*#footer-left {width: 459px;}*/ /*#footer-right {*/ /*width: 459px;*/ /*text-align: right;*/ /*}*/ -#footer p {margin-bottom: 0.4em;} +#footer p { + margin-bottom: 0.4em; +} + #footer .text-separator { - padding: 0 3px; - color: #BBB; + padding: 0 3px; + color: #BBB; +} + +#footer a:hover { + color: #000; } -#footer a:hover {color: #000;} .push { - height: 50px; + height: 50px; } .navigation { - text-align: center; - line-height: 140px; + text-align: center; + line-height: 140px; } -.navigation a.nav-item { - border-bottom: 1px solid transparent; - color: #777; - display: inline-block; - font-size: 14px; - font-weight: 400; - line-height: 34px; - padding: 0 20px; - text-decoration: none; +.navigation a.nav-item { + border-bottom: 1px solid transparent; + color: #777; + display: inline-block; + font-size: 14px; + font-weight: 400; + line-height: 34px; + padding: 0 20px; + text-decoration: none; } -.navigation a.nav-item:active, -.navigation a.nav-item:focus, -.navigation a.nav-item:hover { - border-bottom: 1px solid #3366CC; - color: #5ea1ec; +.navigation a.nav-item:active, +.navigation a.nav-item:focus, +.navigation a.nav-item:hover { + border-bottom: 1px solid #3366CC; + color: #5ea1ec; } - - .left-header { - position: absolute; - left:0; - top:0; - height:100px; - width:100px; + position: absolute; + left: 0; + top: 0; + height: 100px; + width: 100px; + padding: 15px; } .right-header { - position: absolute; - right:0; - top:0; - height:100px; - width:100px; + position: absolute; + right: 0; + top: 0; + height: 100px; + width: 100px; + padding: 15px; } div.imagebox { } -div.imagebox td { - background-color: #e1e1e1; +div.imagebox td { + background-color: #e1e1e1; } -div.imagebox img { - border-style: solid; - border-width: 4px; - padding:5px; - border-color: #e1e1e1; +div.imagebox img { + border-style: solid; + border-width: 4px; + padding: 5px; + border-color: #e1e1e1; } div.caption { - color: lightslategray; - font-size: 14px; + color: lightslategray; + font-size: 14px; } div.section-description { - display:inline-block; - width:200px; - vertical-align: middle; - text-align: left; - font-size: 14px; + display: inline-block; + width: 200px; + vertical-align: middle; + text-align: left; + font-size: 14px; } div.inline-middle { - display:inline-block; - vertical-align: middle; - margin: 25px 15px; -} \ No newline at end of file + display: inline-block; + vertical-align: middle; + margin: 25px 15px; +} + +.well { + border-radius: 5px; + box-shadow: inset 0 0 5px black, 0 0 5px black; + padding: 5px; +} + +.section-title { + color: #888; + margin-bottom: 25px; +} + +.center { + display: block; + margin-left: auto; + margin-right: auto; + text-align: center; +} + +.no-border { + border-style: none; +} + +table.no-border tr, +table.no-border td { + border: none !important; +} + +#page-title h1, #page-title h1 > a, #page-title h2, #page-title h3 { + color: #888; + margin: auto; + margin-top: 10px; +} + +#page-title h2 > p { + margin-top: 10px; + margin-bottom: 10px; +} + +#page-title h3 { + margin-top: 5px; + margin-bottom: 5px; + font-size: 1em; +} + +#page-title { + text-align: center; +} diff --git a/gotrack/src/main/webapp/resources/css/trends.css b/gotrack/src/main/webapp/resources/css/trends.css index 9d1f717..9c0d4a0 100644 --- a/gotrack/src/main/webapp/resources/css/trends.css +++ b/gotrack/src/main/webapp/resources/css/trends.css @@ -1,15 +1,14 @@ div.chart-panel { - width:600px; - height:300px; + width: 600px; + height: 320px; } div.chart-panel-sm { - width:400px; - height:200px; + width: 400px; + height: 220px; } - div.chart { height: 100%; width: 100%; -} \ No newline at end of file +} diff --git a/gotrack/src/main/webapp/resources/js/genes.js b/gotrack/src/main/webapp/resources/js/genes.js index 791886a..3841dd7 100644 --- a/gotrack/src/main/webapp/resources/js/genes.js +++ b/gotrack/src/main/webapp/resources/js/genes.js @@ -39,7 +39,7 @@ function timelineDlgResize() { function afterRowSelection() { var cnt = PF('funcTable').getSelectedRowsCount(); try { - if (cnt > 1) { + if (cnt >= 1) { // enable View Terms button PF('viewTermsWdg').enable(); PF('viewGOGraphWdg').enable(); @@ -383,13 +383,13 @@ function setCompareEdition(p, color) { function addCompareEdition(p, color) { var edition = GLOBALS.dateToEdition[p.x]; - if ( comparisons.length > 2 || comparisons.indexOf(edition) > -1 ) { + if (comparisons.length > 2 || comparisons.indexOf(edition) > -1) { return false; } comparisons.push(edition); - if (utility.isUndefined(color) ) { + if (utility.isUndefined(color)) { color = plotting.comparisonColors[comparisons.length]; } @@ -452,7 +452,7 @@ function commonOptions(options, config) { plotting.addLegend(options); plotting.addScaleToggle(options, config); options.subtitle = { - text: "Click to view annotations at a specific date", + text: "<Click> to view annotations at a specific date. <Ctrl/Command> + <Click> will compare that edition to the currently selected edition.", style: {"font-size": "10px"} }; options.legend = {}; @@ -460,7 +460,7 @@ function commonOptions(options, config) { return '\u25CF ' + this.series.name + ': ' + utility.sigFigs(this.y, 3) + '
'; }; - var clickBehaviour = function(event, p) { + var clickBehaviour = function (event, p) { var compareBehaviour = event.metaKey || event.ctrlKey; if (!compareBehaviour) { hideTags(); @@ -617,27 +617,27 @@ $(document).ready(function () { plotting.mainCharts = []; - plotting.comparisonColors = ['#FF0000','#800080','#80ff1c', '#05feff']; + plotting.comparisonColors = ['#FF0000', '#800080', '#80ff1c', '#05feff']; // This fixes some strange functionality in PrimeFaces Datatable filtering. // By default pressing ctrl (among other things) while a filter is focused // will activate a table filter. This combined with the fact that clicking // on our HighCharts charts does not make the filers lose focus means we // needlessly reloading table data on Chart ctrl-clicks. - $('div.ui-tabs-panels').on("click", "div.highcharts-container", function() { + $('div.ui-tabs-panels').on("click", "div.highcharts-container", function () { $('input.ui-column-filter').blur(); }); // Used for arbitrary numbers of tags -/* var n = plotting.MAXIMALLY_DISTINCT_COLORS.length; - var style = document.createElement('style'); - style.type = 'text/css'; - style.innerHTML = ''; - for (var i = 0; i < plotting.MAXIMALLY_DISTINCT_COLORS.length; i++) { - var color = plotting.MAXIMALLY_DISTINCT_COLORS[n - 1 - i]; - style.innerHTML += '.tag-' + i + ' { color: ' + color + '; }\n'; - style.innerHTML += 'div.selectButtonFA > div.ui-button:nth-child(' + (i+1) + ') > span:before { color: ' + color + '; }\n'; - } - document.getElementsByTagName('head')[0].appendChild(style);*/ + /* var n = plotting.MAXIMALLY_DISTINCT_COLORS.length; + var style = document.createElement('style'); + style.type = 'text/css'; + style.innerHTML = ''; + for (var i = 0; i < plotting.MAXIMALLY_DISTINCT_COLORS.length; i++) { + var color = plotting.MAXIMALLY_DISTINCT_COLORS[n - 1 - i]; + style.innerHTML += '.tag-' + i + ' { color: ' + color + '; }\n'; + style.innerHTML += 'div.selectButtonFA > div.ui-button:nth-child(' + (i+1) + ') > span:before { color: ' + color + '; }\n'; + } + document.getElementsByTagName('head')[0].appendChild(style);*/ }); \ No newline at end of file diff --git a/gotrack/src/main/webapp/resources/js/gograph.js b/gotrack/src/main/webapp/resources/js/gograph.js index 993e669..646e5f3 100644 --- a/gotrack/src/main/webapp/resources/js/gograph.js +++ b/gotrack/src/main/webapp/resources/js/gograph.js @@ -291,7 +291,7 @@ } var createEdgeOpts = function (e) { - return {class: e.classes.join(" "), lineInterpolate: 'basis', minlen: 2}; + return {class: e.classes.join(" ") + ( e.type ? " " + e.type : "" ), lineInterpolate: 'basis', minlen: 2}; }; for (var i = 0; i < rawedges.length; i++) { diff --git a/gotrack/src/main/webapp/resources/js/trends.js b/gotrack/src/main/webapp/resources/js/trends.js index dcdb740..86675bc 100644 --- a/gotrack/src/main/webapp/resources/js/trends.js +++ b/gotrack/src/main/webapp/resources/js/trends.js @@ -22,18 +22,19 @@ function handleFetchCharts(xhr, status, args) { for (var ckey in args.HC_map) { var chart = args.HC_map[ckey]; + $('#loading-spinner-' + ckey).hide(); var options = plotting.defaultHCOptions('hc-' + ckey, chart); + options.subtitle = { + text: args.species.scientificName + }; + if (syncGroups[ckey]) { plotting.addSynchronization(options); } - if (options.series.length === 1) { - options.legend = {enabled: false}; - } else { - plotting.addLegend(options); - } + options.legend = {enabled: false}; options.xAxis.crosshair = true; options.tooltip.pointFormatter = function () { @@ -43,7 +44,7 @@ function handleFetchCharts(xhr, status, args) { plotting.createNewChart(ckey); plotting.charts[ckey].options = options; - plotting.charts[ckey].recreate(options, function(c) { + plotting.charts[ckey].recreate(options, function (c) { c.syncGroup = syncGroups[ckey]; }); } diff --git a/gotrack/src/main/webapp/terms.xhtml b/gotrack/src/main/webapp/terms.xhtml index ee0e6b9..20f2f6d 100644 --- a/gotrack/src/main/webapp/terms.xhtml +++ b/gotrack/src/main/webapp/terms.xhtml @@ -29,7 +29,7 @@ - + diff --git a/gotrack/src/main/webapp/trends.xhtml b/gotrack/src/main/webapp/trends.xhtml index dbe7a2c..c486f77 100644 --- a/gotrack/src/main/webapp/trends.xhtml +++ b/gotrack/src/main/webapp/trends.xhtml @@ -1,151 +1,200 @@ - - - GOtrack - - - - - - - - - - - - - - - - - - - $(document).ready(function () { - $('.loading').show(); - fetchCharts(); - }); - - - - - - - - - - - - - - - - - - - - - - - - -
-

Global Trends

-
- - + + + + + GOTrack + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(document).ready(function () { + $('.loading').show(); + fetchCharts(); + }); + + + + + +
+