Skip to content

Commit e10353d

Browse files
authored
Merge pull request #2250 from broadinstitute/development
Release 1.95.0
2 parents 8a9ca83 + 4edfa8f commit e10353d

35 files changed

+1992
-474
lines changed

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ GEM
328328
multipart-post (2.3.0)
329329
mutex_m (0.3.0)
330330
naturally (2.2.1)
331-
net-imap (0.5.6)
331+
net-imap (0.5.7)
332332
date
333333
net-protocol
334334
net-pop (0.1.2)

app/javascript/components/explore/ExploreDisplayPanelManager.jsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { faLink, faEye, faTimes, faUndo } from '@fortawesome/free-solid-svg-icon
55

66
import ClusterSelector from '~/components/visualization/controls/ClusterSelector'
77
import AnnotationSelector from '~/components/visualization/controls/AnnotationSelector'
8+
import LabelSelector from '~/components/visualization/controls/LabelSelector'
89
import SubsampleSelector from '~/components/visualization/controls/SubsampleSelector'
910
import { ExploreConsensusSelector } from '~/components/visualization/controls/ConsensusSelector'
1011
import SpatialSelector from '~/components/visualization/controls/SpatialSelector'
@@ -24,7 +25,8 @@ import BookmarkManager from '~/components/bookmarks/BookmarkManager'
2425
import { EXPRESSION_SORT_OPTIONS } from '~/components/visualization/PlotDisplayControls'
2526

