JAL-3858 report errors when trying to parse JSON to extract PAE and raise a warning...
authorJames Procter <j.procter@dundee.ac.uk>
Mon, 1 May 2023 12:54:50 +0000 (13:54 +0100)
committerJames Procter <j.procter@dundee.ac.uk>
Mon, 1 May 2023 12:54:50 +0000 (13:54 +0100)
src/jalview/ext/jmol/JmolParser.java
src/jalview/gui/StructureChooser.java
src/jalview/ws/datamodel/alphafold/PAEContactMatrix.java

index f0e477c..25b52b4 100644 (file)
@@ -47,6 +47,7 @@ import jalview.datamodel.SequenceI;
 import jalview.datamodel.annotations.AlphaFoldAnnotationRowBuilder;
 import jalview.datamodel.annotations.AnnotationRowBuilder;
 import jalview.io.DataSourceType;
+import jalview.io.FileFormatException;
 import jalview.io.FileParse;
 import jalview.io.StructureFile;
 import jalview.schemes.ResidueProperties;
@@ -303,18 +304,29 @@ public class JmolParser extends StructureFile implements JmolStatusListener
       // add a PAEMatrix if set (either by above or otherwise)
       if (hasPAEMatrix())
       {
-        Alignment al = new Alignment(prot.toArray(new SequenceI[0]));
-        EBIAlfaFold.addAlphaFoldPAE(al, new File(this.getPAEMatrix()), 0,
-                null, false, false);
-
-        if (al.getAlignmentAnnotation() != null)
+        try
         {
-          for (AlignmentAnnotation alann : al.getAlignmentAnnotation())
+          Alignment al = new Alignment(prot.toArray(new SequenceI[0]));
+          EBIAlfaFold.addAlphaFoldPAE(al, new File(this.getPAEMatrix()), 0,
+                  null, false, false);
+
+          if (al.getAlignmentAnnotation() != null)
           {
-            annotations.add(alann);
+            for (AlignmentAnnotation alann : al.getAlignmentAnnotation())
+            {
+              annotations.add(alann);
+            }
           }
+        } catch (Throwable ff)
+        {
+          Console.error("Couldn't import PAE Matrix from " + getPAEMatrix(),
+                  ff);
+          warningMessage += "Couldn't import PAE Matrix"
+                  + getNewlineString() + ff.getLocalizedMessage()
+                  + getNewlineString();
         }
       }
+
     } catch (OutOfMemoryError er)
     {
       System.out.println(
index 3fce931..03f9269 100644 (file)
@@ -64,6 +64,7 @@ import jalview.gui.structurechooser.PDBStructureChooserQuerySource;
 import jalview.gui.structurechooser.StructureChooserQuerySource;
 import jalview.gui.structurechooser.ThreeDBStructureChooserQuerySource;
 import jalview.io.DataSourceType;
+import jalview.io.FileFormatException;
 import jalview.io.JalviewFileChooser;
 import jalview.io.JalviewFileView;
 import jalview.jbgui.FilterOption;
@@ -76,6 +77,8 @@ import jalview.util.Platform;
 import jalview.util.StringUtils;
 import jalview.ws.DBRefFetcher;
 import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
+import jalview.ws.datamodel.alphafold.PAEContactMatrix;
+import jalview.ws.dbsources.EBIAlfaFold;
 import jalview.ws.seqfetcher.DbSourceProxy;
 import jalview.ws.sifts.SiftsSettings;
 
@@ -699,7 +702,7 @@ public class StructureChooser extends GStructureChooser
   }
 
   /**
-   * Handles action event for btn_pdbFromFile
+   * Handles action event for btn_paeMatrixFile
    */
   @Override
   protected void paeMatrixFile_actionPerformed()
@@ -728,10 +731,24 @@ public class StructureChooser extends GStructureChooser
             "label.load_pae_matrix_file_associate_with_structure",
             pdbFile.getName()));
 
+    // TODO convert to Callable/Promise
     int value = chooser.showOpenDialog(null);
     if (value == JalviewFileChooser.APPROVE_OPTION)
     {
-      localPdbPaeMatrixFileName = chooser.getSelectedFile().getPath();
+      String fileName = chooser.getSelectedFile().getPath();
+      try {
+        PAEContactMatrix.validateContactMatrixFile(fileName);
+      } catch (Exception thr)
+      {
+        JvOptionPane.showInternalMessageDialog(this, MessageManager
+                .formatMessage("label.couldnt_load_file", new Object[]
+                { fileName})+"<br>"+thr.getLocalizedMessage(),
+                MessageManager.getString("label.error_loading_file"),
+                JvOptionPane.WARNING_MESSAGE);
+        Console.error("Couldn't import "+fileName+" as a PAE matrix",thr);
+        return;
+      }
+      localPdbPaeMatrixFileName = fileName;
       Cache.setProperty("LAST_DIRECTORY", localPdbPaeMatrixFileName);
     }
     validateAssociationFromFile();
index 41e677a..22dd7fb 100644 (file)
@@ -1,6 +1,10 @@
 package jalview.ws.datamodel.alphafold;
 
 import java.awt.Color;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.HashMap;
