⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 visualtreenode.java

📁 一个决策树的Applet(转载
💻 JAVA
字号:
package ai.decision.gui;

import java.awt.*;
import java.awt.event.*;
import ai.decision.algorithm.*;

/**
 * The VisualTreeNode class provides a graphical representation
 * of a decision tree node.  Each VisualTreeNode consists of:
 *
 * <p>
 * <ul>
 *     <li>a rectangular box that contains the text label
 *         for the node.
 *     <li>labelled descending arcs if the node is not a
 *         leaf node.
 * </ul>
 *
 * <p>
 * <b>Change History:</b>
 *
 * <p><pre>
 * Name:            Date:            Change:
 * =============================================================
 * J. Kelly         Jun-18-2000      Created.
 * J. Kelly         Jul-12-2000      Converted nodes to use
 *                                   HSV color space for shading.
 * J. Kelly         Nov-14-2000      Converted nodes to use
 *                                   the ColorScheme class for
 *                                   shading.
 * </pre>
 *
 * Copyright 2000 University of Alberta.
 *
 * <!--
 * This file is part of the Decision Tree Applet.
 *
 * The Decision Tree Applet 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.
 *
 * Foobar 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 the Decision Tree Applet; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * -->
 */
public class VisualTreeNode
  extends AbstractTreeNode
{
  // Class data members

  private static final int TRAINING = 0;

  private static final int TESTING  = 1;

  private static int c_trainOrTest;  // Flag. Signals display of
                                     // training or testing stats.

  //-------------------------------------------------------

  DecisionTreeNode m_node;   // Underlying tree node.
  Color   m_trainingColor;   // Color for this node (training).
  Color   m_testingColor;    // Color for this node (testing).
  Font    m_font;            // Font used to draw labels.

  // Constructors

  /**
   * Builds a visual representation of a decision tree
   * node.
   *
   * @param visParent The visual parent node for this
   *        node.  If this value is null, this node
   *        is the root of the decision tree.
   *
   * @param arcNum The arc along which to 'attach'
   *        this node.  This visual node will be centered
   *        at the end of the given parent arc.
   *
   * @param node The decision tree node that this visual
   *        node will represent.
   *
   * @param font The font used to to render the label
   *        for this node.
   *
   * @param g The graphics context that will be used
   *        to render the node.
   */
  public VisualTreeNode( VisualTreeNode visParent,
    int arcNum, DecisionTreeNode node, Font font, Graphics g )
  {
    super( visParent, arcNum );

    if( node == null || g == null )
      throw new NullPointerException( "Node or graphics context is null." );

    m_node = node;

    if( font != null ) {
      m_font = font;
      g.setFont( font );
    }
    else
      m_font = g.getFont();

    // Compute the size of the rectangle required
    // to display this node's label text.
    m_width  = g.getFontMetrics().stringWidth(m_node.getLabel()) + 10;
    m_height = g.getFontMetrics().getHeight() + 4;

    // Attach this node to the parent (if there is
    // a parent).  The node can also figure out who its siblings are.
    if( m_parent != null ) {
      visParent.setChild( arcNum, this );

      if( arcNum != 0 ) {
        // Must have a left sibling.
        m_leftSibling = visParent.getChild( arcNum - 1 );
        m_leftSibling.setRightSibling( this );
      }

      if( arcNum != visParent.getMaxNumChildren() - 1 ) {
        // Must have right sibling.
        m_rightSibling = visParent.getChild( arcNum + 1 );
        m_rightSibling.setLeftSibling( this );
      }
    }

    // Compute the color(s) of this node.
    if( m_node.getTrainingEgsAtNode() == 0 )
      m_trainingColor = ColorScheme.getColor( -1.0 );
    else
      m_trainingColor =
        ColorScheme.getColor(
          ((double)m_node.getTrainingEgsCorrectClassUsingBestTrainingIndex())/
          m_node.getTrainingEgsAtNode() );

    if( m_node.getTestingEgsAtNode() == 0 )
      m_testingColor = ColorScheme.getColor( -1.0 );
    else
      m_testingColor  =
        ColorScheme.getColor(
          ((double)m_node.getTestingEgsCorrectClassUsingBestTrainingIndex())/
          m_node.getTestingEgsAtNode() );

    // If this node isn't a leaf, we build a series of
    // 'vacant' children to indicate that positions are available.
    if( !m_node.isLeaf() ) {
      // This is an internal node, so build
      // a series of 'vacant' children for the node.
      int numArcs = m_node.getArcLabelCount();
      m_children  = new AbstractTreeNode[ numArcs ];

      for( int i = 0; i < numArcs; i++ )
        m_children[i] = new VacantTreeNode( this, i );

      // One pass through the children, setting siblings.
      m_children[0].setLeftSibling( null );
      m_children[0].setRightSibling( m_children[1] );

      for( int i = 1; i < numArcs - 1; i++ ) {
        m_children[i].setLeftSibling(  m_children[i - 1] );
        m_children[i].setRightSibling( m_children[i + 1] );
      }

      m_children[numArcs - 1].setLeftSibling( m_children[numArcs - 2] );
      m_children[numArcs - 1].setRightSibling( null );
    }
  }

  // Public methods

  public boolean isLeaf()
  {
    return m_children == null;
  }

  /**
   * Returns a reference to the internal decision tree
   * node that this visual node represents.
   *
   * @return The decision tree node that this visual
   *         node represents.
   */
  public DecisionTreeNode getDecisionTreeNode()
  {
    return m_node;
  }

  /**
   * Searches through the current node's list of children
   * and attempts to locate a child that matches the
   * supplied child.  If a match is found, the reference
   * to the child is removed, leaving a vacant arc.
   *
   * @param child The child to remove.
   */
  public void removeChild( VisualTreeNode child )
  {
    if( this.isLeaf() ) return;

    // Search through the list of children, looking for a match.
    for( int i = 0; i < m_children.length; i++ ) {
      if( m_children[i] == child ) {
        m_children[i] = new VacantTreeNode( this, i );

        if( i > 0 ) {
          m_children[i].setLeftSibling( m_children[i-1] );
          m_children[i-1].setRightSibling( m_children[i] );
        }

        if( i < m_children.length - 1 ) {
          m_children[i].setRightSibling( m_children[i+1] );
          m_children[i+1].setLeftSibling( m_children[i] );
        }

        return;
      }
    }
  }

  public AbstractTreeNode withinBoundingBox( int x, int y )
  {
    // Perform the same computation that's done
    // when we draw the node.
    int ulcX   = m_xCoord - m_width/2;
    int ulcY   = m_yCoord;
    int width  = m_width;
    int height = m_height;

    // Apply scaling if required.
    if( VisualTreePanel.SCALING_FACTOR != 1.0 ) {
      ulcX   = (int)Math.round( ulcX * VisualTreePanel.SCALING_FACTOR );
      ulcY   = (int)Math.round( ulcY * VisualTreePanel.SCALING_FACTOR );
      width  = (int)Math.round( width * VisualTreePanel.SCALING_FACTOR );
      height = (int)Math.round( height * VisualTreePanel.SCALING_FACTOR );
    }

    // The border does not resize, so add border offset.
    ulcX += VisualTreePanel.ROOT_OFFSET;
    ulcY += VisualTreePanel.BORDER_SIZE;

    // Check for a hit.
    if( x >= ulcX && x <= ulcX + width  - 1 &&
        y >= ulcY && y <= ulcY + height - 1 )
      return this;

    // No hit on the parent - maybe on one of the children?
    if( !isLeaf() ) {
      for( int i = 0; i < m_children.length; i++ ) {
        if( m_children[i] instanceof VacantTreeNode &&
            m_children[i].withinBoundingBox( x, y ) != null )
          return m_children[i];
      }
    }

    return null;
  }

  /**
   * Paints the node and any associated edges/arcs.
   *
   * @param g The graphics context on which to paint.
   */
  public void paintNode( Graphics g )
  {
    int ulcX   = m_xCoord - m_width/2;
    int ulcY   = m_yCoord;
    int width  = m_width;
    int height = m_height;
    int ovalHorizontalPadding = 16;
    int ovalVerticalPadding   = 16;

    // Apply scaling if required.
    if( VisualTreePanel.SCALING_FACTOR != 1.0 ) {
      ulcX   = (int)Math.round( ulcX * VisualTreePanel.SCALING_FACTOR );
      ulcY   = (int)Math.round( ulcY * VisualTreePanel.SCALING_FACTOR );
      width  = (int)Math.round( width * VisualTreePanel.SCALING_FACTOR );
      height = (int)Math.round( height * VisualTreePanel.SCALING_FACTOR );
      ovalHorizontalPadding = (int)Math.round(
        ovalHorizontalPadding * VisualTreePanel.SCALING_FACTOR );
      ovalVerticalPadding = (int)Math.round(
        ovalVerticalPadding * VisualTreePanel.SCALING_FACTOR );
    }

    // The border does not resize, so add border offset.
    ulcX += VisualTreePanel.ROOT_OFFSET;
    ulcY += VisualTreePanel.BORDER_SIZE;

    g.setFont( m_font );

    // Paint the highlight ellipse, if necessary.
    if( m_node.getFlag() == -1 ) {
      g.setColor( Color.red );
      g.drawOval( ulcX - ovalHorizontalPadding/2,
                  ulcY - ovalVerticalPadding/2,
                  width + ovalHorizontalPadding,
                  height + ovalVerticalPadding );
    }

    // Paint the node rectangle.
    if( c_trainOrTest == TRAINING )
      g.setColor( m_trainingColor );
    else
      g.setColor( m_testingColor );

    g.fillRect( ulcX, ulcY, width, height );
    g.setColor(Color.black);
    g.drawRect( ulcX, ulcY, width - 1, height - 1);

    // Paint the label text - unless the scaling factor
    // is less than 1.0.
    if( VisualTreePanel.SCALING_FACTOR == 1.0 )
    g.drawString( m_node.getLabel(),
                  ulcX + 5, ulcY + 2 + g.getFontMetrics().getAscent() );

    // Paint the arcs to subtrees, and any vacant subtree nodes.
    if( m_children != null ) {
      for( int i = 0; i < m_children.length; i++ ) {
        // Paint arc - in red if appropriate.
        if( m_node.getFlag() == i )
          VisualTreeArc.paintArc( this, m_children[i], i, g, Color.red );
        else
          VisualTreeArc.paintArc( this, m_children[i], i, g, Color.black );

        if( m_children[i] instanceof VacantTreeNode )
          m_children[i].paintNode( g );
      }
    }
  }

  // Static methods

  /**
   * Informs all nodes that they should be
   * colored based on training set performance.
   */
  public static void showTrainingPerformance()
  {
    c_trainOrTest = TRAINING;
  }

  /**
   * Informs all nodes that they should
   * be colored based on testing set performance.
   */
  public static void showTestingPerformance()
  {
    c_trainOrTest = TESTING;
  }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -