Skip to content

Commit

Permalink
Display dendrograms
Browse files Browse the repository at this point in the history
  • Loading branch information
sumanthreddy542 committed Aug 1, 2021
1 parent 26b5319 commit 925788f
Show file tree
Hide file tree
Showing 6 changed files with 187 additions and 8 deletions.
117 changes: 117 additions & 0 deletions src/edu/iastate/metnet/metaomgraph/chart/DendrogramChart.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/**
*
*/
package edu.iastate.metnet.metaomgraph.chart;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.HashMap;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.filechooser.FileNameExtensionFilter;

import com.apporiented.algorithm.clustering.visualization.DendrogramPanel;

import edu.iastate.metnet.metaomgraph.AnimatedSwingWorker;
import edu.iastate.metnet.metaomgraph.FrameModel;
import edu.iastate.metnet.metaomgraph.MetaOmGraph;
import edu.iastate.metnet.metaomgraph.ui.TaskbarInternalFrame;

/**
* @author sumanth
* Dendrogram chart panel to display the heatmap chart dendrogram
*
*/
public class DendrogramChart extends TaskbarInternalFrame{
private DendrogramPanel dendrogramPanel;

JScrollPane scrollPane;

// toolbar buttons
private JButton save;

/**
* Constructor
* @param dendrogramPanel
*/
public DendrogramChart(DendrogramPanel dendrogramPanel) {
this.dendrogramPanel = dendrogramPanel;

setBounds(100, 100, 450, 300);
getContentPane().setLayout(new BorderLayout(0, 0));

JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
getContentPane().add(panel, BorderLayout.NORTH);

scrollPane = new JScrollPane();
getContentPane().add(scrollPane, BorderLayout.CENTER);
scrollPane.setViewportView(dendrogramPanel);

save = new JButton(MetaOmGraph.getIconTheme().getSaveAs());
save.setToolTipText("Save Chart as Image");
save.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
saveImage();
}
});
panel.add(save);
this.setClosable(true);
putClientProperty("JInternalFrame.frameType", "normal");
setResizable(true);
setMaximizable(true);
setIconifiable(true);
setClosable(true);
this.setTitle("Dendrogram chart");
FrameModel dendrogramPlotFrameModel = new FrameModel("Dendrogram Plot", "Dendrogram plot", 8);
setModel(dendrogramPlotFrameModel);
}

