JAL-3304 option to export linked features in Jalview format
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 18 Jun 2019 11:14:32 +0000 (12:14 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 18 Jun 2019 11:14:32 +0000 (12:14 +0100)
resources/lang/Messages.properties
resources/lang/Messages_es.properties
src/jalview/appletgui/AlignFrame.java
src/jalview/gui/AnnotationExporter.java
src/jalview/io/FeaturesFile.java
test/jalview/io/FeaturesFileTest.java

index fe7a401..05c7eb4 100644 (file)
@@ -1406,4 +1406,6 @@ label.create_image_of = Create {0} image of {1}
 label.click_to_edit = Click to edit, right-click for menu
 label.by_annotation_tooltip = Annotation Colour is configured from the main Colour menu
 label.show_linked_features = Show {0} features
-label.on_top = on top
\ No newline at end of file
+label.on_top = on top
+label.include_linked_features = Include {0} features
+label.include_linked_tooltip = Include visible {0} features<br>converted to local sequence coordinates
\ No newline at end of file
index 5346f68..c6e3da3 100644 (file)
@@ -1407,4 +1407,6 @@ label.create_image_of = Crear imagen {0} de {1}
 label.click_to_edit = Haga clic para editar, clic en el botón derecho para ver el menú  
 label.by_annotation_tooltip = El color de anotación se configura desde el menú principal de colores
 label.show_linked_features = Características de {0}
-label.on_top = encima
\ No newline at end of file
+label.on_top = encima
+label.include_linked_features = Incluir características de {0}
+label.include_linked_tooltip = Incluir características de {0}<br>convertidas a coordenadas de secuencia local
\ No newline at end of file
index eb3be88..3bb5fe8 100644 (file)
@@ -1448,12 +1448,13 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     {
       features = formatter.printJalviewFormat(
               viewport.getAlignment().getSequencesArray(),
-              alignPanel.getFeatureRenderer(), true);
+              alignPanel.getFeatureRenderer(), true, false);
     }
     else
     {
       features = formatter.printGffFormat(viewport.getAlignment()
-              .getSequencesArray(), alignPanel.getFeatureRenderer(), true);
+              .getSequencesArray(), alignPanel.getFeatureRenderer(), true,
+              false);
     }
 
     if (displayTextbox)
index fac531e..0b0916d 100644 (file)
@@ -30,17 +30,17 @@ import jalview.io.JalviewFileChooser;
 import jalview.io.JalviewFileView;
 import jalview.util.MessageManager;
 
-import java.awt.BorderLayout;
 import java.awt.Color;
-import java.awt.FlowLayout;
+import java.awt.Dimension;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.io.FileWriter;
 import java.io.PrintWriter;
 
-import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
 import javax.swing.ButtonGroup;
 import javax.swing.JButton;
+import javax.swing.JCheckBox;
 import javax.swing.JInternalFrame;
 import javax.swing.JLabel;
 import javax.swing.JLayeredPane;
@@ -71,6 +71,29 @@ public class AnnotationExporter extends JPanel
 
   private boolean wholeView;
 
+  /*
+   * option to export linked (CDS/peptide) features when shown 
+   * on the alignment, converted to this alignment's coordinates
+   */
+  private JCheckBox includeLinkedFeatures;
+
+  /*
+   * output format option shown for feature export
+   */
+  JRadioButton GFFFormat = new JRadioButton();
+
+  /*
+   * output format option shown for annotation export
+   */
+  JRadioButton CSVFormat = new JRadioButton();
+
+  private JPanel linkedFeaturesPanel;
+
+  /**
+   * Constructor
+   * 
+   * @param panel
+   */
   public AnnotationExporter(AlignmentPanel panel)
   {
     this.ap = panel;
@@ -85,17 +108,25 @@ public class AnnotationExporter extends JPanel
     frame = new JInternalFrame();
     frame.setContentPane(this);
     frame.setLayer(JLayeredPane.PALETTE_LAYER);
-    Desktop.addInternalFrame(frame, "", frame.getPreferredSize().width,
-            frame.getPreferredSize().height);
+    Dimension preferredSize = frame.getPreferredSize();
+    Desktop.addInternalFrame(frame, "", true, preferredSize.width,
+            preferredSize.height, true, true);
   }
 
   /**
-   * Configures the diglog for options to export visible features
+   * Configures the dialog for options to export visible features. If from a split
+   * frame panel showing linked features, make the option to include these in the
+   * export visible.
    */
   public void exportFeatures()
   {
     exportFeatures = true;
     CSVFormat.setVisible(false);
+    if (ap.av.isShowComplementFeatures())
+    {
+      linkedFeaturesPanel.setVisible(true);
+      frame.pack();
+    }
     frame.setTitle(MessageManager.getString("label.export_features"));
   }
 
@@ -215,14 +246,17 @@ public class AnnotationExporter extends JPanel
 
     FeaturesFile formatter = new FeaturesFile();
     final FeatureRenderer fr = ap.getFeatureRenderer();
+    boolean includeComplement = includeLinkedFeatures.isSelected();
+
     if (GFFFormat.isSelected())
     {
-      text = formatter.printGffFormat(sequences, fr, includeNonPositional);
+      text = formatter.printGffFormat(sequences, fr, includeNonPositional,
+              includeComplement);
     }
     else
     {
       text = formatter.printJalviewFormat(sequences, fr,
-              includeNonPositional);
+              includeNonPositional, includeComplement);
     }
     return text;
   }
@@ -268,11 +302,70 @@ public class AnnotationExporter extends JPanel
     }
   }
 
+  /**
+   * Adds widgets to the panel
+   * 
+   * @throws Exception
+   */
   private void jbInit() throws Exception
   {
-    this.setLayout(new BorderLayout());
+    this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+    this.setBackground(Color.white);
+
+    JPanel formatPanel = buildFormatOptionsPanel();
+    JPanel linkedFeatures = buildLinkedFeaturesPanel();
+    JPanel actionsPanel = buildActionsPanel();
+
+    this.add(formatPanel);
+    this.add(linkedFeatures);
+    this.add(actionsPanel);
+  }
+
+  /**
+   * Builds a panel with a checkbox for the option to export linked (CDS/peptide)
+   * features. This is hidden by default, and only made visible if exporting
+   * features from a split frame panel which is configured to show linked
+   * features.
+   * 
+   * @return
+   */
+  private JPanel buildLinkedFeaturesPanel()
+  {
+    linkedFeaturesPanel = new JPanel();
+    linkedFeaturesPanel.setOpaque(false);
+
+    boolean nucleotide = ap.av.isNucleotide();
+    String complement = nucleotide
+            ? MessageManager.getString("label.protein").toLowerCase()
+            : "CDS";
+    JLabel label = new JLabel(
+            MessageManager.formatMessage("label.include_linked_features",
+                    complement));
+    label.setHorizontalAlignment(SwingConstants.TRAILING);
+    String tooltip = MessageManager
+            .formatMessage("label.include_linked_tooltip", complement);
+    label.setToolTipText(
+            JvSwingUtils.wrapTooltip(true, tooltip));
+
+    includeLinkedFeatures = new JCheckBox();
+    linkedFeaturesPanel.add(label);
+    linkedFeaturesPanel.add(includeLinkedFeatures);
+    linkedFeaturesPanel.setVisible(false);
+
+    return linkedFeaturesPanel;
+  }
+
+  /**
+   * Builds the panel with to File or Textbox or Close actions
+   * 
+   * @return
+   */
+  JPanel buildActionsPanel()
+  {
+    JPanel actionsPanel = new JPanel();
+    actionsPanel.setOpaque(false);
 
-    toFile.setText(MessageManager.getString("label.to_file"));
+    JButton toFile = new JButton(MessageManager.getString("label.to_file"));
     toFile.addActionListener(new ActionListener()
     {
       @Override
@@ -281,7 +374,8 @@ public class AnnotationExporter extends JPanel
         toFile_actionPerformed();
       }
     });
