All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.cmu.tetradapp.editor.RocPlot Maven / Gradle / Ivy

The newest version!
///////////////////////////////////////////////////////////////////////////////
// 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, 2022 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.util.NumberFormatUtil;
import org.apache.commons.math3.util.FastMath;

import javax.swing.*;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.NumberFormat;

/**
 * Plots a ROC plot.
 *
 * @author Frank Wimbely, Joseph Ramsey
 */
class RocPlot extends JPanel implements PropertyChangeListener {

    /**
     * The background color of this component.
     */
    private final Color backgroundColor = Color.WHITE;
    /**
     * Color the axes are drawn in for graphs.
     */
    private final Color boundaryColor = Color.DARK_GRAY;
    /**
     * Color the title is drawn in.
     */
    private final Color titleColor = Color.DARK_GRAY;
    /**
     * Color the plot is drawn in.
     */
    private final Color plotColor = Color.BLUE;
    /**
     * The font used for bold text.
     */
    private final Font fontBold = new Font("Serif", Font.BOLD, 12);
    /**
     * The font used for titles.
     */
    private final Font titleFont = new Font("Serif", Font.BOLD, 18);
    /**
     * The font metrics for the title font.
     */
    private final FontMetrics titleFm;
    /**
     * The font metrics of the non-bold font.
     */
    private final FontMetrics fm;
    /**
     * The data defining the ROC curve
     */
    private final double[][] points;
    /**
     * A String to be printed on the plot.
     */
    private final String info;
    /**
     * The stored size of this component.
     */
    private Dimension size;
    /**
     * The rectangle within which the graph is to be plotted.
     */
    private Rectangle plotRect;
    /**
     * The insets of the graph from the boundaries of this component.
     */
    private Insets graphInsets = new Insets(25, 25, 25, 25);
    /**
     * The title of this graph, which is drawn at the top of the graph.
     */
    private String title = "ROC Plot";

    /**
     * Constructs a power graph using the given model.  The argument points contains the coordinates of x and y for each
     * point.  I.e. points[i][0] is the x coordinate and points[i][1] is the y coordinate of the ith point.
     *
     * @param points an array of  objects
     * @param title  a {@link java.lang.String} object
     * @param info   a {@link java.lang.String} object
     */
    public RocPlot(double[][] points, String title, String info) {
        this.points = points;
        this.info = info;
        /*
      The font used non-bold text.
     */
        Font font = new Font("Serif", Font.PLAIN, 12);
        this.fm = getFontMetrics(font);
        this.titleFm = getFontMetrics(this.titleFont);
        setFont(font);

        if (title != null) {
            this.title = title;
        }
    }

    /**
     * Calculates the rectangle in which the graph is plotted.  Labels for the graph are drawn in the margin.
     *
     * @param size the size of this component with respect to which the plot rectangle is calculated.
     */
    private void calcPlotRect(Dimension size) {
        int left = this.graphInsets.left;
        int top = this.graphInsets.top;
        int width = size.width - this.graphInsets.left - this.graphInsets.right;
        int height = size.height - this.graphInsets.top - this.graphInsets.bottom;

        this.plotRect = new Rectangle(left, top, width, height);
    }

    /**
     * Draws the boundary of the plot rectangle.
     *
     * @param g the graphics context.
     */
    private void drawBoundary(Graphics g) {
        Rectangle r = getPlotRect();
        g.setColor(this.boundaryColor);
        g.drawRect(r.x, r.y, r.width, r.height);
    }

    /**
     * This method draws tick marks for the x axis.  The x axis represents pi_e, the true probability of effect in
     * treatment, and ranges in value from pi_c to 1.0.
     *
     * @param g the graphics context.
     */
    private void drawXTickMarks(Graphics g) {
        Rectangle plotRect = getPlotRect();
        int yPos = plotRect.y + plotRect.height;
        NumberFormat nf = NumberFormatUtil.getInstance().getNumberFormat();

        for (double d = 0.0; d <= 1.0; d += 0.1) {
            int xPos = getXPos(d);

            g.setColor(this.boundaryColor);
            g.drawLine(xPos, yPos, xPos, yPos - 10);
            g.drawString(nf.format(d), xPos - 3, yPos + 12);
        }
    }

    /**
     * Draws tick marks for the y axis.
     *
     * @param g the graphics context.
     */
    private void drawYTickMarks(Graphics g) {
        Rectangle plotRect = getPlotRect();
        int xPos = plotRect.x;
        NumberFormat nf = NumberFormat.getInstance();

        nf.setMinimumFractionDigits(1);
        nf.setMaximumFractionDigits(1);

        for (double d = 0.0; d <= 1.0; d += 0.1) {
            int yPos = getYPos(d);

            g.setColor(this.boundaryColor);
            g.drawLine(xPos, yPos, xPos + 10, yPos);

            String str = nf.format(d);
            int strWid = this.fm.stringWidth(str);
            int strHgt = this.fm.getAscent();

            g.drawString(str, xPos - strWid - 5, yPos + strHgt / 2);
        }
    }

