diff --git a/src/main/java/org/broad/igv/sam/AlignmentDataManager.java b/src/main/java/org/broad/igv/sam/AlignmentDataManager.java index 1aaba591d2..77e9957cdc 100644 --- a/src/main/java/org/broad/igv/sam/AlignmentDataManager.java +++ b/src/main/java/org/broad/igv/sam/AlignmentDataManager.java @@ -265,7 +265,7 @@ public AlignmentInterval getLoadedInterval(ReferenceFrame frame) { } public AlignmentInterval getLoadedInterval(ReferenceFrame frame, boolean includeOverlaps) { - // Search for interval completely containining reference frame region + // Search for interval completely containing reference frame region for (AlignmentInterval interval : intervalCache) { if (interval.contains(frame.getCurrentRange())) { return interval; @@ -354,11 +354,12 @@ public void load(ReferenceFrame frame, loadedInterval.packAlignments(renderOptions); + IGVEventBus.getInstance().post(new DataLoadedEvent(frame)); } finally { currentlyLoading = null; } - IGVEventBus.getInstance().post(new DataLoadedEvent(frame)); + } diff --git a/src/main/java/org/broad/igv/sam/AlignmentTrack.java b/src/main/java/org/broad/igv/sam/AlignmentTrack.java index 9673548137..c94aa76df8 100644 --- a/src/main/java/org/broad/igv/sam/AlignmentTrack.java +++ b/src/main/java/org/broad/igv/sam/AlignmentTrack.java @@ -86,8 +86,7 @@ public class AlignmentTrack extends AbstractTrack implements IGVEventObserver { public static void sortSelectedReadsToTheTop(final Set selectedReadNames) { //copy this in case it changes out from under us Set selectedReadNameCopy = new HashSet<>(selectedReadNames); - UIUtilities.invokeOnEventThread(() -> - IGV.getInstance().sortAlignmentTracks(SortOption.NONE, null, null, false, selectedReadNameCopy)); + IGV.getInstance().sortAlignmentTracks(SortOption.NONE, null, null, false, selectedReadNameCopy); } public enum ColorOption { diff --git a/src/main/java/org/broad/igv/ui/supdiagram/SupplementalAlignmentDiagram.java b/src/main/java/org/broad/igv/ui/supdiagram/SupplementalAlignmentDiagram.java index 0c50a07718..834a7765fb 100644 --- a/src/main/java/org/broad/igv/ui/supdiagram/SupplementalAlignmentDiagram.java +++ b/src/main/java/org/broad/igv/ui/supdiagram/SupplementalAlignmentDiagram.java @@ -102,7 +102,7 @@ protected void paintComponent(final Graphics g) { g.setColor(Color.LIGHT_GRAY); elementsOnScreen.clear(); final int mid = getHeight() / 3; - Map saInPositionOrder = drawAlignmentsInPositionOrder((Graphics2D) g.create(), toDraw, selected, getWidth(), mid); + Map saInPositionOrder = drawAlignmentsInCondensedChromosomeOrder((Graphics2D) g.create(), toDraw, selected, getWidth(), mid); drawArcs((Graphics2D) g.create(), toDraw, selected, mid, saInPositionOrder); drawContigLabels((Graphics2D) g.create(), mid + 15, saInPositionOrder); final int readOrderMidline = 2 * getHeight() / 3; @@ -156,7 +156,7 @@ private Map drawAlignmentsInReadOrder(fi double lastPosition = scaledBorderGap; for (SupplementaryAlignment sa : (Iterable) toDraw::iterateInReadOrder) { - final double spaceToUse = getSpaceToUse(totalAlignedBases, availableSpace, sa.getNumberOfAlignedBases()); + final double spaceToUse = getSpaceToUse(availableSpace, sa.getNumberOfAlignedBases(), totalAlignedBases); final int end = (int) (lastPosition + spaceToUse); AlignmentArrow readArrow = new AlignmentArrow(midline, ALIGNMENT_HEIGHT, (int) lastPosition, end, sa.getStrand()); lastPosition = end + scaledAlignmentGap; @@ -173,8 +173,8 @@ private static Graphics2D getSelectedGraphics(final Graphics2D g) { selectedGraphics.setColor(SELECTED_COLOR); return selectedGraphics; } - - private Map> groupBySpanningInterval(List intervals){ + + private static Map> groupBySpanningInterval(List intervals){ List currentGroup = null; Map> output = new LinkedHashMap<>(); Locatable spanning = null; @@ -191,7 +191,9 @@ private Map> groupBySpanningInterval(Li spanning = new Interval(spanning.getContig(), Math.min(spanning.getStart(), loc.getStart()), Math.max(spanning.getEnd(), loc.getEnd())); } else { output.put(spanning, currentGroup); - currentGroup = null; + currentGroup = new ArrayList<>(); + currentGroup.add(loc); + spanning = loc; } } if( currentGroup != null) { @@ -213,11 +215,43 @@ private static Map drawAlignmentsInConde final int scaledContigGap = scale(2, BETWEEN_CONTIG_GAP, width); final int scaledBorderGap = scale(BORDER_GAP / 3, BORDER_GAP, width); + final var groupedBySpan = groupBySpanningInterval(toDraw.streamInPositionOrder().toList()); + final Map> byContig = groupedBySpan.keySet() + .stream() + .collect(Collectors.groupingBy(Locatable::getContig)); + + //tihs should probably vary per contig instead of being uniform + final double perContigAvailableSpace = (width - (2 * scaledBorderGap + (contigs.size() -1) * scaledContigGap))/((double)contigs.size()); + + int contigStart = scaledBorderGap; + for(var contigEntry: byContig.entrySet()){ + //find the available space for each contig and set the drawing head there + int contigEnd = (int)(contigStart + perContigAvailableSpace); + List distinctSpans = contigEntry.getValue(); + //find the reference length of all the span groups on this contig + int totalSpansLength = distinctSpans.stream().mapToInt(Locatable::getLengthOnReference).sum(); + int spanStart = contigStart; + for(Locatable span: distinctSpans){ + //now handle each span group + int spanLength = span.getLengthOnReference(); + int spanSpaceAvailable = (int)getSpaceToUse((double) perContigAvailableSpace - (distinctSpans.size() -1) * scaledAlignmentGap, spanLength, totalSpansLength ); + for(SupplementaryAlignment sa: groupedBySpan.get(span)){ + //each read in the span is placed relatively within the space + int scaledReadStart = (int)getSpaceToUse(spanSpaceAvailable, sa.getStart() - span.getStart(), spanLength); + int scaledReadEnd = (int)getSpaceToUse(spanSpaceAvailable, sa.getEnd() - span.getStart(), spanLength); + //arrows that overlap will appear overlapping one another + AlignmentArrow readArrow = new AlignmentArrow(midline, ALIGNMENT_HEIGHT, + spanStart + scaledReadStart, + spanStart + scaledReadEnd, + sa.getStrand()); + positions.put(sa, readArrow); + spanStart += spanSpaceAvailable + scaledAlignmentGap; + } - final double availableSpace = width - (2 * scaledBorderGap + (toDraw.size() - 1) * scaledAlignmentGap + (contigs.size() - 1) * scaledContigGap); - - String lastContig = contigs.get(0); - double lastPosition = scaledBorderGap; + } + //move contig start forward + contigStart = contigEnd + scaledContigGap; + } // | ... [ ]>-5kbp<[ ] ... [ ]> | |[ |> ... | // Contigs all the same scale? @@ -228,25 +262,6 @@ private static Map drawAlignmentsInConde // merge overlappers into single zones // discover close by / far away zones - - - - for (SupplementaryAlignment sa : (Iterable) toDraw::iterateInPositionOrder) { - - final double spaceToUse = getSpaceToUse(totalAlignedBases, availableSpace, sa.getLengthOnReference()); - final String newContig = sa.getContig(); - if (lastPosition != scaledBorderGap && !Objects.equals(lastContig, newContig)) { - lastPosition += scaledContigGap; - } - - lastContig = newContig; - final int end = (int) (lastPosition + spaceToUse); - - AlignmentArrow readArrow = new AlignmentArrow(midline, ALIGNMENT_HEIGHT, (int) lastPosition, end, sa.getStrand()); - positions.put(sa, readArrow); - lastPosition = end + scaledAlignmentGap; - } - drawArrows(g, selected, positions, toDraw.getPrimaryAlignment()); return positions; } @@ -267,7 +282,7 @@ private static Map drawAlignmentsInPosit double lastPosition = scaledBorderGap; for (SupplementaryAlignment sa : (Iterable) toDraw::iterateInPositionOrder) { - final double spaceToUse = getSpaceToUse(totalAlignedBases, availableSpace, sa.getLengthOnReference()); + final double spaceToUse = getSpaceToUse(availableSpace, sa.getLengthOnReference(), totalAlignedBases); final String newContig = sa.getContig(); if (lastPosition != scaledBorderGap && !Objects.equals(lastContig, newContig)) { lastPosition += scaledContigGap; @@ -320,7 +335,7 @@ private static void drawArrows(final Graphics2D g, final Set