From 1f8022f2b026e9852c76f0803d92da016a1bde5e Mon Sep 17 00:00:00 2001 From: Charles Ofoegbu Date: Sat, 10 Jan 2015 14:29:31 +0000 Subject: [PATCH 1/1] JAL-1553 implementation of column selection by annotation and threshold queries --- src/jalview/gui/AlignFrame.java | 6 + src/jalview/gui/AlignViewport.java | 12 + src/jalview/gui/AnnotationColumnSelection.java | 660 ++++++++++++++++++++++++ src/jalview/jbgui/GAlignFrame.java | 18 + 4 files changed, 696 insertions(+) create mode 100644 src/jalview/gui/AnnotationColumnSelection.java diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index 3273121..af3b0fb 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -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); diff --git a/src/jalview/gui/AlignViewport.java b/src/jalview/gui/AlignViewport.java index 497dad4..10e14d1 100644 --- a/src/jalview/gui/AlignViewport.java +++ b/src/jalview/gui/AlignViewport.java @@ -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 index 0000000..ee8f03a --- /dev/null +++ b/src/jalview/gui/AnnotationColumnSelection.java @@ -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 getAnnotationItems(boolean isSeqAssociated) + { + Vector list = new Vector(); + 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; + } + +} diff --git a/src/jalview/jbgui/GAlignFrame.java b/src/jalview/jbgui/GAlignFrame.java index 4bf8176..7a5dc54 100755 --- a/src/jalview/jbgui/GAlignFrame.java +++ b/src/jalview/jbgui/GAlignFrame.java @@ -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) { -- 1.7.10.2