/*
* TreeStatFrame.java
*
* Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard
*
* This file is part of BEAST.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership and licensing.
*
* BEAST is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* BEAST is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with BEAST; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
package dr.app.treestat;
import dr.evolution.tree.TreeUtils;
import jam.framework.Application;
import jam.framework.DocumentFrame;
import jam.util.IconUtils;
import javax.swing.*;
import javax.swing.plaf.BorderUIResource;
import java.awt.*;
import java.io.*;
import dr.evolution.io.Importer;
import dr.evolution.io.NexusImporter;
import dr.evolution.io.NewickImporter;
import dr.evolution.io.TreeImporter;
import dr.evolution.tree.Tree;
import dr.app.treestat.statistics.TreeSummaryStatistic;
public class TreeStatFrame extends DocumentFrame {
/**
*
*/
private static final long serialVersionUID = -1775448072034877658L;
private TreeStatData treeStatData = null;
private JTabbedPane tabbedPane = new JTabbedPane();
private TaxonSetsPanel taxonSetsPanel;
private StatisticsPanel statisticsPanel;
private JLabel statusLabel;
private JLabel progressLabel;
private JProgressBar progressBar;
final Icon gearIcon = IconUtils.getIcon(this.getClass(), "images/gear.png");
public TreeStatFrame(Application application, String title) {
super();
setTitle(title);
treeStatData = new TreeStatData();
setImportAction(importTaxaAction);
setExportAction(processTreeFileAction);
getOpenAction().setEnabled(false);
getSaveAction().setEnabled(false);
getSaveAsAction().setEnabled(false);
}
public void initializeComponents() {
setSize(new java.awt.Dimension(800, 600));
taxonSetsPanel = new TaxonSetsPanel(this, treeStatData);
statisticsPanel = new StatisticsPanel(this, treeStatData);
tabbedPane.addTab("Statistics", null, statisticsPanel);
tabbedPane.addTab("Taxon Sets", null, taxonSetsPanel);
statusLabel = new JLabel("No statistics selected");
processTreeFileAction.setEnabled(false);
JPanel progressPanel = new JPanel(new BorderLayout(0,0));
progressLabel = new JLabel("");
progressBar = new JProgressBar();
progressPanel.add(progressLabel, BorderLayout.NORTH);
progressPanel.add(progressBar, BorderLayout.CENTER);
JPanel panel2 = new JPanel(new FlowLayout());
JButton goButton = new JButton(processTreeFileAction);
goButton.setFocusable(false);
goButton.putClientProperty("JButton.buttonType", "textured");
goButton.setMargin(new Insets(4,4,4,4));
panel2.add(goButton);
panel2.add(progressPanel);
JPanel panel1 = new JPanel(new BorderLayout(0,0));
panel1.add(statusLabel, BorderLayout.WEST);
panel1.add(panel2, BorderLayout.EAST);
panel1.setBorder(new BorderUIResource.EmptyBorderUIResource(new java.awt.Insets(0, 6, 0, 6)));
JPanel panel = new JPanel(new BorderLayout(0,0));
panel.add(tabbedPane, BorderLayout.CENTER);
panel.add(panel1, BorderLayout.SOUTH);
panel.setBorder(new BorderUIResource.EmptyBorderUIResource(new java.awt.Insets(12, 12, 12, 12)));
getContentPane().setLayout(new java.awt.BorderLayout(0, 0));
getContentPane().add(panel, BorderLayout.CENTER);
}
public void fireDataChanged() {
if (treeStatData.statistics.size() > 0) {
statusLabel.setText("" + treeStatData.statistics.size() + " statistics selected");
processTreeFileAction.setEnabled(true);
} else {
statusLabel = new JLabel("No statistics selected");
processTreeFileAction.setEnabled(false);
}
taxonSetsPanel.dataChanged();
statisticsPanel.dataChanged();
}
protected boolean readFromFile(File file) throws IOException {
return false;
}
protected boolean writeToFile(File file) {
return false;
}
public final void doImport() {
FileDialog dialog = new FileDialog(this,
"Import Tree File...",
FileDialog.LOAD);
dialog.setVisible(true);
if (dialog.getFile() != null) {
File file = new File(dialog.getDirectory(), dialog.getFile());
try {
importFromFile(file);
} catch (Importer.ImportException ie) {
JOptionPane.showMessageDialog(this, "Unable to read tree file: " + ie,
"Unable to read tree file",
JOptionPane.ERROR_MESSAGE);
} catch (FileNotFoundException fnfe) {
JOptionPane.showMessageDialog(this, "Unable to open file: File not found",
"Unable to open file",
JOptionPane.ERROR_MESSAGE);
} catch (IOException ioe) {
JOptionPane.showMessageDialog(this, "Unable to read file: " + ioe,
"Unable to read file",
JOptionPane.ERROR_MESSAGE);
} catch (Exception e) {
JOptionPane.showMessageDialog(this, "Error: " + e,
"Error",
JOptionPane.ERROR_MESSAGE);
}
}
}
protected void importFromFile(File file) throws IOException, Importer.ImportException {
BufferedReader reader = new BufferedReader(new FileReader(file));
String line = reader.readLine();
Tree tree = null;
if (line.toUpperCase().startsWith("#NEXUS")) {
NexusImporter importer = new NexusImporter(reader);
tree = importer.importTree(null);
} else {
reader.close();
reader = new BufferedReader(new FileReader(file));
NewickImporter importer = new NewickImporter(reader);
tree = importer.importTree(null);
}
treeStatData.allTaxa = TreeUtils.getLeafSet(tree);
statusLabel.setText(Integer.toString(treeStatData.allTaxa.size()) + " taxa loaded.");
reader.close();
fireDataChanged();
}
public final void doExport() {
FileDialog inDialog = new FileDialog(this,
"Import Tree File...",
FileDialog.LOAD);
inDialog.setVisible(true);
if (inDialog.getFile() != null) {
File inFile = new File(inDialog.getDirectory(), inDialog.getFile());
FileDialog outDialog = new FileDialog(this,
"Save Log File As...",
FileDialog.SAVE);
outDialog.setVisible(true);
if (outDialog.getFile() != null) {
File outFile = new File(outDialog.getDirectory(), outDialog.getFile());
try {
processTreeFile(inFile, outFile);
} catch (FileNotFoundException fnfe) {
JOptionPane.showMessageDialog(this, "Unable to open file: File not found",
"Unable to open file",
JOptionPane.ERROR_MESSAGE);
} catch (IOException ioe) {
JOptionPane.showMessageDialog(this, "Unable to read/write file: " + ioe,
"Unable to read/write file",
JOptionPane.ERROR_MESSAGE);
} catch (Importer.ImportException ie) {
JOptionPane.showMessageDialog(this, "Unable to import file: " + ie,
"Unable to import tree file",
JOptionPane.ERROR_MESSAGE);
} catch (Exception e) {
JOptionPane.showMessageDialog(this, "Error: " + e,
"Error",
JOptionPane.ERROR_MESSAGE);
}
}
}
}
protected void processTreeFile(File inFile, File outFile) throws IOException, Importer.ImportException {
processTreeFileAction.setEnabled(false);
BufferedReader r = new BufferedReader(new FileReader(inFile));
String line = r.readLine();
r.close();
final ProgressMonitorInputStream in = new ProgressMonitorInputStream(
this,
"Reading " + inFile.getName(),
new FileInputStream(inFile));
in.getProgressMonitor().setMillisToDecideToPopup(0);
in.getProgressMonitor().setMillisToPopup(0);
final Reader reader = new InputStreamReader(new BufferedInputStream(in));
// final Reader reader = new FileReader(inFile);
final TreeImporter importer;
if (line.toUpperCase().startsWith("#NEXUS")) {
importer = new NexusImporter(reader);
} else {
reader.close();
importer = new NewickImporter(reader);
}
final Tree firstTree = importer.importNextTree();
boolean isUltrametric = TreeUtils.isUltrametric(firstTree);
boolean isBinary = TreeUtils.isBinary(firstTree);
boolean stop = false;
// check that the trees conform with the requirements of the selected statistics
for (int i = 0; i < treeStatData.statistics.size(); i++) {
TreeSummaryStatistic tss = (TreeSummaryStatistic)treeStatData.statistics.get(i);
String label = tss.getSummaryStatisticName();
if (!isUltrametric && !tss.allowsNonultrametricTrees()) {
if (JOptionPane.showConfirmDialog(
this, "Warning: These trees may not be ultrametric and this is\na requirement of the " +
label + " statistic. Do you wish to continue?", "Warning", JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) {
stop = true;
break;
}
// don't ask the question again...
isUltrametric = true;
}
if (!isBinary && !tss.allowsPolytomies()) {
if (JOptionPane.showConfirmDialog(
this, "Warning: These trees may not be strictly bifurcating and this is\na requirement of the " +
label + " statistic. Do you wish to continue?", "Warning", JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) {
stop = true;
break;
}
// don't ask the question again...
isBinary = true;
}
}
if (stop) {
processTreeFileAction.setEnabled(true);
return;
}
final PrintWriter writer = new PrintWriter(new FileWriter(outFile));
// Thread readThread = new Thread() {
// public void run() {
Tree tree = firstTree;
writer.print("state");
for (int i = 0; i < treeStatData.statistics.size(); i++) {
TreeSummaryStatistic tss = (TreeSummaryStatistic)treeStatData.statistics.get(i);
int dim = tss.getStatisticDimensions(tree);
for (int j = 0; j < dim; j++) {
writer.print("\t" + tss.getStatisticLabel(tree, j));
}
}
writer.println();
state = 0;
do {
writer.print(state);
for (int i = 0; i < treeStatData.statistics.size(); i++) {
TreeSummaryStatistic tss = (TreeSummaryStatistic)treeStatData.statistics.get(i);
double[] stats = tss.getSummaryStatistic(tree);
for (int j = 0; j < stats.length; j++) {
writer.print("\t" + stats[j]);
}
}
writer.println();
state += 1;
final int currentState = state;
in.getProgressMonitor().setNote("Processing Tree " + currentState + "...");
// EventQueue.invokeLater(
// new Runnable() {
// public void run() {
// progressLabel.setText("Processing Tree " + currentState + "...");
// }
// });
// try {
tree = importer.importNextTree();
// } catch (final IOException e) {
// EventQueue.invokeLater(
// new Runnable() {
// public void run() {
// JOptionPane.showMessageDialog(TreeStatFrame.this, "File I/O Error: " + e.getMessage(),
// "File I/O Error",
// JOptionPane.ERROR_MESSAGE);
// }
// });
// } catch (final Importer.ImportException e) {
// EventQueue.invokeLater(
// new Runnable() {
// public void run() {
// JOptionPane.showMessageDialog(TreeStatFrame.this, "Error importing tree: " + e.getMessage(),
// "Tree Import Error",
// JOptionPane.ERROR_MESSAGE);
// }
// });
// }
} while (tree != null);
// }
// };
//
// readThread.start();
// while (readThread.isAlive()) {
// Thread.yield();
// }
reader.close();
writer.close();
progressLabel.setText("" + state + " trees processed.");
processTreeFileAction.setEnabled(true);
}
private int state = 0;
public void doCopy() {
// statisticsPanel.doCopy();
}
public JComponent getExportableComponent() {
return statisticsPanel.getExportableComponent();
}
protected AbstractAction importTaxaAction = new AbstractAction("Import Taxa...") {
/**
*
*/
private static final long serialVersionUID = -3185667996732228702L;
public void actionPerformed(java.awt.event.ActionEvent ae) {
doImport();
}
};
protected AbstractAction processTreeFileAction = new AbstractAction("Process Tree File...", gearIcon) {
/**
*
*/
private static final long serialVersionUID = -8285433136692586532L;
public void actionPerformed(java.awt.event.ActionEvent ae) {
doExport();
}
};
TreeImporter treeImporter;
}