/* * Copyright 2015 MiLaboratory.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.milaboratory.core.alignment; import com.milaboratory.core.sequence.SequenceQuality; import com.milaboratory.util.BitArray; import java.util.Arrays; import static com.milaboratory.util.StringUtil.spaces; public final class AlignmentHelper implements java.io.Serializable { protected final String seq1String, seq2String; protected final String markup; protected final int[] seq1Position, seq2Position; protected final BitArray match; protected final int offset; public AlignmentHelper(String seq1String, String seq2String, int[] seq1Position, int[] seq2Position, BitArray match) { this(seq1String, seq2String, seq1Position, seq2Position, match, 0); } public AlignmentHelper(String seq1String, String seq2String, int[] seq1Position, int[] seq2Position, BitArray match, int offset) { if (seq1Position.length == 0) seq1Position = new int[1]; if (seq2Position.length == 0) seq2Position = new int[1]; this.seq1String = seq1String; this.seq2String = seq2String; this.seq1Position = seq1Position; this.seq2Position = seq2Position; this.match = match; this.offset = Math.max(Math.max(("" + aL(seq2Position[0])).length(), ("" + aL(seq1Position[0])).length()), offset); char[] chars = new char[match.size()]; Arrays.fill(chars, ' '); for (int n : match.getBits()) chars[n] = '|'; this.markup = new String(chars); } public AlignmentHelper getRange(int from, int to) { return getRange(from, to, 0); } public AlignmentHelper getRange(int from, int to, int offset) { return new AlignmentHelper(seq1String.substring(from, to), seq2String.substring(from, to), Arrays.copyOfRange(seq1Position, from, to), Arrays.copyOfRange(seq2Position, from, to), match.getRange(from, to), offset); } public AlignmentHelper[] split(int length) { return split(length, 0); } public AlignmentHelper[] split(int length, int offset) { AlignmentHelper[] ret = new AlignmentHelper[(size() + length - 1) / length]; for (int i = 0; i < ret.length; ++i) { int pointer = i * length; int l = Math.min(length, size() - pointer); ret[i] = getRange(pointer, pointer + l, offset); } return ret; } /** * Gets the identity of alignment, i.e. ratio of matching nucleotides in the aligned region */ public double identity() { return match.bitCount() * 1.0 / match.size(); } /** * Gets the size of aligned region */ public int size() { return match.size(); } public int getSequence1PositionAt(int i) { return seq1Position[i]; } public int getSequence2PositionAt(int i) { return seq2Position[i]; } /** * Get the aligned query sequence */ public String getSeq1String() { return seq1String; } /** * Get the aligned subject sequence */ public String getSeq2String() { return seq2String; } /** * Get the alignment markup line */ public String getMarkup() { return markup; } /** * Gets the first line of formatted alignment (query sequence) */ public String getLine1() { String startPosition = String.valueOf(aL(seq1Position[0])); int spaces = offset - startPosition.length(); return spaces(spaces) + startPosition + " " + seq1String + " " + aR(seq1Position[seq1Position.length - 1]); } public String getLine1Compact() { String startPosition = String.valueOf(aL(seq1Position[0])); int spaces = offset - startPosition.length(); return spaces(spaces) + startPosition + " " + toCompact(seq1String) + " " + aR(seq1Position[seq1Position.length - 1]); } /** * Gets the second line of formatted alignment (alignment markup) */ public String getLine2() { return spaces(offset + 1) + markup; } /** * Gets the third line of formatted alignment (subject sequence) */ public String getLine3() { String startPosition = String.valueOf(aL(seq2Position[0])); int spaces = offset - startPosition.length(); return spaces(spaces) + startPosition + " " + seq2String + " " + aR(seq2Position[seq2Position.length - 1]); } public String toStringWithSeq2Quality(SequenceQuality quality) { char[] chars = new char[size()]; for (int i = 0; i < size(); ++i) chars[i] = seq2Position[i] < 0 ? ' ' : (char) (33 + quality.value(seq2Position[i])); return getLine1() + "\n" + getLine2() + "\n" + getLine3() + "\n" + spaces(offset + 1) + new String(chars); } public String getLine3Compact() { String startPosition = String.valueOf(aL(seq2Position[0])); int spaces = offset - startPosition.length(); return spaces(spaces) + startPosition + " " + toCompact(seq2String) + " " + aR(seq2Position[seq2Position.length - 1]); } private String toCompact(String seqString) { char[] chars = seqString.toCharArray(); for (int i = 0; i < match.size(); ++i) if (match.get(i)) chars[i] = Character.toLowerCase(chars[i]); return new String(chars); } @Override public String toString() { return getLine1() + "\n" + getLine2() + "\n" + getLine3(); } /** * Gets the alignment string in contact format (no markup line, mismatches shown by lower-case characters) */ public String toCompactString() { return getLine1Compact() + "\n" + getLine3Compact(); } private static int aL(int f) { return f < 0 ? ~f : f; } private static int aR(int f) { return f < 0 ? ~f - 1 : f; } }