@@ -8,6 +12,8 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
+import org.json.simple.JSONObject;
+
 import jalview.analysis.AverageDistanceEngine;
 import jalview.bin.Console;
 import jalview.datamodel.BinaryNode;
@@ -15,8 +21,13 @@ import jalview.datamodel.ContactListI;
 import jalview.datamodel.ContactListImpl;
 import jalview.datamodel.ContactListProviderI;
 import jalview.datamodel.ContactMatrixI;
+import jalview.datamodel.SequenceDummy;
 import jalview.datamodel.SequenceI;
+import jalview.io.DataSourceType;
+import jalview.io.FileFormatException;
+import jalview.io.FileParse;
 import jalview.util.MapUtils;
+import jalview.ws.dbsources.EBIAlfaFold;
 
 public class PAEContactMatrix implements ContactMatrixI
 {
@@ -47,7 +58,7 @@ public class PAEContactMatrix implements ContactMatrixI
   }
 
   @SuppressWarnings("unchecked")
-  public PAEContactMatrix(SequenceI _refSeq, Map<String, Object> pae_obj)
+  public PAEContactMatrix(SequenceI _refSeq, Map<String, Object> pae_obj) throws FileFormatException
   {
     setRefSeq(_refSeq);
     // convert the lists to primitive arrays and store
@@ -101,9 +112,17 @@ public class PAEContactMatrix implements ContactMatrixI
   @SuppressWarnings("unchecked")
   private void parse_version_2_pAE(Map<String, Object> pae_obj)
   {
-    // this is never going to be reached by the integer rounding.. or is it ?
-    maxscore = ((Double) MapUtils.getFirst(pae_obj,
-            "max_predicted_aligned_error", "max_pae")).floatValue();
+    maxscore = -1;
+    // look for a maxscore element - if there is one...
+    try
+    {
+      // this is never going to be reached by the integer rounding.. or is it ?
+      maxscore = ((Double) MapUtils.getFirst(pae_obj,
+              "max_predicted_aligned_error", "max_pae")).floatValue();
+    } catch (Throwable t)
+    {
+      // ignore if a key is not found.
+    }
     List<List<Long>> scoreRows = ((List<List<Long>>) MapUtils
             .getFirst(pae_obj, "predicted_aligned_error", "pae"));
     elements = new float[scoreRows.size()][scoreRows.size()];
@@ -114,10 +133,20 @@ public class PAEContactMatrix implements ContactMatrixI
       while (scores.hasNext())
       {
         Object d = scores.next();
+
         if (d instanceof Double)
+        {
           elements[row][col++] = ((Double) d).longValue();
+        }
         else
+        {
           elements[row][col++] = (float) ((Long) d).longValue();
+        }
+        
+        if (maxscore < elements[row][col - 1])
+        {
+          maxscore = elements[row][col - 1];
+        }
       }
       row++;
       col = 0;
@@ -139,10 +168,26 @@ public class PAEContactMatrix implements ContactMatrixI
     // dataset refSeq
     Iterator<Long> rows = ((List<Long>) pae_obj.get("residue1")).iterator();
     Iterator<Long> cols = ((List<Long>) pae_obj.get("residue2")).iterator();
+    // two pass - to allocate the elements array
+    while (rows.hasNext())
+    {
+      int row = rows.next().intValue();
+      int col = cols.next().intValue();
+      if (maxrow < row)
+      {
+        maxrow = row;
+      }
+      if (maxcol < col)
+      {
+        maxcol = col;
+      }
+
+    }
+    rows = ((List<Long>) pae_obj.get("residue1")).iterator();
+    cols = ((List<Long>) pae_obj.get("residue2")).iterator();
     Iterator<Double> scores = ((List<Double>) pae_obj.get("distance"))
             .iterator();
-    // assume square matrix
-    elements = new float[length][length];
+    elements = new float[maxrow][maxcol];
     while (scores.hasNext())
     {
       float escore = scores.next().floatValue();
@@ -373,4 +418,30 @@ public class PAEContactMatrix implements ContactMatrixI
   {
     return treeType;
   }
+
+  public static void validateContactMatrixFile(String fileName) throws FileFormatException,IOException
+  {
+    FileInputStream infile=null;
+    try {
+      infile = new FileInputStream(new File(fileName));
+    } catch (Throwable t)
+    {
+      new IOException("Couldn't open "+fileName,t);      
+    }
+    
+    
+    JSONObject paeDict=null;
+    try {
+      paeDict = EBIAlfaFold.parseJSONtoPAEContactMatrix(infile);
+    } catch (Throwable t)
+    {
+      new FileFormatException("Couldn't parse "+fileName+" as a JSON dict or array containing a dict");
+    }
+    
+    PAEContactMatrix matrix = new PAEContactMatrix(new SequenceDummy("Predicted"), (Map<String,Object>)paeDict);
+    if (matrix.getWidth()<=0)
+    {
+      throw new FileFormatException("No data in PAE matrix read from '"+fileName+"'");
+    }
+  } 
 }