From d4463c2b77760bd15e1414d2d9bacc21b568a80e Mon Sep 17 00:00:00 2001 From: Andrew Duncan Date: Mon, 8 Apr 2019 13:55:39 -0400 Subject: [PATCH 01/18] show gene annotations --- icgc-viewer/js/Model/GeneFeature.js | 187 +++++++++++++++++++++++ icgc-viewer/js/Model/SSMFeature.js | 1 + icgc-viewer/js/Store/SeqFeature/Genes.js | 7 +- 3 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 icgc-viewer/js/Model/GeneFeature.js diff --git a/icgc-viewer/js/Model/GeneFeature.js b/icgc-viewer/js/Model/GeneFeature.js new file mode 100644 index 0000000..3b14a33 --- /dev/null +++ b/icgc-viewer/js/Model/GeneFeature.js @@ -0,0 +1,187 @@ +/** + * Simple implementation of an SSM feature object. + */ +define([ + 'JBrowse/Util', + 'dojo/request' + ], + function( Util, request ) { + +var counter = 0; + +var GeneFeature = Util.fastDeclare({ + +/** + * @param args.data {Object} key-value data, must include 'start' and 'end' + * @param args.parent {Feature} optional parent feature + * @param args.id {String} optional unique identifier. can also be in data.uniqueID. + * + * Note: args.data.subfeatures can be an array of these same args, + * which will be inflated to more instances of this class. + */ +constructor: function( args ) { + args = args || {}; + this.data = args.data || {}; + this._parent = args.parent; + this._uniqueID = args.id || this.data.uniqueID || ( + this._parent ? this._parent.id()+'_'+(counter++) : 'GeneFeature_'+(counter++) + ); + + // inflate any subfeatures that are not already feature objects + var subfeatures; + if(( subfeatures = this.data.subfeatures )) { + for( var i = 0; i < subfeatures.length; i++ ) { + if( typeof subfeatures[i].get != 'function' ) { + subfeatures[i] = new GeneFeature( + { data: subfeatures[i], + parent: this + }); + } + } + } +}, + +/** + * Get a piece of data about the feature. All features must have + * 'start' and 'end', but everything else is optional. + */ +get: function(name) { + var thisB = this; + if (name == 'annotations') { + var geneId = this.data[name.toLowerCase()]; + + // Find projects related to the current mutation + var url = encodeURI('https://dcc.icgc.org/api/v1/genes/' + geneId); + request(url, { + method: 'get', + headers: { 'X-Requested-With': null }, + handleAs: 'json' + }).then(function(gene) { + document.getElementById('annotations-icgc-' + geneId).innerHTML = thisB.createProjectIncidenceTable(gene.sets); + }).catch(function(err) { + console.log(err) + document.getElementById('annotations-icgc-' + geneId).innerHTML = 'Error creating annotations table'; + }); + return geneId; + } else { + return this.data[ name.toLowerCase() ]; + } +}, + +/** + * Creates a table of annotations for the gene + * @param {object} sets + */ +createProjectIncidenceTable: function(sets) { + var thisB = this; + + var thStyle = 'border: 1px solid #e6e6e6; padding: .2rem .2rem;'; + var setTable = ''; + var goTermRow = '' + setTable += pathwayRow; + + if (!hasSet) { + curatedSetRow += '-'; + } + curatedSetRow += '' + setTable += curatedSetRow; + + if (!hasGo) { + goTermRow += '-'; + } + goTermRow += '' + setTable += goTermRow; + + setTable += '
GO Term
    ' + var curatedSetRow = '
Curated Gene Set
    ' + var pathwayRow = '
Reactome Pathways
    ' + + var hasGo = false; + var hasSet = false; + var hasPathway = false; + + Object.keys(sets).forEach(set => { + var listItem = '
  • ' + thisB.createLinkWithIdAndName('https://dcc.icgc.org/genesets/', sets[set].id, sets[set].name) + '
  • '; + if (sets[set].type == 'go_term') { + goTermRow += listItem; + hasGo = true; + } else if (sets[set].type == 'curated_set') { + curatedSetRow += listItem; + hasSet = true; + } else if (sets[set].type == 'pathway') { + pathwayRow += listItem; + hasPathway = true; + } + }); + + if (!hasPathway) { + pathwayRow += '-'; + } + pathwayRow += '
'; + return setTable; +}, + +/** +* Creates a link to a given ID and name +* @param {string} link Base URL for link +* @param {string} id ID to apped to base URL +* @param {string} name Name to display +*/ +createLinkWithIdAndName: function(link, id, name) { + return id !== null ? "" + name + "" : "n/a"; +}, + + +/** + * Set an item of data. + */ +set: function( name, val ) { + this.data[ name ] = val; +}, + +/** + * Get an array listing which data keys are present in this feature. + */ +tags: function() { + var t = []; + var d = this.data; + for( var k in d ) { + if( d.hasOwnProperty( k ) ) + t.push( k ); + } + return t; +}, + +/** + * Get the unique ID of this feature. + */ +id: function( newid ) { + if( newid ) + this._uniqueID = newid; + return this._uniqueID; +}, + +/** + * Get this feature's parent feature, or undefined if none. + */ +parent: function() { + return this._parent; +}, + +/** + * Get an array of child features, or undefined if none. + */ +children: function() { + return this.get('subfeatures'); +}, + +toJSON: function() { + const d = Object.assign({},this) + delete d._parent + return d +} + +}); + +return GeneFeature; +}); \ No newline at end of file diff --git a/icgc-viewer/js/Model/SSMFeature.js b/icgc-viewer/js/Model/SSMFeature.js index 7401263..21b56d6 100644 --- a/icgc-viewer/js/Model/SSMFeature.js +++ b/icgc-viewer/js/Model/SSMFeature.js @@ -84,6 +84,7 @@ get: function(name) { return this.data[ name.toLowerCase() ]; } }, + /** * Creates a table of projects and their associated tumour type and incidence rate for the given mutation * @param {object} projects Object of the form projectId -> projectObject diff --git a/icgc-viewer/js/Store/SeqFeature/Genes.js b/icgc-viewer/js/Store/SeqFeature/Genes.js index 37f79c1..75edd17 100644 --- a/icgc-viewer/js/Store/SeqFeature/Genes.js +++ b/icgc-viewer/js/Store/SeqFeature/Genes.js @@ -6,14 +6,14 @@ define([ 'dojo/_base/array', 'dojo/request', './BaseSeqFeature', - 'JBrowse/Model/SimpleFeature' + '../../Model/GeneFeature' ], function( declare, array, request, BaseSeqFeature, - SimpleFeature + GeneFeature ) { return declare(BaseSeqFeature, { @@ -115,6 +115,7 @@ function( 'strand': gene.strand, 'gene description': thisB.prettyValue(gene.description), 'type': thisB.prettyValue(gene.type), + 'annotations': gene.id, 'about': { 'gene name': thisB.prettyValue(gene.name), 'symbol': thisB.prettyValue(gene.symbol), @@ -132,7 +133,7 @@ function( }, } } - featureCallback(new SimpleFeature(geneFeature)); + featureCallback(new GeneFeature(geneFeature)); }); finishCallback(); From d95b794ba7978b1f971a639530519dbdea28cf0b Mon Sep 17 00:00:00 2001 From: Andrew Duncan Date: Wed, 17 Apr 2019 13:26:28 -0400 Subject: [PATCH 02/18] only show go terms with direct annotation --- icgc-viewer/js/Model/GeneFeature.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/icgc-viewer/js/Model/GeneFeature.js b/icgc-viewer/js/Model/GeneFeature.js index 3b14a33..7425112 100644 --- a/icgc-viewer/js/Model/GeneFeature.js +++ b/icgc-viewer/js/Model/GeneFeature.js @@ -85,9 +85,10 @@ createProjectIncidenceTable: function(sets) { var hasSet = false; var hasPathway = false; + var count = 0; Object.keys(sets).forEach(set => { var listItem = '
  • ' + thisB.createLinkWithIdAndName('https://dcc.icgc.org/genesets/', sets[set].id, sets[set].name) + '
  • '; - if (sets[set].type == 'go_term') { + if (sets[set].type == 'go_term' && sets[set].annotation == 'direct') { goTermRow += listItem; hasGo = true; } else if (sets[set].type == 'curated_set') { From 82c3d1a5e9be7b4ca84f179fff20c9c2589c1299 Mon Sep 17 00:00:00 2001 From: Andrew Duncan Date: Wed, 17 Apr 2019 14:06:06 -0400 Subject: [PATCH 03/18] add annotations for genes to dialog --- data/advanced-tracks.conf | 10 +++++++++- icgc-viewer/js/Model/GeneFeature.js | 1 - icgc-viewer/js/View/ICGCDialog.js | 1 + icgc-viewer/js/View/ICGCProjectDialog.js | 1 + 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/data/advanced-tracks.conf b/data/advanced-tracks.conf index e88b2ac..0bd16ca 100644 --- a/data/advanced-tracks.conf +++ b/data/advanced-tracks.conf @@ -4,6 +4,8 @@ type=JBrowse/View/Track/CanvasVariants key=ICGC_Mutations filters={"mutation":{"functionalImpact":{"is":["High"]}}} size=300 +metadata.datatype=SSM +unsafePopup=true [tracks.ICGC_Genes] storeClass=icgc-viewer/Store/SeqFeature/Genes @@ -11,6 +13,8 @@ type=JBrowse/View/Track/CanvasVariants key=ICGC_Genes filters={"gene":{"type":{"is":["protein_coding"]}}} size=400 +metadata.datatype=Gene +unsafePopup=true [tracks.ICGC_Genes_donor_DO229446] storeClass=icgc-viewer/Store/SeqFeature/Genes @@ -18,10 +22,14 @@ type=JBrowse/View/Track/CanvasVariants key=ICGC_Genes_donor_DO229446 donor=DO229446 filters={"gene":{"type":{"is":["protein_coding"]}}} +metadata.datatype=Gene +unsafePopup=true [tracks.ICGC_SSMs_donor_DO229446] storeClass=icgc-viewer/Store/SeqFeature/SimpleSomaticMutations type=JBrowse/View/Track/CanvasVariants key=ICGC_SSMs_donor_DO229446 donor=DO229446 -filters={"mutation":{"functionalImpact":{"is":["High"]}}} \ No newline at end of file +filters={"mutation":{"functionalImpact":{"is":["High"]}}} +metadata.datatype=SSM +unsafePopup=true \ No newline at end of file diff --git a/icgc-viewer/js/Model/GeneFeature.js b/icgc-viewer/js/Model/GeneFeature.js index 7425112..43431e1 100644 --- a/icgc-viewer/js/Model/GeneFeature.js +++ b/icgc-viewer/js/Model/GeneFeature.js @@ -85,7 +85,6 @@ createProjectIncidenceTable: function(sets) { var hasSet = false; var hasPathway = false; - var count = 0; Object.keys(sets).forEach(set => { var listItem = '
  • ' + thisB.createLinkWithIdAndName('https://dcc.icgc.org/genesets/', sets[set].id, sets[set].name) + '
  • '; if (sets[set].type == 'go_term' && sets[set].annotation == 'direct') { diff --git a/icgc-viewer/js/View/ICGCDialog.js b/icgc-viewer/js/View/ICGCDialog.js index 5452ceb..571001d 100644 --- a/icgc-viewer/js/View/ICGCDialog.js +++ b/icgc-viewer/js/View/ICGCDialog.js @@ -942,6 +942,7 @@ function ( }; if (storeClass === 'Genes') { + trackConf.fmtDetailValue_annotations = function(value) { return "
    Loading...Loading... Date: Wed, 17 Apr 2019 14:09:01 -0400 Subject: [PATCH 04/18] fix example tracks --- data/advanced-tracks.conf | 6 +++++- data/tracks.conf | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/data/advanced-tracks.conf b/data/advanced-tracks.conf index 0bd16ca..7a78cea 100644 --- a/data/advanced-tracks.conf +++ b/data/advanced-tracks.conf @@ -6,6 +6,7 @@ filters={"mutation":{"functionalImpact":{"is":["High"]}}} size=300 metadata.datatype=SSM unsafePopup=true +fmtDetailValue_projects=function(value) { return "
    Loading...
    ";} [tracks.ICGC_Genes] storeClass=icgc-viewer/Store/SeqFeature/Genes @@ -15,6 +16,7 @@ filters={"gene":{"type":{"is":["protein_coding"]}}} size=400 metadata.datatype=Gene unsafePopup=true +fmtDetailValue_annotations=function(value) { return "
    Loading...
    ";} [tracks.ICGC_Genes_donor_DO229446] storeClass=icgc-viewer/Store/SeqFeature/Genes @@ -24,6 +26,7 @@ donor=DO229446 filters={"gene":{"type":{"is":["protein_coding"]}}} metadata.datatype=Gene unsafePopup=true +fmtDetailValue_annotations=function(value) { return "
    Loading...
    ";} [tracks.ICGC_SSMs_donor_DO229446] storeClass=icgc-viewer/Store/SeqFeature/SimpleSomaticMutations @@ -32,4 +35,5 @@ key=ICGC_SSMs_donor_DO229446 donor=DO229446 filters={"mutation":{"functionalImpact":{"is":["High"]}}} metadata.datatype=SSM -unsafePopup=true \ No newline at end of file +unsafePopup=true +fmtDetailValue_projects=function(value) { return "
    Loading...
    ";} \ No newline at end of file diff --git a/data/tracks.conf b/data/tracks.conf index c975f74..225b7f4 100644 --- a/data/tracks.conf +++ b/data/tracks.conf @@ -4,10 +4,12 @@ type=JBrowse/View/Track/CanvasVariants key=ICGC_Mutations metadata.datatype=SSM unsafePopup=true +fmtDetailValue_projects=function(value) { return "
    Loading...
    ";} [tracks.ICGC_Genes] storeClass=icgc-viewer/Store/SeqFeature/icgcGenes type=JBrowse/View/Track/CanvasVariants key=ICGC_Genes metadata.datatype=Gene -unsafePopup=true \ No newline at end of file +unsafePopup=true +fmtDetailValue_annotations=function(value) { return "
    Loading...
    ";} \ No newline at end of file From 09047e95db9101000bbce6194040fe81452e5eb0 Mon Sep 17 00:00:00 2001 From: Andrew Duncan Date: Wed, 17 Apr 2019 14:09:41 -0400 Subject: [PATCH 05/18] update readme with annotations --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3eb9311..8ed97dc 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,7 @@ storeClass=icgc-viewer/Store/SeqFeature/Genes type=JBrowse/View/Track/CanvasVariants key=ICGC_Genes unsafePopup=true +fmtDetailValue_annotations=function(value) { return "
    Loading...
    ";} ``` ### Extra notes From 13294b6b1d4cc8502d96283d3c7d2bc1ca86ac9a Mon Sep 17 00:00:00 2001 From: Andrew Duncan Date: Mon, 29 Apr 2019 10:58:21 -0400 Subject: [PATCH 06/18] better loading message --- README.md | 4 ++-- data/advanced-tracks.conf | 8 ++++---- data/tracks.conf | 4 ++-- icgc-viewer/css/main.css | 4 ++++ icgc-viewer/js/Model/GeneFeature.js | 8 ++++---- icgc-viewer/js/View/ICGCDialog.js | 4 ++-- icgc-viewer/js/View/ICGCProjectDialog.js | 4 ++-- 7 files changed, 20 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 8ed97dc..070701f 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ storeClass=icgc-viewer/Store/SeqFeature/Genes type=JBrowse/View/Track/CanvasVariants key=ICGC_Genes unsafePopup=true -fmtDetailValue_annotations=function(value) { return "
    Loading...
    ";} +fmtDetailValue_annotations=function(value) { return "
    Loading content...
    ";} ``` ### Extra notes @@ -138,7 +138,7 @@ storeClass=icgc-viewer/Store/SeqFeature/SimpleSomaticMutations type=JBrowse/View/Track/CanvasVariants key=ICGC_Mutations unsafePopup=true -fmtDetailValue_projects=function(value) { return "
    Loading...
    ";} +fmtDetailValue_projects=function(value) { return "
    Loading content...
    ";} ``` ### Extra notes diff --git a/data/advanced-tracks.conf b/data/advanced-tracks.conf index 7a78cea..1047fca 100644 --- a/data/advanced-tracks.conf +++ b/data/advanced-tracks.conf @@ -6,7 +6,7 @@ filters={"mutation":{"functionalImpact":{"is":["High"]}}} size=300 metadata.datatype=SSM unsafePopup=true -fmtDetailValue_projects=function(value) { return "
    Loading...
    ";} +fmtDetailValue_projects=function(value) { return "
    Loading content...
    ";} [tracks.ICGC_Genes] storeClass=icgc-viewer/Store/SeqFeature/Genes @@ -16,7 +16,7 @@ filters={"gene":{"type":{"is":["protein_coding"]}}} size=400 metadata.datatype=Gene unsafePopup=true -fmtDetailValue_annotations=function(value) { return "
    Loading...
    ";} +fmtDetailValue_annotations=function(value) { return "
    Loading content...
    ";} [tracks.ICGC_Genes_donor_DO229446] storeClass=icgc-viewer/Store/SeqFeature/Genes @@ -26,7 +26,7 @@ donor=DO229446 filters={"gene":{"type":{"is":["protein_coding"]}}} metadata.datatype=Gene unsafePopup=true -fmtDetailValue_annotations=function(value) { return "
    Loading...
    ";} +fmtDetailValue_annotations=function(value) { return "
    Loading content...
    ";} [tracks.ICGC_SSMs_donor_DO229446] storeClass=icgc-viewer/Store/SeqFeature/SimpleSomaticMutations @@ -36,4 +36,4 @@ donor=DO229446 filters={"mutation":{"functionalImpact":{"is":["High"]}}} metadata.datatype=SSM unsafePopup=true -fmtDetailValue_projects=function(value) { return "
    Loading...
    ";} \ No newline at end of file +fmtDetailValue_projects=function(value) { return "
    Loading content...
    ";} \ No newline at end of file diff --git a/data/tracks.conf b/data/tracks.conf index 225b7f4..19db861 100644 --- a/data/tracks.conf +++ b/data/tracks.conf @@ -4,7 +4,7 @@ type=JBrowse/View/Track/CanvasVariants key=ICGC_Mutations metadata.datatype=SSM unsafePopup=true -fmtDetailValue_projects=function(value) { return "
    Loading...
    ";} +fmtDetailValue_projects=function(value) { return "
    Loading content...
    ";} [tracks.ICGC_Genes] storeClass=icgc-viewer/Store/SeqFeature/icgcGenes @@ -12,4 +12,4 @@ type=JBrowse/View/Track/CanvasVariants key=ICGC_Genes metadata.datatype=Gene unsafePopup=true -fmtDetailValue_annotations=function(value) { return "
    Loading...
    ";} \ No newline at end of file +fmtDetailValue_annotations=function(value) { return "
    Loading content...
    ";} \ No newline at end of file diff --git a/icgc-viewer/css/main.css b/icgc-viewer/css/main.css index 011f7bc..05be90c 100644 --- a/icgc-viewer/css/main.css +++ b/icgc-viewer/css/main.css @@ -78,4 +78,8 @@ table.results-table tr:nth-child(odd) { .dijitContentPane.dijitAccordionContainer-child.dijitAccordionContainer-dijitContentPane { width: 100% !important; +} + +.popup-dialog { + width: 900px !important; } \ No newline at end of file diff --git a/icgc-viewer/js/Model/GeneFeature.js b/icgc-viewer/js/Model/GeneFeature.js index 43431e1..a68b176 100644 --- a/icgc-viewer/js/Model/GeneFeature.js +++ b/icgc-viewer/js/Model/GeneFeature.js @@ -1,5 +1,5 @@ /** - * Simple implementation of an SSM feature object. + * Simple implementation of an Gene feature object. */ define([ 'JBrowse/Util', @@ -77,9 +77,9 @@ createProjectIncidenceTable: function(sets) { var thStyle = 'border: 1px solid #e6e6e6; padding: .2rem .2rem;'; var setTable = ''; - var goTermRow = '
    GO Term
      ' - var curatedSetRow = '
    Curated Gene Set
      ' - var pathwayRow = '
    Reactome Pathways
      ' + var goTermRow = '
    GO Term
      ' + var curatedSetRow = '
    Curated Gene Set
      ' + var pathwayRow = '
    Reactome Pathways
      ' var hasGo = false; var hasSet = false; diff --git a/icgc-viewer/js/View/ICGCDialog.js b/icgc-viewer/js/View/ICGCDialog.js index 571001d..a1e6722 100644 --- a/icgc-viewer/js/View/ICGCDialog.js +++ b/icgc-viewer/js/View/ICGCDialog.js @@ -942,7 +942,7 @@ function ( }; if (storeClass === 'Genes') { - trackConf.fmtDetailValue_annotations = function(value) { return "
      Loading...Loading content...Loading...Loading content...Loading...Loading content...Loading...Loading content... Date: Wed, 1 May 2019 10:54:45 -0400 Subject: [PATCH 07/18] remove unused class --- icgc-viewer/css/main.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/icgc-viewer/css/main.css b/icgc-viewer/css/main.css index 05be90c..011f7bc 100644 --- a/icgc-viewer/css/main.css +++ b/icgc-viewer/css/main.css @@ -78,8 +78,4 @@ table.results-table tr:nth-child(odd) { .dijitContentPane.dijitAccordionContainer-child.dijitAccordionContainer-dijitContentPane { width: 100% !important; -} - -.popup-dialog { - width: 900px !important; } \ No newline at end of file From 8bceeb7a91aaf3506051ea7c27207fd589e0e978 Mon Sep 17 00:00:00 2001 From: Andrew Duncan Date: Thu, 27 Jun 2019 13:57:30 -0400 Subject: [PATCH 08/18] track dialogs now take up more space, use a grid system --- icgc-viewer/css/main.css | 60 +++++++++++++++++++ icgc-viewer/js/Model/GeneFeature.js | 8 +-- icgc-viewer/js/Model/SSMFeature.js | 2 +- .../js/Store/SeqFeature/BaseSeqFeature.js | 6 +- icgc-viewer/js/Store/SeqFeature/Genes.js | 8 +-- .../SeqFeature/SimpleSomaticMutations.js | 8 +-- icgc-viewer/js/View/ICGCDialog.js | 4 +- icgc-viewer/js/View/ICGCProjectDialog.js | 2 +- icgc-viewer/js/View/Track/GeneTrack.js | 38 ++++++++++++ icgc-viewer/js/View/Track/SSMTrack.js | 42 +++++++++++++ 10 files changed, 161 insertions(+), 17 deletions(-) create mode 100644 icgc-viewer/js/View/Track/GeneTrack.js create mode 100644 icgc-viewer/js/View/Track/SSMTrack.js diff --git a/icgc-viewer/css/main.css b/icgc-viewer/css/main.css index 011f7bc..1247102 100644 --- a/icgc-viewer/css/main.css +++ b/icgc-viewer/css/main.css @@ -78,4 +78,64 @@ table.results-table tr:nth-child(odd) { .dijitContentPane.dijitAccordionContainer-child.dijitAccordionContainer-dijitContentPane { width: 100% !important; +} + +.popup-dialog { + width: 80% !important; +} + +.value_container.projects { + width: 100% !important; +} + +.value.projects { + width: 100% !important; + padding: 0 !important; +} + +.value_container.mutation_consequences { + width: 100% !important; +} + +.value.mutation_consequences { + width: 100% !important; + padding: 0 !important; +} + +.value_container.annotations { + width: 100% !important; +} + +.value.annotations { + width: 100% !important; + padding: 0 !important; +} + +.value_container.feature_sequence { + width: 100% !important; +} + +.value.feature_sequence { + width: 100% !important; + padding: 0 !important; +} + +.feature-detail { + width: 100% !important; +} + +.popup-table { + width: 100% !important; + padding-left: 1em !important; + padding-right:1em !important; + padding-top: 0.3em !important; +} + +.popup-table-header { + border: 1px solid #e6e6e6 !important; + padding: .2rem .2rem !important; +} + +.feature-detail { + width: 100% !important; } \ No newline at end of file diff --git a/icgc-viewer/js/Model/GeneFeature.js b/icgc-viewer/js/Model/GeneFeature.js index a68b176..99330f6 100644 --- a/icgc-viewer/js/Model/GeneFeature.js +++ b/icgc-viewer/js/Model/GeneFeature.js @@ -76,7 +76,7 @@ createProjectIncidenceTable: function(sets) { var thisB = this; var thStyle = 'border: 1px solid #e6e6e6; padding: .2rem .2rem;'; - var setTable = ''; + var setTable = '
      '; var goTermRow = '' setTable += pathwayRow; if (!hasSet) { - curatedSetRow += '-'; + curatedSetRow += 'n/a'; } curatedSetRow += '' setTable += curatedSetRow; if (!hasGo) { - goTermRow += '-'; + goTermRow += 'n/a'; } goTermRow += '' setTable += goTermRow; diff --git a/icgc-viewer/js/Model/SSMFeature.js b/icgc-viewer/js/Model/SSMFeature.js index 21b56d6..78307d9 100644 --- a/icgc-viewer/js/Model/SSMFeature.js +++ b/icgc-viewer/js/Model/SSMFeature.js @@ -103,7 +103,7 @@ createProjectIncidenceTable: function(projects, projectCounts, mutationId) { `; - var projectTable = '' + headerRow; + var projectTable = '
      ' + headerRow; var count = 0; Object.keys(projects).forEach(project => { diff --git a/icgc-viewer/js/Store/SeqFeature/BaseSeqFeature.js b/icgc-viewer/js/Store/SeqFeature/BaseSeqFeature.js index 6eba2ad..b2ccfb7 100644 --- a/icgc-viewer/js/Store/SeqFeature/BaseSeqFeature.js +++ b/icgc-viewer/js/Store/SeqFeature/BaseSeqFeature.js @@ -66,7 +66,11 @@ function( * @param {string} value Value to make pretty */ prettyValue: function(value) { - return value ? value : 'n/a'; + if (value && value !== null && value !== undefined && typeof value !== 'undefined') { + return value; + } else { + return 'n/a'; + } }, /** diff --git a/icgc-viewer/js/Store/SeqFeature/Genes.js b/icgc-viewer/js/Store/SeqFeature/Genes.js index 75edd17..cc07308 100644 --- a/icgc-viewer/js/Store/SeqFeature/Genes.js +++ b/icgc-viewer/js/Store/SeqFeature/Genes.js @@ -82,7 +82,7 @@ function( const ENSEMBL_LINK = "http://feb2014.archive.ensembl.org/Homo_sapiens/Gene/Summary?db=core;g="; const ICGC_LINK = "https://dcc.icgc.org/genes/"; const ENTREZ_LINK = "http://www.ncbi.nlm.nih.gov/gene/"; - const HGNC_LINK = "http://www.genenames.org/data/hgnc_data.php?hgnc_id="; + const HGNC_LINK = "https://www.genenames.org/data/gene-symbol-report/#!/hgnc_id/HGNC:"; const OMIM_LINK = "http://omim.org/entry/"; const UNIPROTKB_SWISSPROT_LINK = "http://www.uniprot.org/uniprot/"; const COSMIC_LINK = "http://cancer.sanger.ac.uk/cosmic/gene/analysis?ln="; @@ -113,16 +113,16 @@ function( 'start': gene.start - 1, 'end': gene.end - 1, 'strand': gene.strand, - 'gene description': thisB.prettyValue(gene.description), 'type': thisB.prettyValue(gene.type), 'annotations': gene.id, 'about': { 'gene name': thisB.prettyValue(gene.name), 'symbol': thisB.prettyValue(gene.symbol), 'type': thisB.prettyValue(gene.type), - 'id': thisB.prettyValue(gene.id) + 'id': thisB.prettyValue(gene.id), + 'description': thisB.prettyValue(gene.description), }, - 'external references': { + 'references': { 'icgc': thisB.createLinkWithId(ICGC_LINK, gene.id), 'ensembl (release 75)': thisB.createLinkWithId(ENSEMBL_LINK, gene.id), 'entrez gene': thisB.createLinksWithId(ENTREZ_LINK, gene.externalDbIds.entrez_gene), diff --git a/icgc-viewer/js/Store/SeqFeature/SimpleSomaticMutations.js b/icgc-viewer/js/Store/SeqFeature/SimpleSomaticMutations.js index 5608d24..0635e92 100644 --- a/icgc-viewer/js/Store/SeqFeature/SimpleSomaticMutations.js +++ b/icgc-viewer/js/Store/SeqFeature/SimpleSomaticMutations.js @@ -98,7 +98,7 @@ function( `; - var consequenceTable = '' + headerRow; + var consequenceTable = '
      ' + headerRow; var count = 0; for (consequence of consequences) { @@ -196,10 +196,10 @@ function( 'affected projects': thisB.prettyValue(variant.affectedProjectCount), 'affected donors': thisB.getDonorFraction(variant), 'type': thisB.prettyValue(variant.type), - 'id': thisB.prettyValue(variant.id) + 'id': thisB.prettyValue(variant.id), + 'description': thisB.prettyValue(variant.description), }, - 'variant description': variant.description, - 'external references': { + 'references': { 'civic': thisB.createLinkWithId(CIVIC_LINK, variant.external_db_ids.civic), 'clinvar': thisB.createLinkWithId(CLINVAR_LINK, variant.external_db_ids.clinvar), 'icgc': thisB.createLinkWithId(ICGC_LINK, variant.id), diff --git a/icgc-viewer/js/View/ICGCDialog.js b/icgc-viewer/js/View/ICGCDialog.js index a1e6722..722013c 100644 --- a/icgc-viewer/js/View/ICGCDialog.js +++ b/icgc-viewer/js/View/ICGCDialog.js @@ -70,7 +70,7 @@ function ( types: ['donor', 'mutation', 'gene'], /** - * Create a DOM object containing GDC primary site interface + * Create a DOM object containing ICGC primary site interface * @return {object} DOM object */ _dialogContent: function () { @@ -212,7 +212,7 @@ function ( dom.empty(loadingIcon); facetsResponse.json().then(function (facetsJsonResponse) { - // Respone will have a code if errored + // Response will have a code if errored if (!facetsJsonResponse.code) { // Create accordion of the facets available for (var facet in facetsJsonResponse.facets) { diff --git a/icgc-viewer/js/View/ICGCProjectDialog.js b/icgc-viewer/js/View/ICGCProjectDialog.js index 03ef142..22b8c14 100644 --- a/icgc-viewer/js/View/ICGCProjectDialog.js +++ b/icgc-viewer/js/View/ICGCProjectDialog.js @@ -31,7 +31,7 @@ function ( size: 20, /** - * Create a DOM object containing GDC primary site interface + * Create a DOM object containing ICGC primary site interface * @return {object} DOM object */ _dialogContent: function () { diff --git a/icgc-viewer/js/View/Track/GeneTrack.js b/icgc-viewer/js/View/Track/GeneTrack.js new file mode 100644 index 0000000..f7e104c --- /dev/null +++ b/icgc-viewer/js/View/Track/GeneTrack.js @@ -0,0 +1,38 @@ +define( + [ + "dojo/_base/declare", + "JBrowse/View/Track/CanvasFeatures", + 'JBrowse/View/Track/_ExportMixin', + 'dojo/dom-construct' + ], + function( + declare, + CanvasFeatures, + ExportMixin, + domConstruct) { + return declare([ CanvasFeatures, ExportMixin ], { + + _renderAdditionalTagsDetail: function( track, f, featDiv, container ) { + var atElement = domConstruct.create( + 'div', + { className: 'additional', + innerHTML: '

      Information

      ' + }, + container ) + + var coreDetailsContent = dojo.create('div', { className: 'core', style: 'display: flex; flex-direction: column;' }, atElement ); + var firstRow = dojo.create('div', { style: 'display: flex; flex-direction: row;' }, coreDetailsContent ); + var secondRow = dojo.create('div', { style: 'display: flex; flex-direction: row;' }, coreDetailsContent ); + + var aboutSection = dojo.create('div', { style: 'flex-grow:1; flex-basis: 0' }, firstRow) + var referenceSection = dojo.create('div', { style: 'flex-grow:1; flex-basis: 0' }, firstRow) + + this.renderDetailField( aboutSection, 'about', f.get('about'), f, undefined, track.store.getTagMetadata('about')) + this.renderDetailField( referenceSection, 'references', f.get('references'), f, undefined, track.store.getTagMetadata('references')) + + var annotationSection = dojo.create('div', { style: 'flex-grow:1; flex-basis: 0' }, secondRow) + this.renderDetailField( annotationSection, 'annotations', f.get('annotations'), f, undefined, track.store.getTagMetadata('annotations')) + }, + }); + } +); \ No newline at end of file diff --git a/icgc-viewer/js/View/Track/SSMTrack.js b/icgc-viewer/js/View/Track/SSMTrack.js new file mode 100644 index 0000000..3800444 --- /dev/null +++ b/icgc-viewer/js/View/Track/SSMTrack.js @@ -0,0 +1,42 @@ +define( + [ + "dojo/_base/declare", + "JBrowse/View/Track/CanvasFeatures", + 'JBrowse/View/Track/_ExportMixin', + 'dojo/dom-construct' + ], + function( + declare, + CanvasFeatures, + ExportMixin, + domConstruct) { + return declare([ CanvasFeatures, ExportMixin ], { + + _renderAdditionalTagsDetail: function( track, f, featDiv, container ) { + var atElement = domConstruct.create( + 'div', + { className: 'additional', + innerHTML: '

      Information

      ' + }, + container ) + + var coreDetailsContent = dojo.create('div', { className: 'core', style: 'display: flex; flex-direction: column; width: 100%;' }, atElement ); + var firstRow = dojo.create('div', { style: 'display: flex; flex-direction: row;' }, coreDetailsContent ); + var secondRow = dojo.create('div', { style: 'display: flex; flex-direction: row;' }, coreDetailsContent ); + var thirdRow = dojo.create('div', { style: 'display: flex; flex-direction: row;' }, coreDetailsContent ); + + var aboutSection = dojo.create('div', { style: 'flex-grow:1; flex-basis: 0' }, firstRow) + var referenceSection = dojo.create('div', { style: 'flex-grow:1; flex-basis: 0' }, firstRow) + + this.renderDetailField( aboutSection, 'about', f.get('about'), f, undefined, track.store.getTagMetadata('about')) + this.renderDetailField( referenceSection, 'references', f.get('references'), f, undefined, track.store.getTagMetadata('references')) + + var consequenceSection = dojo.create('div', { style: 'flex-grow:1; flex-basis: 0' }, secondRow) + this.renderDetailField( consequenceSection, 'mutation consequences', f.get('mutation consequences'), f, undefined, track.store.getTagMetadata('mutation consequences')) + + var projectSection = dojo.create('div', { style: 'flex-grow:1; flex-basis: 0' }, thirdRow) + this.renderDetailField( projectSection, 'projects', f.get('projects'), f, undefined, track.store.getTagMetadata('projects')) + }, + }); + } +); \ No newline at end of file From 6aa4fd91dc22d4525a589c541eb43821e0f206c1 Mon Sep 17 00:00:00 2001 From: Andrew Duncan Date: Tue, 2 Jul 2019 14:31:11 -0400 Subject: [PATCH 09/18] move description to be on its own --- icgc-viewer/js/Model/GeneFeature.js | 6 +++--- icgc-viewer/js/Store/SeqFeature/Genes.js | 4 ++-- .../js/Store/SeqFeature/SimpleSomaticMutations.js | 5 +---- icgc-viewer/js/View/Track/GeneTrack.js | 10 +++++++--- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/icgc-viewer/js/Model/GeneFeature.js b/icgc-viewer/js/Model/GeneFeature.js index 99330f6..faca0d4 100644 --- a/icgc-viewer/js/Model/GeneFeature.js +++ b/icgc-viewer/js/Model/GeneFeature.js @@ -77,9 +77,9 @@ createProjectIncidenceTable: function(sets) { var thStyle = 'border: 1px solid #e6e6e6; padding: .2rem .2rem;'; var setTable = ''; - var goTermRow = ' @@ -105,6 +105,7 @@ createProjectIncidenceTable: function(projects, projectCounts, mutationId) { var projectTable = '' + headerRow; + var tdStyle = 'border: 1px solid #e6e6e6; padding: .2rem .2rem;'; var count = 0; Object.keys(projects).forEach(project => { var trStyle = ''; @@ -112,11 +113,11 @@ createProjectIncidenceTable: function(projects, projectCounts, mutationId) { trStyle = 'style=\"background-color: #f2f2f2\"'; } var projectRow = ` - - - - - + + + + + `; diff --git a/icgc-viewer/js/Store/SeqFeature/SimpleSomaticMutations.js b/icgc-viewer/js/Store/SeqFeature/SimpleSomaticMutations.js index e715299..22ed931 100644 --- a/icgc-viewer/js/Store/SeqFeature/SimpleSomaticMutations.js +++ b/icgc-viewer/js/Store/SeqFeature/SimpleSomaticMutations.js @@ -85,7 +85,7 @@ function( * @param {List} consequences */ createConsequencesTable: function(consequences) { - var thStyle = 'border: 1px solid #e6e6e6; padding: .2rem .2rem;'; + var thStyle = 'border: 1px solid #b3b3b3; padding: .2rem .2rem;'; var headerRow = ` @@ -100,6 +100,7 @@ function( var consequenceTable = '' + headerRow; + var tdStyle = 'border: 1px solid #e6e6e6; padding: .2rem .2rem;'; var count = 0; for (consequence of consequences) { var trStyle = ''; @@ -107,13 +108,13 @@ function( trStyle = 'style=\"background-color: #f2f2f2\"'; } var consequenceRow = ` - - - - - - - + + + + + + + `; diff --git a/icgc-viewer/js/View/ICGCDialog.js b/icgc-viewer/js/View/ICGCDialog.js index e175f5e..991c68a 100644 --- a/icgc-viewer/js/View/ICGCDialog.js +++ b/icgc-viewer/js/View/ICGCDialog.js @@ -125,15 +125,15 @@ function ( if (type === 'donor') { thisB.donorAccordion = new AccordionContainer({ id: newAccordionId, className: "accordionContainer" }, thisB.donorFacetTab.containerNode); var loadingIcon = thisB.createLoadingIcon(thisB.donorFacetTab.containerNode); - thisB.createFacet('donor', thisB.donorAccordion, loadingIcon); + thisB.createFacet(type, thisB.donorAccordion, loadingIcon); } else if (type === 'mutation') { thisB.mutationAccordion = new AccordionContainer({ id: newAccordionId, className: "accordionContainer" }, thisB.mutationFacetTab.containerNode); var loadingIcon = thisB.createLoadingIcon(thisB.mutationFacetTab.containerNode); - thisB.createFacet('mutation', thisB.mutationAccordion, loadingIcon); + thisB.createFacet(type, thisB.mutationAccordion, loadingIcon); } else if (type === 'gene') { thisB.geneAccordion = new AccordionContainer({ id: newAccordionId, className: "accordionContainer" }, thisB.geneFacetTab.containerNode); var loadingIcon = thisB.createLoadingIcon(thisB.geneFacetTab.containerNode); - thisB.createFacet('gene', thisB.geneAccordion, loadingIcon); + thisB.createFacet(type, thisB.geneAccordion, loadingIcon); } }, @@ -170,28 +170,28 @@ function ( */ getFiltersForType: function(type) { var thisB = this; - var filters = {}; if (type === 'donor') { - filters = thisB.donorFilters; + return thisB.donorFilters; } else if (type === 'mutation') { - filters = thisB.mutationFilters; + return thisB.mutationFilters; } else if (type === 'gene') { - filters = thisB.geneFilters; + return thisB.geneFilters; } - return filters; }, /** * Compare function used for sorting facets - * @param {*} a - * @param {*} b + * @param {*} a Object with a string field called 'term' + * @param {*} b Object with a string field called 'term' */ compareTermElements: function(a, b) { - if (a.term < b.term) + if (a.term < b.term) { return -1; - if (a.term > b.term) + } else if (a.term > b.term) { return 1; - return 0; + } else { + return 0; + } }, /** diff --git a/icgc-viewer/js/View/ICGCProjectDialog.js b/icgc-viewer/js/View/ICGCProjectDialog.js index 7492c4f..3919896 100644 --- a/icgc-viewer/js/View/ICGCProjectDialog.js +++ b/icgc-viewer/js/View/ICGCProjectDialog.js @@ -207,7 +207,7 @@ function ( var storeConf = { browser: this.browser, refSeq: this.browser.refSeq, - type: storeClass, + type: 'icgc-viewer/Store/SeqFeature/' + storeClass, project: projectId, filters: JSON.stringify(projectFilters) }; @@ -221,7 +221,7 @@ function ( label += '_' + projectId var trackConf = { - type: 'JBrowse/View/Track/' + trackType, + type: trackType, store: storeName, label: label, key: key, diff --git a/icgc-viewer/js/main.js b/icgc-viewer/js/main.js index 6972bdd..4586fea 100644 --- a/icgc-viewer/js/main.js +++ b/icgc-viewer/js/main.js @@ -19,13 +19,13 @@ return declare(JBrowsePlugin, { this.browser.afterMilestone('initView', function () { this.browser.addGlobalMenuItem('icgc', new MenuItem( { - label: 'Explore ICGC', + label: 'Explore donors, genes and mutations', iconClass: "dijitIconSearch", onClick: lang.hitch(this, 'createICGCTrack') })); this.browser.addGlobalMenuItem('icgc', new MenuItem( { - label: 'ICGC Projects', + label: 'Projects', iconClass: "dijitIconSearch", onClick: lang.hitch(this, 'createICGCProjectTrack') })); From 4e82732f2e6ba3c0924c1149646e8a5617d9be1b Mon Sep 17 00:00:00 2001 From: Andrew Duncan Date: Wed, 14 Aug 2019 15:07:01 -0400 Subject: [PATCH 14/18] some cleanup --- README.md | 7 +++++-- icgc-viewer/js/View/ICGCDialog.js | 2 +- icgc-viewer/js/main.js | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 62562fe..a5d14cc 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# ICGC JBrowse Plugin - Faceted Search and New Store Classes -A plugin for [JBrowse](https://jbrowse.org/) for viewing ICGC data. For any bugs, issues, or feature recommendations please create an issue through GitHub. +# ICGC JBrowse Plugin +A plugin for [JBrowse](https://jbrowse.org/) for viewing [ICGC](https://icgc.org/) data. For any bugs, issues, or feature recommendations please create an issue through GitHub. # Installation and Setup ## 1. Install JBrowse @@ -64,6 +64,9 @@ displayColumns = ``` # Available Store SeqFeature +## A note on filters +All SeqFeatures support filters as they are used in the ICGC API Documentation. + ## Genes A simple view of all genes returned by the ICGC portal for a given range of the chromosome you are looking at. diff --git a/icgc-viewer/js/View/ICGCDialog.js b/icgc-viewer/js/View/ICGCDialog.js index 991c68a..e511e7c 100644 --- a/icgc-viewer/js/View/ICGCDialog.js +++ b/icgc-viewer/js/View/ICGCDialog.js @@ -208,7 +208,6 @@ function ( // Fetch facets and display in accordion fetch(url).then(function (facetsResponse) { - // Clear loading indicator dom.empty(loadingIcon); facetsResponse.json().then(function (facetsJsonResponse) { @@ -236,6 +235,7 @@ function ( value: { "facet": facet, "term" : term.term, "type": type }, checked: thisB.isChecked(facet, term.term, thisB.getFiltersForType(type)), onChange: function(isChecked) { + // Update the selected facets based on selection if (isChecked) { if (this.value.type === 'donor') { thisB.donorFilters = thisB.addToFilters(this.value, thisB.donorFilters); diff --git a/icgc-viewer/js/main.js b/icgc-viewer/js/main.js index 4586fea..b54b05f 100644 --- a/icgc-viewer/js/main.js +++ b/icgc-viewer/js/main.js @@ -25,7 +25,7 @@ return declare(JBrowsePlugin, { })); this.browser.addGlobalMenuItem('icgc', new MenuItem( { - label: 'Projects', + label: 'Explore Projects', iconClass: "dijitIconSearch", onClick: lang.hitch(this, 'createICGCProjectTrack') })); From 55d8cb499314aab539e54323376b668f59de0fae Mon Sep 17 00:00:00 2001 From: Andrew Duncan Date: Wed, 14 Aug 2019 15:53:13 -0400 Subject: [PATCH 15/18] better handling of no results --- icgc-viewer/css/main.css | 5 + icgc-viewer/js/View/ICGCDialog.js | 257 ++++++++++++++++-------------- 2 files changed, 142 insertions(+), 120 deletions(-) diff --git a/icgc-viewer/css/main.css b/icgc-viewer/css/main.css index 1247102..6270c3d 100644 --- a/icgc-viewer/css/main.css +++ b/icgc-viewer/css/main.css @@ -10,6 +10,11 @@ table.results-table td { padding: .2rem .4rem; } +table.results-table th { + border: 1px solid #b3b3b3; + padding: .2rem .4rem; +} + table.results-table tr:nth-child(odd) { background-color: #f2f2f2; } diff --git a/icgc-viewer/js/View/ICGCDialog.js b/icgc-viewer/js/View/ICGCDialog.js index e511e7c..f4692ac 100644 --- a/icgc-viewer/js/View/ICGCDialog.js +++ b/icgc-viewer/js/View/ICGCDialog.js @@ -215,63 +215,68 @@ function ( if (!facetsJsonResponse.code) { // Create accordion of the facets available for (var facet in facetsJsonResponse.facets) { - var paneId = facet + '-' + type + '-' + thisB.accordionId; - var contentPane = new ContentPane({ - title: thisB.camelCaseToTitleCase(facet), - style: "height: auto", - id: paneId - }); - - var facetHolder = dom.create('span', { className: "flex-column", style: "width: 100%" }); - if (facetsJsonResponse.facets[facet].terms) { - facetsJsonResponse.facets[facet].terms.sort(thisB.compareTermElements); - facetsJsonResponse.facets[facet].terms.forEach((term) => { - var facetCheckbox = dom.create('span', { className: "flex-row" }, facetHolder) - var checkboxName = facet + '-' + term.term; - var checkboxId = facet + '-' + term.term + '-' + type + '-' + thisB.accordionId; - var checkBox = new CheckBox({ - name: checkboxName, - id: checkboxId, - value: { "facet": facet, "term" : term.term, "type": type }, - checked: thisB.isChecked(facet, term.term, thisB.getFiltersForType(type)), - onChange: function(isChecked) { - // Update the selected facets based on selection - if (isChecked) { - if (this.value.type === 'donor') { - thisB.donorFilters = thisB.addToFilters(this.value, thisB.donorFilters); - } else if (this.value.type === 'mutation') { - thisB.mutationFilters = thisB.addToFilters(this.value, thisB.mutationFilters); - } else if (this.value.type === 'gene') { - thisB.geneFilters = thisB.addToFilters(this.value, thisB.geneFilters); + if (facet != 'projectName') { + var paneId = facet + '-' + type + '-' + thisB.accordionId; + var contentPane = new ContentPane({ + title: thisB.camelCaseToTitleCase(facet), + style: "height: auto", + id: paneId + }); + + var facetHolder = dom.create('span', { className: "flex-column", style: "width: 100%" }); + if (!facetsJsonResponse.facets[facet].terms || facetsJsonResponse.facets[facet].terms.length == 0) { + dom.create('span', { className: "flex-row", innerHTML: "No terms for the selected facet." }, facetHolder) + } + if (facetsJsonResponse.facets[facet].terms) { + facetsJsonResponse.facets[facet].terms.sort(thisB.compareTermElements); + facetsJsonResponse.facets[facet].terms.forEach((term) => { + var facetCheckbox = dom.create('span', { className: "flex-row" }, facetHolder) + var checkboxName = facet + '-' + term.term; + var checkboxId = facet + '-' + term.term + '-' + type + '-' + thisB.accordionId; + var checkBox = new CheckBox({ + name: checkboxName, + id: checkboxId, + value: { "facet": facet, "term" : term.term, "type": type }, + checked: thisB.isChecked(facet, term.term, thisB.getFiltersForType(type)), + onChange: function(isChecked) { + // Update the selected facets based on selection + if (isChecked) { + if (this.value.type === 'donor') { + thisB.donorFilters = thisB.addToFilters(this.value, thisB.donorFilters); + } else if (this.value.type === 'mutation') { + thisB.mutationFilters = thisB.addToFilters(this.value, thisB.mutationFilters); + } else if (this.value.type === 'gene') { + thisB.geneFilters = thisB.addToFilters(this.value, thisB.geneFilters); + } + } else { + if (this.value.type === 'donor') { + thisB.donorFilters = thisB.removeFromFilters(this.value, thisB.donorFilters); + } else if (this.value.type === 'mutation') { + thisB.mutationFilters = thisB.removeFromFilters(this.value, thisB.mutationFilters); + } else if (this.value.type === 'gene') { + thisB.geneFilters = thisB.removeFromFilters(this.value, thisB.geneFilters); + } } - } else { - if (this.value.type === 'donor') { - thisB.donorFilters = thisB.removeFromFilters(this.value, thisB.donorFilters); - } else if (this.value.type === 'mutation') { - thisB.mutationFilters = thisB.removeFromFilters(this.value, thisB.mutationFilters); - } else if (this.value.type === 'gene') { - thisB.geneFilters = thisB.removeFromFilters(this.value, thisB.geneFilters); + + // Update with newly applied filter + for (var type of thisB.types) { + thisB.updateAccordion(type); + thisB.updateSearchResults(type); } } - - // Update with newly applied filter - for (var type of thisB.types) { - thisB.updateAccordion(type); - thisB.updateSearchResults(type); - } - } - }, 'checkbox').placeAt(facetCheckbox); - - // Add text label to checkbox - var labelName = facet + '-' + term.term + '-' + type + '-' + thisB.accordionId; - var labelContent = term.term + ' (' + (term.count).toLocaleString() + ')'; - dom.create("label", { "for" : labelName, innerHTML: labelContent }, facetCheckbox); - }); + }, 'checkbox').placeAt(facetCheckbox); + + // Add text label to checkbox + var labelName = facet + '-' + term.term + '-' + type + '-' + thisB.accordionId; + var labelContent = term.term + ' (' + (term.count).toLocaleString() + ')'; + dom.create("label", { "for" : labelName, innerHTML: labelContent }, facetCheckbox); + }); + } + + // Place facet group into holder and add to accordion + dojo.place(facetHolder, contentPane.containerNode); + accordion.addChild(contentPane); } - - // Place facet group into holder and add to accordion - dojo.place(facetHolder, contentPane.containerNode); - accordion.addChild(contentPane); } // Update accordion with new content @@ -318,10 +323,14 @@ function ( dom.empty(resultsInfo); facetsResponse.json().then(function (facetsJsonResponse) { if (!facetsJsonResponse.code) { - var endResult = facetsJsonResponse.pagination.from + facetsJsonResponse.pagination.count; - var resultsInfo = dom.create('div', { innerHTML: "Showing " + (facetsJsonResponse.pagination.from).toLocaleString() + " to " + endResult.toLocaleString() + " of " + (facetsJsonResponse.pagination.total).toLocaleString() }, thisB.donorResultsTab.containerNode); - thisB.createDonorsTable(facetsJsonResponse.hits, thisB.donorResultsTab.containerNode, combinedFacetObject); - thisB.createPaginationButtons(thisB.donorResultsTab.containerNode, facetsJsonResponse.pagination, type, thisB.donorPage); + if (facetsJsonResponse.pagination.from && facetsJsonResponse.pagination.count && facetsJsonResponse.pagination.total) { + var endResult = facetsJsonResponse.pagination.from + facetsJsonResponse.pagination.count; + var resultsInfo = dom.create('div', { innerHTML: "Showing " + (facetsJsonResponse.pagination.from).toLocaleString() + " to " + endResult.toLocaleString() + " of " + (facetsJsonResponse.pagination.total).toLocaleString() }, thisB.donorResultsTab.containerNode); + thisB.createDonorsTable(facetsJsonResponse.hits, thisB.donorResultsTab.containerNode, combinedFacetObject); + thisB.createPaginationButtons(thisB.donorResultsTab.containerNode, facetsJsonResponse.pagination, type, thisB.donorPage); + } else { + var resultsInfo = dom.create('div', { innerHTML: "No results for the selected facets." }, thisB.donorResultsTab.containerNode); + } } }, function (res3) { console.error('error', res3); @@ -338,37 +347,41 @@ function ( dom.empty(resultsInfo); facetsResponse.json().then(function (facetsJsonResponse) { if (!facetsJsonResponse.code) { - var ssmMenu = new Menu({ style: "display: none;"}); - var menuItemSSMFiltered = new MenuItem({ - label: "Filtered SSMs form ICGC", - iconClass: "dijitIconNewTask", - onClick: function() { - thisB.addTrack('SimpleSomaticMutations', undefined, combinedFacetObject, 'icgc-viewer/View/Track/SSMTrack'); - alert("Adding track with all SSMs from the ICGC, with current filters applied"); - } - }); - ssmMenu.addChild(menuItemSSMFiltered); - ssmMenu.startup(); - - var buttonAllSSMs = new ComboButton({ - label: "All SSMs from ICGC", - iconClass: "dijitIconNewTask", - dropDown: ssmMenu, - onClick: function() { - thisB.addTrack('SimpleSomaticMutations', undefined, undefined, 'icgc-viewer/View/Track/SSMTrack'); - alert("Add track with all SSMs from the ICGC"); - } - }); - buttonAllSSMs.placeAt(thisB.mutationResultsTab.containerNode); - buttonAllSSMs.startup(); - thisB.addTooltipToButton(menuItemSSMFiltered, "Add track with all SSMs from the ICGC, with current filters applied"); - thisB.addTooltipToButton(buttonAllSSMs, "Add track with all SSMs from the ICGC"); - - var endResult = facetsJsonResponse.pagination.from + facetsJsonResponse.pagination.count; - var resultsInfo = dom.create('div', { innerHTML: "Showing " + (facetsJsonResponse.pagination.from).toLocaleString() + " to " + endResult.toLocaleString() + " of " + (facetsJsonResponse.pagination.total).toLocaleString() }, thisB.mutationResultsTab.containerNode); - - thisB.createMutationsTable(facetsJsonResponse.hits, thisB.mutationResultsTab.containerNode, combinedFacetObject); - thisB.createPaginationButtons(thisB.mutationResultsTab.containerNode, facetsJsonResponse.pagination, type, thisB.mutationPage); + if (facetsJsonResponse.pagination.from && facetsJsonResponse.pagination.count && facetsJsonResponse.pagination.total) { + var ssmMenu = new Menu({ style: "display: none;"}); + var menuItemSSMFiltered = new MenuItem({ + label: "Filtered SSMs form ICGC", + iconClass: "dijitIconNewTask", + onClick: function() { + thisB.addTrack('SimpleSomaticMutations', undefined, combinedFacetObject, 'icgc-viewer/View/Track/SSMTrack'); + alert("Adding track with all SSMs from the ICGC, with current filters applied"); + } + }); + ssmMenu.addChild(menuItemSSMFiltered); + ssmMenu.startup(); + + var buttonAllSSMs = new ComboButton({ + label: "All SSMs from ICGC", + iconClass: "dijitIconNewTask", + dropDown: ssmMenu, + onClick: function() { + thisB.addTrack('SimpleSomaticMutations', undefined, undefined, 'icgc-viewer/View/Track/SSMTrack'); + alert("Add track with all SSMs from the ICGC"); + } + }); + buttonAllSSMs.placeAt(thisB.mutationResultsTab.containerNode); + buttonAllSSMs.startup(); + thisB.addTooltipToButton(menuItemSSMFiltered, "Add track with all SSMs from the ICGC, with current filters applied"); + thisB.addTooltipToButton(buttonAllSSMs, "Add track with all SSMs from the ICGC"); + + var endResult = facetsJsonResponse.pagination.from + facetsJsonResponse.pagination.count; + var resultsInfo = dom.create('div', { innerHTML: "Showing " + (facetsJsonResponse.pagination.from).toLocaleString() + " to " + endResult.toLocaleString() + " of " + (facetsJsonResponse.pagination.total).toLocaleString() }, thisB.mutationResultsTab.containerNode); + + thisB.createMutationsTable(facetsJsonResponse.hits, thisB.mutationResultsTab.containerNode, combinedFacetObject); + thisB.createPaginationButtons(thisB.mutationResultsTab.containerNode, facetsJsonResponse.pagination, type, thisB.mutationPage); + } else { + var resultsInfo = dom.create('div', { innerHTML: "No results for the selected facets." }, thisB.mutationResultsTab.containerNode); + } } }, function (res3) { console.error('error', res3); @@ -385,38 +398,42 @@ function ( dom.empty(resultsInfo); facetsResponse.json().then(function (facetsJsonResponse) { if (!facetsJsonResponse.code) { - var geneMenu = new Menu({ style: "display: none;"}); - var menuItemGeneFiltered = new MenuItem({ - label: "Filtered Genes from ICGC", - iconClass: "dijitIconNewTask", - onClick: function() { - thisB.addTrack('Genes', undefined, combinedFacetObject, 'icgc-viewer/View/Track/GeneTrack'); - alert("Adding track with all genes from the ICGC, with current filters applied"); - } - }); - geneMenu.addChild(menuItemGeneFiltered); - geneMenu.startup(); - - var buttonAllGenes = new ComboButton({ - label: "All Genes from ICGC", - iconClass: "dijitIconNewTask", - dropDown: geneMenu, - style: "padding-right: 8px;", - onClick: function() { - thisB.addTrack('Genes', undefined, undefined, 'icgc-viewer/View/Track/GeneTrack'); - alert("Adding track with all genes from the ICGC"); - } - }); - buttonAllGenes.placeAt(thisB.geneResultsTab.containerNode); - buttonAllGenes.startup(); - thisB.addTooltipToButton(menuItemGeneFiltered, "Add track with all genes from the ICGC, with current filters applied"); - thisB.addTooltipToButton(buttonAllGenes, "Add track with all genes from the ICGC"); - - var endResult = facetsJsonResponse.pagination.from + facetsJsonResponse.pagination.count; - var resultsInfo = dom.create('div', { innerHTML: "Showing " + (facetsJsonResponse.pagination.from).toLocaleString() + " to " + endResult.toLocaleString() + " of " + (facetsJsonResponse.pagination.total).toLocaleString() }, thisB.geneResultsTab.containerNode); - - thisB.createGenesTable(facetsJsonResponse.hits, thisB.geneResultsTab.containerNode, combinedFacetObject); - thisB.createPaginationButtons(thisB.geneResultsTab.containerNode, facetsJsonResponse.pagination, type, thisB.genePage); + if (facetsJsonResponse.pagination.from && facetsJsonResponse.pagination.count && facetsJsonResponse.pagination.total) { + var geneMenu = new Menu({ style: "display: none;"}); + var menuItemGeneFiltered = new MenuItem({ + label: "Filtered Genes from ICGC", + iconClass: "dijitIconNewTask", + onClick: function() { + thisB.addTrack('Genes', undefined, combinedFacetObject, 'icgc-viewer/View/Track/GeneTrack'); + alert("Adding track with all genes from the ICGC, with current filters applied"); + } + }); + geneMenu.addChild(menuItemGeneFiltered); + geneMenu.startup(); + + var buttonAllGenes = new ComboButton({ + label: "All Genes from ICGC", + iconClass: "dijitIconNewTask", + dropDown: geneMenu, + style: "padding-right: 8px;", + onClick: function() { + thisB.addTrack('Genes', undefined, undefined, 'icgc-viewer/View/Track/GeneTrack'); + alert("Adding track with all genes from the ICGC"); + } + }); + buttonAllGenes.placeAt(thisB.geneResultsTab.containerNode); + buttonAllGenes.startup(); + thisB.addTooltipToButton(menuItemGeneFiltered, "Add track with all genes from the ICGC, with current filters applied"); + thisB.addTooltipToButton(buttonAllGenes, "Add track with all genes from the ICGC"); + + var endResult = facetsJsonResponse.pagination.from + facetsJsonResponse.pagination.count; + var resultsInfo = dom.create('div', { innerHTML: "Showing " + (facetsJsonResponse.pagination.from).toLocaleString() + " to " + endResult.toLocaleString() + " of " + (facetsJsonResponse.pagination.total).toLocaleString() }, thisB.geneResultsTab.containerNode); + + thisB.createGenesTable(facetsJsonResponse.hits, thisB.geneResultsTab.containerNode, combinedFacetObject); + thisB.createPaginationButtons(thisB.geneResultsTab.containerNode, facetsJsonResponse.pagination, type, thisB.genePage); + } else { + var resultsInfo = dom.create('div', { innerHTML: "No results for the selected facets." }, thisB.geneResultsTab.containerNode); + } } }, function (res3) { console.error('error', res3); From 49d01b6d1551612d0182baadaec6e122c6bba7d8 Mon Sep 17 00:00:00 2001 From: Andrew Duncan Date: Wed, 14 Aug 2019 16:21:26 -0400 Subject: [PATCH 16/18] fix page count issue --- icgc-viewer/js/View/ICGCDialog.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/icgc-viewer/js/View/ICGCDialog.js b/icgc-viewer/js/View/ICGCDialog.js index f4692ac..602d7e9 100644 --- a/icgc-viewer/js/View/ICGCDialog.js +++ b/icgc-viewer/js/View/ICGCDialog.js @@ -324,7 +324,7 @@ function ( facetsResponse.json().then(function (facetsJsonResponse) { if (!facetsJsonResponse.code) { if (facetsJsonResponse.pagination.from && facetsJsonResponse.pagination.count && facetsJsonResponse.pagination.total) { - var endResult = facetsJsonResponse.pagination.from + facetsJsonResponse.pagination.count; + var endResult = facetsJsonResponse.pagination.from + facetsJsonResponse.pagination.count - 1; var resultsInfo = dom.create('div', { innerHTML: "Showing " + (facetsJsonResponse.pagination.from).toLocaleString() + " to " + endResult.toLocaleString() + " of " + (facetsJsonResponse.pagination.total).toLocaleString() }, thisB.donorResultsTab.containerNode); thisB.createDonorsTable(facetsJsonResponse.hits, thisB.donorResultsTab.containerNode, combinedFacetObject); thisB.createPaginationButtons(thisB.donorResultsTab.containerNode, facetsJsonResponse.pagination, type, thisB.donorPage); @@ -374,7 +374,7 @@ function ( thisB.addTooltipToButton(menuItemSSMFiltered, "Add track with all SSMs from the ICGC, with current filters applied"); thisB.addTooltipToButton(buttonAllSSMs, "Add track with all SSMs from the ICGC"); - var endResult = facetsJsonResponse.pagination.from + facetsJsonResponse.pagination.count; + var endResult = facetsJsonResponse.pagination.from + facetsJsonResponse.pagination.count - 1; var resultsInfo = dom.create('div', { innerHTML: "Showing " + (facetsJsonResponse.pagination.from).toLocaleString() + " to " + endResult.toLocaleString() + " of " + (facetsJsonResponse.pagination.total).toLocaleString() }, thisB.mutationResultsTab.containerNode); thisB.createMutationsTable(facetsJsonResponse.hits, thisB.mutationResultsTab.containerNode, combinedFacetObject); @@ -426,7 +426,7 @@ function ( thisB.addTooltipToButton(menuItemGeneFiltered, "Add track with all genes from the ICGC, with current filters applied"); thisB.addTooltipToButton(buttonAllGenes, "Add track with all genes from the ICGC"); - var endResult = facetsJsonResponse.pagination.from + facetsJsonResponse.pagination.count; + var endResult = facetsJsonResponse.pagination.from + facetsJsonResponse.pagination.count - 1; var resultsInfo = dom.create('div', { innerHTML: "Showing " + (facetsJsonResponse.pagination.from).toLocaleString() + " to " + endResult.toLocaleString() + " of " + (facetsJsonResponse.pagination.total).toLocaleString() }, thisB.geneResultsTab.containerNode); thisB.createGenesTable(facetsJsonResponse.hits, thisB.geneResultsTab.containerNode, combinedFacetObject); From be230031cbe44becf52d6925181793f31c25b9dd Mon Sep 17 00:00:00 2001 From: Andrew Duncan Date: Thu, 15 Aug 2019 10:17:11 -0400 Subject: [PATCH 17/18] better error handling and messages --- icgc-viewer/js/View/ICGCDialog.js | 33 +++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/icgc-viewer/js/View/ICGCDialog.js b/icgc-viewer/js/View/ICGCDialog.js index 602d7e9..89e06c7 100644 --- a/icgc-viewer/js/View/ICGCDialog.js +++ b/icgc-viewer/js/View/ICGCDialog.js @@ -224,11 +224,17 @@ function ( }); var facetHolder = dom.create('span', { className: "flex-column", style: "width: 100%" }); + + // If facet has no terms if (!facetsJsonResponse.facets[facet].terms || facetsJsonResponse.facets[facet].terms.length == 0) { dom.create('span', { className: "flex-row", innerHTML: "No terms for the selected facet." }, facetHolder) } + // If facet has at least one term if (facetsJsonResponse.facets[facet].terms) { + // Sort in ascending alphabetical order facetsJsonResponse.facets[facet].terms.sort(thisB.compareTermElements); + + // Create a checkbox for each term facetsJsonResponse.facets[facet].terms.forEach((term) => { var facetCheckbox = dom.create('span', { className: "flex-row" }, facetHolder) var checkboxName = facet + '-' + term.term; @@ -285,10 +291,10 @@ function ( thisB.resize(); } }, function (res3) { - console.error('error', res3); + console.error('There was an error parsing the JSON response from ICGC.', res3); }); }, function (err) { - console.error('error', err); + console.error('There was an error fetching facets from ICGC.', err); }); }, @@ -301,6 +307,7 @@ function ( var combinedFacetObject = thisB.createCombinedFacets(); dom.empty(thisB.prettyFacetHolder); + // Add button for clearing selected facets if (Object.keys(thisB.donorFilters).length + Object.keys(thisB.mutationFilters).length + Object.keys(thisB.geneFilters).length > 0) { var clearFacetButton = new Button({ iconClass: "dijitIconDelete", @@ -311,6 +318,7 @@ function ( thisB.addTooltipToButton(clearFacetButton, "Clears all facets"); } + // Pretty print filters var combinedFacets = Object.assign({}, thisB.donorFilters, thisB.mutationFilters, thisB.geneFilters); thisB.prettyPrintFilters(thisB.prettyFacetHolder, combinedFacets); @@ -318,6 +326,7 @@ function ( dom.empty(thisB.donorResultsTab.containerNode); var resultsInfo = thisB.createLoadingIcon(thisB.donorResultsTab.containerNode); + // Create donor tab content var donorUrl = thisB.createDonorUrl(combinedFacetObject); fetch(donorUrl).then(function (facetsResponse) { dom.empty(resultsInfo); @@ -333,15 +342,18 @@ function ( } } }, function (res3) { - console.error('error', res3); + console.error('There was an error creating the donor results table.', res3); + dom.create('div', { innerHTML: "There was an error creating the donor results table." }, thisB.donorResultsTab.containerNode); }); }, function (err) { - console.error('error', err); + console.error('There was an error fetching donor data for current facets.', err); + dom.create('div', { innerHTML: "There was an error creating the donor results table." }, thisB.donorResultsTab.containerNode); }); } else if (type === 'mutation') { dom.empty(thisB.mutationResultsTab.containerNode); var resultsInfo = thisB.createLoadingIcon(thisB.mutationResultsTab.containerNode); + // Create mutation tab content var mutationUrl = thisB.createMutationUrl(combinedFacetObject); fetch(mutationUrl).then(function (facetsResponse) { dom.empty(resultsInfo); @@ -384,15 +396,18 @@ function ( } } }, function (res3) { - console.error('error', res3); + console.error('There was an error creating the mutation results table.', res3); + dom.create('div', { innerHTML: "There was an error creating the mutation results table." }, thisB.mutationResultsTab.containerNode); }); }, function (err) { - console.error('error', err); + console.error('There was an error fetching mutation data for current facets.', err); + dom.create('div', { innerHTML: "There was an error creating the mutation results table." }, thisB.mutationResultsTab.containerNode); }); } else if (type === 'gene') { dom.empty(thisB.geneResultsTab.containerNode); var resultsInfo = thisB.createLoadingIcon(thisB.geneResultsTab.containerNode); + // Create gene tab content var geneUrl = thisB.createGeneUrl(combinedFacetObject); fetch(geneUrl).then(function (facetsResponse) { dom.empty(resultsInfo); @@ -436,10 +451,12 @@ function ( } } }, function (res3) { - console.error('error', res3); + console.error('There was an error creating the gene results table.', res3); + dom.create('div', { innerHTML: "There was an error creating the gene results table." }, thisB.geneResultsTab.containerNode); }); }, function (err) { - console.error('error', err); + console.error('There was an error fetching gene data for current facets.', err); + dom.create('div', { innerHTML: "There was an error creating the gene results table." }, thisB.geneResultsTab.containerNode); }); } }, From 6dff1d2fa34b09bfd9a7f2dc06ab3393a24a6f17 Mon Sep 17 00:00:00 2001 From: Andrew Duncan Date: Thu, 15 Aug 2019 10:21:54 -0400 Subject: [PATCH 18/18] small text change --- icgc-viewer/js/View/ICGCDialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icgc-viewer/js/View/ICGCDialog.js b/icgc-viewer/js/View/ICGCDialog.js index 89e06c7..c239410 100644 --- a/icgc-viewer/js/View/ICGCDialog.js +++ b/icgc-viewer/js/View/ICGCDialog.js @@ -227,7 +227,7 @@ function ( // If facet has no terms if (!facetsJsonResponse.facets[facet].terms || facetsJsonResponse.facets[facet].terms.length == 0) { - dom.create('span', { className: "flex-row", innerHTML: "No terms for the selected facet." }, facetHolder) + dom.create('span', { className: "flex-row", innerHTML: "No terms available for the selected facet." }, facetHolder) } // If facet has at least one term if (facetsJsonResponse.facets[facet].terms) {