2627
/** Get the selected clustering and annotation, or their defaults */
27-
function getSelectedClusterAndAnnot(exploreInfo, exploreParams) {
28+
export function getSelectedClusterAndAnnot(exploreInfo, exploreParams) {
29+
if (!exploreInfo) {return [null, null]}
2830
const annotList = exploreInfo.annotationList
2931
let selectedCluster
3032
let selectedAnnot
@@ -283,7 +285,7 @@ export default function ExploreDisplayPanelManager({
283285
// the wrong tabs
284286
const updateParams = { geneList: '', ideogramFileId: '' }
285287

286-
const clusterParamNames = ['cluster', 'annotation', 'subsample', 'spatialGroups']
288+
const clusterParamNames = ['cluster', 'annotation', 'subsample', 'label', 'spatialGroups']
287289
clusterParamNames.forEach(param => {
288290
updateParams[param] = param in newParams ? newParams[param] : exploreParamsWithDefaults[param]
289291
})
@@ -411,6 +413,13 @@ export default function ExploreDisplayPanelManager({
411413
cluster={exploreParamsWithDefaults.cluster}
412414
shownAnnotation={shownAnnotation}
413415
updateClusterParams={updateClusterParams}/>
416+
{ shownTab === 'pathway' &&
417+
<LabelSelector
418+
exploreParamsWithDefaults={exploreParamsWithDefaults}
419+
exploreInfo={exploreInfo}
420+
updateClusterParams={updateClusterParams}
421+
/>
422+
}
414423
{ shownTab === 'scatter' && <CreateAnnotation
415424
isSelecting={isCellSelecting}
416425
setIsSelecting={setIsCellSelecting}

app/javascript/components/explore/ExploreDisplayTabs.jsx

Lines changed: 60 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,39 +13,25 @@ import ScatterPlot from '~/components/visualization/ScatterPlot'
1313
import StudyViolinPlot from '~/components/visualization/StudyViolinPlot'
1414
import DotPlot from '~/components/visualization/DotPlot'
1515
import Heatmap from '~/components/visualization/Heatmap'
16+
import Pathway from '~/components/visualization/Pathway'
1617
import GeneListHeatmap from '~/components/visualization/GeneListHeatmap'
1718
import GenomeView from './GenomeView'
18-
import { getAnnotationValues, getShownAnnotation } from '~/lib/cluster-utils'
19+
import { getAnnotationValues, getEligibleLabels } from '~/lib/cluster-utils'
1920
import RelatedGenesIdeogram from '~/components/visualization/RelatedGenesIdeogram'
2021
import InferCNVIdeogram from '~/components/visualization/InferCNVIdeogram'
2122
import useResizeEffect from '~/hooks/useResizeEffect'
2223
import LoadingSpinner from '~/lib/LoadingSpinner'
2324
import { log } from '~/lib/metrics-api'
2425
import { getFeatureFlagsWithDefaults } from '~/providers/UserProvider'
25-
import ExploreDisplayPanelManager from './ExploreDisplayPanelManager'
26+
import ExploreDisplayPanelManager, {getSelectedClusterAndAnnot} from './ExploreDisplayPanelManager'
2627
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'
2728
import Tooltip from 'react-bootstrap/lib/Tooltip'
2829
import PlotTabs from './PlotTabs'
2930
import {
3031
initCellFaceting, filterCells, getFacetsParam, parseFacetsParam
3132
} from '~/lib/cell-faceting'
33+
import { getIsPathway } from '~/lib/search-utils'
3234

33-
/** Get the selected clustering and annotation, or their defaults */
34-
export function getSelectedClusterAndAnnot(exploreInfo, exploreParams) {
35-
if (!exploreInfo) {return [null, null]}
36-
const annotList = exploreInfo.annotationList
37-
let selectedCluster
38-
let selectedAnnot
39-
if (exploreParams?.cluster) {
40-
selectedCluster = exploreParams.cluster
41-
selectedAnnot = exploreParams.annotation
42-
} else {
43-
selectedCluster = annotList.default_cluster
44-
selectedAnnot = annotList.default_annotation
45-
}
46-
47-
return [selectedCluster, selectedAnnot]
48-
}
4935

5036
/** Determine if current annotation has one-vs-rest or pairwise DE */
5137
function getHasComparisonDe(exploreInfo, exploreParams, comparison) {
@@ -286,7 +272,7 @@ export default function ExploreDisplayTabs({
286272
const [filterErrorText, setFilterErrorText] = useState(null)
287273

288274
const {
289-
enabledTabs, disabledTabs, isGeneList, isGene, isMultiGene, hasIdeogramOutputs
275+
enabledTabs, disabledTabs, isGeneList, isGene, isPathway, isMultiGene, hasIdeogramOutputs
290276
} = getEnabledTabs(exploreInfo, exploreParamsWithDefaults, cellFaceting)
291277

292278
// exploreParams object without genes specified, to pass to cluster comparison plots
@@ -299,13 +285,27 @@ export default function ExploreDisplayTabs({
299285
window.SCP.exploreInfo = exploreInfo
300286

301287
/** helper function so that StudyGeneField doesn't have to see the full exploreParams object */
302-
function searchGenes(genes) {
288+
function queryFn(queries) {
289+
const isPathway = getIsPathway(queries[0])
303290
// also unset any selected gene lists or ideogram files
304-
const newParams = { genes, geneList: '', ideogramFileId: '' }
305-
if (genes.length < 2) {
306-
// and unset the consensus if there are no longer 2+ genes
307-
newParams.consensus = ''
291+
const newParams = { geneList: '', ideogramFileId: '' }
292+
if (isPathway) {
293+
newParams.pathway = queries[0]
294+
newParams['genes'] = []
295+
} else {
296+
newParams.genes = queries
297+
newParams['pathway'] = ''
298+
299+
if (queries.length < 2) {
300+
// and unset the consensus if there are no longer 2+ genes
301+
newParams.consensus = ''
302+
}
308303
}
304+
305+
if (exploreParams?.label !== '') {
306+
newParams.label = exploreParams.label
307+
}
308+
309309
updateExploreParams(newParams)
310310
}
311311

@@ -320,7 +320,7 @@ export default function ExploreDisplayTabs({
320320
exploreInfo &&
321321
exploreInfo.taxonNames.length === 1 &&
322322
exploreParams.genes.length === 1 &&
323-
!isGeneList
323+
!isGeneList && !isPathway
324324
) {
325325
showRelatedGenesIdeogram = true
326326
currentTaxon = exploreInfo.taxonNames[0]
@@ -516,25 +516,38 @@ export default function ExploreDisplayTabs({
516516
return { main, side }
517517
}
518518

519+
let queries
520+
if (exploreParams.pathway !== '') {
521+
queries = [exploreParams.pathway]
522+
} else {
523+
queries = exploreParams.genes
524+
}
525+
526+
// eslint-disable-next-line no-unused-vars
527+
const [_, selectedAnnotation] = getSelectedClusterAndAnnot(exploreInfo, exploreParams)
528+
519529
return (
520530
<>
521531
{/* Render top content for Explore view, i.e. gene search box and plot tabs */}
522532
<div className="row position-forward">
523533
<div className="col-md-5">
524534
<div className="flexbox">
525-
<StudyGeneField genes={exploreParams.genes}
526-
searchGenes={searchGenes}
535+
<StudyGeneField
536+
queries={queries}
537+
queryFn={queryFn}
527538
allGenes={exploreInfo ? exploreInfo.uniqueGenes : []}
528539
isLoading={!exploreInfo}
529-
speciesList={exploreInfo ? exploreInfo.taxonNames : []}/>
540+
speciesList={exploreInfo ? exploreInfo.taxonNames : []}
541+
selectedAnnotation={selectedAnnotation}
542+
/>
530543
{ // show if this is gene search || gene list
531-
(isGene || isGeneList || hasIdeogramOutputs) &&
544+
(isGene || isGeneList || hasIdeogramOutputs || isPathway) &&
532545
<OverlayTrigger placement="top" overlay={
533546
<Tooltip id="back-to-cluster-view">{'Return to cluster view'}</Tooltip>
534547
}>
535548
<button className="action fa-lg"
536549
aria-label="Back arrow"
537-
onClick={() => searchGenes([])}>
550+
onClick={() => queryFn([])}>
538551
<FontAwesomeIcon icon={faArrowLeft}/>
539552
</button>
540553
</OverlayTrigger>
@@ -559,7 +572,7 @@ export default function ExploreDisplayTabs({
559572
taxon={currentTaxon}
560573
target={`.${plotContainerClass}`}
561574
genesInScope={exploreInfo.uniqueGenes}
562-
searchGenes={searchGenes}
575+
queryFn={queryFn}
563576
speciesList={exploreInfo.taxonNames}
564577

565578
studyAccession={studyAccession}
@@ -666,6 +679,17 @@ export default function ExploreDisplayTabs({
666679
/>
667680
</div>
668681
}
682+
{ enabledTabs.includes('pathway') &&
683+
<div className={shownTab === 'pathway' ? '' : 'hidden'}>
684+
<Pathway
685+
studyAccession={studyAccession}
686+
{... exploreParamsWithDefaults}
687+
labels={getEligibleLabels(exploreParamsWithDefaults, exploreInfo)}
688+
dimensions={getPlotDimensions({ showViewOptionsControls, showDifferentialExpressionTable })}
689+
queryFn={queryFn}
690+
/>
691+
</div>
692+
}
669693
{ enabledTabs.includes('geneListHeatmap') &&
670694
<div className={shownTab === 'geneListHeatmap' ? '' : 'hidden'}>
671695
<GeneListHeatmap
@@ -726,7 +750,7 @@ export default function ExploreDisplayTabs({
726750
clearExploreParams={clearExploreParams}
727751
exploreParamsWithDefaults={exploreParamsWithDefaults}
728752
routerLocation={routerLocation}
729-
searchGenes={searchGenes}
753+
queryFn={queryFn}
730754
countsByLabelForDe={countsByLabelForDe}
731755
setShowUpstreamDifferentialExpressionPanel={setShowUpstreamDifferentialExpressionPanel}
732756
showDifferentialExpressionPanel={showDifferentialExpressionPanel}
@@ -765,6 +789,7 @@ export function getEnabledTabs(exploreInfo, exploreParams, cellFaceting) {
765789
const numGenes = exploreParams?.genes?.length
766790
const isMultiGene = numGenes > 1
767791
const isGene = exploreParams?.genes?.length > 0
792+
const isPathway = exploreParams?.pathway && exploreParams.pathway !== ''
768793
const isConsensus = !!exploreParams.consensus
769794
const hasClusters = exploreInfo && exploreInfo.clusterGroupNames.length > 0
770795
const hasSpatialGroups = exploreParams.spatialGroups?.length > 0
@@ -783,6 +808,8 @@ export function getEnabledTabs(exploreInfo, exploreParams, cellFaceting) {
783808

784809
if (isGeneList) {
785810
enabledTabs = ['geneListHeatmap']
811+
} else if (isPathway) {
812+
enabledTabs = ['pathway']
786813
} else if (isGene) {
787814
if (isMultiGene) {
788815
if (isConsensus) {
@@ -838,5 +865,5 @@ export function getEnabledTabs(exploreInfo, exploreParams, cellFaceting) {
838865
disabledTabs = []
839866
}
840867

841-
return { enabledTabs, disabledTabs, isGeneList, isGene, isMultiGene, hasIdeogramOutputs }
868+
return { enabledTabs, disabledTabs, isGeneList, isGene, isPathway, isMultiGene, hasIdeogramOutputs }
842869
}

app/javascript/components/explore/ExploreTabRouter.jsx

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@ function updateExploreParams(newOptions, wasUserSpecified=true) {
4343
const search = location.search
4444
const currentParams = buildExploreParamsFromQuery(search)
4545
const mergedOpts = Object.assign({}, currentParams, newOptions)
46+
47+
if (newOptions.pathway && newOptions.pathway !== '') {
48+
mergedOpts.genes = []
49+
}
50+
51+
if (newOptions.genes?.length > 0) {
52+
mergedOpts.pathway = ''
53+
}
54+
4655
if (wasUserSpecified) {
4756
// this is just default params being fetched from the server, so don't change the url
4857
Object.keys(newOptions).forEach(key => {
@@ -62,7 +71,7 @@ function updateExploreParams(newOptions, wasUserSpecified=true) {
6271
// view options settings should not add history entries
6372
// e.g. when a user hits 'back', it shouldn't undo their cluster selection,
6473
// it should take them to the page they were on before they came to the explore tab
65-
navigate(`${query}#study-visualize`, { replace: true })
74+
navigate(query, { replace: true })
6675
}
6776

6877
/** converts query string parameters into the dataParams object */
@@ -90,6 +99,7 @@ function buildExploreParamsFromQuery(query) {
9099
})
91100
exploreParams.cluster = queryParams.cluster ? queryParams.cluster : ''
92101
exploreParams.annotation = annotation
102+
exploreParams.label = queryParams.label ? queryParams.label : ''
93103
exploreParams.subsample = queryParams.subsample ? queryParams.subsample : ''
94104
exploreParams.consensus = queryParams.consensus ? queryParams.consensus : null
95105
if (queryParams.spatialGroups === SPATIAL_GROUPS_EMPTY) {
@@ -98,6 +108,8 @@ function buildExploreParamsFromQuery(query) {
98108
exploreParams.spatialGroups = queryParams.spatialGroups ? queryParams.spatialGroups.split(',') : []
99109
}
100110
exploreParams.genes = geneParamToArray(queryParams.genes)
111+
exploreParams.pathway = queryParams.pathway ? queryParams.pathway : ''
112+
101113
exploreParams.geneList = queryParams.geneList ? queryParams.geneList : ''
102114
exploreParams.heatmapRowCentering = queryParams.heatmapRowCentering ?
103115
queryParams.heatmapRowCentering :
@@ -117,7 +129,7 @@ function buildExploreParamsFromQuery(query) {
117129
exploreParams.expressionFilter = filterArray
118130
}
119131
}
120-
exploreParams.expressionSort = queryParams.expressionSort
132+
exploreParams.expressionSort = queryParams.expressionSort ? queryParams.expressionSort : ''
121133
exploreParams.hiddenTraces = queryParams.hiddenTraces ? queryParams.hiddenTraces.split(',') : []
122134
exploreParams.isSplitLabelArrays = queryParams.isSplitLabelArrays === 'true' ? true : null
123135

@@ -131,8 +143,10 @@ function buildQueryFromParams(exploreParams) {
131143
const querySafeOptions = {
132144
cluster: exploreParams.cluster,
133145
annotation: getIdentifierForAnnotation(exploreParams.annotation),
146+
label: exploreParams.label,
134147
subsample: exploreParams.subsample,
135148
genes: geneArrayToParam(exploreParams.genes),
149+
pathway: exploreParams.pathway,
136150
consensus: exploreParams.consensus,
137151
geneList: exploreParams.geneList,
138152
spatialGroups: exploreParams.spatialGroups.join(','),
@@ -165,7 +179,7 @@ function buildQueryFromParams(exploreParams) {
165179

166180
/** controls list in which query string params are rendered into URL bar */
167181
const PARAM_LIST_ORDER = [
168-
'geneList', 'genes', 'cluster', 'spatialGroups', 'annotation', 'subsample', 'consensus',
182+
'geneList', 'genes', 'pathway', 'cluster', 'spatialGroups', 'annotation', 'subsample', 'consensus',
169183
'tab', 'scatterColor', 'distributionPlot', 'distributionPoints',
170184
'heatmapFit', 'heatmapRowCentering', 'trackFileName', 'ideogramFileId', 'expressionFilter', 'expressionSort',
171185
'isSplitLabelArrays', 'hiddenTraces', 'facets'

app/javascript/components/explore/PlotTabs.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const tabList = [
88
{ key: 'distribution', label: 'Distribution' },
99
{ key: 'dotplot', label: 'Dot plot' },
1010
{ key: 'heatmap', label: 'Heatmap' },
11+
{ key: 'pathway', label: 'Pathway' },
1112
{ key: 'geneListHeatmap', label: 'Precomputed heatmap' },
1213
{ key: 'spatial', label: 'Spatial' },
1314
{ key: 'genome', label: 'Genome' },

0 commit comments

Comments
 (0)