//--------------------------------------------------------------------------------//
// COPYRIGHT NOTICE //
//--------------------------------------------------------------------------------//
// Copyright (c) 2012, Instituto de Microelectronica de Sevilla (IMSE-CNM) //
// //
// All rights reserved. //
// //
// Redistribution and use in source and binary forms, with or without //
// modification, are permitted provided that the following conditions are met: //
// //
// * Redistributions of source code must retain the above copyright notice, //
// this list of conditions and the following disclaimer. //
// //
// * Redistributions in binary form must reproduce the above copyright //
// notice, this list of conditions and the following disclaimer in the //
// documentation and/or other materials provided with the distribution. //
// //
// * Neither the name of the IMSE-CNM nor the names of its contributors may //
// be used to endorse or promote products derived from this software //
// without specific prior written permission. //
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" //
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE //
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE //
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE //
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL //
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR //
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER //
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, //
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE //
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //
//--------------------------------------------------------------------------------//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// PANEL DE REPRESENTACION DE LA EVOLUCION DEL APRENDIZAJE //
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
package xfuzzy.xfsl;
import xfuzzy.util.*;
import javax.swing.*;
import java.awt.*;
public class XfslGraphPanel extends JPanel {
/**
* C�digo asociado a la clase serializable
*/
private static final long serialVersionUID = 95505666603068L;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// CONSTANTES PRIVADAS //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
private final static int HEIGHT = 300;
private final static double log10 = Math.log(10.0);
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// MIEMBROS PRIVADOS //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
private Graphics2D gc, gd;
private Graphics2D gtrn_error, gtrn_rmse, gtrn_mxae;
private Graphics2D gtst_error, gtst_rmse, gtst_mxae;
private Dimension size;
private int x0, y0, x1, y1;
private int yresc = 3;
private int xresc = 0;
private int xscale = 20;
private int pos = 0;
private XfslStatus[] hist = new XfslStatus[130];
private Xfsl xfsl;
private boolean classif;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// CONSTRUCTOR //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
public XfslGraphPanel(Xfsl xfsl) {
super();
this.xfsl = xfsl;
Dimension prefsize = new Dimension(getPreferredSize().width,HEIGHT);
setPreferredSize(prefsize);
setBackground(XConstants.textbackground);
setBorder(BorderFactory.createLoweredBevelBorder());
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// METODOS PUBLICOS //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
//-------------------------------------------------------------//
// Limpiar la representacion //
//-------------------------------------------------------------//
public void reset() {
yresc = 3;
xresc = 0;
xscale = 20;
pos = 0;
repaint();
}
//-------------------------------------------------------------//
// Annadir un dato a la representacion //
//-------------------------------------------------------------//
public void addStatus(XfslStatus status) {
int step = xscale/20;
if( (status.epoch%step) != 0) return;
paintStatus(status);
hist[pos] = status;
pos++;
}
//-------------------------------------------------------------//
// Pintar el panel //
//-------------------------------------------------------------//
public void paint(Graphics g) {
super.paint(g);
setVars(g);
paintLeyend();
paintAxis();
paintHist();
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// METODOS PRIVADOS //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
//-------------------------------------------------------------//
// Calcula las variables internas //
//-------------------------------------------------------------//
private void setVars(Graphics g){
this.gc = (Graphics2D) g;
this.gtrn_error = (Graphics2D) g.create(); gtrn_error.setColor(Color.blue);
this.gtrn_rmse = (Graphics2D) g.create(); gtrn_rmse.setColor(Color.red);
this.gtrn_mxae = (Graphics2D) g.create(); gtrn_mxae.setColor(Color.green);
float dash[] = {4.0f,4.0f};
this.gd = (Graphics2D) g.create();
this.gd.setStroke(new BasicStroke(1.0f,2,0,10.0f,dash,0.0f));
this.gtst_error=(Graphics2D) gd.create(); gtst_error.setColor(Color.blue);
this.gtst_rmse =(Graphics2D) gd.create(); gtst_rmse.setColor(Color.red);
this.gtst_mxae =(Graphics2D) gd.create(); gtst_mxae.setColor(Color.green);
this.size = getSize();
this.x0 = 170;
this.y0 = size.height - 50;
this.x1 = size.width - 110;
this.y1 = 30;
}
//-------------------------------------------------------------//
// Dibuja la leyenda de la representacion grafica //
//-------------------------------------------------------------//
private void paintLeyend() {
this.classif = xfsl.getConfig().errorfunction.isClassification();
if(!classif) {
gc.drawString("Training", 15, 40);
gc.drawString("Error", 20, 60);
gc.drawString("RMSE", 20, 80);
gc.drawString("MxAE", 20, 100);
gc.drawString("Test", 15, 140);
gc.drawString("Error", 20, 160);
gc.drawString("RMSE", 20, 180);
gc.drawString("MxAE", 20, 200);
gtrn_error.drawLine(60, 55, 100, 55);
gtrn_rmse.drawLine(60, 75, 100, 75);
gtrn_mxae.drawLine(60, 95, 100, 95);
gtst_error.drawLine(60,155, 100,155);
gtst_rmse.drawLine(60,175, 100,175);
gtst_mxae.drawLine(60,195, 100,195);
} else {
gc.drawString("Training", 15, 40);
gc.drawString("Error", 20, 60);
gc.drawString("Missc.", 20, 80);
gc.drawString("Test", 15, 140);
gc.drawString("Error", 20, 160);
gc.drawString("Missc.", 20, 180);
gtrn_error.drawLine(60, 55, 100, 55);
gtrn_rmse.drawLine(60, 75, 100, 75);
gtst_error.drawLine(60,155, 100,155);
gtst_rmse.drawLine(60,175, 100,175);
}
}
//-------------------------------------------------------------//
// Dibuja los ejes de la representacion grafica //
//-------------------------------------------------------------//
private void paintAxis() {
gc.drawString("Iteration", size.width-90, size.height-20);
gc.drawLine(x0, y1, x0, y0+1);
gc.drawLine(x0, y0+1, x1, y0+1);
gc.drawLine(x1, y1, x1, y0+1);
FontMetrics fm = getFontMetrics(getFont());
for(int i=0 ; i<yresc ; i++) {
int ypos = y1 + (y0-y1)*i/yresc;
String label = "1.0"+(i==0?"":"E-"+i);
int xpos = fm.stringWidth(label)+10;
gc.drawLine(x0-4, ypos, x0, ypos);
gc.drawString(label, x0-xpos, ypos+5);
gd.drawLine(x0, ypos, x1, ypos);
}
for(int i=0 ; i<=5 ; i++) {
int iter = i*xscale;
int xpos = x0 + (x1-x0)*i/5;
int spos = fm.stringWidth(""+iter)/2;
gc.drawLine(xpos, y0+5, xpos, y0+1);
gc.drawString(""+iter,xpos-spos, y0+21);
}
}
//-------------------------------------------------------------//
// Dibuja la evolucion historica //
//-------------------------------------------------------------//
private void paintHist() {
XfslGraphPoint p0, p1;
if(pos == 0) return;
p0 = createGraphPoint(hist[0]);
for(int i=1; i<pos; i++) {
p1 = createGraphPoint(hist[i]);
paintPoints(p0,p1);
p0 = p1;
}
}
//-------------------------------------------------------------//
// Dibuja un nuevo punto en la evolucion //
//-------------------------------------------------------------//
private void paintStatus(XfslStatus status) {
if(pos == 0) return;
setVars(getGraphics());
XfslGraphPoint p0 = createGraphPoint(hist[pos-1]);
XfslGraphPoint p1 = createGraphPoint(status);
if(verticalOutOfBounds(p0) || verticalOutOfBounds(p1) ) {
yresc++;
repaint();
}
else if(horizontalOutOfBounds(p1)) {
rescale();
repaint();
}
else paintPoints(p0,p1);
}
//-------------------------------------------------------------//
// Dibuja un segmento en la evolucion //
//-------------------------------------------------------------//
private void paintPoints(XfslGraphPoint p0, XfslGraphPoint p1) {
if(p0.testing && p1.testing) {
if(!classif) gtst_mxae.drawLine(p0.x, p0.ysm, p1.x, p1.ysm );
gtst_rmse.drawLine(p0.x, p0.ysr, p1.x, p1.ysr );
gtst_error.drawLine(p0.x,p0.yse, p1.x, p1.yse );
}
if(!classif) gtrn_mxae.drawLine(p0.x, p0.yrm, p1.x, p1.yrm );
gtrn_rmse.drawLine(p0.x, p0.yrr, p1.x, p1.yrr );
gtrn_error.drawLine(p0.x,p0.yre, p1.x, p1.yre );
}
//-------------------------------------------------------------//
// Aumenta en un grado la escala temporal //
//-------------------------------------------------------------//
private void rescale() {
for(int i=0; 2*i<pos && 2*i<hist.length; i++) hist[i] = hist[2*i];
pos = pos/2;
xresc++;
xscale=20;
for(int i=0; i<xresc ; i++) if(i%3 != 0) xscale*=2; else xscale=xscale*5/2;
}
//-------------------------------------------------------------//
// Construye un punto de la evolucion del aprendizaje //
//-------------------------------------------------------------//
private XfslGraphPoint createGraphPoint(XfslStatus status) {
XfslGraphPoint p = new XfslGraphPoint();
p.x = (int) (x0 + (x1-x0)*status.epoch/(5*xscale) );
p.yre = ypos(status.trn.error);
p.yrr = ypos(status.trn.rmse);
p.yrm = ypos(status.trn.mxae);
p.testing = status.testing;
if(p.testing) {
p.yse = ypos(status.tst.error);
p.ysr = ypos(status.tst.rmse);
p.ysm = ypos(status.tst.mxae);
}
return p;
}
//-------------------------------------------------------------//
// Calcula la posicion de un valor sobre la coordenada Y //
//-------------------------------------------------------------//
private int ypos(double value) {
if(value <= 1e-10) return y0;
return (int) (y1 - (y0 - y1)*Math.log(value)/(yresc * log10) );
}
//-------------------------------------------------------------//
// Detecta si un punto se sale de los limites de la grafica //
//-------------------------------------------------------------//
private boolean verticalOutOfBounds(XfslGraphPoint p) {
if(p.yre>y0 || p.yrr>y0 || p.yrm>y0) return true;
if(p.testing && (p.yse>y0 || p.ysr>y0 || p.ysm>y0)) return true;
return false;
}
//-------------------------------------------------------------//
// Detecta si un punto se sale de los limites de la grafica //
//-------------------------------------------------------------//
private boolean horizontalOutOfBounds(XfslGraphPoint p) {
return (p.x>x1);
}
}