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

Mutation Plot Diagram on Study View - GSoC #4646

Draft
wants to merge 49 commits into
base: master
Choose a base branch
from

Conversation

aditygrg2
Copy link
Contributor

@aditygrg2 aditygrg2 commented Jun 20, 2023

Mutation Plot on Study View

@aditygrg2 aditygrg2 marked this pull request as draft June 20, 2023 17:49
Comment on lines 113 to 121
const filteredDataForStudyView = filteredDataByCodon(
codon,
this.props.dataStore
);

// Send the data to study view if the page is study view.
if (this.props.getFilteredData !== undefined) {
this.props.getFilteredData(filteredDataForStudyView);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a low level library component. We should not introduce anything study view specific here. This needs to be done outside of this component. Also, I don't think we need a new filteredDataByCodon function. It should be already computed in the store. This is probably what we should be using instead:

public get mutationsByPosition(): { [pos: number]: T[] } {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the suggestions, the new implementation now uses this method.

@@ -37,6 +37,7 @@ export type LollipopPlotProps = {
dataStore?: DataStore;
onXAxisOffset?: (offset: number) => void;
yAxisLabelFormatter?: (symbol?: string, groupName?: string) => string;
getFilteredData?: (selectedLollipopData: any[]) => void;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need this getFilteredData property in this component.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is removed now.

Comment on lines 851 to 853
public setCustomDataByCodon(data: any[]) {
this.props.store.sampleDataByCodon = data.slice();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not the correct way to do it. We don't need an action like this. Instead sampleDataByCodon can and should be computed inside the store.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is removed now.

Comment on lines 1154 to 1156
clearFilters() {
this.sampleDataByCodon = [];
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pretty confusing, and most likely we don't even need a function like this. sampleDataByCodon should be a computed value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree. This is removed too. Now there is StudyViewMutationMapperStore with computed samplesViaSelectedCodons

@@ -106,6 +106,7 @@ class DefaultMutationMapperStore<T extends Mutation>

@observable
private _selectedTranscript: string | undefined = undefined;
sampleDataByCodon?: any[] = [];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a computed value. Also should be a well defined type, not just any. We may need to do this in a more specific store, like StudyViewMutationMapperStore.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type is updated in the new implementation.

@@ -17,6 +17,26 @@ import { ApplyFilterFn } from '../model/FilterApplier';

export const TEXT_INPUT_FILTER_ID = '_mutationTableTextInputFilter_';

export function filteredDataByCodon(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to recompute filtered data here. This data already exists in the mutation mapper store. We just need a @computed value to get samplesByPosition.

Another thing is the sample defined in this function is actually a Partial<Mutation>, we can probably use mutationsByPosition as is without even adding a new function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is removed now.

@@ -2647,6 +2739,7 @@ export class StudyViewPageStore
this.submittedPillStore = {};
this.hesitantPillStore = {};
this.resetClinicalEventTypeFilter();
this.mutationPlotStore[this.selectedMutationPlotGene].clearFilters();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's just remove this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@@ -175,6 +181,7 @@ export interface IChartContainerProps {
@observer
export class ChartContainer extends React.Component<IChartContainerProps, {}> {
private chartHeaderHeight = 20;
private mutationPlotRef: any;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should avoid any and be more specific here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated with the component name.

@@ -192,6 +199,7 @@ export class ChartContainer extends React.Component<IChartContainerProps, {}> {
super(props);

makeObservable(this);
this.mutationPlotRef = React.createRef();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably don't need this line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I was just trying out different things, removed this line

@aditygrg2 aditygrg2 requested a review from onursumer June 21, 2023 20:35
Comment on lines 17 to 19
patientId?: string;
studyId?: string;
sampleId?: string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should not modify our base Mutation model. These fields are specific to cbioportal mutation data. This mutation model is designed to be generic.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated this model

@@ -83,6 +83,7 @@ export interface MutationMapperStore<T extends Mutation> {
getTranscriptId?: () => string | undefined;
selectedTranscript?: string | undefined;
ptmSources?: string[];
sampleDataByCodon?: any[];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be defined somewhere else mutation mapper store should not store sample/patient data. Also we should avoid any type

@@ -1,4 +1,4 @@
import _ from 'lodash';
import _, { uniq } from 'lodash';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't need this import, we can simply call _.uniq

Comment on lines 2580 to 2581
if (selectedTable == FreqColumnTypeEnum.MUTATION)
this.addMutationPlot(hugoGeneSymbol);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (selectedTable == FreqColumnTypeEnum.MUTATION)
this.addMutationPlot(hugoGeneSymbol);
if (selectedTable == FreqColumnTypeEnum.MUTATION) {
this.addMutationPlot(hugoGeneSymbol);
}

@action.bound
addMutationPlot(hugoGeneSymbol: string): void {
if (!this.visibleMutationPlotByGene(hugoGeneSymbol)) {
let mutationPlotSpecs = [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let mutationPlotSpecs = [
const mutationPlotSpecs = [

Comment on lines 1438 to 1444
toggleXAxisAtTop={
this.chartType === ChartTypeEnum.MUTATION_DIAGRAM
? this.props.store.getMutationStore(
this.props.chartMeta.uniqueKey
).toggleXAxisOnTop
: undefined
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again, probably we won't need this

@@ -0,0 +1,66 @@
import { Mutation } from 'cbioportal-ts-api-client';
import { DefaultMutationMapperStoreConfig } from '../../../../../packages/react-mutation-mapper/dist/store/DefaultMutationMapperStore';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not the right way to import from packages. Do this instead:

Suggested change
import { DefaultMutationMapperStoreConfig } from '../../../../../packages/react-mutation-mapper/dist/store/DefaultMutationMapperStore';
import { DefaultMutationMapperStoreConfig } from 'react-mutation-mapper';

}

@computed
get samplesViaSelectedCodons(): SampleData[] {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

samplesByPosition

const selectedPositions = dataStore.selectedPositions;
const mutationsByPosition = this.mutationsByPosition;

const mutationData = Object.values(selectedPositions).map(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be more clear here. This should be mutationsGroupedBySelectedPostions, right?

Comment on lines 51 to 64
const samplesViaSelectedCodons: SampleData[] = [];

mutationData.map(val => {
val.map(m => {
samplesViaSelectedCodons.push({
patientId: m.patientId,
studyId: m.studyId,
sampleId: m.sampleId,
value: m.keyword,
});
});
});

return samplesViaSelectedCodons;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are not using the return valiue of mutationData.map here, ideally we should be doing something like this:

Suggested change
const samplesViaSelectedCodons: SampleData[] = [];
mutationData.map(val => {
val.map(m => {
samplesViaSelectedCodons.push({
patientId: m.patientId,
studyId: m.studyId,
sampleId: m.sampleId,
value: m.keyword,
});
});
});
return samplesViaSelectedCodons;
return _.flatten(mutationData).map(m =>
({
patientId: m.patientId,
studyId: m.studyId,
sampleId: m.sampleId,
value: m.keyword,
})
);

@@ -178,6 +178,10 @@ export default class StudyViewPage extends React.Component<
let hashString: string = hash || getBrowserWindow().studyPageFilter;
delete (window as any).studyPageFilter;

this.store.mutationMapperFF = query['test']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this a placeholder for a feature flag?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

@@ -358,6 +375,7 @@ export type StudyViewURLQuery = {
filterValues?: string;
sharedGroups?: string;
sharedCustomData?: string;
test?: string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

placeholder for feature flag?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

readonly genes = remoteData<Gene[]>({
await: () => [],
invoke: async () => {
let geneData: Gene[] = [];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to define a variable, we can just return the value from the map function.

invoke: async () => {
let mutations: Mutation[] = [];

this.visibleMutationPlotGenes.map(gene => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should use the value returned by map function instead of defining a redundant mutations variable

@@ -2568,8 +2601,70 @@ export class StudyViewPageStore
);
}

mutationMapperFF = true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should be more clear with variable naming, something like mutationMapperFeatureEnabled would be better

@@ -80,6 +86,7 @@ export interface ChartControls {
isShowNAChecked?: boolean;
showNAToggle?: boolean;
showSwapAxes?: boolean;
showResultsPageButton?: boolean;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's make it more clear, something like

Suggested change
showResultsPageButton?: boolean;
showMutationDiagramResultsPageButton?: boolean;

value: string;
};

interface DefaultMutationMapperStoreConfig {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we really need to duplicate DefaultMutationMapperStoreConfig? We can probably reuse the existing one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, the package does not have DefaultMutationMapperStoreConfig exported, so needed to create a copy on our frontend app.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can export DefaultMutationMapperStoreConfig from the package's index.tsx. We already made some modifications to the package itself, so it should okay to modify the index.tsx as well.

tableType: FreqColumnTypeEnum
) => void;
selectedMutationPlotGenes?: string[];
mutationMapperFF?: boolean;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to name this property better. something like enableMutationDiagramButton

@@ -95,6 +101,9 @@ export type MultiSelectionTableProps = BaseMultiSelectionTableProps & {
selectedGenes: string[];
onGeneSelect: (hugoGeneSymbol: string) => void;
columns: MultiSelectionTableColumn[];
setOperationsButtonText: string;
selectedMutationPlotGenes?: string[];
mutationMapperFF?: boolean;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, we need a better name

src/routes.tsx Outdated
@@ -377,7 +377,7 @@ export const makeRoutes = () => {
})}
/>
<Route
path="/results/:tab?"
path="/results/:tab"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need to modify this file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, this is a mistake. I will revert this.

@aditygrg2 aditygrg2 changed the title Mutation Plot Diagram on Study View - Draft PR Mutation Plot Diagram on Study View - GSoC Sep 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants