title: How to number basecalls on chromatogram?
body: <p>I've created an image of a chromatogram (of a dna sequence).</p>
  
  <p>How would I go about putting a number over each basecall?</p>
  
  <p>I can get the pixel length of the picture and the number of bases. If I divide these, I would get the average distance between basecalls, which would offer a good approximation of where each basecall would go.</p>
  
  <p>How would I put numbers (1 - [number of bases]) along the top of the picture? </p>
  
  <p>Here is a picture of the GUI and what the program looks like:</p>
  
  <p><a href="https://drive.google.com/file/d/0B5nGPfKaY21KVFVsaE9XSHJmWG8/view?usp=sharing" rel="nofollow">https://drive.google.com/file/d/0B5nGPfKaY21KVFVsaE9XSHJmWG8/view?usp=sharing</a></p>
  
  <p>Here is the source code:</p>
  
  <p>[When the getChrom button is pressed, the method renderTrace is executed, rendering the trace.]</p>
  
  <pre><code>public class TraceRender extends javax.swing.JFrame {
  public TraceRender() {
      initComponents();
  }
  
  /**
   * This method is called from within the constructor to initialize the form.
   * WARNING: Do NOT modify this code. The content of this method is always
   * regenerated by the Form Editor.
   */
  @SuppressWarnings("unchecked")
  // &lt;editor-fold defaultstate="collapsed" desc="Generated Code"&gt;                          
  private void initComponents() {
  
      fileChooser = new javax.swing.JFileChooser();
      textarea = new javax.swing.JTextField();
      getChrom = new javax.swing.JButton();
      ScrollPane = new javax.swing.JScrollPane();
      Label = new javax.swing.JLabel();
      text = new javax.swing.JTextField();
      Menu = new javax.swing.JMenuBar();
      File = new javax.swing.JMenu();
      Open = new javax.swing.JMenuItem();
      Exit = new javax.swing.JMenuItem();
      Edit = new javax.swing.JMenu();
      Documentation = new javax.swing.JMenu();
      Help = new javax.swing.JMenu();
  
      fileChooser.setDialogTitle("This is my open dialog");
      fileChooser.setFileFilter(new myCustomFilter());
  
      setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
  
      textarea.setEditable(false);
      textarea.setText("ABSOLUTE PATH");
  
      getChrom.setText("Execute");
      getChrom.addActionListener(new java.awt.event.ActionListener() {
          public void actionPerformed(java.awt.event.ActionEvent evt) {
              getChromActionPerformed(evt);
          }
      });
  
      Label.setText("[AVI]-Error.noImageLoaded");
      ScrollPane.setViewportView(Label);
  
      text.setText("nothing");
  
      File.setText("FILE");
  
      Open.setText("Get File");
      Open.addActionListener(new java.awt.event.ActionListener() {
          public void actionPerformed(java.awt.event.ActionEvent evt) {
              OpenActionPerformed(evt);
          }
      });
      File.add(Open);
  
      Exit.setText("Close Program");
      Exit.addActionListener(new java.awt.event.ActionListener() {
          public void actionPerformed(java.awt.event.ActionEvent evt) {
              ExitActionPerformed(evt);
          }
      });
      File.add(Exit);
  
      Menu.add(File);
  
      Edit.setText("EDIT");
      Menu.add(Edit);
  
      Documentation.setText("DOCUMENTATION");
      Menu.add(Documentation);
  
      Help.setText("HELP");
      Menu.add(Help);
  
      setJMenuBar(Menu);
  
      javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
      getContentPane().setLayout(layout);
      layout.setHorizontalGroup(
          layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
          .addGroup(layout.createSequentialGroup()
              .addContainerGap()
              .addComponent(textarea, javax.swing.GroupLayout.PREFERRED_SIZE, 1005, javax.swing.GroupLayout.PREFERRED_SIZE)
              .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 79, Short.MAX_VALUE)
              .addComponent(getChrom, javax.swing.GroupLayout.PREFERRED_SIZE, 291, javax.swing.GroupLayout.PREFERRED_SIZE)
              .addGap(49, 49, 49))
          .addComponent(ScrollPane, javax.swing.GroupLayout.Alignment.TRAILING)
          .addGroup(layout.createSequentialGroup()
              .addGap(33, 33, 33)
              .addComponent(text, javax.swing.GroupLayout.PREFERRED_SIZE, 630, javax.swing.GroupLayout.PREFERRED_SIZE)
              .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
      );
      layout.setVerticalGroup(
          layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
          .addGroup(layout.createSequentialGroup()
              .addContainerGap()
              .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                  .addComponent(textarea, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                  .addComponent(getChrom))
              .addGap(48, 48, 48)
              .addComponent(ScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 265, javax.swing.GroupLayout.PREFERRED_SIZE)
              .addGap(53, 53, 53)
              .addComponent(text, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
              .addContainerGap(113, Short.MAX_VALUE))
      );
  
      pack();
  }// &lt;/editor-fold&gt;                        
  
  private void OpenActionPerformed(java.awt.event.ActionEvent evt) {                                     
      // TODO add your handling code here:
  
      int returnVal = fileChooser.showOpenDialog(this);
      if (returnVal == JFileChooser.APPROVE_OPTION) {
          File file = fileChooser.getSelectedFile();
          textarea.setText(String.valueOf(file.getAbsolutePath()));
      } else {
          System.out.println("File access cancelled by user.");
      }
  
  }                                    
  
  private void ExitActionPerformed(java.awt.event.ActionEvent evt) {                                     
      // TODO add your handling code here:
      System.exit(0);
  }                                    
  
  private void getChromActionPerformed(java.awt.event.ActionEvent evt) {                                         
      try {
          // TODO add your handling code here:
          renderTrace();
      } catch (IOException | UnsupportedChromatogramFormatException ex) {
          Logger.getLogger(TraceRender.class.getName()).log(Level.SEVERE, null, ex);
      }
  }                                        
  
  private void renderTrace() throws IOException, UnsupportedChromatogramFormatException {
      ABIFChromatogram abiChrom = new ABIFChromatogram();
  
      File abi = new File(textarea.getText());
  
      ABITrace abiTrace = new ABITrace(abi);
      ABIFParser abiParse = new ABIFParser(abi);
      ChromatogramFactory chromFactory = new ChromatogramFactory();
  
      Chromatogram chrom = ChromatogramFactory.create(abi);
  
      ChromatogramGraphic gfx = new ChromatogramGraphic(chrom);
  
      gfx.setHeight(240);
      gfx.setHorizontalScale(2.0f);
      // set some options that affect the output
      // turn off filled-in "callboxes"
      gfx.setOption(ChromatogramGraphic.Option.DRAW_CALL_A,
              Boolean.FALSE);
      gfx.setOption(ChromatogramGraphic.Option.DRAW_CALL_C,
              Boolean.FALSE);
      gfx.setOption(ChromatogramGraphic.Option.DRAW_CALL_G,
              Boolean.FALSE);
      gfx.setOption(ChromatogramGraphic.Option.DRAW_CALL_T,
              Boolean.FALSE);
      gfx.setOption(ChromatogramGraphic.Option.DRAW_CALL_OTHER,
              Boolean.TRUE);
      gfx.setOption(ChromatogramGraphic.Option.DRAW_CALL_SEPARATORS,
              Boolean.TRUE);
  
      // this option controls whether each trace/callbox/etc is scaled/positioned
      // individually, or whether the scaling is done on all shapes at the level
      // of the graphics context
      // enabling this option is recommended for higher-quality output
  
      gfx.setOption(ChromatogramGraphic.Option.USE_PER_SHAPE_TRANSFORM,
              Boolean.TRUE);
  
      BufferedImage bi = new BufferedImage(
              gfx.getWidth(),
              gfx.getHeight(),
              BufferedImage.TYPE_INT_RGB);
      Graphics2D g2 = bi.createGraphics();
      g2.setBackground(Color.white);
      g2.clearRect(0, 0, bi.getWidth(), bi.getHeight());
      if (g2.getClip() == null) {
          g2.setClip(new Rectangle(0, 0, bi.getWidth(), bi.getHeight()));
      }
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
      // the main event
      gfx.drawTo(g2);
      // work-around an OS X bug where sometimes the last Shape drawn
      // doesn't show up in the output
      g2.draw(new java.awt.Rectangle(-10, -10, 5, 5));
  
      text.setText(String.valueOf(gfx.getWidth()));
      ImageIcon ii = new ImageIcon(bi);
      Label.setIcon(ii);
      /*
      try {
          ImageIO.write(bi, "png", new File("gfx-image.png"));
      } catch (IOException ex) {
          ex.printStackTrace();
      }
      */
  
  
  }
  
  /**
   * @param args the command line arguments
   */
  public static void main(String args[]) {
      /* Set the Nimbus look and feel */
      //&lt;editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) "&gt;
      /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
       * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
       */
      try {
          for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
              if ("Nimbus".equals(info.getName())) {
                  javax.swing.UIManager.setLookAndFeel(info.getClassName());
                  break;
              }
          }
      } catch (ClassNotFoundException ex) {
          java.util.logging.Logger.getLogger(TraceRender.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
      } catch (InstantiationException ex) {
          java.util.logging.Logger.getLogger(TraceRender.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
      } catch (IllegalAccessException ex) {
          java.util.logging.Logger.getLogger(TraceRender.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
      } catch (javax.swing.UnsupportedLookAndFeelException ex) {
          java.util.logging.Logger.getLogger(TraceRender.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
      }
      //&lt;/editor-fold&gt;
  
      /* Create and display the form */
      java.awt.EventQueue.invokeLater(new Runnable() {
          public void run() {
              new TraceRender().setVisible(true);
          }
      });
  }
  
  class myCustomFilter extends javax.swing.filechooser.FileFilter {
  
      @Override
      public boolean accept(File file) {
          // Allow only directories, or files with ".txt" extension
          return file.isDirectory() || file.getAbsolutePath().endsWith(".ab1");
      }
  
      @Override
      public String getDescription() {
          // This description will be displayed in the dialog,
          // hard-coded = ugly, should be done via I18N
          return "ABIF Files (*.ab1)";
      }
  }
  
  
  // Variables declaration - do not modify                     
  private javax.swing.JMenu Documentation;
  private javax.swing.JMenu Edit;
  private javax.swing.JMenuItem Exit;
  private javax.swing.JMenu File;
  private javax.swing.JMenu Help;
  private javax.swing.JLabel Label;
  private javax.swing.JMenuBar Menu;
  private javax.swing.JMenuItem Open;
  private javax.swing.JScrollPane ScrollPane;
  private javax.swing.JFileChooser fileChooser;
  private javax.swing.JButton getChrom;
  private javax.swing.JTextField text;
  private javax.swing.JTextField textarea;
  // End of variables declaration                   
  }
  </code></pre>