From 89f36e42fb462f8d7b59def3ead995fb16a87b59 Mon Sep 17 00:00:00 2001 From: "cmzmasek@gmail.com" Date: Tue, 18 Dec 2012 00:30:01 +0000 Subject: [PATCH] "rio" work --- .../java/src/org/forester/application/rio.java | 171 +- .../archaeopteryx/MainFrameApplication.java | 2280 ++++++++++---------- .../java/src/org/forester/phylogeny/Phylogeny.java | 318 +-- .../org/forester/phylogeny/PhylogenyMethods.java | 26 + forester/java/src/org/forester/rio/RIO.java | 301 ++- forester/java/src/org/forester/rio/TestRIO.java | 10 +- forester/java/src/org/forester/sdi/GSDIR.java | 30 +- 7 files changed, 1648 insertions(+), 1488 deletions(-) diff --git a/forester/java/src/org/forester/application/rio.java b/forester/java/src/org/forester/application/rio.java index 8af0486..13b2ade 100644 --- a/forester/java/src/org/forester/application/rio.java +++ b/forester/java/src/org/forester/application/rio.java @@ -31,19 +31,16 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.SortedSet; -import java.util.TreeSet; import org.forester.datastructures.IntMatrix; import org.forester.io.parsers.phyloxml.PhyloXmlParser; import org.forester.phylogeny.Phylogeny; -import org.forester.phylogeny.PhylogenyNode; -import org.forester.phylogeny.data.Taxonomy; +import org.forester.phylogeny.PhylogenyMethods; import org.forester.phylogeny.factories.ParserBasedPhylogenyFactory; import org.forester.phylogeny.factories.PhylogenyFactory; import org.forester.rio.RIO; -import org.forester.rio.RIOException; import org.forester.rio.RIO.REROOTING; +import org.forester.rio.RIOException; import org.forester.sdi.SDIException; import org.forester.sdi.SDIutil.ALGORITHM; import org.forester.util.BasicDescriptiveStatistics; @@ -54,8 +51,8 @@ import org.forester.util.ForesterUtil; public class rio { final static private String PRG_NAME = "rio"; - final static private String PRG_VERSION = "4.000 beta 2"; - final static private String PRG_DATE = "2012.12.14"; + final static private String PRG_VERSION = "4.000 beta 3"; + final static private String PRG_DATE = "2012.12.17"; final static private String E_MAIL = "czmasek@burnham.org"; final static private String WWW = "www.phylosoft.org/forester/"; final static private String HELP_OPTION_1 = "help"; @@ -80,7 +77,7 @@ public class rio { if ( cla.isOptionSet( HELP_OPTION_1 ) || cla.isOptionSet( HELP_OPTION_2 ) || ( args.length == 0 ) ) { printHelp(); } - if ( ( args.length < 3 ) || ( args.length > 5 ) ) { + if ( ( args.length < 3 ) || ( args.length > 8 ) ) { System.out.println(); System.out.println( "[" + PRG_NAME + "] incorrect number of arguments" ); System.out.println(); @@ -94,7 +91,7 @@ public class rio { } final File gene_trees_file = cla.getFile( 0 ); final File species_tree_file = cla.getFile( 1 ); - final File othology_outtable = cla.getFile( 2 ); + final File orthology_outtable = cla.getFile( 2 ); final File logfile; if ( cla.getNumberOfNames() > 3 ) { logfile = cla.getFile( 3 ); @@ -105,11 +102,11 @@ public class rio { else { logfile = null; } - String outgroup = ""; + final String outgroup = ""; ForesterUtil.fatalErrorIfFileNotReadable( PRG_NAME, gene_trees_file ); ForesterUtil.fatalErrorIfFileNotReadable( PRG_NAME, species_tree_file ); - if ( othology_outtable.exists() ) { - ForesterUtil.fatalError( PRG_NAME, "\"" + othology_outtable + "\" already exists" ); + if ( orthology_outtable.exists() ) { + ForesterUtil.fatalError( PRG_NAME, "\"" + orthology_outtable + "\" already exists" ); } boolean sdir = false; if ( cla.isOptionSet( USE_SDIR ) ) { @@ -121,7 +118,7 @@ public class rio { long time = 0; System.out.println( "Gene trees : " + gene_trees_file ); System.out.println( "Species tree : " + species_tree_file ); - System.out.println( "All vs all orthology table: " + othology_outtable ); + System.out.println( "All vs all orthology table: " + orthology_outtable ); if ( !sdir ) { if ( logfile != null ) { System.out.println( "Logfile : " + logfile ); @@ -144,6 +141,15 @@ public class rio { if ( !species_tree.isRooted() ) { ForesterUtil.fatalError( PRG_NAME, "species tree is not rooted" ); } + final int o = PhylogenyMethods.countNumberOfOneDescendantNodes( species_tree ); + if ( o > 0 ) { + ForesterUtil.printWarningMessage( PRG_NAME, "species tree has " + o + + " internal nodes with only one descendent! Going to strip them." ); + PhylogenyMethods.deleteInternalNodesWithOnlyOneDescendent( species_tree ); + if ( PhylogenyMethods.countNumberOfOneDescendantNodes( species_tree ) > 0 ) { + ForesterUtil.unexpectedFatalError( PRG_NAME, "stripping of one-desc nodes failed" ); + } + } final ALGORITHM algorithm; if ( sdir ) { algorithm = ALGORITHM.SDIR; @@ -152,19 +158,38 @@ public class rio { algorithm = ALGORITHM.GSDIR; } try { - final RIO rio = new RIO( gene_trees_file, species_tree, algorithm, REROOTING.BY_ALGORITHM, outgroup , logfile != null, true ); + final RIO rio = RIO.executeAnalysis( gene_trees_file, + species_tree, + algorithm, + REROOTING.BY_ALGORITHM, + outgroup, + logfile != null, + true ); if ( algorithm == ALGORITHM.GSDIR ) { ForesterUtil.programMessage( PRG_NAME, "taxonomy linking based on: " + rio.getGSDIRtaxCompBase() ); } - tableOutput( othology_outtable, rio ); - if ( ( algorithm == ALGORITHM.GSDIR ) && ( logfile != null ) ) { - writeLogFile( logfile, rio ); + tableOutput( orthology_outtable, rio ); + if ( ( algorithm != ALGORITHM.SDIR ) && ( logfile != null ) ) { + writeLogFile( logfile, + rio, + species_tree_file, + gene_trees_file, + orthology_outtable, + PRG_NAME, + PRG_VERSION, + PRG_DATE, + ForesterUtil.getForesterLibraryInformation() ); } final BasicDescriptiveStatistics stats = rio.getDuplicationsStatistics(); - ForesterUtil.programMessage( PRG_NAME, "Mean: " + stats.arithmeticMean() + "(" + stats.sampleStandardDeviation() + ")" ); - ForesterUtil.programMessage( PRG_NAME, "Min: " + (int) stats.getMin() ); - ForesterUtil.programMessage( PRG_NAME, "Max: " + (int) stats.getMax() ); - + final java.text.DecimalFormat df = new java.text.DecimalFormat( "0.#" ); + ForesterUtil.programMessage( PRG_NAME, + "Mean number of duplications : " + df.format( stats.arithmeticMean() ) + + " (sd: " + df.format( stats.sampleStandardDeviation() ) + ")" ); + if ( stats.getN() > 3 ) { + ForesterUtil.programMessage( PRG_NAME, "Median number of duplications: " + df.format( stats.median() ) ); + } + ForesterUtil.programMessage( PRG_NAME, "Minimum duplications : " + ( int ) stats.getMin() ); + ForesterUtil.programMessage( PRG_NAME, "Maximum duplications : " + ( int ) stats.getMax() ); } catch ( final RIOException e ) { ForesterUtil.fatalError( PRG_NAME, e.getLocalizedMessage() ); @@ -178,42 +203,36 @@ public class rio { catch ( final Exception e ) { ForesterUtil.unexpectedFatalError( PRG_NAME, e ); } - time = System.currentTimeMillis() - time; ForesterUtil.programMessage( PRG_NAME, "time: " + time + "ms" ); ForesterUtil.programMessage( PRG_NAME, "OK" ); System.exit( 0 ); } - private static void writeLogFile( final File logfile, final RIO rio ) throws IOException { - final EasyWriter out = ForesterUtil.createEasyWriter( logfile ); - out.println( "Species stripped from gene trees:" ); - final SortedSet rn = new TreeSet(); - for( final PhylogenyNode n : rio.getRemovedGeneTreeNodes() ) { - final Taxonomy t = n.getNodeData().getTaxonomy(); - switch ( rio.getGSDIRtaxCompBase() ) { - case CODE: { - rn.add( t.getTaxonomyCode() ); - break; - } - case ID: { - rn.add( t.getIdentifier().toString() ); - break; - } - case SCIENTIFIC_NAME: { - rn.add( t.getScientificName() ); - break; - } - } - } - for( final String s : rn ) { - out.println( s ); - } - out.println(); - out.println( "Some information about duplication numbers in gene trees:" ); - out.println( rio.getLog().toString() ); - out.close(); - ForesterUtil.programMessage( PRG_NAME, "wrote log to \"" + logfile + "\"" ); + private final static void printHelp() { + System.out.println( "Usage" ); + System.out.println(); + System.out + .println( PRG_NAME + + " [options] [logfile]" ); + System.out.println(); + System.out.println( " Options" ); + System.out.println( " -" + USE_SDIR + + " : to use SDIR instead of GSDIR (faster, but non-binary species trees are disallowed)" ); + System.out.println(); + System.out.println( " Formats" ); + System.out.println( " The species tree is expected to be in phyloXML format." ); + System.out + .println( " The gene trees ideally are in phyloXML as well, but can also be in New Hamphshire (Newick)" ); + System.out.println( " or Nexus format as long as species information can be extracted from the gene names" ); + System.out.println( " (e.g. \"HUMAN\" from \"BCL2_HUMAN\")." ); + System.out.println(); + System.out.println( " Examples" ); + System.out.println( " \"rio gene_trees.nh species.xml outtable.tsv log.txt\"" ); + System.out.println(); + System.out.println( " More information: http://code.google.com/p/forester/wiki/RIO" ); + System.out.println(); + System.exit( -1 ); } private static void tableOutput( final File table_outfile, final RIO rio ) throws IOException, RIOException { @@ -221,6 +240,30 @@ public class rio { writeTable( table_outfile, rio, m ); } + private static void writeLogFile( final File logfile, + final RIO rio, + final File species_tree_file, + final File gene_trees_file, + final File outtable, + final String prg_name, + final String prg_v, + final String prg_date, + final String f ) throws IOException { + final EasyWriter out = ForesterUtil.createEasyWriter( logfile ); + out.println( prg_name ); + out.println( "version : " + prg_v ); + out.println( "date : " + prg_date ); + out.println( "based on: " + f ); + out.println( "----------------------------------" ); + out.println( "Gene trees : " + gene_trees_file ); + out.println( "Species tree : " + species_tree_file ); + out.println( "All vs all orthology table : " + outtable ); + out.flush(); + out.println( rio.getLog().toString() ); + out.close(); + ForesterUtil.programMessage( PRG_NAME, "wrote log to \"" + logfile + "\"" ); + } + private static void writeTable( final File table_outfile, final RIO rio, final IntMatrix m ) throws IOException { final EasyWriter w = ForesterUtil.createEasyWriter( table_outfile ); final java.text.DecimalFormat df = new java.text.DecimalFormat( "0.###" ); @@ -249,30 +292,4 @@ public class rio { w.close(); ForesterUtil.programMessage( PRG_NAME, "wrote table to \"" + table_outfile + "\"" ); } - - private final static void printHelp() { - System.out.println( "Usage" ); - System.out.println(); - System.out - .println( PRG_NAME - + " [options] [logfile]" ); - System.out.println(); - System.out.println( " Options" ); - System.out.println( " -" + USE_SDIR - + " : to use SDIR instead of GSDIR (faster, but non-binary species trees are disallowed)" ); - System.out.println(); - System.out.println( " Formats" ); - System.out.println( " The species tree is expected to be in phyloXML format." ); - System.out - .println( " The gene trees ideally are in phyloXML as well, but can also be in New Hamphshire (Newick)" ); - System.out.println( " or Nexus format as long as species information can be extracted from the gene names" ); - System.out.println( " (e.g. \"HUMAN\" from \"BCL2_HUMAN\")." ); - System.out.println(); - System.out.println( " Examples" ); - System.out.println( " \"rio gene_trees.nh species.xml outtable.tsv log.txt\"" ); - System.out.println(); - System.out.println( " More information: http://code.google.com/p/forester/wiki/RIO" ); - System.out.println(); - System.exit( -1 ); - } } diff --git a/forester/java/src/org/forester/archaeopteryx/MainFrameApplication.java b/forester/java/src/org/forester/archaeopteryx/MainFrameApplication.java index 14b480f..7b3f411 100644 --- a/forester/java/src/org/forester/archaeopteryx/MainFrameApplication.java +++ b/forester/java/src/org/forester/archaeopteryx/MainFrameApplication.java @@ -110,72 +110,6 @@ import org.forester.util.DescriptiveStatistics; import org.forester.util.ForesterUtil; import org.forester.util.WindowsUtils; -class DefaultFilter extends FileFilter { - - @Override - public boolean accept( final File f ) { - final String file_name = f.getName().trim().toLowerCase(); - return file_name.endsWith( ".nh" ) || file_name.endsWith( ".newick" ) || file_name.endsWith( ".phy" ) - || file_name.endsWith( ".nwk" ) || file_name.endsWith( ".phb" ) || file_name.endsWith( ".ph" ) - || file_name.endsWith( ".tr" ) || file_name.endsWith( ".dnd" ) || file_name.endsWith( ".tree" ) - || file_name.endsWith( ".nhx" ) || file_name.endsWith( ".xml" ) || file_name.endsWith( ".phyloxml" ) - || file_name.endsWith( "phylo.xml" ) || file_name.endsWith( ".pxml" ) || file_name.endsWith( ".nexus" ) - || file_name.endsWith( ".nx" ) || file_name.endsWith( ".nex" ) || file_name.endsWith( ".tre" ) - || file_name.endsWith( ".zip" ) || file_name.endsWith( ".tol" ) || file_name.endsWith( ".tolxml" ) - || file_name.endsWith( ".con" ) || f.isDirectory(); - } - - @Override - public String getDescription() { - return "All supported files (*.xml, *.phyloxml, *phylo.xml, *.nhx, *.nh, *.newick, *.nex, *.nexus, *.phy, *.tre, *.tree, *.tol, ...)"; - } -} - -class GraphicsFileFilter extends FileFilter { - - @Override - public boolean accept( final File f ) { - final String file_name = f.getName().trim().toLowerCase(); - return file_name.endsWith( ".jpg" ) || file_name.endsWith( ".jpeg" ) || file_name.endsWith( ".png" ) - || file_name.endsWith( ".gif" ) || file_name.endsWith( ".bmp" ) || f.isDirectory(); - } - - @Override - public String getDescription() { - return "Image files (*.jpg, *.jpeg, *.png, *.gif, *.bmp)"; - } -} - -class MsaFileFilter extends FileFilter { - - @Override - public boolean accept( final File f ) { - final String file_name = f.getName().trim().toLowerCase(); - return file_name.endsWith( ".msa" ) || file_name.endsWith( ".aln" ) || file_name.endsWith( ".fasta" ) - || file_name.endsWith( ".fas" ) || file_name.endsWith( ".fa" ) || f.isDirectory(); - } - - @Override - public String getDescription() { - return "Multiple sequence alignment files (*.msa, *.aln, *.fasta, *.fa, *.fas)"; - } -} - -class SequencesFileFilter extends FileFilter { - - @Override - public boolean accept( final File f ) { - final String file_name = f.getName().trim().toLowerCase(); - return file_name.endsWith( ".fasta" ) || file_name.endsWith( ".fa" ) || file_name.endsWith( ".fas" ) - || file_name.endsWith( ".seqs" ) || f.isDirectory(); - } - - @Override - public String getDescription() { - return "Sequences files (*.fasta, *.fa, *.fas, *.seqs )"; - } -} - public final class MainFrameApplication extends MainFrame { static final String INFER_ANCESTOR_TAXONOMIES = "Infer Ancestor Taxonomies"; @@ -238,6 +172,51 @@ public final class MainFrameApplication extends MainFrame { // expression values menu: JMenuItem _read_values_jmi; + private MainFrameApplication( final Phylogeny[] phys, final Configuration config ) { + _configuration = config; + if ( _configuration == null ) { + throw new IllegalArgumentException( "configuration is null" ); + } + setVisible( false ); + setOptions( Options.createInstance( _configuration ) ); + _mainpanel = new MainPanel( _configuration, this ); + _open_filechooser = null; + _open_filechooser_for_species_tree = null; + _save_filechooser = null; + _writetopdf_filechooser = null; + _writetographics_filechooser = null; + _msa_filechooser = null; + _seqs_filechooser = null; + _values_filechooser = null; + _jmenubar = new JMenuBar(); + buildFileMenu(); + buildTypeMenu(); + _contentpane = getContentPane(); + _contentpane.setLayout( new BorderLayout() ); + _contentpane.add( _mainpanel, BorderLayout.CENTER ); + // App is this big + setSize( MainFrameApplication.FRAME_X_SIZE, MainFrameApplication.FRAME_Y_SIZE ); + // The window listener + setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE ); + addWindowListener( new WindowAdapter() { + + @Override + public void windowClosing( final WindowEvent e ) { + exit(); + } + } ); + // setVisible( true ); + if ( ( phys != null ) && ( phys.length > 0 ) ) { + AptxUtil.addPhylogeniesToTabs( phys, "", null, _configuration, _mainpanel ); + validate(); + getMainPanel().getControlPanel().showWholeAll(); + getMainPanel().getControlPanel().showWhole(); + } + //activateSaveAllIfNeeded(); + // ...and its children + _contentpane.repaint(); + } + private MainFrameApplication( final Phylogeny[] phys, final Configuration config, final String title ) { this( phys, config, title, null ); } @@ -438,51 +417,6 @@ public final class MainFrameApplication extends MainFrame { System.gc(); } - private MainFrameApplication( final Phylogeny[] phys, final Configuration config ) { - _configuration = config; - if ( _configuration == null ) { - throw new IllegalArgumentException( "configuration is null" ); - } - setVisible( false ); - setOptions( Options.createInstance( _configuration ) ); - _mainpanel = new MainPanel( _configuration, this ); - _open_filechooser = null; - _open_filechooser_for_species_tree = null; - _save_filechooser = null; - _writetopdf_filechooser = null; - _writetographics_filechooser = null; - _msa_filechooser = null; - _seqs_filechooser = null; - _values_filechooser = null; - _jmenubar = new JMenuBar(); - buildFileMenu(); - buildTypeMenu(); - _contentpane = getContentPane(); - _contentpane.setLayout( new BorderLayout() ); - _contentpane.add( _mainpanel, BorderLayout.CENTER ); - // App is this big - setSize( MainFrameApplication.FRAME_X_SIZE, MainFrameApplication.FRAME_Y_SIZE ); - // The window listener - setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE ); - addWindowListener( new WindowAdapter() { - - @Override - public void windowClosing( final WindowEvent e ) { - exit(); - } - } ); - // setVisible( true ); - if ( ( phys != null ) && ( phys.length > 0 ) ) { - AptxUtil.addPhylogeniesToTabs( phys, "", null, _configuration, _mainpanel ); - validate(); - getMainPanel().getControlPanel().showWholeAll(); - getMainPanel().getControlPanel().showWhole(); - } - //activateSaveAllIfNeeded(); - // ...and its children - _contentpane.repaint(); - } - private MainFrameApplication( final Phylogeny[] phys, final String config_file, final String title ) { // Reads the config file (false, false => not url, not applet): this( phys, new Configuration( config_file, false, false, true ), title ); @@ -660,80 +594,299 @@ public final class MainFrameApplication extends MainFrame { } } - void buildAnalysisMenu() { - _analysis_menu = MainFrame.createMenu( "Analysis", getConfiguration() ); - _analysis_menu.add( _gsdi_item = new JMenuItem( "GSDI (Generalized Speciation Duplication Inference)" ) ); - _analysis_menu.add( _gsdir_item = new JMenuItem( "GSDIR (re-rooting)" ) ); - _analysis_menu.addSeparator(); - _analysis_menu.add( _root_min_dups_item = new JMenuItem( "Root by Minimizing Duplications | Height (SDI)" ) ); - _analysis_menu.add( _root_min_cost_l_item = new JMenuItem( "Root by Minimizing Cost L | Height (SDI)" ) ); - _analysis_menu.addSeparator(); - _analysis_menu.add( _load_species_tree_item = new JMenuItem( "Load Species Tree..." ) ); - customizeJMenuItem( _gsdi_item ); - customizeJMenuItem( _gsdir_item ); - customizeJMenuItem( _root_min_dups_item ); - customizeJMenuItem( _root_min_cost_l_item ); - customizeJMenuItem( _load_species_tree_item ); - _analysis_menu.addSeparator(); - _analysis_menu.add( _lineage_inference = new JMenuItem( INFER_ANCESTOR_TAXONOMIES ) ); - customizeJMenuItem( _lineage_inference ); - _lineage_inference.setToolTipText( "Inference of ancestor taxonomies/lineages" ); - _jmenubar.add( _analysis_menu ); + public void end() { + _mainpanel.terminate(); + _contentpane.removeAll(); + setVisible( false ); + dispose(); } - void buildPhylogeneticInferenceMenu() { - final InferenceManager im = getInferenceManager(); - _inference_menu = MainFrame.createMenu( "Inference", getConfiguration() ); - _inference_menu.add( _inference_from_msa_item = new JMenuItem( "From Multiple Sequence Alignment..." ) ); - customizeJMenuItem( _inference_from_msa_item ); - _inference_from_msa_item.setToolTipText( "Basic phylogenetic inference from MSA" ); - if ( im.canDoMsa() ) { - _inference_menu.add( _inference_from_seqs_item = new JMenuItem( "From Unaligned Sequences..." ) ); - customizeJMenuItem( _inference_from_seqs_item ); - _inference_from_seqs_item - .setToolTipText( "Basic phylogenetic inference including multiple sequence alignment" ); - } - else { - _inference_menu - .add( _inference_from_seqs_item = new JMenuItem( "From Unaligned Sequences (no program found)" ) ); - customizeJMenuItem( _inference_from_seqs_item ); - _inference_from_seqs_item.setEnabled( false ); - } - _jmenubar.add( _inference_menu ); + @Override + public MainPanel getMainPanel() { + return _mainpanel; } - @Override - void buildFileMenu() { - _file_jmenu = MainFrame.createMenu( "File", getConfiguration() ); - _file_jmenu.add( _open_item = new JMenuItem( "Read Tree from File..." ) ); - _file_jmenu.addSeparator(); - _file_jmenu.add( _open_url_item = new JMenuItem( "Read Tree from URL/Webservice..." ) ); - _file_jmenu.addSeparator(); - final WebservicesManager webservices_manager = WebservicesManager.getInstance(); - _load_phylogeny_from_webservice_menu_items = new JMenuItem[ webservices_manager - .getAvailablePhylogeniesWebserviceClients().size() ]; - for( int i = 0; i < webservices_manager.getAvailablePhylogeniesWebserviceClients().size(); ++i ) { - final PhylogeniesWebserviceClient client = webservices_manager.getAvailablePhylogeniesWebserviceClient( i ); - _load_phylogeny_from_webservice_menu_items[ i ] = new JMenuItem( client.getMenuName() ); - _file_jmenu.add( _load_phylogeny_from_webservice_menu_items[ i ] ); - } - if ( getConfiguration().isEditable() ) { - _file_jmenu.addSeparator(); - _file_jmenu.add( _new_item = new JMenuItem( "New" ) ); - _new_item.setToolTipText( "to create a new tree with one node, as source for manual tree construction" ); - } - _file_jmenu.addSeparator(); - _file_jmenu.add( _save_item = new JMenuItem( "Save Tree As..." ) ); - _file_jmenu.add( _save_all_item = new JMenuItem( "Save All Trees As..." ) ); - _save_all_item.setToolTipText( "Write all phylogenies to one file." ); - _save_all_item.setEnabled( false ); - _file_jmenu.addSeparator(); - _file_jmenu.add( _write_to_pdf_item = new JMenuItem( "Export to PDF file ..." ) ); - if ( AptxUtil.canWriteFormat( "tif" ) || AptxUtil.canWriteFormat( "tiff" ) || AptxUtil.canWriteFormat( "TIF" ) ) { - _file_jmenu.add( _write_to_tif_item = new JMenuItem( "Export to TIFF file..." ) ); + public Msa getMsa() { + return _msa; + } + + public File getMsaFile() { + return _msa_file; + } + + public List getSeqs() { + return _seqs; + } + + public File getSeqsFile() { + return _seqs_file; + } + + public void readMsaFromFile() { + // Set an initial directory if none set yet + final File my_dir = getCurrentDir(); + _msa_filechooser.setMultiSelectionEnabled( false ); + // Open file-open dialog and set current directory + if ( my_dir != null ) { + _msa_filechooser.setCurrentDirectory( my_dir ); } - _file_jmenu.add( _write_to_png_item = new JMenuItem( "Export to PNG file..." ) ); - _file_jmenu.add( _write_to_jpg_item = new JMenuItem( "Export to JPG file..." ) ); + final int result = _msa_filechooser.showOpenDialog( _contentpane ); + // All done: get the msa + final File file = _msa_filechooser.getSelectedFile(); + setCurrentDir( _msa_filechooser.getCurrentDirectory() ); + if ( ( file != null ) && !file.isDirectory() && ( result == JFileChooser.APPROVE_OPTION ) ) { + setMsaFile( null ); + setMsa( null ); + Msa msa = null; + try { + final InputStream is = new FileInputStream( file ); + if ( FastaParser.isLikelyFasta( file ) ) { + msa = FastaParser.parseMsa( is ); + } + else { + msa = GeneralMsaParser.parse( is ); + } + } + catch ( final MsaFormatException e ) { + try { + _mainpanel.getCurrentTreePanel().setArrowCursor(); + } + catch ( final Exception ex ) { + // Do nothing. + } + JOptionPane.showMessageDialog( this, + e.getLocalizedMessage(), + "Multiple sequence alignment format error", + JOptionPane.ERROR_MESSAGE ); + return; + } + catch ( final IOException e ) { + try { + _mainpanel.getCurrentTreePanel().setArrowCursor(); + } + catch ( final Exception ex ) { + // Do nothing. + } + JOptionPane.showMessageDialog( this, + e.getLocalizedMessage(), + "Failed to read multiple sequence alignment", + JOptionPane.ERROR_MESSAGE ); + return; + } + catch ( final IllegalArgumentException e ) { + try { + _mainpanel.getCurrentTreePanel().setArrowCursor(); + } + catch ( final Exception ex ) { + // Do nothing. + } + JOptionPane.showMessageDialog( this, + e.getLocalizedMessage(), + "Unexpected error during reading of multiple sequence alignment", + JOptionPane.ERROR_MESSAGE ); + return; + } + catch ( final Exception e ) { + try { + _mainpanel.getCurrentTreePanel().setArrowCursor(); + } + catch ( final Exception ex ) { + // Do nothing. + } + e.printStackTrace(); + JOptionPane.showMessageDialog( this, + e.getLocalizedMessage(), + "Unexpected error during reading of multiple sequence alignment", + JOptionPane.ERROR_MESSAGE ); + return; + } + if ( ( msa == null ) || ( msa.getNumberOfSequences() < 1 ) ) { + JOptionPane.showMessageDialog( this, + "Multiple sequence alignment is empty", + "Illegal Multiple Sequence Alignment", + JOptionPane.ERROR_MESSAGE ); + return; + } + if ( msa.getNumberOfSequences() < 4 ) { + JOptionPane.showMessageDialog( this, + "Multiple sequence alignment needs to contain at least 3 sequences", + "Illegal multiple sequence alignment", + JOptionPane.ERROR_MESSAGE ); + return; + } + if ( msa.getLength() < 2 ) { + JOptionPane.showMessageDialog( this, + "Multiple sequence alignment needs to contain at least 2 residues", + "Illegal multiple sequence alignment", + JOptionPane.ERROR_MESSAGE ); + return; + } + System.gc(); + setMsaFile( _msa_filechooser.getSelectedFile() ); + setMsa( msa ); + } + } + + public void readSeqsFromFile() { + // Set an initial directory if none set yet + final File my_dir = getCurrentDir(); + _seqs_filechooser.setMultiSelectionEnabled( false ); + // Open file-open dialog and set current directory + if ( my_dir != null ) { + _seqs_filechooser.setCurrentDirectory( my_dir ); + } + final int result = _seqs_filechooser.showOpenDialog( _contentpane ); + // All done: get the seqs + final File file = _seqs_filechooser.getSelectedFile(); + setCurrentDir( _seqs_filechooser.getCurrentDirectory() ); + if ( ( file != null ) && !file.isDirectory() && ( result == JFileChooser.APPROVE_OPTION ) ) { + setSeqsFile( null ); + setSeqs( null ); + List seqs = null; + try { + if ( FastaParser.isLikelyFasta( new FileInputStream( file ) ) ) { + seqs = FastaParser.parse( new FileInputStream( file ) ); + for( final Sequence seq : seqs ) { + System.out.println( SequenceWriter.toFasta( seq, 60 ) ); + } + } + else { + //TODO error + } + } + catch ( final MsaFormatException e ) { + try { + _mainpanel.getCurrentTreePanel().setArrowCursor(); + } + catch ( final Exception ex ) { + // Do nothing. + } + JOptionPane.showMessageDialog( this, + e.getLocalizedMessage(), + "Multiple sequence file format error", + JOptionPane.ERROR_MESSAGE ); + return; + } + catch ( final IOException e ) { + try { + _mainpanel.getCurrentTreePanel().setArrowCursor(); + } + catch ( final Exception ex ) { + // Do nothing. + } + JOptionPane.showMessageDialog( this, + e.getLocalizedMessage(), + "Failed to read multiple sequence file", + JOptionPane.ERROR_MESSAGE ); + return; + } + catch ( final IllegalArgumentException e ) { + try { + _mainpanel.getCurrentTreePanel().setArrowCursor(); + } + catch ( final Exception ex ) { + // Do nothing. + } + JOptionPane.showMessageDialog( this, + e.getLocalizedMessage(), + "Unexpected error during reading of multiple sequence file", + JOptionPane.ERROR_MESSAGE ); + return; + } + catch ( final Exception e ) { + try { + _mainpanel.getCurrentTreePanel().setArrowCursor(); + } + catch ( final Exception ex ) { + // Do nothing. + } + e.printStackTrace(); + JOptionPane.showMessageDialog( this, + e.getLocalizedMessage(), + "Unexpected error during reading of multiple sequence file", + JOptionPane.ERROR_MESSAGE ); + return; + } + if ( ( seqs == null ) || ( seqs.size() < 1 ) ) { + JOptionPane.showMessageDialog( this, + "Multiple sequence file is empty", + "Illegal multiple sequence file", + JOptionPane.ERROR_MESSAGE ); + return; + } + if ( seqs.size() < 4 ) { + JOptionPane.showMessageDialog( this, + "Multiple sequence file needs to contain at least 3 sequences", + "Illegal multiple sequence file", + JOptionPane.ERROR_MESSAGE ); + return; + } + // if ( msa.getLength() < 2 ) { + // JOptionPane.showMessageDialog( this, + // "Multiple sequence alignment needs to contain at least 2 residues", + // "Illegal multiple sequence file", + // JOptionPane.ERROR_MESSAGE ); + // return; + // } + System.gc(); + setSeqsFile( _seqs_filechooser.getSelectedFile() ); + setSeqs( seqs ); + } + } + + void buildAnalysisMenu() { + _analysis_menu = MainFrame.createMenu( "Analysis", getConfiguration() ); + _analysis_menu.add( _gsdi_item = new JMenuItem( "GSDI (Generalized Speciation Duplication Inference)" ) ); + _analysis_menu.add( _gsdir_item = new JMenuItem( "GSDIR (re-rooting)" ) ); + _analysis_menu.addSeparator(); + _analysis_menu.add( _root_min_dups_item = new JMenuItem( "Root by Minimizing Duplications | Height (SDI)" ) ); + _analysis_menu.add( _root_min_cost_l_item = new JMenuItem( "Root by Minimizing Cost L | Height (SDI)" ) ); + _analysis_menu.addSeparator(); + _analysis_menu.add( _load_species_tree_item = new JMenuItem( "Load Species Tree..." ) ); + customizeJMenuItem( _gsdi_item ); + customizeJMenuItem( _gsdir_item ); + customizeJMenuItem( _root_min_dups_item ); + customizeJMenuItem( _root_min_cost_l_item ); + customizeJMenuItem( _load_species_tree_item ); + _analysis_menu.addSeparator(); + _analysis_menu.add( _lineage_inference = new JMenuItem( INFER_ANCESTOR_TAXONOMIES ) ); + customizeJMenuItem( _lineage_inference ); + _lineage_inference.setToolTipText( "Inference of ancestor taxonomies/lineages" ); + _jmenubar.add( _analysis_menu ); + } + + @Override + void buildFileMenu() { + _file_jmenu = MainFrame.createMenu( "File", getConfiguration() ); + _file_jmenu.add( _open_item = new JMenuItem( "Read Tree from File..." ) ); + _file_jmenu.addSeparator(); + _file_jmenu.add( _open_url_item = new JMenuItem( "Read Tree from URL/Webservice..." ) ); + _file_jmenu.addSeparator(); + final WebservicesManager webservices_manager = WebservicesManager.getInstance(); + _load_phylogeny_from_webservice_menu_items = new JMenuItem[ webservices_manager + .getAvailablePhylogeniesWebserviceClients().size() ]; + for( int i = 0; i < webservices_manager.getAvailablePhylogeniesWebserviceClients().size(); ++i ) { + final PhylogeniesWebserviceClient client = webservices_manager.getAvailablePhylogeniesWebserviceClient( i ); + _load_phylogeny_from_webservice_menu_items[ i ] = new JMenuItem( client.getMenuName() ); + _file_jmenu.add( _load_phylogeny_from_webservice_menu_items[ i ] ); + } + if ( getConfiguration().isEditable() ) { + _file_jmenu.addSeparator(); + _file_jmenu.add( _new_item = new JMenuItem( "New" ) ); + _new_item.setToolTipText( "to create a new tree with one node, as source for manual tree construction" ); + } + _file_jmenu.addSeparator(); + _file_jmenu.add( _save_item = new JMenuItem( "Save Tree As..." ) ); + _file_jmenu.add( _save_all_item = new JMenuItem( "Save All Trees As..." ) ); + _save_all_item.setToolTipText( "Write all phylogenies to one file." ); + _save_all_item.setEnabled( false ); + _file_jmenu.addSeparator(); + _file_jmenu.add( _write_to_pdf_item = new JMenuItem( "Export to PDF file ..." ) ); + if ( AptxUtil.canWriteFormat( "tif" ) || AptxUtil.canWriteFormat( "tiff" ) || AptxUtil.canWriteFormat( "TIF" ) ) { + _file_jmenu.add( _write_to_tif_item = new JMenuItem( "Export to TIFF file..." ) ); + } + _file_jmenu.add( _write_to_png_item = new JMenuItem( "Export to PNG file..." ) ); + _file_jmenu.add( _write_to_jpg_item = new JMenuItem( "Export to JPG file..." ) ); if ( AptxUtil.canWriteFormat( "gif" ) ) { _file_jmenu.add( _write_to_gif_item = new JMenuItem( "Export to GIF file..." ) ); } @@ -931,6 +1084,27 @@ public final class MainFrameApplication extends MainFrame { _jmenubar.add( _options_jmenu ); } + void buildPhylogeneticInferenceMenu() { + final InferenceManager im = getInferenceManager(); + _inference_menu = MainFrame.createMenu( "Inference", getConfiguration() ); + _inference_menu.add( _inference_from_msa_item = new JMenuItem( "From Multiple Sequence Alignment..." ) ); + customizeJMenuItem( _inference_from_msa_item ); + _inference_from_msa_item.setToolTipText( "Basic phylogenetic inference from MSA" ); + if ( im.canDoMsa() ) { + _inference_menu.add( _inference_from_seqs_item = new JMenuItem( "From Unaligned Sequences..." ) ); + customizeJMenuItem( _inference_from_seqs_item ); + _inference_from_seqs_item + .setToolTipText( "Basic phylogenetic inference including multiple sequence alignment" ); + } + else { + _inference_menu + .add( _inference_from_seqs_item = new JMenuItem( "From Unaligned Sequences (no program found)" ) ); + customizeJMenuItem( _inference_from_seqs_item ); + _inference_from_seqs_item.setEnabled( false ); + } + _jmenubar.add( _inference_menu ); + } + void buildToolsMenu() { _tools_menu = createMenu( "Tools", getConfiguration() ); _tools_menu.add( _confcolor_item = new JMenuItem( "Colorize Branches Depending on Confidence" ) ); @@ -955,271 +1129,71 @@ public final class MainFrameApplication extends MainFrame { _tools_menu .add( _collapse_below_threshold = new JMenuItem( "Collapse Branches with Confidence Below Threshold into Multifurcations" ) ); customizeJMenuItem( _collapse_below_threshold ); - _collapse_below_threshold - .setToolTipText( "To collapse branches with confidence values below a threshold into multifurcations (in the case of multiple confidences per branch: without at least one confidence value above a threshold)" ); - _tools_menu.addSeparator(); - _tools_menu - .add( _move_node_names_to_tax_sn_jmi = new JMenuItem( "Transfer Node Names to Taxonomic Scientific Names" ) ); - customizeJMenuItem( _move_node_names_to_tax_sn_jmi ); - _move_node_names_to_tax_sn_jmi.setToolTipText( "To interpret node names as taxonomic scientific names" ); - _tools_menu.add( _move_node_names_to_seq_names_jmi = new JMenuItem( "Transfer Node Names to Sequence Names" ) ); - customizeJMenuItem( _move_node_names_to_seq_names_jmi ); - _move_node_names_to_seq_names_jmi.setToolTipText( "To interpret node names as sequence (protein, gene) names" ); - _tools_menu - .add( _extract_tax_code_from_node_names_jmi = new JMenuItem( "Extract Taxonomic Codes from Node Names" ) ); - customizeJMenuItem( _extract_tax_code_from_node_names_jmi ); - _extract_tax_code_from_node_names_jmi - .setToolTipText( "To extract taxonomic codes (mnemonics) from nodes names in the form of 'xyz_ECOLI'" ); - _tools_menu.addSeparator(); - _tools_menu - .add( _obtain_detailed_taxonomic_information_jmi = new JMenuItem( OBTAIN_DETAILED_TAXONOMIC_INFORMATION ) ); - customizeJMenuItem( _obtain_detailed_taxonomic_information_jmi ); - _obtain_detailed_taxonomic_information_jmi - .setToolTipText( "To add additional taxonomic information (from UniProt Taxonomy)" ); - _tools_menu - .add( _obtain_detailed_taxonomic_information_deleting_jmi = new JMenuItem( "Obtain Detailed Taxonomic Information (deletes nodes!)" ) ); - customizeJMenuItem( _obtain_detailed_taxonomic_information_deleting_jmi ); - _obtain_detailed_taxonomic_information_deleting_jmi - .setToolTipText( "To add additional taxonomic information, deletes nodes for which taxonomy cannot found (from UniProt Taxonomy)" ); - _tools_menu.add( _obtain_seq_information_jmi = new JMenuItem( "Obtain Sequence Information" ) ); - customizeJMenuItem( _obtain_seq_information_jmi ); - _obtain_seq_information_jmi.setToolTipText( "To add additional sequence information" ); - _tools_menu.addSeparator(); - if ( !Constants.__RELEASE ) { - _tools_menu.add( _function_analysis = new JMenuItem( "Add UniProtKB Annotations" ) ); - customizeJMenuItem( _function_analysis ); - _function_analysis - .setToolTipText( "To add UniProtKB annotations for sequences with appropriate identifiers" ); - _tools_menu.addSeparator(); - } - _tools_menu.add( _read_values_jmi = new JMenuItem( "Read Vector/Expression Values" ) ); - customizeJMenuItem( _read_values_jmi ); - _read_values_jmi.setToolTipText( "To add vector (e.g. gene expression) values (beta)" ); - _jmenubar.add( _tools_menu ); - } - - private void choosePdfWidth() { - final String s = ( String ) JOptionPane.showInputDialog( this, - "Please enter the default line width for PDF export.\n" - + "[current value: " - + getOptions().getPrintLineWidth() + "]\n", - "Line Width for PDF Export", - JOptionPane.QUESTION_MESSAGE, - null, - null, - getOptions().getPrintLineWidth() ); - if ( !ForesterUtil.isEmpty( s ) ) { - boolean success = true; - float f = 0.0f; - final String m_str = s.trim(); - if ( !ForesterUtil.isEmpty( m_str ) ) { - try { - f = Float.parseFloat( m_str ); - } - catch ( final Exception ex ) { - success = false; - } - } - else { - success = false; - } - if ( success && ( f > 0.0 ) ) { - getOptions().setPrintLineWidth( f ); - } - } - } - - private void choosePrintSize() { - final String s = ( String ) JOptionPane.showInputDialog( this, - "Please enter values for width and height,\nseparated by a comma.\n" - + "[current values: " - + getOptions().getPrintSizeX() + ", " - + getOptions().getPrintSizeY() + "]\n" - + "[A4: " + Constants.A4_SIZE_X + ", " - + Constants.A4_SIZE_Y + "]\n" + "[US Letter: " - + Constants.US_LETTER_SIZE_X + ", " - + Constants.US_LETTER_SIZE_Y + "]", - "Default Size for Graphics Export", - JOptionPane.QUESTION_MESSAGE, - null, - null, - getOptions().getPrintSizeX() + ", " - + getOptions().getPrintSizeY() ); - if ( !ForesterUtil.isEmpty( s ) && ( s.indexOf( ',' ) > 0 ) ) { - boolean success = true; - int x = 0; - int y = 0; - final String[] str_ary = s.split( "," ); - if ( str_ary.length == 2 ) { - final String x_str = str_ary[ 0 ].trim(); - final String y_str = str_ary[ 1 ].trim(); - if ( !ForesterUtil.isEmpty( x_str ) && !ForesterUtil.isEmpty( y_str ) ) { - try { - x = Integer.parseInt( x_str ); - y = Integer.parseInt( y_str ); - } - catch ( final Exception ex ) { - success = false; - } - } - else { - success = false; - } - } - else { - success = false; - } - if ( success && ( x > 1 ) && ( y > 1 ) ) { - getOptions().setPrintSizeX( x ); - getOptions().setPrintSizeY( y ); - } - } - } - - @Override - void close() { - if ( isUnsavedDataPresent() ) { - final int r = JOptionPane.showConfirmDialog( this, - "Exit despite potentially unsaved changes?", - "Exit?", - JOptionPane.YES_NO_OPTION ); - if ( r != JOptionPane.YES_OPTION ) { - return; - } - } - exit(); - } - - private void closeCurrentPane() { - if ( getMainPanel().getCurrentTreePanel() != null ) { - if ( getMainPanel().getCurrentTreePanel().isEdited() ) { - final int r = JOptionPane.showConfirmDialog( this, - "Close tab despite potentially unsaved changes?", - "Close Tab?", - JOptionPane.YES_NO_OPTION ); - if ( r != JOptionPane.YES_OPTION ) { - return; - } - } - getMainPanel().closeCurrentPane(); - activateSaveAllIfNeeded(); - } - } - - private void collapse( final Phylogeny phy, final double m ) { - final PhylogenyNodeIterator it = phy.iteratorPostorder(); - final List to_be_removed = new ArrayList(); - double min_support = Double.MAX_VALUE; - boolean conf_present = false; - while ( it.hasNext() ) { - final PhylogenyNode n = it.next(); - if ( !n.isExternal() && !n.isRoot() ) { - final List c = n.getBranchData().getConfidences(); - if ( ( c != null ) && ( c.size() > 0 ) ) { - conf_present = true; - double max = 0; - for( final Confidence confidence : c ) { - if ( confidence.getValue() > max ) { - max = confidence.getValue(); - } - } - if ( max < getMinNotCollapseConfidenceValue() ) { - to_be_removed.add( n ); - } - if ( max < min_support ) { - min_support = max; - } - } - } - } - if ( conf_present ) { - for( final PhylogenyNode node : to_be_removed ) { - PhylogenyMethods.removeNode( node, phy ); - } - if ( to_be_removed.size() > 0 ) { - phy.externalNodesHaveChanged(); - phy.clearHashIdToNodeMap(); - phy.recalculateNumberOfExternalDescendants( true ); - getCurrentTreePanel().resetNodeIdToDistToLeafMap(); - getCurrentTreePanel().updateSetOfCollapsedExternalNodes(); - getCurrentTreePanel().calculateLongestExtNodeInfo(); - getCurrentTreePanel().setNodeInPreorderToNull(); - getCurrentTreePanel().recalculateMaxDistanceToRoot(); - getCurrentTreePanel().resetPreferredSize(); - getCurrentTreePanel().setEdited( true ); - getCurrentTreePanel().repaint(); - repaint(); - } - if ( to_be_removed.size() > 0 ) { - JOptionPane.showMessageDialog( this, "Collapsed " + to_be_removed.size() - + " branches with\nconfidence values below " + getMinNotCollapseConfidenceValue(), "Collapsed " - + to_be_removed.size() + " branches", JOptionPane.INFORMATION_MESSAGE ); - } - else { - JOptionPane.showMessageDialog( this, "No branch collapsed,\nminimum confidence value per branch is " - + min_support, "No branch collapsed", JOptionPane.INFORMATION_MESSAGE ); - } - } - else { - JOptionPane.showMessageDialog( this, - "No branch collapsed because no confidence values present", - "No confidence values present", - JOptionPane.INFORMATION_MESSAGE ); + _collapse_below_threshold + .setToolTipText( "To collapse branches with confidence values below a threshold into multifurcations (in the case of multiple confidences per branch: without at least one confidence value above a threshold)" ); + _tools_menu.addSeparator(); + _tools_menu + .add( _move_node_names_to_tax_sn_jmi = new JMenuItem( "Transfer Node Names to Taxonomic Scientific Names" ) ); + customizeJMenuItem( _move_node_names_to_tax_sn_jmi ); + _move_node_names_to_tax_sn_jmi.setToolTipText( "To interpret node names as taxonomic scientific names" ); + _tools_menu.add( _move_node_names_to_seq_names_jmi = new JMenuItem( "Transfer Node Names to Sequence Names" ) ); + customizeJMenuItem( _move_node_names_to_seq_names_jmi ); + _move_node_names_to_seq_names_jmi.setToolTipText( "To interpret node names as sequence (protein, gene) names" ); + _tools_menu + .add( _extract_tax_code_from_node_names_jmi = new JMenuItem( "Extract Taxonomic Codes from Node Names" ) ); + customizeJMenuItem( _extract_tax_code_from_node_names_jmi ); + _extract_tax_code_from_node_names_jmi + .setToolTipText( "To extract taxonomic codes (mnemonics) from nodes names in the form of 'xyz_ECOLI'" ); + _tools_menu.addSeparator(); + _tools_menu + .add( _obtain_detailed_taxonomic_information_jmi = new JMenuItem( OBTAIN_DETAILED_TAXONOMIC_INFORMATION ) ); + customizeJMenuItem( _obtain_detailed_taxonomic_information_jmi ); + _obtain_detailed_taxonomic_information_jmi + .setToolTipText( "To add additional taxonomic information (from UniProt Taxonomy)" ); + _tools_menu + .add( _obtain_detailed_taxonomic_information_deleting_jmi = new JMenuItem( "Obtain Detailed Taxonomic Information (deletes nodes!)" ) ); + customizeJMenuItem( _obtain_detailed_taxonomic_information_deleting_jmi ); + _obtain_detailed_taxonomic_information_deleting_jmi + .setToolTipText( "To add additional taxonomic information, deletes nodes for which taxonomy cannot found (from UniProt Taxonomy)" ); + _tools_menu.add( _obtain_seq_information_jmi = new JMenuItem( "Obtain Sequence Information" ) ); + customizeJMenuItem( _obtain_seq_information_jmi ); + _obtain_seq_information_jmi.setToolTipText( "To add additional sequence information" ); + _tools_menu.addSeparator(); + if ( !Constants.__RELEASE ) { + _tools_menu.add( _function_analysis = new JMenuItem( "Add UniProtKB Annotations" ) ); + customizeJMenuItem( _function_analysis ); + _function_analysis + .setToolTipText( "To add UniProtKB annotations for sequences with appropriate identifiers" ); + _tools_menu.addSeparator(); } + _tools_menu.add( _read_values_jmi = new JMenuItem( "Read Vector/Expression Values" ) ); + customizeJMenuItem( _read_values_jmi ); + _read_values_jmi.setToolTipText( "To add vector (e.g. gene expression) values (beta)" ); + _jmenubar.add( _tools_menu ); } - private void collapseBelowThreshold() { - if ( getCurrentTreePanel() != null ) { - final Phylogeny phy = getCurrentTreePanel().getPhylogeny(); - if ( ( phy != null ) && !phy.isEmpty() ) { - final String s = ( String ) JOptionPane.showInputDialog( this, - "Please enter the minimum confidence value\n", - "Minimal Confidence Value", - JOptionPane.QUESTION_MESSAGE, - null, - null, - getMinNotCollapseConfidenceValue() ); - if ( !ForesterUtil.isEmpty( s ) ) { - boolean success = true; - double m = 0.0; - final String m_str = s.trim(); - if ( !ForesterUtil.isEmpty( m_str ) ) { - try { - m = Double.parseDouble( m_str ); - } - catch ( final Exception ex ) { - success = false; - } - } - else { - success = false; - } - if ( success && ( m >= 0.0 ) ) { - setMinNotCollapseConfidenceValue( m ); - collapse( phy, m ); - } - } + @Override + void close() { + if ( isUnsavedDataPresent() ) { + final int r = JOptionPane.showConfirmDialog( this, + "Exit despite potentially unsaved changes?", + "Exit?", + JOptionPane.YES_NO_OPTION ); + if ( r != JOptionPane.YES_OPTION ) { + return; } } + exit(); } - private PhyloXmlParser createPhyloXmlParser() { - PhyloXmlParser xml_parser = null; - if ( getConfiguration().isValidatePhyloXmlAgainstSchema() ) { - try { - xml_parser = PhyloXmlParser.createPhyloXmlParserXsdValidating(); - } - catch ( final Exception e ) { - JOptionPane.showMessageDialog( this, - e.getLocalizedMessage(), - "failed to create validating XML parser", - JOptionPane.WARNING_MESSAGE ); - } - } - if ( xml_parser == null ) { - xml_parser = new PhyloXmlParser(); + void executeFunctionAnalysis() { + if ( ( _mainpanel.getCurrentPhylogeny() == null ) || ( _mainpanel.getCurrentPhylogeny().isEmpty() ) ) { + return; } - return xml_parser; + final GoAnnotation a = new GoAnnotation( this, + _mainpanel.getCurrentTreePanel(), + _mainpanel.getCurrentPhylogeny() ); + new Thread( a ).start(); } void executeGSDI() { @@ -1319,16 +1293,6 @@ public final class MainFrameApplication extends MainFrame { JOptionPane.INFORMATION_MESSAGE ); } - void executeFunctionAnalysis() { - if ( ( _mainpanel.getCurrentPhylogeny() == null ) || ( _mainpanel.getCurrentPhylogeny().isEmpty() ) ) { - return; - } - final GoAnnotation a = new GoAnnotation( this, - _mainpanel.getCurrentTreePanel(), - _mainpanel.getCurrentPhylogeny() ); - new Thread( a ).start(); - } - void executeLineageInference() { if ( ( _mainpanel.getCurrentPhylogeny() == null ) || ( _mainpanel.getCurrentPhylogeny().isEmpty() ) ) { return; @@ -1347,43 +1311,6 @@ public final class MainFrameApplication extends MainFrame { new Thread( inferrer ).start(); } - private void executePhyleneticInference( final boolean from_unaligned_seqs ) { - final PhyloInferenceDialog dialog = new PhyloInferenceDialog( this, - getPhylogeneticInferenceOptions(), - from_unaligned_seqs ); - dialog.activate(); - if ( dialog.getValue() == JOptionPane.OK_OPTION ) { - if ( !from_unaligned_seqs ) { - if ( getMsa() != null ) { - final PhylogeneticInferrer inferrer = new PhylogeneticInferrer( getMsa(), - getPhylogeneticInferenceOptions() - .copy(), this ); - new Thread( inferrer ).start(); - } - else { - JOptionPane.showMessageDialog( this, - "No multiple sequence alignment selected", - "Phylogenetic Inference Not Launched", - JOptionPane.WARNING_MESSAGE ); - } - } - else { - if ( getSeqs() != null ) { - final PhylogeneticInferrer inferrer = new PhylogeneticInferrer( getSeqs(), - getPhylogeneticInferenceOptions() - .copy(), this ); - new Thread( inferrer ).start(); - } - else { - JOptionPane.showMessageDialog( this, - "No input sequences selected", - "Phylogenetic Inference Not Launched", - JOptionPane.WARNING_MESSAGE ); - } - } - } - } - void executeSDIR( final boolean minimize_cost ) { if ( !isOKforSDI( true, true ) ) { return; @@ -1424,68 +1351,6 @@ public final class MainFrameApplication extends MainFrame { System.exit( 0 ); } - public void end() { - _mainpanel.terminate(); - _contentpane.removeAll(); - setVisible( false ); - dispose(); - } - - private void extractTaxCodeFromNodeNames() throws PhyloXmlDataFormatException { - if ( getCurrentTreePanel() != null ) { - final Phylogeny phy = getCurrentTreePanel().getPhylogeny(); - if ( ( phy != null ) && !phy.isEmpty() ) { - final PhylogenyNodeIterator it = phy.iteratorPostorder(); - while ( it.hasNext() ) { - final PhylogenyNode n = it.next(); - final String name = n.getName().trim(); - if ( !ForesterUtil.isEmpty( name ) ) { - final String code = ParserUtils - .extractTaxonomyCodeFromNodeName( name, NHXParser.TAXONOMY_EXTRACTION.YES ); - if ( !ForesterUtil.isEmpty( code ) ) { - PhylogenyMethods.setTaxonomyCode( n, code ); - } - } - } - } - } - } - - private ControlPanel getControlPanel() { - return getMainPanel().getControlPanel(); - } - - private File getCurrentDir() { - if ( ( _current_dir == null ) || !_current_dir.canRead() ) { - if ( ForesterUtil.isWindowns() ) { - try { - _current_dir = new File( WindowsUtils.getCurrentUserDesktopPath() ); - } - catch ( final Exception e ) { - _current_dir = null; - } - } - } - if ( ( _current_dir == null ) || !_current_dir.canRead() ) { - if ( System.getProperty( "user.home" ) != null ) { - _current_dir = new File( System.getProperty( "user.home" ) ); - } - else if ( System.getProperty( "user.dir" ) != null ) { - _current_dir = new File( System.getProperty( "user.dir" ) ); - } - } - return _current_dir; - } - - @Override - public MainPanel getMainPanel() { - return _mainpanel; - } - - private double getMinNotCollapseConfidenceValue() { - return _min_not_collapse; - } - boolean isOKforSDI( final boolean species_tree_has_to_binary, final boolean gene_tree_has_to_binary ) { if ( ( _mainpanel.getCurrentPhylogeny() == null ) || _mainpanel.getCurrentPhylogeny().isEmpty() ) { return false; @@ -1516,178 +1381,138 @@ public final class MainFrameApplication extends MainFrame { } } - private boolean isUnsavedDataPresent() { - final List tps = getMainPanel().getTreePanels(); - for( final TreePanel tp : tps ) { - if ( tp.isEdited() ) { - return true; + @Override + void readPhylogeniesFromURL() { + URL url = null; + Phylogeny[] phys = null; + final String message = "Please enter a complete URL, for example \"http://www.phyloxml.org/examples/apaf.xml\""; + final String url_string = JOptionPane.showInputDialog( this, + message, + "Use URL/webservice to obtain a phylogeny", + JOptionPane.QUESTION_MESSAGE ); + boolean nhx_or_nexus = false; + if ( ( url_string != null ) && ( url_string.length() > 0 ) ) { + try { + url = new URL( url_string ); + PhylogenyParser parser = null; + if ( url.getHost().toLowerCase().indexOf( "tolweb" ) >= 0 ) { + parser = new TolParser(); + } + else { + parser = ParserUtils.createParserDependingOnUrlContents( url, getConfiguration() + .isValidatePhyloXmlAgainstSchema() ); + } + if ( parser instanceof NexusPhylogeniesParser ) { + nhx_or_nexus = true; + } + else if ( parser instanceof NHXParser ) { + nhx_or_nexus = true; + } + if ( _mainpanel.getCurrentTreePanel() != null ) { + _mainpanel.getCurrentTreePanel().setWaitCursor(); + } + else { + _mainpanel.setWaitCursor(); + } + final PhylogenyFactory factory = ParserBasedPhylogenyFactory.getInstance(); + phys = factory.create( url.openStream(), parser ); + } + catch ( final MalformedURLException e ) { + JOptionPane.showMessageDialog( this, + "Malformed URL: " + url + "\n" + e.getLocalizedMessage(), + "Malformed URL", + JOptionPane.ERROR_MESSAGE ); } - } - return false; - } - - private void moveNodeNamesToSeqNames() throws PhyloXmlDataFormatException { - if ( getCurrentTreePanel() != null ) { - final Phylogeny phy = getCurrentTreePanel().getPhylogeny(); - if ( ( phy != null ) && !phy.isEmpty() ) { - PhylogenyMethods - .transferNodeNameToField( phy, PhylogenyMethods.PhylogenyNodeField.SEQUENCE_NAME, false ); + catch ( final IOException e ) { + JOptionPane.showMessageDialog( this, + "Could not read from " + url + "\n" + + ForesterUtil.wordWrap( e.getLocalizedMessage(), 80 ), + "Failed to read URL", + JOptionPane.ERROR_MESSAGE ); } - } - } - - private void moveNodeNamesToTaxSn() throws PhyloXmlDataFormatException { - if ( getCurrentTreePanel() != null ) { - final Phylogeny phy = getCurrentTreePanel().getPhylogeny(); - if ( ( phy != null ) && !phy.isEmpty() ) { - PhylogenyMethods.transferNodeNameToField( phy, - PhylogenyMethods.PhylogenyNodeField.TAXONOMY_SCIENTIFIC_NAME, - false ); + catch ( final Exception e ) { + JOptionPane.showMessageDialog( this, + ForesterUtil.wordWrap( e.getLocalizedMessage(), 80 ), + "Unexpected Exception", + JOptionPane.ERROR_MESSAGE ); + } + finally { + if ( _mainpanel.getCurrentTreePanel() != null ) { + _mainpanel.getCurrentTreePanel().setArrowCursor(); + } + else { + _mainpanel.setArrowCursor(); + } + } + if ( ( phys != null ) && ( phys.length > 0 ) ) { + if ( nhx_or_nexus && getOptions().isInternalNumberAreConfidenceForNhParsing() ) { + for( final Phylogeny phy : phys ) { + PhylogenyMethods.transferInternalNodeNamesToConfidence( phy ); + } + } + AptxUtil.addPhylogeniesToTabs( phys, + new File( url.getFile() ).getName(), + new File( url.getFile() ).toString(), + getConfiguration(), + getMainPanel() ); + _mainpanel.getControlPanel().showWhole(); } - } - } - - private void newTree() { - final Phylogeny[] phys = new Phylogeny[ 1 ]; - final Phylogeny phy = new Phylogeny(); - final PhylogenyNode node = new PhylogenyNode(); - phy.setRoot( node ); - phy.setRooted( true ); - phys[ 0 ] = phy; - AptxUtil.addPhylogeniesToTabs( phys, "", "", getConfiguration(), getMainPanel() ); - _mainpanel.getControlPanel().showWhole(); - _mainpanel.getCurrentTreePanel().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR ); - _mainpanel.getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR ); - if ( getMainPanel().getMainFrame() == null ) { - // Must be "E" applet version. - ( ( ArchaeopteryxE ) ( ( MainPanelApplets ) getMainPanel() ).getApplet() ) - .setSelectedTypeInTypeMenu( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR ); - } - else { - getMainPanel().getMainFrame().setSelectedTypeInTypeMenu( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR ); } activateSaveAllIfNeeded(); System.gc(); } - private void obtainDetailedTaxonomicInformation() { - if ( getCurrentTreePanel() != null ) { - final Phylogeny phy = getCurrentTreePanel().getPhylogeny(); - if ( ( phy != null ) && !phy.isEmpty() ) { - final TaxonomyDataManager t = new TaxonomyDataManager( this, - _mainpanel.getCurrentTreePanel(), - phy.copy(), - false, - true ); - new Thread( t ).start(); - } - } + void setMsa( final Msa msa ) { + _msa = msa; } - private void obtainDetailedTaxonomicInformationDelete() { - if ( getCurrentTreePanel() != null ) { - final Phylogeny phy = getCurrentTreePanel().getPhylogeny(); - if ( ( phy != null ) && !phy.isEmpty() ) { - final TaxonomyDataManager t = new TaxonomyDataManager( this, - _mainpanel.getCurrentTreePanel(), - phy.copy(), - true, - true ); - new Thread( t ).start(); - } - } + void setMsaFile( final File msa_file ) { + _msa_file = msa_file; } - private void obtainSequenceInformation() { - if ( getCurrentTreePanel() != null ) { - final Phylogeny phy = getCurrentTreePanel().getPhylogeny(); - if ( ( phy != null ) && !phy.isEmpty() ) { - final SequenceDataRetriver u = new SequenceDataRetriver( this, - _mainpanel.getCurrentTreePanel(), - phy.copy() ); - new Thread( u ).start(); - } - } + void setSeqs( final List seqs ) { + _seqs = seqs; } - private void print() { - if ( ( getCurrentTreePanel() == null ) || ( getCurrentTreePanel().getPhylogeny() == null ) - || getCurrentTreePanel().getPhylogeny().isEmpty() ) { - return; - } - if ( !getOptions().isPrintUsingActualSize() ) { - getCurrentTreePanel().setParametersForPainting( getOptions().getPrintSizeX() - 80, - getOptions().getPrintSizeY() - 140, - true ); - getCurrentTreePanel().resetPreferredSize(); - getCurrentTreePanel().repaint(); - } - final String job_name = Constants.PRG_NAME; - boolean error = false; - String printer_name = null; - try { - printer_name = Printer.print( getCurrentTreePanel(), job_name ); - } - catch ( final Exception e ) { - error = true; - JOptionPane.showMessageDialog( this, e.getMessage(), "Printing Error", JOptionPane.ERROR_MESSAGE ); - } - if ( !error && ( printer_name != null ) ) { - String msg = "Printing data sent to printer"; - if ( printer_name.length() > 1 ) { - msg += " [" + printer_name + "]"; - } - JOptionPane.showMessageDialog( this, msg, "Printing...", JOptionPane.INFORMATION_MESSAGE ); - } - if ( !getOptions().isPrintUsingActualSize() ) { - getControlPanel().showWhole(); - } + void setSeqsFile( final File seqs_file ) { + _seqs_file = seqs_file; } - private void printPhylogenyToPdf( final String file_name ) { - if ( !getOptions().isPrintUsingActualSize() ) { - getCurrentTreePanel().setParametersForPainting( getOptions().getPrintSizeX(), - getOptions().getPrintSizeY(), - true ); - getCurrentTreePanel().resetPreferredSize(); - getCurrentTreePanel().repaint(); - } - String pdf_written_to = ""; + void writePhylogenyToGraphicsFile( final String file_name, final GraphicsExportType type ) { + _mainpanel.getCurrentTreePanel().setParametersForPainting( _mainpanel.getCurrentTreePanel().getWidth(), + _mainpanel.getCurrentTreePanel().getHeight(), + true ); + String file_written_to = ""; boolean error = false; try { - if ( getOptions().isPrintUsingActualSize() ) { - pdf_written_to = PdfExporter.writePhylogenyToPdf( file_name, - getCurrentTreePanel(), - getCurrentTreePanel().getWidth(), - getCurrentTreePanel().getHeight() ); - } - else { - pdf_written_to = PdfExporter.writePhylogenyToPdf( file_name, getCurrentTreePanel(), getOptions() - .getPrintSizeX(), getOptions().getPrintSizeY() ); - } + file_written_to = AptxUtil.writePhylogenyToGraphicsFile( file_name, + _mainpanel.getCurrentTreePanel().getWidth(), + _mainpanel.getCurrentTreePanel().getHeight(), + _mainpanel.getCurrentTreePanel(), + _mainpanel.getControlPanel(), + type, + getOptions() ); } catch ( final IOException e ) { error = true; JOptionPane.showMessageDialog( this, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE ); } if ( !error ) { - if ( !ForesterUtil.isEmpty( pdf_written_to ) ) { + if ( ( file_written_to != null ) && ( file_written_to.length() > 0 ) ) { JOptionPane.showMessageDialog( this, - "Wrote PDF to: " + pdf_written_to, - "Information", + "Wrote image to: " + file_written_to, + "Graphics Export", JOptionPane.INFORMATION_MESSAGE ); } else { JOptionPane.showMessageDialog( this, - "There was an unknown problem when attempting to write to PDF file: \"" + "There was an unknown problem when attempting to write to an image file: \"" + file_name + "\"", "Error", JOptionPane.ERROR_MESSAGE ); } } - if ( !getOptions().isPrintUsingActualSize() ) { - getControlPanel().showWhole(); - } + _contentpane.repaint(); } private void addExpressionValuesFromFile() { @@ -1785,447 +1610,632 @@ public final class MainFrameApplication extends MainFrame { stats.addValue( d ); l.add( d ); } - if ( !l.isEmpty() ) { - if ( node.getNodeData().getProperties() != null ) { - node.getNodeData().getProperties() - .removePropertiesWithGivenReferencePrefix( PhyloXmlUtil.VECTOR_PROPERTY_REF ); - } - node.getNodeData().setVector( l ); + if ( !l.isEmpty() ) { + if ( node.getNodeData().getProperties() != null ) { + node.getNodeData().getProperties() + .removePropertiesWithGivenReferencePrefix( PhyloXmlUtil.VECTOR_PROPERTY_REF ); + } + node.getNodeData().setVector( l ); + } + } + } + if ( not_found > 0 ) { + JOptionPane.showMessageDialog( this, "Could not fine expression values for " + not_found + + " external node(s)", "Warning", JOptionPane.WARNING_MESSAGE ); + } + getCurrentTreePanel().setStatisticsForExpressionValues( stats ); + } + } + + private void choosePdfWidth() { + final String s = ( String ) JOptionPane.showInputDialog( this, + "Please enter the default line width for PDF export.\n" + + "[current value: " + + getOptions().getPrintLineWidth() + "]\n", + "Line Width for PDF Export", + JOptionPane.QUESTION_MESSAGE, + null, + null, + getOptions().getPrintLineWidth() ); + if ( !ForesterUtil.isEmpty( s ) ) { + boolean success = true; + float f = 0.0f; + final String m_str = s.trim(); + if ( !ForesterUtil.isEmpty( m_str ) ) { + try { + f = Float.parseFloat( m_str ); + } + catch ( final Exception ex ) { + success = false; + } + } + else { + success = false; + } + if ( success && ( f > 0.0 ) ) { + getOptions().setPrintLineWidth( f ); + } + } + } + + private void choosePrintSize() { + final String s = ( String ) JOptionPane.showInputDialog( this, + "Please enter values for width and height,\nseparated by a comma.\n" + + "[current values: " + + getOptions().getPrintSizeX() + ", " + + getOptions().getPrintSizeY() + "]\n" + + "[A4: " + Constants.A4_SIZE_X + ", " + + Constants.A4_SIZE_Y + "]\n" + "[US Letter: " + + Constants.US_LETTER_SIZE_X + ", " + + Constants.US_LETTER_SIZE_Y + "]", + "Default Size for Graphics Export", + JOptionPane.QUESTION_MESSAGE, + null, + null, + getOptions().getPrintSizeX() + ", " + + getOptions().getPrintSizeY() ); + if ( !ForesterUtil.isEmpty( s ) && ( s.indexOf( ',' ) > 0 ) ) { + boolean success = true; + int x = 0; + int y = 0; + final String[] str_ary = s.split( "," ); + if ( str_ary.length == 2 ) { + final String x_str = str_ary[ 0 ].trim(); + final String y_str = str_ary[ 1 ].trim(); + if ( !ForesterUtil.isEmpty( x_str ) && !ForesterUtil.isEmpty( y_str ) ) { + try { + x = Integer.parseInt( x_str ); + y = Integer.parseInt( y_str ); + } + catch ( final Exception ex ) { + success = false; } } + else { + success = false; + } } - if ( not_found > 0 ) { - JOptionPane.showMessageDialog( this, "Could not fine expression values for " + not_found - + " external node(s)", "Warning", JOptionPane.WARNING_MESSAGE ); + else { + success = false; + } + if ( success && ( x > 1 ) && ( y > 1 ) ) { + getOptions().setPrintSizeX( x ); + getOptions().setPrintSizeY( y ); } - getCurrentTreePanel().setStatisticsForExpressionValues( stats ); } } - private void readPhylogeniesFromFile() { - boolean exception = false; - Phylogeny[] phys = null; - // Set an initial directory if none set yet - final File my_dir = getCurrentDir(); - _open_filechooser.setMultiSelectionEnabled( true ); - // Open file-open dialog and set current directory - if ( my_dir != null ) { - _open_filechooser.setCurrentDirectory( my_dir ); + private void closeCurrentPane() { + if ( getMainPanel().getCurrentTreePanel() != null ) { + if ( getMainPanel().getCurrentTreePanel().isEdited() ) { + final int r = JOptionPane.showConfirmDialog( this, + "Close tab despite potentially unsaved changes?", + "Close Tab?", + JOptionPane.YES_NO_OPTION ); + if ( r != JOptionPane.YES_OPTION ) { + return; + } + } + getMainPanel().closeCurrentPane(); + activateSaveAllIfNeeded(); } - final int result = _open_filechooser.showOpenDialog( _contentpane ); - // All done: get the file - final File[] files = _open_filechooser.getSelectedFiles(); - setCurrentDir( _open_filechooser.getCurrentDirectory() ); - boolean nhx_or_nexus = false; - if ( ( files != null ) && ( files.length > 0 ) && ( result == JFileChooser.APPROVE_OPTION ) ) { - for( final File file : files ) { - if ( ( file != null ) && !file.isDirectory() ) { - if ( _mainpanel.getCurrentTreePanel() != null ) { - _mainpanel.getCurrentTreePanel().setWaitCursor(); - } - else { - _mainpanel.setWaitCursor(); - } - if ( ( _open_filechooser.getFileFilter() == MainFrameApplication.nhfilter ) - || ( _open_filechooser.getFileFilter() == MainFrameApplication.nhxfilter ) ) { - try { - final NHXParser nhx = new NHXParser(); - setSpecialOptionsForNhxParser( nhx ); - phys = PhylogenyMethods.readPhylogenies( nhx, file ); - nhx_or_nexus = true; - } - catch ( final Exception e ) { - exception = true; - exceptionOccuredDuringOpenFile( e ); - } - } - else if ( _open_filechooser.getFileFilter() == MainFrameApplication.xmlfilter ) { - warnIfNotPhyloXmlValidation( getConfiguration() ); - try { - final PhyloXmlParser xml_parser = createPhyloXmlParser(); - phys = PhylogenyMethods.readPhylogenies( xml_parser, file ); - } - catch ( final Exception e ) { - exception = true; - exceptionOccuredDuringOpenFile( e ); + } + + private void collapse( final Phylogeny phy, final double m ) { + final PhylogenyNodeIterator it = phy.iteratorPostorder(); + final List to_be_removed = new ArrayList(); + double min_support = Double.MAX_VALUE; + boolean conf_present = false; + while ( it.hasNext() ) { + final PhylogenyNode n = it.next(); + if ( !n.isExternal() && !n.isRoot() ) { + final List c = n.getBranchData().getConfidences(); + if ( ( c != null ) && ( c.size() > 0 ) ) { + conf_present = true; + double max = 0; + for( final Confidence confidence : c ) { + if ( confidence.getValue() > max ) { + max = confidence.getValue(); } } - else if ( _open_filechooser.getFileFilter() == MainFrameApplication.tolfilter ) { - try { - phys = PhylogenyMethods.readPhylogenies( new TolParser(), file ); - } - catch ( final Exception e ) { - exception = true; - exceptionOccuredDuringOpenFile( e ); - } + if ( max < getMinNotCollapseConfidenceValue() ) { + to_be_removed.add( n ); } - else if ( _open_filechooser.getFileFilter() == MainFrameApplication.nexusfilter ) { - try { - final NexusPhylogeniesParser nex = new NexusPhylogeniesParser(); - setSpecialOptionsForNexParser( nex ); - phys = PhylogenyMethods.readPhylogenies( nex, file ); - nhx_or_nexus = true; - } - catch ( final Exception e ) { - exception = true; - exceptionOccuredDuringOpenFile( e ); - } + if ( max < min_support ) { + min_support = max; } - // "*.*": - else { + } + } + } + if ( conf_present ) { + for( final PhylogenyNode node : to_be_removed ) { + PhylogenyMethods.removeNode( node, phy ); + } + if ( to_be_removed.size() > 0 ) { + phy.externalNodesHaveChanged(); + phy.clearHashIdToNodeMap(); + phy.recalculateNumberOfExternalDescendants( true ); + getCurrentTreePanel().resetNodeIdToDistToLeafMap(); + getCurrentTreePanel().updateSetOfCollapsedExternalNodes(); + getCurrentTreePanel().calculateLongestExtNodeInfo(); + getCurrentTreePanel().setNodeInPreorderToNull(); + getCurrentTreePanel().recalculateMaxDistanceToRoot(); + getCurrentTreePanel().resetPreferredSize(); + getCurrentTreePanel().setEdited( true ); + getCurrentTreePanel().repaint(); + repaint(); + } + if ( to_be_removed.size() > 0 ) { + JOptionPane.showMessageDialog( this, "Collapsed " + to_be_removed.size() + + " branches with\nconfidence values below " + getMinNotCollapseConfidenceValue(), "Collapsed " + + to_be_removed.size() + " branches", JOptionPane.INFORMATION_MESSAGE ); + } + else { + JOptionPane.showMessageDialog( this, "No branch collapsed,\nminimum confidence value per branch is " + + min_support, "No branch collapsed", JOptionPane.INFORMATION_MESSAGE ); + } + } + else { + JOptionPane.showMessageDialog( this, + "No branch collapsed because no confidence values present", + "No confidence values present", + JOptionPane.INFORMATION_MESSAGE ); + } + } + + private void collapseBelowThreshold() { + if ( getCurrentTreePanel() != null ) { + final Phylogeny phy = getCurrentTreePanel().getPhylogeny(); + if ( ( phy != null ) && !phy.isEmpty() ) { + final String s = ( String ) JOptionPane.showInputDialog( this, + "Please enter the minimum confidence value\n", + "Minimal Confidence Value", + JOptionPane.QUESTION_MESSAGE, + null, + null, + getMinNotCollapseConfidenceValue() ); + if ( !ForesterUtil.isEmpty( s ) ) { + boolean success = true; + double m = 0.0; + final String m_str = s.trim(); + if ( !ForesterUtil.isEmpty( m_str ) ) { try { - final PhylogenyParser parser = ParserUtils - .createParserDependingOnFileType( file, getConfiguration() - .isValidatePhyloXmlAgainstSchema() ); - if ( parser instanceof NexusPhylogeniesParser ) { - final NexusPhylogeniesParser nex = ( NexusPhylogeniesParser ) parser; - setSpecialOptionsForNexParser( nex ); - nhx_or_nexus = true; - } - else if ( parser instanceof NHXParser ) { - final NHXParser nhx = ( NHXParser ) parser; - setSpecialOptionsForNhxParser( nhx ); - nhx_or_nexus = true; - } - else if ( parser instanceof PhyloXmlParser ) { - warnIfNotPhyloXmlValidation( getConfiguration() ); - } - phys = PhylogenyMethods.readPhylogenies( parser, file ); + m = Double.parseDouble( m_str ); } - catch ( final Exception e ) { - exception = true; - exceptionOccuredDuringOpenFile( e ); + catch ( final Exception ex ) { + success = false; } } - if ( _mainpanel.getCurrentTreePanel() != null ) { - _mainpanel.getCurrentTreePanel().setArrowCursor(); - } else { - _mainpanel.setArrowCursor(); + success = false; } - if ( !exception && ( phys != null ) && ( phys.length > 0 ) ) { - boolean one_desc = false; - if ( nhx_or_nexus ) { - for( final Phylogeny phy : phys ) { - if ( getOptions().isInternalNumberAreConfidenceForNhParsing() ) { - PhylogenyMethods.transferInternalNodeNamesToConfidence( phy ); - } - if ( PhylogenyMethods.getMinimumDescendentsPerInternalNodes( phy ) == 1 ) { - one_desc = true; - break; - } - } - } - AptxUtil.addPhylogeniesToTabs( phys, - file.getName(), - file.getAbsolutePath(), - getConfiguration(), - getMainPanel() ); - _mainpanel.getControlPanel().showWhole(); - if ( nhx_or_nexus && one_desc ) { - JOptionPane - .showMessageDialog( this, - "One or more trees contain (a) node(s) with one descendant, " - + ForesterUtil.LINE_SEPARATOR - + "possibly indicating illegal parentheses within node names.", - "Warning: Possible Error in New Hampshire Formatted Data", - JOptionPane.WARNING_MESSAGE ); - } + if ( success && ( m >= 0.0 ) ) { + setMinNotCollapseConfidenceValue( m ); + collapse( phy, m ); } } } } - activateSaveAllIfNeeded(); - System.gc(); } - public void readSeqsFromFile() { - // Set an initial directory if none set yet - final File my_dir = getCurrentDir(); - _seqs_filechooser.setMultiSelectionEnabled( false ); - // Open file-open dialog and set current directory - if ( my_dir != null ) { - _seqs_filechooser.setCurrentDirectory( my_dir ); - } - final int result = _seqs_filechooser.showOpenDialog( _contentpane ); - // All done: get the seqs - final File file = _seqs_filechooser.getSelectedFile(); - setCurrentDir( _seqs_filechooser.getCurrentDirectory() ); - if ( ( file != null ) && !file.isDirectory() && ( result == JFileChooser.APPROVE_OPTION ) ) { - setSeqsFile( null ); - setSeqs( null ); - List seqs = null; - try { - if ( FastaParser.isLikelyFasta( new FileInputStream( file ) ) ) { - seqs = FastaParser.parse( new FileInputStream( file ) ); - for( final Sequence seq : seqs ) { - System.out.println( SequenceWriter.toFasta( seq, 60 ) ); - } + private PhyloXmlParser createPhyloXmlParser() { + PhyloXmlParser xml_parser = null; + if ( getConfiguration().isValidatePhyloXmlAgainstSchema() ) { + try { + xml_parser = PhyloXmlParser.createPhyloXmlParserXsdValidating(); + } + catch ( final Exception e ) { + JOptionPane.showMessageDialog( this, + e.getLocalizedMessage(), + "failed to create validating XML parser", + JOptionPane.WARNING_MESSAGE ); + } + } + if ( xml_parser == null ) { + xml_parser = new PhyloXmlParser(); + } + return xml_parser; + } + + private void executePhyleneticInference( final boolean from_unaligned_seqs ) { + final PhyloInferenceDialog dialog = new PhyloInferenceDialog( this, + getPhylogeneticInferenceOptions(), + from_unaligned_seqs ); + dialog.activate(); + if ( dialog.getValue() == JOptionPane.OK_OPTION ) { + if ( !from_unaligned_seqs ) { + if ( getMsa() != null ) { + final PhylogeneticInferrer inferrer = new PhylogeneticInferrer( getMsa(), + getPhylogeneticInferenceOptions() + .copy(), this ); + new Thread( inferrer ).start(); } else { - //TODO error + JOptionPane.showMessageDialog( this, + "No multiple sequence alignment selected", + "Phylogenetic Inference Not Launched", + JOptionPane.WARNING_MESSAGE ); } } - catch ( final MsaFormatException e ) { - try { - _mainpanel.getCurrentTreePanel().setArrowCursor(); + else { + if ( getSeqs() != null ) { + final PhylogeneticInferrer inferrer = new PhylogeneticInferrer( getSeqs(), + getPhylogeneticInferenceOptions() + .copy(), this ); + new Thread( inferrer ).start(); } - catch ( final Exception ex ) { - // Do nothing. + else { + JOptionPane.showMessageDialog( this, + "No input sequences selected", + "Phylogenetic Inference Not Launched", + JOptionPane.WARNING_MESSAGE ); } - JOptionPane.showMessageDialog( this, - e.getLocalizedMessage(), - "Multiple sequence file format error", - JOptionPane.ERROR_MESSAGE ); - return; } - catch ( final IOException e ) { - try { - _mainpanel.getCurrentTreePanel().setArrowCursor(); - } - catch ( final Exception ex ) { - // Do nothing. + } + } + + private void extractTaxCodeFromNodeNames() throws PhyloXmlDataFormatException { + if ( getCurrentTreePanel() != null ) { + final Phylogeny phy = getCurrentTreePanel().getPhylogeny(); + if ( ( phy != null ) && !phy.isEmpty() ) { + final PhylogenyNodeIterator it = phy.iteratorPostorder(); + while ( it.hasNext() ) { + final PhylogenyNode n = it.next(); + final String name = n.getName().trim(); + if ( !ForesterUtil.isEmpty( name ) ) { + final String code = ParserUtils + .extractTaxonomyCodeFromNodeName( name, NHXParser.TAXONOMY_EXTRACTION.YES ); + if ( !ForesterUtil.isEmpty( code ) ) { + PhylogenyMethods.setTaxonomyCode( n, code ); + } + } } - JOptionPane.showMessageDialog( this, - e.getLocalizedMessage(), - "Failed to read multiple sequence file", - JOptionPane.ERROR_MESSAGE ); - return; } - catch ( final IllegalArgumentException e ) { + } + } + + private ControlPanel getControlPanel() { + return getMainPanel().getControlPanel(); + } + + private File getCurrentDir() { + if ( ( _current_dir == null ) || !_current_dir.canRead() ) { + if ( ForesterUtil.isWindowns() ) { try { - _mainpanel.getCurrentTreePanel().setArrowCursor(); + _current_dir = new File( WindowsUtils.getCurrentUserDesktopPath() ); } - catch ( final Exception ex ) { - // Do nothing. + catch ( final Exception e ) { + _current_dir = null; } - JOptionPane.showMessageDialog( this, - e.getLocalizedMessage(), - "Unexpected error during reading of multiple sequence file", - JOptionPane.ERROR_MESSAGE ); - return; } - catch ( final Exception e ) { - try { - _mainpanel.getCurrentTreePanel().setArrowCursor(); - } - catch ( final Exception ex ) { - // Do nothing. - } - e.printStackTrace(); - JOptionPane.showMessageDialog( this, - e.getLocalizedMessage(), - "Unexpected error during reading of multiple sequence file", - JOptionPane.ERROR_MESSAGE ); - return; + } + if ( ( _current_dir == null ) || !_current_dir.canRead() ) { + if ( System.getProperty( "user.home" ) != null ) { + _current_dir = new File( System.getProperty( "user.home" ) ); } - if ( ( seqs == null ) || ( seqs.size() < 1 ) ) { - JOptionPane.showMessageDialog( this, - "Multiple sequence file is empty", - "Illegal multiple sequence file", - JOptionPane.ERROR_MESSAGE ); - return; + else if ( System.getProperty( "user.dir" ) != null ) { + _current_dir = new File( System.getProperty( "user.dir" ) ); } - if ( seqs.size() < 4 ) { - JOptionPane.showMessageDialog( this, - "Multiple sequence file needs to contain at least 3 sequences", - "Illegal multiple sequence file", - JOptionPane.ERROR_MESSAGE ); - return; + } + return _current_dir; + } + + private double getMinNotCollapseConfidenceValue() { + return _min_not_collapse; + } + + private PhylogeneticInferenceOptions getPhylogeneticInferenceOptions() { + if ( _phylogenetic_inference_options == null ) { + _phylogenetic_inference_options = new PhylogeneticInferenceOptions(); + } + return _phylogenetic_inference_options; + } + + private boolean isUnsavedDataPresent() { + final List tps = getMainPanel().getTreePanels(); + for( final TreePanel tp : tps ) { + if ( tp.isEdited() ) { + return true; + } + } + return false; + } + + private void moveNodeNamesToSeqNames() throws PhyloXmlDataFormatException { + if ( getCurrentTreePanel() != null ) { + final Phylogeny phy = getCurrentTreePanel().getPhylogeny(); + if ( ( phy != null ) && !phy.isEmpty() ) { + PhylogenyMethods + .transferNodeNameToField( phy, PhylogenyMethods.PhylogenyNodeField.SEQUENCE_NAME, false ); + } + } + } + + private void moveNodeNamesToTaxSn() throws PhyloXmlDataFormatException { + if ( getCurrentTreePanel() != null ) { + final Phylogeny phy = getCurrentTreePanel().getPhylogeny(); + if ( ( phy != null ) && !phy.isEmpty() ) { + PhylogenyMethods.transferNodeNameToField( phy, + PhylogenyMethods.PhylogenyNodeField.TAXONOMY_SCIENTIFIC_NAME, + false ); + } + } + } + + private void newTree() { + final Phylogeny[] phys = new Phylogeny[ 1 ]; + final Phylogeny phy = new Phylogeny(); + final PhylogenyNode node = new PhylogenyNode(); + phy.setRoot( node ); + phy.setRooted( true ); + phys[ 0 ] = phy; + AptxUtil.addPhylogeniesToTabs( phys, "", "", getConfiguration(), getMainPanel() ); + _mainpanel.getControlPanel().showWhole(); + _mainpanel.getCurrentTreePanel().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR ); + _mainpanel.getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR ); + if ( getMainPanel().getMainFrame() == null ) { + // Must be "E" applet version. + ( ( ArchaeopteryxE ) ( ( MainPanelApplets ) getMainPanel() ).getApplet() ) + .setSelectedTypeInTypeMenu( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR ); + } + else { + getMainPanel().getMainFrame().setSelectedTypeInTypeMenu( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR ); + } + activateSaveAllIfNeeded(); + System.gc(); + } + + private void obtainDetailedTaxonomicInformation() { + if ( getCurrentTreePanel() != null ) { + final Phylogeny phy = getCurrentTreePanel().getPhylogeny(); + if ( ( phy != null ) && !phy.isEmpty() ) { + final TaxonomyDataManager t = new TaxonomyDataManager( this, + _mainpanel.getCurrentTreePanel(), + phy.copy(), + false, + true ); + new Thread( t ).start(); + } + } + } + + private void obtainDetailedTaxonomicInformationDelete() { + if ( getCurrentTreePanel() != null ) { + final Phylogeny phy = getCurrentTreePanel().getPhylogeny(); + if ( ( phy != null ) && !phy.isEmpty() ) { + final TaxonomyDataManager t = new TaxonomyDataManager( this, + _mainpanel.getCurrentTreePanel(), + phy.copy(), + true, + true ); + new Thread( t ).start(); + } + } + } + + private void obtainSequenceInformation() { + if ( getCurrentTreePanel() != null ) { + final Phylogeny phy = getCurrentTreePanel().getPhylogeny(); + if ( ( phy != null ) && !phy.isEmpty() ) { + final SequenceDataRetriver u = new SequenceDataRetriver( this, + _mainpanel.getCurrentTreePanel(), + phy.copy() ); + new Thread( u ).start(); } - // if ( msa.getLength() < 2 ) { - // JOptionPane.showMessageDialog( this, - // "Multiple sequence alignment needs to contain at least 2 residues", - // "Illegal multiple sequence file", - // JOptionPane.ERROR_MESSAGE ); - // return; - // } - System.gc(); - setSeqsFile( _seqs_filechooser.getSelectedFile() ); - setSeqs( seqs ); } } - public void readMsaFromFile() { - // Set an initial directory if none set yet - final File my_dir = getCurrentDir(); - _msa_filechooser.setMultiSelectionEnabled( false ); - // Open file-open dialog and set current directory - if ( my_dir != null ) { - _msa_filechooser.setCurrentDirectory( my_dir ); + private void print() { + if ( ( getCurrentTreePanel() == null ) || ( getCurrentTreePanel().getPhylogeny() == null ) + || getCurrentTreePanel().getPhylogeny().isEmpty() ) { + return; } - final int result = _msa_filechooser.showOpenDialog( _contentpane ); - // All done: get the msa - final File file = _msa_filechooser.getSelectedFile(); - setCurrentDir( _msa_filechooser.getCurrentDirectory() ); - if ( ( file != null ) && !file.isDirectory() && ( result == JFileChooser.APPROVE_OPTION ) ) { - setMsaFile( null ); - setMsa( null ); - Msa msa = null; - try { - final InputStream is = new FileInputStream( file ); - if ( FastaParser.isLikelyFasta( file ) ) { - msa = FastaParser.parseMsa( is ); - } - else { - msa = GeneralMsaParser.parse( is ); - } - } - catch ( final MsaFormatException e ) { - try { - _mainpanel.getCurrentTreePanel().setArrowCursor(); - } - catch ( final Exception ex ) { - // Do nothing. - } - JOptionPane.showMessageDialog( this, - e.getLocalizedMessage(), - "Multiple sequence alignment format error", - JOptionPane.ERROR_MESSAGE ); - return; - } - catch ( final IOException e ) { - try { - _mainpanel.getCurrentTreePanel().setArrowCursor(); - } - catch ( final Exception ex ) { - // Do nothing. - } - JOptionPane.showMessageDialog( this, - e.getLocalizedMessage(), - "Failed to read multiple sequence alignment", - JOptionPane.ERROR_MESSAGE ); - return; - } - catch ( final IllegalArgumentException e ) { - try { - _mainpanel.getCurrentTreePanel().setArrowCursor(); - } - catch ( final Exception ex ) { - // Do nothing. - } - JOptionPane.showMessageDialog( this, - e.getLocalizedMessage(), - "Unexpected error during reading of multiple sequence alignment", - JOptionPane.ERROR_MESSAGE ); - return; + if ( !getOptions().isPrintUsingActualSize() ) { + getCurrentTreePanel().setParametersForPainting( getOptions().getPrintSizeX() - 80, + getOptions().getPrintSizeY() - 140, + true ); + getCurrentTreePanel().resetPreferredSize(); + getCurrentTreePanel().repaint(); + } + final String job_name = Constants.PRG_NAME; + boolean error = false; + String printer_name = null; + try { + printer_name = Printer.print( getCurrentTreePanel(), job_name ); + } + catch ( final Exception e ) { + error = true; + JOptionPane.showMessageDialog( this, e.getMessage(), "Printing Error", JOptionPane.ERROR_MESSAGE ); + } + if ( !error && ( printer_name != null ) ) { + String msg = "Printing data sent to printer"; + if ( printer_name.length() > 1 ) { + msg += " [" + printer_name + "]"; } - catch ( final Exception e ) { - try { - _mainpanel.getCurrentTreePanel().setArrowCursor(); - } - catch ( final Exception ex ) { - // Do nothing. - } - e.printStackTrace(); - JOptionPane.showMessageDialog( this, - e.getLocalizedMessage(), - "Unexpected error during reading of multiple sequence alignment", - JOptionPane.ERROR_MESSAGE ); - return; + JOptionPane.showMessageDialog( this, msg, "Printing...", JOptionPane.INFORMATION_MESSAGE ); + } + if ( !getOptions().isPrintUsingActualSize() ) { + getControlPanel().showWhole(); + } + } + + private void printPhylogenyToPdf( final String file_name ) { + if ( !getOptions().isPrintUsingActualSize() ) { + getCurrentTreePanel().setParametersForPainting( getOptions().getPrintSizeX(), + getOptions().getPrintSizeY(), + true ); + getCurrentTreePanel().resetPreferredSize(); + getCurrentTreePanel().repaint(); + } + String pdf_written_to = ""; + boolean error = false; + try { + if ( getOptions().isPrintUsingActualSize() ) { + pdf_written_to = PdfExporter.writePhylogenyToPdf( file_name, + getCurrentTreePanel(), + getCurrentTreePanel().getWidth(), + getCurrentTreePanel().getHeight() ); } - if ( ( msa == null ) || ( msa.getNumberOfSequences() < 1 ) ) { - JOptionPane.showMessageDialog( this, - "Multiple sequence alignment is empty", - "Illegal Multiple Sequence Alignment", - JOptionPane.ERROR_MESSAGE ); - return; + else { + pdf_written_to = PdfExporter.writePhylogenyToPdf( file_name, getCurrentTreePanel(), getOptions() + .getPrintSizeX(), getOptions().getPrintSizeY() ); } - if ( msa.getNumberOfSequences() < 4 ) { + } + catch ( final IOException e ) { + error = true; + JOptionPane.showMessageDialog( this, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE ); + } + if ( !error ) { + if ( !ForesterUtil.isEmpty( pdf_written_to ) ) { JOptionPane.showMessageDialog( this, - "Multiple sequence alignment needs to contain at least 3 sequences", - "Illegal multiple sequence alignment", - JOptionPane.ERROR_MESSAGE ); - return; + "Wrote PDF to: " + pdf_written_to, + "Information", + JOptionPane.INFORMATION_MESSAGE ); } - if ( msa.getLength() < 2 ) { + else { JOptionPane.showMessageDialog( this, - "Multiple sequence alignment needs to contain at least 2 residues", - "Illegal multiple sequence alignment", + "There was an unknown problem when attempting to write to PDF file: \"" + + file_name + "\"", + "Error", JOptionPane.ERROR_MESSAGE ); - return; } - System.gc(); - setMsaFile( _msa_filechooser.getSelectedFile() ); - setMsa( msa ); + } + if ( !getOptions().isPrintUsingActualSize() ) { + getControlPanel().showWhole(); } } - @Override - void readPhylogeniesFromURL() { - URL url = null; + private void readPhylogeniesFromFile() { + boolean exception = false; Phylogeny[] phys = null; - final String message = "Please enter a complete URL, for example \"http://www.phyloxml.org/examples/apaf.xml\""; - final String url_string = JOptionPane.showInputDialog( this, - message, - "Use URL/webservice to obtain a phylogeny", - JOptionPane.QUESTION_MESSAGE ); + // Set an initial directory if none set yet + final File my_dir = getCurrentDir(); + _open_filechooser.setMultiSelectionEnabled( true ); + // Open file-open dialog and set current directory + if ( my_dir != null ) { + _open_filechooser.setCurrentDirectory( my_dir ); + } + final int result = _open_filechooser.showOpenDialog( _contentpane ); + // All done: get the file + final File[] files = _open_filechooser.getSelectedFiles(); + setCurrentDir( _open_filechooser.getCurrentDirectory() ); boolean nhx_or_nexus = false; - if ( ( url_string != null ) && ( url_string.length() > 0 ) ) { - try { - url = new URL( url_string ); - PhylogenyParser parser = null; - if ( url.getHost().toLowerCase().indexOf( "tolweb" ) >= 0 ) { - parser = new TolParser(); - } - else { - parser = ParserUtils.createParserDependingOnUrlContents( url, getConfiguration() - .isValidatePhyloXmlAgainstSchema() ); - } - if ( parser instanceof NexusPhylogeniesParser ) { - nhx_or_nexus = true; - } - else if ( parser instanceof NHXParser ) { - nhx_or_nexus = true; - } - if ( _mainpanel.getCurrentTreePanel() != null ) { - _mainpanel.getCurrentTreePanel().setWaitCursor(); - } - else { - _mainpanel.setWaitCursor(); - } - final PhylogenyFactory factory = ParserBasedPhylogenyFactory.getInstance(); - phys = factory.create( url.openStream(), parser ); - } - catch ( final MalformedURLException e ) { - JOptionPane.showMessageDialog( this, - "Malformed URL: " + url + "\n" + e.getLocalizedMessage(), - "Malformed URL", - JOptionPane.ERROR_MESSAGE ); - } - catch ( final IOException e ) { - JOptionPane.showMessageDialog( this, - "Could not read from " + url + "\n" - + ForesterUtil.wordWrap( e.getLocalizedMessage(), 80 ), - "Failed to read URL", - JOptionPane.ERROR_MESSAGE ); - } - catch ( final Exception e ) { - JOptionPane.showMessageDialog( this, - ForesterUtil.wordWrap( e.getLocalizedMessage(), 80 ), - "Unexpected Exception", - JOptionPane.ERROR_MESSAGE ); - } - finally { - if ( _mainpanel.getCurrentTreePanel() != null ) { - _mainpanel.getCurrentTreePanel().setArrowCursor(); - } - else { - _mainpanel.setArrowCursor(); - } - } - if ( ( phys != null ) && ( phys.length > 0 ) ) { - if ( nhx_or_nexus && getOptions().isInternalNumberAreConfidenceForNhParsing() ) { - for( final Phylogeny phy : phys ) { - PhylogenyMethods.transferInternalNodeNamesToConfidence( phy ); + if ( ( files != null ) && ( files.length > 0 ) && ( result == JFileChooser.APPROVE_OPTION ) ) { + for( final File file : files ) { + if ( ( file != null ) && !file.isDirectory() ) { + if ( _mainpanel.getCurrentTreePanel() != null ) { + _mainpanel.getCurrentTreePanel().setWaitCursor(); + } + else { + _mainpanel.setWaitCursor(); + } + if ( ( _open_filechooser.getFileFilter() == MainFrameApplication.nhfilter ) + || ( _open_filechooser.getFileFilter() == MainFrameApplication.nhxfilter ) ) { + try { + final NHXParser nhx = new NHXParser(); + setSpecialOptionsForNhxParser( nhx ); + phys = PhylogenyMethods.readPhylogenies( nhx, file ); + nhx_or_nexus = true; + } + catch ( final Exception e ) { + exception = true; + exceptionOccuredDuringOpenFile( e ); + } + } + else if ( _open_filechooser.getFileFilter() == MainFrameApplication.xmlfilter ) { + warnIfNotPhyloXmlValidation( getConfiguration() ); + try { + final PhyloXmlParser xml_parser = createPhyloXmlParser(); + phys = PhylogenyMethods.readPhylogenies( xml_parser, file ); + } + catch ( final Exception e ) { + exception = true; + exceptionOccuredDuringOpenFile( e ); + } + } + else if ( _open_filechooser.getFileFilter() == MainFrameApplication.tolfilter ) { + try { + phys = PhylogenyMethods.readPhylogenies( new TolParser(), file ); + } + catch ( final Exception e ) { + exception = true; + exceptionOccuredDuringOpenFile( e ); + } + } + else if ( _open_filechooser.getFileFilter() == MainFrameApplication.nexusfilter ) { + try { + final NexusPhylogeniesParser nex = new NexusPhylogeniesParser(); + setSpecialOptionsForNexParser( nex ); + phys = PhylogenyMethods.readPhylogenies( nex, file ); + nhx_or_nexus = true; + } + catch ( final Exception e ) { + exception = true; + exceptionOccuredDuringOpenFile( e ); + } + } + // "*.*": + else { + try { + final PhylogenyParser parser = ParserUtils + .createParserDependingOnFileType( file, getConfiguration() + .isValidatePhyloXmlAgainstSchema() ); + if ( parser instanceof NexusPhylogeniesParser ) { + final NexusPhylogeniesParser nex = ( NexusPhylogeniesParser ) parser; + setSpecialOptionsForNexParser( nex ); + nhx_or_nexus = true; + } + else if ( parser instanceof NHXParser ) { + final NHXParser nhx = ( NHXParser ) parser; + setSpecialOptionsForNhxParser( nhx ); + nhx_or_nexus = true; + } + else if ( parser instanceof PhyloXmlParser ) { + warnIfNotPhyloXmlValidation( getConfiguration() ); + } + phys = PhylogenyMethods.readPhylogenies( parser, file ); + } + catch ( final Exception e ) { + exception = true; + exceptionOccuredDuringOpenFile( e ); + } + } + if ( _mainpanel.getCurrentTreePanel() != null ) { + _mainpanel.getCurrentTreePanel().setArrowCursor(); + } + else { + _mainpanel.setArrowCursor(); + } + if ( !exception && ( phys != null ) && ( phys.length > 0 ) ) { + boolean one_desc = false; + if ( nhx_or_nexus ) { + for( final Phylogeny phy : phys ) { + if ( getOptions().isInternalNumberAreConfidenceForNhParsing() ) { + PhylogenyMethods.transferInternalNodeNamesToConfidence( phy ); + } + if ( PhylogenyMethods.getMinimumDescendentsPerInternalNodes( phy ) == 1 ) { + one_desc = true; + break; + } + } + } + AptxUtil.addPhylogeniesToTabs( phys, + file.getName(), + file.getAbsolutePath(), + getConfiguration(), + getMainPanel() ); + _mainpanel.getControlPanel().showWhole(); + if ( nhx_or_nexus && one_desc ) { + JOptionPane + .showMessageDialog( this, + "One or more trees contain (a) node(s) with one descendant, " + + ForesterUtil.LINE_SEPARATOR + + "possibly indicating illegal parentheses within node names.", + "Warning: Possible Error in New Hampshire Formatted Data", + JOptionPane.WARNING_MESSAGE ); + } } } - AptxUtil.addPhylogeniesToTabs( phys, - new File( url.getFile() ).getName(), - new File( url.getFile() ).toString(), - getConfiguration(), - getMainPanel() ); - _mainpanel.getControlPanel().showWhole(); } } activateSaveAllIfNeeded(); @@ -2334,6 +2344,10 @@ public final class MainFrameApplication extends MainFrame { _min_not_collapse = min_not_collapse; } + private void setPhylogeneticInferenceOptions( final PhylogeneticInferenceOptions phylogenetic_inference_options ) { + _phylogenetic_inference_options = phylogenetic_inference_options; + } + private void setSpecialOptionsForNexParser( final NexusPhylogeniesParser nex ) { nex.setReplaceUnderscores( getOptions().isReplaceUnderscoresInNhParsing() ); } @@ -2444,43 +2458,6 @@ public final class MainFrameApplication extends MainFrame { return exception; } - void writePhylogenyToGraphicsFile( final String file_name, final GraphicsExportType type ) { - _mainpanel.getCurrentTreePanel().setParametersForPainting( _mainpanel.getCurrentTreePanel().getWidth(), - _mainpanel.getCurrentTreePanel().getHeight(), - true ); - String file_written_to = ""; - boolean error = false; - try { - file_written_to = AptxUtil.writePhylogenyToGraphicsFile( file_name, - _mainpanel.getCurrentTreePanel().getWidth(), - _mainpanel.getCurrentTreePanel().getHeight(), - _mainpanel.getCurrentTreePanel(), - _mainpanel.getControlPanel(), - type, - getOptions() ); - } - catch ( final IOException e ) { - error = true; - JOptionPane.showMessageDialog( this, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE ); - } - if ( !error ) { - if ( ( file_written_to != null ) && ( file_written_to.length() > 0 ) ) { - JOptionPane.showMessageDialog( this, - "Wrote image to: " + file_written_to, - "Graphics Export", - JOptionPane.INFORMATION_MESSAGE ); - } - else { - JOptionPane.showMessageDialog( this, - "There was an unknown problem when attempting to write to an image file: \"" - + file_name + "\"", - "Error", - JOptionPane.ERROR_MESSAGE ); - } - } - _contentpane.repaint(); - } - private void writeToFile( final Phylogeny t ) { if ( t == null ) { return; @@ -2665,18 +2642,10 @@ public final class MainFrameApplication extends MainFrame { } } - static MainFrame createInstance( final Phylogeny[] phys, final Configuration config, final String title ) { - return new MainFrameApplication( phys, config, title ); - } - public static MainFrameApplication createInstance( final Phylogeny[] phys, final Configuration config ) { return new MainFrameApplication( phys, config ); } - static MainFrame createInstance( final Phylogeny[] phys, final String config_file_name, final String title ) { - return new MainFrameApplication( phys, config_file_name, title ); - } - public static MainFrame createInstance( final Phylogeny[] phys, final Configuration config, final String title, @@ -2684,6 +2653,14 @@ public final class MainFrameApplication extends MainFrame { return new MainFrameApplication( phys, config, title, current_dir ); } + static MainFrame createInstance( final Phylogeny[] phys, final Configuration config, final String title ) { + return new MainFrameApplication( phys, config, title ); + } + + static MainFrame createInstance( final Phylogeny[] phys, final String config_file_name, final String title ) { + return new MainFrameApplication( phys, config_file_name, title ); + } + static void setTextForGraphicsSizeChooserMenuItem( final JMenuItem mi, final Options o ) { mi.setText( "Enter Default Size for Graphics Export... (current: " + o.getPrintSizeX() + ", " + o.getPrintSizeY() + ")" ); @@ -2704,50 +2681,58 @@ public final class MainFrameApplication extends MainFrame { JOptionPane.WARNING_MESSAGE ); } } +} // MainFrameApplication. - private void setPhylogeneticInferenceOptions( final PhylogeneticInferenceOptions phylogenetic_inference_options ) { - _phylogenetic_inference_options = phylogenetic_inference_options; - } - - private PhylogeneticInferenceOptions getPhylogeneticInferenceOptions() { - if ( _phylogenetic_inference_options == null ) { - _phylogenetic_inference_options = new PhylogeneticInferenceOptions(); - } - return _phylogenetic_inference_options; - } +class DefaultFilter extends FileFilter { - public Msa getMsa() { - return _msa; + @Override + public boolean accept( final File f ) { + final String file_name = f.getName().trim().toLowerCase(); + return file_name.endsWith( ".nh" ) || file_name.endsWith( ".newick" ) || file_name.endsWith( ".phy" ) + || file_name.endsWith( ".nwk" ) || file_name.endsWith( ".phb" ) || file_name.endsWith( ".ph" ) + || file_name.endsWith( ".tr" ) || file_name.endsWith( ".dnd" ) || file_name.endsWith( ".tree" ) + || file_name.endsWith( ".nhx" ) || file_name.endsWith( ".xml" ) || file_name.endsWith( ".phyloxml" ) + || file_name.endsWith( "phylo.xml" ) || file_name.endsWith( ".pxml" ) || file_name.endsWith( ".nexus" ) + || file_name.endsWith( ".nx" ) || file_name.endsWith( ".nex" ) || file_name.endsWith( ".tre" ) + || file_name.endsWith( ".zip" ) || file_name.endsWith( ".tol" ) || file_name.endsWith( ".tolxml" ) + || file_name.endsWith( ".con" ) || f.isDirectory(); } - void setMsa( final Msa msa ) { - _msa = msa; + @Override + public String getDescription() { + return "All supported files (*.xml, *.phyloxml, *phylo.xml, *.nhx, *.nh, *.newick, *.nex, *.nexus, *.phy, *.tre, *.tree, *.tol, ...)"; } +} - void setMsaFile( final File msa_file ) { - _msa_file = msa_file; - } +class GraphicsFileFilter extends FileFilter { - public File getMsaFile() { - return _msa_file; + @Override + public boolean accept( final File f ) { + final String file_name = f.getName().trim().toLowerCase(); + return file_name.endsWith( ".jpg" ) || file_name.endsWith( ".jpeg" ) || file_name.endsWith( ".png" ) + || file_name.endsWith( ".gif" ) || file_name.endsWith( ".bmp" ) || f.isDirectory(); } - public List getSeqs() { - return _seqs; + @Override + public String getDescription() { + return "Image files (*.jpg, *.jpeg, *.png, *.gif, *.bmp)"; } +} - void setSeqs( final List seqs ) { - _seqs = seqs; - } +class MsaFileFilter extends FileFilter { - void setSeqsFile( final File seqs_file ) { - _seqs_file = seqs_file; + @Override + public boolean accept( final File f ) { + final String file_name = f.getName().trim().toLowerCase(); + return file_name.endsWith( ".msa" ) || file_name.endsWith( ".aln" ) || file_name.endsWith( ".fasta" ) + || file_name.endsWith( ".fas" ) || file_name.endsWith( ".fa" ) || f.isDirectory(); } - public File getSeqsFile() { - return _seqs_file; + @Override + public String getDescription() { + return "Multiple sequence alignment files (*.msa, *.aln, *.fasta, *.fa, *.fas)"; } -} // MainFrameApplication. +} class NexusFilter extends FileFilter { @@ -2808,6 +2793,21 @@ class PdfFilter extends FileFilter { } } // PdfFilter +class SequencesFileFilter extends FileFilter { + + @Override + public boolean accept( final File f ) { + final String file_name = f.getName().trim().toLowerCase(); + return file_name.endsWith( ".fasta" ) || file_name.endsWith( ".fa" ) || file_name.endsWith( ".fas" ) + || file_name.endsWith( ".seqs" ) || f.isDirectory(); + } + + @Override + public String getDescription() { + return "Sequences files (*.fasta, *.fa, *.fas, *.seqs )"; + } +} + class TolFilter extends FileFilter { @Override diff --git a/forester/java/src/org/forester/phylogeny/Phylogeny.java b/forester/java/src/org/forester/phylogeny/Phylogeny.java index d3095aa..5649a5b 100644 --- a/forester/java/src/org/forester/phylogeny/Phylogeny.java +++ b/forester/java/src/org/forester/phylogeny/Phylogeny.java @@ -144,6 +144,10 @@ public class Phylogeny { } } + public void clearHashIdToNodeMap() { + setIdToNodeMap( null ); + } + /** * Returns a deep copy of this Phylogeny. *

@@ -155,60 +159,60 @@ public class Phylogeny { } /** - * Returns a shallow copy of this Phylogeny. + * Returns a deep copy of this Phylogeny. *

* (The resulting Phylogeny has its references in the external nodes * corrected, if they are lacking/obsolete in this.) */ - public Phylogeny copyShallow() { - return copyShallow( _root ); - } - - public Phylogeny copyShallow( final PhylogenyNode source ) { + public Phylogeny copy( final PhylogenyNode source ) { final Phylogeny tree = new Phylogeny(); if ( isEmpty() ) { tree.init(); return tree; } tree._rooted = _rooted; - tree._name = _name; - tree._description = _description; - tree._type = _type; + tree._name = new String( _name ); + tree._description = new String( _description ); + tree._type = new String( _type ); tree._rerootable = _rerootable; - tree._distance_unit = _distance_unit; - tree._confidence = _confidence; - tree._identifier = _identifier; + tree._distance_unit = new String( _distance_unit ); + if ( _confidence != null ) { + tree._confidence = ( Confidence ) _confidence.copy(); + } + if ( _identifier != null ) { + tree._identifier = ( Identifier ) _identifier.copy(); + } tree.setAllowMultipleParents( isAllowMultipleParents() ); - tree._root = PhylogenyMethods.copySubTreeShallow( source ); + tree._root = PhylogenyMethods.copySubTree( source ); return tree; } /** - * Returns a deep copy of this Phylogeny. + * Returns a shallow copy of this Phylogeny. *

* (The resulting Phylogeny has its references in the external nodes * corrected, if they are lacking/obsolete in this.) */ - public Phylogeny copy( final PhylogenyNode source ) { + public Phylogeny copyShallow() { + return copyShallow( _root ); + } + + public Phylogeny copyShallow( final PhylogenyNode source ) { final Phylogeny tree = new Phylogeny(); if ( isEmpty() ) { tree.init(); return tree; } tree._rooted = _rooted; - tree._name = new String( _name ); - tree._description = new String( _description ); - tree._type = new String( _type ); + tree._name = _name; + tree._description = _description; + tree._type = _type; tree._rerootable = _rerootable; - tree._distance_unit = new String( _distance_unit ); - if ( _confidence != null ) { - tree._confidence = ( Confidence ) _confidence.copy(); - } - if ( _identifier != null ) { - tree._identifier = ( Identifier ) _identifier.copy(); - } + tree._distance_unit = _distance_unit; + tree._confidence = _confidence; + tree._identifier = _identifier; tree.setAllowMultipleParents( isAllowMultipleParents() ); - tree._root = PhylogenyMethods.copySubTree( source ); + tree._root = PhylogenyMethods.copySubTreeShallow( source ); return tree; } @@ -375,10 +379,6 @@ public class Phylogeny { return _identifier; } - private HashMap getIdToNodeMap() { - return _id_to_node_map; - } - /** * Returns the name of this Phylogeny. */ @@ -423,23 +423,18 @@ public class Phylogeny { } /** - * Return Node by TaxonomyId Olivier CHABROL : - * olivier.chabrol@univ-provence.fr + * This is time-inefficient since it runs a iterator each time it is called. * - * @param taxonomyID - * search taxonomy identifier - * @param nodes - * sublist node to search - * @return List node with the same taxonomy identifier */ - private List getNodeByTaxonomyID( final String taxonomyID, final List nodes ) { - final List retour = new ArrayList(); - for( final PhylogenyNode node : nodes ) { - if ( taxonomyID.equals( PhylogenyMethods.getTaxonomyIdentifier( node ) ) ) { - retour.add( node ); - } + public int getNodeCount() { + if ( isEmpty() ) { + return 0; } - return retour; + int c = 0; + for( final PhylogenyNodeIterator it = iteratorPreorder(); it.hasNext(); it.next() ) { + ++c; + } + return c; } /** @@ -547,21 +542,6 @@ public class Phylogeny { return nodes.get( 0 ); } - /** - * This is time-inefficient since it runs a iterator each time it is called. - * - */ - public int getNodeCount() { - if ( isEmpty() ) { - return 0; - } - int c = 0; - for( final PhylogenyNodeIterator it = iteratorPreorder(); it.hasNext(); it.next() ) { - ++c; - } - return c; - } - public int getNumberOfBranches() { if ( isEmpty() ) { return 0; @@ -655,74 +635,11 @@ public class Phylogeny { return _sequenceRelationQueries; } - /** - * List all species contains in all leaf under a node Olivier CHABROL : - * olivier.chabrol@univ-provence.fr - * - * @param node - * PhylogenyNode whose sub node species are returned - * @return species contains in all leaf under the param node - */ - private List getSubNodeTaxonomy( final PhylogenyNode node ) { - final List taxonomyList = new ArrayList(); - final List childs = node.getAllExternalDescendants(); - String speciesId = null; - for( final PhylogenyNode phylogenyNode : childs ) { - // taxId = new Long(phylogenyNode.getTaxonomyID()); - speciesId = PhylogenyMethods.getTaxonomyIdentifier( phylogenyNode ); - if ( !taxonomyList.contains( speciesId ) ) { - taxonomyList.add( speciesId ); - } - } - return taxonomyList; - } - - /** - * Create a map [], the list contains the - * species contains in all leaf under phylogeny node Olivier CHABROL : - * olivier.chabrol@univ-provence.fr - * - * @param node - * the tree root node - * @param map - * map to fill - */ - private void getTaxonomyMap( final PhylogenyNode node, final Map> map ) { - // node is leaf - if ( node.isExternal() ) { - return; - } - map.put( node, getSubNodeTaxonomy( node ) ); - getTaxonomyMap( node.getChildNode1(), map ); - getTaxonomyMap( node.getChildNode2(), map ); - } - public String getType() { return _type; } /** - * Hashes the ID number of each PhylogenyNode of this Phylogeny to its - * corresponding PhylogenyNode, in order to make method getNode( id ) run in - * constant time. Important: The user is responsible for calling this method - * (again) after this Phylogeny has been changed/created/renumbered. - */ - private void reHashIdToNodeMap() { - if ( isEmpty() ) { - return; - } - setIdToNodeMap( new HashMap() ); - for( final PhylogenyNodeIterator iter = iteratorPreorder(); iter.hasNext(); ) { - final PhylogenyNode node = iter.next(); - getIdToNodeMap().put( node.getId(), node ); - } - } - - public void clearHashIdToNodeMap() { - setIdToNodeMap( null ); - } - - /** * Deletes this Phylogeny. */ public void init() { @@ -739,10 +656,6 @@ public class Phylogeny { setAllowMultipleParents( Phylogeny.ALLOW_MULTIPLE_PARENTS_DEFAULT ); } - private boolean isAllowMultipleParents() { - return _allow_multiple_parents; - } - /** * Returns whether this is a completely binary tree (i.e. all internal nodes * are bifurcations). @@ -762,31 +675,6 @@ public class Phylogeny { } /** - * Util method to check if all element of a list is contains in the - * rangeList. Olivier CHABROL : olivier.chabrol@univ-provence.fr - * - * @param list - * list to be check - * @param rangeList - * the range list to compare - * @return true if all param list element are contains in param - * rangeList, false otherwise. - */ - private boolean isContains( final List list, final List rangeList ) { - if ( list.size() > rangeList.size() ) { - return false; - } - String l = null; - for( final Iterator iterator = list.iterator(); iterator.hasNext(); ) { - l = iterator.next(); - if ( !rangeList.contains( l ) ) { - return false; - } - } - return true; - } - - /** * Checks whether a Phylogeny object is deleted (or empty). * * @return true if the tree is deleted (or empty), false otherwise @@ -1120,10 +1008,6 @@ public class Phylogeny { } } - private void setAllowMultipleParents( final boolean allow_multiple_parents ) { - _allow_multiple_parents = allow_multiple_parents; - } - public void setConfidence( final Confidence confidence ) { _confidence = confidence; } @@ -1214,6 +1098,10 @@ public class Phylogeny { } } + public String toNexus() { + return toNexus( NH_CONVERSION_SUPPORT_VALUE_STYLE.NONE ); + } + public String toNexus( final NH_CONVERSION_SUPPORT_VALUE_STYLE svs ) { try { return new PhylogenyWriter().toNexus( this, svs ).toString(); @@ -1223,10 +1111,6 @@ public class Phylogeny { } } - public String toNexus() { - return toNexus( NH_CONVERSION_SUPPORT_VALUE_STYLE.NONE ); - } - public String toPhyloXML( final int phyloxml_level ) { try { return new PhylogenyWriter().toPhyloXML( this, phyloxml_level ).toString(); @@ -1267,4 +1151,120 @@ public class Phylogeny { setRooted( false ); return; } // unRoot() + + private HashMap getIdToNodeMap() { + return _id_to_node_map; + } + + /** + * Return Node by TaxonomyId Olivier CHABROL : + * olivier.chabrol@univ-provence.fr + * + * @param taxonomyID + * search taxonomy identifier + * @param nodes + * sublist node to search + * @return List node with the same taxonomy identifier + */ + private List getNodeByTaxonomyID( final String taxonomyID, final List nodes ) { + final List retour = new ArrayList(); + for( final PhylogenyNode node : nodes ) { + if ( taxonomyID.equals( PhylogenyMethods.getTaxonomyIdentifier( node ) ) ) { + retour.add( node ); + } + } + return retour; + } + + /** + * List all species contains in all leaf under a node Olivier CHABROL : + * olivier.chabrol@univ-provence.fr + * + * @param node + * PhylogenyNode whose sub node species are returned + * @return species contains in all leaf under the param node + */ + private List getSubNodeTaxonomy( final PhylogenyNode node ) { + final List taxonomyList = new ArrayList(); + final List childs = node.getAllExternalDescendants(); + String speciesId = null; + for( final PhylogenyNode phylogenyNode : childs ) { + // taxId = new Long(phylogenyNode.getTaxonomyID()); + speciesId = PhylogenyMethods.getTaxonomyIdentifier( phylogenyNode ); + if ( !taxonomyList.contains( speciesId ) ) { + taxonomyList.add( speciesId ); + } + } + return taxonomyList; + } + + /** + * Create a map [], the list contains the + * species contains in all leaf under phylogeny node Olivier CHABROL : + * olivier.chabrol@univ-provence.fr + * + * @param node + * the tree root node + * @param map + * map to fill + */ + private void getTaxonomyMap( final PhylogenyNode node, final Map> map ) { + // node is leaf + if ( node.isExternal() ) { + return; + } + map.put( node, getSubNodeTaxonomy( node ) ); + getTaxonomyMap( node.getChildNode1(), map ); + getTaxonomyMap( node.getChildNode2(), map ); + } + + private boolean isAllowMultipleParents() { + return _allow_multiple_parents; + } + + /** + * Util method to check if all element of a list is contains in the + * rangeList. Olivier CHABROL : olivier.chabrol@univ-provence.fr + * + * @param list + * list to be check + * @param rangeList + * the range list to compare + * @return true if all param list element are contains in param + * rangeList, false otherwise. + */ + private boolean isContains( final List list, final List rangeList ) { + if ( list.size() > rangeList.size() ) { + return false; + } + String l = null; + for( final Iterator iterator = list.iterator(); iterator.hasNext(); ) { + l = iterator.next(); + if ( !rangeList.contains( l ) ) { + return false; + } + } + return true; + } + + /** + * Hashes the ID number of each PhylogenyNode of this Phylogeny to its + * corresponding PhylogenyNode, in order to make method getNode( id ) run in + * constant time. Important: The user is responsible for calling this method + * (again) after this Phylogeny has been changed/created/renumbered. + */ + private void reHashIdToNodeMap() { + if ( isEmpty() ) { + return; + } + setIdToNodeMap( new HashMap() ); + for( final PhylogenyNodeIterator iter = iteratorPreorder(); iter.hasNext(); ) { + final PhylogenyNode node = iter.next(); + getIdToNodeMap().put( node.getId(), node ); + } + } + + private void setAllowMultipleParents( final boolean allow_multiple_parents ) { + _allow_multiple_parents = allow_multiple_parents; + } } diff --git a/forester/java/src/org/forester/phylogeny/PhylogenyMethods.java b/forester/java/src/org/forester/phylogeny/PhylogenyMethods.java index 09db386..1dbcfa3 100644 --- a/forester/java/src/org/forester/phylogeny/PhylogenyMethods.java +++ b/forester/java/src/org/forester/phylogeny/PhylogenyMethods.java @@ -308,6 +308,17 @@ public class PhylogenyMethods { return stats; } + public static int countNumberOfOneDescendantNodes( final Phylogeny phy ) { + int count = 0; + for( final PhylogenyNodeIterator iter = phy.iteratorPreorder(); iter.hasNext(); ) { + final PhylogenyNode n = iter.next(); + if ( !n.isExternal() && ( n.getNumberOfDescendants() == 1 ) ) { + count++; + } + } + return count; + } + public static int countNumberOfPolytomies( final Phylogeny phy ) { int count = 0; for( final PhylogenyNodeIterator iter = phy.iteratorPreorder(); iter.hasNext(); ) { @@ -398,6 +409,21 @@ public class PhylogenyMethods { return deleted; } + final public static void deleteInternalNodesWithOnlyOneDescendent( final Phylogeny phy ) { + final ArrayList to_delete = new ArrayList(); + for( final PhylogenyNodeIterator iter = phy.iteratorPostorder(); iter.hasNext(); ) { + final PhylogenyNode n = iter.next(); + if ( !n.isExternal() && ( n.getNumberOfDescendants() == 1 ) ) { + to_delete.add( n ); + } + } + for( final PhylogenyNode d : to_delete ) { + PhylogenyMethods.removeNode( d, phy ); + } + phy.clearHashIdToNodeMap(); + phy.externalNodesHaveChanged(); + } + final public static void deleteNonOrthologousExternalNodes( final Phylogeny phy, final PhylogenyNode n ) { if ( n.isInternal() ) { throw new IllegalArgumentException( "node is not external" ); diff --git a/forester/java/src/org/forester/rio/RIO.java b/forester/java/src/org/forester/rio/RIO.java index 8e1e5bb..30f2fff 100644 --- a/forester/java/src/org/forester/rio/RIO.java +++ b/forester/java/src/org/forester/rio/RIO.java @@ -36,6 +36,8 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import org.forester.datastructures.IntMatrix; import org.forester.io.parsers.PhylogenyParser; @@ -44,6 +46,7 @@ import org.forester.io.parsers.util.ParserUtils; import org.forester.phylogeny.Phylogeny; import org.forester.phylogeny.PhylogenyMethods; import org.forester.phylogeny.PhylogenyNode; +import org.forester.phylogeny.data.Taxonomy; import org.forester.phylogeny.factories.ParserBasedPhylogenyFactory; import org.forester.phylogeny.factories.PhylogenyFactory; import org.forester.sdi.GSDI; @@ -57,47 +60,52 @@ import org.forester.util.ForesterUtil; public final class RIO { - public enum REROOTING { - NONE, BY_ALGORITHM, MIDPOINT, OUTGROUP; - } - private Phylogeny[] _analyzed_gene_trees; - private List _removed_gene_tree_nodes; - private int _ext_nodes; - private TaxonomyComparisonBase _gsdir_tax_comp_base; - private StringBuilder _log; - private BasicDescriptiveStatistics _duplications_stats; - private boolean _produce_log; - private boolean _verbose; - private REROOTING _rerooting; + private Phylogeny[] _analyzed_gene_trees; + private List _removed_gene_tree_nodes; + private int _ext_nodes; + private TaxonomyComparisonBase _gsdir_tax_comp_base; + private final StringBuilder _log; + private final BasicDescriptiveStatistics _duplications_stats; + private final boolean _produce_log; + private final boolean _verbose; + private final REROOTING _rerooting; - public RIO( final File gene_trees_file, - final Phylogeny species_tree, - final ALGORITHM algorithm, - final REROOTING rerooting, - final String outgroup, - final boolean produce_log, - final boolean verbose ) throws IOException, SDIException, RIOException { - checkReRooting( rerooting, outgroup ); - init( produce_log, verbose, rerooting ); - inferOrthologs( gene_trees_file, species_tree, algorithm, outgroup ); - } - - public RIO( final Phylogeny[] gene_trees, - final Phylogeny species_tree, - final ALGORITHM algorithm, - final REROOTING rerooting, - final String outgroup, - final boolean produce_log, - final boolean verbose ) throws IOException, SDIException, RIOException { - checkReRooting( rerooting, outgroup ); - init( produce_log, verbose, rerooting ); - inferOrthologs( gene_trees, species_tree, algorithm, outgroup ); + private RIO( final Phylogeny[] gene_trees, + final Phylogeny species_tree, + final ALGORITHM algorithm, + final REROOTING rerooting, + final String outgroup, + final int first, + final int last, + final boolean produce_log, + final boolean verbose ) throws IOException, SDIException, RIOException { + if ( !ForesterUtil.isEmpty( outgroup ) && ( rerooting != REROOTING.OUTGROUP ) ) { + throw new IllegalArgumentException( "can only use outgroup when re-rooting by outgroup" ); + } + if ( !( ( last == -1 ) && ( first == -1 ) ) + && ( ( last < first ) || ( last >= gene_trees.length ) || ( first >= gene_trees.length ) || ( last < 0 ) || ( first < 0 ) ) ) { + throw new IllegalArgumentException( "gene tree range is out of range: " + first + "-" + last ); + } + _produce_log = produce_log; + _verbose = verbose; + _rerooting = rerooting; + _ext_nodes = -1; + _log = new StringBuilder(); + _gsdir_tax_comp_base = null; + _analyzed_gene_trees = null; + _removed_gene_tree_nodes = null; + _duplications_stats = new BasicDescriptiveStatistics(); + inferOrthologs( gene_trees, species_tree, algorithm, outgroup, first, last ); } public final Phylogeny[] getAnalyzedGeneTrees() { return _analyzed_gene_trees; } + public final BasicDescriptiveStatistics getDuplicationsStatistics() { + return _duplications_stats; + } + /** * Returns the numbers of number of ext nodes in gene trees analyzed (after * stripping). @@ -120,28 +128,13 @@ public final class RIO { return _removed_gene_tree_nodes; } - private final void inferOrthologs( final File gene_trees_file, - final Phylogeny species_tree, - final ALGORITHM algorithm, - final String outgroup ) throws SDIException, RIOException, - FileNotFoundException, IOException { - final PhylogenyFactory factory = ParserBasedPhylogenyFactory.getInstance(); - final PhylogenyParser p = ParserUtils.createParserDependingOnFileType( gene_trees_file, true ); - if ( p instanceof NHXParser ) { - final NHXParser nhx = ( NHXParser ) p; - nhx.setReplaceUnderscores( false ); - nhx.setIgnoreQuotes( true ); - nhx.setTaxonomyExtraction( NHXParser.TAXONOMY_EXTRACTION.YES ); - } - final Phylogeny[] gene_trees = factory.create( gene_trees_file, p ); - inferOrthologs( gene_trees, species_tree, algorithm, outgroup ); - } - private final void inferOrthologs( final Phylogeny[] gene_trees, final Phylogeny species_tree, final ALGORITHM algorithm, - final String outgroup ) throws SDIException, RIOException, - FileNotFoundException, IOException { + final String outgroup, + final int first, + final int last ) throws SDIException, RIOException, FileNotFoundException, + IOException { if ( algorithm == ALGORITHM.SDIR ) { // Removes from species_tree all species not found in gene_tree. PhylogenyMethods.taxonomyBasedDeletionOfExternalNodes( gene_trees[ 0 ], species_tree ); @@ -149,21 +142,32 @@ public final class RIO { throw new RIOException( "failed to establish species based mapping between gene and species trees" ); } } - if ( _produce_log ) { - _log = new StringBuilder(); - if ( _rerooting == REROOTING.BY_ALGORITHM ) { - writeLogSubHeader(); + if ( log() ) { + preLog( gene_trees, species_tree, algorithm, outgroup ); + } + final Phylogeny[] my_gene_trees; + if ( ( first >= 0 ) && ( last >= first ) && ( last < gene_trees.length ) ) { + if ( log() ) { + log( "Gene tree range: " + first + "-" + last ); + } + my_gene_trees = new Phylogeny[ 1 + last - first ]; + int c = 0; + for( int i = first; i <= last; ++i ) { + my_gene_trees[ c++ ] = gene_trees[ i ]; } } - _analyzed_gene_trees = new Phylogeny[ gene_trees.length ]; - int gene_tree_ext_nodes = 0; - if ( _verbose ) { + else { + my_gene_trees = gene_trees; + } + if ( _verbose && ( my_gene_trees.length > 10 ) ) { System.out.println(); } - for( int i = 0; i < gene_trees.length; ++i ) { - final Phylogeny gt = gene_trees[ i ]; - if ( _verbose ) { - ForesterUtil.updateProgress( ( double ) i / gene_trees.length ); + _analyzed_gene_trees = new Phylogeny[ my_gene_trees.length ]; + int gene_tree_ext_nodes = 0; + for( int i = 0; i < my_gene_trees.length; ++i ) { + final Phylogeny gt = my_gene_trees[ i ]; + if ( _verbose && ( my_gene_trees.length > 10 ) ) { + ForesterUtil.updateProgress( ( ( double ) i ) / my_gene_trees.length ); } if ( i == 0 ) { gene_tree_ext_nodes = gt.getNumberOfExternalNodes(); @@ -182,22 +186,48 @@ public final class RIO { } _analyzed_gene_trees[ i ] = performOrthologInference( gt, species_tree, algorithm, outgroup, i ); } - if ( _verbose ) { + if ( log() ) { + postLog( species_tree ); + } + if ( _verbose && ( my_gene_trees.length > 10 ) ) { System.out.println(); System.out.println(); } } - private final void init( final boolean produce_log, final boolean verbose, final REROOTING rerooting ) { - _produce_log = produce_log; - _verbose = verbose; - _rerooting = rerooting; - _ext_nodes = -1; - _log = null; - _gsdir_tax_comp_base = null; - _analyzed_gene_trees = null; - _removed_gene_tree_nodes = null; - _duplications_stats = new BasicDescriptiveStatistics(); + private final boolean log() { + return _produce_log; + } + + private final void log( final String s ) { + _log.append( s ); + _log.append( ForesterUtil.LINE_SEPARATOR ); + } + + private final void logRemovedGeneTreeNodes() { + log( "Species stripped from gene trees:" ); + final SortedSet rn = new TreeSet(); + for( final PhylogenyNode n : getRemovedGeneTreeNodes() ) { + final Taxonomy t = n.getNodeData().getTaxonomy(); + switch ( getGSDIRtaxCompBase() ) { + case CODE: { + rn.add( t.getTaxonomyCode() ); + break; + } + case ID: { + rn.add( t.getIdentifier().toString() ); + break; + } + case SCIENTIFIC_NAME: { + rn.add( t.getScientificName() ); + break; + } + } + } + for( final String s : rn ) { + log( s ); + } + log( "" ); } private final Phylogeny performOrthologInference( final Phylogeny gene_tree, @@ -249,7 +279,7 @@ public final class RIO { } final List shortests = GSDIR.getIndexesOfShortestTree( assigned_trees ); assigned_tree = assigned_trees.get( shortests.get( 0 ) ); - if ( _produce_log ) { + if ( log() ) { writeStatsToLog( i, gsdir, shortests ); } if ( i == 0 ) { @@ -266,7 +296,7 @@ public final class RIO { try { n = gene_tree.getNode( outgroup ); } - catch ( IllegalArgumentException e ) { + catch ( final IllegalArgumentException e ) { throw new RIOException( "failed to perform re-rooting by outgroup: " + e.getLocalizedMessage() ); } gene_tree.reRoot( n ); @@ -294,19 +324,73 @@ public final class RIO { return sdir.infer( gene_tree, species_tree, false, true, true, true, 1 )[ 0 ]; } - private void writeLogSubHeader() { + private final void postLog( final Phylogeny species_tree ) { + log( "" ); + if ( getRemovedGeneTreeNodes().size() > 0 ) { + logRemovedGeneTreeNodes(); + } + log( "Species tree external nodes (after stripping) : " + species_tree.getNumberOfExternalNodes() ); + log( "Species tree polytomies (after stripping) : " + + PhylogenyMethods.countNumberOfPolytomies( species_tree ) ); + log( "Taxonomy linking based on : " + getGSDIRtaxCompBase() ); + final java.text.DecimalFormat df = new java.text.DecimalFormat( "0.#" ); + log( "Gene trees analyzed : " + _duplications_stats.getN() ); + log( "Mean number of duplications : " + df.format( _duplications_stats.arithmeticMean() ) + + " (sd: " + df.format( _duplications_stats.sampleStandardDeviation() ) + ")" ); + if ( _duplications_stats.getN() > 3 ) { + log( "Median number of duplications : " + df.format( _duplications_stats.median() ) ); + } + log( "Minimum duplications : " + ( int ) _duplications_stats.getMin() ); + log( "Maximum duplications : " + ( int ) _duplications_stats.getMax() ); + } + + private final void preLog( final Phylogeny[] gene_trees, + final Phylogeny species_tree, + final ALGORITHM algorithm, + final String outgroup ) { + log( "Number of gene tree (total) : " + gene_trees.length ); + log( "Algorithm : " + algorithm ); + log( "Species tree external nodes (prior to stripping): " + species_tree.getNumberOfExternalNodes() ); + log( "Species tree polytomies (prior to stripping) : " + + PhylogenyMethods.countNumberOfPolytomies( species_tree ) ); + String rs = ""; + switch ( _rerooting ) { + case BY_ALGORITHM: { + rs = "minimizing duplications"; + break; + } + case MIDPOINT: { + rs = "midpoint"; + break; + } + case OUTGROUP: { + rs = "outgroup: " + outgroup; + break; + } + case NONE: { + rs = "none"; + break; + } + } + log( "Re-rooting : " + rs ); + if ( _rerooting == REROOTING.BY_ALGORITHM ) { + writeLogSubHeader(); + } + } + + private final void writeLogSubHeader() { + _log.append( ForesterUtil.LINE_SEPARATOR ); + _log.append( "Some information about duplication numbers in gene trees:" ); + _log.append( ForesterUtil.LINE_SEPARATOR ); _log.append( "#" ); _log.append( "\t" ); - _log.append( "with minimal number of duplications" ); + _log.append( "re-rootings with minimal number of duplications" ); _log.append( "/" ); - _log.append( "root placements" ); - _log.append( "\t[" ); - _log.append( "min" ); - _log.append( "-" ); - _log.append( "max" ); - _log.append( "]\t<" ); - _log.append( "shortest" ); - _log.append( ">" ); + _log.append( "total root placements" ); + _log.append( "\t" ); + _log.append( "duplications range" ); + _log.append( "\t" ); + _log.append( "mininal duplication re-rootings with shortest tree heigth" ); _log.append( ForesterUtil.LINE_SEPARATOR ); } @@ -317,13 +401,12 @@ public final class RIO { _log.append( gsdir.getMinDuplicationsSumGeneTrees().size() ); _log.append( "/" ); _log.append( stats.getN() ); - _log.append( "\t[" ); + _log.append( "\t" ); _log.append( ( int ) stats.getMin() ); _log.append( "-" ); _log.append( ( int ) stats.getMax() ); - _log.append( "]\t<" ); + _log.append( "\t" ); _log.append( shortests.size() ); - _log.append( ">" ); _log.append( ForesterUtil.LINE_SEPARATOR ); } @@ -384,13 +467,41 @@ public final class RIO { return m; } - private final static void checkReRooting( final REROOTING rerooting, final String outgroup ) { - if ( !ForesterUtil.isEmpty( outgroup ) && rerooting != REROOTING.OUTGROUP ) { - throw new IllegalArgumentException( "can only use outgroup when re-rooting in this manner" ); + public final static RIO executeAnalysis( final File gene_trees_file, + final Phylogeny species_tree, + final ALGORITHM algorithm, + final REROOTING rerooting, + final String outgroup, + final boolean produce_log, + final boolean verbose ) throws IOException, SDIException, RIOException { + final PhylogenyFactory factory = ParserBasedPhylogenyFactory.getInstance(); + final PhylogenyParser p = ParserUtils.createParserDependingOnFileType( gene_trees_file, true ); + if ( p instanceof NHXParser ) { + final NHXParser nhx = ( NHXParser ) p; + nhx.setReplaceUnderscores( false ); + nhx.setIgnoreQuotes( true ); + nhx.setTaxonomyExtraction( NHXParser.TAXONOMY_EXTRACTION.YES ); } + final Phylogeny[] gene_trees = factory.create( gene_trees_file, p ); + return new RIO( gene_trees, species_tree, algorithm, rerooting, outgroup, -1, -1, produce_log, verbose ); } - public BasicDescriptiveStatistics getDuplicationsStatistics() { - return _duplications_stats; + public final static RIO executeAnalysis( final Phylogeny[] gene_trees, final Phylogeny species_tree ) + throws IOException, SDIException, RIOException { + return new RIO( gene_trees, species_tree, ALGORITHM.GSDIR, REROOTING.BY_ALGORITHM, null, -1, -1, false, false ); + } + + public final static RIO executeAnalysis( final Phylogeny[] gene_trees, + final Phylogeny species_tree, + final ALGORITHM algorithm, + final REROOTING rerooting, + final String outgroup, + final boolean produce_log, + final boolean verbose ) throws IOException, SDIException, RIOException { + return new RIO( gene_trees, species_tree, algorithm, rerooting, outgroup, -1, -1, produce_log, verbose ); + } + + public enum REROOTING { + NONE, BY_ALGORITHM, MIDPOINT, OUTGROUP; } } diff --git a/forester/java/src/org/forester/rio/TestRIO.java b/forester/java/src/org/forester/rio/TestRIO.java index 1480e8a..5ba32cb 100644 --- a/forester/java/src/org/forester/rio/TestRIO.java +++ b/forester/java/src/org/forester/rio/TestRIO.java @@ -41,7 +41,13 @@ public final class TestRIO { species_tree_1.setRooted( true ); PhylogenyMethods.transferNodeNameToField( species_tree_1, PhylogenyNodeField.TAXONOMY_CODE, true ); //Archaeopteryx.createApplication( species_trees_1 ); - RIO rio = new RIO( gene_trees_1, species_tree_1, ALGORITHM.GSDIR, REROOTING.BY_ALGORITHM, "", true, false ); + RIO rio = RIO.executeAnalysis( gene_trees_1, + species_tree_1, + ALGORITHM.GSDIR, + REROOTING.BY_ALGORITHM, + "", + true, + false ); if ( rio.getAnalyzedGeneTrees().length != 5 ) { return false; } @@ -80,7 +86,7 @@ public final class TestRIO { final Phylogeny species_tree_2 = factory.create( species_trees_2_str, new NHXParser() )[ 0 ]; species_tree_2.setRooted( true ); PhylogenyMethods.transferNodeNameToField( species_tree_2, PhylogenyNodeField.TAXONOMY_CODE, true ); - rio = new RIO( gene_trees_2, species_tree_2, ALGORITHM.GSDIR, REROOTING.BY_ALGORITHM, null, true, false ); + rio = RIO.executeAnalysis( gene_trees_2, species_tree_2 ); m = RIO.calculateOrthologTable( rio.getAnalyzedGeneTrees(), true ); // System.out.println( m.toString() ); if ( !m.getRowAsString( 0, ',' ).equals( "ARATH,5,5,5,5,5,5" ) ) { diff --git a/forester/java/src/org/forester/sdi/GSDIR.java b/forester/java/src/org/forester/sdi/GSDIR.java index c211c42..97de397 100644 --- a/forester/java/src/org/forester/sdi/GSDIR.java +++ b/forester/java/src/org/forester/sdi/GSDIR.java @@ -39,13 +39,8 @@ import org.forester.util.BasicDescriptiveStatistics; public class GSDIR implements GSDII { - private final int _min_duplications_sum; - private final int _speciations_sum; - - @Override - public int getSpeciationsSum() { - return _speciations_sum; - } + private final int _min_duplications_sum; + private final int _speciations_sum; private final BasicDescriptiveStatistics _duplications_sum_stats; private final List _min_duplications_sum_gene_trees; private final List _stripped_gene_tree_nodes; @@ -107,14 +102,6 @@ public class GSDIR implements GSDII { _speciations_sum = speciations_sum; } - public int getMinDuplicationsSum() { - return _min_duplications_sum; - } - - public List getMinDuplicationsSumGeneTrees() { - return _min_duplications_sum_gene_trees; - } - public BasicDescriptiveStatistics getDuplicationsSumStats() { return _duplications_sum_stats; } @@ -124,12 +111,25 @@ public class GSDIR implements GSDII { return _mapped_species_tree_nodes; } + public int getMinDuplicationsSum() { + return _min_duplications_sum; + } + + public List getMinDuplicationsSumGeneTrees() { + return _min_duplications_sum_gene_trees; + } + @Override public final SortedSet getReMappedScientificNamesFromGeneTree() { return _scientific_names_mapped_to_reduced_specificity; } @Override + public int getSpeciationsSum() { + return _speciations_sum; + } + + @Override public List getStrippedExternalGeneTreeNodes() { return _stripped_gene_tree_nodes; } -- 1.7.10.2