    /**
     * Draws the title of the graph.
     *
     * @param g the graphics context.
     */
    private void drawTitle(Graphics g) {
        int stringWidth = this.titleFm.stringWidth(this.title);
        int stringHeight = this.titleFm.getHeight();

        g.setFont(this.titleFont);
        g.setColor(this.titleColor);
        g.drawString(this.title, this.plotRect.x + this.plotRect.width / 2 - stringWidth / 2,
                stringHeight);
    }

    /**
     * @return the stored plot rectangle.
     */
    private Rectangle getPlotRect() {
        return this.plotRect;
    }

    /**
     * 

getPreferredSize.

* * @return the preferred size of this component. */ public Dimension getPreferredSize() { return new Dimension(600, 600); } /** * @param x the value of x (between pi_c and 1.0). * @return a pixel x position which is the proportion x / (range from pi_e to 1.0) from the left side of the unit * square to the right. */ private int getXPos(double x) { Rectangle r = getPlotRect(); final double range = 1.0; return r.x + (int) ((x / range) * (double) this.plotRect.width); } /** * @param y a value between 0.0 and 1.0, inclusive. * @return a pixel y position which is the proportion x / 1.0 from the bottom of the unit square to the top. */ private int getYPos(double y) { Rectangle r = getPlotRect(); return r.y + r.height - (int) (y * (double) r.height); } /** * {@inheritDoc} *

* Paints the "power" graph for each of the requested measures. Measures are requested by selecting the appropriate * checkboxes in the control panel. */ public void paint(Graphics g) { Dimension size = getSize(); if ((this.size == null) || !this.size.equals(size)) { this.size = size; calcGraphInsets(); calcPlotRect(size); } g.setColor(this.backgroundColor); g.fillRect(0, 0, getWidth(), getHeight()); drawBoundary(g); drawXTickMarks(g); drawYTickMarks(g); drawTitle(g); drawXLabel(g); drawYLabel(g); g.setColor(this.plotColor); // Plot point or lines however you want. For lines, call this repeatedly // for relevant points. for (double[] point : this.points) { int x = getXPos(point[0]); int y = getYPos(point[1]); //Draw an "x" at the point on the curve. g.drawLine(x - 2, y + 2, x + 2, y - 2); g.drawLine(x - 2, y - 2, x + 2, y + 2); //g.fillRect(getXPos(points[i][0]), getYPos(points[i][1]), 1, 1); } g.setColor(this.boundaryColor); // g.drawString(info, size.width / 2, size.height / 2); g.drawString(this.info, getXPos(0.6), getYPos(0.2)); } private void drawXLabel(Graphics g) { g.setFont(this.fontBold); Rectangle plotRect = getPlotRect(); /* The x axis label. */ final String xLabel = "False Positive Fraction"; int stringWidth = this.fm.stringWidth(xLabel); // where to begin drawing (the rotated image) Point translate = new Point( plotRect.x + plotRect.width / 2 - stringWidth / 2, getSize().height - 8); g.setColor(this.boundaryColor); g.drawString(xLabel, translate.x, translate.y); } private void drawYLabel(Graphics g) { g.setFont(this.fontBold); // # radians to rotate. final double theta = -FastMath.PI / 2; Rectangle plotRect = getPlotRect(); /* The y axis laabel. */ final String yLabel = "True Positive Fraction"; int stringWidth = this.fm.stringWidth(yLabel); // where to begin drawing (the rotated image) Point translate = new Point(this.fm.getAscent(), plotRect.y + (plotRect.height / 2 + stringWidth / 2)); Graphics2D g2 = (Graphics2D) g; AffineTransform save = g2.getTransform(); g2.translate(translate.x, translate.y); g2.rotate(theta); g2.setColor(this.boundaryColor); g2.drawString(yLabel, 0, 0); g2.setTransform(save); } private void calcGraphInsets() { int top = this.titleFm.getHeight() + this.titleFm.getDescent() + 10; int left = (int) (2.5 * this.fm.getHeight()); int bottom = 2 * this.fm.getHeight(); int right = (int) (2.5 * this.fm.getHeight()); this.graphInsets = new Insets(top, left, bottom, right); } /** * {@inheritDoc} *

* Reacts to any property change event by repainting the graph. */ public void propertyChange(PropertyChangeEvent e) { repaint(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy