JAL-1553 implementation of column selection by annotation and threshold queries
authorCharles Ofoegbu <tcnofoegbu@dundee.ac.uk>
Sat, 10 Jan 2015 14:29:31 +0000 (14:29 +0000)
committerCharles Ofoegbu <tcnofoegbu@dundee.ac.uk>
Sat, 10 Jan 2015 14:29:31 +0000 (14:29 +0000)
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignViewport.java
src/jalview/gui/AnnotationColumnSelection.java [new file with mode: 0644]
src/jalview/jbgui/GAlignFrame.java

index 3273121..af3b0fb 100644 (file)
@@ -3325,6 +3325,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   }
 
   @Override
+  public void annotationColumn_actionPerformed(ActionEvent e)
+  {
+    new AnnotationColumnSelection(viewport, alignPanel);
+  }
+
+  @Override
   public void rnahelicesColour_actionPerformed(ActionEvent e)
   {
     new RNAHelicesColourChooser(viewport, alignPanel);
index 497dad4..10e14d1 100644 (file)
@@ -151,6 +151,7 @@ public class AlignViewport extends AlignmentViewport implements
 
   private boolean rightAlignIds = false;
 
+  private AnnotationColumnSelection currentAnnotationColumnSelectionState;
   /**
    * Creates a new AlignViewport object.
    * 
@@ -1318,4 +1319,15 @@ public class AlignViewport extends AlignmentViewport implements
   {
     this.rightAlignIds = rightAlignIds;
   }
+
+  public AnnotationColumnSelection getCurrentAnnotationColumnSelectionState()
+  {
+    return currentAnnotationColumnSelectionState;
+  }
+
+  public void setCurrentAnnotationColumnSelectionState(
+          AnnotationColumnSelection currentAnnotationColumnSelectionState)
+  {
+    this.currentAnnotationColumnSelectionState = currentAnnotationColumnSelectionState;
+  }
 }
diff --git a/src/jalview/gui/AnnotationColumnSelection.java b/src/jalview/gui/AnnotationColumnSelection.java
new file mode 100644 (file)
index 0000000..ee8f03a
--- /dev/null
@@ -0,0 +1,660 @@
+package jalview.gui;
+
+import jalview.bin.Cache;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.GraphLine;
+import jalview.schemes.AnnotationColourGradient;
+import jalview.schemes.ColourSchemeI;
+import jalview.util.MessageManager;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JInternalFrame;
+import javax.swing.JLayeredPane;
+import javax.swing.JPanel;
+import javax.swing.JSlider;
+import javax.swing.JTextField;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import net.miginfocom.swing.MigLayout;
+
+public class AnnotationColumnSelection extends JPanel
+{
+  JInternalFrame frame;
+
+  AlignViewport av;
+
+  AlignmentPanel ap;
+
+  ColourSchemeI oldcs;
+
+  Hashtable oldgroupColours;
+
+  private JComboBox annotations;
+
+  int[] annmap;
+
+  JPanel minColour = new JPanel();
+
+  JPanel maxColour = new JPanel();
+
+  JButton defColours = new JButton();
+
+  JButton ok = new JButton();
+
+  JButton cancel = new JButton();
+
+  JPanel jPanel1 = new JPanel();
+
+  JPanel jPanel2 = new JPanel();
+
+  BorderLayout borderLayout1 = new BorderLayout();
+
+  private JComboBox threshold = new JComboBox();
+
+  JSlider slider = new JSlider();
+
+  JTextField thresholdValue = new JTextField(20);
+
+  JCheckBox currentColours = new JCheckBox();
+
+  JCheckBox thresholdIsMin = new JCheckBox();
+
+  JCheckBox seqAssociated = new JCheckBox();
+
+  private jalview.datamodel.AlignmentAnnotation currentAnnotation;
+
+  boolean adjusting = false;
+
+  /**
+   * enabled if the user is dragging the slider - try to keep updates to a
+   * minimun
+   */
+  boolean sliderDragging = false;
+
+  public AnnotationColumnSelection(AlignViewport av, final AlignmentPanel ap)
+  {
+
+    this.av = av;
+    this.ap = ap;
+    frame = new JInternalFrame();
+    frame.setContentPane(this);
+    frame.setLayer(JLayeredPane.PALETTE_LAYER);
+    Desktop.addInternalFrame(frame, "Select By Annotation", 520, 215);
+
+    slider.addChangeListener(new ChangeListener()
+    {
+      @Override
+      public void stateChanged(ChangeEvent evt)
+      {
+        if (!adjusting)
+        {
+          thresholdValue.setText((slider.getValue() / 1000f) + "");
+          valueChanged(!sliderDragging);
+        }
+      }
+    });
+    slider.addMouseListener(new MouseAdapter()
+    {
+      @Override
+      public void mousePressed(MouseEvent e)
+      {
+        sliderDragging = true;
+        super.mousePressed(e);
+      }
+
+      @Override
+      public void mouseDragged(MouseEvent e)
+      {
+        sliderDragging = true;
+        super.mouseDragged(e);
+      }
+
+      @Override
+      public void mouseReleased(MouseEvent evt)
+      {
+        if (sliderDragging)
+        {
+          sliderDragging = false;
+          valueChanged(true);
+        }
+        ap.paintAlignment(true);
+      }
+    });
+
+    if (av.getAlignment().getAlignmentAnnotation() == null)
+    {
+      return;
+    }
+
+    // Always get default shading from preferences.
+    setDefaultMinMax();
+
+    adjusting = true;
+
+    setAnnotations(new JComboBox(
+            getAnnotationItems(seqAssociated.isSelected())));
+
+    threshold.addItem(MessageManager
+            .getString("label.threshold_feature_no_thereshold"));
+    threshold.addItem(MessageManager
+            .getString("label.threshold_feature_above_thereshold"));
+    threshold.addItem(MessageManager
+            .getString("label.threshold_feature_below_thereshold"));
+
+    if (av.getCurrentAnnotationColumnSelectionState() != null)
+    {
+      annotations.setSelectedIndex(av
+              .getCurrentAnnotationColumnSelectionState().getAnnotations()
+              .getSelectedIndex());
+      threshold.setSelectedIndex(av
+              .getCurrentAnnotationColumnSelectionState().getThreshold()
+              .getSelectedIndex());
+      System.out.println("selected annotation : "
+              + av.getCurrentAnnotationColumnSelectionState()
+                      .getAnnotations().getSelectedIndex());
+      System.out.println("selected threshold : "
+              + av.getCurrentAnnotationColumnSelectionState()
+                      .getThreshold().getSelectedIndex());
+    }
+
+    try
+    {
+      jbInit();
+    } catch (Exception ex)
+    {
+    }
+
+    adjusting = false;
+
+    changeColumnSelection();
+    frame.invalidate();
+    frame.pack();
+
+  }
+
+  private Vector<String> getAnnotationItems(boolean isSeqAssociated)
+  {
+    Vector<String> list = new Vector<String>();
+    int index = 1;
+    int[] anmap = new int[av.getAlignment().getAlignmentAnnotation().length];
+    boolean enableSeqAss = false;
+    for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
+    {
+      if (av.getAlignment().getAlignmentAnnotation()[i].sequenceRef == null)
+      {
+        if (isSeqAssociated)
+        {
+          continue;
+        }
+      }
+      else
+      {
+        enableSeqAss = true;
+      }
+      String label = av.getAlignment().getAlignmentAnnotation()[i].label;
+      if (!list.contains(label))
+      {
+        anmap[list.size()] = i;
+        list.add(label);
+
+      }
+      else
+      {
+        if (!isSeqAssociated)
+        {
+          anmap[list.size()] = i;
+          list.add(label + "_" + (index++));
+        }
+      }
+    }
+    seqAssociated.setEnabled(enableSeqAss);
+    this.annmap = new int[list.size()];
+    System.arraycopy(anmap, 0, this.annmap, 0, this.annmap.length);
+    return list;
+  }
+
+  private void setDefaultMinMax()
+  {
+    minColour.setBackground(Cache.getDefaultColour("ANNOTATIONCOLOUR_MIN",
+            Color.orange));
+    maxColour.setBackground(Cache.getDefaultColour("ANNOTATIONCOLOUR_MAX",
+            Color.red));
+  }
+
+  public AnnotationColumnSelection()
+  {
+    try
+    {
+      jbInit();
+    } catch (Exception ex)
+    {
+      ex.printStackTrace();
+    }
+  }
+
+  private void jbInit() throws Exception
+  {
+    ok.setOpaque(false);
+    ok.setText(MessageManager.getString("action.ok"));
+    ok.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        ok_actionPerformed(e);
+      }
+    });
+    cancel.setOpaque(false);
+    cancel.setText(MessageManager.getString("action.cancel"));
+    cancel.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        cancel_actionPerformed(e);
+      }
+    });
+
+    getAnnotations().addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        annotations_actionPerformed(e);
+      }
+    });
+    getThreshold().addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        threshold_actionPerformed(e);
+      }
+    });
+    thresholdValue.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        thresholdValue_actionPerformed(e);
+      }
+    });
+    slider.setPaintLabels(false);
+    slider.setPaintTicks(true);
+    slider.setBackground(Color.white);
+    slider.setEnabled(false);
+    slider.setOpaque(false);
+    slider.setPreferredSize(new Dimension(100, 32));
+    thresholdValue.setEnabled(false);
+    thresholdValue.setColumns(7);
+    thresholdIsMin.setBackground(Color.white);
+    thresholdIsMin.setFont(JvSwingUtils.getLabelFont());
+    thresholdIsMin.setText(MessageManager
+            .getString("label.threshold_minmax"));
+    thresholdIsMin.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent actionEvent)
+      {
+        thresholdIsMin_actionPerformed(actionEvent);
+      }
+    });
+    seqAssociated.setBackground(Color.white);
+    seqAssociated.setFont(JvSwingUtils.getLabelFont());
+    seqAssociated.setText(MessageManager
+            .getString("label.per_sequence_only"));
+    seqAssociated.addActionListener(new ActionListener()
+    {
+
+      @Override
+      public void actionPerformed(ActionEvent arg0)
+      {
+        seqAssociated_actionPerformed(arg0);
+      }
+    });
+
+    this.setLayout(borderLayout1);
+    jPanel2.setLayout(new MigLayout("", "[left][center][right]", "[][][]"));
+    jPanel1.setBackground(Color.white);
+    jPanel2.setBackground(Color.white);
+
+    jPanel1.add(ok);
+    jPanel1.add(cancel);
+    jPanel2.add(getAnnotations(), "grow, wrap");
+    jPanel2.add(seqAssociated, "wrap");
+    jPanel2.add(getThreshold(), "grow, wrap");
+    jPanel2.add(thresholdIsMin, "wrap");
+    jPanel2.add(slider, "grow");
+    jPanel2.add(thresholdValue, "grow");
+    this.add(jPanel1, java.awt.BorderLayout.SOUTH);
+    this.add(jPanel2, java.awt.BorderLayout.CENTER);
+    this.validate();
+  }
+
+  protected void seqAssociated_actionPerformed(ActionEvent arg0)
+  {
+    adjusting = true;
+    String cursel = (String) getAnnotations().getSelectedItem();
+    boolean isvalid = false, isseqs = seqAssociated.isSelected();
+    this.getAnnotations().removeAllItems();
+    for (String anitem : getAnnotationItems(seqAssociated.isSelected()))
+    {
+      if (anitem.equals(cursel) || (isseqs && cursel.startsWith(anitem)))
+      {
+        isvalid = true;
+        cursel = anitem;
+      }
+      this.getAnnotations().addItem(anitem);
+    }
+    adjusting = false;
+    if (isvalid)
+    {
+      this.getAnnotations().setSelectedItem(cursel);
+    }
+    else
+    {
+      if (getAnnotations().getItemCount() > 0)
+      {
+        getAnnotations().setSelectedIndex(0);
+      }
+    }
+  }
+
+
+  void changeColumnSelection()
+  {
+    // Check if combobox is still adjusting
+    if (adjusting)
+    {
+      return;
+    }
+
+    setCurrentAnnotation(av.getAlignment().getAlignmentAnnotation()[annmap[getAnnotations()
+            .getSelectedIndex()]]);
+
+    int aboveThreshold = -1;
+    if (getThreshold().getSelectedIndex() == 1)
+    {
+      aboveThreshold = AnnotationColourGradient.ABOVE_THRESHOLD;
+    }
+    else if (getThreshold().getSelectedIndex() == 2)
+    {
+      aboveThreshold = AnnotationColourGradient.BELOW_THRESHOLD;
+    }
+
+    slider.setEnabled(true);
+    thresholdValue.setEnabled(true);
+    thresholdIsMin.setEnabled(true);
+
+    if (aboveThreshold == AnnotationColourGradient.NO_THRESHOLD)
+    {
+      slider.setEnabled(false);
+      thresholdValue.setEnabled(false);
+      thresholdValue.setText("");
+      thresholdIsMin.setEnabled(false);
+    }
+    else if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD
+            && getCurrentAnnotation().threshold == null)
+    {
+      getCurrentAnnotation()
+              .setThreshold(new jalview.datamodel.GraphLine(
+                              (getCurrentAnnotation().graphMax - getCurrentAnnotation().graphMin) / 2f,
+                      "Threshold", Color.black));
+    }
+
+    if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
+    {
+      adjusting = true;
+      float range = getCurrentAnnotation().graphMax * 1000
+              - getCurrentAnnotation().graphMin * 1000;
+
+      slider.setMinimum((int) (getCurrentAnnotation().graphMin * 1000));
+      slider.setMaximum((int) (getCurrentAnnotation().graphMax * 1000));
+      slider.setValue((int) (getCurrentAnnotation().threshold.value * 1000));
+      thresholdValue.setText(getCurrentAnnotation().threshold.value + "");
+      slider.setMajorTickSpacing((int) (range / 10f));
+      slider.setEnabled(true);
+      thresholdValue.setEnabled(true);
+      adjusting = false;
+    }
+
+    markColumnsContaining(getCurrentAnnotation(), aboveThreshold);
+    av.setCurrentAnnotationColumnSelectionState(this);
+    ap.alignmentChanged();
+    // ensure all associated views (overviews, structures, etc) are notified of
+    // updated colours.
+    ap.paintAlignment(true);
+  }
+
+  public boolean markColumnsContaining(
+          AlignmentAnnotation currentAnnotation, int thresholdComparisonType)
+  {
+    try
+    {
+      if (currentAnnotation != null)
+      {
+        Annotation[] annotations = currentAnnotation.annotations;
+        ColumnSelection cs = av.getColumnSelection();
+        cs.clear();
+        if (thresholdComparisonType == AnnotationColourGradient.NO_THRESHOLD)
+        {
+          int count = 0;
+          do
+          {
+            if (annotations[count] != null)
+            {
+              if (currentAnnotation.label.equals("Secondary Structure")
+                      && annotations[count].secondaryStructure != ' ')
+              {
+                cs.addElement(count);
+              }
+              else if (currentAnnotation.label
+                      .equals("Iron Sulphur Contacts"))
+              {
+                cs.addElement(count);
+              }
+              else if (annotations[count].value != 0.0)
+              {
+                cs.addElement(count);
+              }
+
+            }
+            count++;
+          } while (count < annotations.length);
+        }
+        else
+        {
+          int count = 0;
+          do
+          {
+            if (annotations[count] != null)
+            {
+              if (thresholdComparisonType == AnnotationColourGradient.ABOVE_THRESHOLD)
+              {
+                if (annotations[count].value > currentAnnotation.threshold.value)
+                {
+                  cs.addElement(count);
+                }
+              }
+              else if (thresholdComparisonType == AnnotationColourGradient.BELOW_THRESHOLD)
+              {
+                if (annotations[count].value < currentAnnotation.threshold.value)
+                {
+                  cs.addElement(count);
+                }
+              }
+
+            }
+            count++;
+          } while (count < annotations.length);
+        }
+      }
+
+      return true;
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+      return false;
+    }
+  }
+
+  public void ok_actionPerformed(ActionEvent e)
+  {
+    changeColumnSelection();
+    try
+    {
+      frame.setClosed(true);
+    } catch (Exception ex)
+    {
+    }
+  }
+
+  public void cancel_actionPerformed(ActionEvent e)
+  {
+    reset();
+    // ensure all original colouring is propagated to listeners.
+    ap.paintAlignment(true);
+    try
+    {
+      frame.setClosed(true);
+    } catch (Exception ex)
+    {
+    }
+  }
+
+  void reset()
+  {
+    av.getColumnSelection().clear();
+  }
+
+  public void thresholdCheck_actionPerformed(ActionEvent e)
+  {
+    changeColumnSelection();
+  }
+
+  public void annotations_actionPerformed(ActionEvent e)
+  {
+    changeColumnSelection();
+  }
+
+  public void threshold_actionPerformed(ActionEvent e)
+  {
+    changeColumnSelection();
+  }
+
+  public void thresholdValue_actionPerformed(ActionEvent e)
+  {
+    try
+    {
+      float f = Float.parseFloat(thresholdValue.getText());
+      slider.setValue((int) (f * 1000));
+      changeColumnSelection();
+    } catch (NumberFormatException ex)
+    {
+    }
+  }
+
+  public void valueChanged(boolean updateAllAnnotation)
+  {
+    getCurrentAnnotation().threshold.value = slider.getValue() / 1000f;
+    changeColumnSelection();
+    // propagateSeqAssociatedThreshold(updateAllAnnotation);
+    ap.paintAlignment(false);
+  }
+
+  private void propagateSeqAssociatedThreshold(boolean allAnnotation)
+  {
+    if (getCurrentAnnotation().sequenceRef == null
+            || getCurrentAnnotation().threshold == null)
+    {
+      return;
+    }
+
+
+    float thr = getCurrentAnnotation().threshold.value;
+    for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
+    {
+      AlignmentAnnotation aa = av.getAlignment().getAlignmentAnnotation()[i];
+      if (aa.label.equals(getCurrentAnnotation().label)
+              && (getCurrentAnnotation().getCalcId() == null ? aa
+                      .getCalcId() == null : getCurrentAnnotation()
+                      .getCalcId()
+                              .equals(aa.getCalcId())))
+      {
+        if (aa.threshold == null)
+        {
+          aa.threshold = new GraphLine(getCurrentAnnotation().threshold);
+        }
+        else
+        {
+          aa.threshold.value = thr;
+        }
+      }
+    }
+  }
+
+  public void currentColours_actionPerformed(ActionEvent e)
+  {
+    if (currentColours.isSelected())
+    {
+      reset();
+    }
+
+    maxColour.setEnabled(!currentColours.isSelected());
+    minColour.setEnabled(!currentColours.isSelected());
+
+    changeColumnSelection();
+  }
+
+  public void thresholdIsMin_actionPerformed(ActionEvent actionEvent)
+  {
+    changeColumnSelection();
+  }
+
+  public jalview.datamodel.AlignmentAnnotation getCurrentAnnotation()
+  {
+    return currentAnnotation;
+  }
+
+  public void setCurrentAnnotation(
+          jalview.datamodel.AlignmentAnnotation currentAnnotation)
+  {
+    this.currentAnnotation = currentAnnotation;
+  }
+
+  public JComboBox getThreshold()
+  {
+    return threshold;
+  }
+
+  public void setThreshold(JComboBox threshold)
+  {
+    this.threshold = threshold;
+  }
+
+  public JComboBox getAnnotations()
+  {
+    return annotations;
+  }
+
+  public void setAnnotations(JComboBox annotations)
+  {
+    this.annotations = annotations;
+  }
+
+}
index 4bf8176..7a5dc54 100755 (executable)
@@ -268,6 +268,8 @@ public class GAlignFrame extends JInternalFrame
 
   JMenuItem annotationColour = new JMenuItem();
 
