/*
* Copyright 2013 Serdar.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.fub.maps.project.detector.model.inference.ui;
import de.fub.maps.project.detector.model.inference.EvaluationDetailPanel;
import de.fub.maps.project.detector.model.inference.processhandler.InferenceModelProcessHandler;
import de.fub.maps.project.detector.model.inference.ui.charts.PrecisionRecallBarChartPanel;
import de.fub.utilsmodule.components.CustomOutlineView;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import java.util.List;
import javax.swing.JLabel;
import org.jfree.data.category.DefaultCategoryDataset;
import org.netbeans.swing.outline.Outline;
import org.openide.DialogDescriptor;
import org.openide.DialogDisplayer;
import org.openide.explorer.ExplorerManager;
import org.openide.explorer.view.OutlineView;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.PropertySupport;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import weka.classifiers.Evaluation;
import weka.core.Instances;
/**
*
* @author Serdar
*/
@NbBundle.Messages({
"CLT_TransportMode_Label_Text=Transport Mode"
})
public class EvaluationPanel extends javax.swing.JPanel implements ExplorerManager.Provider {
private static final String NUMBER_PATTERN = "{0, number, 000.00} %";
private static final long serialVersionUID = 1L;
private transient final ExplorerManager explorerManager = new ExplorerManager();
private transient Evaluation evaluation;
private transient InferenceModelProcessHandler processHandler;
/**
* Creates new form EvaluationPanel
*/
public EvaluationPanel() {
initComponents();
outlineView.getActionMap().clear();
Outline outline = outlineView.getOutline();
outline.getActionMap().clear();
outline.setRootVisible(false);
}
public EvaluationPanel(InferenceModelProcessHandler processHandler) {
this();
this.processHandler = processHandler;
}
public PrecisionRecallBarChartPanel getBarChartPanel() {
return barChartPanel;
}
public OutlineView getOutlineView() {
return outlineView;
}
public JLabel getTitle() {
return title;
}
public JLabel getCorrectClassifiedInstances() {
return correctClassifiedInstances;
}
public JLabel getIncorrectClassifiedInstances() {
return incorrectClassifiedInstances;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jPanel2 = new javax.swing.JPanel();
jPanel6 = new javax.swing.JPanel();
barChartPanel = new de.fub.maps.project.detector.model.inference.ui.charts.PrecisionRecallBarChartPanel();
outlineView = new CustomOutlineView(NbBundle.getMessage(EvaluationPanel.class, "CLT_Doman_Axis_Name"));
jPanel3 = new javax.swing.JPanel();
title = new javax.swing.JLabel();
jPanel1 = new javax.swing.JPanel();
jPanel4 = new javax.swing.JPanel();
jLabel1 = new javax.swing.JLabel();
correctClassifiedInstances = new javax.swing.JLabel();
jLabel2 = new javax.swing.JLabel();
incorrectClassifiedInstances = new javax.swing.JLabel();
jPanel5 = new javax.swing.JPanel();
toolBar = new javax.swing.JToolBar();
filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0));
infoButton = new javax.swing.JButton();
jSeparator1 = new javax.swing.JSeparator();
jSeparator2 = new javax.swing.JSeparator();
setBackground(new java.awt.Color(255, 255, 255));
setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(102, 102, 102), 2));
setMaximumSize(new java.awt.Dimension(2147483647, 350));
setMinimumSize(new java.awt.Dimension(0, 300));
setPreferredSize(new java.awt.Dimension(0, 300));
setLayout(new java.awt.BorderLayout(0, 8));
jPanel2.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 4, 8, 4));
jPanel2.setMinimumSize(new java.awt.Dimension(0, 32));
jPanel2.setOpaque(false);
jPanel2.setPreferredSize(new java.awt.Dimension(0, 429));
jPanel6.setMinimumSize(new java.awt.Dimension(0, 10));
jPanel6.setPreferredSize(new java.awt.Dimension(0, 420));
jPanel6.setLayout(new java.awt.BorderLayout());
barChartPanel.setPreferredSize(new java.awt.Dimension(0, 420));
jPanel6.add(barChartPanel, java.awt.BorderLayout.CENTER);
outlineView.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(213, 213, 213)));
outlineView.setPropertyColumns(new String[] {"precision", "Precision", "recall", "Recall"});
outlineView.setWheelScrollingEnabled(false);
javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
jPanel2.setLayout(jPanel2Layout);
jPanel2Layout.setHorizontalGroup(
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel2Layout.createSequentialGroup()
.addComponent(jPanel6, javax.swing.GroupLayout.DEFAULT_SIZE, 657, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(outlineView, javax.swing.GroupLayout.PREFERRED_SIZE, 281, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
jPanel2Layout.setVerticalGroup(
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel6, javax.swing.GroupLayout.PREFERRED_SIZE, 210, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(outlineView, javax.swing.GroupLayout.PREFERRED_SIZE, 210, javax.swing.GroupLayout.PREFERRED_SIZE)
);
add(jPanel2, java.awt.BorderLayout.CENTER);
jPanel3.setBackground(new java.awt.Color(255, 216, 178));
jPanel3.setBorder(javax.swing.BorderFactory.createMatteBorder(0, 0, 2, 0, new java.awt.Color(204, 204, 204)));
jPanel3.setMinimumSize(new java.awt.Dimension(0, 32));
jPanel3.setPreferredSize(new java.awt.Dimension(0, 32));
jPanel3.setLayout(new java.awt.BorderLayout());
title.setFont(new java.awt.Font("Tahoma", 1, 24)); // NOI18N
title.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
org.openide.awt.Mnemonics.setLocalizedText(title, org.openide.util.NbBundle.getMessage(EvaluationPanel.class, "EvaluationPanel.title.text")); // NOI18N
title.setPreferredSize(new java.awt.Dimension(0, 29));
jPanel3.add(title, java.awt.BorderLayout.CENTER);
add(jPanel3, java.awt.BorderLayout.NORTH);
jPanel1.setBackground(new java.awt.Color(204, 204, 204));
jPanel1.setBorder(javax.swing.BorderFactory.createMatteBorder(2, 0, 0, 0, new java.awt.Color(204, 204, 204)));
jPanel1.setMaximumSize(new java.awt.Dimension(32767, 32));
jPanel1.setMinimumSize(new java.awt.Dimension(10, 32));
jPanel1.setPreferredSize(new java.awt.Dimension(10, 32));
jPanel1.setLayout(new java.awt.BorderLayout());
jPanel4.setBackground(new java.awt.Color(255, 216, 178));
jPanel4.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 8, 1, 8));
jPanel4.setPreferredSize(new java.awt.Dimension(0, 41));
jLabel1.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(EvaluationPanel.class, "EvaluationPanel.jLabel1.text")); // NOI18N
correctClassifiedInstances.setFont(new java.awt.Font("Monospaced", 0, 11)); // NOI18N
correctClassifiedInstances.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
org.openide.awt.Mnemonics.setLocalizedText(correctClassifiedInstances, org.openide.util.NbBundle.getMessage(EvaluationPanel.class, "EvaluationPanel.correctClassifiedInstances.text")); // NOI18N
correctClassifiedInstances.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 8));
jLabel2.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(EvaluationPanel.class, "EvaluationPanel.jLabel2.text")); // NOI18N
incorrectClassifiedInstances.setFont(new java.awt.Font("Monospaced", 0, 11)); // NOI18N
incorrectClassifiedInstances.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
org.openide.awt.Mnemonics.setLocalizedText(incorrectClassifiedInstances, org.openide.util.NbBundle.getMessage(EvaluationPanel.class, "EvaluationPanel.incorrectClassifiedInstances.text")); // NOI18N
incorrectClassifiedInstances.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 8));
jPanel5.setOpaque(false);
jPanel5.setLayout(new java.awt.BorderLayout());
toolBar.setFloatable(false);
toolBar.setRollover(true);
toolBar.setOpaque(false);
toolBar.add(filler1);
org.openide.awt.Mnemonics.setLocalizedText(infoButton, org.openide.util.NbBundle.getMessage(EvaluationPanel.class, "EvaluationPanel.infoButton.text")); // NOI18N
infoButton.setFocusable(false);
infoButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
infoButton.setMaximumSize(new java.awt.Dimension(24, 30));
infoButton.setOpaque(false);
infoButton.setPreferredSize(new java.awt.Dimension(32, 21));
infoButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
infoButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
infoButtonActionPerformed(evt);
}
});
toolBar.add(infoButton);
jPanel5.add(toolBar, java.awt.BorderLayout.CENTER);
jSeparator1.setOrientation(javax.swing.SwingConstants.VERTICAL);
jSeparator2.setOrientation(javax.swing.SwingConstants.VERTICAL);
javax.swing.GroupLayout jPanel4Layout = new javax.swing.GroupLayout(jPanel4);
jPanel4.setLayout(jPanel4Layout);
jPanel4Layout.setHorizontalGroup(
jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel4Layout.createSequentialGroup()
.addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 162, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(correctClassifiedInstances)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel2)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(incorrectClassifiedInstances)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jPanel5, javax.swing.GroupLayout.DEFAULT_SIZE, 449, Short.MAX_VALUE))
);
jPanel4Layout.setVerticalGroup(
jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel4Layout.createSequentialGroup()
.addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(correctClassifiedInstances, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(incorrectClassifiedInstances, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jPanel5, javax.swing.GroupLayout.PREFERRED_SIZE, 28, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jSeparator1)
.addComponent(jSeparator2))
.addContainerGap())
);
jPanel1.add(jPanel4, java.awt.BorderLayout.CENTER);
add(jPanel1, java.awt.BorderLayout.SOUTH);
}// </editor-fold>//GEN-END:initComponents
private void infoButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_infoButtonActionPerformed
if (evaluation != null) {
DialogDescriptor descriptor = new DialogDescriptor(new EvaluationDetailPanel(evaluation), "Detail Evaluation Statistics"); //NO18N
DialogDisplayer.getDefault().createDialog(descriptor).setVisible(true);
}
}//GEN-LAST:event_infoButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private de.fub.maps.project.detector.model.inference.ui.charts.PrecisionRecallBarChartPanel barChartPanel;
private javax.swing.JLabel correctClassifiedInstances;
private javax.swing.Box.Filler filler1;
private javax.swing.JLabel incorrectClassifiedInstances;
private javax.swing.JButton infoButton;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JPanel jPanel3;
private javax.swing.JPanel jPanel4;
private javax.swing.JPanel jPanel5;
private javax.swing.JPanel jPanel6;
private javax.swing.JSeparator jSeparator1;
private javax.swing.JSeparator jSeparator2;
private org.openide.explorer.view.OutlineView outlineView;
private javax.swing.JLabel title;
private javax.swing.JToolBar toolBar;
// End of variables declaration//GEN-END:variables
@Override
public ExplorerManager getExplorerManager() {
return explorerManager;
}
public void updatePanel(Evaluation evaluation) {
DefaultCategoryDataset dataset = getBarChartPanel().getDataset();
dataset.clear();
this.evaluation = evaluation;
double correct = evaluation.pctCorrect();
double incorrect = evaluation.pctIncorrect();
getCorrectClassifiedInstances().setText(MessageFormat.format(NUMBER_PATTERN, correct));
getIncorrectClassifiedInstances().setText(MessageFormat.format(NUMBER_PATTERN, incorrect));
int numClasses = evaluation.getHeader().numClasses();
for (int classIndex = 0; classIndex < numClasses; classIndex++) {
double precision = evaluation.precision(classIndex) * 100;
double recall = evaluation.recall(classIndex) * 100;
dataset.addValue(precision, NbBundle.getMessage(EvaluationPanel.class, "EvaluationPanel.CLT_Precision_Text"), evaluation.getHeader().classAttribute().value(classIndex));
dataset.addValue(recall, NbBundle.getMessage(EvaluationPanel.class, "EvaluationPanel.CLT_Recall_Text"), evaluation.getHeader().classAttribute().value(classIndex));
}
getExplorerManager().setRootContext(new AbstractNode(Children.create(new EvaluationNodeFactory(evaluation), true)));
repaint();
}
private static class EvaluationNodeFactory extends ChildFactory<SimpleEvaluationNode> {
private final Evaluation evaluation;
public EvaluationNodeFactory(Evaluation evaluation) {
this.evaluation = evaluation;
}
@Override
protected boolean createKeys(List<SimpleEvaluationNode> toPopulate) {
Instances header = evaluation.getHeader();
int numClasses = header.numClasses();
for (int index = 0; index < numClasses; index++) {
toPopulate.add(new SimpleEvaluationNode(evaluation, index));
}
return true;
}
@Override
protected Node createNodeForKey(SimpleEvaluationNode node) {
return node;
}
}
private static class SimpleEvaluationNode extends AbstractNode implements Comparable<SimpleEvaluationNode> {
private final Evaluation evaluation;
private final int classIndex;
private static final Image EMPTY_IMAGE = getEmptyImage();
public SimpleEvaluationNode(Evaluation evaluation, int classIndex) {
super(Children.LEAF);
this.evaluation = evaluation;
this.classIndex = classIndex;
setDisplayName(evaluation.getHeader().classAttribute().value(classIndex));
}
@Override
protected Sheet createSheet() {
Sheet sheet = Sheet.createDefault();
Sheet.Set set = Sheet.createPropertiesSet();
sheet.put(set);
Property<?> property = new PropertySupport.ReadOnly<Double>("precision", Double.class, NbBundle.getMessage(EvaluationPanel.class, "EvaluationPanel.CLT_Precision_Text"), "The precision value that this classifier obtained for the given label.") {
@Override
public Double getValue() throws IllegalAccessException, InvocationTargetException {
double precision = evaluation.precision(classIndex) * 100;
String formatedString = MessageFormat.format("{0, number, 000.00}", precision).replaceAll(",", "\\.");
Double result = Double.valueOf(formatedString);
return result;
}
};
set.put(property);
property = new PropertySupport.ReadOnly<Double>("recall", Double.class, NbBundle.getMessage(EvaluationPanel.class, "EvaluationPanel.CLT_Recall_Text"), "The recall value that this classifier obtained for the given label.") {
@Override
public Double getValue() throws IllegalAccessException, InvocationTargetException {
double recall = evaluation.recall(classIndex) * 100;
String formatedString = MessageFormat.format("{0, number, 000.00}", recall).replaceAll(",", "\\.");
Double result = Double.valueOf(formatedString);
return result;
}
};
set.put(property);
return sheet;
}
@Override
public Image getIcon(int type) {
return EMPTY_IMAGE;
}
@Override
public Image getOpenedIcon(int type) {
return getIcon(type);
}
@Override
public int compareTo(SimpleEvaluationNode evaluationNode) {
return getDisplayName().compareToIgnoreCase(evaluationNode.getDisplayName());
}
private static Image getEmptyImage() {
BufferedImage bufferedImage = new BufferedImage(16, 16, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g2d = bufferedImage.createGraphics();
g2d.setPaint(new Color(255, 255, 255, 0));
g2d.fill(new Rectangle(bufferedImage.getWidth(), bufferedImage.getHeight()));
g2d.dispose();
return bufferedImage;
}
}
private static class MyOutlineView extends OutlineView {
private static final long serialVersionUID = 1L;
public MyOutlineView() {
getActionMap().clear();
}
public MyOutlineView(String nodesColumnLabel) {
super(nodesColumnLabel);
getActionMap().clear();
}
}
}