intensityclustering.IntensityClustering.java Source code

Java tutorial

Introduction

Here is the source code for intensityclustering.IntensityClustering.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package intensityclustering;

import TMARKERPluginInterface.PluginManager;
import com.boxysystems.jgoogleanalytics.FocusPoint;
import com.boxysystems.jgoogleanalytics.JGoogleAnalyticsTracker;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.SystemColor;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JRadioButton;
import org.jdesktop.swingx.JXColorSelectionButton;
import org.math.plot.Plot2DPanel;
import org.math.plot.Plot3DPanel;
import org.math.plot.PlotPanel;
import org.math.plot.plotObjects.Line;
import org.math.plot.plots.Plot;
import plugins.TMARKERPluginManager;
import tmarker.FileChooser;
import tmarker.TMAspot.TMALabel;
import tmarker.TMAspot.TMApoint;
import tmarker.TMAspot.TMAspot;
import tmarker.misc.Misc;
import tmarker.tmarker;
import weka.clusterers.Clusterer;
import weka.clusterers.EM;
import weka.clusterers.FarthestFirst;
import weka.clusterers.HierarchicalClusterer;
import weka.clusterers.SimpleKMeans;
import weka.core.Attribute;
import weka.core.FastVector;
import weka.core.Instance;
import weka.core.Instances;
import weka.gui.hierarchyvisualizer.HierarchyVisualizer;

/**
 * Plugin for the clustering of nuclei according to their colors/intensities.
 * Unstained and stained nuclei can be automatically clustered in up to 4
 * clusters (0, 1+, 2+ and 3+). This might influence the staining estimation
 * value.
 *
 * @author Peter J. Schffler
 */
public class IntensityClustering extends javax.swing.JFrame implements TMARKERPluginInterface.Pluggable {

    public static String PLUGINNAME = "Intensity Clustering";
    private static final String PLUGINVERSION = "1."
            + java.util.ResourceBundle.getBundle("intensityclustering/Bundle").getString("build");
    PluginManager manager;
    List<TMAspot> current_TMAspots_Intensity = null;
    JFrame clusterVisualizer = null; // for visualization of the hierarchical clusterer.
    private String dispayed3DColorSpace = "";