+  JMenuItem annotationColumn = new JMenuItem();
+
   protected JMenuItem rnahelicesColour = new JMenuItem();
 
   JMenuItem associatedData = new JMenuItem();
@@ -1874,6 +1876,16 @@ public class GAlignFrame extends JInternalFrame
       }
     });
 
+    annotationColumn.setText("Select by annotation...");
+    annotationColumn.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        annotationColumn_actionPerformed(e);
+      }
+    });
+
     rnahelicesColour.setText(MessageManager
             .getString("action.by_rna_helixes"));
     rnahelicesColour.addActionListener(new ActionListener()
@@ -2408,6 +2420,7 @@ public class GAlignFrame extends JInternalFrame
     selectMenu.add(unGroup);
     selectMenu.add(grpsFromSelection);
     selectMenu.add(deleteGroups);
+    selectMenu.add(annotationColumn);
     calculateMenu.add(expandAlignment);
     // TODO - determine if the listenToViewSelections button is needed : see bug
     // JAL-574
@@ -2986,6 +2999,11 @@ public class GAlignFrame extends JInternalFrame
 
   }
 
+  public void annotationColumn_actionPerformed(ActionEvent e)
+  {
+
+  }
+
   public void rnahelicesColour_actionPerformed(ActionEvent e)
   {