Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add message when no available mutations and tabs for top ten genes with highest frequency for group comparison lollipop plot #4415

Merged
merged 1 commit into from
Nov 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/globalStyles/global.scss
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,10 @@ th.reactable-header-sort-asc:after {
}
}

.comparisonMutationMapperTabs {
height: 0;
}

.mainTabs {
> .nav {
@extend .portalWidth;
Expand Down
77 changes: 73 additions & 4 deletions src/pages/groupComparison/GroupComparisonMutationsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import ErrorMessage from 'shared/components/ErrorMessage';
import { LollipopGeneSelector } from './LollipopGeneSelector';
import GroupComparisonMutationsTabPlot from './GroupComparisonMutationsTabPlot';
import OverlapExclusionIndicator from './OverlapExclusionIndicator';
import { MSKTab, MSKTabs } from 'shared/components/MSKTabs/MSKTabs';

interface IGroupComparisonMutationsTabProps {
store: GroupComparisonStore;
Expand All @@ -24,8 +25,39 @@ export default class GroupComparisonMutationsTab extends React.Component<
IGroupComparisonMutationsTabProps,
{}
> {
@observable public geneTab: string | undefined;
constructor(props: IGroupComparisonMutationsTabProps) {
super(props);
makeObservable(this);
}

@action.bound
protected handleGeneChange(id: string | undefined) {
this.geneTab = id;
this.props.store.setSelectedMutationMapperGene(id);
}

@computed get tabs() {
return this.props.store.genesWithMaxFrequency.map(g => (
<MSKTab
key={g.hugoGeneSymbol}
id={g.hugoGeneSymbol}
linkText={g.hugoGeneSymbol}
/>
));
}

@computed get activeTabId(): string | undefined {
let activeTabId;
if (this.geneTab) {
activeTabId = this.geneTab;
} else if (this.props.store.userSelectedMutationMapperGene) {
activeTabId = this.props.store.userSelectedMutationMapperGene;
} else {
activeTabId = this.props.store.activeMutationMapperGene!
.hugoGeneSymbol;
}
return activeTabId;
}

readonly tabUI = MakeMobxView({
Expand All @@ -45,22 +77,59 @@ export default class GroupComparisonMutationsTab extends React.Component<
</div>
);
}

return (
<>
{!this.props.store.userSelectedMutationMapperGene && (
{/* {!this.props.store.userSelectedMutationMapperGene ? (
<div className="alert alert-info">
<div>
Gene with highest frequency is displayed by
default. Gene can be changed in the dropdown
below.
</div>
<div>
The top 10 genes with highest frequency are
shown below the dropdown and can be selected by
clicking on their respective tabs.
</div>
</div>
) : (
<div className="alert alert-info">
Gene with highest frequency is displayed by default.
Gene can be changed in the dropdown below.
The top 10 genes with highest frequency are shown
below the dropdown and can be selected by clicking
on their respective tabs.
</div>
)}
)} */}
<OverlapExclusionIndicator
store={this.props.store}
only="sample"
/>
<LollipopGeneSelector
store={this.props.store}
genes={this.props.store.availableGenes.result!}
handleGeneChange={this.handleGeneChange}
key={
'comparisonLollipopGene' +
this.props.store.activeMutationMapperGene!
.hugoGeneSymbol
}
/>
<div style={{ display: 'flex' }}>
<div style={{ paddingRight: '5px' }}>
Highest Frequency:
</div>
<MSKTabs
activeTabId={this.activeTabId}
onTabClick={(id: string) =>
this.handleGeneChange(id)
}
className="pillTabs comparisonMutationMapperTabs"
tabButtonStyle="pills"
defaultTabId={false}
>
{this.tabs}
</MSKTabs>
</div>
<GroupComparisonMutationsTabPlot
store={this.props.store}
mutations={_(this.props.store.mutationsByGroup.result!)
Expand Down
29 changes: 25 additions & 4 deletions src/pages/groupComparison/GroupComparisonMutationsTabPlot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export default class GroupComparisonMutationsTabPlot extends React.Component<
this.props.store.mutationsByGroup,
this.props.store.profiledSamplesCount,
this.mutationMapperToolStore.mutationMapperStores,
this.props.store.coverageInformation,
],
render: () => {
if (
Expand All @@ -92,9 +93,12 @@ export default class GroupComparisonMutationsTabPlot extends React.Component<
return (
<>
<h3>
{_(this.props.store.mutationsByGroup.result!)
.keys()
.join(' vs ')}
{this.props.store.activeMutationMapperGene
?.hugoGeneSymbol +
' mutations: ' +
_(this.props.store.mutationsByGroup.result!)
.keys()
.join(' vs ')}
</h3>
<GroupComparisonMutationMapper
{...convertToMutationMapperProps({
Expand All @@ -115,7 +119,24 @@ export default class GroupComparisonMutationsTabPlot extends React.Component<
</>
);
} else {
return null;
if (
Object.values(
this.props.store.coverageInformation.result!.samples
).some(s => !_.isEmpty(s.allGenes) || !_.isEmpty(s.byGene))
) {
return (
<div style={{ marginTop: '20px' }}>
Selected gene has no mutations for profiled samples.
</div>
);
} else {
return (
<div style={{ marginTop: '20px' }}>
Selected gene has no mutations due to no profiled
samples.
</div>
);
}
}
},
renderPending: () => (
Expand Down
11 changes: 3 additions & 8 deletions src/pages/groupComparison/GroupComparisonStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ import { FeatureFlagEnum } from 'shared/featureFlags';

export default class GroupComparisonStore extends ComparisonStore {
@observable private sessionId: string;
@observable private _userSelectedMutationMapperGene: string;
@observable private _userSelectedMutationMapperGene: string | undefined;

constructor(
sessionId: string,
Expand Down Expand Up @@ -452,13 +452,8 @@ export default class GroupComparisonStore extends ComparisonStore {
}

@action.bound
public setSelectedMutationMapperGene(gene: Gene) {
this._userSelectedMutationMapperGene = gene.hugoGeneSymbol;
}

@action.bound
public clearSelectedMutationMapperGene() {
this._userSelectedMutationMapperGene = '';
public setSelectedMutationMapperGene(gene: string | undefined) {
this._userSelectedMutationMapperGene = gene;
}

@autobind
Expand Down
103 changes: 52 additions & 51 deletions src/pages/groupComparison/LollipopGeneSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,58 +8,59 @@ import GroupComparisonStore from './GroupComparisonStore';
interface ILollipopGeneSelectorProps {
store: GroupComparisonStore;
genes: Gene[];
handleGeneChange: (id?: string) => void;
}

export const LollipopGeneSelector: React.FC<ILollipopGeneSelectorProps> = ({
store,
genes,
}: ILollipopGeneSelectorProps) => {
const loadOptions = (inputText: string, callback: any) => {
if (!inputText) {
callback([]);
}
const stringCompare = (item: any) =>
item.hugoGeneSymbol.startsWith(inputText.toUpperCase());
const options = genes;
callback(
options
.filter(stringCompare)
.slice(0, 200)
.map(g => ({
label: g.hugoGeneSymbol,
value: g,
}))
);
};
export const LollipopGeneSelector: React.FC<ILollipopGeneSelectorProps> = observer(
({ store, genes, handleGeneChange }: ILollipopGeneSelectorProps) => {
const loadOptions = (inputText: string, callback: any) => {
if (!inputText) {
callback([]);
}
const stringCompare = (item: any) =>
item.hugoGeneSymbol.startsWith(inputText.toUpperCase());
const options = genes;
callback(
options
.filter(stringCompare)
.slice(0, 200)
.map(g => ({
label: g.hugoGeneSymbol,
value: g,
}))
);
};

return (
<div style={{ width: 200, paddingBottom: 10 }}>
<AsyncSelect
name="Select gene"
onChange={(option: any | null) => {
if (option) {
store.setSelectedMutationMapperGene(option.value);
} else {
store.clearSelectedMutationMapperGene();
return (
<div style={{ width: 200, paddingBottom: 10 }}>
<AsyncSelect
name="Select gene"
onChange={(option: any | null) => {
if (option) {
handleGeneChange(option.value.hugoGeneSymbol);
} else {
handleGeneChange(undefined);
}
}}
isClearable={true}
isSearchable={true}
defaultOptions={genes.slice(0, 200).map(gene => ({
label: gene.hugoGeneSymbol,
value: gene,
}))}
value={
store.userSelectedMutationMapperGene
? {
label: store.userSelectedMutationMapperGene,
value: store.activeMutationMapperGene,
}
: null
}
}}
isClearable={true}
isSearchable={true}
defaultOptions={genes.slice(0, 200).map(gene => ({
label: gene.hugoGeneSymbol,
value: gene,
}))}
value={{
label: store.activeMutationMapperGene!.hugoGeneSymbol,
value: store.activeMutationMapperGene,
}}
placeholder={
store.activeMutationMapperGene!.hugoGeneSymbol ||
'Select a gene'
}
loadOptions={loadOptions}
cacheOptions={true}
/>
</div>
);
};
placeholder={'Search genes'}
loadOptions={loadOptions}
cacheOptions={true}
/>
</div>
);
}
);
13 changes: 8 additions & 5 deletions src/shared/components/MSKTabs/MSKTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ interface IMSKTabsProps {
contentWindowExtra?: JSX.Element;
hrefRoot?: string;
onMount?: () => void;
defaultTabId?: string | Boolean;
}

@observer
Expand Down Expand Up @@ -218,9 +219,11 @@ export class MSKTabs extends React.Component<IMSKTabsProps> {
) {
return this.props.activeTabId;
} else {
return (toArrayedChildren[0] as React.ReactElement<
IMSKTabProps
>).props.id;
return this.props.defaultTabId === false
? undefined
: (toArrayedChildren[0] as React.ReactElement<
IMSKTabProps
>).props.id;
}
})();

Expand Down Expand Up @@ -287,7 +290,7 @@ export class MSKTabs extends React.Component<IMSKTabsProps> {

protected navTabs(
children: React.ReactElement<IMSKTabProps>[],
effectiveActiveTab: string
effectiveActiveTab: string | undefined
) {
// restart the tab refs before each tab rendering
this.tabRefs = [];
Expand Down Expand Up @@ -349,7 +352,7 @@ export class MSKTabs extends React.Component<IMSKTabsProps> {

protected tabPages(
children: React.ReactElement<IMSKTabProps>[],
effectiveActiveTab: string
effectiveActiveTab: string | undefined
): JSX.Element[][] {
const pages: JSX.Element[][] = [[]];
let currentPage = 1;
Expand Down