-    toTextbox.setText(MessageManager.getString("label.to_textbox"));
+    JButton toTextbox = new JButton(
+            MessageManager.getString("label.to_textbox"));
     toTextbox.addActionListener(new ActionListener()
     {
       @Override
@@ -290,7 +384,7 @@ public class AnnotationExporter extends JPanel
         toTextbox_actionPerformed();
       }
     });
-    close.setText(MessageManager.getString("action.close"));
+    JButton close = new JButton(MessageManager.getString("action.close"));
     close.addActionListener(new ActionListener()
     {
       @Override
@@ -299,52 +393,49 @@ public class AnnotationExporter extends JPanel
         close_actionPerformed();
       }
     });
+
+    actionsPanel.add(toFile);
+    actionsPanel.add(toTextbox);
+    actionsPanel.add(close);
+
+    return actionsPanel;
+  }
+
+  /**
+   * Builds the panel with options to output in Jalview, GFF or CSV format. GFF is
+   * only made visible when exporting features, CSV only when exporting
+   * annotation.
+   * 
+   * @return
+   */
+  JPanel buildFormatOptionsPanel()
+  {
+    JPanel formatPanel = new JPanel();
+    // formatPanel.setBorder(BorderFactory.createEtchedBorder());
+    formatPanel.setOpaque(false);
+
+    JRadioButton jalviewFormat = new JRadioButton("Jalview");
     jalviewFormat.setOpaque(false);
     jalviewFormat.setSelected(true);
-    jalviewFormat.setText("Jalview");
     GFFFormat.setOpaque(false);
     GFFFormat.setText("GFF");
     CSVFormat.setOpaque(false);
     CSVFormat.setText(MessageManager.getString("label.csv_spreadsheet"));
-    jLabel1.setHorizontalAlignment(SwingConstants.TRAILING);
-    jLabel1.setText(MessageManager.getString("action.format") + " ");
-    this.setBackground(Color.white);
-    jPanel3.setBorder(BorderFactory.createEtchedBorder());
-    jPanel3.setOpaque(false);
-    jPanel1.setOpaque(false);
-    jPanel1.add(toFile);
-    jPanel1.add(toTextbox);
-    jPanel1.add(close);
-    jPanel3.add(jLabel1);
-    jPanel3.add(jalviewFormat);
-    jPanel3.add(GFFFormat);
-    jPanel3.add(CSVFormat);
+
+    ButtonGroup buttonGroup = new ButtonGroup();
     buttonGroup.add(jalviewFormat);
     buttonGroup.add(GFFFormat);
     buttonGroup.add(CSVFormat);
-    this.add(jPanel3, BorderLayout.CENTER);
-    this.add(jPanel1, BorderLayout.SOUTH);
-  }
-
-  JPanel jPanel1 = new JPanel();
-
-  JButton toFile = new JButton();
-
-  JButton toTextbox = new JButton();
-
-  JButton close = new JButton();
 
-  ButtonGroup buttonGroup = new ButtonGroup();
+    JLabel format = new JLabel(
+            MessageManager.getString("action.format") + " ");
+    format.setHorizontalAlignment(SwingConstants.TRAILING);
 
-  JRadioButton jalviewFormat = new JRadioButton();
+    formatPanel.add(format);
+    formatPanel.add(jalviewFormat);
+    formatPanel.add(GFFFormat);
+    formatPanel.add(CSVFormat);
 
-  JRadioButton GFFFormat = new JRadioButton();
-
-  JRadioButton CSVFormat = new JRadioButton();
-
-  JLabel jLabel1 = new JLabel();
-
-  JPanel jPanel3 = new JPanel();
-
-  FlowLayout flowLayout1 = new FlowLayout();
+    return formatPanel;
+  }
 }
