JAL-629 Fix null AlignPanel. More descriptive label of pAE Matrix allows 'Add referen...
[jalview.git] / src / jalview / ws / datamodel / alphafold / PAEContactMatrix.java
1 package jalview.ws.datamodel.alphafold;
2
3 import java.util.Iterator;
4 import java.util.List;
5 import java.util.Map;
6
7 import jalview.datamodel.ContactListI;
8 import jalview.datamodel.ContactListImpl;
9 import jalview.datamodel.ContactListProviderI;
10 import jalview.datamodel.ContactMatrixI;
11 import jalview.datamodel.SequenceI;
12 import jalview.util.MapUtils;
13
14 public class PAEContactMatrix implements ContactMatrixI
15 {
16
17   SequenceI refSeq = null;
18
19   /**
20    * the length that refSeq is expected to be (excluding gaps, of course)
21    */
22   int length;
23
24   int maxrow = 0, maxcol = 0;
25
26   int[] indices1, indices2;
27
28   float[][] elements;
29
30   float maxscore;
31
32   private void setRefSeq(SequenceI _refSeq)
33   {
34     refSeq = _refSeq;
35     while (refSeq.getDatasetSequence() != null)
36     {
37       refSeq = refSeq.getDatasetSequence();
38     }
39     length = _refSeq.getEnd() - _refSeq.getStart() + 1;
40   }
41
42   @SuppressWarnings("unchecked")
43   public PAEContactMatrix(SequenceI _refSeq, Map<String, Object> pae_obj)
44   {
45     setRefSeq(_refSeq);
46     // convert the lists to primitive arrays and store
47
48     if (!MapUtils.containsAKey(pae_obj, "predicted_aligned_error", "pae"))
49     {
50       parse_version_1_pAE(pae_obj);
51       return;
52     }
53     else
54     {
55       parse_version_2_pAE(pae_obj);
56     }
57   }
58
59   /**
60    * construct a sequence associated PAE matrix directly from a float array
61    * 
62    * @param _refSeq
63    * @param matrix
64    */
65   public PAEContactMatrix(SequenceI _refSeq, float[][] matrix)
66   {
67     setRefSeq(_refSeq);
68     maxcol = 0;
69     for (float[] row : matrix)
70     {
71       if (row.length > maxcol)
72       {
73         maxcol = row.length;
74       }
75       maxscore = row[0];
76       for (float f : row)
77       {
78         if (maxscore < f)
79         {
80           maxscore = f;
81         }
82       }
83     }
84     maxrow = matrix.length;
85     elements = matrix;
86
87   }
88
89   /**
90    * parse a sane JSON representation of the pAE
91    * 
92    * @param pae_obj
93    */
94   @SuppressWarnings("unchecked")
95   private void parse_version_2_pAE(Map<String, Object> pae_obj)
96   {
97     // this is never going to be reached by the integer rounding.. or is it ?
98     maxscore = ((Double) MapUtils.getFirst(pae_obj,
99             "max_predicted_aligned_error", "max_pae")).floatValue();
100     List<List<Long>> scoreRows = ((List<List<Long>>) MapUtils
101             .getFirst(pae_obj, "predicted_aligned_error", "pae"));
102     elements = new float[scoreRows.size()][scoreRows.size()];
103     int row = 0, col = 0;
104     for (List<Long> scoreRow : scoreRows)
105     {
106       Iterator<Long> scores = scoreRow.iterator();
107       while (scores.hasNext())
108       {
109         Object d = scores.next();
110         if (d instanceof Double)
111           elements[row][col++] = ((Double) d).longValue();
112         else
113           elements[row][col++] = (float) ((Long) d).longValue();
114       }
115       row++;
116       col = 0;
117     }
118     maxcol = length;
119     maxrow = length;
120   }
121
122   /**
123    * v1 format got ditched 28th July 2022 see
124    * https://alphafold.ebi.ac.uk/faq#:~:text=We%20updated%20the%20PAE%20JSON%20file%20format%20on%2028th%20July%202022
125    * 
126    * @param pae_obj
127    */
128   @SuppressWarnings("unchecked")
129   private void parse_version_1_pAE(Map<String, Object> pae_obj)
130   {
131     // assume indices are with respect to range defined by _refSeq on the
132     // dataset refSeq
133     Iterator<Long> rows = ((List<Long>) pae_obj.get("residue1")).iterator();
134     Iterator<Long> cols = ((List<Long>) pae_obj.get("residue2")).iterator();
135     Iterator<Double> scores = ((List<Double>) pae_obj.get("distance"))
136             .iterator();
137     // assume square matrix
138     elements = new float[length][length];
139     while (scores.hasNext())
140     {
141       float escore = scores.next().floatValue();
142       int row = rows.next().intValue();
143       int col = cols.next().intValue();
144       if (maxrow < row)
145       {
146         maxrow = row;
147       }
148       if (maxcol < col)
149       {
150         maxcol = col;
151       }
152       elements[row - 1][col - 1] = escore;
153     }
154
155     maxscore = ((Double) MapUtils.getFirst(pae_obj,
156             "max_predicted_aligned_error", "max_pae")).floatValue();
157   }
158
159   @Override
160   public ContactListI getContactList(final int _column)
161   {
162     if (_column < 0 || _column >= elements.length)
163     {
164       return null;
165     }
166
167     return new ContactListImpl(new ContactListProviderI()
168     {
169       @Override
170       public int getPosition()
171       {
172         return _column;
173       }
174
175       @Override
176       public int getContactHeight()
177       {
178         return maxcol - 1;
179       }
180
181       @Override
182       public double getContactAt(int column)
183       {
184         if (column < 0 || column >= elements[_column].length)
185         {
186           return -1;
187         }
188         return elements[_column][column];
189       }
190     });
191   }
192
193   @Override
194   public float getMin()
195   {
196     return 0;
197   }
198
199   @Override
200   public float getMax()
201   {
202     return maxscore;
203   }
204
205   @Override
206   public boolean hasReferenceSeq()
207   {
208     return (refSeq != null);
209   }
210
211   @Override
212   public SequenceI getReferenceSeq()
213   {
214     return refSeq;
215   }
216
217   @Override
218   public String getAnnotDescr()
219   {
220     return "Predicted Alignment Error for " + refSeq.getName();
221   }
222
223   @Override
224   public String getAnnotLabel()
225   {
226     StringBuilder label = new StringBuilder("pAE Matrix");
227     if (this.getReferenceSeq() != null)
228       label.append(":").append(this.getReferenceSeq().getDisplayId(false));
229     return label.toString();
230   }
231
232   public static final String PAEMATRIX = "PAE_MATRIX";
233
234   @Override
235   public String getType()
236   {
237     return PAEMATRIX;
238   }
239
240   @Override
241   public int getWidth()
242   {
243     return length;
244   }
245
246   @Override
247   public int getHeight()
248   {
249     return length;
250   }
251 }