source: src/main/java/weka/gui/ensembleLibraryEditor/AddModelsPanel.java @ 17

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

Import di weka.

File size: 16.3 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 *    AddModelsPanel.java
19 *    Copyright (C) 2006 Robert Jung
20 *
21 */
22
23package weka.gui.ensembleLibraryEditor;
24
25import weka.classifiers.Classifier;
26import weka.classifiers.AbstractClassifier;
27import weka.classifiers.EnsembleLibraryModel;
28import weka.classifiers.trees.J48;
29import weka.gui.GenericObjectEditor;
30import weka.gui.ensembleLibraryEditor.tree.GenericObjectNode;
31import weka.gui.ensembleLibraryEditor.tree.ModelTreeNodeEditor;
32import weka.gui.ensembleLibraryEditor.tree.ModelTreeNodeRenderer;
33
34import java.awt.BorderLayout;
35import java.awt.Dimension;
36import java.awt.GridBagConstraints;
37import java.awt.GridBagLayout;
38import java.awt.event.ActionEvent;
39import java.awt.event.ActionListener;
40import java.util.Iterator;
41import java.util.Vector;
42
43import javax.swing.AbstractAction;
44import javax.swing.BorderFactory;
45import javax.swing.JButton;
46import javax.swing.JLabel;
47import javax.swing.JList;
48import javax.swing.JPanel;
49import javax.swing.JScrollPane;
50import javax.swing.JTree;
51import javax.swing.KeyStroke;
52import javax.swing.ListSelectionModel;
53import javax.swing.ToolTipManager;
54import javax.swing.tree.DefaultTreeModel;
55
56/**
57 * The purpose of this class is to create a user interface that will
58 * provide an intuitive method of building "playlists" of weka
59 * classifiers to be trained.  The main gui consists of two parts: the
60 * top and bottom. The top will use a JTree to show all of the options
61 * available for a particular classifier. The intent of showing these
62 * options in a tree is to allow users to collapse/expand tree nodes
63 * to quickly access all of the available options at different levels.
64 * The bottom half of the gui will show the current "playlist" of
65 * chosen models that the user can opt to add to the current library. 
66 * <p/>
67 * The overall concept is that users will use the tree to specify
68 * combinations of options to the currently selected classifier type.
69 * then they will use the "generate models" button to generate a set
70 * models from the selected options. This can be done many times with
71 * different sets of options for different model types to generate a
72 * list in the bottom half of the gui.  Once the user is satisfied
73 * with their list of models they are provided a button to "add all
74 * models" to the model library displayed by the ListModelsPanel.
75 * <p/>
76 * Note that there are currently 9 different classes that implement
77 * tree nodes and tree node editors created to support this class
78 * in modelling/rendering weka classifier parameters. see
79 * appropriate classes for details.  They currently reside in the
80 * weka.gui.libraryEditor.tree package.
81 * <p/>
82 * To instantiate the treeModel:
83 * <ul>
84 *   <li>ModelNodeEditor</li>
85 *   <li>ModelNodeRenderer</li>
86 * </ul>
87 *
88 * To render/model weka objects:
89 * <ul>
90 *   <li>PropertyNode</li>
91 *   <li>GenericObjectNode</li>
92 *   <li>GenericObjectNodeEditor</li>
93 *   <li>CheckBoxNode</li>
94 *   <li>CheckBoxNodeEditor</li>
95 *   <li>NumberNode</li>
96 *   <li>NumberNodeEditor</li>
97 *   <li>DefaultNode</li>
98 * </ul>
99 *
100 * These classes are responsible for
101 * representing the different kinds of tree nodes that will be
102 * contained in the JTree object, as well as the renderers and editors
103 * that will be responsible for displaying their properties in the
104 * user interface. 
105 * <p/>
106 * Code for this class was inspired and partly borrowed from the
107 * following excellent tutorial on creating custom JTree renderers
108 * and editors authored by John Zukowski: <br/>
109 * <a href="http://www.java2s.com/ExampleCode/Swing-JFC/CheckBoxNodeTreeSample.htm" target="_blank">http://www.java2s.com/ExampleCode/Swing-JFC/CheckBoxNodeTreeSample.htm</a>
110 *
111 * @author  Robert Jung (mrbobjung@gmail.com)
112 * @version $Revision: 5928 $
113 */
114public class AddModelsPanel 
115  extends JPanel
116  implements ActionListener {
117 
118  /** for serialization */
119  private static final long serialVersionUID = 4874639416371962573L;
120
121  /**
122   * This is a reference to the main gui object that is responsible
123   * for displaying the model library.  This panel will add models
124   * to the main panel through methods in this object.
125   */
126  private ListModelsPanel m_ListModelsPanel;
127 
128  /**
129   * The JTree that will display the classifier options available in
130   * the currently select3ed model type
131   */
132  private JTree m_Tree;
133 
134  /**
135   * The tree model that will be used to add and remove nodes from
136   * the currently selected model type
137   */
138  private DefaultTreeModel m_TreeModel;
139 
140  /**
141   * This button will allow users to generate a group of models from
142   * the currently selected classifer options in the m_Tree object.
143   */
144  private JButton m_GenerateButton;
145 
146  /**
147   * This will display messages associated with model generation.
148   * Currently the number of models generated and the number of
149   * them that had errors.
150   */
151  private JLabel m_GenerateLabel;
152 
153  /**
154   * This button will allow users to remove all of the models
155   * currently selected in the m_ModeList object
156   */
157  private JButton m_RemoveSelectedButton;
158 
159  /**
160   * This button will remove all of the models that had errors
161   * during model generation.
162   */
163  private JButton m_RemoveInvalidButton;
164 
165  /**
166   * This button will add all of the models that had are
167   * currently selected in the model list.
168   */
169  private JButton m_AddSelectedButton;
170 
171  /**
172   * This button will allow users to add all models currently in
173   * the model list to the model library in the ListModelsPanel.
174   * Note that this operation will exclude any models that had
175   * errors
176   */
177  private JButton m_AddAllButton;
178 
179  /**
180   * This object will store all of the model sets generated from the
181   * m_Tree.  The ModelList class is a custom class in weka.gui that
182   * knows how to display library model objects in a JList
183   */
184  private ModelList m_ModelList;
185 
186  /** the scroll pane holding our classifer parameters */
187  JScrollPane m_TreeView;
188 
189  /**
190   * This constructor simply stores the reference to the
191   * ListModelsPanel and builf the user interface.
192   *
193   * @param listModelsPanel     the reference to the panel
194   */
195  public AddModelsPanel(ListModelsPanel listModelsPanel) {
196    m_ListModelsPanel = listModelsPanel;
197   
198    createAddModelsPanel();
199  }
200 
201  /**
202   * This method is responsible for building the use interface.
203   */
204  private void createAddModelsPanel() {
205    GridBagConstraints gbc = new GridBagConstraints();
206    setLayout(new GridBagLayout());
207   
208    m_TreeView = new JScrollPane();
209    m_TreeView.setPreferredSize(new Dimension(150, 50));
210   
211    buildClassifierTree(new J48());
212   
213    ToolTipManager.sharedInstance().registerComponent(m_Tree);
214   
215    gbc.weightx = 1;
216    gbc.weighty = 1.5;
217    gbc.fill = GridBagConstraints.BOTH;
218    gbc.gridx = 0;
219    gbc.gridy = 0;
220    gbc.gridwidth = 3;
221    gbc.anchor = GridBagConstraints.WEST;
222    add(m_TreeView, gbc);
223   
224    m_GenerateButton = new JButton("Generate Models");
225    m_GenerateButton.setToolTipText(
226        "Generate a set of models from options specified in options tree");
227    m_GenerateButton.addActionListener(this);
228    gbc.weightx = 0;
229    gbc.weighty = 0;
230    gbc.fill = GridBagConstraints.NONE;
231    gbc.gridx = 0;
232    gbc.gridy = 1;
233    gbc.anchor = GridBagConstraints.WEST;
234    gbc.gridwidth = 1;
235    add(m_GenerateButton, gbc);
236   
237    m_GenerateLabel = new JLabel("");
238    gbc.weightx = 1;
239    gbc.fill = GridBagConstraints.HORIZONTAL;
240    gbc.gridx = 1;
241    gbc.gridy = 1;
242    gbc.anchor = GridBagConstraints.WEST;
243    gbc.gridwidth = 2;
244    add(m_GenerateLabel, gbc);
245   
246    m_RemoveInvalidButton = new JButton("Remove Invalid");
247    m_RemoveInvalidButton.setToolTipText(
248        "Remove all invalid (red) models from the above list");
249    m_RemoveInvalidButton.addActionListener(this);
250    gbc.weightx = 0;
251    gbc.fill = GridBagConstraints.NONE;
252    gbc.gridx = 2;
253    gbc.gridy = 1;
254    gbc.anchor = GridBagConstraints.WEST;
255    gbc.gridwidth = 1;
256    //OK, this button was removed because we thought it was a waste
257    //of space.  Instead of removing invalid models, we just explicitly
258    //prevent the user from adding them to the main list.  I'm going to
259    //leave the code in with this final "add" statement commented out
260    //because we are still on the fence as to whether this is a good
261    //idea
262    //add(m_RemoveInvalidButton, gbc);
263   
264    m_ModelList = new ModelList();
265   
266    m_ModelList.getInputMap().put(
267        KeyStroke.getKeyStroke("released DELETE"), "deleteSelected");
268    m_ModelList.getActionMap().put("deleteSelected",
269        new AbstractAction("deleteSelected") {
270      /** for serialization */
271      private static final long serialVersionUID = -3351194234735560372L;
272     
273      public void actionPerformed(ActionEvent evt) {
274       
275        Object[] currentModels = m_ModelList.getSelectedValues();
276       
277        ModelList.SortedListModel dataModel = ((ModelList.SortedListModel) m_ModelList.getModel());
278       
279        for (int i = 0; i < currentModels.length; i++) {
280          dataModel.removeElement((EnsembleLibraryModel) currentModels[i]);
281        }
282       
283        //Shrink the selected range to the first index that was selected
284        int selected[] = new int[1];
285        selected[0] = m_ModelList.getSelectedIndices()[0];
286        m_ModelList.setSelectedIndices(selected);
287       
288      }
289    });
290   
291    m_ModelList
292    .setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
293    m_ModelList.setLayoutOrientation(JList.VERTICAL);
294    m_ModelList.setVisibleRowCount(-1);
295   
296    JPanel modelListPanel = new JPanel();
297    modelListPanel.setBorder(
298        BorderFactory.createTitledBorder("Working Set of Newly Generated Models"));
299   
300    JScrollPane listView = new JScrollPane(m_ModelList);
301    //listView.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
302    listView.setPreferredSize(new Dimension(150, 50));
303   
304    modelListPanel.setLayout(new BorderLayout());
305    modelListPanel.add(listView, BorderLayout.CENTER);
306   
307    gbc.weightx = 1;
308    gbc.weighty = 1;
309    gbc.fill = GridBagConstraints.BOTH;
310    gbc.gridx = 0;
311    gbc.gridy = 2;
312    gbc.gridwidth = 3;
313    gbc.anchor = GridBagConstraints.WEST;
314    add(modelListPanel, gbc);
315   
316    m_RemoveSelectedButton = new JButton("Remove Selected");
317    m_RemoveSelectedButton.setToolTipText("Remove all currently selected models from the above list");
318    m_RemoveSelectedButton.addActionListener(this);
319    gbc.weightx = 1;
320    gbc.weighty = 0;
321    gbc.fill = GridBagConstraints.HORIZONTAL;
322    gbc.gridx = 0;
323    gbc.gridy = 3;
324    gbc.anchor = GridBagConstraints.WEST;
325    gbc.gridwidth = 1;
326    add(m_RemoveSelectedButton, gbc);
327   
328    m_AddSelectedButton = new JButton("Add Selected");
329    m_AddSelectedButton.setToolTipText(
330        "Add selected models in the above list to the model library");
331    m_AddSelectedButton.addActionListener(this);
332    gbc.weightx = 1;
333    gbc.fill = GridBagConstraints.HORIZONTAL;
334    gbc.gridx = 1;
335    gbc.gridy = 3;
336    gbc.anchor = GridBagConstraints.WEST;
337    gbc.gridwidth = 1;
338    add(m_AddSelectedButton, gbc);
339   
340    m_AddAllButton = new JButton("Add All");
341    m_AddAllButton.setToolTipText(
342        "Add all models in the above list to the model library");
343    m_AddAllButton.addActionListener(this);
344    gbc.weightx = 1;
345    gbc.fill = GridBagConstraints.HORIZONTAL;
346    gbc.gridx = 2;
347    gbc.gridy = 3;
348    gbc.anchor = GridBagConstraints.WEST;
349    gbc.gridwidth = 1;
350    add(m_AddAllButton, gbc);
351  }
352 
353  /**
354   * This method necessarily seperates the process of building the
355   * tree object from the rest of the GUI construction.  In order to
356   * prevent all kinds of strange garbage collection problems, we take
357   * the conservative approach of gutting and rebuilding the JTree
358   * every time a new classifier is chosen for the root node.
359   *
360   * @param classifier  the classifier to build the tree for
361   */
362  public void buildClassifierTree(Classifier classifier) {
363   
364    //This block sets up the root node of the tree.  Note that
365    //the constructor for the GenericObjectNode will take care
366    //of creating all of the child nodes containing the node
367    //properties
368    GenericObjectEditor classifierEditor = new GenericObjectEditor();
369    classifierEditor.setClassType(Classifier.class);
370    classifierEditor.setValue(classifier);
371   
372    GenericObjectNode rootNode = new GenericObjectNode(this, classifier,
373        classifierEditor, "Current Classifier");
374   
375    m_TreeModel = new DefaultTreeModel(rootNode);
376    m_Tree = new JTree(m_TreeModel);
377    rootNode.setTree(m_Tree);
378    rootNode.updateTree();
379   
380    m_Tree.setRootVisible(true);
381   
382    ModelTreeNodeRenderer renderer = new ModelTreeNodeRenderer();
383    m_Tree.setCellRenderer(renderer);
384    m_Tree.setCellEditor(new ModelTreeNodeEditor(m_Tree));
385    m_Tree.setEditable(true);
386    m_Tree.setVisibleRowCount(8);
387    //ToolTipManager.sharedInstance().registerComponent(m_Tree);
388   
389    //This "tentatively seems to work better:
390    m_Tree.setRowHeight(0);
391   
392    m_TreeView.setViewportView(m_Tree);
393  }
394 
395  /**
396   * This will support the button triggered events for this panel.
397   *
398   * @param e   the event
399   */
400  public void actionPerformed(ActionEvent e) {
401   
402    ModelList.SortedListModel dataModel = ((ModelList.SortedListModel) m_ModelList.getModel());
403   
404    if (e.getSource() == m_GenerateButton) {
405     
406      //here we want to generate all permutations of the
407      //options specified and then add each of them to the
408      //model list panel
409     
410      Vector models = ((GenericObjectNode) m_TreeModel.getRoot()).getValues();
411     
412      int total = models.size();
413      int invalid = 0;
414     
415      for (int i = 0; i < models.size(); i++) {
416        Classifier classifier = (Classifier) models.get(i);
417       
418        //This method will invoke the classifier's setOptions
419        //method to see if the current set of options was
420        //valid. 
421       
422        EnsembleLibraryModel model = m_ListModelsPanel.getLibrary().createModel(classifier);
423       
424        model.testOptions();
425       
426        if (!model.getOptionsWereValid())
427          invalid++;
428       
429        dataModel.add(model);
430      }
431     
432      //update the message text with model generation info
433      String generateString = new String("  " + total
434          + " models generated");
435      generateString += ", " + invalid + " had errors";
436      m_GenerateLabel.setText(generateString);
437     
438    } else if (e.getSource() == m_RemoveSelectedButton) {
439     
440      //here we simply get the list of models that are
441      //currently selected and ten remove them from the list
442     
443      Object[] currentModels = m_ModelList.getSelectedValues();
444     
445      for (int i = 0; i < currentModels.length; i++) {
446        dataModel.removeElement(currentModels[i]);
447      }
448     
449      //Shrink the selected range to the first index that was selected
450      if (m_ModelList.getSelectedIndices().length > 0) {
451        int selected[] = new int[1];
452        selected[0] = m_ModelList.getSelectedIndices()[0];
453        m_ModelList.setSelectedIndices(selected);
454      }
455     
456    } else if (e.getSource() == m_RemoveInvalidButton) {
457     
458      //here we simply remove all the models that were not
459      //valid
460     
461      Vector toRemove = new Vector();
462     
463      for (int i = 0; i < dataModel.getSize(); i++) {
464       
465        EnsembleLibraryModel currentModel = (EnsembleLibraryModel) dataModel.getElementAt(i);
466        if (!currentModel.getOptionsWereValid()) {
467          toRemove.add(currentModel);
468        }
469      }
470     
471      for (int i = 0; i < toRemove.size(); i++)
472        dataModel.removeElement(toRemove.get(i));
473     
474    } else if (e.getSource() == m_AddAllButton) {
475     
476      //here we just need to add all of the models to the
477      //ListModelsPanel object
478     
479      Iterator it = dataModel.iterator();
480     
481      while (it.hasNext()) {
482        EnsembleLibraryModel currentModel = (EnsembleLibraryModel) it.next();
483        if (currentModel.getOptionsWereValid()) {
484          m_ListModelsPanel.addModel(currentModel);
485        }
486      }
487     
488      int size = dataModel.getSize();
489     
490      for (int i = 0; i < size; i++) {
491        dataModel.removeElement(dataModel.getElementAt(0));
492      }
493    }
494  }
495}
Note: See TracBrowser for help on using the repository browser.