index 70f2ac7..ada4140 100755 (executable)
@@ -29,11 +29,13 @@ import jalview.api.FeaturesSourceI;
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.MappedFeatures;
 import jalview.datamodel.SequenceDummy;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.datamodel.features.FeatureMatcherSet;
 import jalview.datamodel.features.FeatureMatcherSetI;
+import jalview.gui.Desktop;
 import jalview.io.gff.GffHelperBase;
 import jalview.io.gff.GffHelperFactory;
 import jalview.io.gff.GffHelperI;
@@ -49,9 +51,11 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.TreeMap;
 
 /**
  * Parses and writes features files, which may be in Jalview, GFF2 or GFF3
@@ -563,32 +567,31 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
   }
 
   /**
-   * Returns contents of a Jalview format features file, for visible features,
-   * as filtered by type and group. Features with a null group are displayed if
-   * their feature type is visible. Non-positional features may optionally be
-   * included (with no check on type or group).
+   * Returns contents of a Jalview format features file, for visible features, as
+   * filtered by type and group. Features with a null group are displayed if their
+   * feature type is visible. Non-positional features may optionally be included
+   * (with no check on type or group).
    * 
    * @param sequences
    * @param fr
    * @param includeNonPositional
-   *          if true, include non-positional features (regardless of group or
-   *          type)
+   *                               if true, include non-positional features
+   *                               (regardless of group or type)
+   * @param includeComplement
+   *                               if true, include visible complementary
+   *                               (CDS/protein) positional features, with
+   *                               locations converted to local sequence
+   *                               coordinates
    * @return
    */
   public String printJalviewFormat(SequenceI[] sequences,
-          FeatureRenderer fr, boolean includeNonPositional)
+          FeatureRenderer fr, boolean includeNonPositional,
+          boolean includeComplement)
   {
     Map<String, FeatureColourI> visibleColours = fr
             .getDisplayedFeatureCols();
     Map<String, FeatureMatcherSetI> featureFilters = fr.getFeatureFilters();
 
-    if (!includeNonPositional
-            && (visibleColours == null || visibleColours.isEmpty()))
-    {
-      // no point continuing.
-      return "No Features Visible";
-    }
-
     /*
      * write out feature colours (if we know them)
      */
@@ -620,10 +623,125 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
     int count = outputFeaturesByGroup(out, fr, types, sequences,
             includeNonPositional);
 
+    if (includeComplement)
+    {
+      count += outputComplementFeatures(out, fr, sequences);
+    }
+
     return count > 0 ? out.toString() : "No Features Visible";
   }
 
   /**
+   * Outputs any visible complementary positional features, within feature group
+   * 
+   * @param out
+   * @param fr
+   * @param sequences
+   * @return
+   */
+  private int outputComplementFeatures(StringBuilder out,
+          FeatureRenderer fr, SequenceI[] sequences)
+  {
+    AlignViewportI comp = fr.getViewport().getCodingComplement();
+    FeatureRenderer fr2 = Desktop.getAlignFrameFor(comp)
+            .getFeatureRenderer();
+
+    /*
+     * build a map of {group, {seqName, List<SequenceFeature>}}
+     */
+    Map<String, Map<String, List<SequenceFeature>>> map = new TreeMap<>();
+    int count = 0;
+
+    for (SequenceI seq : sequences)
+    {
+      /*
+       * avoid duplication of features (e.g. peptide feature 
+       * at all 3 mapped codon positions)
+       */
+      List<SequenceFeature> found = new ArrayList<>();
+      String seqName = seq.getName();
+
+      for (int pos = seq.getStart(); pos <= seq.getEnd(); pos++)
+      {
+        MappedFeatures mf = fr2.findComplementFeaturesAtResidue(seq, pos);
+
+        if (mf != null)
+        {
+          MapList mapping = mf.mapping.getMap();
+          for (SequenceFeature sf : mf.features)
+          {
+            String group = sf.getFeatureGroup();
+            if (group == null)
+            {
+              group = "";
+            }
+            if (!map.containsKey(group))
+            {
+              map.put(group, new LinkedHashMap<>());
+            }
+            Map<String, List<SequenceFeature>> groupFeatures = map
+                    .get(group);
+            if (!groupFeatures.containsKey(seqName))
+            {
+              groupFeatures.put(seqName, new ArrayList<>());
+            }
+            List<SequenceFeature> foundFeatures = groupFeatures
+                    .get(seqName);
+
+            /*
+             * make a virtual feature with local coordinates
+             */
+            if (!found.contains(sf))
+            {
+              found.add(sf);
+              int begin = sf.getBegin();
+              int end = sf.getEnd();
+              int[] range = mf.mapping.getTo() == seq.getDatasetSequence()
+                      ? mapping.locateInTo(begin, end)
+                      : mapping.locateInFrom(begin, end);
+              SequenceFeature sf2 = new SequenceFeature(sf, range[0],
+                      range[1], group,
+                      sf.getScore());
+              foundFeatures.add(sf2);
+              count++;
+            }
+          }
+        }
+      }
+    }
+
+    /*
+     * output features by group
+     */
+    for (Entry<String, Map<String, List<SequenceFeature>>> groupFeatures : map.entrySet())
+    {
+      out.append(newline);
+      String group = groupFeatures.getKey();
+      if (!"".equals(group))
+      {
+        out.append(STARTGROUP).append(TAB).append(group).append(newline);
+      }
+      Map<String, List<SequenceFeature>> seqFeaturesMap = groupFeatures
+              .getValue();
+      for (Entry<String, List<SequenceFeature>> seqFeatures : seqFeaturesMap
+              .entrySet())
+      {
+        String sequenceName = seqFeatures.getKey();
+        for (SequenceFeature sf : seqFeatures.getValue())
+        {
+          out.append(formatJalviewFeature(sequenceName, sf));
+        }
+      }
+      if (!"".equals(group))
+      {
+        out.append(ENDGROUP).append(TAB).append(group).append(newline);
+      }
+    }
+
+    return count;
+  }
+
+  /**
    * Outputs any feature filters defined for visible feature types, sandwiched by
    * STARTFILTERS and ENDFILTERS lines
    * 
@@ -876,15 +994,19 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
    * Returns features output in GFF2 format
    * 
    * @param sequences
-   *          the sequences whose features are to be output
+   *                                       the sequences whose features are to be
+   *                                       output
    * @param visible
-   *          a map whose keys are the type names of visible features
+   *                                       a map whose keys are the type names of
+   *                                       visible features
    * @param visibleFeatureGroups
    * @param includeNonPositionalFeatures
+   * @param includeComplement
    * @return
    */
   public String printGffFormat(SequenceI[] sequences,
-          FeatureRenderer fr, boolean includeNonPositionalFeatures)
+          FeatureRenderer fr, boolean includeNonPositionalFeatures,
+          boolean includeComplement)
   {
     Map<String, FeatureColourI> visibleColours = fr.getDisplayedFeatureCols();
 
index 6f7bebe..090de6f 100644 (file)
@@ -476,7 +476,7 @@ public class FeaturesFileTest
      */
     FeatureRenderer fr = af.alignPanel.getFeatureRenderer();
     String exported = featuresFile
-            .printJalviewFormat(al.getSequencesArray(), fr, false);
+            .printJalviewFormat(al.getSequencesArray(), fr, false, false);
     String expected = "No Features Visible";
     assertEquals(expected, exported);
 
@@ -485,7 +485,7 @@ public class FeaturesFileTest
      */
     fr.setGroupVisibility("uniprot", true);
     exported = featuresFile.printJalviewFormat(al.getSequencesArray(), fr,
-            true);
+            true, false);
     expected = "\nSTARTGROUP\tuniprot\n"
             + "Cath\tFER_CAPAA\t-1\t0\t0\tDomain\t0.0\n"
             + "ENDGROUP\tuniprot\n\n"