    /**
     * Creates new form IntensityClusteringFrame
     */
    public IntensityClustering() {
        initComponents();
        try {
            this.setIconImage(ImageIO.read((getClass().getResource("/intensityclustering/icon.png"))));
        } catch (IOException ex) {
            Logger.getLogger(IntensityClustering.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * 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() {
        java.awt.GridBagConstraints gridBagConstraints;

        buttonGroup1 = new javax.swing.ButtonGroup();
        buttonGroup2 = new javax.swing.ButtonGroup();
        buttonGroup3 = new javax.swing.ButtonGroup();
        buttonGroup4 = new javax.swing.ButtonGroup();
        jPanel20 = new javax.swing.JPanel();
        jPanel11 = new javax.swing.JPanel();
        jPanel2 = new javax.swing.JPanel();
        jPanel28 = new javax.swing.JPanel();
        jLabel39 = new javax.swing.JLabel();
        jLabel41 = new javax.swing.JLabel();
        jPanel9 = new javax.swing.JPanel();
        jPanel15 = new javax.swing.JPanel();
        jPanel29 = new javax.swing.JPanel();
        jLabel5 = new javax.swing.JLabel();
        jTextField1 = new javax.swing.JTextField();
        jLabel30 = new javax.swing.JLabel();
        jTextField16 = new javax.swing.JTextField();
        jLabel36 = new javax.swing.JLabel();
        jTextField17 = new javax.swing.JTextField();
        jSlider7 = new javax.swing.JSlider();
        jPanel21 = new javax.swing.JPanel();
        jLabel38 = new javax.swing.JLabel();
        jLabel42 = new javax.swing.JLabel();
        jPanel5 = new javax.swing.JPanel();
        jPanel25 = new javax.swing.JPanel();
        jPanel4 = new javax.swing.JPanel();
        jLabel34 = new javax.swing.JLabel();
        jPanel8 = new javax.swing.JPanel();
        jXColorSelectionButton3 = new org.jdesktop.swingx.JXColorSelectionButton();
        jXColorSelectionButton4 = new org.jdesktop.swingx.JXColorSelectionButton();
        jXColorSelectionButton5 = new org.jdesktop.swingx.JXColorSelectionButton();
        jXColorSelectionButton6 = new org.jdesktop.swingx.JXColorSelectionButton();
        jLabel35 = new javax.swing.JLabel();
        jPanel18 = new javax.swing.JPanel();
        jButton13 = new javax.swing.JButton();
        jRadioButton7 = new javax.swing.JRadioButton();
        jRadioButton8 = new javax.swing.JRadioButton();
        jRadioButton13 = new javax.swing.JRadioButton();
        jButton1 = new javax.swing.JButton();
        jLabel37 = new javax.swing.JLabel();
        jPanel17 = new javax.swing.JPanel();
        jRadioButton9 = new javax.swing.JRadioButton();
        jRadioButton10 = new javax.swing.JRadioButton();
        jRadioButton11 = new javax.swing.JRadioButton();
        jRadioButton12 = new javax.swing.JRadioButton();
        jButton16 = new javax.swing.JButton();
        jButton17 = new javax.swing.JButton();
        jButton2 = new javax.swing.JButton();
        jButton3 = new javax.swing.JButton();
        jPanel22 = new javax.swing.JPanel();
        jPanel26 = new javax.swing.JPanel();
        jPanel23 = new javax.swing.JPanel();
        jRadioButton3 = new javax.swing.JRadioButton();
        jButton14 = new javax.swing.JButton();
        jPanel27 = new javax.swing.JPanel();
        jPanel24 = new javax.swing.JPanel();
        jButton15 = new javax.swing.JButton();
        jPanel12 = new javax.swing.JPanel();
        jRadioButton1 = new javax.swing.JRadioButton();
        jPanel16 = new javax.swing.JPanel();
        jRadioButton2 = new javax.swing.JRadioButton();
        jComboBox2 = new javax.swing.JComboBox();
        jLabel43 = new javax.swing.JLabel();
        jRadioButton5 = new javax.swing.JRadioButton();
        jRadioButton6 = new javax.swing.JRadioButton();
        jRadioButton4 = new javax.swing.JRadioButton();
        jButton18 = new javax.swing.JButton();
        jPanel30 = new javax.swing.JPanel();
        jLabel40 = new javax.swing.JLabel();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTextArea1 = new javax.swing.JTextArea();

        setTitle(PLUGINNAME + " v1."
                + java.util.ResourceBundle.getBundle("intensityclustering/Bundle").getString("build")); // NOI18N

        jPanel20.setLayout(new java.awt.BorderLayout());

        jPanel11.setLayout(new java.awt.GridLayout(2, 1, 10, 10));

        jPanel2.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        jPanel2.setPreferredSize(new java.awt.Dimension(500, 330));
        jPanel2.setLayout(new java.awt.BorderLayout());

        jPanel28.setLayout(new javax.swing.BoxLayout(jPanel28, javax.swing.BoxLayout.PAGE_AXIS));

        jLabel39.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
        jLabel39.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("intensityclustering/Bundle"); // NOI18N
        jLabel39.setText(bundle.getString("IntensityClustering.jLabel39.text")); // NOI18N
        jLabel39.setAlignmentX(0.5F);
        jPanel28.add(jLabel39);

        jLabel41.setForeground(new java.awt.Color(255, 0, 0));
        jLabel41.setText(bundle.getString("IntensityClustering.jLabel41.text")); // NOI18N
        jLabel41.setAlignmentX(0.5F);
        jPanel28.add(jLabel41);

        jPanel2.add(jPanel28, java.awt.BorderLayout.PAGE_START);

        jPanel11.add(jPanel2);

        jPanel9.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        jPanel9.setPreferredSize(new java.awt.Dimension(500, 330));
        jPanel9.setLayout(new java.awt.BorderLayout());

        jPanel15.setLayout(new java.awt.BorderLayout());

        jPanel29.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT, 1, 0));

        jLabel5.setText(bundle.getString("IntensityClustering.jLabel5.text")); // NOI18N
        jPanel29.add(jLabel5);

        jTextField1.setColumns(3);
        jTextField1.setHorizontalAlignment(javax.swing.JTextField.TRAILING);
        jTextField1.setText(bundle.getString("IntensityClustering.jTextField1.text")); // NOI18N
        jTextField1.setMargin(new java.awt.Insets(0, 0, 0, 0));
        jTextField1.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                jTextField1KeyPressed(evt);
            }
        });
        jPanel29.add(jTextField1);

        jLabel30.setText(bundle.getString("IntensityClustering.jLabel30.text")); // NOI18N
        jPanel29.add(jLabel30);

        jTextField16.setColumns(3);
        jTextField16.setHorizontalAlignment(javax.swing.JTextField.TRAILING);
        jTextField16.setText(bundle.getString("IntensityClustering.jTextField16.text")); // NOI18N
        jTextField16.setMargin(new java.awt.Insets(0, 0, 0, 0));
        jTextField16.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                jTextField16KeyReleased(evt);
            }
        });
        jPanel29.add(jTextField16);

        jLabel36.setText(bundle.getString("IntensityClustering.jLabel36.text")); // NOI18N
        jPanel29.add(jLabel36);

        jTextField17.setColumns(3);
        jTextField17.setHorizontalAlignment(javax.swing.JTextField.TRAILING);
        jTextField17.setToolTipText(bundle.getString("IntensityClustering.jTextField17.toolTipText")); // NOI18N
        jTextField17.setBorder(null);
        jTextField17.setOpaque(false);
        jPanel29.add(jTextField17);

        jSlider7.setMaximum(255);
        jSlider7.setMinimum(2);
        jSlider7.setValue(51);
        jSlider7.setOpaque(false);
        jSlider7.setPreferredSize(new java.awt.Dimension(100, 26));
        jSlider7.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                jSlider7StateChanged(evt);
            }
        });
        jPanel29.add(jSlider7);

        jPanel15.add(jPanel29, java.awt.BorderLayout.PAGE_START);

        jPanel9.add(jPanel15, java.awt.BorderLayout.PAGE_END);

        jPanel21.setLayout(new javax.swing.BoxLayout(jPanel21, javax.swing.BoxLayout.PAGE_AXIS));

        jLabel38.setBackground(jPanel9.getBackground().darker());
        jLabel38.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
        jLabel38.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        jLabel38.setText(bundle.getString("IntensityClustering.jLabel38.text")); // NOI18N
        jLabel38.setAlignmentX(0.5F);
        jPanel21.add(jLabel38);

        jLabel42.setForeground(new java.awt.Color(255, 0, 0));
        jLabel42.setText(bundle.getString("IntensityClustering.jLabel42.text")); // NOI18N
        jLabel42.setAlignmentX(0.5F);
        jPanel21.add(jLabel42);

        jPanel9.add(jPanel21, java.awt.BorderLayout.NORTH);

        jPanel11.add(jPanel9);

        jPanel20.add(jPanel11, java.awt.BorderLayout.LINE_END);

        jPanel5.setLayout(new java.awt.BorderLayout());

        jPanel25.setLayout(new java.awt.BorderLayout());

        jPanel4.setLayout(new java.awt.GridBagLayout());

        jLabel34.setText(bundle.getString("IntensityClustering.jLabel34.text")); // NOI18N
        jLabel34.setToolTipText(bundle.getString("IntensityClustering.jLabel34.toolTipText")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 0);
        jPanel4.add(jLabel34, gridBagConstraints);

        jPanel8.setLayout(new java.awt.GridLayout(1, 1, 15, 0));

        jXColorSelectionButton3.setBackground(new java.awt.Color(0, 0, 255));
        jXColorSelectionButton3.setText(bundle.getString("IntensityClustering.jXColorSelectionButton3.text")); // NOI18N
        jPanel8.add(jXColorSelectionButton3);

        jXColorSelectionButton4.setBackground(new java.awt.Color(0, 0, 255));
        jPanel8.add(jXColorSelectionButton4);

        jXColorSelectionButton5.setBackground(new java.awt.Color(0, 0, 255));
        jPanel8.add(jXColorSelectionButton5);

        jXColorSelectionButton6.setBackground(new java.awt.Color(0, 0, 255));
        jPanel8.add(jXColorSelectionButton6);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.gridwidth = 4;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(0, 20, 10, 0);
        jPanel4.add(jPanel8, gridBagConstraints);

        jLabel35.setText(bundle.getString("IntensityClustering.jLabel35.text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(0, 5, 10, 0);
        jPanel4.add(jLabel35, gridBagConstraints);

        jPanel18.setLayout(new java.awt.GridBagLayout());

        jButton13.setText(bundle.getString("IntensityClustering.jButton13.text")); // NOI18N
        jButton13.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton13ActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.gridwidth = 3;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(2, 5, 2, 2);
        jPanel18.add(jButton13, gridBagConstraints);

        buttonGroup1.add(jRadioButton7);
        jRadioButton7.setText(bundle.getString("IntensityClustering.jRadioButton7.text")); // NOI18N
        jRadioButton7.setToolTipText(bundle.getString("IntensityClustering.jRadioButton7.toolTipText")); // NOI18N
        jRadioButton7.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jRadioButton7ActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.insets = new java.awt.Insets(5, 0, 5, 0);
        jPanel18.add(jRadioButton7, gridBagConstraints);

        buttonGroup1.add(jRadioButton8);
        jRadioButton8.setSelected(true);
        jRadioButton8.setText(bundle.getString("IntensityClustering.jRadioButton8.text")); // NOI18N
        jRadioButton8.setToolTipText(bundle.getString("IntensityClustering.jRadioButton8.toolTipText")); // NOI18N
        jRadioButton8.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jRadioButton8ActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.insets = new java.awt.Insets(5, 0, 5, 0);
        jPanel18.add(jRadioButton8, gridBagConstraints);

        buttonGroup1.add(jRadioButton13);
        jRadioButton13.setText(bundle.getString("IntensityClustering.jRadioButton13.text")); // NOI18N
        jRadioButton13.setToolTipText(bundle.getString("IntensityClustering.jRadioButton13.toolTipText")); // NOI18N
        jRadioButton13.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jRadioButton13ActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
        gridBagConstraints.insets = new java.awt.Insets(5, 0, 5, 0);
        jPanel18.add(jRadioButton13, gridBagConstraints);

        jButton1.setText("Show Nucleus Singlets (very slow)");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(2, 5, 2, 2);
        jPanel18.add(jButton1, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.gridwidth = 5;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(0, 10, 5, 0);
        jPanel4.add(jPanel18, gridBagConstraints);

        jLabel37.setText(bundle.getString("IntensityClustering.jLabel37.text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridwidth = 5;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(10, 10, 0, 0);
        jPanel4.add(jLabel37, gridBagConstraints);

        jPanel17.setLayout(new java.awt.GridLayout(1, 0));

        buttonGroup2.add(jRadioButton9);
        jRadioButton9.setText(bundle.getString("IntensityClustering.jRadioButton9.text")); // NOI18N
        jRadioButton9.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
        jPanel17.add(jRadioButton9);

        buttonGroup2.add(jRadioButton10);
        jRadioButton10.setText(bundle.getString("IntensityClustering.jRadioButton10.text")); // NOI18N
        jRadioButton10.setToolTipText(bundle.getString("IntensityClustering.jRadioButton10.toolTipText")); // NOI18N
        jRadioButton10.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
        jPanel17.add(jRadioButton10);

        buttonGroup2.add(jRadioButton11);
        jRadioButton11.setText(bundle.getString("IntensityClustering.jRadioButton11.text")); // NOI18N
        jRadioButton11.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
        jPanel17.add(jRadioButton11);

        buttonGroup2.add(jRadioButton12);
        jRadioButton12.setSelected(true);
        jRadioButton12.setText(bundle.getString("IntensityClustering.jRadioButton12.text")); // NOI18N
        jRadioButton12.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
        jPanel17.add(jRadioButton12);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.gridwidth = 4;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 0);
        jPanel4.add(jPanel17, gridBagConstraints);

        jButton16.setText(bundle.getString("IntensityClustering.jButton16.text")); // NOI18N
        jButton16.setToolTipText(bundle.getString("IntensityClustering.jButton16.toolTipText")); // NOI18N
        jButton16.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton16ActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 4;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(0, 20, 5, 0);
        jPanel4.add(jButton16, gridBagConstraints);

        jButton17.setText(bundle.getString("IntensityClustering.jButton17.text")); // NOI18N
        jButton17.setToolTipText(bundle.getString("IntensityClustering.jButton17.toolTipText")); // NOI18N
        jButton17.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton17ActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 4;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 0);
        jPanel4.add(jButton17, gridBagConstraints);

        jButton2.setText("Save Cluster Centers...");
        jButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton2ActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 5;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(0, 20, 5, 0);
        jPanel4.add(jButton2, gridBagConstraints);

        jButton3.setText("Load Cluster Centers...");
        jButton3.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton3ActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 5;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 0);
        jPanel4.add(jButton3, gridBagConstraints);

        jPanel25.add(jPanel4, java.awt.BorderLayout.LINE_START);

        jPanel5.add(jPanel25, java.awt.BorderLayout.PAGE_START);

        jPanel22.setLayout(new java.awt.BorderLayout());

        jPanel26.setBorder(javax.swing.BorderFactory
                .createTitledBorder(bundle.getString("IntensityClustering.jPanel26.border.title"))); // NOI18N
        jPanel26.setLayout(new java.awt.BorderLayout());

        jPanel23.setLayout(new java.awt.GridBagLayout());

        buttonGroup3.add(jRadioButton3);
        jRadioButton3.setText(bundle.getString("IntensityClustering.jRadioButton3.text")); // NOI18N
        jRadioButton3.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(10, 5, 0, 0);
        jPanel23.add(jRadioButton3, gridBagConstraints);

        jButton14.setText(bundle.getString("IntensityClustering.jButton14.text")); // NOI18N
        jButton14.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton14ActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(2, 25, 2, 2);
        jPanel23.add(jButton14, gridBagConstraints);

        jPanel26.add(jPanel23, java.awt.BorderLayout.PAGE_START);

        jPanel22.add(jPanel26, java.awt.BorderLayout.LINE_START);

        jPanel27.setBorder(javax.swing.BorderFactory
                .createTitledBorder(bundle.getString("IntensityClustering.jPanel27.border.title"))); // NOI18N
        jPanel27.setLayout(new java.awt.BorderLayout());

        jPanel24.setLayout(new java.awt.GridBagLayout());

        jButton15.setText(bundle.getString("IntensityClustering.jButton15.text")); // NOI18N
        jButton15.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton15ActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(4, 25, 7, 0);
        jPanel24.add(jButton15, gridBagConstraints);

        jPanel12.setLayout(new java.awt.GridLayout(4, 0));

        buttonGroup4.add(jRadioButton1);
        jRadioButton1.setSelected(true);
        jRadioButton1.setText(bundle.getString("IntensityClustering.jRadioButton1.text")); // NOI18N
        jPanel12.add(jRadioButton1);

        jPanel16.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT, 0, 0));

        buttonGroup4.add(jRadioButton2);
        jRadioButton2.setText(bundle.getString("IntensityClustering.jRadioButton2.text")); // NOI18N
        jPanel16.add(jRadioButton2);

        jComboBox2.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "SINGLE", "COMPLETE", "AVERAGE",
                "MEAN", "CENTROID", "WARD", "ADJCOMLPETE", "NEIGHBOR_JOINING" }));
        jComboBox2.setSelectedIndex(4);
        jPanel16.add(jComboBox2);

        jLabel43.setText(bundle.getString("IntensityClustering.jLabel43.text")); // NOI18N
        jLabel43.setToolTipText(bundle.getString("IntensityClustering.jLabel43.toolTipText")); // NOI18N
        jLabel43.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT);
        jLabel43.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jLabel43MouseClicked(evt);
            }
        });
        jPanel16.add(jLabel43);

        jPanel12.add(jPanel16);

        buttonGroup4.add(jRadioButton5);
        jRadioButton5.setText(bundle.getString("IntensityClustering.jRadioButton5.text")); // NOI18N
        jPanel12.add(jRadioButton5);

        buttonGroup4.add(jRadioButton6);
        jRadioButton6.setText(bundle.getString("IntensityClustering.jRadioButton6.text")); // NOI18N
        jPanel12.add(jRadioButton6);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(0, 25, 0, 0);
        jPanel24.add(jPanel12, gridBagConstraints);

        buttonGroup3.add(jRadioButton4);
        jRadioButton4.setSelected(true);
        jRadioButton4.setText(bundle.getString("IntensityClustering.jRadioButton4.text")); // NOI18N
        jRadioButton4.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(10, 10, 0, 0);
        jPanel24.add(jRadioButton4, gridBagConstraints);

        jButton18.setText(bundle.getString("IntensityClustering.jButton18.text")); // NOI18N
        jButton18.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton18ActionPerformed(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
        gridBagConstraints.insets = new java.awt.Insets(4, 25, 7, 0);
        jPanel24.add(jButton18, gridBagConstraints);

        jPanel27.add(jPanel24, java.awt.BorderLayout.PAGE_START);

        jPanel30.setLayout(new java.awt.BorderLayout());

        jLabel40.setText(bundle.getString("IntensityClustering.jLabel40.text")); // NOI18N
        jPanel30.add(jLabel40, java.awt.BorderLayout.PAGE_START);

        jTextArea1.setBackground(SystemColor.info);
        jTextArea1.setColumns(40);
        jTextArea1.setFont(jTextArea1.getFont());
        jTextArea1.setRows(5);
        jTextArea1.setText(bundle.getString("IntensityClustering.jTextArea1.text")); // NOI18N
        jTextArea1.setWrapStyleWord(true);
        jScrollPane1.setViewportView(jTextArea1);

        jPanel30.add(jScrollPane1, java.awt.BorderLayout.CENTER);

        jPanel27.add(jPanel30, java.awt.BorderLayout.CENTER);

        jPanel22.add(jPanel27, java.awt.BorderLayout.CENTER);

        jPanel5.add(jPanel22, java.awt.BorderLayout.CENTER);

        jPanel20.add(jPanel5, java.awt.BorderLayout.CENTER);

        getContentPane().add(jPanel20, java.awt.BorderLayout.CENTER);

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void jTextField1KeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jTextField1KeyPressed
        if (evt.getKeyCode() == KeyEvent.VK_ENTER) {
            drawNucleiIntensities2D(manager.getSelectedTMAspots(), false);
        }
    }//GEN-LAST:event_jTextField1KeyPressed

    private void jTextField16KeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jTextField16KeyReleased
        if (evt.getKeyCode() == KeyEvent.VK_ENTER) {
            drawNucleiIntensities2D(manager.getSelectedTMAspots(), false);
        }
    }//GEN-LAST:event_jTextField16KeyReleased

    private void jSlider7StateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jSlider7StateChanged
        drawNucleiIntensities2D(manager.getSelectedTMAspots(), false);
    }//GEN-LAST:event_jSlider7StateChanged

    private void jButton13ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton13ActionPerformed
        List<TMAspot> tss = manager.getSelectedTMAspots();
        drawNucleiIntensities3D(tss);
        drawNucleiIntensities2D(tss, false);
        jLabel41.setText(" ");
        jLabel42.setText(" ");
    }//GEN-LAST:event_jButton13ActionPerformed

    private void jRadioButton7ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButton7ActionPerformed
        //drawNucleiIntensities3D(manager.getSelectedTMAspots());
        change3DPlotAxis();
    }//GEN-LAST:event_jRadioButton7ActionPerformed

    private void jRadioButton8ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButton8ActionPerformed
        //drawNucleiIntensities3D(manager.getSelectedTMAspots());
        change3DPlotAxis();
    }//GEN-LAST:event_jRadioButton8ActionPerformed

    private void jRadioButton13ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButton13ActionPerformed
        //drawNucleiIntensities3D(manager.getSelectedTMAspots());
        change3DPlotAxis();
    }//GEN-LAST:event_jRadioButton13ActionPerformed

    private void jButton16ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton16ActionPerformed
        adoptMeanIntensities();
        drawNucleiIntensities3D(manager.getSelectedTMAspots());
        drawNucleiIntensities2D(manager.getSelectedTMAspots(), false);
    }//GEN-LAST:event_jButton16ActionPerformed

    private void jButton17ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton17ActionPerformed
        adoptUnkownPointsIntensities();
        drawNucleiIntensities3D(manager.getSelectedTMAspots());
        drawNucleiIntensities2D(manager.getSelectedTMAspots(), false);
    }//GEN-LAST:event_jButton17ActionPerformed

    private void jButton14ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton14ActionPerformed
        clusterPointsManually(manager.getSelectedTMAspots());
        JGoogleAnalyticsTracker tracker = new JGoogleAnalyticsTracker("TMARKER", "UA-61194283-1");
        FocusPoint focusPoint = new FocusPoint("IntensityClusteringManualUsage");
        tracker.trackAsynchronously(focusPoint);
    }//GEN-LAST:event_jButton14ActionPerformed

    private void jButton15ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton15ActionPerformed
        clusterPointsAutomaticallyColorSpace(manager.getSelectedTMAspots());
        drawNucleiIntensities2D(manager.getSelectedTMAspots(), false);
        JGoogleAnalyticsTracker tracker = new JGoogleAnalyticsTracker("TMARKER", "UA-61194283-1");
        FocusPoint focusPoint = new FocusPoint("IntensityClusteringAutomatic3D");
        tracker.trackAsynchronously(focusPoint);
    }//GEN-LAST:event_jButton15ActionPerformed

    private void jLabel43MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jLabel43MouseClicked
        displayDendrogram();
    }//GEN-LAST:event_jLabel43MouseClicked

    private void jButton18ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton18ActionPerformed
        drawNucleiIntensities2D(manager.getSelectedTMAspots(), true);
        drawNucleiIntensities3D(manager.getSelectedTMAspots());
        JGoogleAnalyticsTracker tracker = new JGoogleAnalyticsTracker("TMARKER", "UA-61194283-1");
        FocusPoint focusPoint = new FocusPoint("IntensityClusteringAutomatic2D");
        tracker.trackAsynchronously(focusPoint);
    }//GEN-LAST:event_jButton18ActionPerformed

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
        List<TMAspot> tss = manager.getSelectedTMAspots();
        drawNucleiIntensities3DSinglets(tss);
        jLabel41.setText(" ");
    }//GEN-LAST:event_jButton1ActionPerformed

    private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton3ActionPerformed
        loadClusterCenters();
    }//GEN-LAST:event_jButton3ActionPerformed

    private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
        saveClusterCenters();
    }//GEN-LAST:event_jButton2ActionPerformed

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(IntensityClustering.class.getName())
                    .log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(IntensityClustering.class.getName())
                    .log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(IntensityClustering.class.getName())
                    .log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(IntensityClustering.class.getName())
                    .log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new IntensityClustering().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.ButtonGroup buttonGroup1;
    private javax.swing.ButtonGroup buttonGroup2;
    private javax.swing.ButtonGroup buttonGroup3;
    private javax.swing.ButtonGroup buttonGroup4;
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton13;
    private javax.swing.JButton jButton14;
    private javax.swing.JButton jButton15;
    private javax.swing.JButton jButton16;
    private javax.swing.JButton jButton17;
    private javax.swing.JButton jButton18;
    private javax.swing.JButton jButton2;
    private javax.swing.JButton jButton3;
    private javax.swing.JComboBox jComboBox2;
    private javax.swing.JLabel jLabel30;
    private javax.swing.JLabel jLabel34;
    private javax.swing.JLabel jLabel35;
    private javax.swing.JLabel jLabel36;
    private javax.swing.JLabel jLabel37;
    private javax.swing.JLabel jLabel38;
    private javax.swing.JLabel jLabel39;
    private javax.swing.JLabel jLabel40;
    private javax.swing.JLabel jLabel41;
    private javax.swing.JLabel jLabel42;
    private javax.swing.JLabel jLabel43;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JPanel jPanel11;
    private javax.swing.JPanel jPanel12;
    private javax.swing.JPanel jPanel15;
    private javax.swing.JPanel jPanel16;
    private javax.swing.JPanel jPanel17;
    private javax.swing.JPanel jPanel18;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel20;
    private javax.swing.JPanel jPanel21;
    private javax.swing.JPanel jPanel22;
    private javax.swing.JPanel jPanel23;
    private javax.swing.JPanel jPanel24;
    private javax.swing.JPanel jPanel25;
    private javax.swing.JPanel jPanel26;
    private javax.swing.JPanel jPanel27;
    private javax.swing.JPanel jPanel28;
    private javax.swing.JPanel jPanel29;
    private javax.swing.JPanel jPanel30;
    private javax.swing.JPanel jPanel4;
    private javax.swing.JPanel jPanel5;
    private javax.swing.JPanel jPanel8;
    private javax.swing.JPanel jPanel9;
    private javax.swing.JRadioButton jRadioButton1;
    private javax.swing.JRadioButton jRadioButton10;
    private javax.swing.JRadioButton jRadioButton11;
    private javax.swing.JRadioButton jRadioButton12;
    private javax.swing.JRadioButton jRadioButton13;
    private javax.swing.JRadioButton jRadioButton2;
    private javax.swing.JRadioButton jRadioButton3;
    private javax.swing.JRadioButton jRadioButton4;
    private javax.swing.JRadioButton jRadioButton5;
    private javax.swing.JRadioButton jRadioButton6;
    private javax.swing.JRadioButton jRadioButton7;
    private javax.swing.JRadioButton jRadioButton8;
    private javax.swing.JRadioButton jRadioButton9;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JSlider jSlider7;
    private javax.swing.JTextArea jTextArea1;
    private javax.swing.JTextField jTextField1;
    private javax.swing.JTextField jTextField16;
    private javax.swing.JTextField jTextField17;
    private org.jdesktop.swingx.JXColorSelectionButton jXColorSelectionButton3;
    private org.jdesktop.swingx.JXColorSelectionButton jXColorSelectionButton4;
    private org.jdesktop.swingx.JXColorSelectionButton jXColorSelectionButton5;
    private org.jdesktop.swingx.JXColorSelectionButton jXColorSelectionButton6;
    // End of variables declaration//GEN-END:variables

    @Override
    public String getAuthor() {
        return "Peter J. Schffler";
    }

    @Override
    public String getVersion() {
        return PLUGINVERSION;
    }

    @Override
    public boolean start() {
        return true;
    }

    @Override
    public boolean stop() {
        setVisible(false);
        return true;
    }

    @Override
    public void setPluginManager(PluginManager manager) {
        this.manager = manager;
    }

    @Override
    public Icon getIcon() {
        return new ImageIcon(this.getIconImage());
    }

    @Override
    public String getPluginName() {
        return PLUGINNAME;
    }

    @Override
    public void actionPerformed(java.awt.event.ActionEvent evt) {
        jLabel41.setText(" ");
        jLabel42.setText(" ");
        this.setVisible(true);
        adoptUnkownPointsIntensities();
        List<TMAspot> tss = manager.getSelectedTMAspots();
        if (!tss.isEmpty()) {
            drawNucleiIntensities3D(tss);
            drawNucleiIntensities2D(tss, false);
        }
    }

    @Override
    public void setParameterDefaults() {
        setParam_nClusters(4);
        setParam_ColorSpace("HSB");
        setParam_ColorOfClassK(0, Color.BLUE);
        setParam_ColorOfClassK(1, Color.YELLOW);
        setParam_ColorOfClassK(2, Color.ORANGE);
        setParam_ColorOfClassK(3, Color.RED);
        setParam_ManualAutomaticClustering(1);
        setParam_AutomaticClustererString("K-Means");
        setParam_HierarchicalClusteringMethod("CENTROID");
    }

    @Override
    public void setParameters(Properties parameters) {
        String value;
        value = parameters.getProperty("nClusters");
        if (value != null) {
            setParam_nClusters(Integer.parseInt(value));
        }
        value = parameters.getProperty("colorSpace");
        if (value != null) {
            setParam_ColorSpace(value);
        }
        value = parameters.getProperty("colorClass0");
        if (value != null) {
            setParam_ColorOfClassK(0, new Color(Integer.parseInt(value)));
        }
        value = parameters.getProperty("colorClass1");
        if (value != null) {
            setParam_ColorOfClassK(1, new Color(Integer.parseInt(value)));
        }
        value = parameters.getProperty("colorClass2");
        if (value != null) {
            setParam_ColorOfClassK(2, new Color(Integer.parseInt(value)));
        }
        value = parameters.getProperty("colorClass3");
        if (value != null) {
            setParam_ColorOfClassK(3, new Color(Integer.parseInt(value)));
        }
        value = parameters.getProperty("manualAutomaticClustering");
        if (value != null) {
            setParam_ManualAutomaticClustering(Integer.parseInt(value));
        }
        value = parameters.getProperty("automaticClusteringString");
        if (value != null) {
            setParam_AutomaticClustererString(value);
        }
        value = parameters.getProperty("hierarchicalClusteringMethod");
        if (value != null) {
            setParam_HierarchicalClusteringMethod(value);
        }
    }

    @Override
    public Properties getParameters() {
        Properties parameters = new Properties();
        parameters.setProperty("nClusters", Integer.toString(getParam_nClusters()));
        parameters.setProperty("colorSpace", getParam_ColorSpace());
        parameters.setProperty("colorClass0", Integer.toString(getParam_ColorOfClassK(0).getRGB()));
        parameters.setProperty("colorClass1", Integer.toString(getParam_ColorOfClassK(1).getRGB()));
        parameters.setProperty("colorClass2", Integer.toString(getParam_ColorOfClassK(2).getRGB()));
        parameters.setProperty("colorClass3", Integer.toString(getParam_ColorOfClassK(3).getRGB()));
        parameters.setProperty("manualAutomaticClustering", Integer.toString(getParam_ManualAutomaticClustering()));
        parameters.setProperty("automaticClusteringString", getParam_AutomaticClustererString());
        parameters.setProperty("hierarchicalClusteringMethod", getParam_HierarchicalClusteringMethod());
        return parameters;
    }

    @Override
    public String getHTMLReport(String HTMLFolderPath) {
        String output = "<html>";
        char linebreak = '\n';
        String HTMLFolderName = new File(HTMLFolderPath).getName() + File.separator;

        // Save the intensity plot images
        if (!getClusteringDescription().equals("-")) {
            try {
                File file_tmp = new File(HTMLFolderPath + "3DPlot.png");
                BufferedImage bi = get3DPlot();
                ImageIO.write(bi, "png", file_tmp);
                file_tmp = new File(HTMLFolderPath + "2DPlot.png");
                bi = get2DPlot();
                ImageIO.write(bi, "png", file_tmp);
            } catch (IOException ex) {
                Logger.getLogger(IntensityClustering.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        output += "<table><tr>" + linebreak + "  <td colspan=2><i><u>Intensity Clustering Parameters</u></i></td>"
                + linebreak + " </tr>" + linebreak + " <tr>" + linebreak + "  <td><b>Color Space</b></td>"
                + linebreak + "  <td>" + getParam_ColorSpace() + "</td>" + linebreak + " </tr>" + linebreak
                + " <tr>" + linebreak + "  <td><b>Number of Classes</b></td>" + linebreak + "  <td>"
                + getParam_nClusters() + "</td>" + linebreak + " </tr>" + linebreak + " <tr>" + linebreak
                + "  <td><b>Clustering:</b></td>" + linebreak + "  <td>" + getClusteringDescription() + "</td>"
                + linebreak + " </tr>" + linebreak;

        if (!getClusteringDescription().equals("-")) {
            // save the two clustering images
            output += " <tr>" + linebreak + "  <td></td>" + linebreak + "  <td>" + " <br><a href=\""
                    + HTMLFolderName + "3DPlot.png\"><img alt=\"Nucleus Distribution in Color Space\" src=\""
                    + HTMLFolderName + "3DPlot.png\" width=400></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" + linebreak
                    + "                <a href=\"" + HTMLFolderName
                    + "2DPlot.png\"><img alt=\"Nucleus Distribution in Color Space\" src=\"" + HTMLFolderName
                    + "2DPlot.png\" width=400></a><br><br>" + linebreak + "  </td>" + " </tr>" + linebreak + " <tr>"
                    + linebreak + "  <td></td>" + linebreak + "  <td><textarea rows=\"10\" cols=\"115\">"
                    + getClustererInfo() + "</textarea></td>" + linebreak + " </tr>" + linebreak;
        }
        output += "</table><br>" + linebreak;

        output += "</html>";
        return output;
    }

    @Override
    public void updateOptionsToTMAspot(TMAspot visible_TMAspot, List<TMAspot> selected_TMAspots) {
        if (isShowing()) {
            drawNucleiIntensities2D(selected_TMAspots, false);
            drawNucleiIntensities3D(selected_TMAspots);
        }
    }

    @Override
    public void drawInformationPreNuclei(TMAspot ts, Graphics g, double z, int x_min, int y_min, int x_max,
            int y_max) {
    }

    @Override
    public void drawInformationPostNuclei(TMAspot ts, Graphics g, double z, int x_min, int y_min, int x_max,
            int y_max) {
    }

    @Override
    public BufferedImage showAlternativeImage(TMAspot ts) {
        return null;
    }

    @Override
    public void TMAspotMouseClicked(TMAspot ts, TMApoint tp, MouseEvent evt) {

    }

    /**
     * Draws the 2D Histogram Plot in the IntensityClustering. X-Axsis is
     * intensity value of chanel 2 image (where the stained nuclei are). Y-axis
     * are relative frequencies of present nuclei.
     *
     * @param tss The TMAspots whose nuclei are considered (both gold-standard
     * and estimated nuclei).
     * @param doAlsoClustering If true, the TMApoints are also clustered
     * according to the histogram.
     */
    void drawNucleiIntensities2D(List<TMAspot> tss, boolean doAlsoClustering) {
        // draw the plot
        Plot2DPanel plot;
        if (((java.awt.BorderLayout) (jPanel9.getLayout()))
                .getLayoutComponent(java.awt.BorderLayout.CENTER) != null) {
            plot = (Plot2DPanel) ((java.awt.BorderLayout) (jPanel9.getLayout()))
                    .getLayoutComponent(java.awt.BorderLayout.CENTER);
            plot.removeAllPlots();
            plot.removeAllPlotables();
        } else {
            plot = new Plot2DPanel(PlotPanel.SOUTH);
            plot.setAxisLabels("Intensity", "Frequency");
            plot.plotCanvas.setBackground(jPanel9.getBackground());
            plot.plotLegend.setBackground(jPanel9.getBackground());
            plot.plotToolBar.setBackground(plot.plotCanvas.getBackground());
        }
        if (((java.awt.BorderLayout) (jPanel9.getLayout()))
                .getLayoutComponent(java.awt.BorderLayout.CENTER) == null) {
            jPanel9.add(plot, java.awt.BorderLayout.CENTER);
            jPanel15.setBackground(plot.plotCanvas.getBackground());
            jPanel15.setVisible(true);
            validate();
            pack();
        }

        if (tss.size() > 0) {
            try {
                this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

                List<Integer> intensities = new ArrayList<>();
                int intensity;
                int min = Integer.parseInt(jTextField1.getText());
                int max = Integer.parseInt(jTextField16.getText());
                for (TMAspot ts : tss) {
                    //TODO: GET THE CHANNEL 2 Image
                    //BufferedImage img = ts.getBufferedImage(TMAspot.SHOW_CHANNEL2_IMAGE, false);
                    BufferedImage img = ts.getBufferedImage(false);
                    // img can be null if color deconvolution has not been performed, yet.
                    if (img != null) {
                        List<TMApoint> tps = ts.getPoints();
                        for (TMALabel tp : tps) {
                            intensity = TMAspot.getAverageColorAtPoint(img, tp.x, tp.y, ts.getParam_r(), false)
                                    .getRed();
                            if (intensity >= min && intensity <= max) {
                                intensities.add(intensity);
                            }
                        }
                    }
                }

                double[] intensities_array = new double[intensities.size()];

                for (int i = 0; i < intensities.size(); i++) {
                    intensities_array[i] = intensities.get(i);
                }

                int nbins = jSlider7.getValue();
                if (intensities_array.length > 0) {
                    plot.addHistogramPlot("TMA points", intensities_array, 0, 256, nbins);
                } //else {
                  //  JOptionPane.showMessageDialog(this, "No TMA points have been found.", "No TMA points found.", JOptionPane.WARNING_MESSAGE);
                  //}

                //// Cluster Points according to histograms
                if (doAlsoClustering) {
                    // Find Clusters
                    int n = getParam_nClusters();

                    // Create ARFF Data
                    FastVector atts;
                    Instances data;
                    int i;

                    // 1. create arff data format
                    atts = new FastVector(1);
                    for (i = 0; i < 1; i++) {
                        atts.addElement(new Attribute(Integer.toString(i)));
                    }

                    // 2. create Instances object
                    data = new Instances("TMA points", atts, tmarker.getNumberNuclei(tss));

                    // 3. fill with data
                    for (i = 0; i < intensities_array.length; i++) {
                        // add the instance
                        Instance inst = new Instance(1.0, new double[] { intensities_array[i] });
                        inst.setDataset(data);
                        data.add(inst);
                    }

                    // 4. set data class index (last attribute is the class)
                    //data.setClassIndex(data.numAttributes() - 1); // not for weka 3.5.X
                    if (tmarker.DEBUG > 4) {
                        java.util.logging.Logger.getLogger(getClass().getName()).log(java.util.logging.Level.INFO,
                                data.toString());
                    }

                    Clusterer clusterer = getClusterer();
                    String[] options = getClustererOptions();

                    if (tmarker.DEBUG > 3) {
                        if (options.length > 0) {
                            String info = "Clusterer should have options:\n";
                            for (String o : options) {
                                info += o + " ";
                            }
                            info += "\n";
                            java.util.logging.Logger.getLogger(getClass().getName())
                                    .log(java.util.logging.Level.INFO, info);
                        }
                    }

                    clusterer.setOptions(options); // set the clusterer options
                    clusterer.buildClusterer(data); // build the clusterer

                    // order the clusters according to the brightness
                    // The most bright cluster should be 0, then 1, then 2,...
                    ArrayList<ArrayList<Double>> values = new ArrayList<>();
                    for (i = 0; i < n; i++) {
                        values.add(new ArrayList<Double>());
                    }
                    int z;
                    double value;
                    for (i = 0; i < data.numInstances(); i++) {
                        z = clusterer.clusterInstance(data.instance(i));
                        value = data.instance(i).value(0);
                        values.get(z).add(value);
                    }
                    double[] means = new double[n];
                    double[] stds = new double[n];
                    for (i = 0; i < n; i++) {
                        means[i] = Misc.mean(values.get(i).toArray(new Double[values.get(i).size()]));
                        stds[i] = Misc.std(values.get(i).toArray(new Double[values.get(i).size()]));
                    }
                    int[] ordering = Misc.orderArray(means, true);

                    for (i = 0; i < n; i++) {
                        int ind = Misc.IndexOf(ordering, i);
                        plot.addPlotable(new Line(getParam_ColorOfClassK(i),
                                new double[] { means[ind], plot.plotCanvas.base.roundXmin[1] },
                                new double[] { means[ind], plot.plotCanvas.base.roundXmax[1] }, 2 * stds[ind]));
                        plot.addPlot(Plot2DPanel.LINE, "Staining " + i, getParam_ColorOfClassK(i),
                                new double[][] { new double[] { means[ind], plot.plotCanvas.base.roundXmin[1] },
                                        new double[] { means[ind], plot.plotCanvas.base.roundXmax[1] } });
                    }

                    String clusterInfo = "";
                    for (String o : clusterer.getOptions()) {
                        clusterInfo += o + " ";
                    }
                    clusterInfo += "\n\n";
                    clusterInfo += clusterer.toString().trim();
                    if (getParam_AutomaticClustererString().equalsIgnoreCase("Hierarchical")) {
                        try {
                            clusterInfo += ((HierarchicalClusterer) clusterer).graph();
                            HierarchyVisualizer a = new HierarchyVisualizer(
                                    ((HierarchicalClusterer) clusterer).graph());
                            a.setSize(800, 600);
                            if (clusterVisualizer == null) {
                                clusterVisualizer = new JFrame("Hierarchical Clusterer Dendrogram");
                                clusterVisualizer.setIconImage(getIconImage());
                                clusterVisualizer.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                                clusterVisualizer.setSize(800, 600);
                            }
                            Container contentPane = clusterVisualizer.getContentPane();
                            contentPane.removeAll();
                            contentPane.add(a);
                        } catch (Exception e) {
                            clusterVisualizer = null;
                        }
                    }
                    jTextArea1.setText(clusterInfo);

                    if (tmarker.DEBUG > 3) {
                        String info = "Clusterer has options\n";
                        for (String o : clusterer.getOptions()) {
                            info += o + " ";
                        }
                        info += "\n";
                        info += clusterer.toString() + "\n";
                        // info += (clusterer).globalInfo() + "\n";
                        info += "\n";
                        info += clusterInfo + "\n";
                        java.util.logging.Logger.getLogger(getClass().getName()).log(java.util.logging.Level.INFO,
                                info);
                    }

                    // cluster all TMAspots and assign the corresponding class to them
                    // Cluster the points
                    List<List<Integer>> clustered_points = new ArrayList<>();
                    for (i = 0; i < n; i++) {
                        clustered_points.add(new ArrayList<Integer>());
                    }

                    int k;
                    for (TMAspot ts : tss) {
                        //TODO: GET THE CHANNEL 2 IMAGE
                        //BufferedImage img = ts.getBufferedImage(TMAspot.SHOW_CHANNEL2_IMAGE, false);
                        BufferedImage img = ts.getBufferedImage(false);
                        List<TMApoint> tps = ts.getPoints();
                        for (TMApoint tp : tps) {
                            intensity = TMAspot.getAverageColorAtPoint(img, tp.x, tp.y, ts.getParam_r(), false)
                                    .getRed();

                            // add the instance
                            Instance inst = new Instance(1.0, new double[] { intensity });
                            inst.setDataset(data);
                            k = ordering[clusterer.clusterInstance(inst)];

                            // store the color for later visualization
                            clustered_points.get(k).add(intensity);

                            // set the staining of the TMApoint
                            switch (k) {
                            case 0:
                                tp.setStaining(TMALabel.STAINING_0);
                                break;
                            case 1:
                                tp.setStaining(TMALabel.STAINING_1);
                                break;
                            case 2:
                                tp.setStaining(TMALabel.STAINING_2);
                                break;
                            default:
                                tp.setStaining(TMALabel.STAINING_3);
                                break;
                            }
                        }
                        ts.dispStainingInfo();
                        if (manager.getVisibleTMAspot() == ts) {
                            manager.repaintVisibleTMAspot();
                        }
                    }

                    // Write the description
                    String description = "Nuclei clustered with " + getParam_AutomaticClustererString();
                    if (getParam_AutomaticClustererString().equalsIgnoreCase("Hierarchical")) {
                        description += " (" + getParam_HierarchicalClusteringMethod() + ")";
                    }
                    description += ", n=" + getParam_nClusters() + ", channel 2 intensity.";
                    jLabel42.setText(description);
                    jLabel41.setText(" ");

                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            }
        }
    }

    /**
     * Changes the plot axes and transfers the datapoints into another color space (which the user clicked on).
     */
    void change3DPlotAxis() {
        Plot3DPanel plot;
        if (((java.awt.BorderLayout) (jPanel2.getLayout()))
                .getLayoutComponent(java.awt.BorderLayout.CENTER) != null) {
            plot = (Plot3DPanel) ((java.awt.BorderLayout) (jPanel2.getLayout()))
                    .getLayoutComponent(java.awt.BorderLayout.CENTER);
        } else {
            plot = new Plot3DPanel();
            plot.plotCanvas.setBackground(jPanel2.getBackground());
            plot.plotToolBar.setBackground(plot.plotCanvas.getBackground());
            plot.addLegend(PlotPanel.SOUTH);
            plot.plotLegend.setBackground(jPanel2.getBackground());
        }
        String newcolorSpace = getParam_ColorSpace();
        if (newcolorSpace.equalsIgnoreCase("hsb")) {
            plot.setAxisLabels("Hue", "Saturation", "Brightness");
        } else if (newcolorSpace.equalsIgnoreCase("rtp")) {
            plot.setAxisLabels("R", "Theta", "Phi");
        } else {
            plot.setAxisLabels("Red", "Green", "Blue");
        }

        List<Plot> plots = plot.getPlots();
        float[] container = new float[3];
        for (Plot scatter : plots) {
            double[][] data = scatter.getData();
            for (int i = 0; i < data.length; i++) {
                double[] point = data[i];
                Color c;
                if (dispayed3DColorSpace.equalsIgnoreCase("rgb")) {
                    c = new Color((int) (point[0]), (int) (point[1]), (int) (point[2]));
                } else if (dispayed3DColorSpace.equalsIgnoreCase("hsb")) {
                    c = new Color(Color.HSBtoRGB((float) (point[0]), (float) (point[1]), (float) (point[2])));
                } else {
                    RTPtoRGB((float) (point[0]), (float) (point[1]), (float) (point[2]), container);
                    try {
                        c = new Color(container[0] / 255.0f, container[1] / 255.0f, container[2] / 255.0f);
                    } catch (Exception e) {
                        c = Color.BLACK;
                    }
                }
                Color2Feature(c, newcolorSpace, container);
                point[0] = container[0];
                point[1] = container[1];
                point[2] = container[2];
            }
        }
        // reset axes
        plot.revalidate();
        plot.plotCanvas.resetBase();
        plot.plotCanvas.resetMapData();

        dispayed3DColorSpace = newcolorSpace;
    }

    /**
     * Draws the 3D Plot in the IntensityClustering. Axis are color values
     * (either RGB or HSB), points are nuclei.
     *
     * @param tss The TMAspots whose nuclei are to be drawn (both gold-standard
     * and estimated nuclei).
     */
    void drawNucleiIntensities3D(List<TMAspot> tss) {
        // draw the plot
        Plot3DPanel plot;
        if (((java.awt.BorderLayout) (jPanel2.getLayout()))
                .getLayoutComponent(java.awt.BorderLayout.CENTER) != null) {
            plot = (Plot3DPanel) ((java.awt.BorderLayout) (jPanel2.getLayout()))
                    .getLayoutComponent(java.awt.BorderLayout.CENTER);
            plot.removeAllPlots();
        } else {
            plot = new Plot3DPanel();
            plot.plotCanvas.setBackground(jPanel2.getBackground());
            plot.plotToolBar.setBackground(plot.plotCanvas.getBackground());
            plot.addLegend(PlotPanel.SOUTH);
            plot.plotLegend.setBackground(jPanel2.getBackground());
        }
        plot.plotLegend.setVisible(true);
        String colorSpace = getParam_ColorSpace();
        if (colorSpace.equalsIgnoreCase("hsb")) {
            plot.setAxisLabels("Hue", "Saturation", "Brightness");
        } else if (colorSpace.equalsIgnoreCase("rtp")) {
            plot.setAxisLabels("R", "Theta", "Phi");
        } else {
            plot.setAxisLabels("Red", "Green", "Blue");
        }
        if (((java.awt.BorderLayout) (jPanel2.getLayout()))
                .getLayoutComponent(java.awt.BorderLayout.CENTER) == null) {
            jPanel2.add(plot, java.awt.BorderLayout.CENTER);
            validate();
            pack();
        }

        if (tss.size() > 0) {
            try {
                this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

                List<Float> rs_0 = new ArrayList<>();
                List<Float> gs_0 = new ArrayList<>();
                List<Float> bs_0 = new ArrayList<>();
                List<Float> rs_1 = new ArrayList<>();
                List<Float> gs_1 = new ArrayList<>();
                List<Float> bs_1 = new ArrayList<>();
                List<Float> rs_2 = new ArrayList<>();
                List<Float> gs_2 = new ArrayList<>();
                List<Float> bs_2 = new ArrayList<>();
                List<Float> rs_3 = new ArrayList<>();
                List<Float> gs_3 = new ArrayList<>();
                List<Float> bs_3 = new ArrayList<>();
                Color c;
                BufferedImage img;
                float[] features = new float[3];
                for (TMAspot ts : tss) {
                    img = ts.getBufferedImage();
                    List<TMApoint> tps = ts.getPoints(TMALabel.STAINING_0, false);
                    for (TMApoint tp : tps) {
                        Color2Feature(TMAspot.getAverageColorAtPoint(img, tp.x, tp.y, ts.getParam_r(), false),
                                colorSpace, features);
                        rs_0.add(features[0]);
                        gs_0.add(features[1]);
                        bs_0.add(features[2]);
                    }
                    tps = ts.getPoints(TMALabel.STAINING_1, false);
                    for (TMApoint tp : tps) {
                        Color2Feature(TMAspot.getAverageColorAtPoint(img, tp.x, tp.y, ts.getParam_r(), false),
                                colorSpace, features);
                        rs_1.add(features[0]);
                        gs_1.add(features[1]);
                        bs_1.add(features[2]);
                    }
                    tps = ts.getPoints(TMALabel.STAINING_2, false);
                    for (TMApoint tp : tps) {
                        Color2Feature(TMAspot.getAverageColorAtPoint(img, tp.x, tp.y, ts.getParam_r(), false),
                                colorSpace, features);
                        rs_2.add(features[0]);
                        gs_2.add(features[1]);
                        bs_2.add(features[2]);
                    }
                    tps = ts.getPoints(TMALabel.STAINING_3, false);
                    for (TMApoint tp : tps) {
                        Color2Feature(TMAspot.getAverageColorAtPoint(img, tp.x, tp.y, ts.getParam_r(), false),
                                colorSpace, features);
                        rs_3.add(features[0]);
                        gs_3.add(features[1]);
                        bs_3.add(features[2]);
                    }
                }

                double[] xs_0 = new double[rs_0.size()];
                double[] ys_0 = new double[gs_0.size()];
                double[] zs_0 = new double[bs_0.size()];
                double[] xs_1 = new double[rs_1.size()];
                double[] ys_1 = new double[gs_1.size()];
                double[] zs_1 = new double[bs_1.size()];
                double[] xs_2 = new double[rs_2.size()];
                double[] ys_2 = new double[gs_2.size()];
                double[] zs_2 = new double[bs_2.size()];
                double[] xs_3 = new double[rs_3.size()];
                double[] ys_3 = new double[gs_3.size()];
                double[] zs_3 = new double[bs_3.size()];

                for (int i = 0; i < rs_0.size(); i++) {
                    xs_0[i] = rs_0.get(i);
                    ys_0[i] = gs_0.get(i);
                    zs_0[i] = bs_0.get(i);
                }
                for (int i = 0; i < rs_1.size(); i++) {
                    xs_1[i] = rs_1.get(i);
                    ys_1[i] = gs_1.get(i);
                    zs_1[i] = bs_1.get(i);
                }
                for (int i = 0; i < rs_2.size(); i++) {
                    xs_2[i] = rs_2.get(i);
                    ys_2[i] = gs_2.get(i);
                    zs_2[i] = bs_2.get(i);
                }
                for (int i = 0; i < rs_3.size(); i++) {
                    xs_3[i] = rs_3.get(i);
                    ys_3[i] = gs_3.get(i);
                    zs_3[i] = bs_3.get(i);
                }

                if (xs_0.length > 0) {
                    c = getParam_ColorOfClassK(0);
                    plot.addScatterPlot("Staining 0", c, xs_0, ys_0, zs_0);
                }
                if (xs_1.length > 0) {
                    c = getParam_ColorOfClassK(1);
                    plot.addScatterPlot("Staining 1", c, xs_1, ys_1, zs_1);
                }
                if (xs_2.length > 0) {
                    c = getParam_ColorOfClassK(2);
                    plot.addScatterPlot("Staining 2", c, xs_2, ys_2, zs_2);
                }
                if (xs_3.length > 0) {
                    c = getParam_ColorOfClassK(3);
                    plot.addScatterPlot("Staining 3", c, xs_3, ys_3, zs_3);
                }
                //if (xs_0.length==0 && xs_1.length==0 && xs_2.length==0 && xs_3.length==0) {
                //    JOptionPane.showMessageDialog(this, "No TMA points have been found.", "No TMA points found.", JOptionPane.WARNING_MESSAGE);
                //}

                // add cluster Centers defined by the user
                if (isManualClustering()) {
                    int n = getParam_nClusters();
                    for (int i = 0; i < n; i++) {
                        c = getParam_ColorOfClassK(i);
                        Color2Feature(c, colorSpace, features);
                        plot.addScatterPlot("Center " + (i + 1), c.darker(), new double[] { features[0] },
                                new double[] { features[1] }, new double[] { features[2] });
                    }
                }

            } finally {
                this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            }
        }
    }

    /**
     * Draws the 3D Plot in the IntensityClustering. Axis are color values
     * (either RGB or HSB), points are nuclei. Each nucleus is displayed with its color (rather than with its class color).
     *
     * @param tss The TMAspots whose nuclei are to be drawn (both gold-standard
     * and estimated nuclei).
     */
    void drawNucleiIntensities3DSinglets2(List<TMAspot> tss) {
        // draw the plot
        Plot3DPanel plot;
        if (((java.awt.BorderLayout) (jPanel2.getLayout()))
                .getLayoutComponent(java.awt.BorderLayout.CENTER) != null) {
            plot = (Plot3DPanel) ((java.awt.BorderLayout) (jPanel2.getLayout()))
                    .getLayoutComponent(java.awt.BorderLayout.CENTER);
            plot.removeAllPlots();
        } else {
            plot = new Plot3DPanel();
            plot.plotCanvas.setBackground(jPanel2.getBackground());
            plot.plotToolBar.setBackground(plot.plotCanvas.getBackground());
            plot.addLegend(PlotPanel.SOUTH);
            plot.plotLegend.setBackground(jPanel2.getBackground());
        }
        plot.plotLegend.setVisible(false);
        String colorSpace = getParam_ColorSpace();
        if (colorSpace.equalsIgnoreCase("hsb")) {
            plot.setAxisLabels("Hue", "Saturation", "Brightness");
        } else if (colorSpace.equalsIgnoreCase("rtp")) {
            plot.setAxisLabels("R", "Theta", "Phi");
        } else {
            plot.setAxisLabels("Red", "Green", "Blue");
        }
        if (((java.awt.BorderLayout) (jPanel2.getLayout()))
                .getLayoutComponent(java.awt.BorderLayout.CENTER) == null) {
            jPanel2.add(plot, java.awt.BorderLayout.CENTER);
            validate();
            pack();
        }

        if (tss.size() > 0) {
            try {
                this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

                Color c;
                BufferedImage img;
                float[] features = new float[3];
                double[] xs_0 = new double[1];
                double[] ys_0 = new double[1];
                double[] zs_0 = new double[1];
                for (TMAspot ts : tss) {
                    img = ts.getBufferedImage();
                    List<TMApoint> tps = ts.getPoints();
                    for (TMApoint tp : tps) {
                        c = TMAspot.getAverageColorAtPoint(img, tp.x, tp.y, ts.getParam_r(), false);
                        Color2Feature(c, colorSpace, features);

                        xs_0[0] = features[0];
                        ys_0[0] = features[1];
                        zs_0[0] = features[2];

                        plot.addScatterPlot(null, c, xs_0, ys_0, zs_0);
                    }
                }

            } finally {
                this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            }
        }
    }

    /**
     * Draws the 3D Plot in the IntensityClustering. Axis are color values
     * (either RGB or HSB), points are nuclei. Each nucleus is displayed with its color (rather than with its class color).
     *
     * @param tss The TMAspots whose nuclei are to be drawn (both gold-standard
     * and estimated nuclei).
     */
    void drawNucleiIntensities3DSinglets(List<TMAspot> tss) {
        // draw the plot
        Plot3DPanel plot;
        if (((java.awt.BorderLayout) (jPanel2.getLayout()))
                .getLayoutComponent(java.awt.BorderLayout.CENTER) != null) {
            plot = (Plot3DPanel) ((java.awt.BorderLayout) (jPanel2.getLayout()))
                    .getLayoutComponent(java.awt.BorderLayout.CENTER);
            plot.removeAllPlots();
        } else {
            plot = new Plot3DPanel();
            plot.plotCanvas.setBackground(jPanel2.getBackground());
            plot.plotToolBar.setBackground(plot.plotCanvas.getBackground());
            plot.addLegend(PlotPanel.SOUTH);
            plot.plotLegend.setBackground(jPanel2.getBackground());
        }
        plot.plotLegend.setVisible(false);
        String colorSpace = getParam_ColorSpace();
        if (colorSpace.equalsIgnoreCase("hsb")) {
            plot.setAxisLabels("Hue", "Saturation", "Brightness");
        } else if (colorSpace.equalsIgnoreCase("rtp")) {
            plot.setAxisLabels("R", "Theta", "Phi");
        } else {
            plot.setAxisLabels("Red", "Green", "Blue");
        }
        if (((java.awt.BorderLayout) (jPanel2.getLayout()))
                .getLayoutComponent(java.awt.BorderLayout.CENTER) == null) {
            jPanel2.add(plot, java.awt.BorderLayout.CENTER);
            validate();
            pack();
        }

        if (tss.size() > 0) {
            try {
                this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

                BufferedImage img;
                for (TMAspot ts : tss) {
                    img = ts.getBufferedImage();
                    List<TMApoint> tps = ts.getPoints();
                    DrawNucleiIntensitySingletsFork.DrawNucleiIntensitySinglets_Fork((TMARKERPluginManager) manager,
                            this, ts, img, tps, colorSpace, plot);
                }

            } finally {
                this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            }
        }
    }

    static NucleusIntensity3DSinglet drawNucleiIntensity3DSingletsCore(TMAspot ts, BufferedImage img, TMApoint tp,
            String colorSpace, Plot3DPanel plot) {
        float[] features = new float[3];
        Color c = TMAspot.getAverageColorAtPoint(img, tp.x, tp.y, ts.getParam_r(), false);
        Color2Feature(c, colorSpace, features);

        return (new NucleusIntensity3DSinglet(c, features));

        //plot.addScatterPlot(null, c, new double[]{features[0]}, new double[]{features[1]}, new double[]{features[2]});
    }

    /**
     * Adopt the mean colors of already labeled nuclei as cluster centers for
     * the stainings.
     */
    public void adoptMeanIntensities() {
        int n = 4; //getParam_nClusters();
        if (manager.getVisibleTMAspot() != null) {
            byte staining;
            for (int i = 0; i < n; i++) {
                staining = i == 0 ? TMALabel.STAINING_0
                        : i == 1 ? TMALabel.STAINING_1 : i == 2 ? TMALabel.STAINING_2 : TMALabel.STAINING_3;
                setParam_ColorOfClassK(i, manager.getVisibleTMAspot().getAverageColor(staining, false, false));
            }
        }
    }

    /**
     * Adopt the intensities of the "Unknown" points from TMARKER settings as
     * cluster centers for the stainings.
     */
    public void adoptUnkownPointsIntensities() {
        int n = 4; //getParam_nClusters();
        byte staining;
        for (int i = 0; i < n; i++) {
            staining = i == 0 ? TMALabel.STAINING_0
                    : i == 1 ? TMALabel.STAINING_1 : i == 2 ? TMALabel.STAINING_2 : TMALabel.STAINING_3;
            setParam_ColorOfClassK(i, manager.getLabelsColor(TMALabel.LABEL_UNK, staining));
        }
    }

    /**
     * Clusters the TMApoints on given TMAspots according to their staining
     * intensity (color) and according to the center points given by the user
     * (as colors). All parameters (e.g. clusterer and parameters) are selected
     * by the user. Features are simple color features.
     *
     * @param tss The TMAspots of which all nuclei (gold-standard and estimated)
     * are clustered according to color.
     */
    private void clusterPointsManually(List<TMAspot> tss) {
        if (tss.size() > 0) {
            try {
                tmarker t = tss.get(0).getCenter();
                this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

                int n = getParam_nClusters();
                double[][] centers = new double[n][3];
                Color c;
                float[] features = new float[3];
                String colorSpace = getParam_ColorSpace();
                for (int i = 0; i < n; i++) {
                    Color2Feature(getParam_ColorOfClassK(i), colorSpace, features);
                    centers[i][0] = features[0];
                    centers[i][1] = features[1];
                    centers[i][2] = features[2];
                }

                // Cluster the points
                List<List<Color>> clustered_points = new ArrayList<>();
                for (int i = 0; i < n; i++) {
                    clustered_points.add(new ArrayList<Color>());
                }

                BufferedImage img;
                double[] dists = new double[n];
                int k;
                for (TMAspot ts : tss) {
                    img = ts.getBufferedImage();
                    List<TMApoint> tps = ts.getPoints();
                    for (TMApoint tp : tps) {
                        c = TMAspot.getAverageColorAtPoint(img, tp.x, tp.y, ts.getParam_r(), false);
                        Color2Feature(c, colorSpace, features);
                        // calculate distance to center
                        for (int i = 0; i < n; i++) {
                            dists[i] = Misc.Euclidean_distance(
                                    new double[] { features[0], features[1], features[2] }, centers[i]);
                        }
                        // find the min dist
                        k = Misc.min_arg(dists);
                        // assign the point to the class ind
                        byte staining = k == 0 ? TMALabel.STAINING_0
                                : k == 1 ? TMALabel.STAINING_1 : k == 2 ? TMALabel.STAINING_2 : TMALabel.STAINING_3;
                        tp.setStaining(staining);
                        // store the color for later visualization
                        clustered_points.get(k).add(c);
                    }
                    ts.dispStainingInfo();
                    if (t.getVisibleTMAspot() == ts) {
                        t.getTMAView().repaint();
                    }
                }

                // draw the points
                Plot3DPanel plot;
                if (((java.awt.BorderLayout) (jPanel2.getLayout()))
                        .getLayoutComponent(java.awt.BorderLayout.CENTER) != null) {
                    plot = (Plot3DPanel) ((java.awt.BorderLayout) (jPanel2.getLayout()))
                            .getLayoutComponent(java.awt.BorderLayout.CENTER);
                    plot.removeAllPlots();
                } else {
                    plot = new Plot3DPanel();
                    plot.plotCanvas.setBackground(jPanel2.getBackground());
                    plot.addLegend(PlotPanel.SOUTH);
                    plot.plotLegend.setBackground(jPanel2.getBackground());
                }
                if (colorSpace.equalsIgnoreCase("hsb")) {
                    plot.setAxisLabels("Hue", "Saturation", "Brightness");
                } else if (colorSpace.equalsIgnoreCase("rtp")) {
                    plot.setAxisLabels("R", "Theta", "Phi");
                } else {
                    plot.setAxisLabels("Red", "Green", "Blue");
                }

                for (int i = 0; i < n; i++) {
                    double[] xs = new double[clustered_points.get(i).size()];
                    double[] ys = new double[clustered_points.get(i).size()];
                    double[] zs = new double[clustered_points.get(i).size()];
                    for (int j = 0; j < clustered_points.get(i).size(); j++) {
                        Color2Feature(clustered_points.get(i).get(j), colorSpace, features);
                        xs[j] = features[0];
                        ys[j] = features[1];
                        zs[j] = features[2];
                    }
                    if (xs.length > 0) {
                        c = getParam_ColorOfClassK(i);
                        plot.addScatterPlot("Cluster " + (i + 1), c, xs, ys, zs);
                    }
                }

                // add cluster Centers defined by the user
                for (int i = 0; i < n; i++) {
                    c = getParam_ColorOfClassK(i);
                    Color2Feature(c, colorSpace, features);
                    plot.addScatterPlot("Center " + (i + 1), c.darker(), new double[] { features[0] },
                            new double[] { features[1] }, new double[] { features[2] });
                }

                // Write the description
                String description = "Nuclei clustered to manual center points with K-Nearest Neighbor";
                description += ", n=" + getParam_nClusters() + ", color space " + getParam_ColorSpace() + ".";
                jLabel41.setText(description);
                jLabel42.setText(" ");

                if (((java.awt.BorderLayout) (jPanel2.getLayout()))
                        .getLayoutComponent(java.awt.BorderLayout.CENTER) == null) {
                    jPanel2.add(plot, java.awt.BorderLayout.CENTER);
                    validate();
                    pack();
                }
            } finally {
                this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            }
        }
    }

    /**
     * Clusters the TMApoints on given TMAspots according to their staining
     * intensity (color). All parameters (e.g. clusterer and parameters) are
     * selected by the user. Features are simple color features.
     *
     * @param tss The TMAspots of which all nuclei (gold-standard and estimated)
     * are clustered according to color.
     */
    private void clusterPointsAutomaticallyColorSpace(List<TMAspot> tss) {
        if (tss.size() > 0) {
            try {
                this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

                int n = getParam_nClusters();

                // Create ARFF Data
                FastVector atts;
                Instances data;
                int i;

                // 1. create arff data format
                atts = new FastVector(3);
                for (i = 0; i < 3; i++) {
                    atts.addElement(new Attribute(Integer.toString(i)));
                }

                // 2. create Instances object
                data = new Instances("TMA points", atts, tmarker.getNumberNuclei(tss));

                // 3. fill with data
                BufferedImage img;
                Color c;
                float[] features = new float[3];
                String colorSpace = getParam_ColorSpace();
                for (TMAspot ts : tss) {
                    img = ts.getBufferedImage();
                    List<TMApoint> tps = ts.getPoints();
                    for (TMApoint tp : tps) {
                        Color2Feature(TMAspot.getAverageColorAtPoint(img, tp.x, tp.y, ts.getParam_r(), false),
                                colorSpace, features);

                        // add the instance
                        Instance inst = new Instance(1.0, new double[] { features[0], features[1], features[2] });
                        inst.setDataset(data);
                        data.add(inst);
                    }
                }

                // 4. set data class index (last attribute is the class)
                //data.setClassIndex(data.numAttributes() - 1); // not for weka 3.5.X
                if (tmarker.DEBUG > 4) {
                    java.util.logging.Logger.getLogger(getClass().getName()).log(java.util.logging.Level.INFO,
                            data.toString());
                }

                Clusterer clusterer = getClusterer();
                String[] options = getClustererOptions();
                if (false && colorSpace.equalsIgnoreCase("hsb")) {
                    String[] newoptions = new String[options.length + 2];
                    System.arraycopy(options, 0, newoptions, 0, options.length);
                    newoptions[options.length] = "-A";
                    newoptions[options.length + 1] = "weka.core.MyHSBDistance";
                    options = newoptions;
                }

                if (tmarker.DEBUG > 3) {
                    if (options.length > 0) {
                        String info = "Clusterer should have options\n";
                        for (String o : options) {
                            info += o + " ";
                        }
                        info += "\n";
                        java.util.logging.Logger.getLogger(getClass().getName()).log(java.util.logging.Level.INFO,
                                info);
                    }
                }

                clusterer.setOptions(options); // set the clusterer options
                clusterer.buildClusterer(data); // build the clusterer

                // order the clusters according to the brightness
                // The most bright cluster should be 0, then 1, then 2,...
                ArrayList<ArrayList<Double>> values = new ArrayList<>();
                for (i = 0; i < clusterer.numberOfClusters(); i++) {
                    values.add(new ArrayList<Double>());
                }
                int z;
                double value;
                for (i = 0; i < data.numInstances(); i++) {
                    z = clusterer.clusterInstance(data.instance(i));
                    value = getParam_ColorSpace().equalsIgnoreCase("hsb") ? data.instance(i).value(2)
                            : Misc.RGBToGray(data.instance(i).value(0), data.instance(i).value(1),
                                    data.instance(i).value(2));
                    values.get(z).add(value);
                }
                double[] means = new double[clusterer.numberOfClusters()];
                for (i = 0; i < clusterer.numberOfClusters(); i++) {
                    means[i] = Misc.mean(values.get(i).toArray(new Double[values.get(i).size()]));
                }
                int[] ordering = Misc.orderArray(means, !getParam_ColorSpace().equalsIgnoreCase("rtp"));

                String clusterInfo = "";
                for (String o : clusterer.getOptions()) {
                    clusterInfo += o + " ";
                }
                clusterInfo += "\n\n";
                clusterInfo += clusterer.toString().trim();
                if (getParam_AutomaticClustererString().equalsIgnoreCase("Hierarchical")) {
                    try {
                        clusterInfo += ((HierarchicalClusterer) clusterer).graph();
                        HierarchyVisualizer a = new HierarchyVisualizer(
                                ((HierarchicalClusterer) clusterer).graph());
                        a.setSize(800, 600);
                        if (clusterVisualizer == null) {
                            clusterVisualizer = new JFrame("Hierarchical Clusterer Dendrogram");
                            clusterVisualizer.setIconImage(getIconImage());
                            clusterVisualizer.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                            clusterVisualizer.setSize(800, 600);
                        }
                        Container contentPane = clusterVisualizer.getContentPane();
                        contentPane.removeAll();
                        contentPane.add(a);
                    } catch (Exception e) {
                        clusterVisualizer = null;
                    }
                }
                jTextArea1.setText(clusterInfo);

                if (tmarker.DEBUG > 3) {
                    String info = "Clusterer has options\n";
                    for (String o : clusterer.getOptions()) {
                        info += o + " ";
                    }
                    info += "\n";
                    info += clusterer.toString() + "\n";
                    // info += (clusterer).globalInfo() + "\n";
                    info += "\n";
                    info += clusterInfo + "\n";
                    java.util.logging.Logger.getLogger(getClass().getName()).log(java.util.logging.Level.INFO,
                            info);
                }

                // cluster all TMAspots and assign the corresponding class to them
                // Cluster the points
                List<List<Color>> clustered_points = new ArrayList<>();
                for (i = 0; i < clusterer.numberOfClusters(); i++) {
                    clustered_points.add(new ArrayList<Color>());
                }

                int k;
                for (TMAspot ts : tss) {
                    img = ts.getBufferedImage();
                    List<TMApoint> tps = ts.getPoints();
                    for (TMApoint tp : tps) {
                        c = TMAspot.getAverageColorAtPoint(img, tp.x, tp.y, ts.getParam_r(), false);
                        Color2Feature(c, colorSpace, features);

                        // add the instance
                        Instance inst = new Instance(1.0, new double[] { features[0], features[1], features[2] });
                        inst.setDataset(data);
                        k = ordering[clusterer.clusterInstance(inst)];

                        // store the color for later visualization
                        clustered_points.get(k).add(c);

                        // set the staining of the TMApoint
                        switch (k) {
                        case 0:
                            tp.setStaining(TMALabel.STAINING_0);
                            break;
                        case 1:
                            tp.setStaining(TMALabel.STAINING_1);
                            break;
                        case 2:
                            tp.setStaining(TMALabel.STAINING_2);
                            break;
                        default:
                            tp.setStaining(TMALabel.STAINING_3);
                            break;
                        }
                    }
                    ts.dispStainingInfo();
                    if (manager.getVisibleTMAspot() == ts) {
                        manager.repaintVisibleTMAspot();
                    }
                }

                // draw the points
                Plot3DPanel plot;
                if (((java.awt.BorderLayout) (jPanel2.getLayout()))
                        .getLayoutComponent(java.awt.BorderLayout.CENTER) != null) {
                    plot = (Plot3DPanel) ((java.awt.BorderLayout) (jPanel2.getLayout()))
                            .getLayoutComponent(java.awt.BorderLayout.CENTER);
                    plot.removeAllPlots();
                } else {
                    plot = new Plot3DPanel();
                    plot.plotCanvas.setBackground(jPanel2.getBackground());
                    plot.addLegend(PlotPanel.SOUTH);
                    plot.plotLegend.setBackground(jPanel2.getBackground());
                }
                if (colorSpace.equalsIgnoreCase("hsb")) {
                    plot.setAxisLabels("Hue", "Saturation", "Brightness");
                } else if (colorSpace.equalsIgnoreCase("rtp")) {
                    plot.setAxisLabels("R", "Theta", "Phi");
                } else {
                    plot.setAxisLabels("Red", "Green", "Blue");
                }

                for (i = 0; i < clusterer.numberOfClusters(); i++) {
                    double[] xs = new double[clustered_points.get(i).size()];
                    double[] ys = new double[clustered_points.get(i).size()];
                    double[] zs = new double[clustered_points.get(i).size()];
                    for (int j = 0; j < clustered_points.get(i).size(); j++) {
                        Color2Feature(clustered_points.get(i).get(j), colorSpace, features);
                        xs[j] = features[0];
                        ys[j] = features[1];
                        zs[j] = features[2];
                    }
                    if (xs.length > 0) {
                        c = getParam_ColorOfClassK(i);
                        plot.addScatterPlot("Staining " + i, c, xs, ys, zs);
                    }
                }

                // Write the description
                String description = "Nuclei clustered with " + getParam_AutomaticClustererString();
                if (getParam_AutomaticClustererString().equalsIgnoreCase("Hierarchical")) {
                    description += " (" + getParam_HierarchicalClusteringMethod() + ")";
                }
                description += ", n=" + getParam_nClusters() + ", color space " + getParam_ColorSpace() + ".";
                jLabel41.setText(description);
                jLabel42.setText(" ");

                if (((java.awt.BorderLayout) (jPanel2.getLayout()))
                        .getLayoutComponent(java.awt.BorderLayout.CENTER) == null) {
                    jPanel2.add(plot, java.awt.BorderLayout.CENTER);
                    validate();
                    pack();
                }
            } catch (Exception | OutOfMemoryError e) {
                java.util.logging.Logger.getLogger(getClass().getName()).log(java.util.logging.Level.SEVERE, null,
                        e);
                JOptionPane.showMessageDialog(this,
                        "The clustering could not be performed.\n\n" + "A possible reasons is:\n"
                                + "- Not enough memory (too many points), \n\n"
                                + "You might want to try a different clustering method or less TMAspots.\n\n"
                                + "The error message is: \n" + e.getMessage(),
                        "Error at Nucleus clustering", JOptionPane.WARNING_MESSAGE);
            } finally {
                this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            }
        }
    }

    /**
     * Displays the dendrogram of the hierarchical clusterer, if any.
     */
    private void displayDendrogram() {
        if (clusterVisualizer != null) {
            clusterVisualizer.setVisible(true);
        } else {
            JOptionPane.showMessageDialog(this,
                    "A dendrogram has not been created, yet,\n" + "or could not be computed.");
        }
    }

    /**
     * Saves the current cluster centers into a file which the users chooses.
     */
    private void saveClusterCenters() {

        int n = getParam_nClusters();

        ArrayList exts = new ArrayList();
        ArrayList descs = new ArrayList();
        exts.add("txt");
        descs.add("Text file");
        File file = FileChooser.chooseSavingFile(null, "", "clusters.txt", exts, descs);
        String sep = ";";

        if (file != null) {
            BufferedWriter writer = null;
            try {
                writer = new BufferedWriter(new FileWriter(file));
                for (int i = 0; i < n; i++) {
                    Color c = getParam_ColorOfClassK(i);
                    writer.write(Integer.toString(c.getRed()) + sep);
                    writer.write(Integer.toString(c.getGreen()) + sep);
                    writer.write(Integer.toString(c.getBlue()));
                    writer.newLine();
                }
            } catch (IOException ex) {
                Logger.getLogger(IntensityClustering.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                try {
                    writer.close();
                } catch (IOException ex) {
                    Logger.getLogger(IntensityClustering.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    /**
     * Loads cluster centers and sets into the plugin. They can be used for manual clustering.
     */
    private void loadClusterCenters() {
        ArrayList exts = new ArrayList();
        ArrayList descs = new ArrayList();
        exts.add("txt");
        descs.add("Text file");
        File file = FileChooser.chooseLoadingFile(null, "", exts, descs);
        String sep = ";";

        if (file != null) {
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new FileReader(file));
                int n = 0;
                String line;
                Color c;
                while (reader.ready() && !(line = reader.readLine()).isEmpty()) {
                    String[] split = line.split(sep);
                    c = new Color(Integer.parseInt(split[0]), Integer.parseInt(split[1]),
                            Integer.parseInt(split[2]));
                    setParam_ColorOfClassK(n, c);
                    n++;
                }
                setParam_nClusters(n);
            } catch (IOException ex) {
                Logger.getLogger(IntensityClustering.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                try {
                    reader.close();
                } catch (IOException ex) {
                    Logger.getLogger(IntensityClustering.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }

        int n = getParam_nClusters();
        double[][] centers = new double[n][3];
        float[] features = new float[3];
        String colorSpace = getParam_ColorSpace();
        for (int i = 0; i < n; i++) {
            Color2Feature(getParam_ColorOfClassK(i), colorSpace, features);
            centers[i][0] = features[0];
            centers[i][1] = features[1];
            centers[i][2] = features[2];
        }

    }

    /**
     * Returns a new weka clusterer used for nucleus staining intensity
     * clustering. The kind of clusterer is determined by the user.
     *
     * @return A new weka clusterer.
     */
    private Clusterer getClusterer() {
        String clustername = getParam_AutomaticClustererString();
        Clusterer clusterer = null;
        if (clustername.equalsIgnoreCase("K-Means")) {
            clusterer = new SimpleKMeans();
        } else if (clustername.equalsIgnoreCase("Hierarchical")) {
            clusterer = new HierarchicalClusterer();
        } else if (clustername.equalsIgnoreCase("EM")) {
            clusterer = new EM();
        } else {
            clusterer = new FarthestFirst();
        }
        return clusterer;
    }

    /**
     * Returns the name of the selected clusterer.
     *
     * @return A name of the clusterer (One of "K-Means", "Hierarchical", "EM"
     * or "Farthest First").
     */
    public String getParam_AutomaticClustererString() {
        String clustername = "Farthest First";
        if (jRadioButton1.isSelected()) {
            clustername = "K-Means";
        } else if (jRadioButton2.isSelected()) {
            clustername = "Hierarchical";
        } else if (jRadioButton5.isSelected()) {
            clustername = "EM";
        }
        return clustername;
    }

    /**
     * Sets the name of the selected clusterer.
     *
     * @param name A name of the clusterer (One of "K-Means", "Hierarchical",
     * "EM" or "Farthest First").
     */
    public void setParam_AutomaticClustererString(String name) {
        jRadioButton1.setSelected(name.equalsIgnoreCase("K-Means"));
        jRadioButton2.setSelected(name.equalsIgnoreCase("Hierarchical"));
        jRadioButton5.setSelected(name.equalsIgnoreCase("EM"));
        jRadioButton6.setSelected(name.equalsIgnoreCase("Farthest First"));
    }

    /**
     * Returns clusterer options for the weka clustering algorithm.
     *
     * @return Options for the clustering algorithm. These might be changed by
     * the user in the program.
     */
    private String[] getClustererOptions() {
        String[] options = null;
        // SimpleKMeans
        if (jRadioButton1.isSelected()) {
            options = new String[3];
            options[0] = "-N"; // Number clusters
            options[1] = Integer.toString(getParam_nClusters());
            options[2] = "-V";
            // Hierarchical Clustering
        } else if (jRadioButton2.isSelected()) {
            options = new String[4];
            options[0] = "-N"; // Number clusters
            options[1] = Integer.toString(getParam_nClusters());
            options[2] = "-L"; // Number clusters
            options[3] = (String) jComboBox2.getSelectedItem();
        } else {
            options = new String[2];
            options[0] = "-N"; // Number clusters
            options[1] = Integer.toString(getParam_nClusters());
        }
        return options;// build clusterer                
    }

    /**
     * Returns the text written in the WEKA clusterer output information of the
     * automatic intensity clustering.
     *
     * @return The text in jTextArea1.
     */
    public String getClustererInfo() {
        return jTextArea1.getText();
    }

    /**
     * Whether or not manual clustering should be done (indicated by the user).
     *
     * @return If true, manual clustering should be done, automatic clustering
     * otherwise.
     */
    private boolean isManualClustering() {
        return jRadioButton3.isSelected();
    }

    /**
     * Returns the description of the recent clustering method (the red headline
     * text of the two plots).
     *
     * @return The description of the current clustering method. "-", if no
     * clustering is done.
     */
    public String getClusteringDescription() {
        String description = "-";
        if (!jLabel41.getText().trim().isEmpty()) {
            description = jLabel41.getText().trim();
        }
        if (!jLabel42.getText().trim().isEmpty()) {
            description = jLabel42.getText().trim();
        }
        return description;
    }

    /**
     * Returns the 3D Plot of the nucleus intensity distribution.
     *
     * @return The 3D Plot of the nucleus intensity distribution.
     */
    public BufferedImage get3DPlot() {
        return Misc.getScreenShot(jPanel2);
    }

    /**
     * Returns the 2D Plot of the nucleus intensity histogram.
     *
     * @return The 2D Plot of the nucleus intensity histogram.
     */
    public BufferedImage get2DPlot() {
        return Misc.getScreenShot(jPanel9);
    }

    /**
     * Returns a feature vector for a given color.
     *
     * @param c The color to be processed.
     * @param colorSpace If "rgb", the color is directly used. If "hsb", the c
     * is first converted to HSB. If "rtp" the color is first converted to r
     * theta phi.
     * @param feature The container in which the feature is written. If null or
     * length is smaller than 3, a new container is created.
     * @return The container of the feature (length 3).
     */
    static float[] Color2Feature(Color c, String colorSpace, float[] feature) {
        if (feature == null || feature.length < 3) {
            feature = new float[3];
        }
        if (colorSpace.equalsIgnoreCase("hsb")) {
            Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), feature);
        } else if (colorSpace.equalsIgnoreCase("rtp")) {
            RGBtoRTP(c.getRed(), c.getGreen(), c.getBlue(), feature);
        } else {
            feature[0] = c.getRed();
            feature[1] = c.getGreen();
            feature[2] = c.getBlue();
        }
        return (feature);
    }

    /**
     * Converts a RGB color to r theta phi.
     *
     * @param r The red value (0-255).
     * @param g The red value (0-255).
     * @param b The red value (0-255).
     * @param container the rtp value is stored here. If Null or length less
     * then 3, a new float array is created.
     * @return A float array with the r theta phi values calculated from r g b.
     */
    static float[] RGBtoRTP(int r, int g, int b, float[] container) {
        if (container == null || container.length < 3) {
            container = new float[3];
        }

        double r_double = 1.0 * r;
        double g_double = 1.0 * g;
        double b_double = 1.0 * b;

        double rad = Math.sqrt(Math.pow(r_double, 2) + Math.pow(g_double, 2) + Math.pow(b_double, 2));

        double theta_deg;
        if (r_double == 0) {
            theta_deg = 0;
        } else {
            double p = g_double / r_double;
            double theta = Math.atan(p);
            theta_deg = Math.toDegrees(theta);
        }

        double phi_deg;
        if (rad == 0) {
            phi_deg = 0;
        } else {
            double q = Math.sqrt(Math.pow(r_double, 2) + Math.pow(g_double, 2)) / rad;
            double phi = Math.asin(q);
            phi_deg = Math.toDegrees(phi);
        }

        container[0] = (float) (rad);
        container[1] = (float) (theta_deg);
        container[2] = (float) (phi_deg);

        return (container);
    }

    /**
     * Converts a r theta phi color to RGB.
     *
     * @param rad The radius value (double).
     * @param theta The theta angle (double).
     * @param phi The phi angle (double).
     * @param container the RGB value is stored here. If Null or length less
     * then 3, a new float array is created.
     * @return A float array with the RGB (0-255) values calculated from r theta phi values.
     */
    static float[] RTPtoRGB(double rad, double theta, double phi, float[] container) {
        if (container == null || container.length < 3) {
            container = new float[3];
        }

        double theta_rad = Math.toRadians(1.0 * theta);
        double phi_rad = Math.toRadians(1.0 * phi);

        container[0] = (float) Math.round(rad * Math.cos(theta_rad) * Math.sin(phi_rad));
        container[1] = (float) Math.round(rad * Math.sin(theta_rad) * Math.sin(phi_rad));
        container[2] = (float) Math.round(rad * Math.cos(phi_rad));

        return (container);
    }

    /**
     * Returns which color space should be used for clustering (RGB, HSB or R
     * THETA PHI), as indicated by the user.
     *
     * @return "HSB", if the HSB Color space should be used. "RGB" for RGB
     * space. "RTP" for r theta phi space.
     */
    public String getParam_ColorSpace() {
        if (jRadioButton7.isSelected()) {
            return "RGB";
        }
        if (jRadioButton8.isSelected()) {
            return "HSB";
        }
        return "RTP";
    }

    /**
     * Sets the color space to be used for clustering (RGB, HSB or R THETA PHI).
     *
     * @param colorSpace "HSB", if the HSB Color space should be used. "RGB" for
     * RGB space. "RTP" for r theta phi space.
     */
    public void setParam_ColorSpace(String colorSpace) {
        if (colorSpace.equalsIgnoreCase("RGB")) {
            jRadioButton7.setSelected(true);
        } else if (colorSpace.equalsIgnoreCase("HSB")) {
            jRadioButton8.setSelected(true);
        } else {
            jRadioButton13.setSelected(true);
        }
        dispayed3DColorSpace = colorSpace.toLowerCase();
    }

    /**
     * Returns the color of the class labels in the visualization plots.
     *
     * @param k The class of which the color is wanted (starts with 0).
     * @return The color of the nuclei in class k.
     */
    public Color getParam_ColorOfClassK(int k) {
        return ((JXColorSelectionButton) jPanel8.getComponent(k)).getBackground();
    }

    /**
     * Sets the color of the class labels in the visualization plots.
     *
     * @param k The class of which the color is set (starts with 0).
     * @param c The color of the nuclei in class k.
     */
    public void setParam_ColorOfClassK(int k, Color c) {
        ((JXColorSelectionButton) jPanel8.getComponent(k)).setBackground(c);
    }

    /**
     * Returns the index of the selected nucleus intensity clustering method.
     *
     * @return 0 for manual clustering, 1 for automatic clustering.
     */
    public int getParam_ManualAutomaticClustering() {
        int i = 0;
        if (jRadioButton4.isSelected()) {
            i = 1;
        }
        return i;
    }

    /**
     * Sets the index of the selected nucleus intensity clustering method.
     *
     * @param i 0 for manual clustering, 1 for automatic clustering.
     */
    public void setParam_ManualAutomaticClustering(int i) {
        jRadioButton3.setSelected(i == 0);
        jRadioButton4.setSelected(i == 1);
    }

    /**
     * Returns the selected method for the hierarchical intensity clusterer.
     *
     * @return The selected method for the hierarchical intensity clusterer.
     */
    public String getParam_HierarchicalClusteringMethod() {
        return (String) (jComboBox2.getSelectedItem());
    }

    /**
     * Sets the method for the hierarchical intensity clusterer.
     *
     * @param method The method for the hierarchical intensity clusterer.
     */
    public void setParam_HierarchicalClusteringMethod(String method) {
        jComboBox2.setSelectedItem(method);
    }

    /**
     * Returns the number of clusters used for nucleus intensity clustering.
     *
     * @return The number of clusters.
     */
    public int getParam_nClusters() {
        int n = 1;
        for (Component c : jPanel17.getComponents()) {
            if (((JRadioButton) c).isSelected()) {
                return n;
            } else {
                n++;
            }
        }
        return n;
    }

    /**
     * Sets the number of clusters used for nucleus intensity clustering.
     *
     * @param n The number of clusters.
     */
    public void setParam_nClusters(int n) {
        ((JRadioButton) jPanel17.getComponent(Math.max(0, Math.min(n - 1, jPanel17.getComponentCount()))))
                .setSelected(true);
    }

    /**
     * Refreshes the intensity panel with the given list of TMAspots, i.e.
     * redraws the 3D plot and the 2D plot.
     *
     * @param tss The list of TMAspots whose TMApoints are considered (should be
     * the currently selected TMAspots).
     */
    void updateIntensityPanelToTMAspots(List<TMAspot> tss) {
        if (tss != null && (current_TMAspots_Intensity == null || !current_TMAspots_Intensity.containsAll(tss)
                || !tss.containsAll(current_TMAspots_Intensity))) {
            //adoptMeanIntensities();
            drawNucleiIntensities2D(tss, false);
            drawNucleiIntensities3D(tss);
            current_TMAspots_Intensity = tss;
        }
    }

    /**
     * Sets all necessary parameters to the values of the selected TMAspots.
     *
     * @param t The tmarker program from which the TMAspots are taken. Null
     * allowed.
     */
    public void updateOptionsToTMAspot(tmarker t) {
        if (t != null) {
            updateIntensityPanelToTMAspots(t.getSelectedTMAspots(false));
            pack();
        }
    }

}