From 01dd60b282ea075d333a5a875a00906b80e6ec69 Mon Sep 17 00:00:00 2001 From: James Procter Date: Tue, 29 Aug 2023 18:23:57 +0100 Subject: [PATCH] JAL-4124 decouple mappable contact matrix mapping logic from underlying contact matrix data so one matrix+tree+clustering can be referenced multiple times --- src/jalview/datamodel/ContactMatrix.java | 75 +++++----- src/jalview/datamodel/ContactMatrixI.java | 12 ++ src/jalview/datamodel/FloatContactMatrix.java | 133 ++++++++++++++++++ src/jalview/datamodel/GroupSetHolder.java | 24 ++++ .../datamodel/SeqDistanceContactMatrix.java | 2 +- .../ws/datamodel/MappableContactMatrixI.java | 2 + .../datamodel/alphafold/MappableContactMatrix.java | 76 +++++++--- .../ws/datamodel/alphafold/PAEContactMatrix.java | 147 +++++--------------- 8 files changed, 298 insertions(+), 173 deletions(-) create mode 100644 src/jalview/datamodel/FloatContactMatrix.java create mode 100644 src/jalview/datamodel/GroupSetHolder.java diff --git a/src/jalview/datamodel/ContactMatrix.java b/src/jalview/datamodel/ContactMatrix.java index 48b6e6b..32fa5b1 100644 --- a/src/jalview/datamodel/ContactMatrix.java +++ b/src/jalview/datamodel/ContactMatrix.java @@ -1,17 +1,12 @@ package jalview.datamodel; -import java.awt.Color; -import java.math.BigInteger; import java.util.ArrayList; -import java.util.BitSet; -import java.util.HashMap; import java.util.List; -import java.util.Spliterator; import java.util.StringTokenizer; import jalview.bin.Console; -public abstract class ContactMatrix implements ContactMatrixI +public abstract class ContactMatrix extends GroupSetHolder implements ContactMatrixI { /** * are contacts reflexive ? @@ -107,26 +102,7 @@ public abstract class ContactMatrix implements ContactMatrixI @Override public double getContactAt(int column) { - List clist; - Float cl = null; - if (symmetric) - { - if (p < column) - { - clist = contacts.get(p); - cl = clist.get(column); - } - else - { - clist = contacts.get(column); - cl = clist.get(p); - } - } - else - { - clist = contacts.get(p); - cl = clist.get(column); - } + Float cl = getFloatElementAt(column, p); if (cl == null) { // return 0 not NaN ? @@ -136,7 +112,41 @@ public abstract class ContactMatrix implements ContactMatrixI } }); } - + private Float getFloatElementAt(int column, int p) + { + + List clist; + Float cl = null; + if (symmetric) + { + if (p < column) + { + clist = contacts.get(p); + cl = clist.get(column); + } + else + { + clist = contacts.get(column); + cl = clist.get(p); + } + } + else + { + clist = contacts.get(p); + cl = clist.get(column); + } + return cl; + } + @Override + public double getElementAt(int column, int row) + { + Float cl = getFloatElementAt(column, row); + if (cl!=null) + { + return cl; + } + throw(new RuntimeException("Out of Bounds "+column+","+row)); + } @Override public float getMin() { @@ -160,17 +170,6 @@ public abstract class ContactMatrix implements ContactMatrixI { return "Contact Matrix"; } - GroupSet grps = new GroupSet(); - @Override - public GroupSetI getGroupSet() - { - return grps; - } - @Override - public void setGroupSet(GroupSet makeGroups) - { - grps = makeGroups; - } public static String contactToFloatString(ContactMatrixI cm) { StringBuilder sb = new StringBuilder(); diff --git a/src/jalview/datamodel/ContactMatrixI.java b/src/jalview/datamodel/ContactMatrixI.java index 925025f..4261519 100644 --- a/src/jalview/datamodel/ContactMatrixI.java +++ b/src/jalview/datamodel/ContactMatrixI.java @@ -199,5 +199,17 @@ public interface ContactMatrixI } return Color.white; } + + /** + * direct access to column and row position of matrix + + * Implementations are allowed to throw + * RunTimeExceptions if _column/i are out of bounds + * + * @param column + * @param row + * @return + */ + double getElementAt(int column, int row); } diff --git a/src/jalview/datamodel/FloatContactMatrix.java b/src/jalview/datamodel/FloatContactMatrix.java new file mode 100644 index 0000000..5fb156f --- /dev/null +++ b/src/jalview/datamodel/FloatContactMatrix.java @@ -0,0 +1,133 @@ +package jalview.datamodel; + +public class FloatContactMatrix extends GroupSetHolder implements ContactMatrixI +{ + + int maxrow = 0, maxcol = 0; + + + float[][] elements; + + float maxscore; + + + public FloatContactMatrix(float[][] matrix) + { + maxcol = 0; + for (float[] row : matrix) + { + if (row.length > maxcol) + { + maxcol = row.length; + } + maxscore = row[0]; + for (float f : row) + { + if (maxscore < f) + { + maxscore = f; + } + } + } + maxrow = matrix.length; + elements = matrix; + } + + public FloatContactMatrix(float[][] elements2, GroupSet grps2) + { + this(elements2); + setGroupSet(grps2); + } + + /** + * getContactList(column) @returns the vector of predicted alignment errors + * for reference position given by column + */ + @Override + public ContactListI getContactList(final int column) + { + if (column < 0 || column >= elements.length) + { + return null; + } + + return new ContactListImpl(new ContactListProviderI() + { + @Override + public int getPosition() + { + return column; + } + + @Override + public int getContactHeight() + { + return maxcol - 1; + } + + @Override + public double getContactAt(int mcolumn) + { + if (mcolumn < 0 || mcolumn >= elements[column].length) + { + return -1; + } + return elements[column][mcolumn]; + } + }); + } + + /** + * getElementAt(column, i) @returns the predicted superposition error for the + * ith position when column is used as reference + */ + @Override + public double getElementAt(int _column, int i) + { + return elements[_column][i]; + } + + @Override + public float getMin() + { + return 0; + } + + @Override + public float getMax() + { + return maxscore; + } + + @Override + public String getAnnotDescr() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getAnnotLabel() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getType() + { + return null; + } + + @Override + public int getWidth() + { + return maxcol; + } + + @Override + public int getHeight() + { + return maxrow; + } +} diff --git a/src/jalview/datamodel/GroupSetHolder.java b/src/jalview/datamodel/GroupSetHolder.java new file mode 100644 index 0000000..faeb7c0 --- /dev/null +++ b/src/jalview/datamodel/GroupSetHolder.java @@ -0,0 +1,24 @@ +package jalview.datamodel; + +/** + * holds a group set and provides getters and setters for ContactMatrixI + * implementations + * + * @author jprocter + */ +public class GroupSetHolder +{ + + GroupSet grps = new GroupSet(); + + public GroupSetI getGroupSet() + { + return grps; + } + + public void setGroupSet(GroupSet makeGroups) + { + grps = makeGroups; + } + +} diff --git a/src/jalview/datamodel/SeqDistanceContactMatrix.java b/src/jalview/datamodel/SeqDistanceContactMatrix.java index f8fd750..b04ac13 100644 --- a/src/jalview/datamodel/SeqDistanceContactMatrix.java +++ b/src/jalview/datamodel/SeqDistanceContactMatrix.java @@ -114,7 +114,7 @@ public class SeqDistanceContactMatrix return width; } @Override - protected double getElementAt(int _column, int i) + public double getElementAt(int _column, int i) { return Math.abs(_column - i); } diff --git a/src/jalview/ws/datamodel/MappableContactMatrixI.java b/src/jalview/ws/datamodel/MappableContactMatrixI.java index 9762428..3f294d0 100644 --- a/src/jalview/ws/datamodel/MappableContactMatrixI.java +++ b/src/jalview/ws/datamodel/MappableContactMatrixI.java @@ -73,4 +73,6 @@ public interface MappableContactMatrixI extends ContactMatrixI * @return sequence position(s) corresponding to column in contact matrix */ int[] getMappedPositionsFor(SequenceI localFrame, int from, int to); + + ContactMatrixI getMappedMatrix(); } diff --git a/src/jalview/ws/datamodel/alphafold/MappableContactMatrix.java b/src/jalview/ws/datamodel/alphafold/MappableContactMatrix.java index d545741..cc96ac4 100644 --- a/src/jalview/ws/datamodel/alphafold/MappableContactMatrix.java +++ b/src/jalview/ws/datamodel/alphafold/MappableContactMatrix.java @@ -7,6 +7,7 @@ import java.util.BitSet; import jalview.datamodel.ContactListI; import jalview.datamodel.ContactListImpl; import jalview.datamodel.ContactListProviderI; +import jalview.datamodel.ContactMatrixI; import jalview.datamodel.GroupSet; import jalview.datamodel.GroupSetI; import jalview.datamodel.Mapping; @@ -17,42 +18,77 @@ import jalview.ws.datamodel.MappableContactMatrixI; public abstract class MappableContactMatrix> implements MappableContactMatrixI { - SequenceI refSeq = null; - - MapList toSeq = null; - /** - * the length that refSeq is expected to be (excluding gaps, of course) + * the matrix that is being mapped to */ - int length; + protected ContactMatrixI mappedMatrix=null; + + public ContactListI getContactList(int column) + { + return mappedMatrix.getContactList(column); + } + + public float getMin() + { + return mappedMatrix.getMin(); + } + + public float getMax() + { + return mappedMatrix.getMax(); + } + + public int getWidth() + { + return mappedMatrix.getWidth(); + } + + public int getHeight() + { + return mappedMatrix.getHeight(); + } @Override - public boolean hasReferenceSeq() + public ContactMatrixI getMappedMatrix() { - return (refSeq != null); + return mappedMatrix; } + + @Override + public GroupSetI getGroupSet() + { + return mappedMatrix.getGroupSet(); + }; @Override - public SequenceI getReferenceSeq() + public void setGroupSet(GroupSet makeGroups) { - return refSeq; + mappedMatrix.setGroupSet(makeGroups); } + + /** + * the sequence and how it is mapped to the matrix + */ + + SequenceI refSeq = null; + + MapList toSeq = null; /** - * container for groups - defined on matrix columns + * the length that refSeq is expected to be (excluding gaps, of course) */ - GroupSet grps = new GroupSet(); + int length; @Override - public GroupSetI getGroupSet() + public boolean hasReferenceSeq() { - return grps; - }; + return (refSeq != null); + } @Override - public void setGroupSet(GroupSet makeGroups) + public SequenceI getReferenceSeq() { - grps = makeGroups; + return refSeq; } @Override @@ -439,7 +475,7 @@ public abstract class MappableContactMatrix> } /** - * get a specific element of the contact matrix in its data-local coordinates + * get a specific element of the underlying contact matrix in its data-local coordinates * rather than the mapped frame. Implementations are allowed to throw * RunTimeExceptions if _column/i are out of bounds * @@ -447,6 +483,8 @@ public abstract class MappableContactMatrix> * @param i * @return */ - protected abstract double getElementAt(int _column, int i); + public double getElementAt(int _column, int i) { + return mappedMatrix.getElementAt(_column, i); + } } diff --git a/src/jalview/ws/datamodel/alphafold/PAEContactMatrix.java b/src/jalview/ws/datamodel/alphafold/PAEContactMatrix.java index 22884f1..0c1f71a 100644 --- a/src/jalview/ws/datamodel/alphafold/PAEContactMatrix.java +++ b/src/jalview/ws/datamodel/alphafold/PAEContactMatrix.java @@ -13,6 +13,7 @@ import jalview.datamodel.ContactListI; import jalview.datamodel.ContactListImpl; import jalview.datamodel.ContactListProviderI; import jalview.datamodel.ContactMatrixI; +import jalview.datamodel.FloatContactMatrix; import jalview.datamodel.GroupSet; import jalview.datamodel.SequenceDummy; import jalview.datamodel.SequenceI; @@ -41,14 +42,6 @@ public class PAEContactMatrix extends { - int maxrow = 0, maxcol = 0; - - - float[][] elements; - - float maxscore; - - @SuppressWarnings("unchecked") public PAEContactMatrix(SequenceI _refSeq, Map pae_obj) throws FileFormatException @@ -75,26 +68,8 @@ public class PAEContactMatrix extends */ public PAEContactMatrix(SequenceI _refSeq, float[][] matrix) { + mappedMatrix=new FloatContactMatrix(matrix); setRefSeq(_refSeq); - maxcol = 0; - for (float[] row : matrix) - { - if (row.length > maxcol) - { - maxcol = row.length; - } - maxscore = row[0]; - for (float f : row) - { - if (maxscore < f) - { - maxscore = f; - } - } - } - maxrow = matrix.length; - elements = matrix; - } /** @@ -108,20 +83,40 @@ public class PAEContactMatrix extends public PAEContactMatrix(SequenceI newRefSeq, MapList newFromMapList, float[][] elements2, GroupSet grps2) { - this(newRefSeq, elements2); + this(newRefSeq, new FloatContactMatrix(elements2,grps2)); + toSeq = newFromMapList; + } + + public PAEContactMatrix(SequenceI _refSeq, + ContactMatrixI floatContactMatrix) + { + mappedMatrix = floatContactMatrix; + setRefSeq(_refSeq); + } + public PAEContactMatrix(SequenceI _refSeq, MapList newFromMapList, + ContactMatrixI floatContactMatrix) + { + mappedMatrix = floatContactMatrix; + setRefSeq(_refSeq); toSeq = newFromMapList; - grps = grps2; + } + + @Override + protected PAEContactMatrix newMappableContactMatrix(SequenceI newRefSeq, + MapList newFromMapList) + { + return new PAEContactMatrix(newRefSeq, newFromMapList, mappedMatrix); } /** - * parse a sane JSON representation of the pAE + * parse a sane JSON representation of the pAE and update the mappedMatrix * * @param pae_obj */ @SuppressWarnings("unchecked") private void parse_version_2_pAE(Map pae_obj) { - maxscore = -1; + float maxscore = -1; // look for a maxscore element - if there is one... try { @@ -134,7 +129,7 @@ public class PAEContactMatrix extends } List> scoreRows = ((List>) MapUtils .getFirst(pae_obj, "predicted_aligned_error", "pae")); - elements = new float[scoreRows.size()][scoreRows.size()]; + float[][] elements = new float[scoreRows.size()][scoreRows.size()]; int row = 0, col = 0; for (List scoreRow : scoreRows) { @@ -160,8 +155,7 @@ public class PAEContactMatrix extends row++; col = 0; } - maxcol = length; - maxrow = length; + mappedMatrix=new FloatContactMatrix(elements); } /** @@ -178,6 +172,8 @@ public class PAEContactMatrix extends Iterator rows = ((List) pae_obj.get("residue1")).iterator(); Iterator cols = ((List) pae_obj.get("residue2")).iterator(); // two pass - to allocate the elements array + + int maxrow=-1,maxcol=-1; while (rows.hasNext()) { int row = rows.next().intValue(); @@ -196,7 +192,7 @@ public class PAEContactMatrix extends cols = ((List) pae_obj.get("residue2")).iterator(); Iterator scores = ((List) pae_obj.get("distance")) .iterator(); - elements = new float[maxcol][maxrow]; + float[][] elements = new float[maxcol][maxrow]; while (scores.hasNext()) { float escore = scores.next().floatValue(); @@ -213,68 +209,7 @@ public class PAEContactMatrix extends elements[col - 1][row-1] = escore; } - maxscore = ((Double) MapUtils.getFirst(pae_obj, - "max_predicted_aligned_error", "max_pae")).floatValue(); - } - - /** - * getContactList(column) @returns the vector of predicted alignment errors - * for reference position given by column - */ - @Override - public ContactListI getContactList(final int column) - { - if (column < 0 || column >= elements.length) - { - return null; - } - - return new ContactListImpl(new ContactListProviderI() - { - @Override - public int getPosition() - { - return column; - } - - @Override - public int getContactHeight() - { - return maxcol - 1; - } - - @Override - public double getContactAt(int mcolumn) - { - if (mcolumn < 0 || mcolumn >= elements[column].length) - { - return -1; - } - return elements[column][mcolumn]; - } - }); - } - - /** - * getElementAt(column, i) @returns the predicted superposition error for the - * ith position when column is used as reference - */ - @Override - protected double getElementAt(int _column, int i) - { - return elements[_column][i]; - } - - @Override - public float getMin() - { - return 0; - } - - @Override - public float getMax() - { - return maxscore; + mappedMatrix=new FloatContactMatrix(elements); } @Override @@ -303,17 +238,7 @@ public class PAEContactMatrix extends return PAEMATRIX; } - @Override - public int getWidth() - { - return maxcol; - } - @Override - public int getHeight() - { - return maxrow; - } public static void validateContactMatrixFile(String fileName) throws FileFormatException, IOException { @@ -343,12 +268,4 @@ public class PAEContactMatrix extends "No data in PAE matrix read from '" + fileName + "'"); } } - @Override - protected PAEContactMatrix newMappableContactMatrix(SequenceI newRefSeq, - MapList newFromMapList) - { - PAEContactMatrix pae = new PAEContactMatrix(newRefSeq, newFromMapList, - elements, new GroupSet(grps)); - return pae; - } } -- 1.7.10.2