@@ -499,7 +499,7 @@ public class FeaturesFileTest
     fr.setVisible("METAL");
     fr.setVisible("GAMMA-TURN");
     exported = featuresFile.printJalviewFormat(al.getSequencesArray(), fr,
-            false);
+            false, false);
     expected = "METAL\tcc9900\n"
             + "GAMMA-TURN\tscore|ff0000|00ffff|noValueMin|20.0|95.0|below|66.0\n"
             + "\nSTARTGROUP\tuniprot\n"
@@ -513,7 +513,7 @@ public class FeaturesFileTest
      */
     fr.setVisible("Pfam");
     exported = featuresFile.printJalviewFormat(al.getSequencesArray(), fr,
-            false);
+            false, false);
     /*
      * features are output within group, ordered by sequence and type
      */
@@ -539,14 +539,14 @@ public class FeaturesFileTest
             + "\ndesc2\tFER_CAPAN\t-1\t4\t9\tPfam\n"
             + "\ndesc4\tFER1_SOLLC\t-1\t5\t8\tPfam\t-2.6\n";
     exported = featuresFile.printJalviewFormat(al.getSequencesArray(), fr,
-            false);
+            false, false);
     assertEquals(expected, exported);
 
     /*
      * include non-positional (overrides group not shown)
      */
     exported = featuresFile.printJalviewFormat(al.getSequencesArray(), fr,
-            true);
+            true, false);
     expected = "METAL\tcc9900\n" + "Pfam\tff0000\n"
             + "GAMMA-TURN\tscore|ff0000|00ffff|noValueMin|20.0|95.0|below|66.0\n"
             + "\nSTARTGROUP\tuniprot\n"
