Skip to content

Commit

Permalink
Merge pull request #4520 from dippindots/fix-9988
Browse files Browse the repository at this point in the history
Study view km plot optimization
alisman authored Apr 27, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
2 parents 88899c2 + dd9a466 commit 3f0ac3d
Showing 18 changed files with 370 additions and 65 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/pages/groupComparison/Survival.tsx
Original file line number Diff line number Diff line change
@@ -771,6 +771,7 @@ export default class Survival extends React.Component<ISurvivalProps, {}> {
this.selectedSurvivalPlotPrefix
]
}
compactMode={false}
/>
</div>
</div>
156 changes: 102 additions & 54 deletions src/pages/resultsView/survival/SurvivalChart.tsx
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@ import {
filterScatterData,
SurvivalPlotFilters,
SurvivalSummary,
SURVIVAL_COMPACT_MODE_THRESHOLD,
} from './SurvivalUtil';
import { toConditionalPrecision } from 'shared/lib/NumberUtils';
import { getPatientViewUrl } from '../../../shared/api/urls';
@@ -88,10 +89,13 @@ export interface ISurvivalChartProps {
legendLabelComponent?: any;
yAxisTickCount?: number;
xAxisTickCount?: number;
// Compact mode will hide censoring dots in the chart and do binning based on configuration
compactMode?: boolean;
}

const MIN_GROUP_SIZE_FOR_LOGRANK = 10;
// Start to down sampling when there are more than 1000 dots in the plot.
// TODO: 1000 samples is our current setting, but we should make this configurable
const SURVIVAL_DOWN_SAMPLING_THRESHOLD = 1000;

@observer
@@ -269,15 +273,30 @@ export default class SurvivalChart
// The filter is only available when user zooms in the plot.
@computed
get scatterData(): GroupedScatterData {
return filterScatterData(
this.unfilteredScatterData,
this.scatterFilter,
{
xDenominator: this.downSamplingDenominators.x,
yDenominator: this.downSamplingDenominators.y,
threshold: SURVIVAL_DOWN_SAMPLING_THRESHOLD,
}
);
if (this.props.compactMode) {
return filterScatterData(
this.unfilteredScatterData,
this.scatterFilter,
{
xDenominator: this.downSamplingDenominators.x,
yDenominator: this.downSamplingDenominators.y,
threshold: SURVIVAL_DOWN_SAMPLING_THRESHOLD,
enableCensoringCross: false,
floorTimeToMonth: true,
}
);
} else {
return filterScatterData(
this.unfilteredScatterData,
this.scatterFilter,
{
xDenominator: this.downSamplingDenominators.x,
yDenominator: this.downSamplingDenominators.y,
threshold: SURVIVAL_DOWN_SAMPLING_THRESHOLD,
enableCensoringCross: true,
}
);
}
}

public static defaultProps: Partial<ISurvivalChartProps> = {
@@ -790,6 +809,77 @@ export default class SurvivalChart
));
}

@computed get tooltipContent() {
return (
<div>
Patient ID:{' '}
<a
href={getPatientViewUrl(
this.tooltipModel.datum.studyId,
this.tooltipModel.datum.patientId
)}
target="_blank"
>
{this.tooltipModel.datum.patientId}
</a>
<br />
{!!this.props.showCurveInTooltip && [
`Curve: ${this.tooltipModel.datum.group}`,
<br />,
]}
{this.props.yLabelTooltip}:{' '}
{this.tooltipModel.datum.y.toFixed(2)}%<br />
{this.tooltipModel.datum.status
? this.props.xLabelWithEventTooltip
: this.props.xLabelWithoutEventTooltip}
: {this.tooltipModel.datum.x.toFixed(2)} months{' '}
{this.tooltipModel.datum.status ? '' : '(censored)'}
<br />
{this.props.analysisClinicalAttribute && (
<span>
{this.props.analysisClinicalAttribute.displayName}:{' '}
{
this.props.patientToAnalysisGroups[
this.tooltipModel.datum.uniquePatientKey
]
}
</span>
)}
<br />
Number of patients at risk: {this.tooltipModel.datum.atRisk}
</div>
);
}

@computed get compactTooltipContent() {
return (
<div>
Events during [{this.tooltipModel.datum.x},
{this.tooltipModel.datum.x + 1}) months
<br />
{this.tooltipModel.datum.numberOfEvents !== undefined && (
<>
Patients with an event:{' '}
{this.tooltipModel.datum.numberOfEvents}
</>
)}
<br />
{this.tooltipModel.datum.numberOfCensored !== undefined && (
<>
Censored patients:{' '}
{this.tooltipModel.datum.numberOfCensored}
</>
)}
<br />
<br />% event free at interval end:{' '}
{this.tooltipModel.datum.y.toFixed(2)}%
<br />
Patients at risk at interval end:{' '}
{this.tooltipModel.datum.atRisk}
</div>
);
}

public render() {
if (
_.flatten(_.values(this.props.sortedGroupedSurvivals)).length === 0
@@ -829,51 +919,9 @@ export default class SurvivalChart
onMouseEnter={this.tooltipMouseEnter}
onMouseLeave={this.tooltipMouseLeave}
>
<div>
Patient ID:{' '}
<a
href={getPatientViewUrl(
this.tooltipModel.datum.studyId,
this.tooltipModel.datum.patientId
)}
target="_blank"
>
{this.tooltipModel.datum.patientId}
</a>
<br />
{!!this.props.showCurveInTooltip && [
`Curve: ${this.tooltipModel.datum.group}`,
<br />,
]}
{this.props.yLabelTooltip}:{' '}
{this.tooltipModel.datum.y.toFixed(2)}%<br />
{this.tooltipModel.datum.status
? this.props.xLabelWithEventTooltip
: this.props.xLabelWithoutEventTooltip}
: {this.tooltipModel.datum.x.toFixed(2)} months{' '}
{this.tooltipModel.datum.status
? ''
: '(censored)'}
<br />
{this.props.analysisClinicalAttribute && (
<span>
{
this.props.analysisClinicalAttribute
.displayName
}
:{' '}
{
this.props.patientToAnalysisGroups[
this.tooltipModel.datum
.uniquePatientKey
]
}
</span>
)}
<br />
Number of patients at risk:{' '}
{this.tooltipModel.datum.atRisk}
</div>
{this.props.compactMode
? this.compactTooltipContent
: this.tooltipContent}
</Popover>
)}
{this.props.showTable && (
Loading

0 comments on commit 3f0ac3d

Please sign in to comment.