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

ACTIN-292: Add Chromosomal Rearrangements #612

Merged
merged 9 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from 8 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.hartwig.hmftools.datamodel.purple;

import org.immutables.gson.Gson;
import org.immutables.value.Value;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

@Gson.TypeAdapters
@Value.Immutable
@Value.Style(passAnnotations = { NotNull.class, Nullable.class })
public interface ChromosomalRearrangements
{
boolean hasTrisomy1q();

boolean hasCodeletion1p19q();
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ public interface PurpleRecord
@NotNull
PurpleCharacteristics characteristics();

@NotNull
ChromosomalRearrangements chromosomalRearrangements();

@NotNull
List<PurpleDriver> somaticDrivers();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,11 @@
"allSomaticGeneCopyNumbers": [],
"allSomaticGainsLosses": [],
"reportableSomaticGainsLosses": [],
"suspectGeneCopyNumbersWithLOH": []
"suspectGeneCopyNumbersWithLOH": [],
"chromosomalRearrangements": {
"hasTrisomy1q": false,
"hasCodeletion1p19q": false
}
},
"linx": {
"allSomaticStructuralVariants": [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,11 @@
"maxCopyNumber": 1.2,
"minMinorAlleleCopyNumber": 0.4
}
]
],
"chromosomalRearrangements": {
"hasTrisomy1q": false,
"hasCodeletion1p19q": false
}
},
"linx": {
"allSomaticStructuralVariants": [
Expand Down
10 changes: 7 additions & 3 deletions orange-datamodel/src/test/resources/real.orange.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"sampleId": "Test",
"samplingDate": {
"year": 2024,
"month": 8,
"day": 1
"month": 9,
"day": 12
},
"experimentType": "WHOLE_GENOME",
"configuredPrimaryTumor": [
Expand Down Expand Up @@ -736,7 +736,11 @@
],
"reportableGermlineFullLosses": [],
"allGermlineLossOfHeterozygosities": [],
"reportableGermlineLossOfHeterozygosities": []
"reportableGermlineLossOfHeterozygosities": [],
"chromosomalRearrangements": {
"hasTrisomy1q": false,
"hasCodeletion1p19q": false
}
},
"linx": {
"somaticDrivers": [
Expand Down
4 changes: 4 additions & 0 deletions orange/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ interesting and added to the report:
A maximum of 10 additional gains (sorted by minimum copy number) and 10 additional losses are reported as potentially interesting:
- For a band with more than one gene amplified, the gene with the highest minimum copy number is picked.
- For a band with a loss that has no losses reported in this band already, an arbitrary gene is picked.
- Potentially interesting chromosomal rearrangements:
1. 1q trisomy: In case 98% of 1q has copy number > 2.8 AND 90% of 1q has copy number < 3.5
2. 1p19q co-deletion: In case 98% of 1p and 98% of 19q have MACN < 0.2
- Other potentially relevant fusions. A maximum of 10 additional fusions (picked arbitrarily) are reported as potentially interesting:
1. Any fusion that is not reported and has a reported type other than NONE.
2. Any fusion in a gene that is configured as an oncogene in the driver gene panel.
Expand Down Expand Up @@ -264,6 +267,7 @@ investigate potential causes for QC failure.
- Upcoming:
- Add presence of tumor stats to quality control page and to orange-datamodel
- Ensure only exonic variants that are phased with reported variants are shown in 'potentially interesting' section
- Add potentially interesting chromosomal rearrangements (1q trisomy and 1p19q co-deletion) to report
- [3.7.0](https://github.com/hartwigmedical/hmftools/releases/tag/orange-v3.7.0):
- Add unreported reason to fusions in ORANGE
- Add etiology information to signatures and sort by allocation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@
import com.hartwig.hmftools.common.drivercatalog.panel.DriverGene;
import com.hartwig.hmftools.common.drivercatalog.panel.DriverGeneFile;
import com.hartwig.hmftools.common.ensemblcache.EnsemblDataCache;
import com.hartwig.hmftools.common.metrics.BamFlagStats;
import com.hartwig.hmftools.common.metrics.BamMetricsSummary;
import com.hartwig.hmftools.common.fusion.KnownFusionCache;
import com.hartwig.hmftools.common.genome.refgenome.RefGenomeVersion;
import com.hartwig.hmftools.common.hla.LilacSummaryData;
import com.hartwig.hmftools.common.isofox.IsofoxData;
import com.hartwig.hmftools.common.isofox.IsofoxDataLoader;
import com.hartwig.hmftools.common.linx.LinxData;
import com.hartwig.hmftools.common.linx.LinxDataLoader;
import com.hartwig.hmftools.common.metrics.BamFlagStats;
import com.hartwig.hmftools.common.metrics.BamMetricsSummary;
import com.hartwig.hmftools.common.peach.PeachGenotype;
import com.hartwig.hmftools.common.peach.PeachGenotypeFile;
import com.hartwig.hmftools.common.pipeline.PipelineVersionFile;
Expand Down Expand Up @@ -68,6 +68,7 @@
import com.hartwig.hmftools.orange.algo.plot.DummyPlotManager;
import com.hartwig.hmftools.orange.algo.plot.FileBasedPlotManager;
import com.hartwig.hmftools.orange.algo.plot.PlotManager;
import com.hartwig.hmftools.orange.algo.purple.ChromosomalRearrangementsDeterminer;
import com.hartwig.hmftools.orange.algo.purple.GermlineGainLossFactory;
import com.hartwig.hmftools.orange.algo.purple.GermlineLossOfHeterozygosityFactory;
import com.hartwig.hmftools.orange.algo.purple.PurpleData;
Expand Down Expand Up @@ -207,8 +208,10 @@ public OrangeRecord run(@NotNull OrangeConfig config) throws Exception
PurpleVariantFactory purpleVariantFactory = new PurpleVariantFactory(pave);
GermlineGainLossFactory germlineGainLossFactory = new GermlineGainLossFactory(ensemblDataCache);
GermlineLossOfHeterozygosityFactory germlineLOHFactory = new GermlineLossOfHeterozygosityFactory(ensemblDataCache);
ChromosomalRearrangementsDeterminer chromosomalRearrangementsDeterminer =
ChromosomalRearrangementsDeterminer.createForRefGenomeVersion(config.refGenomeVersion());
PurpleInterpreter purpleInterpreter = new PurpleInterpreter(purpleVariantFactory, germlineGainLossFactory,
germlineLOHFactory, driverGenes, linx, chord, config.convertGermlineToSomatic());
germlineLOHFactory, driverGenes, linx, chromosomalRearrangementsDeterminer, chord, config.convertGermlineToSomatic());
PurpleRecord purple = purpleInterpreter.interpret(purpleData);

ImmuneEscapeRecord immuneEscape = ImmuneEscapeInterpreter.interpret(purple, linx);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package com.hartwig.hmftools.orange.algo.purple;

import java.util.List;

import com.google.common.annotations.VisibleForTesting;
import com.hartwig.hmftools.common.genome.refgenome.RefGenomeCoordinates;
import com.hartwig.hmftools.common.genome.refgenome.RefGenomeFunctions;
import com.hartwig.hmftools.common.purple.PurpleCopyNumber;
import com.hartwig.hmftools.datamodel.orange.OrangeRefGenomeVersion;

import org.jetbrains.annotations.NotNull;

public final class ChromosomalRearrangementsDeterminer
{
@NotNull
private final RefGenomeCoordinates refGenomeCoordinates;
cbruel marked this conversation as resolved.
Show resolved Hide resolved

@NotNull
public static ChromosomalRearrangementsDeterminer createForRefGenomeVersion(@NotNull final OrangeRefGenomeVersion refGenomeVersion)
{
return new ChromosomalRearrangementsDeterminer(resolveRefGenomeCoordinates(refGenomeVersion));
}

@VisibleForTesting
ChromosomalRearrangementsDeterminer(@NotNull final RefGenomeCoordinates refGenomeCoordinates)
{
this.refGenomeCoordinates = refGenomeCoordinates;
}

private static final double LOWER_THRESHOLD_TRISOMY = 2.8;
private static final double UPPER_THRESHOLD_TRISOMY = 3.5;
private static final double THRESHOLD_DELETION = 0.2;
private static final double LOWER_LIMIT_PERCENTAGE_TRISOMY = 0.98;
private static final double UPPER_LIMIT_PERCENTAGE_TRISOMY = 0.90;
private static final double UPPER_LIMIT_PERCENTAGE_DELETION = 0.98;

private static final String CHR_1 = "1";
private static final String CHR_19 = "19";
cbruel marked this conversation as resolved.
Show resolved Hide resolved

public boolean determine1qTrisomy(@NotNull List<PurpleCopyNumber> allSomaticCopyNumbers)
{
int centromere1 = refGenomeCoordinates.centromere(CHR_1);
int length1QArm = refGenomeCoordinates.length(CHR_1) - centromere1;
int lengthAboveLowerThreshold = 0;
int lengthBelowUpperThreshold = 0;

for(PurpleCopyNumber copyNumber : allSomaticCopyNumbers)
{
String chromosome = RefGenomeFunctions.stripChrPrefix(copyNumber.chromosome());
if(chromosome.equals(CHR_1) && overlapsWithQArm(copyNumber, centromere1))
{
int length = copyNumber.start() > centromere1 ? copyNumber.length() : copyNumber.end() - centromere1 + 1;

if(copyNumber.averageTumorCopyNumber() > LOWER_THRESHOLD_TRISOMY)
{
lengthAboveLowerThreshold += length;
}
if(copyNumber.averageTumorCopyNumber() < UPPER_THRESHOLD_TRISOMY)
{
lengthBelowUpperThreshold += length;
}
}
}

return (double) lengthAboveLowerThreshold / length1QArm > LOWER_LIMIT_PERCENTAGE_TRISOMY
&& (double) lengthBelowUpperThreshold / length1QArm > UPPER_LIMIT_PERCENTAGE_TRISOMY;
}

public boolean determine1p19qCodeletion(@NotNull List<PurpleCopyNumber> allSomaticCopyNumbers)
{
int centromere1 = refGenomeCoordinates.centromere(CHR_1);
int centromere19 = refGenomeCoordinates.centromere(CHR_19);
int length19QArm = refGenomeCoordinates.length(CHR_19) - centromere19;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@kduyvesteyn Should there be a "+ 1" added here? Same in line 43.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@kduyvesteyn I made some drawings and looked into how this is calculated in SvUtilities, and figured it out :)

int lengthDeletion1p = 0;
int lengthDeletionChr19 = 0;

for(PurpleCopyNumber copyNumber : allSomaticCopyNumbers)
{
String chromosome = RefGenomeFunctions.stripChrPrefix(copyNumber.chromosome());
if(chromosome.equals(CHR_1) && copyNumber.start() < centromere1 && copyNumber.minorAlleleCopyNumber() < THRESHOLD_DELETION)
{
int length = copyNumber.end() < centromere1 ? copyNumber.length() : centromere1 - copyNumber.start() + 1;
lengthDeletion1p += length;
}
if(chromosome.equals(CHR_19) && overlapsWithQArm(copyNumber, centromere19)
&& copyNumber.minorAlleleCopyNumber() < THRESHOLD_DELETION)
{
int length = copyNumber.start() > centromere19 ? copyNumber.length() : copyNumber.end() - centromere19 + 1;
lengthDeletionChr19 += length;
}
}

return (double) lengthDeletion1p / centromere1 > UPPER_LIMIT_PERCENTAGE_DELETION
&& (double) lengthDeletionChr19 / length19QArm > UPPER_LIMIT_PERCENTAGE_DELETION;
}

@NotNull
private static RefGenomeCoordinates resolveRefGenomeCoordinates(@NotNull OrangeRefGenomeVersion refGenomeVersion)
{
return refGenomeVersion == OrangeRefGenomeVersion.V38 ? RefGenomeCoordinates.COORDS_38 : RefGenomeCoordinates.COORDS_37;
}

private static boolean overlapsWithQArm(@NotNull PurpleCopyNumber copyNumber, int centromere)
{
return copyNumber.start() > centromere || (copyNumber.start() < centromere && centromere < copyNumber.end());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
import com.hartwig.hmftools.datamodel.linx.LinxBreakendType;
import com.hartwig.hmftools.datamodel.linx.LinxRecord;
import com.hartwig.hmftools.datamodel.linx.LinxSvAnnotation;
import com.hartwig.hmftools.datamodel.purple.ChromosomalRearrangements;
import com.hartwig.hmftools.datamodel.purple.ImmutableChromosomalRearrangements;
import com.hartwig.hmftools.datamodel.purple.ImmutablePurpleCharacteristics;
import com.hartwig.hmftools.datamodel.purple.ImmutablePurpleFit;
import com.hartwig.hmftools.datamodel.purple.ImmutablePurpleGainLoss;
Expand Down Expand Up @@ -68,21 +70,26 @@ public class PurpleInterpreter
private final List<DriverGene> driverGenes;
@NotNull
private final LinxRecord linx;
@NotNull
private final ChromosomalRearrangementsDeterminer chromosomalRearrangementsDeterminer;
@Nullable
private final ChordData chord;
boolean convertGermlineToSomatic;

public PurpleInterpreter(@NotNull final PurpleVariantFactory purpleVariantFactory,
@NotNull final GermlineGainLossFactory germlineGainLossFactory,
@NotNull final GermlineLossOfHeterozygosityFactory germlineLossOfHeterozygosityFactory,
@NotNull final List<DriverGene> driverGenes, @NotNull final LinxRecord linx, @Nullable final ChordData chord,
@NotNull final List<DriverGene> driverGenes, @NotNull final LinxRecord linx,
@NotNull ChromosomalRearrangementsDeterminer chromosomalRearrangementsDeterminer,
@Nullable final ChordData chord,
boolean convertGermlineToSomatic)
{
this.purpleVariantFactory = purpleVariantFactory;
this.germlineGainLossFactory = germlineGainLossFactory;
this.germlineLossOfHeterozygosityFactory = germlineLossOfHeterozygosityFactory;
this.driverGenes = driverGenes;
this.linx = linx;
this.chromosomalRearrangementsDeterminer = chromosomalRearrangementsDeterminer;
this.chord = chord;
this.convertGermlineToSomatic = convertGermlineToSomatic;
}
Expand Down Expand Up @@ -186,6 +193,7 @@ public PurpleRecord interpret(@NotNull PurpleData purple)
.reportableGermlineFullLosses(reportableGermlineFullLosses)
.allGermlineLossOfHeterozygosities(allGermlineLossOfHeterozygosities)
.reportableGermlineLossOfHeterozygosities(reportableGermlineLossOfHeterozygosities)
.chromosomalRearrangements(createChromosomalRearrangements(purple, chromosomalRearrangementsDeterminer))
.build();
}

Expand Down Expand Up @@ -444,4 +452,14 @@ private static PurpleCharacteristics createCharacteristics(@NotNull PurpleData p
.svTumorMutationalBurden(purple.purityContext().svTumorMutationalBurden())
.build();
}

@NotNull
private static ChromosomalRearrangements createChromosomalRearrangements(@NotNull PurpleData purple,
@NotNull ChromosomalRearrangementsDeterminer chromosomalRearrangementsDeterminer)
{
return ImmutableChromosomalRearrangements.builder()
.hasTrisomy1q(chromosomalRearrangementsDeterminer.determine1qTrisomy(purple.allSomaticCopyNumbers()))
.hasCodeletion1p19q(chromosomalRearrangementsDeterminer.determine1p19qCodeletion(purple.allSomaticCopyNumbers()))
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.hartwig.hmftools.datamodel.linx.FusionLikelihoodType;
import com.hartwig.hmftools.datamodel.linx.LinxFusion;
import com.hartwig.hmftools.datamodel.orange.OrangeRecord;
import com.hartwig.hmftools.datamodel.purple.ChromosomalRearrangements;
import com.hartwig.hmftools.datamodel.purple.CopyNumberInterpretation;
import com.hartwig.hmftools.datamodel.purple.PurpleDriver;
import com.hartwig.hmftools.datamodel.purple.PurpleGainLoss;
Expand All @@ -23,6 +24,7 @@
import com.hartwig.hmftools.orange.report.interpretation.PurpleQCInterpretation;
import com.hartwig.hmftools.orange.report.interpretation.VariantDedup;
import com.hartwig.hmftools.orange.report.tables.BreakendTable;
import com.hartwig.hmftools.orange.report.tables.ChromosomalRearrangementsTable;
import com.hartwig.hmftools.orange.report.tables.DnaFusionTable;
import com.hartwig.hmftools.orange.report.tables.GainLossTable;
import com.hartwig.hmftools.orange.report.tables.HomozygousDisruptionTable;
Expand Down Expand Up @@ -158,6 +160,7 @@ private void addSomaticAmpDels(@NotNull Document document)
String nearDriverGainsTitle = "Potentially interesting near-driver amps";
String suspectGainsTitle = "Other regions with amps";
String suspectLossesTitle = "Regions with deletions in genes in other autosomal regions";
String chromosomalRearrangementsTitle = "Potentially interesting chromosomal rearrangements";

if(PurpleQCInterpretation.isContaminated(report.purple().fit().qc()))
{
Expand All @@ -166,6 +169,7 @@ private void addSomaticAmpDels(@NotNull Document document)
document.add(tables.createNotAvailable(nearDriverGainsTitle, contentWidth()));
document.add(tables.createNotAvailable(suspectGainsTitle, contentWidth()));
document.add(tables.createNotAvailable(suspectLossesTitle, contentWidth()));
document.add(tables.createNotAvailable(chromosomalRearrangementsTitle, contentWidth()));
}
else
{
Expand All @@ -190,6 +194,9 @@ private void addSomaticAmpDels(@NotNull Document document)
List<PurpleGainLoss> suspectLosses = selectLosses(report.purple().additionalSuspectSomaticGainsLosses());
String titleSuspectLosses = suspectLossesTitle + " (" + suspectLosses.size() + ")";
document.add(GainLossTable.build(titleSuspectLosses, contentWidth(), max10(suspectLosses), report.isofox(), reportResources));

ChromosomalRearrangements chromosomalRearrangements = report.purple().chromosomalRearrangements();
document.add(ChromosomalRearrangementsTable.build(chromosomalRearrangementsTitle, contentWidth(), chromosomalRearrangements, reportResources));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.hartwig.hmftools.orange.report.tables;

import com.hartwig.hmftools.datamodel.purple.ChromosomalRearrangements;
import com.hartwig.hmftools.orange.report.ReportResources;
import com.hartwig.hmftools.orange.report.util.Cells;
import com.hartwig.hmftools.orange.report.util.Tables;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Table;

import org.apache.logging.log4j.util.Strings;
import org.jetbrains.annotations.NotNull;

public final class ChromosomalRearrangementsTable
{
@NotNull
public static Table build(@NotNull String title, float width, @NotNull ChromosomalRearrangements chromosomalRearrangements,
@NotNull ReportResources reportResources)
{
Cells cells = new Cells(reportResources);
Table table = Tables.createContent(width,
new float[] { 2, 1, 3 },
new Cell[] { cells.createHeader("Chromosomal rearrangement"), cells.createHeader("Detected?"),
cells.createHeader(Strings.EMPTY) });

table.addCell(cells.createContent("1q trisomy"));
table.addCell(cells.createContent(chromosomalRearrangements.hasTrisomy1q() ? "Yes" : "No"));
table.addCell(cells.createContent(Strings.EMPTY));

table.addCell(cells.createContent("1p19q co-deletion"));
table.addCell(cells.createContent(chromosomalRearrangements.hasCodeletion1p19q() ? "Yes" : "No"));
table.addCell(cells.createContent(Strings.EMPTY));

return new Tables(reportResources).createWrapping(table, title);
}
}
Binary file modified orange/src/main/resources/COLO829_Targeted_TumorOnly.orange.pdf
Binary file not shown.
Binary file modified orange/src/main/resources/COLO829_WGS_TumorReference.orange.pdf
Binary file not shown.
Loading