@@ -573,11 +573,11 @@ public class FeaturesFileTest
     FeatureRendererModel fr = (FeatureRendererModel) af.alignPanel
             .getFeatureRenderer();
     String exported = featuresFile.printGffFormat(al.getSequencesArray(),
-            fr, false);
+            fr, false, false);
     String gffHeader = "##gff-version 2\n";
     assertEquals(gffHeader, exported);
     exported = featuresFile.printGffFormat(al.getSequencesArray(), fr,
-            true);
+            true, false);
     assertEquals(gffHeader, exported);
 
     /*
@@ -614,7 +614,7 @@ public class FeaturesFileTest
      * with no features displayed, exclude non-positional features
      */
     exported = featuresFile.printGffFormat(al.getSequencesArray(), fr,
-            false);
+            false, false);
     assertEquals(gffHeader, exported);
 
     /*
@@ -623,7 +623,7 @@ public class FeaturesFileTest
     fr.setGroupVisibility("Uniprot", true);
     fr.setGroupVisibility("s3dm", false);
     exported = featuresFile.printGffFormat(al.getSequencesArray(), fr,
-            true);
+            true, false);
     String expected = gffHeader
             + "FER_CAPAA\tUniprot\tDomain\t0\t0\t0.0\t.\t.\n";
     assertEquals(expected, exported);
@@ -635,7 +635,7 @@ public class FeaturesFileTest
     fr.setVisible("METAL");
     fr.setVisible("GAMMA-TURN");
     exported = featuresFile.printGffFormat(al.getSequencesArray(), fr,
-            false);
+            false, false);
     // METAL feature has null group: description used for column 2
     expected = gffHeader + "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\n";
     assertEquals(expected, exported);
@@ -645,7 +645,7 @@ public class FeaturesFileTest
      */
     fr.setGroupVisibility("s3dm", true);
     exported = featuresFile.printGffFormat(al.getSequencesArray(), fr,
-            false);
+            false, false);
     // METAL feature has null group: description used for column 2
     expected = gffHeader + "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\n"
             + "FER_CAPAN\ts3dm\tGAMMA-TURN\t36\t38\t2.1\t.\t.\n";
@@ -656,7 +656,7 @@ public class FeaturesFileTest
      */
     fr.setVisible("Pfam");
     exported = featuresFile.printGffFormat(al.getSequencesArray(), fr,
-            false);
+            false, false);
     // Pfam feature columns include strand(+), phase(2), attributes
     expected = gffHeader
             + "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\n"
