gt:                     double breakpoint2 = breakpoints[ntileIndex];
context: ///////////////////////////////////////////////////////////////////////////////
  // For information as to what this class does, see the Javadoc, below.       //
  // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,       //
  // 2007, 2008, 2009, 2010, 2014, 2015 by Peter Spirtes, Richard Scheines, Joseph   //
  // Ramsey, and Clark Glymour.                                                //
  //                                                                           //
  // 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 //
  ///////////////////////////////////////////////////////////////////////////////
  
  package edu.cmu.tetradapp.editor;
  
  
  import edu.cmu.tetrad.data.ContinuousVariable;
  import edu.cmu.tetrad.data.DataSet;
  import edu.cmu.tetrad.graph.Node;
  import edu.cmu.tetrad.util.StatUtils;
  import edu.cmu.tetradapp.util.DoubleTextField;
  
  import javax.swing.*;
  import java.awt.*;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.awt.event.ItemEvent;
  import java.awt.event.ItemListener;
  import java.awt.geom.Point2D;
  import java.text.DecimalFormat;
  import java.text.NumberFormat;
  import java.util.*;
  import java.util.List;
  
  /**
   * This is the wizard which allows the user to select the x and y-axis variables
   * to chart the ScatterPlot.
   *
   * @author Adrian Tang
   * @author Joseph Ramsey
   */
  public class ScatterPlotView extends JPanel {
      private ScatterPlot scatterPlot;
      private ScatterPlotChart scatterPlotChart;
      private String x;
      private String y;
      private static final String[] tiles = new String[]{"1-tile", "2-tile", "tertile", "quartile", "quintile", "sextile",
              "septile", "octile", "nontile", "decile"};
  
      public ScatterPlotView(DataSet dataSet) {
  
          // This is annoying. jdramsey 5/14/2014
  //        if (!dataSet.isContinuous()) throw new IllegalArgumentException("Data set not continuous.");
          if (!(dataSet.getNumColumns() >= 2)) throw new IllegalArgumentException("Need at least two columns.");
  
          DataSet dataSet1 = dataSet;
  
          this.x = dataSet.getVariable(0).getName();
          this.y = dataSet.getVariable(1).getName();
  
          setLayout(new BorderLayout());
          ScatterPlot ScatterPlot = new ScatterPlot(dataSet1, false, x, y);
          ScatterPlotChart ScatterPlotChart = new ScatterPlotChart(ScatterPlot);
          this.scatterPlot = ScatterPlot;
          this.scatterPlotChart = ScatterPlotChart;
  
          add(ScatterPlotChart, BorderLayout.CENTER);
          add(new ScatterPlotController(this), BorderLayout.EAST);
  
          setPreferredSize(new Dimension(750, 450));
      }
  
      private void setX(String x) {
          this.x = x;
      }
  
      private void setY(String y) {
          this.y = y;
      }
  
      private ScatterPlot getScatterPlot() {
          return scatterPlot;
      }
  
      public static class ScatterPlotController extends JPanel {
          private final ScatterPlot scatterPlot;
          private final JComboBox xSelector;
          private final JComboBox ySelector;
          private final JComboBox newConditioningVariableSelector;
          private final JButton newConditioningVariableButton;
          private final JButton removeConditioningVariableButton;
          private final java.util.List<ConditioningPanel> conditioningPanels = new ArrayList<>();
          private final JCheckBox includeLineCheckbox;
  
          // To provide some memory of previous settings for the inquiry dialogs.
          private final Map<Node, ConditioningPanel> conditioningPanelMap = new HashMap<>();
  
          /**
           * Constructs the editor panel given the initial ScatterPlot and the dataset.
           */
          public ScatterPlotController(final ScatterPlotView ScatterPlotView) {
              this.setLayout(new BorderLayout());
              this.scatterPlot = ScatterPlotView.getScatterPlot();
              Node xNode = getXNode();
              Node yNode = getYNode();
              this.xSelector = new JComboBox();
              this.ySelector = new JComboBox();
              ListCellRenderer renderer = new VariableBoxRenderer();
              this.xSelector.setRenderer(renderer);
              this.ySelector.setRenderer(renderer);
  
              includeLineCheckbox = new JCheckBox("Show Regression Line");
              List<Node> variables = scatterPlot.getDataSet().getVariables();
  
              Collections.sort(variables);
  
              for (Node node : variables) {
                  this.xSelector.addItem(node);
  
                  if (node == xNode) {
                      this.xSelector.setSelectedItem(node);
                  }
              }
  
              for (Node node : variables) {
                  this.ySelector.addItem(node);
  
                  if (node == yNode) {
                      this.ySelector.setSelectedItem(node);
                  }
              }
  
              this.xSelector.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                      String node = ((Node) xSelector.getSelectedItem()).getName();
                      ScatterPlotView.setX(node);
                      refreshChart(ScatterPlotView);
                  }
              });
  
              this.ySelector.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                      String node = ((Node) ySelector.getSelectedItem()).getName();
                      ScatterPlotView.setY(node);
                      refreshChart(ScatterPlotView);
                  }
              });
  
              includeLineCheckbox.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                      refreshChart(ScatterPlotView);
                  }
              });
  
              this.newConditioningVariableSelector = new JComboBox();
  
              for (Node node : variables) {
                  this.newConditioningVariableSelector.addItem(node);
              }
  
              this.newConditioningVariableButton = new JButton("Add");
  
              this.newConditioningVariableButton.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                      System.out.println("New conditioning variable action performed");
                      Node selected = (Node) newConditioningVariableSelector.getSelectedItem();
  
                      for (ConditioningPanel panel : conditioningPanels) {
                          if (selected == panel.getVariable()) {
                              JOptionPane.showMessageDialog(ScatterPlotController.this,
                                      "There is already a conditioning variable called " + selected + ".");
                              return;
                          }
                      }
  
                      if (selected instanceof ContinuousVariable) {
                          final ContinuousVariable _var = (ContinuousVariable) selected;
  
                          ContinuousConditioningPanel panel1 = (ContinuousConditioningPanel) conditioningPanelMap.get(_var);
  
                          if (panel1 == null) {
                              panel1 = ContinuousConditioningPanel.getDefault(_var, scatterPlot);
                          }
  
                          ContinuousInquiryPanel panel2 = new ContinuousInquiryPanel(_var, scatterPlot, panel1);
  
                          JOptionPane.showOptionDialog(ScatterPlotController.this, panel2,
                                  null, JOptionPane.DEFAULT_OPTION,
                                  JOptionPane.PLAIN_MESSAGE, null, null, null);
  
                          ContinuousConditioningPanel.Type type = panel2.getType();
                          double low = panel2.getLow();
                          double high = panel2.getHigh();
                          int ntile = panel2.getNtile();
                          int ntileIndex = panel2.getNtileIndex();
  
                          ContinuousConditioningPanel panel3 = new ContinuousConditioningPanel(_var, low, high, ntile, ntileIndex, type);
  
                          conditioningPanels.add(panel3);
                          conditioningPanelMap.put(_var, panel3);
                      } else {
                          throw new IllegalStateException();
                      }
  
                      buildEditArea();
                      resetConditioning();
  
                      refreshChart(ScatterPlotView);
                  }
              });
  
              this.removeConditioningVariableButton = new JButton("Remove Checked");
  
              this.removeConditioningVariableButton.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                      for (ConditioningPanel panel : new ArrayList<>(conditioningPanels)) {
                          if (panel.isSelected()) {
                              panel.setSelected(false);
                              conditioningPanels.remove(panel);
                              scatterPlot.removeConditioningVariable(panel.getVariable().toString());
                              refreshChart(ScatterPlotView);
                          }
                      }
  
                      buildEditArea();
                      resetConditioning();
                  }
              });
  
              // build the gui.
              restrictSize(this.xSelector);
              restrictSize(this.newConditioningVariableSelector);
              restrictSize(this.newConditioningVariableButton);
              restrictSize(this.removeConditioningVariableButton);
  
              buildEditArea();
          }
  
          private void refreshChart(ScatterPlotView ScatterPlotView) {
              ScatterPlot ScatterPlot = new ScatterPlot(ScatterPlotView.scatterPlot.getDataSet(),
                      includeLineCheckbox.isSelected(),
                      ScatterPlotView.x, ScatterPlotView.y);
              ScatterPlot.removeConditioningVariables();
              for (ConditioningPanel panel : conditioningPanels) {
                  if (panel instanceof ContinuousConditioningPanel) {
                      Node node = panel.getVariable();
                      double low = ((ContinuousConditioningPanel) panel).getLow();
                      double high = ((ContinuousConditioningPanel) panel).getHigh();
                      ScatterPlot.addConditioningVariable(node.getName(), low, high);
                  }
              }
  
              ScatterPlotView.scatterPlotChart.setScatterPlot(ScatterPlot);
              ScatterPlotView.scatterPlotChart.repaint();
          }
  
          private void resetConditioning() {
  
              // Need to set the conditions on the ScatterPlot and also update the list of conditions in the view.
              scatterPlot.removeConditioningVariables();
  
              for (ConditioningPanel panel : conditioningPanels) {
                  if (panel instanceof ContinuousConditioningPanel) {
                      Node node = panel.getVariable();
                      double low = ((ContinuousConditioningPanel) panel).getLow();
                      double high = ((ContinuousConditioningPanel) panel).getHigh();
                      scatterPlot.addConditioningVariable(node.getName(), low, high);
                  }
              }
          }
  
          private void buildEditArea() {
              restrictSize(xSelector);
              restrictSize(ySelector);
  
              Box main = Box.createVerticalBox();
              Box b1 = Box.createHorizontalBox();
              b1.add(new JLabel("ScatterPlot for: "));
              b1.add(Box.createHorizontalGlue());
              main.add(b1);
  
              Box b1a = Box.createHorizontalBox();
              b1a.add(new JLabel("X-axis = "));
              b1a.add(Box.createHorizontalGlue());
              b1a.add(xSelector);
              main.add(b1a);
  
              Box b1b = Box.createHorizontalBox();
              b1b.add(new JLabel("Y-axis = "));
              b1b.add(Box.createHorizontalGlue());
              b1b.add(ySelector);
              main.add(b1b);
  
              Box b1c = Box.createHorizontalBox();
              b1c.add(includeLineCheckbox);
              main.add(b1c);
  
              main.add(Box.createVerticalStrut(20));
  
              Box b3 = Box.createHorizontalBox();
              JLabel l1 = new JLabel("Conditioning on: ");
              l1.setFont(l1.getFont().deriveFont(Font.ITALIC));
              b3.add(l1);
              b3.add(Box.createHorizontalGlue());
              main.add(b3);
  
              main.add(Box.createVerticalStrut(20));
  
              for (ConditioningPanel panel : conditioningPanels) {
                  main.add(panel.getBox());
                  main.add(Box.createVerticalStrut(10));
              }
  
              main.add(Box.createVerticalStrut(10));
              main.add(Box.createVerticalGlue());
              main.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
  
              Box b6 = Box.createHorizontalBox();
              b6.add(newConditioningVariableSelector);
              b6.add(newConditioningVariableButton);
              b6.add(Box.createHorizontalGlue());
              main.add(b6);
  
              Box b7 = Box.createHorizontalBox();
              b7.add(removeConditioningVariableButton);
              b7.add(Box.createHorizontalGlue());
              main.add(b7);
  
              this.removeAll();
              this.add(main, BorderLayout.CENTER);
              revalidate();
              repaint();
          }
  
          //========================== Private Methods ================================//
  
          private Node getXNode() {
              return this.scatterPlot.getDataSet().getVariable(this.scatterPlot.getXvar());
          }
  
          private Node getYNode() {
              return this.scatterPlot.getDataSet().getVariable(this.scatterPlot.getYvar());
          }
  
          private static void restrictSize(JComponent component) {
              component.setMaximumSize(component.getPreferredSize());
          }
  
          //========================== Inner classes ===========================//
  
  
          private static class VariableBoxRenderer extends DefaultListCellRenderer {
  
              public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
                  Node node = (Node) value;
                  if (node == null) {
                      this.setText("");
                  } else {
                      this.setText(node.getName());
                  }
                  if (isSelected) {
                      setBackground(list.getSelectionBackground());
                      setForeground(list.getSelectionForeground());
                  } else {
                      setBackground(list.getBackground());
                      setForeground(list.getForeground());
                  }
  
                  return this;
              }
          }
  
          private interface ConditioningPanel {
              Box getBox();
  
              // selected for removal.
              boolean isSelected();
  
              Node getVariable();
  
              void setSelected(boolean b);
          }
  
          private static class ContinuousConditioningPanel implements ConditioningPanel {
  
              public int getNtile() {
                  return ntile;
              }
  
              public int getNtileIndex() {
                  return ntileIndex;
              }
  
              public enum Type {Range, Ntile, AboveAverage, BelowAverage}
  
              private ContinuousVariable variable;
              private Box box;
  
              private Type type;
              private double low;
              private double high;
              private int ntile;
              private int ntileIndex;
  
              // Mark selected if this panel is to be removed.
              private JCheckBox checkBox;
  
              public ContinuousConditioningPanel(ContinuousVariable variable, double low, double high, int ntile, int ntileIndex, Type type) {
                  if (variable == null) throw new NullPointerException();
                  if (low >= high) {
                      throw new IllegalArgumentException("Low >= high.");
                  }
                  if (ntile < 2 || ntile > 10) {
                      throw new IllegalArgumentException("Ntile should be in range 2 to 10: " + ntile);
                  }
  
                  this.variable = variable;
                  NumberFormat nf = new DecimalFormat("0.0000");
  
                  this.type = type;
                  this.low = low;
                  this.high = high;
                  this.ntile = ntile;
                  this.ntileIndex = ntileIndex;
  
                  Box b4 = Box.createHorizontalBox();
                  b4.add(Box.createRigidArea(new Dimension(10, 0)));
  
                  if (type == Type.Range) {
                      b4.add(new JLabel(variable + " = (" + nf.format(low) + ", " + nf.format(high) + ")"));
                  } else if (type == Type.AboveAverage) {
                      b4.add(new JLabel(variable + " = Above Average"));
                  } else if (type == Type.BelowAverage) {
                      b4.add(new JLabel(variable + " = Below Average"));
                  } else if (type == Type.Ntile) {
                      b4.add(new JLabel(variable + " = " + tiles[ntile - 1] + " " + ntileIndex));
                  }
  
                  b4.add(Box.createHorizontalGlue());
                  this.checkBox = new JCheckBox();
                  restrictSize(checkBox);
                  b4.add(checkBox);
                  this.box = b4;
  
              }
  
              public static ContinuousConditioningPanel getDefault(ContinuousVariable variable, ScatterPlot ScatterPlot) {
                  double[] data = ScatterPlot.getContinuousData(variable.getName());
                  double max = StatUtils.max(data);
                  double avg = StatUtils.mean(data);
                  return new ContinuousConditioningPanel(variable, avg, max, 2, 1, Type.AboveAverage);
              }
  
              public ContinuousVariable getVariable() {
                  return variable;
              }
  
              public Type getType() {
                  return type;
              }
  
              public Box getBox() {
                  return box;
              }
  
              public boolean isSelected() {
                  return checkBox.isSelected();
              }
  
              public void setSelected(boolean b) {
                  checkBox.setSelected(false);
              }
  
              public double getLow() {
                  return low;
              }
  
              public double getHigh() {
                  return high;
              }
          }
      }
  
      private static class ContinuousInquiryPanel extends JPanel {
          private JComboBox ntileCombo;
          private JComboBox ntileIndexCombo;
          private DoubleTextField field1;
          private DoubleTextField field2;
          private ScatterPlotController.ContinuousConditioningPanel.Type type;
          private final Map<String, Integer> ntileMap = new HashMap<>();
          private final double[] data;
  
          /**
           * @param variable          This is the variable being conditioned on. Must be continuous and one of the variables
           *                          in the ScatterPlot.
           * @param ScatterPlot       We need this to get the column of data for the variable.
           * @param conditioningPanel We will try to get some initialization information out of the conditioning
           *                          panel. This must be for the same variable as variable.
           */
          public ContinuousInquiryPanel(final ContinuousVariable variable, ScatterPlot ScatterPlot,
                                        ScatterPlotController.ContinuousConditioningPanel conditioningPanel) {
              data = ScatterPlot.getContinuousData(variable.getName());
  
              if (conditioningPanel == null)
                  throw new NullPointerException();
              if (!(variable == conditioningPanel.getVariable()))
                  throw new IllegalArgumentException("Wrong variable for conditioning panel.");
  
              // There is some order dependence in the below; careful rearranging things.
              NumberFormat nf = new DecimalFormat("0.00");
  
              field1 = new DoubleTextField(conditioningPanel.getLow(), 4, nf);
              field2 = new DoubleTextField(conditioningPanel.getHigh(), 4, nf);
  
              JRadioButton radio1 = new JRadioButton();
              JRadioButton radio2 = new JRadioButton();
              JRadioButton radio3 = new JRadioButton();
              JRadioButton radio4 = new JRadioButton();
  
              radio1.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                      type = ScatterPlotController.ContinuousConditioningPanel.Type.AboveAverage;
                      field1.setValue(StatUtils.mean(data));
                      field2.setValue(StatUtils.max(data));
                  }
              });
  
              radio2.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                      type = ScatterPlotController.ContinuousConditioningPanel.Type.BelowAverage;
                      field1.setValue(StatUtils.min(data));
                      field2.setValue(StatUtils.mean(data));
                  }
              });
  
              radio3.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                      type = ScatterPlotController.ContinuousConditioningPanel.Type.Ntile;
                      double[] breakpoints = getNtileBreakpoints(data, getNtile());
                      double breakpoint1 = breakpoints[getNtileIndex() - 1];
                      double breakpoint2 = breakpoints[getNtileIndex()];
                      field1.setValue(breakpoint1);
                      field2.setValue(breakpoint2);
                  }
              });
  
              radio4.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                      type = ScatterPlotController.ContinuousConditioningPanel.Type.Range;
                  }
              });
  
              ButtonGroup group = new ButtonGroup();
              group.add(radio1);
              group.add(radio2);
              group.add(radio3);
              group.add(radio4);
  
              type = conditioningPanel.getType();
  
              ntileCombo = new JComboBox();
              ntileIndexCombo = new JComboBox();
  
              int ntile = conditioningPanel.getNtile();
              int ntileIndex = conditioningPanel.getNtileIndex();
  
              for (int n = 2; n <= 10; n++) {
                  ntileCombo.addItem(tiles[n - 1]);
                  ntileMap.put(tiles[n - 1], n);
              }
  
              for (int n = 1; n <= ntile; n++) {
                  ntileIndexCombo.addItem(n);
              }
  
              ntileCombo.setSelectedItem(tiles[ntile - 1]);
              ntileIndexCombo.setSelectedItem(ntileIndex);
  
              ntileCombo.addItemListener(new ItemListener() {
                  public void itemStateChanged(ItemEvent e) {
                      String item = (String) e.getItem();
                      int ntileIndex = ntileMap.get(item);
  
                      for (int i = ntileIndexCombo.getItemCount() - 1; i >= 0; i--) {
                          ntileIndexCombo.removeItemAt(i);
                      }
  
                      for (int n = 1; n <= ntileIndex; n++) {
                          ntileIndexCombo.addItem(n);
                      }
  
                      double[] breakpoints = getNtileBreakpoints(data, getNtile());
                      double breakpoint1 = breakpoints[getNtileIndex() - 1];
                      double breakpoint2 = breakpoints[getNtileIndex()];
                      field1.setValue(breakpoint1);
                      field2.setValue(breakpoint2);
                  }
              });
  
              ntileIndexCombo.addItemListener(new ItemListener() {
                  public void itemStateChanged(ItemEvent e) {
                      int ntile = getNtile();
                      int ntileIndex = getNtileIndex();
                      double[] breakpoints = getNtileBreakpoints(data, ntile);
                      double breakpoint1 = breakpoints[ntileIndex - 1];
  