source: src/main/java/weka/gui/AttributeSelectionPanel.java @ 14

Last change on this file since 14 was 4, checked in by gnappo, 14 years ago

Import di weka.

File size: 12.2 KB
Line 
1/*
2 *    This program is free software; you can redistribute it and/or modify
3 *    it under the terms of the GNU General Public License as published by
4 *    the Free Software Foundation; either version 2 of the License, or
5 *    (at your option) any later version.
6 *
7 *    This program is distributed in the hope that it will be useful,
8 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 *    GNU General Public License for more details.
11 *
12 *    You should have received a copy of the GNU General Public License
13 *    along with this program; if not, write to the Free Software
14 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 */
16
17/*
18 *    AttributeSelectionPanel.java
19 *    Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.gui;
24
25import weka.core.Instances;
26
27import java.awt.Dimension;
28import java.awt.GridLayout;
29import java.awt.BorderLayout;
30import java.awt.event.ActionListener;
31import java.awt.event.ActionEvent;
32import java.util.regex.Pattern;
33import javax.swing.JPanel;
34import javax.swing.JButton;
35import javax.swing.JOptionPane;
36import javax.swing.JTable;
37import javax.swing.JScrollPane;
38import javax.swing.ListSelectionModel;
39import javax.swing.table.TableColumnModel;
40import javax.swing.table.AbstractTableModel;
41import javax.swing.BorderFactory;
42
43/**
44 * Creates a panel that displays the attributes contained in a set of
45 * instances, letting the user toggle whether each attribute is selected
46 * or not (eg: so that unselected attributes can be removed before
47 * classification). <br>
48 * Besides the All, None and Invert button one can also choose attributes which
49 * names match a regular expression (Pattern button). E.g. for removing all
50 * attributes that contain an ID and therefore unwanted information, one can
51 * match all names that contain "id" in the name:<br>
52 * <pre>   (.*_id_.*|.*_id$|^id$)</pre>
53 * This does not match e.g. "humidity", which could be an attribute we would
54 * like to keep.
55 *
56 * @author Len Trigg (trigg@cs.waikato.ac.nz)
57 * @author FracPete (fracpete at waikato dot ac dot nz)
58 * @version $Revision: 1.9 $
59 */
60public class AttributeSelectionPanel
61  extends JPanel {
62
63  /** for serialization */
64  private static final long serialVersionUID = 627131485290359194L;
65
66  /**
67   * A table model that looks at the names of attributes and maintains
68   * a list of attributes that have been "selected".
69   */
70  class AttributeTableModel
71    extends AbstractTableModel {
72
73    /** for serialization */
74    private static final long serialVersionUID = -4152987434024338064L;
75
76    /** The instances who's attribute structure we are reporting */
77    protected Instances m_Instances;
78   
79    /** The flag for whether the instance will be included */
80    protected boolean [] m_Selected;
81
82   
83    /**
84     * Creates the tablemodel with the given set of instances.
85     *
86     * @param instances the initial set of Instances
87     */
88    public AttributeTableModel(Instances instances) {
89
90      setInstances(instances);
91    }
92
93    /**
94     * Sets the tablemodel to look at a new set of instances.
95     *
96     * @param instances the new set of Instances.
97     */
98    public void setInstances(Instances instances) {
99
100      m_Instances = instances;
101      m_Selected = new boolean [m_Instances.numAttributes()];
102    }
103   
104    /**
105     * Gets the number of attributes.
106     *
107     * @return the number of attributes.
108     */
109    public int getRowCount() {
110     
111      return m_Selected.length;
112    }
113   
114    /**
115     * Gets the number of columns: 3
116     *
117     * @return 3
118     */
119    public int getColumnCount() {
120     
121      return 3;
122    }
123   
124    /**
125     * Gets a table cell
126     *
127     * @param row the row index
128     * @param column the column index
129     * @return the value at row, column
130     */
131    public Object getValueAt(int row, int column) {
132     
133      switch (column) {
134      case 0:
135        return new Integer(row + 1);
136      case 1:
137        return new Boolean(m_Selected[row]);
138      case 2:
139        return m_Instances.attribute(row).name();
140      default:
141        return null;
142      }
143    }
144   
145    /**
146     * Gets the name for a column.
147     *
148     * @param column the column index.
149     * @return the name of the column.
150     */
151    public String getColumnName(int column) {
152     
153      switch (column) {
154      case 0:
155        return new String("No.");
156      case 1:
157        return new String("");
158      case 2:
159        return new String("Name");
160      default:
161        return null;
162      }
163    }
164   
165    /**
166     * Sets the value at a cell.
167     *
168     * @param value the new value.
169     * @param row the row index.
170     * @param col the column index.
171     */
172    public void setValueAt(Object value, int row, int col) {
173     
174      if (col == 1) {
175        m_Selected[row] = ((Boolean) value).booleanValue(); 
176      }
177    }
178   
179    /**
180     * Gets the class of elements in a column.
181     *
182     * @param col the column index.
183     * @return the class of elements in the column.
184     */
185    public Class getColumnClass(int col) {
186      return getValueAt(0, col).getClass();
187    }
188
189    /**
190     * Returns true if the column is the "selected" column.
191     *
192     * @param row ignored
193     * @param col the column index.
194     * @return true if col == 1.
195     */
196    public boolean isCellEditable(int row, int col) {
197
198      if (col == 1) { 
199        return true;
200      }
201      return false;
202    }
203   
204    /**
205     * Gets an array containing the indices of all selected attributes.
206     *
207     * @return the array of selected indices.
208     */
209    public int [] getSelectedAttributes() {
210     
211      int [] r1 = new int[getRowCount()];
212      int selCount = 0;
213      for (int i = 0; i < getRowCount(); i++) {
214        if (m_Selected[i]) {
215          r1[selCount++] = i;
216        }
217      }
218      int [] result = new int[selCount];
219      System.arraycopy(r1, 0, result, 0, selCount);
220      return result;
221    }
222   
223    /**
224     * Sets the state of all attributes to selected.
225     */
226    public void includeAll() {
227     
228      for (int i = 0; i < m_Selected.length; i++) {
229        m_Selected[i] = true;
230      }
231      fireTableRowsUpdated(0, m_Selected.length);
232    }
233   
234    /**
235     * Deselects all attributes.
236     */
237    public void removeAll() {
238     
239      for (int i = 0; i < m_Selected.length; i++) {
240        m_Selected[i] = false;
241      }
242      fireTableRowsUpdated(0, m_Selected.length);
243    }
244
245    /**
246     * Inverts the selected status of each attribute.
247     */
248    public void invert() {
249
250      for (int i = 0; i < m_Selected.length; i++) {
251        m_Selected[i] = !m_Selected[i];
252      }
253      fireTableRowsUpdated(0, m_Selected.length);
254    }
255
256    /**
257     * applies the perl regular expression pattern to select the attribute
258     * names (expects a valid reg expression!)
259     * @param pattern     a perl reg. expression
260     */
261    public void pattern(String pattern) {
262      for (int i = 0; i < m_Selected.length; i++)
263        m_Selected[i] = Pattern.matches(
264                          pattern, m_Instances.attribute(i).name());
265      fireTableRowsUpdated(0, m_Selected.length);
266    }
267  }
268
269  /** Press to select all attributes */ 
270  protected JButton m_IncludeAll = new JButton("All");
271
272  /** Press to deselect all attributes */
273  protected JButton m_RemoveAll = new JButton("None");
274
275  /** Press to invert the current selection */
276  protected JButton m_Invert = new JButton("Invert");
277
278  /** Press to enter a perl regular expression for selection */
279  protected JButton m_Pattern = new JButton("Pattern");
280
281  /** The table displaying attribute names and selection status */
282  protected JTable m_Table = new JTable();
283
284  /** The table model containingn attribute names and selection status */
285  protected AttributeTableModel m_Model;
286
287  /** The current regular expression. */
288  protected String m_PatternRegEx = "";
289 
290  /**
291   * Creates the attribute selection panel with no initial instances.
292   */
293  public AttributeSelectionPanel() {
294
295    m_IncludeAll.setToolTipText("Selects all attributes");
296    m_IncludeAll.setEnabled(false);
297    m_IncludeAll.addActionListener(new ActionListener() {
298      public void actionPerformed(ActionEvent e) {
299        m_Model.includeAll();
300      }
301    });
302    m_RemoveAll.setToolTipText("Unselects all attributes");
303    m_RemoveAll.setEnabled(false);
304    m_RemoveAll.addActionListener(new ActionListener() {
305      public void actionPerformed(ActionEvent e) {
306        m_Model.removeAll();
307      }
308    });
309    m_Invert.setToolTipText("Inverts the current attribute selection");
310    m_Invert.setEnabled(false);
311    m_Invert.addActionListener(new ActionListener() {
312      public void actionPerformed(ActionEvent e) {
313        m_Model.invert();
314      }
315    });
316    m_Pattern.setToolTipText("Selects all attributes that match a reg. expression");
317    m_Pattern.setEnabled(false);
318    m_Pattern.addActionListener(new ActionListener() {
319      public void actionPerformed(ActionEvent e) {
320        String pattern = JOptionPane.showInputDialog(
321                            m_Pattern.getParent(),
322                            "Enter a Perl regular expression",
323                            m_PatternRegEx);
324        if (pattern != null) {
325          try {
326            Pattern.compile(pattern);
327            m_PatternRegEx = pattern;
328            m_Model.pattern(pattern);
329          }
330          catch (Exception ex) {
331            JOptionPane.showMessageDialog(
332              m_Pattern.getParent(),
333              "'" + pattern + "' is not a valid Perl regular expression!\n" 
334              + "Error: " + ex, 
335              "Error in Pattern...", 
336              JOptionPane.ERROR_MESSAGE);
337          }
338        }
339      }
340    });
341    m_Table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
342    m_Table.setColumnSelectionAllowed(false); 
343    m_Table.setPreferredScrollableViewportSize(new Dimension(250, 150));
344
345    // Set up the layout
346    JPanel p1 = new JPanel();
347    p1.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 5));
348    p1.setLayout(new GridLayout(1, 4, 5, 5));
349    p1.add(m_IncludeAll);
350    p1.add(m_RemoveAll);
351    p1.add(m_Invert);
352    p1.add(m_Pattern);
353
354    setLayout(new BorderLayout());
355    add(p1, BorderLayout.NORTH);
356    add(new JScrollPane(m_Table), BorderLayout.CENTER);
357  }
358
359  /**
360   * Sets the instances who's attribute names will be displayed.
361   *
362   * @param newInstances the new set of instances
363   */
364  public void setInstances(Instances newInstances) {
365
366    if (m_Model == null) {
367      m_Model = new AttributeTableModel(newInstances);
368      m_Table.setModel(m_Model);
369      TableColumnModel tcm = m_Table.getColumnModel();
370      tcm.getColumn(0).setMaxWidth(60);
371      tcm.getColumn(1).setMaxWidth(tcm.getColumn(1).getMinWidth());
372      tcm.getColumn(2).setMinWidth(100);
373    } else {
374      m_Model.setInstances(newInstances);
375      m_Table.clearSelection();
376    }
377    m_IncludeAll.setEnabled(true);
378    m_RemoveAll.setEnabled(true);
379    m_Invert.setEnabled(true);
380    m_Pattern.setEnabled(true);
381    m_Table.sizeColumnsToFit(2);
382    m_Table.revalidate();
383    m_Table.repaint();
384  }
385
386  /**
387   * Gets an array containing the indices of all selected attributes.
388   *
389   * @return the array of selected indices.
390   */
391  public int [] getSelectedAttributes() {
392   
393    return m_Model.getSelectedAttributes();
394  }
395 
396  /**
397   * Gets the selection model used by the table.
398   *
399   * @return a value of type 'ListSelectionModel'
400   */
401  public ListSelectionModel getSelectionModel() {
402
403    return m_Table.getSelectionModel();
404  }
405 
406  /**
407   * Tests the attribute selection panel from the command line.
408   *
409   * @param args must contain the name of an arff file to load.
410   */
411  public static void main(String[] args) {
412
413    try {
414      if (args.length == 0) {
415        throw new Exception("supply the name of an arff file");
416      }
417      Instances i = new Instances(new java.io.BufferedReader(
418                                  new java.io.FileReader(args[0])));
419      AttributeSelectionPanel asp = new AttributeSelectionPanel();
420      final javax.swing.JFrame jf =
421        new javax.swing.JFrame("Attribute Selection Panel");
422      jf.getContentPane().setLayout(new BorderLayout());
423      jf.getContentPane().add(asp, BorderLayout.CENTER);
424      jf.addWindowListener(new java.awt.event.WindowAdapter() {
425        public void windowClosing(java.awt.event.WindowEvent e) {
426          jf.dispose();
427          System.exit(0);
428        }
429      });
430      jf.pack();
431      jf.setVisible(true);
432      asp.setInstances(i);
433    } catch (Exception ex) {
434      ex.printStackTrace();
435      System.err.println(ex.getMessage());
436    }
437  }
438 
439} // AttributeSelectionPanel
Note: See TracBrowser for help on using the repository browser.