/* * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * ClassAssigner.java * Copyright (C) 2002 University of Waikato, Hamilton, New Zealand * */ package weka.gui.beans; import weka.core.Instances; import java.awt.BorderLayout; import java.beans.EventSetDescriptor; import java.io.Serializable; import java.util.Vector; import javax.swing.JPanel; /** * Bean that assigns a class attribute to a data set. * * @author Mark Hall * @version $Revision: 7332 $ */ public class ClassAssigner extends JPanel implements Visible, DataSourceListener, TrainingSetListener, TestSetListener, DataSource, TrainingSetProducer, TestSetProducer, BeanCommon, EventConstraints, Serializable, InstanceListener, StructureProducer { /** for serialization */ private static final long serialVersionUID = 4011131665025817924L; private String m_classColumn = "last"; /** format of instances for current incoming connection (if any) */ private Instances m_connectedFormat; private Object m_trainingProvider; private Object m_testProvider; private Object m_dataProvider; private Object m_instanceProvider; private Vector m_trainingListeners = new Vector(); private Vector m_testListeners = new Vector(); private Vector m_dataListeners = new Vector(); private Vector m_instanceListeners = new Vector(); private Vector m_dataFormatListeners = new Vector(); protected transient weka.gui.Logger m_logger = null; protected BeanVisual m_visual = new BeanVisual("ClassAssigner", BeanVisual.ICON_PATH+"ClassAssigner.gif", BeanVisual.ICON_PATH+"ClassAssigner_animated.gif"); /** * Global info for this bean * * @return a <code>String</code> value */ public String globalInfo() { return "Designate which column is to be considered the class column " +"in incoming data."; } public ClassAssigner() { setLayout(new BorderLayout()); add(m_visual, BorderLayout.CENTER); } /** * Set a custom (descriptive) name for this bean * * @param name the name to use */ public void setCustomName(String name) { m_visual.setText(name); } /** * Get the custom (descriptive) name for this bean (if one has been set) * * @return the custom name (or the default name) */ public String getCustomName() { return m_visual.getText(); } /** * Tool tip text for this property * * @return a <code>String</code> value */ public String classColumnTipText() { return "Specify the number of the column that contains the class attribute"; } private Instances getUpstreamStructure() { if (m_dataProvider != null && m_dataProvider instanceof StructureProducer) { return ((StructureProducer)m_dataProvider).getStructure("dataSet"); } if (m_trainingProvider != null && m_trainingProvider instanceof StructureProducer) { return ((StructureProducer)m_trainingProvider).getStructure("trainingSet"); } if (m_testProvider != null && m_testProvider instanceof StructureProducer) { return ((StructureProducer)m_testProvider).getStructure("testSet"); } if (m_instanceProvider != null && m_instanceProvider instanceof StructureProducer) { return ((StructureProducer)m_instanceProvider).getStructure("instance"); } return null; } /** * Get the structure of the output encapsulated in the named * event. If the structure can't be determined in advance of * seeing input, or this StructureProducer does not generate * the named event, null should be returned. * * @param eventName the name of the output event that encapsulates * the requested output. * * @return the structure of the output encapsulated in the named * event or null if it can't be determined in advance of seeing input * or the named event is not generated by this StructureProduce. */ public Instances getStructure(String eventName) { if (!eventName.equals("trainingSet") && !eventName.equals("testSet") && !eventName.equals("dataSet") && !eventName.equals("instance")) { return null; } if (m_trainingProvider == null && m_testProvider == null && m_dataProvider == null && m_instanceProvider == null) { return null; } if (eventName.equals("dataSet") && m_dataListeners.size() == 0) { // downstream has asked for the structure of something that we // are not producing at the moment return null; } if (eventName.equals("trainingSet") && m_trainingListeners.size() == 0) { // downstream has asked for the structure of something that we // are not producing at the moment return null; } if (eventName.equals("testSet") && m_testListeners.size() == 0) { // downstream has asked for the structure of something that we // are not producing at the moment return null; } if (eventName.equals("instance") && m_instanceListeners.size() == 0) { // downstream has asked for the structure of something that we // are not producing at the moment return null; } return getUpstreamStructure(); } /** * Returns the structure of the incoming instances (if any) * * @return an <code>Instances</code> value */ public Instances getConnectedFormat() { // loaders will push instances format to us // when the user makes configuration changes // to the loader in the gui. However, if a fully // configured flow is loaded then we won't get // this information pushed to us until the // flow is run. In this case we want to pull // it (if possible) from upstream steps so // that our customizer can provide the nice // UI with the drop down box of class names. if (m_connectedFormat == null) { // try and pull the incoming structure // from the upstream step (if possible) m_connectedFormat = getUpstreamStructure(); } return m_connectedFormat; } public void setClassColumn(String col) { m_classColumn = col; if (m_connectedFormat != null) { assignClass(m_connectedFormat); } } public String getClassColumn() { return m_classColumn; } public void acceptDataSet(DataSetEvent e) { Instances dataSet = e.getDataSet(); assignClass(dataSet); notifyDataListeners(e); if (e.isStructureOnly()) { m_connectedFormat = e.getDataSet(); // tell any listening customizers (or other notifyDataFormatListeners(); } } public void acceptTrainingSet(TrainingSetEvent e) { Instances trainingSet = e.getTrainingSet(); assignClass(trainingSet); notifyTrainingListeners(e); if (e.isStructureOnly()) { m_connectedFormat = e.getTrainingSet(); // tell any listening customizers (or other notifyDataFormatListeners(); } } public void acceptTestSet(TestSetEvent e) { Instances testSet = e.getTestSet(); assignClass(testSet); notifyTestListeners(e); if (e.isStructureOnly()) { m_connectedFormat = e.getTestSet(); // tell any listening customizers (or other notifyDataFormatListeners(); } } public void acceptInstance(InstanceEvent e) { if (e.getStatus() == InstanceEvent.FORMAT_AVAILABLE) { // Instances dataSet = e.getInstance().dataset(); m_connectedFormat = e.getStructure(); // System.err.println("Assigning class column..."); assignClass(m_connectedFormat); notifyInstanceListeners(e); // tell any listening customizers (or other interested parties) System.err.println("Notifying customizer..."); notifyDataFormatListeners(); } else { // Instances dataSet = e.getInstance().dataset(); // assignClass(dataSet); notifyInstanceListeners(e); } } private void assignClass(Instances dataSet) { int classCol = -1; if (m_classColumn.toLowerCase().compareTo("last") == 0) { dataSet.setClassIndex(dataSet.numAttributes()-1); } else if (m_classColumn.toLowerCase().compareTo("first") == 0) { dataSet.setClassIndex(0); } else { classCol = Integer.parseInt(m_classColumn) - 1; if (/*classCol < 0 ||*/ classCol > dataSet.numAttributes()-1) { if (m_logger != null) { m_logger.logMessage("Class column outside range of data " +"(ClassAssigner)"); } } else { dataSet.setClassIndex(classCol); } } } protected void notifyTestListeners(TestSetEvent tse) { Vector l; synchronized (this) { l = (Vector)m_testListeners.clone(); } if (l.size() > 0) { for(int i = 0; i < l.size(); i++) { System.err.println("Notifying test listeners " +"(ClassAssigner)"); ((TestSetListener)l.elementAt(i)).acceptTestSet(tse); } } } protected void notifyTrainingListeners(TrainingSetEvent tse) { Vector l; synchronized (this) { l = (Vector)m_trainingListeners.clone(); } if (l.size() > 0) { for(int i = 0; i < l.size(); i++) { System.err.println("Notifying training listeners " +"(ClassAssigner)"); ((TrainingSetListener)l.elementAt(i)).acceptTrainingSet(tse); } } } protected void notifyDataListeners(DataSetEvent tse) { Vector l; synchronized (this) { l = (Vector)m_dataListeners.clone(); } if (l.size() > 0) { for(int i = 0; i < l.size(); i++) { System.err.println("Notifying data listeners " +"(ClassAssigner)"); ((DataSourceListener)l.elementAt(i)).acceptDataSet(tse); } } } protected void notifyInstanceListeners(InstanceEvent tse) { Vector l; synchronized (this) { l = (Vector)m_instanceListeners.clone(); } if (l.size() > 0) { for(int i = 0; i < l.size(); i++) { // System.err.println("Notifying instance listeners " // +"(ClassAssigner)"); ((InstanceListener)l.elementAt(i)).acceptInstance(tse); } } } protected void notifyDataFormatListeners() { Vector l; synchronized (this) { l = (Vector)m_dataFormatListeners.clone(); } if (l.size() > 0) { DataSetEvent dse = new DataSetEvent(this, m_connectedFormat); for(int i = 0; i < l.size(); i++) { // System.err.println("Notifying instance listeners " // +"(ClassAssigner)"); ((DataFormatListener)l.elementAt(i)).newDataFormat(dse); } } } public synchronized void addInstanceListener(InstanceListener tsl) { m_instanceListeners.addElement(tsl); if (m_connectedFormat != null) { InstanceEvent e = new InstanceEvent(this, m_connectedFormat); tsl.acceptInstance(e); } } public synchronized void removeInstanceListener(InstanceListener tsl) { m_instanceListeners.removeElement(tsl); } public synchronized void addDataSourceListener(DataSourceListener tsl) { m_dataListeners.addElement(tsl); // pass on any format that we might know about if (m_connectedFormat != null) { DataSetEvent e = new DataSetEvent(this, m_connectedFormat); tsl.acceptDataSet(e); } } public synchronized void removeDataSourceListener(DataSourceListener tsl) { m_dataListeners.removeElement(tsl); } public synchronized void addTrainingSetListener(TrainingSetListener tsl) { m_trainingListeners.addElement(tsl); // pass on any format that we might know about if (m_connectedFormat != null) { TrainingSetEvent e = new TrainingSetEvent(this, m_connectedFormat); tsl.acceptTrainingSet(e); } } public synchronized void removeTrainingSetListener(TrainingSetListener tsl) { m_trainingListeners.removeElement(tsl); } public synchronized void addTestSetListener(TestSetListener tsl) { m_testListeners.addElement(tsl); // pass on any format that we might know about if (m_connectedFormat != null) { TestSetEvent e = new TestSetEvent(this, m_connectedFormat); tsl.acceptTestSet(e); } } public synchronized void removeTestSetListener(TestSetListener tsl) { m_testListeners.removeElement(tsl); } public synchronized void addDataFormatListener(DataFormatListener dfl) { m_dataFormatListeners.addElement(dfl); } public synchronized void removeDataFormatListener(DataFormatListener dfl) { m_dataFormatListeners.removeElement(dfl); } public void setVisual(BeanVisual newVisual) { m_visual = newVisual; } public BeanVisual getVisual() { return m_visual; } public void useDefaultVisual() { m_visual.loadIcons(BeanVisual.ICON_PATH+"ClassAssigner.gif", BeanVisual.ICON_PATH+"ClassAssigner_animated.gif"); } /** * Returns true if, at this time, * the object will accept a connection according to the supplied * event name * * @param eventName the event * @return true if the object will accept a connection */ public boolean connectionAllowed(String eventName) { if (eventName.compareTo("trainingSet") == 0 && (m_trainingProvider != null || m_dataProvider != null || m_instanceProvider != null)) { return false; } if (eventName.compareTo("testSet") == 0 && m_testProvider != null) { return false; } if (eventName.compareTo("instance") == 0 && m_instanceProvider != null || m_trainingProvider != null || m_dataProvider != null) { return false; } return true; } /** * Returns true if, at this time, * the object will accept a connection according to the supplied * EventSetDescriptor * * @param esd the EventSetDescriptor * @return true if the object will accept a connection */ public boolean connectionAllowed(EventSetDescriptor esd) { return connectionAllowed(esd.getName()); } /** * Notify this object that it has been registered as a listener with * a source with respect to the supplied event name * * @param eventName the event * @param source the source with which this object has been registered as * a listener */ public synchronized void connectionNotification(String eventName, Object source) { if (connectionAllowed(eventName)) { if (eventName.compareTo("trainingSet") == 0) { m_trainingProvider = source; } else if (eventName.compareTo("testSet") == 0) { m_testProvider = source; } else if (eventName.compareTo("dataSet") == 0) { m_dataProvider = source; } else if (eventName.compareTo("instance") == 0) { m_instanceProvider = source; } } } /** * Notify this object that it has been deregistered as a listener with * a source with respect to the supplied event name * * @param eventName the event * @param source the source with which this object has been registered as * a listener */ public synchronized void disconnectionNotification(String eventName, Object source) { if (eventName.compareTo("trainingSet") == 0) { if (m_trainingProvider == source) { m_trainingProvider = null; } } if (eventName.compareTo("testSet") == 0) { if (m_testProvider == source) { m_testProvider = null; } } if (eventName.compareTo("dataSet") == 0) { if (m_dataProvider == source) { m_dataProvider = null; } } if (eventName.compareTo("instance") == 0) { if (m_instanceProvider == source) { m_instanceProvider = null; } } } public void setLog(weka.gui.Logger logger) { m_logger = logger; } public void stop() { // Pass on to upstream beans if (m_trainingProvider != null && m_trainingProvider instanceof BeanCommon) { ((BeanCommon)m_trainingProvider).stop(); } if (m_testProvider != null && m_testProvider instanceof BeanCommon) { ((BeanCommon)m_testProvider).stop(); } if (m_dataProvider != null && m_dataProvider instanceof BeanCommon) { ((BeanCommon)m_dataProvider).stop(); } if (m_instanceProvider != null && m_instanceProvider instanceof BeanCommon) { ((BeanCommon)m_instanceProvider).stop(); } } /** * Returns true if. at this time, the bean is busy with some * (i.e. perhaps a worker thread is performing some calculation). * * @return true if the bean is busy. */ public boolean isBusy() { return false; } /** * Returns true, if at the current time, the named event could * be generated. Assumes that the supplied event name is * an event that could be generated by this bean * * @param eventName the name of the event in question * @return true if the named event could be generated at this point in * time */ public boolean eventGeneratable(String eventName) { if (eventName.compareTo("trainingSet") == 0) { if (m_trainingProvider == null) { return false; } else { if (m_trainingProvider instanceof EventConstraints) { if (!((EventConstraints)m_trainingProvider). eventGeneratable("trainingSet")) { return false; } } } } if (eventName.compareTo("dataSet") == 0) { if (m_dataProvider == null) { if (m_instanceProvider == null) { m_connectedFormat = null; notifyDataFormatListeners(); } return false; } else { if (m_dataProvider instanceof EventConstraints) { if (!((EventConstraints)m_dataProvider). eventGeneratable("dataSet")) { m_connectedFormat = null; notifyDataFormatListeners(); return false; } } } } if (eventName.compareTo("instance") == 0) { if (m_instanceProvider == null) { if (m_dataProvider == null) { m_connectedFormat = null; notifyDataFormatListeners(); } return false; } else { if (m_instanceProvider instanceof EventConstraints) { if (!((EventConstraints)m_instanceProvider). eventGeneratable("instance")) { m_connectedFormat = null; notifyDataFormatListeners(); return false; } } } } if (eventName.compareTo("testSet") == 0) { if (m_testProvider == null) { return false; } else { if (m_testProvider instanceof EventConstraints) { if (!((EventConstraints)m_testProvider). eventGeneratable("testSet")) { return false; } } } } return true; } }