// Save the chart as image
private void saveImage() {
HashMap<String, String> fileTypes = new HashMap<String, String>();
fileTypes.put("PNG", ".png");
JFileChooser fileSave = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter("PNG files", "png");
fileSave.addChoosableFileFilter(filter);

if(fileSave.showSaveDialog(MetaOmGraph.getMainWindow()) == JFileChooser.APPROVE_OPTION){
new AnimatedSwingWorker("Saving image...", true) {

@Override
public Object construct() {
File fileToSave = fileSave.getSelectedFile();
if (!fileToSave.getName().toLowerCase().endsWith(".png")) {
fileToSave = new File(fileToSave.getParentFile(), fileToSave.getName() + ".png");
}
BufferedImage image = new BufferedImage(dendrogramPanel.getWidth(),dendrogramPanel.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = image.createGraphics();
dendrogramPanel.paint(g2);
try{
ImageIO.write(image, "png", fileToSave);
JOptionPane.showMessageDialog(MetaOmGraph.getMainWindow(),
"Image saved", "File saved", JOptionPane.INFORMATION_MESSAGE);
} catch (Exception e) {
JOptionPane.showMessageDialog(MetaOmGraph.getMainWindow(),
"Image not saved", "File save error", JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
return false;
}
return null;
}
}.start();
}
}

}
48 changes: 44 additions & 4 deletions src/edu/iastate/metnet/metaomgraph/chart/HeatMapChart.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ public class HeatMapChart extends TaskbarInternalFrame implements ActionListener
private JScrollPane scrollPane;
private JButton bottomPanelButton;

private double minValue;
private boolean clusteredRows;
private HierarchicalClusterData clusteredData;
private boolean transposeData;
private boolean sampleDataOnRow;
private Map<String, Collection<Integer>> splitIndex;
Expand Down Expand Up @@ -395,7 +396,7 @@ else if(col_val.equals("Euclidian distance")){
@Override
public Object construct() {
double[][] pairWiseEuclidianDistance = Utils.computePairWiseEuclidianDistances(heatMapData);
HierarchicalClusterData clusteredData = new HierarchicalClusterData(rowNames, pairWiseEuclidianDistance);
clusteredData = new HierarchicalClusterData(rowNames, pairWiseEuclidianDistance);
List<String> clusteredOrderedData = clusteredData.getClusteredOrderedData();
if(clusteredOrderedData == null || clusteredOrderedData.isEmpty()) {
return null;
Expand All @@ -412,9 +413,26 @@ public Object construct() {
}
rowNames = clusterOrderedRowNames;
scrollPane.setViewportView(heatMap);
clusteredRows = true;
return null;
}
}.start();
if(clusteredRows) {
int result = JOptionPane.showInternalConfirmDialog(null,
"Do you want to see the Dendrogram", "Display dendrogram",
JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
if(result != JOptionPane.YES_OPTION) {
return;
}
new AnimatedSwingWorker("Creating Dendrogram...", true) {
@Override
public Object construct() {
clusteredData.DisplayDendrogram();
clusteredRows = false;
return null;
}
}.start();
}
} else if(col_val.equals("Pearson correlation")){
if (heatMapData.length >= 1000) {
int result = JOptionPane.showInternalConfirmDialog(MetaOmGraph.getDesktop(), "You are trying to cluster "
Expand All @@ -430,7 +448,7 @@ public Object construct() {
@Override
public Object construct() {
double[][] pairWisePearsonCorrelation = Utils.computePairWisePearsonCorrelations(heatMapData);
HierarchicalClusterData clusteredData = new HierarchicalClusterData(rowNames, pairWisePearsonCorrelation);
clusteredData = new HierarchicalClusterData(rowNames, pairWisePearsonCorrelation);
List<String> clusteredOrderedData = clusteredData.getClusteredOrderedData();
if(clusteredOrderedData == null || clusteredOrderedData.isEmpty()) {
return null;
Expand All @@ -447,9 +465,20 @@ public Object construct() {
}
rowNames = clusterOrderedRowNames;
scrollPane.setViewportView(heatMap);
clusteredRows = true;
return null;
}
}.start();
if(clusteredRows) {
int result = JOptionPane.showInternalConfirmDialog(null,
"Do you want to see the Dendrogram", "Display dendrogram",
JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
if(result != JOptionPane.YES_OPTION) {
return;
}
clusteredData.DisplayDendrogram();
clusteredRows = false;
}
} else {
if (heatMapData.length >= 1000) {
int result = JOptionPane.showInternalConfirmDialog(MetaOmGraph.getDesktop(), "You are trying to cluster "
Expand All @@ -465,7 +494,7 @@ public Object construct() {
@Override
public Object construct() {
double[][] pairWiseSpearmanCorrelation = Utils.computePairWiseSpearmanCorrelations(heatMapData);
HierarchicalClusterData clusteredData = new HierarchicalClusterData(rowNames, pairWiseSpearmanCorrelation);
clusteredData = new HierarchicalClusterData(rowNames, pairWiseSpearmanCorrelation);
List<String> clusteredOrderedData = clusteredData.getClusteredOrderedData();
if(clusteredOrderedData == null || clusteredOrderedData.isEmpty()) {
return null;
Expand All @@ -482,9 +511,20 @@ public Object construct() {
}
rowNames = clusterOrderedRowNames;
scrollPane.setViewportView(heatMap);
clusteredRows = true;
return null;
}
}.start();
if(clusteredRows) {
int result = JOptionPane.showInternalConfirmDialog(null,
"Do you want to see the Dendrogram", "Display dendrogram",
JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
if(result != JOptionPane.YES_OPTION) {
return;
}
clusteredData.DisplayDendrogram();
clusteredRows = false;
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1099,7 +1099,7 @@ public void keyPressed(KeyEvent e) {
}
});
filterField.getDocument().addDocumentListener(new FilterFieldListener());
filterField.setToolTipText("Prefix search text with '~' for \"contains\", '!' for \"is not\", and '~!' for \"does not contain\".");
filterField.setToolTipText("Prefix search text with '=' for \"is\", '!' for \"does not contain\", and '!=' for \"is not\".");
filterField.setDefaultText("Use semicolon (;) for multiple filters");
filterField.setColumns(30);
searchPanel.add(filterField, "Center");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ public void keyPressed(KeyEvent e) {
}
});
filterField.getDocument().addDocumentListener(new FilterFieldListener());
filterField.setToolTipText("Prefix search text with '~' for \"contains\", '!' for \"is not\", and '~!' for \"does not contain\".");
filterField.setToolTipText("Prefix search text with '=' for \"is\", '!' for \"does not contain\", and '!=' for \"is not\".");
filterField.setDefaultText("Use semicolon (;) for multiple filters");
filterField.setColumns(20);
searchPanel.add(filterField, "Center");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1253,7 +1253,7 @@ public void keyPressed(KeyEvent e) {
}
});
filterField.getDocument().addDocumentListener(new FilterFieldListener());
filterField.setToolTipText("Prefix search text with '~' for \"contains\", '!' for \"is not\", and '~!' for \"does not contain\".");
filterField.setToolTipText("Prefix search text with '=' for \"is\", '!' for \"does not contain\", and '!=' for \"is not\".");
filterField.setDefaultText("Use semicolon (;) for multiple filters");
filterField.setColumns(30);
searchPanel.add(filterField, "Center");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,22 @@
import java.util.List;

import javax.swing.JOptionPane;

import com.apporiented.algorithm.clustering.AverageLinkageStrategy;
import com.apporiented.algorithm.clustering.Cluster;
import com.apporiented.algorithm.clustering.ClusteringAlgorithm;
import com.apporiented.algorithm.clustering.DefaultClusteringAlgorithm;
import com.apporiented.algorithm.clustering.visualization.DendrogramPanel;

import edu.iastate.metnet.metaomgraph.MetaOmGraph;
import edu.iastate.metnet.metaomgraph.chart.DendrogramChart;

/**
* @author sumanth
* Class to cluster the data
*/
public class HierarchicalClusterData {
private List<String> clusteredDataNames;
private Cluster parentCluster;

/**
* Constructor
Expand All @@ -35,6 +39,7 @@ private void doClustering(double[][] data, String[] names) {
try {
ClusteringAlgorithm algorithm = new DefaultClusteringAlgorithm();
Cluster cluster = algorithm.performClustering(data, names, new AverageLinkageStrategy());
parentCluster = cluster;
fillClusteredOrderedDataFromChildren(cluster);
}catch(Exception e){
JOptionPane.showMessageDialog(null, "Duplicate identifiers found, the feature names should be unique", "Clustering error", JOptionPane.ERROR_MESSAGE);
Expand All @@ -52,6 +57,23 @@ private void fillClusteredOrderedDataFromChildren(Cluster cluster) {
}
}

public void DisplayDendrogram() {
DendrogramPanel dendrogramPanel = new DendrogramPanel();
dendrogramPanel.setModel(parentCluster);
dendrogramPanel.setShowDistances(false);
dendrogramPanel.setShowScale(false);

DendrogramChart dendrogramPlotFrame = new DendrogramChart(dendrogramPanel);
MetaOmGraph.getDesktop().add(dendrogramPlotFrame);
dendrogramPlotFrame.setDefaultCloseOperation(2);
dendrogramPlotFrame.setClosable(true);
dendrogramPlotFrame.setResizable(true);
dendrogramPlotFrame.pack();
dendrogramPlotFrame.setSize(1000, 700);
dendrogramPlotFrame.setVisible(true);
dendrogramPlotFrame.toFront();
}

/**
* Get the clustered data name/id in the order of clustering
* @return clusteredData
Expand Down

0 comments on commit 925788f

Please sign in to comment.