From d2a4d44ff44c11da8ce639de552182019e77fa26 Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Mon, 19 Jun 2017 17:45:25 +0200 Subject: [PATCH 01/16] Detect if children can be SNP'ed together Closes #276. --- .../gui/controller/GraphController.java | 23 +- .../model/drawing/DrawableDummy.java | 4 + .../model/drawing/DrawableNode.java | 2 + .../model/drawing/DrawableSegment.java | 35 +- .../model/drawing/SubGraph.java | 8 +- .../drawing/SubGraphGenomesOnEdgeTest.java | 152 ++++++++ .../model/drawing/SubGraphSNPTest.java | 326 ++++++++++++++++++ .../model/drawing/SubGraphTest.java | 121 ------- 8 files changed, 541 insertions(+), 130 deletions(-) create mode 100644 src/test/java/programminglife/model/drawing/SubGraphGenomesOnEdgeTest.java create mode 100644 src/test/java/programminglife/model/drawing/SubGraphSNPTest.java diff --git a/src/main/java/programminglife/gui/controller/GraphController.java b/src/main/java/programminglife/gui/controller/GraphController.java index d0fc1b9..6e13e6f 100644 --- a/src/main/java/programminglife/gui/controller/GraphController.java +++ b/src/main/java/programminglife/gui/controller/GraphController.java @@ -66,8 +66,12 @@ public void draw(int center, int radius) { subGraph.layout(); long finishTimeLayout = System.nanoTime(); - long startTimeDrawing = System.nanoTime(); + long startTimeGenome = System.nanoTime(); + subGraph.calculateGenomes(); + long finishTimeGenome = System.nanoTime(); + + long startTimeDrawing = System.nanoTime(); for (DrawableNode drawableNode : subGraph.getNodes().values()) { drawNode(drawableNode); for (DrawableNode child : subGraph.getChildren(drawableNode)) { @@ -76,6 +80,14 @@ public void draw(int center, int radius) { } long finishTimeDrawing = System.nanoTime(); + long startTimeSNP = System.nanoTime(); + for (DrawableNode d : subGraph.getNodes().values()) { + if (d.hasSNPChildren(subGraph)) { + highlightNodesByID(d.getChildren(), Color.GOLD); + } + } + long finishTimeSNP = System.nanoTime(); + centerOnNodeId(center); highlightNode(center, Color.DARKORANGE); @@ -84,15 +96,22 @@ public void draw(int center, int radius) { long differenceTimeDrawing = finishTimeDrawing - startTimeDrawing; long differenceTimeLayout = finishTimeLayout - startLayoutTime; long differenceTimeSubGraph = finishTimeSubGraph - startTimeSubGraph; + long differenceTimeSNP = finishTimeSNP - startTimeSNP; + long differenceTimeGenomes = finishTimeGenome - startTimeGenome; long msDifferenceTimeProgram = differenceTimeProgram / 1000000; long millisecondTimeDrawing = differenceTimeDrawing / 1000000; long msDifferenceTimeLayout = differenceTimeLayout / 1000000; long msDifferenceTimeSubGraph = differenceTimeSubGraph / 1000000; + long msDifferenceTimeSNP = differenceTimeSNP / 1000000; + long msDifferenceTimeGenomes = differenceTimeGenomes / 1000000; Console.println("time of SubGraph: " + msDifferenceTimeSubGraph); - Console.println("Time of Drawing: " + millisecondTimeDrawing); Console.println("Time of layout: " + msDifferenceTimeLayout); + Console.println("Time to find genomes: " + msDifferenceTimeGenomes); + Console.println("Time of drawing: " + millisecondTimeDrawing); + Console.println("Time to find SNPs: " + msDifferenceTimeSNP); Console.println("Time of Total Program: " + msDifferenceTimeProgram); + } /** diff --git a/src/main/java/programminglife/model/drawing/DrawableDummy.java b/src/main/java/programminglife/model/drawing/DrawableDummy.java index 0d81c64..96d9767 100644 --- a/src/main/java/programminglife/model/drawing/DrawableDummy.java +++ b/src/main/java/programminglife/model/drawing/DrawableDummy.java @@ -95,6 +95,10 @@ public void colorize(SubGraph sg) { this.setStroke(strokeColor); } + public boolean hasSNPChildren(SubGraph subGraph) { + return false; + } + @Override public void setLocation(int x, int y) { this.setX(x); diff --git a/src/main/java/programminglife/model/drawing/DrawableNode.java b/src/main/java/programminglife/model/drawing/DrawableNode.java index ad5cf8c..6711e8d 100644 --- a/src/main/java/programminglife/model/drawing/DrawableNode.java +++ b/src/main/java/programminglife/model/drawing/DrawableNode.java @@ -94,6 +94,8 @@ final boolean isDrawDimensionsUpToDate() { */ public abstract String details(); + public abstract boolean hasSNPChildren(SubGraph subGraph); + /** * Color this according to contents. * @param sg the {@link SubGraph} this {@link DrawableNode} is in diff --git a/src/main/java/programminglife/model/drawing/DrawableSegment.java b/src/main/java/programminglife/model/drawing/DrawableSegment.java index e2e9402..94998b1 100644 --- a/src/main/java/programminglife/model/drawing/DrawableSegment.java +++ b/src/main/java/programminglife/model/drawing/DrawableSegment.java @@ -4,7 +4,10 @@ import programminglife.model.GenomeGraph; import programminglife.model.XYCoordinate; -import java.util.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.NoSuchElementException; +import java.util.Set; import java.util.stream.Collectors; /** @@ -160,6 +163,36 @@ public DrawableNode getChildSegment() { return this; // Don't ask! } + @Override + public boolean hasSNPChildren(SubGraph subGraph) { + // A SNP-able node has: + if (children.size() < 2) { // - at least 2 children + return false; + } else if (children.size() > 4) { // - at most 4 children + return false; + } else if (children.stream().anyMatch(id -> id < 1)) { // - no dummy children + return false; + } else if (children.stream().anyMatch(id -> getGraph().getSequenceLength(id) != 1)) { // - only children of length 1 + return false; + } else { + Collection childNodes = subGraph.getChildren(this); + Collection childParents = childNodes.stream() + .map(subGraph::getParents) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + Collection childChildren = childNodes.stream() + .map(subGraph::getChildren) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + if (childChildren.size() != 1) { // - all children have 1 and the same child + return false; + } else if (childParents.size() != 1) { // - all children have 1 and the same parent + return false; + } + } + return true; + } + public double getGenomeFraction() { return this.getGraph().getGenomeFraction(this.getIdentifier()); } diff --git a/src/main/java/programminglife/model/drawing/SubGraph.java b/src/main/java/programminglife/model/drawing/SubGraph.java index de198f0..821e42f 100644 --- a/src/main/java/programminglife/model/drawing/SubGraph.java +++ b/src/main/java/programminglife/model/drawing/SubGraph.java @@ -64,10 +64,6 @@ public SubGraph(DrawableSegment centerNode, int radius) { if (!this.nodes.containsKey(centerNode.getIdentifier())) { this.nodes.put(centerNode.getIdentifier(), centerNode); } - - long genomeTime = System.nanoTime(); - this.calculateGenomes(); - Console.println("Time to find genomes through edge: " + (System.nanoTime() - genomeTime) / 1000000); } // TODO: change findParents and findChildren to reliably only find nodes with a *longest* path of at most radius. @@ -486,7 +482,7 @@ Map> calculateGenomes(DrawableNode parent) { * Calculate genomes through edge, based on topological ordering and node-genome information. * @return a {@link Map} of {@link Map Maps} of collections of genomes through links */ - Map>> calculateGenomes() { + public Map>> calculateGenomes() { Map>> genomes = new LinkedHashMap<>(); // For every node in the subGraph for (DrawableNode parent : this.nodes.values()) { @@ -523,7 +519,7 @@ public void setRadius(int radius) { // when getting smaller: drop nodes outside new radius. } - public LinkedHashMap getNodes() { + public LinkedHashMap getNodes() { return this.nodes; } diff --git a/src/test/java/programminglife/model/drawing/SubGraphGenomesOnEdgeTest.java b/src/test/java/programminglife/model/drawing/SubGraphGenomesOnEdgeTest.java new file mode 100644 index 0000000..60ffa15 --- /dev/null +++ b/src/test/java/programminglife/model/drawing/SubGraphGenomesOnEdgeTest.java @@ -0,0 +1,152 @@ +package programminglife.model.drawing; + +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import programminglife.model.GenomeGraph; +import programminglife.utility.InitFXThread; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +/** + * Created by toinehartman on 19/06/2017. + */ +public class SubGraphGenomesOnEdgeTest { + GenomeGraph g; + + @BeforeClass + public static void setUpClass() throws Exception { + InitFXThread.setupClass(); + } + + @Before + public void setUp() throws Exception { + this.g = new GenomeGraph("genomes on edge test"); + } + + @After + public void tearDown() throws Exception { + g.removeCache(); + } + + @Test + public void genomesOnSimpleInsertion() throws Exception { + // [3]--- 0 2 3 ---[5] + // \ / + // 1 4 / + // \ / + // [4]-- 1 4 + + for (int i = 0; i <= 4; i++) { + g.addGenome("GENOME" + i); + } + + for (int i = 3; i <= 5; i++) { + g.replaceNode(i); + g.setSequence(i, "A"); + } + + g.setGenomes(3, new int[] {0, 1, 2, 3, 4}); + g.setGenomes(4, new int[] {1, 4}); + g.setGenomes(5, new int[] {0, 1, 2, 3, 4}); + + g.addEdge(3,4); + g.addEdge(4,5); + g.addEdge(3,5); + + g.cacheLastEdges(); + + SubGraph sg = new SubGraph(new DrawableSegment(g, 3), 5); + Map>> genomes = sg.calculateGenomes(); + + DrawableNode seg3 = sg.getNodes().get(3); + DrawableNode seg4 = sg.getNodes().get(4); + DrawableNode seg5 = sg.getNodes().get(5); + + assertEquals(new HashSet<>(Arrays.asList(1, 4)), new HashSet<>(genomes.get(seg3).get(seg4))); + assertEquals(new HashSet<>(Arrays.asList(0, 2, 3)), new HashSet<>(genomes.get(seg3).get(seg5))); + assertEquals(new HashSet<>(Arrays.asList(1, 4)), new HashSet<>(genomes.get(seg4).get(seg5))); + } + + @Test + public void genomesOnComplexInsertion() throws Exception { + for (int i = 0; i <= 5; i++) { + g.addGenome("GENOME" + i); + } + + for (int i = 3; i <= 6; i++) { + g.replaceNode(i); + g.setSequence(i, "A"); + } + + g.setGenomes(3, new int[] {0, 1, 2, 3, 4, 5}); + g.setGenomes(4, new int[] {2, 5}); + g.setGenomes(5, new int[] {0, 1, 5}); + g.setGenomes(6, new int[] {0, 1, 2, 3, 4, 5}); + + for (int[] edge : new int[][] {{3, 4}, {3, 5}, {3, 6}, {4, 5}, {4, 6}, {5, 6}}) { + g.addEdge(edge[0], edge[1]); + } + + g.cacheLastEdges(); + + SubGraph sg = new SubGraph(new DrawableSegment(g, 3), 5); + Map>> genomes = sg.calculateGenomes(); + + DrawableNode seg3 = sg.getNodes().get(3); + DrawableNode seg4 = sg.getNodes().get(4); + DrawableNode seg5 = sg.getNodes().get(5); + DrawableNode seg6 = sg.getNodes().get(6); + + assertEquals(new HashSet<>(Arrays.asList(2, 5)), new HashSet<>(genomes.get(seg3).get(seg4))); + assertEquals(new HashSet<>(Arrays.asList(0, 1)), new HashSet<>(genomes.get(seg3).get(seg5))); + assertEquals(new HashSet<>(Arrays.asList(3, 4)), new HashSet<>(genomes.get(seg3).get(seg6))); + assertEquals(new HashSet<>(Arrays.asList(2)), new HashSet<>(genomes.get(seg4).get(seg6))); + assertEquals(new HashSet<>(Arrays.asList(5)), new HashSet<>(genomes.get(seg4).get(seg5))); + assertEquals(new HashSet<>(Arrays.asList(0, 1, 5)), new HashSet<>(genomes.get(seg5).get(seg6))); + } + + @Test + public void genomesOnStoppingGenome() throws Exception { + for (int i = 0; i <= 3; i++) { + g.addGenome("GENOME" + i); + } + + for (int i = 3; i <= 6; i++) { + g.replaceNode(i); + g.setSequence(i, "A"); + } + + g.setGenomes(3, new int[] {0, 1, 2, 3}); + g.setGenomes(4, new int[] {0, 1, 2}); + g.setGenomes(5, new int[] {0, 3}); + g.setGenomes(6, new int[] {0, 2, 3}); + + for (int[] edge : new int[][] {{3, 4}, {3, 5}, {4, 5}, {4, 6}, {5, 6}}) { + g.addEdge(edge[0], edge[1]); + } + + g.cacheLastEdges(); + + SubGraph sg = new SubGraph(new DrawableSegment(g, 3), 5); + + DrawableNode seg3 = sg.getNodes().get(3); + DrawableNode seg4 = sg.getNodes().get(4); + DrawableNode seg5 = sg.getNodes().get(5); + DrawableNode seg6 = sg.getNodes().get(6); + + Map>> genomes = sg.calculateGenomes(); + + assertEquals(new HashSet<>(Arrays.asList(0, 1, 2)), new HashSet<>(genomes.get(seg3).get(seg4))); + assertEquals(new HashSet<>(Arrays.asList(3)), new HashSet<>(genomes.get(seg3).get(seg5))); + assertEquals(new HashSet<>(Arrays.asList(2)), new HashSet<>(genomes.get(seg4).get(seg6))); + assertEquals(new HashSet<>(Arrays.asList(0)), new HashSet<>(genomes.get(seg4).get(seg5))); + assertEquals(new HashSet<>(Arrays.asList(0, 3)), new HashSet<>(genomes.get(seg5).get(seg6))); + } +} diff --git a/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java b/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java new file mode 100644 index 0000000..a81c6f1 --- /dev/null +++ b/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java @@ -0,0 +1,326 @@ +package programminglife.model.drawing; + +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import programminglife.model.GenomeGraph; +import programminglife.utility.InitFXThread; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Created by toinehartman on 19/06/2017. + */ +public class SubGraphSNPTest { + GenomeGraph g; + + @BeforeClass + public static void setUpClass() throws Exception { + InitFXThread.setupClass(); + } + + @Before + public void setUp() throws Exception { + g = new GenomeGraph("snp test graph"); + } + + @After + public void tearDown() throws Exception { + g.removeCache(); + } + + @Test + public void simpleSNP() throws Exception { + g.addGenome("GENOME"); + + g.replaceNode(0); + g.replaceNode(1); + g.replaceNode(2); + g.replaceNode(3); + + g.setSequence(0, "ATCG"); + g.setSequence(1, "A"); + g.setSequence(2, "C"); + g.setSequence(3, "GCTA"); + + for (int i = 0; i <= 3; i++) + g.setGenomes(i, new int[] {0}); + + g.addEdge(0, 1); + g.addEdge(0, 2); + g.addEdge(1, 3); + g.addEdge(2, 3); + g.cacheLastEdges(); + + SubGraph sg = new SubGraph(new DrawableSegment(g, 0), 5); + DrawableNode seg0 = sg.getNodes().get(0); + DrawableNode seg1 = sg.getNodes().get(1); + DrawableNode seg2 = sg.getNodes().get(2); + DrawableNode seg3 = sg.getNodes().get(3); + + assertTrue(seg0.hasSNPChildren(sg)); + assertFalse(seg1.hasSNPChildren(sg)); + assertFalse(seg2.hasSNPChildren(sg)); + assertFalse(seg3.hasSNPChildren(sg)); + + g.removeCache(); + } + + @Test + public void quadSNP() throws Exception { + g.addGenome("GENOME"); + + g.replaceNode(0); + g.replaceNode(1); + g.replaceNode(2); + g.replaceNode(3); + g.replaceNode(4); + g.replaceNode(5); + + g.setSequence(0, "ATCG"); + g.setSequence(1, "A"); + g.setSequence(2, "C"); + g.setSequence(3, "G"); + g.setSequence(4, "T"); + g.setSequence(5, "GCTA"); + + for (int i = 0; i <= 5; i++) + g.setGenomes(i, new int[] {0}); + + g.addEdge(0, 1); + g.addEdge(0, 2); + g.addEdge(0, 3); + g.addEdge(0, 4); + g.addEdge(1, 5); + g.addEdge(2, 5); + g.addEdge(3, 5); + g.addEdge(4, 5); + g.cacheLastEdges(); + + SubGraph sg = new SubGraph(new DrawableSegment(g, 0), 5); + DrawableNode seg0 = sg.getNodes().get(0); + DrawableNode seg1 = sg.getNodes().get(1); + DrawableNode seg2 = sg.getNodes().get(2); + DrawableNode seg3 = sg.getNodes().get(3); + DrawableNode seg4 = sg.getNodes().get(4); + DrawableNode seg5 = sg.getNodes().get(5); + + assertTrue(seg0.hasSNPChildren(sg)); + assertFalse(seg1.hasSNPChildren(sg)); + assertFalse(seg2.hasSNPChildren(sg)); + assertFalse(seg3.hasSNPChildren(sg)); + assertFalse(seg4.hasSNPChildren(sg)); + assertFalse(seg5.hasSNPChildren(sg)); + + g.removeCache(); + } + + @Test + public void fiveSNP() throws Exception { + g.addGenome("GENOME"); + + g.replaceNode(0); + g.replaceNode(1); + g.replaceNode(2); + g.replaceNode(3); + g.replaceNode(4); + g.replaceNode(5); + g.replaceNode(6); + + g.setSequence(0, "ATCG"); + g.setSequence(1, "A"); + g.setSequence(2, "C"); + g.setSequence(3, "G"); + g.setSequence(4, "T"); + g.setSequence(5, "T"); + g.setSequence(6, "GCTA"); + + for (int i = 0; i <= 6; i++) + g.setGenomes(i, new int[] {0}); + + g.addEdge(0, 1); + g.addEdge(0, 2); + g.addEdge(0, 3); + g.addEdge(0, 4); + g.addEdge(0, 5); + g.addEdge(1, 6); + g.addEdge(2, 6); + g.addEdge(3, 6); + g.addEdge(4, 6); + g.addEdge(5, 6); + g.cacheLastEdges(); + + SubGraph sg = new SubGraph(new DrawableSegment(g, 0), 5); + DrawableNode seg0 = sg.getNodes().get(0); + DrawableNode seg1 = sg.getNodes().get(1); + DrawableNode seg2 = sg.getNodes().get(2); + DrawableNode seg3 = sg.getNodes().get(3); + DrawableNode seg4 = sg.getNodes().get(4); + DrawableNode seg5 = sg.getNodes().get(5); + DrawableNode seg6 = sg.getNodes().get(6); + + assertFalse(seg0.hasSNPChildren(sg)); + assertFalse(seg1.hasSNPChildren(sg)); + assertFalse(seg2.hasSNPChildren(sg)); + assertFalse(seg3.hasSNPChildren(sg)); + assertFalse(seg4.hasSNPChildren(sg)); + assertFalse(seg5.hasSNPChildren(sg)); + assertFalse(seg6.hasSNPChildren(sg)); + + g.removeCache(); + } + + @Test + public void singleSNP() throws Exception { + g.addGenome("GENOME"); + + g.replaceNode(0); + g.replaceNode(1); + g.replaceNode(2); + + g.setSequence(0, "ATCG"); + g.setSequence(1, "A"); + g.setSequence(2, "CTGA"); + + for (int i = 0; i <= 2; i++) + g.setGenomes(i, new int[] {0}); + + g.addEdge(0, 1); + g.addEdge(1, 2); + g.cacheLastEdges(); + + SubGraph sg = new SubGraph(new DrawableSegment(g, 0), 5); + DrawableNode seg0 = sg.getNodes().get(0); + DrawableNode seg1 = sg.getNodes().get(1); + DrawableNode seg2 = sg.getNodes().get(2); + + assertFalse(seg0.hasSNPChildren(sg)); + assertFalse(seg1.hasSNPChildren(sg)); + assertFalse(seg2.hasSNPChildren(sg)); + + g.removeCache(); + } + + @Test + public void multipleNucleotideSNP() throws Exception { + g.addGenome("GENOME"); + + g.replaceNode(0); + g.replaceNode(1); + g.replaceNode(2); + g.replaceNode(3); + + g.setSequence(0, "ATCG"); + g.setSequence(1, "AT"); + g.setSequence(2, "C"); + g.setSequence(3, "GCTA"); + + for (int i = 0; i <= 3; i++) + g.setGenomes(i, new int[] {0}); + + g.addEdge(0, 1); + g.addEdge(0, 2); + g.addEdge(1, 3); + g.addEdge(2, 3); + g.cacheLastEdges(); + + SubGraph sg = new SubGraph(new DrawableSegment(g, 0), 5); + DrawableNode seg0 = sg.getNodes().get(0); + DrawableNode seg1 = sg.getNodes().get(1); + DrawableNode seg2 = sg.getNodes().get(2); + DrawableNode seg3 = sg.getNodes().get(3); + + assertFalse(seg0.hasSNPChildren(sg)); + assertFalse(seg1.hasSNPChildren(sg)); + assertFalse(seg2.hasSNPChildren(sg)); + assertFalse(seg3.hasSNPChildren(sg)); + + g.removeCache(); + } + + @Test + public void simpleSNPWithParent() throws Exception { + g.addGenome("GENOME"); + + g.replaceNode(0); + g.replaceNode(1); + g.replaceNode(2); + g.replaceNode(3); + g.replaceNode(4); + + g.setSequence(0, "G"); + g.setSequence(1, "ATCG"); + g.setSequence(2, "A"); + g.setSequence(3, "C"); + g.setSequence(4, "GCTA"); + + for (int i = 0; i <= 4; i++) + g.setGenomes(i, new int[] {0}); + + g.addEdge(0, 2); + g.addEdge(1, 2); + g.addEdge(1, 3); + g.addEdge(3, 4); + g.addEdge(2, 4); + g.cacheLastEdges(); + + SubGraph sg = new SubGraph(new DrawableSegment(g, 0), 5); + DrawableNode seg0 = sg.getNodes().get(0); + DrawableNode seg1 = sg.getNodes().get(1); + DrawableNode seg2 = sg.getNodes().get(2); + DrawableNode seg3 = sg.getNodes().get(3); + DrawableNode seg4 = sg.getNodes().get(4); + + assertFalse(seg0.hasSNPChildren(sg)); + assertFalse(seg1.hasSNPChildren(sg)); + assertFalse(seg2.hasSNPChildren(sg)); + assertFalse(seg3.hasSNPChildren(sg)); + assertFalse(seg4.hasSNPChildren(sg)); + + g.removeCache(); + } + + @Test + public void simpleSNPWithChild() throws Exception { + g.addGenome("GENOME"); + + g.replaceNode(0); + g.replaceNode(1); + g.replaceNode(2); + g.replaceNode(3); + g.replaceNode(4); + + g.setSequence(0, "ATCG"); + g.setSequence(1, "A"); + g.setSequence(2, "C"); + g.setSequence(3, "GCTA"); + g.setSequence(4, "G"); + + for (int i = 0; i <= 4; i++) + g.setGenomes(i, new int[] {0}); + + g.addEdge(0, 1); + g.addEdge(0, 2); + g.addEdge(1, 3); + g.addEdge(2, 3); + g.addEdge(2, 4); + g.cacheLastEdges(); + + SubGraph sg = new SubGraph(new DrawableSegment(g, 0), 5); + DrawableNode seg0 = sg.getNodes().get(0); + DrawableNode seg1 = sg.getNodes().get(1); + DrawableNode seg2 = sg.getNodes().get(2); + DrawableNode seg3 = sg.getNodes().get(3); + DrawableNode seg4 = sg.getNodes().get(4); + + assertFalse(seg0.hasSNPChildren(sg)); + assertFalse(seg1.hasSNPChildren(sg)); + assertFalse(seg2.hasSNPChildren(sg)); + assertFalse(seg3.hasSNPChildren(sg)); + assertFalse(seg4.hasSNPChildren(sg)); + + g.removeCache(); + } +} diff --git a/src/test/java/programminglife/model/drawing/SubGraphTest.java b/src/test/java/programminglife/model/drawing/SubGraphTest.java index 496ca9d..aa43aa5 100644 --- a/src/test/java/programminglife/model/drawing/SubGraphTest.java +++ b/src/test/java/programminglife/model/drawing/SubGraphTest.java @@ -96,125 +96,4 @@ public void topoSortTest() throws Exception { found.add(n); } } - - @Test - public void genomesOnSimpleInsertion() { - // [3]--- 0 2 3 ---[5] - // \ / - // 1 4 / - // \ / - // [4]-- 1 4 - - GenomeGraph g = new GenomeGraph("test-simple"); - - for (int i = 0; i <= 4; i++) { - g.addGenome("GENOME" + i); - } - - for (int i = 3; i <= 5; i++) { - g.replaceNode(i); - g.setSequence(i, "A"); - } - - g.setGenomes(3, new int[] {0, 1, 2, 3, 4}); - g.setGenomes(4, new int[] {1, 4}); - g.setGenomes(5, new int[] {0, 1, 2, 3, 4}); - - g.addEdge(3,4); - g.addEdge(4,5); - g.addEdge(3,5); - - g.cacheLastEdges(); - - SubGraph sg = new SubGraph(new DrawableSegment(g, 3), 5); - Map>> genomes = sg.calculateGenomes(); - - DrawableNode seg3 = sg.getNodes().get(3); - DrawableNode seg4 = sg.getNodes().get(4); - DrawableNode seg5 = sg.getNodes().get(5); - - assertEquals(new HashSet<>(Arrays.asList(1, 4)), new HashSet<>(genomes.get(seg3).get(seg4))); - assertEquals(new HashSet<>(Arrays.asList(0, 2, 3)), new HashSet<>(genomes.get(seg3).get(seg5))); - assertEquals(new HashSet<>(Arrays.asList(1, 4)), new HashSet<>(genomes.get(seg4).get(seg5))); - } - - @Test - public void genomesOnComplexInsertion() { - GenomeGraph g = new GenomeGraph("test-complex"); - - for (int i = 0; i <= 5; i++) { - g.addGenome("GENOME" + i); - } - - for (int i = 3; i <= 6; i++) { - g.replaceNode(i); - g.setSequence(i, "A"); - } - - g.setGenomes(3, new int[] {0, 1, 2, 3, 4, 5}); - g.setGenomes(4, new int[] {2, 5}); - g.setGenomes(5, new int[] {0, 1, 5}); - g.setGenomes(6, new int[] {0, 1, 2, 3, 4, 5}); - - for (int[] edge : new int[][] {{3, 4}, {3, 5}, {3, 6}, {4, 5}, {4, 6}, {5, 6}}) { - g.addEdge(edge[0], edge[1]); - } - - g.cacheLastEdges(); - - SubGraph sg = new SubGraph(new DrawableSegment(g, 3), 5); - Map>> genomes = sg.calculateGenomes(); - - DrawableNode seg3 = sg.getNodes().get(3); - DrawableNode seg4 = sg.getNodes().get(4); - DrawableNode seg5 = sg.getNodes().get(5); - DrawableNode seg6 = sg.getNodes().get(6); - - assertEquals(new HashSet<>(Arrays.asList(2, 5)), new HashSet<>(genomes.get(seg3).get(seg4))); - assertEquals(new HashSet<>(Arrays.asList(0, 1)), new HashSet<>(genomes.get(seg3).get(seg5))); - assertEquals(new HashSet<>(Arrays.asList(3, 4)), new HashSet<>(genomes.get(seg3).get(seg6))); - assertEquals(new HashSet<>(Arrays.asList(2)), new HashSet<>(genomes.get(seg4).get(seg6))); - assertEquals(new HashSet<>(Arrays.asList(5)), new HashSet<>(genomes.get(seg4).get(seg5))); - assertEquals(new HashSet<>(Arrays.asList(0, 1, 5)), new HashSet<>(genomes.get(seg5).get(seg6))); - } - - @Test - public void genomesOnStoppingGenome() { - GenomeGraph g = new GenomeGraph("test-stopping"); - - for (int i = 0; i <= 3; i++) { - g.addGenome("GENOME" + i); - } - - for (int i = 3; i <= 6; i++) { - g.replaceNode(i); - g.setSequence(i, "A"); - } - - g.setGenomes(3, new int[] {0, 1, 2, 3}); - g.setGenomes(4, new int[] {0, 1, 2}); - g.setGenomes(5, new int[] {0, 3}); - g.setGenomes(6, new int[] {0, 2, 3}); - - for (int[] edge : new int[][] {{3, 4}, {3, 5}, {4, 5}, {4, 6}, {5, 6}}) { - g.addEdge(edge[0], edge[1]); - } - - g.cacheLastEdges(); - - SubGraph sg = new SubGraph(new DrawableSegment(g, 3), 5); - - DrawableNode seg3 = sg.getNodes().get(3); - DrawableNode seg4 = sg.getNodes().get(4); - DrawableNode seg5 = sg.getNodes().get(5); - DrawableNode seg6 = sg.getNodes().get(6); - - Map>> genomes = sg.calculateGenomes(); - - assertEquals(new HashSet<>(Arrays.asList(0, 1, 2)), new HashSet<>(genomes.get(seg3).get(seg4))); - assertEquals(new HashSet<>(Arrays.asList(3)), new HashSet<>(genomes.get(seg3).get(seg5))); - assertEquals(new HashSet<>(Arrays.asList(2)), new HashSet<>(genomes.get(seg4).get(seg6))); - assertEquals(new HashSet<>(Arrays.asList(0)), new HashSet<>(genomes.get(seg4).get(seg5))); - assertEquals(new HashSet<>(Arrays.asList(0, 3)), new HashSet<>(genomes.get(seg5).get(seg6))); - } } From 0699bffe6ee08f860a0160d5e657cb0809b723bf Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Mon, 19 Jun 2017 18:38:37 +0200 Subject: [PATCH 02/16] Start on replacing SNPs. Problem with layout and/or hierarchy --- .../gui/controller/GraphController.java | 11 -- .../model/drawing/DrawableDummy.java | 4 +- .../model/drawing/DrawableNode.java | 7 +- .../model/drawing/DrawableSNP.java | 152 ++++++++++++++++++ .../model/drawing/DrawableSegment.java | 20 +-- .../model/drawing/SubGraph.java | 20 +++ .../model/drawing/SubGraphSNPTest.java | 72 ++++----- 7 files changed, 227 insertions(+), 59 deletions(-) create mode 100644 src/main/java/programminglife/model/drawing/DrawableSNP.java diff --git a/src/main/java/programminglife/gui/controller/GraphController.java b/src/main/java/programminglife/gui/controller/GraphController.java index 6e13e6f..afc7ece 100644 --- a/src/main/java/programminglife/gui/controller/GraphController.java +++ b/src/main/java/programminglife/gui/controller/GraphController.java @@ -80,14 +80,6 @@ public void draw(int center, int radius) { } long finishTimeDrawing = System.nanoTime(); - long startTimeSNP = System.nanoTime(); - for (DrawableNode d : subGraph.getNodes().values()) { - if (d.hasSNPChildren(subGraph)) { - highlightNodesByID(d.getChildren(), Color.GOLD); - } - } - long finishTimeSNP = System.nanoTime(); - centerOnNodeId(center); highlightNode(center, Color.DARKORANGE); @@ -96,19 +88,16 @@ public void draw(int center, int radius) { long differenceTimeDrawing = finishTimeDrawing - startTimeDrawing; long differenceTimeLayout = finishTimeLayout - startLayoutTime; long differenceTimeSubGraph = finishTimeSubGraph - startTimeSubGraph; - long differenceTimeSNP = finishTimeSNP - startTimeSNP; long differenceTimeGenomes = finishTimeGenome - startTimeGenome; long msDifferenceTimeProgram = differenceTimeProgram / 1000000; long millisecondTimeDrawing = differenceTimeDrawing / 1000000; long msDifferenceTimeLayout = differenceTimeLayout / 1000000; long msDifferenceTimeSubGraph = differenceTimeSubGraph / 1000000; - long msDifferenceTimeSNP = differenceTimeSNP / 1000000; long msDifferenceTimeGenomes = differenceTimeGenomes / 1000000; Console.println("time of SubGraph: " + msDifferenceTimeSubGraph); Console.println("Time of layout: " + msDifferenceTimeLayout); Console.println("Time to find genomes: " + msDifferenceTimeGenomes); Console.println("Time of drawing: " + millisecondTimeDrawing); - Console.println("Time to find SNPs: " + msDifferenceTimeSNP); Console.println("Time of Total Program: " + msDifferenceTimeProgram); diff --git a/src/main/java/programminglife/model/drawing/DrawableDummy.java b/src/main/java/programminglife/model/drawing/DrawableDummy.java index 96d9767..0d8d711 100644 --- a/src/main/java/programminglife/model/drawing/DrawableDummy.java +++ b/src/main/java/programminglife/model/drawing/DrawableDummy.java @@ -95,8 +95,8 @@ public void colorize(SubGraph sg) { this.setStroke(strokeColor); } - public boolean hasSNPChildren(SubGraph subGraph) { - return false; + public DrawableSegment hasSNPChildren(SubGraph subGraph) { + return null; } @Override diff --git a/src/main/java/programminglife/model/drawing/DrawableNode.java b/src/main/java/programminglife/model/drawing/DrawableNode.java index 6711e8d..6ce2529 100644 --- a/src/main/java/programminglife/model/drawing/DrawableNode.java +++ b/src/main/java/programminglife/model/drawing/DrawableNode.java @@ -94,7 +94,12 @@ final boolean isDrawDimensionsUpToDate() { */ public abstract String details(); - public abstract boolean hasSNPChildren(SubGraph subGraph); + /** + * Checks if the children of this {@link DrawableNode} can be merged as a SNP. + * @param subGraph the {@link SubGraph} this {@link DrawableNode} is in + * @return null if children cannot be SNP'ed, child of SNP otherwise + */ + public abstract DrawableSegment hasSNPChildren(SubGraph subGraph); /** * Color this according to contents. diff --git a/src/main/java/programminglife/model/drawing/DrawableSNP.java b/src/main/java/programminglife/model/drawing/DrawableSNP.java new file mode 100644 index 0000000..6d52d68 --- /dev/null +++ b/src/main/java/programminglife/model/drawing/DrawableSNP.java @@ -0,0 +1,152 @@ +package programminglife.model.drawing; + +import javafx.scene.paint.Color; +import programminglife.model.XYCoordinate; + +import java.util.Collection; +import java.util.Collections; +import java.util.NoSuchElementException; + +/** + * Created by toinehartman on 19/06/2017. + */ +public class DrawableSNP extends DrawableNode { + private DrawableNode parent; + private DrawableNode child; + final private Collection mutations; + + /** + * Construct a {@link DrawableNode}. + * + * @param segments the Segments in this bubble + */ + DrawableSNP(DrawableNode parent, DrawableNode child, Collection segments) { + super(segments.iterator().next().getGraph(), -segments.hashCode()); + + this.parent = parent; + this.child = child; + this.mutations = segments; + } + + /** + * Get the IDs of children of this. + * + * @return IDs of drawable children + */ + @Override + public Collection getChildren() { + return Collections.singleton(this.child.getIdentifier()); + } + + /** + * Get the IDs of parents of this. + * + * @return IDs of drawable parents. + */ + @Override + public Collection getParents() { + return Collections.singleton(this.parent.getIdentifier()); + } + + /** + * Replace a parent with another one. + * + * @param oldParent the parent to replace + * @param newParent the new parent + */ + @Override + void replaceParent(DrawableNode oldParent, DrawableNode newParent) { + if (this.parent.getIdentifier() == oldParent.getIdentifier()) { + this.parent = newParent; + } else { + throw new NoSuchElementException( + String.format("The node to be replaced (%d) is not the parent of this SNP (%d).", + oldParent.getIdentifier(), this.getIdentifier())); + } + } + + /** + * Replace child with another one. + * + * @param oldChild the child to replace + * @param newChild the new child + */ + @Override + void replaceChild(DrawableNode oldChild, DrawableNode newChild) { + if (this.child.getIdentifier() == oldChild.getIdentifier()) { + this.child = newChild; + } else { + throw new NoSuchElementException( + String.format("The node to be replaced (%d) is not the parent of this SNP (%d).", + oldChild.getIdentifier(), this.getIdentifier())); + } + } + + /** + * Information {@link String} about this. + * + * @return info + */ + @Override + public String details() { + return this.mutations.toString(); + } + + @Override + public DrawableSegment hasSNPChildren(SubGraph subGraph) { + return null; + } + + /** + * Color this according to contents. + * + * @param sg the {@link SubGraph} this {@link DrawableNode} is in + */ + @Override + public void colorize(SubGraph sg) { + this.setStroke(Color.RED); + this.setStrokeWidth(4.d); + } + + /** + * Set the location to draw this. + * + * @param x the x location + * @param y the y location + */ + @Override + void setLocation(int x, int y) { + + } + + /** + * Set the size of this drawing. + */ + @Override + protected void setDrawDimensions() { + int segmentLength = 1; + int width, height; + + width = 10 + (int) Math.pow(segmentLength, 1.0 / 2); + height = NODE_HEIGHT; + + this.setSize(new XYCoordinate(width, height)); + this.setDrawDimensionsUpToDate(true); + } + + void setSize(XYCoordinate size) { + this.setWidth(size.getX()); + this.setHeight(size.getY()); + this.setDrawDimensionsUpToDate(true); + } + + @Override + public DrawableNode getParentSegment() { + return parent; + } + + @Override + public DrawableNode getChildSegment() { + return child; + } +} diff --git a/src/main/java/programminglife/model/drawing/DrawableSegment.java b/src/main/java/programminglife/model/drawing/DrawableSegment.java index 94998b1..0d673fd 100644 --- a/src/main/java/programminglife/model/drawing/DrawableSegment.java +++ b/src/main/java/programminglife/model/drawing/DrawableSegment.java @@ -164,33 +164,35 @@ public DrawableNode getChildSegment() { } @Override - public boolean hasSNPChildren(SubGraph subGraph) { + public DrawableSegment hasSNPChildren(SubGraph subGraph) { + Collection childChildren; + // A SNP-able node has: if (children.size() < 2) { // - at least 2 children - return false; + return null; } else if (children.size() > 4) { // - at most 4 children - return false; + return null; } else if (children.stream().anyMatch(id -> id < 1)) { // - no dummy children - return false; + return null; } else if (children.stream().anyMatch(id -> getGraph().getSequenceLength(id) != 1)) { // - only children of length 1 - return false; + return null; } else { Collection childNodes = subGraph.getChildren(this); Collection childParents = childNodes.stream() .map(subGraph::getParents) .flatMap(Collection::stream) .collect(Collectors.toSet()); - Collection childChildren = childNodes.stream() + childChildren = childNodes.stream() .map(subGraph::getChildren) .flatMap(Collection::stream) .collect(Collectors.toSet()); if (childChildren.size() != 1) { // - all children have 1 and the same child - return false; + return null; } else if (childParents.size() != 1) { // - all children have 1 and the same parent - return false; + return null; } } - return true; + return (DrawableSegment) childChildren.iterator().next(); } public double getGenomeFraction() { diff --git a/src/main/java/programminglife/model/drawing/SubGraph.java b/src/main/java/programminglife/model/drawing/SubGraph.java index 821e42f..1160314 100644 --- a/src/main/java/programminglife/model/drawing/SubGraph.java +++ b/src/main/java/programminglife/model/drawing/SubGraph.java @@ -64,6 +64,26 @@ public SubGraph(DrawableSegment centerNode, int radius) { if (!this.nodes.containsKey(centerNode.getIdentifier())) { this.nodes.put(centerNode.getIdentifier(), centerNode); } + + this.replaceSNPs(); + } + + private void replaceSNPs() { + DrawableSegment child; + Map nodesCopy = new LinkedHashMap<>(this.nodes); + for (Map.Entry entry : nodesCopy.entrySet()) { + DrawableNode parent = entry.getValue(); + if ((child = parent.hasSNPChildren(this)) != null) { + System.out.println("Can be SNP'ed: " + parent); + DrawableSNP snp = new DrawableSNP(parent, child, this.getChildren(parent)); + this.nodes.remove(entry.getKey()); + this.nodes.put(snp.getIdentifier(), snp); + parent.getChildren().clear(); + parent.getChildren().add(snp.getIdentifier()); + child.getParents().clear(); + child.getParents().add(snp.getIdentifier()); + } + } } // TODO: change findParents and findChildren to reliably only find nodes with a *longest* path of at most radius. diff --git a/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java b/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java index a81c6f1..979d868 100644 --- a/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java +++ b/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java @@ -7,8 +7,8 @@ import programminglife.model.GenomeGraph; import programminglife.utility.InitFXThread; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; /** * Created by toinehartman on 19/06/2017. @@ -60,10 +60,10 @@ public void simpleSNP() throws Exception { DrawableNode seg2 = sg.getNodes().get(2); DrawableNode seg3 = sg.getNodes().get(3); - assertTrue(seg0.hasSNPChildren(sg)); - assertFalse(seg1.hasSNPChildren(sg)); - assertFalse(seg2.hasSNPChildren(sg)); - assertFalse(seg3.hasSNPChildren(sg)); + assertNotNull(seg0.hasSNPChildren(sg)); + assertNull(seg1.hasSNPChildren(sg)); + assertNull(seg2.hasSNPChildren(sg)); + assertNull(seg3.hasSNPChildren(sg)); g.removeCache(); } @@ -107,12 +107,12 @@ public void quadSNP() throws Exception { DrawableNode seg4 = sg.getNodes().get(4); DrawableNode seg5 = sg.getNodes().get(5); - assertTrue(seg0.hasSNPChildren(sg)); - assertFalse(seg1.hasSNPChildren(sg)); - assertFalse(seg2.hasSNPChildren(sg)); - assertFalse(seg3.hasSNPChildren(sg)); - assertFalse(seg4.hasSNPChildren(sg)); - assertFalse(seg5.hasSNPChildren(sg)); + assertNotNull(seg0.hasSNPChildren(sg)); + assertNull(seg1.hasSNPChildren(sg)); + assertNull(seg2.hasSNPChildren(sg)); + assertNull(seg3.hasSNPChildren(sg)); + assertNull(seg4.hasSNPChildren(sg)); + assertNull(seg5.hasSNPChildren(sg)); g.removeCache(); } @@ -161,13 +161,13 @@ public void fiveSNP() throws Exception { DrawableNode seg5 = sg.getNodes().get(5); DrawableNode seg6 = sg.getNodes().get(6); - assertFalse(seg0.hasSNPChildren(sg)); - assertFalse(seg1.hasSNPChildren(sg)); - assertFalse(seg2.hasSNPChildren(sg)); - assertFalse(seg3.hasSNPChildren(sg)); - assertFalse(seg4.hasSNPChildren(sg)); - assertFalse(seg5.hasSNPChildren(sg)); - assertFalse(seg6.hasSNPChildren(sg)); + assertNull(seg0.hasSNPChildren(sg)); + assertNull(seg1.hasSNPChildren(sg)); + assertNull(seg2.hasSNPChildren(sg)); + assertNull(seg3.hasSNPChildren(sg)); + assertNull(seg4.hasSNPChildren(sg)); + assertNull(seg5.hasSNPChildren(sg)); + assertNull(seg6.hasSNPChildren(sg)); g.removeCache(); } @@ -196,9 +196,9 @@ public void singleSNP() throws Exception { DrawableNode seg1 = sg.getNodes().get(1); DrawableNode seg2 = sg.getNodes().get(2); - assertFalse(seg0.hasSNPChildren(sg)); - assertFalse(seg1.hasSNPChildren(sg)); - assertFalse(seg2.hasSNPChildren(sg)); + assertNull(seg0.hasSNPChildren(sg)); + assertNull(seg1.hasSNPChildren(sg)); + assertNull(seg2.hasSNPChildren(sg)); g.removeCache(); } @@ -232,10 +232,10 @@ public void multipleNucleotideSNP() throws Exception { DrawableNode seg2 = sg.getNodes().get(2); DrawableNode seg3 = sg.getNodes().get(3); - assertFalse(seg0.hasSNPChildren(sg)); - assertFalse(seg1.hasSNPChildren(sg)); - assertFalse(seg2.hasSNPChildren(sg)); - assertFalse(seg3.hasSNPChildren(sg)); + assertNull(seg0.hasSNPChildren(sg)); + assertNull(seg1.hasSNPChildren(sg)); + assertNull(seg2.hasSNPChildren(sg)); + assertNull(seg3.hasSNPChildren(sg)); g.removeCache(); } @@ -273,11 +273,11 @@ public void simpleSNPWithParent() throws Exception { DrawableNode seg3 = sg.getNodes().get(3); DrawableNode seg4 = sg.getNodes().get(4); - assertFalse(seg0.hasSNPChildren(sg)); - assertFalse(seg1.hasSNPChildren(sg)); - assertFalse(seg2.hasSNPChildren(sg)); - assertFalse(seg3.hasSNPChildren(sg)); - assertFalse(seg4.hasSNPChildren(sg)); + assertNull(seg0.hasSNPChildren(sg)); + assertNull(seg1.hasSNPChildren(sg)); + assertNull(seg2.hasSNPChildren(sg)); + assertNull(seg3.hasSNPChildren(sg)); + assertNull(seg4.hasSNPChildren(sg)); g.removeCache(); } @@ -315,11 +315,11 @@ public void simpleSNPWithChild() throws Exception { DrawableNode seg3 = sg.getNodes().get(3); DrawableNode seg4 = sg.getNodes().get(4); - assertFalse(seg0.hasSNPChildren(sg)); - assertFalse(seg1.hasSNPChildren(sg)); - assertFalse(seg2.hasSNPChildren(sg)); - assertFalse(seg3.hasSNPChildren(sg)); - assertFalse(seg4.hasSNPChildren(sg)); + assertNull(seg0.hasSNPChildren(sg)); + assertNull(seg1.hasSNPChildren(sg)); + assertNull(seg2.hasSNPChildren(sg)); + assertNull(seg3.hasSNPChildren(sg)); + assertNull(seg4.hasSNPChildren(sg)); g.removeCache(); } From 42f0af4067f0b404a4b38cecd4a820f8ba37f84c Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Tue, 20 Jun 2017 15:33:33 +0200 Subject: [PATCH 03/16] Replace bubbles by SNPs. Known bug: sometimes, replaceParent on a DrawableDummy causes problems. --- .../model/drawing/DrawableNode.java | 5 +- .../model/drawing/DrawableSNP.java | 70 +++++++++++-------- .../model/drawing/DrawableSegment.java | 17 +---- .../model/drawing/SubGraph.java | 10 +-- 4 files changed, 52 insertions(+), 50 deletions(-) diff --git a/src/main/java/programminglife/model/drawing/DrawableNode.java b/src/main/java/programminglife/model/drawing/DrawableNode.java index 6ce2529..843d7b4 100644 --- a/src/main/java/programminglife/model/drawing/DrawableNode.java +++ b/src/main/java/programminglife/model/drawing/DrawableNode.java @@ -112,7 +112,10 @@ final boolean isDrawDimensionsUpToDate() { * @param x the x location * @param y the y location */ - abstract void setLocation(int x, int y); + protected void setLocation(int x, int y) { + this.setX(x); + this.setY(y); + } /** * Set the size of this drawing. diff --git a/src/main/java/programminglife/model/drawing/DrawableSNP.java b/src/main/java/programminglife/model/drawing/DrawableSNP.java index 6d52d68..750d3a7 100644 --- a/src/main/java/programminglife/model/drawing/DrawableSNP.java +++ b/src/main/java/programminglife/model/drawing/DrawableSNP.java @@ -6,26 +6,42 @@ import java.util.Collection; import java.util.Collections; import java.util.NoSuchElementException; +import java.util.stream.Collectors; /** * Created by toinehartman on 19/06/2017. */ public class DrawableSNP extends DrawableNode { - private DrawableNode parent; - private DrawableNode child; - final private Collection mutations; + private DrawableSegment parent; + private DrawableSegment child; + final private Collection mutations; /** * Construct a {@link DrawableNode}. * - * @param segments the Segments in this bubble + * @param mutations the Segments in this bubble */ - DrawableSNP(DrawableNode parent, DrawableNode child, Collection segments) { - super(segments.iterator().next().getGraph(), -segments.hashCode()); + DrawableSNP(DrawableNode parent, DrawableNode child, Collection mutations) { + super(mutations.iterator().next().getGraph(), -mutations.hashCode()); + + if (!(parent instanceof DrawableSegment)) { + throw new IllegalArgumentException("Parent of SNP must be a Segment!"); + } else if (!(child instanceof DrawableSegment)) { + throw new IllegalArgumentException("Child of SNP must be a Segment!"); + } else if (!mutations.stream().allMatch(DrawableSegment.class::isInstance)) { + throw new IllegalArgumentException("Mutations of SNP must be Segments!"); + } + + this.parent = (DrawableSegment) parent; + this.child = (DrawableSegment) child; + this.mutations = mutations.stream().map(DrawableSegment.class::cast).collect(Collectors.toSet()); - this.parent = parent; - this.child = child; - this.mutations = segments; + this.parent.getChildren().clear(); + this.parent.getChildren().add(this.getIdentifier()); + this.child.getParents().clear(); + this.child.getParents().add(this.getIdentifier()); + + this.setDrawDimensions(); } /** @@ -56,8 +72,8 @@ public Collection getParents() { */ @Override void replaceParent(DrawableNode oldParent, DrawableNode newParent) { - if (this.parent.getIdentifier() == oldParent.getIdentifier()) { - this.parent = newParent; + if (this.parent.getIdentifier() == oldParent.getIdentifier() && newParent instanceof DrawableSegment) { + this.parent = (DrawableSegment) newParent; } else { throw new NoSuchElementException( String.format("The node to be replaced (%d) is not the parent of this SNP (%d).", @@ -73,8 +89,8 @@ void replaceParent(DrawableNode oldParent, DrawableNode newParent) { */ @Override void replaceChild(DrawableNode oldChild, DrawableNode newChild) { - if (this.child.getIdentifier() == oldChild.getIdentifier()) { - this.child = newChild; + if (this.child.getIdentifier() == oldChild.getIdentifier() && newChild instanceof DrawableSegment) { + this.child = (DrawableSegment) newChild; } else { throw new NoSuchElementException( String.format("The node to be replaced (%d) is not the parent of this SNP (%d).", @@ -104,19 +120,9 @@ public DrawableSegment hasSNPChildren(SubGraph subGraph) { */ @Override public void colorize(SubGraph sg) { - this.setStroke(Color.RED); - this.setStrokeWidth(4.d); - } - - /** - * Set the location to draw this. - * - * @param x the x location - * @param y the y location - */ - @Override - void setLocation(int x, int y) { - + this.setFill(Color.BLANCHEDALMOND); + this.setStroke(Color.DARKRED); + this.setStrokeWidth(3.5); } /** @@ -142,11 +148,19 @@ void setSize(XYCoordinate size) { @Override public DrawableNode getParentSegment() { - return parent; + return this; } @Override public DrawableNode getChildSegment() { - return child; + return this; + } + + @Override + public Collection getGenomes() { + return this.mutations.stream() + .map(DrawableSegment::getGenomes) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); } } diff --git a/src/main/java/programminglife/model/drawing/DrawableSegment.java b/src/main/java/programminglife/model/drawing/DrawableSegment.java index 0d673fd..864f8be 100644 --- a/src/main/java/programminglife/model/drawing/DrawableSegment.java +++ b/src/main/java/programminglife/model/drawing/DrawableSegment.java @@ -107,16 +107,6 @@ void setSize(XYCoordinate size) { this.setDrawDimensionsUpToDate(true); } - /** - * Set the location of the Segment. - * @param x the x location - * @param y the y location - */ - void setLocation(int x, int y) { - this.setX(x); - this.setY(y); - } - /** * getter for the width coordinate. * @return XYCoordinate. @@ -165,8 +155,6 @@ public DrawableNode getChildSegment() { @Override public DrawableSegment hasSNPChildren(SubGraph subGraph) { - Collection childChildren; - // A SNP-able node has: if (children.size() < 2) { // - at least 2 children return null; @@ -182,7 +170,7 @@ public DrawableSegment hasSNPChildren(SubGraph subGraph) { .map(subGraph::getParents) .flatMap(Collection::stream) .collect(Collectors.toSet()); - childChildren = childNodes.stream() + Collection childChildren = childNodes.stream() .map(subGraph::getChildren) .flatMap(Collection::stream) .collect(Collectors.toSet()); @@ -191,8 +179,9 @@ public DrawableSegment hasSNPChildren(SubGraph subGraph) { } else if (childParents.size() != 1) { // - all children have 1 and the same parent return null; } + + return (DrawableSegment) childChildren.iterator().next(); } - return (DrawableSegment) childChildren.iterator().next(); } public double getGenomeFraction() { diff --git a/src/main/java/programminglife/model/drawing/SubGraph.java b/src/main/java/programminglife/model/drawing/SubGraph.java index 1160314..fe8867c 100644 --- a/src/main/java/programminglife/model/drawing/SubGraph.java +++ b/src/main/java/programminglife/model/drawing/SubGraph.java @@ -74,14 +74,10 @@ private void replaceSNPs() { for (Map.Entry entry : nodesCopy.entrySet()) { DrawableNode parent = entry.getValue(); if ((child = parent.hasSNPChildren(this)) != null) { - System.out.println("Can be SNP'ed: " + parent); - DrawableSNP snp = new DrawableSNP(parent, child, this.getChildren(parent)); - this.nodes.remove(entry.getKey()); + Collection children = this.getChildren(parent); + DrawableSNP snp = new DrawableSNP(parent, child, children); + children.stream().map(DrawableNode::getIdentifier).forEach(this.nodes::remove); this.nodes.put(snp.getIdentifier(), snp); - parent.getChildren().clear(); - parent.getChildren().add(snp.getIdentifier()); - child.getParents().clear(); - child.getParents().add(snp.getIdentifier()); } } } From 074fa69202e809638c90795dd3473b20a287b398 Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Tue, 20 Jun 2017 16:21:29 +0200 Subject: [PATCH 04/16] Timing and test improvements --- .../gui/controller/GraphController.java | 71 +++++++------------ .../model/drawing/SubGraph.java | 4 +- .../model/drawing/SubGraphSNPTest.java | 5 +- 3 files changed, 29 insertions(+), 51 deletions(-) diff --git a/src/main/java/programminglife/gui/controller/GraphController.java b/src/main/java/programminglife/gui/controller/GraphController.java index afc7ece..c9b4962 100644 --- a/src/main/java/programminglife/gui/controller/GraphController.java +++ b/src/main/java/programminglife/gui/controller/GraphController.java @@ -48,59 +48,38 @@ public int getCenterNodeInt() { return this.centerNodeInt; } + private void time(String description, Runnable r) { + long start = System.nanoTime(); + r.run(); + Console.println(String.format("%s: %d ms", description, (System.nanoTime() - start) / 1000000)); + } + /** * Method to draw the subGraph decided by a center node and radius. * @param center the node of which the radius starts. * @param radius the amount of layers to be drawn. */ public void draw(int center, int radius) { - long startTimeProgram = System.nanoTime(); - DrawableSegment centerNode = new DrawableSegment(graph, center); - centerNodeInt = centerNode.getIdentifier(); - long startTimeSubGraph = System.nanoTime(); - subGraph = new SubGraph(centerNode, radius); - - long finishTimeSubGraph = System.nanoTime(); - - long startLayoutTime = System.nanoTime(); - subGraph.layout(); - long finishTimeLayout = System.nanoTime(); - - long startTimeGenome = System.nanoTime(); - subGraph.calculateGenomes(); - long finishTimeGenome = System.nanoTime(); - - - long startTimeDrawing = System.nanoTime(); - for (DrawableNode drawableNode : subGraph.getNodes().values()) { - drawNode(drawableNode); - for (DrawableNode child : subGraph.getChildren(drawableNode)) { - drawEdge(drawableNode, child); - } - } - long finishTimeDrawing = System.nanoTime(); - - centerOnNodeId(center); - highlightNode(center, Color.DARKORANGE); - - long finishTime = System.nanoTime(); - long differenceTimeProgram = finishTime - startTimeProgram; - long differenceTimeDrawing = finishTimeDrawing - startTimeDrawing; - long differenceTimeLayout = finishTimeLayout - startLayoutTime; - long differenceTimeSubGraph = finishTimeSubGraph - startTimeSubGraph; - long differenceTimeGenomes = finishTimeGenome - startTimeGenome; - long msDifferenceTimeProgram = differenceTimeProgram / 1000000; - long millisecondTimeDrawing = differenceTimeDrawing / 1000000; - long msDifferenceTimeLayout = differenceTimeLayout / 1000000; - long msDifferenceTimeSubGraph = differenceTimeSubGraph / 1000000; - long msDifferenceTimeGenomes = differenceTimeGenomes / 1000000; - Console.println("time of SubGraph: " + msDifferenceTimeSubGraph); - Console.println("Time of layout: " + msDifferenceTimeLayout); - Console.println("Time to find genomes: " + msDifferenceTimeGenomes); - Console.println("Time of drawing: " + millisecondTimeDrawing); - Console.println("Time of Total Program: " + msDifferenceTimeProgram); - + time("Total drawing", () -> { + DrawableSegment centerNode = new DrawableSegment(graph, center); + centerNodeInt = centerNode.getIdentifier(); + + time("Find subgraph", () -> subGraph = new SubGraph(centerNode, radius)); + time("Replace SNPs", subGraph::replaceSNPs); + time("Layout subgraph", subGraph::layout); + time("Calculate genomes through edges", subGraph::calculateGenomes); + time("Drawing", () -> { + for (DrawableNode drawableNode : subGraph.getNodes().values()) { + drawNode(drawableNode); + for (DrawableNode child : subGraph.getChildren(drawableNode)) { + drawEdge(drawableNode, child); + } + } + }); + centerOnNodeId(center); + highlightNode(center, Color.DARKORANGE); + }); } /** diff --git a/src/main/java/programminglife/model/drawing/SubGraph.java b/src/main/java/programminglife/model/drawing/SubGraph.java index fe8867c..9f48ffc 100644 --- a/src/main/java/programminglife/model/drawing/SubGraph.java +++ b/src/main/java/programminglife/model/drawing/SubGraph.java @@ -64,11 +64,9 @@ public SubGraph(DrawableSegment centerNode, int radius) { if (!this.nodes.containsKey(centerNode.getIdentifier())) { this.nodes.put(centerNode.getIdentifier(), centerNode); } - - this.replaceSNPs(); } - private void replaceSNPs() { + public void replaceSNPs() { DrawableSegment child; Map nodesCopy = new LinkedHashMap<>(this.nodes); for (Map.Entry entry : nodesCopy.entrySet()) { diff --git a/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java b/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java index 979d868..2f503d2 100644 --- a/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java +++ b/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java @@ -7,6 +7,7 @@ import programminglife.model.GenomeGraph; import programminglife.utility.InitFXThread; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -60,7 +61,7 @@ public void simpleSNP() throws Exception { DrawableNode seg2 = sg.getNodes().get(2); DrawableNode seg3 = sg.getNodes().get(3); - assertNotNull(seg0.hasSNPChildren(sg)); + assertEquals(seg3, seg0.hasSNPChildren(sg)); assertNull(seg1.hasSNPChildren(sg)); assertNull(seg2.hasSNPChildren(sg)); assertNull(seg3.hasSNPChildren(sg)); @@ -107,7 +108,7 @@ public void quadSNP() throws Exception { DrawableNode seg4 = sg.getNodes().get(4); DrawableNode seg5 = sg.getNodes().get(5); - assertNotNull(seg0.hasSNPChildren(sg)); + assertEquals(seg5, seg0.hasSNPChildren(sg)); assertNull(seg1.hasSNPChildren(sg)); assertNull(seg2.hasSNPChildren(sg)); assertNull(seg3.hasSNPChildren(sg)); From aaf0abcc2d83e54a7537d8e0ef1ea4c63e60ad59 Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Tue, 20 Jun 2017 17:09:05 +0200 Subject: [PATCH 05/16] Improved equals & hashCode for DrawableNode. Closes #279. --- .../model/drawing/DrawableNode.java | 17 +++++++++++++++++ .../model/drawing/DrawableSegment.java | 17 ----------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main/java/programminglife/model/drawing/DrawableNode.java b/src/main/java/programminglife/model/drawing/DrawableNode.java index 843d7b4..e33bbb4 100644 --- a/src/main/java/programminglife/model/drawing/DrawableNode.java +++ b/src/main/java/programminglife/model/drawing/DrawableNode.java @@ -30,6 +30,23 @@ public abstract class DrawableNode extends Rectangle implements Drawable { this.genomes = new LinkedHashSet<>(); } + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof DrawableNode)) return false; + + DrawableNode that = (DrawableNode) o; + if (!this.getClass().equals(that.getClass())) return false; + return this.getIdentifier() != that.getIdentifier(); + } + + @Override + public final int hashCode() { + int result = getGraph().hashCode(); + result = 31 * result + getIdentifier(); + return result; + } + /** * Get the ID. * @return the ID diff --git a/src/main/java/programminglife/model/drawing/DrawableSegment.java b/src/main/java/programminglife/model/drawing/DrawableSegment.java index 864f8be..2392973 100644 --- a/src/main/java/programminglife/model/drawing/DrawableSegment.java +++ b/src/main/java/programminglife/model/drawing/DrawableSegment.java @@ -219,23 +219,6 @@ public String toString() { + this.getLocation().getY(); } - - @Override - public boolean equals(Object other) { - if (other instanceof DrawableSegment) { - DrawableSegment that = (DrawableSegment) other; - if (that.getIdentifier() == this.getIdentifier()) { - return true; - } - } - return false; - } - - @Override - public int hashCode() { - return getIdentifier(); - } - /** * Color a {@link DrawableSegment} depending on its properties. */ From d8c83009845ed1704777321a09f25bb50573a461 Mon Sep 17 00:00:00 2001 From: Yannick Date: Tue, 20 Jun 2017 18:14:36 +0200 Subject: [PATCH 06/16] SNP is now toggable from the menu. --- .../gui/controller/GraphController.java | 13 ++++++-- .../gui/controller/GuiController.java | 30 ++++++++++++------- .../model/drawing/DrawableNode.java | 6 ++-- src/main/resources/Basic_Gui.fxml | 9 ++++-- src/test/resources/Basic_Gui.fxml | 9 ++++-- 5 files changed, 49 insertions(+), 18 deletions(-) diff --git a/src/main/java/programminglife/gui/controller/GraphController.java b/src/main/java/programminglife/gui/controller/GraphController.java index c9b4962..5014d51 100644 --- a/src/main/java/programminglife/gui/controller/GraphController.java +++ b/src/main/java/programminglife/gui/controller/GraphController.java @@ -17,7 +17,6 @@ import static javafx.scene.shape.StrokeType.OUTSIDE; /** - * Created by Martijn van Meerten on 8-5-2017. * Controller for drawing the graph. */ public class GraphController { @@ -31,6 +30,7 @@ public class GraphController { private AnchorPane anchorGraphInfo; private LinkedList oldGenomeList = new LinkedList<>(); private int centerNodeInt; + private boolean drawSNP = false; /** * Initialize controller object. @@ -65,7 +65,9 @@ public void draw(int center, int radius) { centerNodeInt = centerNode.getIdentifier(); time("Find subgraph", () -> subGraph = new SubGraph(centerNode, radius)); - time("Replace SNPs", subGraph::replaceSNPs); + if (drawSNP) { + time("Replace SNPs", subGraph::replaceSNPs); + } time("Layout subgraph", subGraph::layout); time("Calculate genomes through edges", subGraph::calculateGenomes); time("Drawing", () -> { @@ -417,4 +419,11 @@ public void highlightByGenome(int genomeID) { oldGenomeList = drawNodeList; highlightNodes(drawNodeList, Color.YELLOW); } + + /** + * Sets if the glyph snippets will be drawn or not. + */ + void setSNP() { + drawSNP = !drawSNP; + } } diff --git a/src/main/java/programminglife/gui/controller/GuiController.java b/src/main/java/programminglife/gui/controller/GuiController.java index cca77c7..7bd4ba1 100644 --- a/src/main/java/programminglife/gui/controller/GuiController.java +++ b/src/main/java/programminglife/gui/controller/GuiController.java @@ -23,6 +23,7 @@ import javafx.stage.FileChooser; import javafx.stage.FileChooser.ExtensionFilter; import javafx.stage.Stage; +import javafx.scene.canvas.Canvas; import jp.uphy.javafx.console.ConsoleView; import programminglife.ProgrammingLife; import programminglife.controller.MiniMapController; @@ -66,8 +67,11 @@ public class GuiController implements Observer { @FXML private MenuItem btnInstructions; @FXML private Menu menuRecentGFA; @FXML private Menu menuRecentGFF; - @FXML private RadioMenuItem btnToggle; + + @FXML private RadioMenuItem btnSNP; + @FXML private RadioMenuItem btnConsole; @FXML private RadioMenuItem btnMiniMap; + @FXML private Button btnZoomReset; @FXML private Button btnTranslateReset; @FXML private Button btnDraw; @@ -85,7 +89,7 @@ public class GuiController implements Observer { @FXML private AnchorPane anchorLeftControlPanel; @FXML private AnchorPane anchorGraphPanel; @FXML private AnchorPane anchorGraphInfo; - @FXML private javafx.scene.canvas.Canvas miniMap; + @FXML private Canvas miniMap; private double orgSceneX, orgSceneY; private double orgTranslateX, orgTranslateY; @@ -275,18 +279,24 @@ private void fileChooser(ExtensionFilter filter, boolean isGFA) { */ private void initMenuBar() { btnOpenGFA.setOnAction((ActionEvent event) -> fileChooser(extFilterGFA, true)); - btnOpenGFF.setOnAction((ActionEvent event) -> fileChooser(extFilterGFF, false)); - btnOpenGFA.setAccelerator(new KeyCodeCombination(KeyCode.O, KeyCodeCombination.CONTROL_DOWN)); + btnOpenGFF.setOnAction((ActionEvent event) -> fileChooser(extFilterGFF, false)); - btnMiniMap.setOnAction(event -> miniMapController.toggleVisibility()); - btnMiniMap.setAccelerator(new KeyCodeCombination(KeyCode.M, KeyCodeCombination.CONTROL_DOWN)); btnQuit.setOnAction(event -> Alerts.quitAlert()); btnQuit.setAccelerator(new KeyCodeCombination(KeyCode.E, KeyCodeCombination.CONTROL_DOWN)); + btnAbout.setOnAction(event -> Alerts.infoAboutAlert()); btnAbout.setAccelerator(new KeyCodeCombination(KeyCode.I, KeyCodeCombination.CONTROL_DOWN)); btnInstructions.setOnAction(event -> Alerts.infoInstructionAlert()); btnInstructions.setAccelerator(new KeyCodeCombination(KeyCode.H, KeyCodeCombination.CONTROL_DOWN)); + + btnMiniMap.setOnAction(event -> miniMapController.toggleVisibility()); + btnMiniMap.setAccelerator(new KeyCodeCombination(KeyCode.M, KeyCodeCombination.CONTROL_DOWN)); + btnSNP.setOnAction(event -> { + graphController.setSNP(); + Platform.runLater(this::draw); + }); + btnSNP.setAccelerator(new KeyCodeCombination(KeyCode.G, KeyCodeCombination.CONTROL_DOWN)); } @@ -501,8 +511,8 @@ private void initConsole() { AnchorPane.setRightAnchor(console, 0.d); AnchorPane.setLeftAnchor(console, 0.d); - btnToggle.setOnAction(event -> { - if (btnToggle.isSelected()) { + btnConsole.setOnAction(event -> { + if (btnConsole.isSelected()) { st.show(); } else { st.close(); @@ -510,8 +520,8 @@ private void initConsole() { }); st.show(); - btnToggle.setSelected(true); - root.visibleProperty().bind(btnToggle.selectedProperty()); + btnConsole.setSelected(true); + root.visibleProperty().bind(btnConsole.selectedProperty()); Console.setOut(console.getOut()); } diff --git a/src/main/java/programminglife/model/drawing/DrawableNode.java b/src/main/java/programminglife/model/drawing/DrawableNode.java index e33bbb4..2d7eb3a 100644 --- a/src/main/java/programminglife/model/drawing/DrawableNode.java +++ b/src/main/java/programminglife/model/drawing/DrawableNode.java @@ -36,8 +36,10 @@ public final boolean equals(Object o) { if (!(o instanceof DrawableNode)) return false; DrawableNode that = (DrawableNode) o; - if (!this.getClass().equals(that.getClass())) return false; - return this.getIdentifier() != that.getIdentifier(); + if (!this.getClass().equals(that.getClass())) { + return false; + } + return this.getIdentifier() == that.getIdentifier(); } @Override diff --git a/src/main/resources/Basic_Gui.fxml b/src/main/resources/Basic_Gui.fxml index 0f0076f..b02cc3a 100644 --- a/src/main/resources/Basic_Gui.fxml +++ b/src/main/resources/Basic_Gui.fxml @@ -17,11 +17,16 @@ - - + + + + + + + diff --git a/src/test/resources/Basic_Gui.fxml b/src/test/resources/Basic_Gui.fxml index 0f0076f..b02cc3a 100644 --- a/src/test/resources/Basic_Gui.fxml +++ b/src/test/resources/Basic_Gui.fxml @@ -17,11 +17,16 @@ - - + + + + + + + From 8daadaf8b632c5d9f28eb9270615c855bb93e7ad Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Tue, 20 Jun 2017 18:30:43 +0200 Subject: [PATCH 07/16] Things & fixes --- .../gui/controller/GraphController.java | 5 +++++ .../programminglife/model/drawing/DrawableDummy.java | 3 +++ .../programminglife/model/drawing/DrawableNode.java | 8 ++++++-- .../programminglife/model/drawing/DrawableSNP.java | 11 ++++++++--- .../model/drawing/DrawableSegment.java | 3 ++- .../java/programminglife/model/drawing/SubGraph.java | 7 +++++-- 6 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/main/java/programminglife/gui/controller/GraphController.java b/src/main/java/programminglife/gui/controller/GraphController.java index 5014d51..fb85463 100644 --- a/src/main/java/programminglife/gui/controller/GraphController.java +++ b/src/main/java/programminglife/gui/controller/GraphController.java @@ -48,6 +48,11 @@ public int getCenterNodeInt() { return this.centerNodeInt; } + /** + * Utility function for benchmarking purposes. + * @param description the description to print + * @param r the {@link Runnable} to run/benchmark + */ private void time(String description, Runnable r) { long start = System.nanoTime(); r.run(); diff --git a/src/main/java/programminglife/model/drawing/DrawableDummy.java b/src/main/java/programminglife/model/drawing/DrawableDummy.java index 0d8d711..8d3345d 100644 --- a/src/main/java/programminglife/model/drawing/DrawableDummy.java +++ b/src/main/java/programminglife/model/drawing/DrawableDummy.java @@ -95,6 +95,9 @@ public void colorize(SubGraph sg) { this.setStroke(strokeColor); } + /** + * {@inheritDoc} + */ public DrawableSegment hasSNPChildren(SubGraph subGraph) { return null; } diff --git a/src/main/java/programminglife/model/drawing/DrawableNode.java b/src/main/java/programminglife/model/drawing/DrawableNode.java index 2d7eb3a..ebbae3f 100644 --- a/src/main/java/programminglife/model/drawing/DrawableNode.java +++ b/src/main/java/programminglife/model/drawing/DrawableNode.java @@ -32,8 +32,12 @@ public abstract class DrawableNode extends Rectangle implements Drawable { @Override public final boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof DrawableNode)) return false; + if (this == o) { + return true; + } + if (!(o instanceof DrawableNode)) { + return false; + } DrawableNode that = (DrawableNode) o; if (!this.getClass().equals(that.getClass())) { diff --git a/src/main/java/programminglife/model/drawing/DrawableSNP.java b/src/main/java/programminglife/model/drawing/DrawableSNP.java index 750d3a7..db8b0c0 100644 --- a/src/main/java/programminglife/model/drawing/DrawableSNP.java +++ b/src/main/java/programminglife/model/drawing/DrawableSNP.java @@ -14,11 +14,12 @@ public class DrawableSNP extends DrawableNode { private DrawableSegment parent; private DrawableSegment child; - final private Collection mutations; + private final Collection mutations; /** * Construct a {@link DrawableNode}. - * + * @param parent the parent Segment of the mutations/SNP + * @param child the child Segment of the mutations/SNP * @param mutations the Segments in this bubble */ DrawableSNP(DrawableNode parent, DrawableNode child, Collection mutations) { @@ -140,7 +141,11 @@ protected void setDrawDimensions() { this.setDrawDimensionsUpToDate(true); } - void setSize(XYCoordinate size) { + /** + * Set the size of this {@link Drawable}. + * @param size the preferred size + */ + private void setSize(XYCoordinate size) { this.setWidth(size.getX()); this.setHeight(size.getY()); this.setDrawDimensionsUpToDate(true); diff --git a/src/main/java/programminglife/model/drawing/DrawableSegment.java b/src/main/java/programminglife/model/drawing/DrawableSegment.java index 2392973..8a58d17 100644 --- a/src/main/java/programminglife/model/drawing/DrawableSegment.java +++ b/src/main/java/programminglife/model/drawing/DrawableSegment.java @@ -162,7 +162,8 @@ public DrawableSegment hasSNPChildren(SubGraph subGraph) { return null; } else if (children.stream().anyMatch(id -> id < 1)) { // - no dummy children return null; - } else if (children.stream().anyMatch(id -> getGraph().getSequenceLength(id) != 1)) { // - only children of length 1 + } else if (children.stream().anyMatch(id -> getGraph().getSequenceLength(id) != 1)) { + // - only children of length 1 return null; } else { Collection childNodes = subGraph.getChildren(this); diff --git a/src/main/java/programminglife/model/drawing/SubGraph.java b/src/main/java/programminglife/model/drawing/SubGraph.java index 9f48ffc..9d0dfff 100644 --- a/src/main/java/programminglife/model/drawing/SubGraph.java +++ b/src/main/java/programminglife/model/drawing/SubGraph.java @@ -66,12 +66,15 @@ public SubGraph(DrawableSegment centerNode, int radius) { } } + /** + * Detect SNPs and replace them. + */ public void replaceSNPs() { - DrawableSegment child; Map nodesCopy = new LinkedHashMap<>(this.nodes); for (Map.Entry entry : nodesCopy.entrySet()) { DrawableNode parent = entry.getValue(); - if ((child = parent.hasSNPChildren(this)) != null) { + DrawableSegment child = parent.hasSNPChildren(this); + if (child != null) { Collection children = this.getChildren(parent); DrawableSNP snp = new DrawableSNP(parent, child, children); children.stream().map(DrawableNode::getIdentifier).forEach(this.nodes::remove); From 8eb1469df5c28f1febe51570584501d26859b730 Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Wed, 21 Jun 2017 11:01:31 +0200 Subject: [PATCH 08/16] SNP review comments --- .../model/drawing/DrawableNode.java | 8 ++--- .../model/drawing/DrawableSNP.java | 30 ++++++++++++------- .../model/drawing/SubGraphSNPTest.java | 14 --------- 3 files changed, 21 insertions(+), 31 deletions(-) diff --git a/src/main/java/programminglife/model/drawing/DrawableNode.java b/src/main/java/programminglife/model/drawing/DrawableNode.java index ebbae3f..1996938 100644 --- a/src/main/java/programminglife/model/drawing/DrawableNode.java +++ b/src/main/java/programminglife/model/drawing/DrawableNode.java @@ -35,15 +35,11 @@ public final boolean equals(Object o) { if (this == o) { return true; } - if (!(o instanceof DrawableNode)) { - return false; - } - DrawableNode that = (DrawableNode) o; - if (!this.getClass().equals(that.getClass())) { + if (!this.getClass().equals(o.getClass())) { return false; } - return this.getIdentifier() == that.getIdentifier(); + return this.getIdentifier() == ((DrawableNode) o).getIdentifier(); } @Override diff --git a/src/main/java/programminglife/model/drawing/DrawableSNP.java b/src/main/java/programminglife/model/drawing/DrawableSNP.java index db8b0c0..76bc204 100644 --- a/src/main/java/programminglife/model/drawing/DrawableSNP.java +++ b/src/main/java/programminglife/model/drawing/DrawableSNP.java @@ -12,6 +12,8 @@ * Created by toinehartman on 19/06/2017. */ public class DrawableSNP extends DrawableNode { + private static final int SNP_WIDTH = 11; + private DrawableSegment parent; private DrawableSegment child; private final Collection mutations; @@ -73,8 +75,14 @@ public Collection getParents() { */ @Override void replaceParent(DrawableNode oldParent, DrawableNode newParent) { - if (this.parent.getIdentifier() == oldParent.getIdentifier() && newParent instanceof DrawableSegment) { - this.parent = (DrawableSegment) newParent; + if (this.parent.getIdentifier() == oldParent.getIdentifier()) { + if (newParent instanceof DrawableSegment) { + this.parent = (DrawableSegment) newParent; + } else { + throw new IllegalArgumentException( + String.format("The new parent (%d) of this SNP (%d) is not a Segment.", + newParent.getIdentifier(), this.getIdentifier())); + } } else { throw new NoSuchElementException( String.format("The node to be replaced (%d) is not the parent of this SNP (%d).", @@ -90,8 +98,14 @@ void replaceParent(DrawableNode oldParent, DrawableNode newParent) { */ @Override void replaceChild(DrawableNode oldChild, DrawableNode newChild) { - if (this.child.getIdentifier() == oldChild.getIdentifier() && newChild instanceof DrawableSegment) { - this.child = (DrawableSegment) newChild; + if (this.child.getIdentifier() == oldChild.getIdentifier()) { + if (newChild instanceof DrawableSegment) { + this.child = (DrawableSegment) newChild; + } else { + throw new IllegalArgumentException( + String.format("The new child (%d) of this SNP (%d) is not a Segment.", + newChild.getIdentifier(), this.getIdentifier())); + } } else { throw new NoSuchElementException( String.format("The node to be replaced (%d) is not the parent of this SNP (%d).", @@ -131,13 +145,7 @@ public void colorize(SubGraph sg) { */ @Override protected void setDrawDimensions() { - int segmentLength = 1; - int width, height; - - width = 10 + (int) Math.pow(segmentLength, 1.0 / 2); - height = NODE_HEIGHT; - - this.setSize(new XYCoordinate(width, height)); + this.setSize(new XYCoordinate(SNP_WIDTH, NODE_HEIGHT)); this.setDrawDimensionsUpToDate(true); } diff --git a/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java b/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java index 2f503d2..3c3cd71 100644 --- a/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java +++ b/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java @@ -65,8 +65,6 @@ public void simpleSNP() throws Exception { assertNull(seg1.hasSNPChildren(sg)); assertNull(seg2.hasSNPChildren(sg)); assertNull(seg3.hasSNPChildren(sg)); - - g.removeCache(); } @Test @@ -114,8 +112,6 @@ public void quadSNP() throws Exception { assertNull(seg3.hasSNPChildren(sg)); assertNull(seg4.hasSNPChildren(sg)); assertNull(seg5.hasSNPChildren(sg)); - - g.removeCache(); } @Test @@ -169,8 +165,6 @@ public void fiveSNP() throws Exception { assertNull(seg4.hasSNPChildren(sg)); assertNull(seg5.hasSNPChildren(sg)); assertNull(seg6.hasSNPChildren(sg)); - - g.removeCache(); } @Test @@ -200,8 +194,6 @@ public void singleSNP() throws Exception { assertNull(seg0.hasSNPChildren(sg)); assertNull(seg1.hasSNPChildren(sg)); assertNull(seg2.hasSNPChildren(sg)); - - g.removeCache(); } @Test @@ -237,8 +229,6 @@ public void multipleNucleotideSNP() throws Exception { assertNull(seg1.hasSNPChildren(sg)); assertNull(seg2.hasSNPChildren(sg)); assertNull(seg3.hasSNPChildren(sg)); - - g.removeCache(); } @Test @@ -279,8 +269,6 @@ public void simpleSNPWithParent() throws Exception { assertNull(seg2.hasSNPChildren(sg)); assertNull(seg3.hasSNPChildren(sg)); assertNull(seg4.hasSNPChildren(sg)); - - g.removeCache(); } @Test @@ -321,7 +309,5 @@ public void simpleSNPWithChild() throws Exception { assertNull(seg2.hasSNPChildren(sg)); assertNull(seg3.hasSNPChildren(sg)); assertNull(seg4.hasSNPChildren(sg)); - - g.removeCache(); } } From 9ec33a99f1d98d68933b0200f7f8a77fe4704a18 Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Wed, 21 Jun 2017 11:26:01 +0200 Subject: [PATCH 09/16] Another review fix --- src/main/java/programminglife/model/drawing/SubGraph.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/programminglife/model/drawing/SubGraph.java b/src/main/java/programminglife/model/drawing/SubGraph.java index 9d0dfff..bfab8f1 100644 --- a/src/main/java/programminglife/model/drawing/SubGraph.java +++ b/src/main/java/programminglife/model/drawing/SubGraph.java @@ -54,6 +54,7 @@ public SubGraph(DrawableSegment centerNode, int radius) { this.graph = centerNode.getGraph(); this.radius = radius; this.layout = false; + this.genomes = new LinkedHashMap<>(); this.numberOfGenomes = graph.getTotalGenomeNumber(); @@ -500,14 +501,12 @@ Map> calculateGenomes(DrawableNode parent) { * @return a {@link Map} of {@link Map Maps} of collections of genomes through links */ public Map>> calculateGenomes() { - Map>> genomes = new LinkedHashMap<>(); // For every node in the subGraph for (DrawableNode parent : this.nodes.values()) { Map> parentGenomes = this.calculateGenomes(parent); - genomes.put(parent, parentGenomes); + this.genomes.put(parent, parentGenomes); } - this.genomes = genomes; return this.genomes; } From 9d30e1ba04849fae898b0125292d17e3fcb9e6a4 Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Wed, 21 Jun 2017 12:04:38 +0200 Subject: [PATCH 10/16] Less strict requirements for SNPs. Parent of SNP can have multiple children / child of SNP can have multiple parents. Parent/child of SNP does not have to be of type `DrawableSegment` (i.e. can be a `DrawableDummy`. --- .../model/drawing/DrawableSNP.java | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/src/main/java/programminglife/model/drawing/DrawableSNP.java b/src/main/java/programminglife/model/drawing/DrawableSNP.java index 76bc204..6e59637 100644 --- a/src/main/java/programminglife/model/drawing/DrawableSNP.java +++ b/src/main/java/programminglife/model/drawing/DrawableSNP.java @@ -14,8 +14,8 @@ public class DrawableSNP extends DrawableNode { private static final int SNP_WIDTH = 11; - private DrawableSegment parent; - private DrawableSegment child; + private DrawableNode parent; + private DrawableNode child; private final Collection mutations; /** @@ -39,9 +39,10 @@ public class DrawableSNP extends DrawableNode { this.child = (DrawableSegment) child; this.mutations = mutations.stream().map(DrawableSegment.class::cast).collect(Collectors.toSet()); - this.parent.getChildren().clear(); + this.mutations.stream().map(DrawableSegment::getIdentifier).forEach(this.parent.getChildren()::remove); this.parent.getChildren().add(this.getIdentifier()); - this.child.getParents().clear(); + + this.mutations.stream().map(DrawableSegment::getIdentifier).forEach(this.child.getParents()::remove); this.child.getParents().add(this.getIdentifier()); this.setDrawDimensions(); @@ -76,13 +77,7 @@ public Collection getParents() { @Override void replaceParent(DrawableNode oldParent, DrawableNode newParent) { if (this.parent.getIdentifier() == oldParent.getIdentifier()) { - if (newParent instanceof DrawableSegment) { - this.parent = (DrawableSegment) newParent; - } else { - throw new IllegalArgumentException( - String.format("The new parent (%d) of this SNP (%d) is not a Segment.", - newParent.getIdentifier(), this.getIdentifier())); - } + this.parent = newParent; } else { throw new NoSuchElementException( String.format("The node to be replaced (%d) is not the parent of this SNP (%d).", @@ -99,13 +94,7 @@ void replaceParent(DrawableNode oldParent, DrawableNode newParent) { @Override void replaceChild(DrawableNode oldChild, DrawableNode newChild) { if (this.child.getIdentifier() == oldChild.getIdentifier()) { - if (newChild instanceof DrawableSegment) { - this.child = (DrawableSegment) newChild; - } else { - throw new IllegalArgumentException( - String.format("The new child (%d) of this SNP (%d) is not a Segment.", - newChild.getIdentifier(), this.getIdentifier())); - } + this.child = newChild; } else { throw new NoSuchElementException( String.format("The node to be replaced (%d) is not the parent of this SNP (%d).", From 5d9bb5c187f8515f14b3f85760815f8cfa896788 Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Wed, 21 Jun 2017 12:07:56 +0200 Subject: [PATCH 11/16] If similar parents, sort by number of genomes --- src/main/java/programminglife/model/drawing/Layer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/programminglife/model/drawing/Layer.java b/src/main/java/programminglife/model/drawing/Layer.java index ed2b4d0..7f25bd7 100644 --- a/src/main/java/programminglife/model/drawing/Layer.java +++ b/src/main/java/programminglife/model/drawing/Layer.java @@ -96,9 +96,10 @@ public void sort(SubGraph subGraph, Layer neighbour, boolean hasParents) { return 1; } else if (difference > epsilon) { return -1; + } else if (o1.getGenomes().size() != o2.getGenomes().size()) { + return o2.getGenomes().size() - o1.getGenomes().size(); } else { return o2.getIdentifier() - o1.getIdentifier(); - } }); } From 32858c5e7ec6b6f7a4d9817c504edb28009ef6ce Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Wed, 21 Jun 2017 15:25:53 +0200 Subject: [PATCH 12/16] Removed stale code, parent/child is not a Segment anymore --- .../programminglife/model/drawing/DrawableSNP.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/programminglife/model/drawing/DrawableSNP.java b/src/main/java/programminglife/model/drawing/DrawableSNP.java index 6e59637..dd02732 100644 --- a/src/main/java/programminglife/model/drawing/DrawableSNP.java +++ b/src/main/java/programminglife/model/drawing/DrawableSNP.java @@ -27,16 +27,12 @@ public class DrawableSNP extends DrawableNode { DrawableSNP(DrawableNode parent, DrawableNode child, Collection mutations) { super(mutations.iterator().next().getGraph(), -mutations.hashCode()); - if (!(parent instanceof DrawableSegment)) { - throw new IllegalArgumentException("Parent of SNP must be a Segment!"); - } else if (!(child instanceof DrawableSegment)) { - throw new IllegalArgumentException("Child of SNP must be a Segment!"); - } else if (!mutations.stream().allMatch(DrawableSegment.class::isInstance)) { + if (!mutations.stream().allMatch(DrawableSegment.class::isInstance)) { throw new IllegalArgumentException("Mutations of SNP must be Segments!"); } - this.parent = (DrawableSegment) parent; - this.child = (DrawableSegment) child; + this.parent = parent; + this.child = child; this.mutations = mutations.stream().map(DrawableSegment.class::cast).collect(Collectors.toSet()); this.mutations.stream().map(DrawableSegment::getIdentifier).forEach(this.parent.getChildren()::remove); From 95558368c43e2f7aef612b7f55585dff3a0eac93 Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Thu, 22 Jun 2017 01:39:55 +0200 Subject: [PATCH 13/16] Improved DrawableSNP --- ProgrammingLife.iml | 2 +- .../model/drawing/DrawableDummy.java | 2 +- .../model/drawing/DrawableNode.java | 4 +- .../model/drawing/DrawableSNP.java | 21 +++--- .../model/drawing/DrawableSegment.java | 23 +++++- .../model/drawing/SubGraph.java | 12 +-- .../model/drawing/SubGraphSNPTest.java | 73 ++++++++++--------- 7 files changed, 80 insertions(+), 57 deletions(-) diff --git a/ProgrammingLife.iml b/ProgrammingLife.iml index c1f6076..f79f8db 100644 --- a/ProgrammingLife.iml +++ b/ProgrammingLife.iml @@ -12,11 +12,11 @@ - + diff --git a/src/main/java/programminglife/model/drawing/DrawableDummy.java b/src/main/java/programminglife/model/drawing/DrawableDummy.java index 8d3345d..e90b6c3 100644 --- a/src/main/java/programminglife/model/drawing/DrawableDummy.java +++ b/src/main/java/programminglife/model/drawing/DrawableDummy.java @@ -98,7 +98,7 @@ public void colorize(SubGraph sg) { /** * {@inheritDoc} */ - public DrawableSegment hasSNPChildren(SubGraph subGraph) { + public DrawableSNP createSNPIfPossible(SubGraph subGraph) { return null; } diff --git a/src/main/java/programminglife/model/drawing/DrawableNode.java b/src/main/java/programminglife/model/drawing/DrawableNode.java index 1996938..08222e8 100644 --- a/src/main/java/programminglife/model/drawing/DrawableNode.java +++ b/src/main/java/programminglife/model/drawing/DrawableNode.java @@ -116,9 +116,9 @@ final boolean isDrawDimensionsUpToDate() { /** * Checks if the children of this {@link DrawableNode} can be merged as a SNP. * @param subGraph the {@link SubGraph} this {@link DrawableNode} is in - * @return null if children cannot be SNP'ed, child of SNP otherwise + * @return null if children cannot be SNP'ed, SNP with (parent, child and mutation) otherwise */ - public abstract DrawableSegment hasSNPChildren(SubGraph subGraph); + public abstract DrawableSNP createSNPIfPossible(SubGraph subGraph); /** * Color this according to contents. diff --git a/src/main/java/programminglife/model/drawing/DrawableSNP.java b/src/main/java/programminglife/model/drawing/DrawableSNP.java index dd02732..3b2b942 100644 --- a/src/main/java/programminglife/model/drawing/DrawableSNP.java +++ b/src/main/java/programminglife/model/drawing/DrawableSNP.java @@ -24,21 +24,14 @@ public class DrawableSNP extends DrawableNode { * @param child the child Segment of the mutations/SNP * @param mutations the Segments in this bubble */ - DrawableSNP(DrawableNode parent, DrawableNode child, Collection mutations) { + DrawableSNP(DrawableNode parent, DrawableNode child, Collection mutations) { super(mutations.iterator().next().getGraph(), -mutations.hashCode()); - if (!mutations.stream().allMatch(DrawableSegment.class::isInstance)) { - throw new IllegalArgumentException("Mutations of SNP must be Segments!"); - } - this.parent = parent; this.child = child; - this.mutations = mutations.stream().map(DrawableSegment.class::cast).collect(Collectors.toSet()); + this.mutations = mutations; - this.mutations.stream().map(DrawableSegment::getIdentifier).forEach(this.parent.getChildren()::remove); this.parent.getChildren().add(this.getIdentifier()); - - this.mutations.stream().map(DrawableSegment::getIdentifier).forEach(this.child.getParents()::remove); this.child.getParents().add(this.getIdentifier()); this.setDrawDimensions(); @@ -109,7 +102,7 @@ public String details() { } @Override - public DrawableSegment hasSNPChildren(SubGraph subGraph) { + public DrawableSNP createSNPIfPossible(SubGraph subGraph) { return null; } @@ -161,4 +154,12 @@ public Collection getGenomes() { .flatMap(Collection::stream) .collect(Collectors.toSet()); } + + public Collection getMutations() { + return this.mutations; + } + + public DrawableNode getChild() { + return child; + } } diff --git a/src/main/java/programminglife/model/drawing/DrawableSegment.java b/src/main/java/programminglife/model/drawing/DrawableSegment.java index 8a58d17..dbf71c7 100644 --- a/src/main/java/programminglife/model/drawing/DrawableSegment.java +++ b/src/main/java/programminglife/model/drawing/DrawableSegment.java @@ -153,20 +153,33 @@ public DrawableNode getChildSegment() { return this; // Don't ask! } + /** + * {@inheritDoc} + */ @Override - public DrawableSegment hasSNPChildren(SubGraph subGraph) { + public DrawableSNP createSNPIfPossible(SubGraph subGraph) { // A SNP-able node has: if (children.size() < 2) { // - at least 2 children + System.out.println("Not enough children"); return null; } else if (children.size() > 4) { // - at most 4 children + System.out.println("Too many children (" + children.size() + ")"); return null; - } else if (children.stream().anyMatch(id -> id < 1)) { // - no dummy children + } else if (!children.stream().allMatch(id -> id >= 0)) { // - no dummy children + System.out.println("ID < 0"); + return null; + } else if (!subGraph.getChildren(this).stream().allMatch(DrawableSegment.class::isInstance)) { + // - only children of type DrawableSegment + System.out.println("Not all Segments"); return null; } else if (children.stream().anyMatch(id -> getGraph().getSequenceLength(id) != 1)) { // - only children of length 1 + System.out.println("Sequence length > 1"); return null; } else { - Collection childNodes = subGraph.getChildren(this); + Collection childNodes = subGraph.getChildren(this).stream() + .map(DrawableSegment.class::cast) + .collect(Collectors.toSet()); Collection childParents = childNodes.stream() .map(subGraph::getParents) .flatMap(Collection::stream) @@ -176,12 +189,14 @@ public DrawableSegment hasSNPChildren(SubGraph subGraph) { .flatMap(Collection::stream) .collect(Collectors.toSet()); if (childChildren.size() != 1) { // - all children have 1 and the same child + System.out.println("More than 1 children"); return null; } else if (childParents.size() != 1) { // - all children have 1 and the same parent + System.out.println("More than 1 parents"); return null; } - return (DrawableSegment) childChildren.iterator().next(); + return new DrawableSNP(this, childChildren.iterator().next(), childNodes); } } diff --git a/src/main/java/programminglife/model/drawing/SubGraph.java b/src/main/java/programminglife/model/drawing/SubGraph.java index bfab8f1..30128e3 100644 --- a/src/main/java/programminglife/model/drawing/SubGraph.java +++ b/src/main/java/programminglife/model/drawing/SubGraph.java @@ -74,11 +74,13 @@ public void replaceSNPs() { Map nodesCopy = new LinkedHashMap<>(this.nodes); for (Map.Entry entry : nodesCopy.entrySet()) { DrawableNode parent = entry.getValue(); - DrawableSegment child = parent.hasSNPChildren(this); - if (child != null) { - Collection children = this.getChildren(parent); - DrawableSNP snp = new DrawableSNP(parent, child, children); - children.stream().map(DrawableNode::getIdentifier).forEach(this.nodes::remove); + DrawableSNP snp = parent.createSNPIfPossible(this); + if (snp != null) { + snp.getMutations().stream().map(DrawableNode::getIdentifier).forEach(id -> { + this.nodes.remove(id); + parent.getChildren().remove(id); + snp.getChild().getParents().remove(id); + }); this.nodes.put(snp.getIdentifier(), snp); } } diff --git a/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java b/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java index 3c3cd71..c9656fc 100644 --- a/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java +++ b/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java @@ -7,6 +7,8 @@ import programminglife.model.GenomeGraph; import programminglife.utility.InitFXThread; +import java.util.stream.Collectors; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -61,10 +63,10 @@ public void simpleSNP() throws Exception { DrawableNode seg2 = sg.getNodes().get(2); DrawableNode seg3 = sg.getNodes().get(3); - assertEquals(seg3, seg0.hasSNPChildren(sg)); - assertNull(seg1.hasSNPChildren(sg)); - assertNull(seg2.hasSNPChildren(sg)); - assertNull(seg3.hasSNPChildren(sg)); + assertEquals(seg3, seg0.createSNPIfPossible(sg)); + assertNull(seg1.createSNPIfPossible(sg)); + assertNull(seg2.createSNPIfPossible(sg)); + assertNull(seg3.createSNPIfPossible(sg)); } @Test @@ -106,12 +108,15 @@ public void quadSNP() throws Exception { DrawableNode seg4 = sg.getNodes().get(4); DrawableNode seg5 = sg.getNodes().get(5); - assertEquals(seg5, seg0.hasSNPChildren(sg)); - assertNull(seg1.hasSNPChildren(sg)); - assertNull(seg2.hasSNPChildren(sg)); - assertNull(seg3.hasSNPChildren(sg)); - assertNull(seg4.hasSNPChildren(sg)); - assertNull(seg5.hasSNPChildren(sg)); + DrawableSNP snp = new DrawableSNP(seg0, seg5, sg.getChildren(seg0).stream() + .map(DrawableSegment.class::cast) + .collect(Collectors.toSet())); + assertNotNull(seg0.createSNPIfPossible(sg)); + assertNull(seg1.createSNPIfPossible(sg)); + assertNull(seg2.createSNPIfPossible(sg)); + assertNull(seg3.createSNPIfPossible(sg)); + assertNull(seg4.createSNPIfPossible(sg)); + assertNull(seg5.createSNPIfPossible(sg)); } @Test @@ -158,13 +163,13 @@ public void fiveSNP() throws Exception { DrawableNode seg5 = sg.getNodes().get(5); DrawableNode seg6 = sg.getNodes().get(6); - assertNull(seg0.hasSNPChildren(sg)); - assertNull(seg1.hasSNPChildren(sg)); - assertNull(seg2.hasSNPChildren(sg)); - assertNull(seg3.hasSNPChildren(sg)); - assertNull(seg4.hasSNPChildren(sg)); - assertNull(seg5.hasSNPChildren(sg)); - assertNull(seg6.hasSNPChildren(sg)); + assertNull(seg0.createSNPIfPossible(sg)); + assertNull(seg1.createSNPIfPossible(sg)); + assertNull(seg2.createSNPIfPossible(sg)); + assertNull(seg3.createSNPIfPossible(sg)); + assertNull(seg4.createSNPIfPossible(sg)); + assertNull(seg5.createSNPIfPossible(sg)); + assertNull(seg6.createSNPIfPossible(sg)); } @Test @@ -191,9 +196,9 @@ public void singleSNP() throws Exception { DrawableNode seg1 = sg.getNodes().get(1); DrawableNode seg2 = sg.getNodes().get(2); - assertNull(seg0.hasSNPChildren(sg)); - assertNull(seg1.hasSNPChildren(sg)); - assertNull(seg2.hasSNPChildren(sg)); + assertNull(seg0.createSNPIfPossible(sg)); + assertNull(seg1.createSNPIfPossible(sg)); + assertNull(seg2.createSNPIfPossible(sg)); } @Test @@ -225,10 +230,10 @@ public void multipleNucleotideSNP() throws Exception { DrawableNode seg2 = sg.getNodes().get(2); DrawableNode seg3 = sg.getNodes().get(3); - assertNull(seg0.hasSNPChildren(sg)); - assertNull(seg1.hasSNPChildren(sg)); - assertNull(seg2.hasSNPChildren(sg)); - assertNull(seg3.hasSNPChildren(sg)); + assertNull(seg0.createSNPIfPossible(sg)); + assertNull(seg1.createSNPIfPossible(sg)); + assertNull(seg2.createSNPIfPossible(sg)); + assertNull(seg3.createSNPIfPossible(sg)); } @Test @@ -264,11 +269,11 @@ public void simpleSNPWithParent() throws Exception { DrawableNode seg3 = sg.getNodes().get(3); DrawableNode seg4 = sg.getNodes().get(4); - assertNull(seg0.hasSNPChildren(sg)); - assertNull(seg1.hasSNPChildren(sg)); - assertNull(seg2.hasSNPChildren(sg)); - assertNull(seg3.hasSNPChildren(sg)); - assertNull(seg4.hasSNPChildren(sg)); + assertNull(seg0.createSNPIfPossible(sg)); + assertNull(seg1.createSNPIfPossible(sg)); + assertNull(seg2.createSNPIfPossible(sg)); + assertNull(seg3.createSNPIfPossible(sg)); + assertNull(seg4.createSNPIfPossible(sg)); } @Test @@ -304,10 +309,10 @@ public void simpleSNPWithChild() throws Exception { DrawableNode seg3 = sg.getNodes().get(3); DrawableNode seg4 = sg.getNodes().get(4); - assertNull(seg0.hasSNPChildren(sg)); - assertNull(seg1.hasSNPChildren(sg)); - assertNull(seg2.hasSNPChildren(sg)); - assertNull(seg3.hasSNPChildren(sg)); - assertNull(seg4.hasSNPChildren(sg)); + assertNull(seg0.createSNPIfPossible(sg)); + assertNull(seg1.createSNPIfPossible(sg)); + assertNull(seg2.createSNPIfPossible(sg)); + assertNull(seg3.createSNPIfPossible(sg)); + assertNull(seg4.createSNPIfPossible(sg)); } } From 0efe79caac48f1234985c66e1afa64911710c7f4 Mon Sep 17 00:00:00 2001 From: Ivo Wilms Date: Thu, 22 Jun 2017 02:28:29 +0200 Subject: [PATCH 14/16] Fixed failing tests SubGraphSNPTest.simpleSNP failed because it was testing outdated behaviour (createSNPIfPossible now returns an SNP) SubGraphSNPTest.quadSNP failed because creating an SNP changes the parent and child. --- .../programminglife/model/drawing/SubGraphSNPTest.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java b/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java index c9656fc..f60be1d 100644 --- a/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java +++ b/src/test/java/programminglife/model/drawing/SubGraphSNPTest.java @@ -7,9 +7,6 @@ import programminglife.model.GenomeGraph; import programminglife.utility.InitFXThread; -import java.util.stream.Collectors; - -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -63,7 +60,7 @@ public void simpleSNP() throws Exception { DrawableNode seg2 = sg.getNodes().get(2); DrawableNode seg3 = sg.getNodes().get(3); - assertEquals(seg3, seg0.createSNPIfPossible(sg)); + assertNotNull(seg0.createSNPIfPossible(sg)); assertNull(seg1.createSNPIfPossible(sg)); assertNull(seg2.createSNPIfPossible(sg)); assertNull(seg3.createSNPIfPossible(sg)); @@ -108,9 +105,6 @@ public void quadSNP() throws Exception { DrawableNode seg4 = sg.getNodes().get(4); DrawableNode seg5 = sg.getNodes().get(5); - DrawableSNP snp = new DrawableSNP(seg0, seg5, sg.getChildren(seg0).stream() - .map(DrawableSegment.class::cast) - .collect(Collectors.toSet())); assertNotNull(seg0.createSNPIfPossible(sg)); assertNull(seg1.createSNPIfPossible(sg)); assertNull(seg2.createSNPIfPossible(sg)); From d26414a276547e498de628b0662df852a3156496 Mon Sep 17 00:00:00 2001 From: Yannick Date: Thu, 22 Jun 2017 11:40:54 +0200 Subject: [PATCH 15/16] Quit shortcut back to Q. --- src/main/java/programminglife/gui/controller/GuiController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/programminglife/gui/controller/GuiController.java b/src/main/java/programminglife/gui/controller/GuiController.java index 7bd4ba1..f0e0d61 100644 --- a/src/main/java/programminglife/gui/controller/GuiController.java +++ b/src/main/java/programminglife/gui/controller/GuiController.java @@ -283,7 +283,7 @@ private void initMenuBar() { btnOpenGFF.setOnAction((ActionEvent event) -> fileChooser(extFilterGFF, false)); btnQuit.setOnAction(event -> Alerts.quitAlert()); - btnQuit.setAccelerator(new KeyCodeCombination(KeyCode.E, KeyCodeCombination.CONTROL_DOWN)); + btnQuit.setAccelerator(new KeyCodeCombination(KeyCode.Q, KeyCodeCombination.CONTROL_DOWN)); btnAbout.setOnAction(event -> Alerts.infoAboutAlert()); btnAbout.setAccelerator(new KeyCodeCombination(KeyCode.I, KeyCodeCombination.CONTROL_DOWN)); From 45b5a075b14382d6bc10796940c3d8b59382f6e4 Mon Sep 17 00:00:00 2001 From: Iwan Hoogenboom Date: Thu, 22 Jun 2017 13:40:55 +0200 Subject: [PATCH 16/16] Removed System.out.println --- .../programminglife/model/drawing/DrawableSegment.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/main/java/programminglife/model/drawing/DrawableSegment.java b/src/main/java/programminglife/model/drawing/DrawableSegment.java index ab4fd69..4102c6e 100644 --- a/src/main/java/programminglife/model/drawing/DrawableSegment.java +++ b/src/main/java/programminglife/model/drawing/DrawableSegment.java @@ -118,21 +118,16 @@ public DrawableNode getChildSegment() { public DrawableSNP createSNPIfPossible(SubGraph subGraph) { // A SNP-able node has: if (children.size() < 2) { // - at least 2 children - System.out.println("Not enough children"); return null; } else if (children.size() > 4) { // - at most 4 children - System.out.println("Too many children (" + children.size() + ")"); return null; } else if (!children.stream().allMatch(id -> id >= 0)) { // - no dummy children - System.out.println("ID < 0"); return null; } else if (!subGraph.getChildren(this).stream().allMatch(DrawableSegment.class::isInstance)) { // - only children of type DrawableSegment - System.out.println("Not all Segments"); return null; } else if (children.stream().anyMatch(id -> getGraph().getSequenceLength(id) != 1)) { // - only children of length 1 - System.out.println("Sequence length > 1"); return null; } else { Collection childNodes = subGraph.getChildren(this).stream() @@ -147,10 +142,8 @@ public DrawableSNP createSNPIfPossible(SubGraph subGraph) { .flatMap(Collection::stream) .collect(Collectors.toSet()); if (childChildren.size() != 1) { // - all children have 1 and the same child - System.out.println("More than 1 children"); return null; } else if (childParents.size() != 1) { // - all children have 1 and the same parent - System.out.println("More than 1 parents"); return null; }