@@ -770,7 +770,7 @@ public class FeaturesFileTest
     fr.setVisible("METAL");
     fr.setColour("METAL", new FeatureColour(Color.PINK));
     String exported = featuresFile.printGffFormat(al.getSequencesArray(),
-            fr, false);
+            fr, false, false);
     String expected = gffHeader
             + "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\n"
             + "FER_CAPAA\tCath\tMETAL\t41\t41\t0.6\t.\t.\n";
@@ -785,7 +785,7 @@ public class FeaturesFileTest
     fc.setThreshold(1.1f);
     fr.setColour("METAL", fc);
     exported = featuresFile.printGffFormat(al.getSequencesArray(), fr,
-            false);
+            false, false);
     expected = gffHeader + "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\n";
     assertEquals(expected, exported);
 
@@ -794,7 +794,7 @@ public class FeaturesFileTest
      */
     fc.setAboveThreshold(false);
     exported = featuresFile.printGffFormat(al.getSequencesArray(), fr,
-            false);
+            false, false);
     expected = gffHeader + "FER_CAPAA\tCath\tMETAL\t39\t39\t1.2\t.\t.\n"
             + "FER_CAPAA\tCath\tMETAL\t41\t41\t0.6\t.\t.\n";
     assertEquals(expected, exported);
@@ -807,7 +807,7 @@ public class FeaturesFileTest
             "clin_sig"));
     fr.setFeatureFilter("METAL", filter);
     exported = featuresFile.printGffFormat(al.getSequencesArray(), fr,
-            false);
+            false, false);
     expected = gffHeader + "FER_CAPAA\tCath\tMETAL\t41\t41\t0.6\t.\t.\n";
     assertEquals(expected, exported);
   }
@@ -843,7 +843,7 @@ public class FeaturesFileTest
     fr.setColour("METAL", new FeatureColour(Color.PINK));
     String exported = featuresFile.printJalviewFormat(
             al.getSequencesArray(),
-            fr, false);
+            fr, false, false);
     String expected = "METAL\tffafaf\n\nSTARTGROUP\tgrp1\n"
             + "Cath\tFER_CAPAA\t-1\t39\t39\tMETAL\t1.2\n"
             + "ENDGROUP\tgrp1\n\nSTARTGROUP\tgrp2\n"
@@ -861,7 +861,7 @@ public class FeaturesFileTest
     fc.setThreshold(1.1f);
     fr.setColour("METAL", fc);
     exported = featuresFile.printJalviewFormat(al.getSequencesArray(), fr,
-            false);
+            false, false);
     expected = "METAL\tscore|ffffff|000000|noValueMin|abso|0.0|2.0|above|1.1\n\n"
             + "STARTGROUP\tgrp1\n"
             + "Cath\tFER_CAPAA\t-1\t39\t39\tMETAL\t1.2\n"
@@ -873,7 +873,7 @@ public class FeaturesFileTest
      */
     fc.setAboveThreshold(false);
     exported = featuresFile.printJalviewFormat(al.getSequencesArray(), fr,
-            false);
+            false, false);
     expected = "METAL\tscore|ffffff|000000|noValueMin|abso|0.0|2.0|none\n\n"
             + "STARTGROUP\tgrp1\n"
             + "Cath\tFER_CAPAA\t-1\t39\t39\tMETAL\t1.2\n"
@@ -890,7 +890,7 @@ public class FeaturesFileTest
             "clin_sig"));
     fr.setFeatureFilter("METAL", filter);
     exported = featuresFile.printJalviewFormat(al.getSequencesArray(), fr,
-            false);
+            false, false);
     expected = "FER_CAPAA\tCath\tMETAL\t41\t41\t0.6\t.\t.\n";
     expected = "METAL\tscore|ffffff|000000|noValueMin|abso|0.0|2.0|none\n\n"
             + "STARTFILTERS\nMETAL\tclin_sig Contains benign\nENDFILTERS\n\n"