Blended BOQA Exomiser integration - #47
Conversation
|
@leokim-l This PR is intended to work with exomiser/Exomiser#648 |
There was a problem hiding this comment.
All in all, I think this PR adds new interesting parts, addresses a lot of issues of our code structure, adds useful classes and tries to redesign several parts. However, it seems to add lots of parts that duplicate already existing solutions and it has some minor bugs here and there.
I believe if we decide the time has come to redesign a large portion of the code it would be best to sit down and talk about requirements, domain objects and their relationships and map this out together. Alternatively, I could try to take what is in here and adapt it within the branch I was working on. This would roughly mean using the sealed interfaces and the new classes to obtain one implementation of Counter, one way to write out results (and not multiple overlapping classes), one way to write disease IDs and Labels without resorting to String concatenation.
| public static AlgorithmParameters defaultParams() { | ||
| return AlgorithmParameters.create(DEFAULT_ALPHA, DEFAULT_BETA); | ||
| } | ||
|
|
There was a problem hiding this comment.
create() with no arguments does exactly this, though a dedicated method might be better. If we want this dedicated defaultParams() method, then we should get rid of
| .map(TermId::of) | ||
| .collect(toSet()); | ||
| return new DefaultPatientData(randomId, observedTidSet); | ||
| } |
There was a problem hiding this comment.
Why is this method in the interface? To the best of my understanding it should be moved to the class DefaultPatientData. Also, we should consider adding something like
so we avoid misalignments between the HPO Ontology being used by BOQA and the terms being passed from the outside world. We trust Exomiser, of course, but BOQA should internally in its classes enforce this somehow, in my opinion.
There was a problem hiding this comment.
There are now two TargetDisease classes, this one and the one in the diseases directory. There is no clear "better one", both have a little bit more with respect to their minimum common denominator...
| TargetDisease t1 = diseasePair.get(0); | ||
| TargetDisease t2 = diseasePair.get(1); | ||
| String diseaseId = t1.diseaseId() + "-" + t2.diseaseId(); | ||
| String diseaseLabel = t1.diseaseLabel() + "-" + t2.diseaseLabel(); | ||
| String geneId = t1.geneId() + "-" + t2.geneId(); | ||
| String symbol = t1.geneSymbol() + "-" + t2.geneSymbol(); |
There was a problem hiding this comment.
I think we should abandon this strategy for generating IDs and labels, it has already backfired... In one place we write classes and methods that do string concatenation, then someplace else we need to undo it (for sure this happened in the analysis code). Something similar also happened in phenopacket2prompt, where a regex based naming convention based on an ID managed to generate LOTS of issues in downstream analysis. I would prefer being cautious when unpacking ID fields and generating new IDs manually editing strings. We could generate a sort of structured ID, maybe something like DiseaseInfo, containing a List or Set of (ID, Label) pairs.
| } | ||
|
|
||
| /** | ||
| * COPIED FROM BoqaSetCounter. After testing we should make this a default in the interface! |
There was a problem hiding this comment.
Why should this be a default in the interface? I would not want to put source code that may change in an interface, I believe
There was a problem hiding this comment.
Test differences seem harmless and simply done to conform to the new signatures, all good here
| TermId diseaseId = TermId.of(s.diseaseId()); | ||
| HpoDisease hpoDisease = hpoDiseaseMap.get(diseaseId); | ||
| if (hpoDisease != null) { | ||
| Set<TermId> observed = new HashSet<>(); | ||
| for (HpoDiseaseAnnotation hda : hpoDisease.presentAnnotations() ){ | ||
| observed.add(hda.id()); | ||
| } | ||
| diseaseLayers.put(diseaseId, observed); | ||
| } | ||
| } | ||
| case CandidateDisease.Blended b -> { | ||
| List<TargetDisease> list = b.components(); | ||
| Set<TermId> observed = new HashSet<>(); | ||
| for (TargetDisease td: list) { | ||
| TermId diseaseId = TermId.of(td.diseaseId()); | ||
| HpoDisease hpoDisease = hpoDiseaseMap.get(diseaseId); | ||
| if (hpoDisease != null) { | ||
| for (HpoDiseaseAnnotation hda : hpoDisease.presentAnnotations() ){ | ||
| observed.add(hda.id()); | ||
| } |
There was a problem hiding this comment.
This seems wrong, disease layers as per BoqaSetCounter do not only contain observed HPOs, but also the induced graph above them. The counter is agnostic to a single disease or a bleneded one, there should not be differences beyond (maybe) in bookkeeping. I like the idea of using sealed interfaces and changing some parts of our code that are a bit messy, but this re-implementation is missing:
- Filtering for terms below
Phenotypic Abnormality - Adding the induced HPO terms to
diseaseLayers
I'd suggest, if changing the Counter is necessary, to adapt the existing implementation to the sealed interface.
There was a problem hiding this comment.
Looks OK, though consider the comments I had in the components that are used in here, and that I have not explicitly tested this. I would also hesitate to throw out what @hansenp wrote without having taken the time to understand it better. It seems a bit convoluted, but it might contain some things we are missing.
Maybe rather than removing it we mark it @deprecated and wait for him to come back from vacation before removing it?
No description provided.