Skip to content
Snippets Groups Projects
BasePlot.java 28.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • tjc's avatar
    tjc committed
    /* BasePlot.java
     *
     * created: Tue Dec 15 1998
     *
     * This file is part of Artemis
     *
     * Copyright (C) 1998,1999,2000,2001  Genome Research Limited
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * as published by the Free Software Foundation; either version 2
     * of the License, or (at your option) any later version.
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with this program; if not, write to the Free Software
     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     *
    
     * $Header: //tmp/pathsoft/artemis/uk/ac/sanger/artemis/components/BasePlot.java,v 1.20 2009-07-20 15:11:17 tjc Exp $
    
    tjc's avatar
    tjc committed
     **/
    
    package uk.ac.sanger.artemis.components;
    
    import uk.ac.sanger.artemis.*;
    import uk.ac.sanger.artemis.sequence.*;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.components.genebuilder.GeneUtils;
    import uk.ac.sanger.artemis.io.EntryInformationException;
    import uk.ac.sanger.artemis.io.Key;
    import uk.ac.sanger.artemis.io.Location;
    import uk.ac.sanger.artemis.io.Qualifier;
    import uk.ac.sanger.artemis.io.QualifierVector;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.plot.*;
    import uk.ac.sanger.artemis.util.OutOfRangeException;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.util.ReadOnlyException;
    
    tjc's avatar
    tjc committed
    
    import java.awt.*;
    import java.awt.event.*;
    
    tjc's avatar
    tjc committed
    import java.text.NumberFormat;
    
    
    tjc's avatar
    tjc committed
    import javax.swing.JLabel;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    
    
    import org.apache.log4j.Level;
    
    
    tjc's avatar
    tjc committed
    
    /**
     *  A component for plotting functions over the base sequence.  Scrolling and
     *  scale is tied to a FeatureDisplay component.
     *
     *  @author Kim Rutherford
    
     *  @version $Id: BasePlot.java,v 1.20 2009-07-20 15:11:17 tjc Exp $
    
    tjc's avatar
    tjc committed
     **/
    
    public class BasePlot extends Plot
    
    tjc's avatar
    tjc committed
        implements DisplayAdjustmentListener, SelectionChangeListener 
    {
    
    tjc's avatar
    tjc committed
      private static final long serialVersionUID = 1L;
    
    
    tjc's avatar
    tjc committed
      /**
       *  The start base to plot, as obtained from the DisplayAdjustmentEvent.
       **/
      private int start_base;
    
      /**
       *  The end base to plot, as obtained from the DisplayAdjustmentEvent.
       **/
      private int end_base;
    
      /**
       *  The width in bases of the display, as obtained from the
       *  DisplayAdjustmentEvent.
       **/
      private int width_in_bases;
    
      /**
       *  True if and only if the FeatureDisplay is drawing in reverse complement
       *  mode.
       **/
      private boolean rev_comp_display;
    
      /**
       *  The Bases that this BasePlot is graphing.
       **/
      private Bases bases;
    
      /**
       *  The Marker of the start of the selection.  This is a cache used by
       *  getSelectionStartMarker().
       **/
      private Marker selection_start_marker = null;
    
      /**
       *  The Marker of the end of the selection.  This is a cache used by
       *  getSelectionEndMarker()
       **/
      private Marker selection_end_marker = null;
    
      /**
       *  The Selection that was passed to the constructor.
       **/
      private Selection selection;
    
      /**
       *  The GotoEventSource that was passed to the constructor.
       **/
      private GotoEventSource goto_event_source;
      
      /**
       *  This array is used by drawMultiValueGraph().  It is reallocated when
       *  the scale changes.
       **/
      private float[][] value_array_array = null;
    
      /**
       *  The number of bases to step before each evaluation of the algorithm.
       *  (Set by recalculateValues()).
       **/
      private int step_size = 0;
    
      /**
       *  The maximum of the values in value_array_array.
       **/
      private float min_value = Float.MAX_VALUE;
    
      /**
       *  The minimum of the values in value_array_array.
       **/
      private float max_value = Float.MIN_VALUE;
      
    
    tjc's avatar
    tjc committed
      private EntryGroup entryGroup;
      
    
    tjc's avatar
    tjc committed
      /**
       *  Used by getPreferredSize() and getMinimumSize();
       **/
    
    tjc's avatar
    tjc committed
      protected static int HEIGHT;
    
    tjc's avatar
    tjc committed
    
      static 
      {
        final Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
    
        final Integer base_plot_height = 
          Options.getOptions().getIntegerProperty("base_plot_height");
    
        if(base_plot_height == null) 
        {
          if(screen.height <= 600) 
            HEIGHT = 100;
          else 
    
    tjc's avatar
    tjc committed
            HEIGHT = 120;
    
    tjc's avatar
    tjc committed
        }
        else
          HEIGHT = base_plot_height.intValue();
      }
      
    
    tjc's avatar
    tjc committed
      /**
       *  Create a new FeatureDisplay object.
       *  @param algorithm The object that will generate the value we plot in
       *    this component.
       *  @param selection Used to set and display the current selection in the
       *    BasePlot.
    
    tjc's avatar
    tjc committed
       *  @param goto_event_source The object the we will call gotoBase() on.
    
    tjc's avatar
    tjc committed
       *    This allows the user to double click on a base in a BasePlot and have
       *    the FeatureDisplay follow.
       **/
    
    tjc's avatar
    tjc committed
      public BasePlot(final BaseAlgorithm algorithm,
                      final Selection selection,
    
    tjc's avatar
    tjc committed
                      final GotoEventSource goto_event_source,
                      final EntryGroup entryGroup) 
    
    tjc's avatar
    tjc committed
      {
        super(algorithm, false);   // false means don't draw the scale line
    
    tjc's avatar
    tjc committed
    
        this.selection = selection;
        this.goto_event_source = goto_event_source;
    
    tjc's avatar
    tjc committed
        this.bases = getBaseAlgorithm().getBases();
    
    tjc's avatar
    tjc committed
        this.entryGroup  = entryGroup;
        
    
        setBackground(Color.WHITE);
    
    tjc's avatar
    tjc committed
        getSelection().addSelectionChangeListener(this);
    
    tjc's avatar
    tjc committed
    
    
        setToolTipText("tool_tip");
        
    
    tjc's avatar
    tjc committed
        addPlotMouseListener(new PlotMouseListener() 
        {
    
    tjc's avatar
    tjc committed
          /**
           *  Set the selection to be a range from start_base to end_base.
           **/
    
    tjc's avatar
    tjc committed
          private void setSelectionRange(final int start_base,
                                         final int end_base) 
          {
            final Strand strand = bases.getForwardStrand();
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
            try 
            {
    
    tjc's avatar
    tjc committed
              final MarkerRange marker_range =
    
    tjc's avatar
    tjc committed
                strand.makeMarkerRangeFromPositions(start_base, end_base);
              getSelection().setMarkerRange(marker_range);
            } 
            catch(uk.ac.sanger.artemis.util.OutOfRangeException e) 
            {
              getSelection().clear();
    
    tjc's avatar
    tjc committed
            }
          }
    
          /**
           *  Called when the user clicks somewhere on the plot canvas.
           *  @param position the base/amino acid position of the click.  This is
           *    -1 if and only if the click was outside the graph (eg. in the
           *    label at the top)
           **/
    
    tjc's avatar
    tjc committed
          public void mouseClick(final int position) 
          {
    
    tjc's avatar
    tjc committed
          }
    
          /**
           *  Called when the user drags the mouse over the plot.
           *  @param drag_start_position The base/amnino acid position where the
           *    drag started or -1 if the drag was started outside the graph.
           *  @param current_position the base/amino acid position of the click.
           *    This is -1 if and only if the user has dragged the mouse out of
           *    the graph (eg. in the label at the top)
           **/
    
    tjc's avatar
    tjc committed
          public void mouseDrag(int drag_start_position,
                                int current_position) 
          {
            if(rev_comp_display) 
            {
    
    tjc's avatar
    tjc committed
              drag_start_position =
    
    tjc's avatar
    tjc committed
                bases.getComplementPosition(drag_start_position);
    
    tjc's avatar
    tjc committed
              current_position =
    
    tjc's avatar
    tjc committed
                bases.getComplementPosition(current_position);
    
    tjc's avatar
    tjc committed
            }
    
    tjc's avatar
    tjc committed
            setSelectionRange(drag_start_position,
                              current_position);
    
    tjc's avatar
    tjc committed
          }
    
          /**
           *  Called when the user double-clicks somewhere on the plot.
           *  @param position the base/amino acid position of the click.  This is
           *    -1 if and only if the click was outside the graph (eg. in the
           *    label at the top)
           **/
    
    tjc's avatar
    tjc committed
          public void mouseDoubleClick(int position)
          {
            if(rev_comp_display) 
              position = bases.getComplementPosition(position);
            
            setSelectionRange(position, position);
            getGotoEventSource().gotoBase(position);
    
    tjc's avatar
    tjc committed
          }
        });
      }
    
    
      /**
       *  Overridden to set the component height to 150.
       **/
    
    tjc's avatar
    tjc committed
      public Dimension getPreferredSize() 
      {
        return(new Dimension(getSize().width, HEIGHT));
    
    tjc's avatar
    tjc committed
      }
    
      /**
       *  Overridden to set the component height to 150.
       **/
    
      /*public Dimension getMinimumSize() 
    
    tjc's avatar
    tjc committed
      {
        return (new Dimension(getSize().width, HEIGHT));
    
    tjc's avatar
    tjc committed
    
      /**
       *  Implementation of the DisplayAdjustmentListener interface.  Invoked when
       *  a component or changes the scale.
       **/
    
    tjc's avatar
    tjc committed
      public void displayAdjustmentValueChanged(DisplayAdjustmentEvent event) 
      {
        start_base = event.getStart();
    
        end_base   = event.getEnd();
    
    tjc's avatar
    tjc committed
        width_in_bases = event.getWidthInBases();
        rev_comp_display = event.isRevCompDisplay();
    
    tjc's avatar
    tjc committed
        recalculate_flag = true;
    
    
    tjc's avatar
    tjc committed
        if(event.getType() == DisplayAdjustmentEvent.ALL_CHANGE_ADJUST_EVENT) 
        {
    
    tjc's avatar
    tjc committed
          selection_start_marker = null;
          selection_end_marker = null;
    
          resetOffscreenImage();
    
    tjc's avatar
    tjc committed
        }
    
    
    tjc's avatar
    tjc committed
        repaint();
    
    tjc's avatar
    tjc committed
      }
    
      /**
       *  We listen for SelectionChange events so that we can update the
       *  crosshairs.
       **/
    
    tjc's avatar
    tjc committed
      public void selectionChanged(SelectionChangeEvent event) 
      {
    
    tjc's avatar
    tjc committed
        selection_start_marker = null;
        selection_end_marker = null;
    
    tjc's avatar
    tjc committed
        repaint();
    
    tjc's avatar
    tjc committed
      }
    
      /**
       *  Return the algorithm that was passed to the constructor.
       **/
    
    tjc's avatar
    tjc committed
      public BaseAlgorithm getBaseAlgorithm()
      {
        return (BaseAlgorithm)super.getAlgorithm();
    
    tjc's avatar
    tjc committed
      }
    
      /**
       *  Return the new start base to display, from the last event.
       **/
    
    tjc's avatar
    tjc committed
      private int getStart()
      {
    
    tjc's avatar
    tjc committed
        return start_base;
      }
    
      /**
       *  Return the new end base to display, from the last event.
       **/
    
    tjc's avatar
    tjc committed
      private int getEnd() 
      {
    
    tjc's avatar
    tjc committed
        return end_base;
      }
    
      /**
       *  Return the width in bases of the display, from the last event.
       **/
    
    tjc's avatar
    tjc committed
      private int getWidthInBases() 
      {
    
    tjc's avatar
    tjc committed
        return width_in_bases;
      }
    
    
    tjc's avatar
    tjc committed
      /**
       *  Recalculate the values in value_array_array, step_size, min_value and
    
       *  max_value. 
    
    tjc's avatar
    tjc committed
       **/
    
      protected void calculateFeatures(boolean fromPeak) 
    
    tjc's avatar
    tjc committed
      {
        GridBagLayout gridbag = new GridBagLayout();
        JPanel pane = new JPanel(gridbag);
    
        GridBagConstraints c = new GridBagConstraints();
    
        c.anchor = GridBagConstraints.EAST;
        c.gridx = 0;
        c.gridy = 0;
        pane.add(new JLabel("Minimum feature size:"), c);
        
        c.gridx = 0;
        c.gridy = 1;
        pane.add(new JLabel("Cut-off value:"), c);
        
        c.gridx = 0;
        c.gridy = 2;
        pane.add(new JLabel("Key:"), c);
        
        JTextField minSize = new JTextField(String.valueOf (100), 15);
        c.anchor = GridBagConstraints.WEST;
        c.gridx = 1;
        c.gridy = 0;
        pane.add(minSize, c);
        
        JTextField cutoffField = new JTextField(getAlgorithm().getAverage().toString(),15);
        c.gridx = 1;
        c.gridy = 1;
        pane.add(cutoffField,c);
        
        final Key defaultKey;
        if(GeneUtils.isDatabaseEntry(entryGroup))
          defaultKey = new Key("region");
        else
          defaultKey = Key.CDS;
        
    
    tjc's avatar
    tjc committed
        Entry entry = entryGroup.getDefaultEntry();
        if(entry == null)
        {
          JOptionPane.showMessageDialog(null, 
              "Please select a default entry\nand try again!", "No default entry", 
              JOptionPane.WARNING_MESSAGE);
          return;
        }
        
    
    tjc's avatar
    tjc committed
        KeyChoice keyChoice = new KeyChoice(
    
    tjc's avatar
    tjc committed
            entry.getEntryInformation(), defaultKey);
    
    tjc's avatar
    tjc committed
    
        c.gridx = 1;
        c.gridy = 2;
        pane.add(keyChoice, c);
        
        int select = JOptionPane.showConfirmDialog(null, 
                                    pane, "Options", 
                                    JOptionPane.OK_CANCEL_OPTION,
                                    JOptionPane.QUESTION_MESSAGE);
        
        if(select == JOptionPane.CANCEL_OPTION)
          return;
        
        int minFeatureSize = Integer.parseInt(minSize.getText());
        float cutoff = Float.parseFloat(cutoffField.getText());
        Key key = keyChoice.getSelectedItem();
        
        final int end = getBaseAlgorithm().getBases().getLength();
        final int window_size = getWindowSize();
        final Integer default_step_size =
          getAlgorithm().getDefaultStepSize(window_size);
        if(default_step_size == null) 
          step_size = 1;
        else
        {
          if(default_step_size.intValue() < window_size) 
            step_size = default_step_size.intValue();
          else
            step_size = window_size;
        }
        
        // the number of plot points in the graph
        final int number_of_values =
          (end - (getWindowSize() - step_size)) / step_size;
    
        getBaseAlgorithm().setRevCompDisplay(rev_comp_display);
    
        // just one graph calculated
        float [] temp_values = new float [1];
        int featureStart = -1;
        
        final Entry new_entry =
          entryGroup.createEntry ("CDS_" + minFeatureSize + "_" +
                                  getBaseAlgorithm().getAlgorithmShortName());
        
        float average = 0.f;
        int averageCount = 0;
        final String noteField = "Auto-generated from "+getAlgorithm().getAlgorithmName()+
                                 " plot;"+" window size="+getWindowSize()+
    
                                 "; score cut-off="+cutoffField.getText()+
                                 (fromPeak ? "; from the peaks" : "; from the trough");
    
        int lastPos = 0;
    
    tjc's avatar
    tjc committed
        for(int i = 0 ; i < number_of_values ; ++i) 
        {
    
    tjc's avatar
    tjc committed
          getBaseAlgorithm().getValues((i * step_size) + 1,
                                       (i * step_size) + 1 +
    
    tjc's avatar
    tjc committed
                                       getWindowSize() - 1,
                                       temp_values);
    
          final float current_value = temp_values[0];
          int pos = getWindowSize()/2 + (i * step_size) + 1;
    
          if(i == 0)
            lastPos = pos;
    
    tjc's avatar
    tjc committed
          
          if(current_value > cutoff)
          {
            average+=current_value;
            averageCount++;
          }
          
    
            if (fromPeak && current_value > cutoff && featureStart == -1)
              featureStart = pos;
            else if (!fromPeak && current_value < cutoff && featureStart == -1)
              featureStart = pos;
            else if (fromPeak && current_value < cutoff && featureStart > -1)
    
              if (lastPos - featureStart < minFeatureSize)
              {
                average = 0.f;
                averageCount = 0;
                featureStart = -1;
                continue;
              }
    
              // create feature
              MarkerRange range = new MarkerRange(
                 getBaseAlgorithm().getStrand(), featureStart,lastPos);
              final Location new_location = range.createLocation();
    
              average = average / averageCount;
              QualifierVector qualifiers = new QualifierVector();
              qualifiers.add(new Qualifier("score", Float.toString(average)));
              qualifiers.add(new Qualifier("note", noteField));
    
              new_entry.createFeature(key, new_location, qualifiers);
              featureStart = -1;
    
    tjc's avatar
    tjc committed
              average = 0.f;
              averageCount = 0;
    
            }
            else if (!fromPeak && current_value > cutoff && featureStart > -1)
            {
              if (lastPos - featureStart < minFeatureSize)
              {
                average = 0.f;
                averageCount = 0;
                featureStart = -1;
                continue;
              }
    
              // create feature
              MarkerRange range = new MarkerRange(
                  getBaseAlgorithm().getStrand(), featureStart, lastPos);
              final Location new_location = range.createLocation();
    
              average = average / averageCount;
              QualifierVector qualifiers = new QualifierVector();
              qualifiers.add(new Qualifier("score", Float.toString(average)));
              qualifiers.add(new Qualifier("note", noteField));
    
              new_entry.createFeature(key, new_location, qualifiers);
    
    tjc's avatar
    tjc committed
              featureStart = -1;
    
              average = 0.f;
              averageCount = 0;
    
          catch (OutOfRangeException e)
          {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
          catch (ReadOnlyException e)
          {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
          catch (EntryInformationException e)
          {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
    
          lastPos = pos;
    
    tjc's avatar
    tjc committed
    
    
      protected void showAveragesForRange()
      {
        final int end = getBaseAlgorithm().getBases().getLength();
    
        // the number of plot points in the graph
        final int number_of_values =
          (end - (getWindowSize() - step_size)) / step_size;
    
        if(getSelectionStartMarker() == null)
        {
          JOptionPane.showMessageDialog(null, "No range selected.",
                             "Message", JOptionPane.INFORMATION_MESSAGE);
          return; 
        }
         
        int rangeStart = getSelectionStartMarker().getRawPosition();
        int rangeEnd   = getSelectionEndMarker().getRawPosition();
      
        final int numPlots =  getBaseAlgorithm().getValueCount();
        float[] temp_values = new float [numPlots];
        float[] av_values   = new float [numPlots];
        
        int count = 0;
        
        FileViewer fileViewer = new FileViewer(
            getBaseAlgorithm().getAlgorithmShortName()+" :: "+
            rangeStart+".."+rangeEnd);
        fileViewer.appendString("Base\tValue(s)\n\n",Level.INFO);
    
        for(int i = 0 ; i < number_of_values ; ++i) 
        {
          int pos = getWindowSize()/2 + (i * step_size) + 1;
          
          if(pos < rangeStart || pos > rangeEnd)
            continue;
          
          getBaseAlgorithm().getValues((i * step_size) + 1,
                                       (i * step_size) + 1 +
                                       getWindowSize() - 1,
                                       temp_values);
          
          fileViewer.appendString(pos+"\t");
          for(int j=0; j<numPlots; j++)
          {
            av_values[j] += temp_values[j];
            fileViewer.appendString(temp_values[j]+"\t");
          }
          fileViewer.appendString("\n");
          
          count++;
        }
        
        fileViewer.appendString("\n\nAverage Value(s)\n",Level.INFO);
        fileViewer.appendString(    "================\n",Level.INFO);
        
        for(int j=0; j<numPlots; j++)
          fileViewer.appendString(Integer.toString(j+1)+"\t"+
                                  Float.toString(av_values[j]/count)+"\n");
      }
      
    
    tjc's avatar
    tjc committed
      /**
       *  Recalculate the values in value_array_array, step_size, min_value and
       *  max_value.
       **/
    
    tjc's avatar
    tjc committed
      protected void recalculateValues()
      {
        final Float algorithm_minimum = getAlgorithm().getMinimum();
        final Float algorithm_maximum = getAlgorithm().getMaximum();
    
    tjc's avatar
    tjc committed
    
        // use the Algorithm specified maximum if there is one - otherwise
        // calculate it
    
    tjc's avatar
    tjc committed
        if(algorithm_maximum == null) 
    
    tjc's avatar
    tjc committed
          max_value = Float.MIN_VALUE;
    
    tjc's avatar
    tjc committed
        else
          max_value = algorithm_maximum.floatValue();
    
    tjc's avatar
    tjc committed
    
        // use the Algorithm specified minimum if there is one - otherwise
        // calculate it
    
    tjc's avatar
    tjc committed
        if(algorithm_minimum == null) 
    
    tjc's avatar
    tjc committed
          min_value = Float.MAX_VALUE;
    
    tjc's avatar
    tjc committed
        else
          min_value = algorithm_minimum.floatValue();
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        final int window_size = getWindowSize();
    
    tjc's avatar
    tjc committed
    
        final Integer default_step_size =
    
    tjc's avatar
    tjc committed
          getAlgorithm().getDefaultStepSize(window_size);
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        if(default_step_size == null) 
    
    tjc's avatar
    tjc committed
          step_size = 1;
    
    tjc's avatar
    tjc committed
        else
        {
          if(default_step_size.intValue() < window_size) 
            step_size = default_step_size.intValue();
          else
    
    tjc's avatar
    tjc committed
            step_size = window_size;
        }
    
    
    tjc's avatar
    tjc committed
        int real_start = getStart();
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        if(real_start < 1)
    
    tjc's avatar
    tjc committed
          real_start = 1;
    
    
    tjc's avatar
    tjc committed
        final int unit_count = getEnd() - real_start;
    
    tjc's avatar
    tjc committed
    
        // the number of plot points in the graph
        final int number_of_values =
          (unit_count - (window_size - step_size)) / step_size;
    
    
    tjc's avatar
    tjc committed
        if(number_of_values < 2) 
        {
    
    tjc's avatar
    tjc committed
          // there is nothing to plot
          value_array_array = null;
          return;
        }
    
    
    tjc's avatar
    tjc committed
        getBaseAlgorithm().setRevCompDisplay(rev_comp_display);
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        // the number of values that getValues() will return
    
    tjc's avatar
    tjc committed
        final int get_values_return_count =
    
    tjc's avatar
    tjc committed
          getBaseAlgorithm().getValueCount();
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        if(value_array_array == null) 
    
    tjc's avatar
    tjc committed
          value_array_array = new float [get_values_return_count][];
    
    
    tjc's avatar
    tjc committed
        if(value_array_array[0] == null ||
           value_array_array[0].length != number_of_values) 
        {
          for(int i = 0 ; i < value_array_array.length ; ++i) 
    
    tjc's avatar
    tjc committed
            value_array_array[i] = new float [number_of_values];
    
    tjc's avatar
    tjc committed
        }
        else 
        {
    
    tjc's avatar
    tjc committed
          // reuse the previous arrays
        }
    
        float [] temp_values = new float [get_values_return_count];
    
    
    tjc's avatar
    tjc committed
        for(int i = 0 ; i < number_of_values ; ++i) 
        {
          getBaseAlgorithm().getValues(real_start + i * step_size,
                                       real_start + i * step_size +
                                       window_size - 1,
                                       temp_values);
    
          for(int value_index = 0 ;
              value_index < get_values_return_count ;
              ++value_index) 
          {
    
    tjc's avatar
    tjc committed
            final float current_value = temp_values[value_index];
    
            value_array_array[value_index][i] = current_value;
    
            // use the Algorithm specified maximum if there is one - otherwise
            // calculate it
    
    tjc's avatar
    tjc committed
            if(algorithm_maximum == null)
            {
              if (current_value > max_value) 
    
    tjc's avatar
    tjc committed
                max_value = current_value;
            }
    
            // use the Algorithm specified minimum if there is one - otherwise
            // calculate it
    
    tjc's avatar
    tjc committed
            if(algorithm_minimum == null) 
            {
              if(current_value < min_value) 
    
    tjc's avatar
    tjc committed
                min_value = current_value;
            }
          }
        }
    
        recalculate_flag = false;
      }
    
      /**
       *  Redraw the graph on the canvas using the algorithm, start_base and
       *  end_base.  This method plots BaseWindowAlgorithm objects only.
       *  @param g The object to draw into.
       **/
    
      public int drawMultiValueGraph(Graphics g, LineAttributes[] lines) 
    
    tjc's avatar
    tjc committed
      {
        if(recalculate_flag)
          recalculateValues();
    
    tjc's avatar
    tjc committed
        if(value_array_array == null) 
        {
    
    tjc's avatar
    tjc committed
          // there is nothing to draw - probably because the sequence is too short
    
    tjc's avatar
    tjc committed
          drawMinMax(g, 0, 1);
    
    tjc's avatar
    tjc committed
        }
    
    
    tjc's avatar
    tjc committed
        final int window_size = getWindowSize();
    
    tjc's avatar
    tjc committed
    
        // the number of values to plot at each x position
        final int get_values_return_count =
    
    tjc's avatar
    tjc committed
          getBaseAlgorithm().getValueCount();
    
    tjc's avatar
    tjc committed
    
        final int number_of_values = value_array_array[0].length;
    
    
        boolean isBlast  = false;
    
        if(getAlgorithm() instanceof UserDataAlgorithm)
        {
    
          int format = ((UserDataAlgorithm)getAlgorithm()).FORMAT;
          if(format == UserDataAlgorithm.WIGGLE_FIXED_STEP_FORMAT ||
             format == UserDataAlgorithm.WIGGLE_VARIABLE_STEP_FORMAT)
    
          
          if(format == UserDataAlgorithm.BLAST_FORMAT)
            isBlast = true;
    
        }
        
        if(number_of_values > 1 && !isWiggle) 
    
    tjc's avatar
    tjc committed
          drawGlobalAverage(g, min_value, max_value);
    
    
        Stroke stroke = ((Graphics2D)g).getStroke();
    
    tjc's avatar
    tjc committed
        for(int value_index = 0; value_index < get_values_return_count;
            ++value_index)
        {
    
          if(value_index < lines.length)
    
    tjc's avatar
    tjc committed
          {
    
            g.setColor(lines[value_index].getLineColour());
            ((Graphics2D)g).setStroke(lines[value_index].getStroke());
    
    tjc's avatar
    tjc committed
          }
    
    tjc's avatar
    tjc committed
    
          final int offset;
    
    
    tjc's avatar
    tjc committed
          if(getStart() < 1) 
            offset = 1 - getStart();
          else
    
    tjc's avatar
    tjc committed
            offset = 0;
    
    
          drawPoints(g, min_value, max_value, step_size, window_size,
    
                       value_array_array[value_index], value_index, 
    
                       get_values_return_count, isWiggle, isBlast);
    
    tjc's avatar
    tjc committed
        }
    
        ((Graphics2D)g).setStroke(stroke);
        
    
    tjc's avatar
    tjc committed
        drawMinMax(g, min_value, max_value);
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        if(getCrossHairPosition() >= 0)
        {
          final int cross_hair_position = getCrossHairPosition();
          final int selection_base = getPointPosition(cross_hair_position);
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
          if(selection_base >= 1)
          {
            if(selection_base > end_base) 
              cancelCrossHairs();
            else 
            {
    
    tjc's avatar
    tjc committed
              final String label_string;
    
    
    tjc's avatar
    tjc committed
              if(rev_comp_display) 
              {
    
    tjc's avatar
    tjc committed
                label_string =
    
    tjc's avatar
    tjc committed
                  String.valueOf(bases.getLength() - selection_base + 1);
              } 
              else
                label_string = String.valueOf(selection_base);
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
              drawCrossHair(g, cross_hair_position, label_string, 0);
    
    tjc's avatar
    tjc committed
            }
          }
        }
    
    
    tjc's avatar
    tjc committed
        if(getCrossHairPosition() >= 0 && getSelectionStartMarker() != null) 
        {
    
    tjc's avatar
    tjc committed
          final int selection_first_base =
    
    tjc's avatar
    tjc committed
            getSelectionStartMarker().getRawPosition();
    
    tjc's avatar
    tjc committed
    
          final String label_string;
    
    
    tjc's avatar
    tjc committed
          if(rev_comp_display) 
          {
    
    tjc's avatar
    tjc committed
            label_string =
    
    tjc's avatar
    tjc committed
              String.valueOf(bases.getLength() - selection_first_base + 1);
          } 
          else
            label_string = String.valueOf(selection_first_base);
    
          if(Math.abs(selection_first_base -
                      getPointPosition(getCrossHairPosition())) > 3) 
          {
            drawCrossHair(g, getCanvasPosition(selection_first_base),
                          label_string, 1);
          } 
          else 
          {
    
    tjc's avatar
    tjc committed
            // don't draw - too close to main cross hair
          }
        }
    
    
    tjc's avatar
    tjc committed
        if(getCrossHairPosition() >= 0 && getSelectionEndMarker() != null)
        {
          if(getSelectionStartMarker() != null &&
             Math.abs((getSelectionEndMarker().getRawPosition() -
                       getSelectionStartMarker().getRawPosition())) >= 3)
          {
    
    tjc's avatar
    tjc committed
            final int selection_last_base =
    
    tjc's avatar
    tjc committed
              getSelectionEndMarker().getRawPosition();
    
    tjc's avatar
    tjc committed
    
            final String label_string;
    
    
    tjc's avatar
    tjc committed
            if(rev_comp_display)
            {
    
    tjc's avatar
    tjc committed
              label_string =
    
    tjc's avatar
    tjc committed
                String.valueOf(bases.getLength() - selection_last_base + 1);
            } 
            else 
              label_string = String.valueOf(selection_last_base);
    
            if(Math.abs(selection_last_base -
                        getPointPosition(getCrossHairPosition())) > 3)
            {
              drawCrossHair(g, getCanvasPosition (selection_last_base),
                            label_string, 2);
    
    tjc's avatar
    tjc committed
            }
    
    tjc's avatar
    tjc committed
            else
            {
    
    tjc's avatar
    tjc committed
              // don't draw - too close to main cross hair
            }
          }
        }
    
    
        return get_values_return_count;
    
    tjc's avatar
    tjc committed
      }
    
    tjc's avatar
    tjc committed
    
      /**
       *  Get the position in the Feature of the given canvas x position.  This
       *  base position is the label used when the user clicks the mouse in on the
    
    tjc's avatar
    tjc committed
       *  canvas (see drawCrossHair()).
    
    tjc's avatar
    tjc committed
       **/
    
    tjc's avatar
    tjc committed
      protected int getPointPosition(final int canvas_x_position) 
      {
        return (int)((1.0 * canvas_x_position / getSize().width) *
                     getWidthInBases()) + getStart();
    
    tjc's avatar
    tjc committed
      }
    
      /**
       *  Return the canvas position of the given base,
       **/
    
    tjc's avatar
    tjc committed
      private int getCanvasPosition(final int base)
      {
        return (int)((1.0 * base - getStart()) / getWidthInBases() *
                     getSize().width);
    
    tjc's avatar
    tjc committed
      }
    
      /**
       *  Return the Marker of the start base of the Selection or null if there is
       *  nothing selected.
       **/
    
    tjc's avatar
    tjc committed
      private Marker getSelectionStartMarker()
      {
        if(selection_start_marker == null) 
        {
          selection_start_marker = getSelection().getLowestBaseOfSelection();
    
          if(selection_start_marker != null &&
             rev_comp_display) 
          {
            final Strand strand = bases.getReverseStrand();
            final int orig_position = selection_start_marker.getRawPosition();
    
    tjc's avatar
    tjc committed
            final int rev_comp_position =
    
    tjc's avatar
    tjc committed
              bases.getComplementPosition(orig_position);
            try 
            {
              selection_start_marker = strand.makeMarker(orig_position);
            }
            catch(OutOfRangeException e) 
            {
              throw new Error("internal error - unexpected exception: " + e);
    
    tjc's avatar
    tjc committed
            }
          }
        }
    
        return selection_start_marker;
      }
    
      /**
       *  Return the Marker of the end base of the Selection or null if there is
       *  nothing selected.
       **/
    
    tjc's avatar
    tjc committed
      private Marker getSelectionEndMarker() 
      {
        if(selection_end_marker == null) 
        {
          selection_end_marker = getSelection().getHighestBaseOfSelection();
    
          if(selection_end_marker != null &&
             rev_comp_display) 
          {
            final Strand strand = bases.getReverseStrand();
            final int orig_position = selection_end_marker.getRawPosition();
    
    tjc's avatar
    tjc committed
            final int rev_comp_position =
    
    tjc's avatar
    tjc committed
              bases.getComplementPosition(orig_position);
            try 
            {
              selection_end_marker = strand.makeMarker(orig_position);
            }
            catch(OutOfRangeException e) 
            {
              throw new Error("internal error - unexpected exception: " + e);
    
    tjc's avatar
    tjc committed
            }
          }
        }
    
        return selection_end_marker;
      }
    
      /**
       *  Return the Selection object that was passed to the constructor.
       **/
    
    tjc's avatar
    tjc committed
      private Selection getSelection() 
      {
    
    tjc's avatar
    tjc committed
        return selection;
      }
    
      /**
       *  Return the GotoEventSource object that was passed to the constructor.
       **/
    
    tjc's avatar
    tjc committed
      private GotoEventSource getGotoEventSource()
      {
    
    tjc's avatar
    tjc committed
        return goto_event_source;
      }
    
    tjc's avatar
    tjc committed
      
    
    tjc's avatar
    tjc committed
      /**
    
    tjc's avatar
    tjc committed
       * (non-Javadoc)
       * @see javax.swing.JComponent#getToolTipText(java.awt.event.MouseEvent)
       */
      public String getToolTipText(MouseEvent event)
      {
        if(value_array_array == null) // nothing to plot
          return null;
        
        int offset = getStart();
        if(offset < 1) 
          offset = 0;
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        final int get_values_return_count =
          getBaseAlgorithm().getValueCount();
        
    
    tjc's avatar
    tjc committed
        int xpos = getPointPosition(event.getPoint().x);
        
        //getXCoordinate(getWidthInBases(),
        //                          offset, event.getPoint().x);
    
    tjc's avatar
    tjc committed
        
        String tt = Integer.toString(xpos);
        
        NumberFormat df= NumberFormat.getNumberInstance();
        df.setMaximumFractionDigits(2);
        
        float ypos;
        for(int value_index = 0; value_index < get_values_return_count;