2 // forester -- software libraries and applications
3 // for genomics and evolutionary biology research.
5 // Copyright (C) 2010 Christian M Zmasek
6 // Copyright (C) 2010 Sanford-Burnham Medical Research Institute
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 // Contact: phylosoft @ gmail . com
24 // WWW: www.phylosoft.org/forester
26 package org.forester.archaeopteryx.tools;
28 import java.awt.Color;
29 import java.awt.FlowLayout;
30 import java.awt.event.ActionEvent;
31 import java.awt.event.ActionListener;
32 import java.util.List;
34 import javax.swing.BoxLayout;
35 import javax.swing.ButtonGroup;
36 import javax.swing.JButton;
37 import javax.swing.JCheckBox;
38 import javax.swing.JDialog;
39 import javax.swing.JFormattedTextField;
40 import javax.swing.JLabel;
41 import javax.swing.JOptionPane;
42 import javax.swing.JPanel;
43 import javax.swing.JRadioButton;
44 import javax.swing.JTextField;
45 import javax.swing.border.Border;
46 import javax.swing.border.LineBorder;
48 import org.forester.archaeopteryx.AptxUtil;
49 import org.forester.archaeopteryx.MainFrameApplication;
50 import org.forester.evoinference.distance.PairwiseDistanceCalculator.PWD_DISTANCE_METHOD;
51 import org.forester.sequence.Sequence;
52 import org.forester.util.BasicDescriptiveStatistics;
53 import org.forester.util.DescriptiveStatistics;
55 public class PhyloInferenceDialog extends JDialog implements ActionListener {
57 private static final long serialVersionUID = 8337543508238133614L;
58 private final JPanel _pnl;
59 private final JButton _launch_btn;
60 private final JButton _cancel_btn;
61 private final JFormattedTextField _bootstrap_tf;
62 private final JCheckBox _bootstrap_cb;
63 private final PhylogeneticInferenceOptions _opts;
64 private JTextField _input_msa_file_tf;
65 private JButton _select_input_msa_btn;
66 private final MainFrameApplication _parent_frame;
67 private JTextField _msa_length_tf;
68 private JTextField _msa_size_tf;
69 private JTextField _msa_type_tf;
70 private final JRadioButton _distance_calc_kimura_rb;
71 private final JRadioButton _distance_calc_poisson_rb;
72 private final JRadioButton _distance_calc_fract_dissimilarity_rb;
73 private int _value = JOptionPane.CANCEL_OPTION;
74 private JTextField _input_seqs_tf;
75 private JButton _select_input_seqs_btn;
76 private JTextField _input_seqs_number_tf;
77 private JTextField _input_seqs_median_length_tf;
78 private JTextField _input_seqs_min_length_tf;
79 private JTextField _input_seqs_max_length_tf;
80 private JTextField _input_seqs_type_tf;
81 private JTextField _mafft_paramenters_tf;
82 private JTextField _clustalo_paramenters_tf;
83 private JTextField _msa_processing_max_allowed_gap_ratio_tf;
84 private JTextField _msa_processing_min_allowed_length_tf;
85 private JTextField _random_seed_tf;
86 private JCheckBox _execute_msa_processing_cb;
87 private JCheckBox _msa_processing_remove_all_gap_columns_cb;
88 private JCheckBox _mafft_cb;
89 private JCheckBox _clustalo_cb;
90 private JCheckBox _save_pwd_file_cb;
91 private JCheckBox _save_processed_msa_cb;
92 private JCheckBox _save_original_msa_cb;
93 private JTextField _pwd_outfile_tf;
94 private JTextField _processed_msa_outfile_tf;
95 private JTextField _original_msa_outfile_tf;
97 public PhyloInferenceDialog( final MainFrameApplication frame,
98 final PhylogeneticInferenceOptions options,
99 final boolean from_unaligned_seqs ) {
100 super( frame, true );
102 _parent_frame = frame;
105 getContentPane().add( _pnl );
106 final BoxLayout box_layout = new BoxLayout( _pnl, BoxLayout.PAGE_AXIS );
107 _pnl.setLayout( box_layout );
108 if ( from_unaligned_seqs ) {
109 setTitle( "Phylogenetic Inference (including multiple sequence alignment)" );
110 final JPanel inputfile_pnl_1 = new JPanel();
111 final JPanel inputfile_pnl_2 = new JPanel();
112 final JPanel inputfile_pnl_3 = new JPanel();
113 final JPanel inputfile_pnl_4 = new JPanel();
114 inputfile_pnl_1.setLayout( new FlowLayout() );
115 inputfile_pnl_2.setLayout( new FlowLayout() );
116 inputfile_pnl_3.setLayout( new FlowLayout() );
117 inputfile_pnl_4.setLayout( new FlowLayout() );
118 inputfile_pnl_1.add( new JLabel( "Input Sequence File:" ) );
119 inputfile_pnl_1.add( _input_seqs_tf = new JTextField() );
120 inputfile_pnl_1.add( _select_input_seqs_btn = new JButton( "Select Input File" ) );
121 inputfile_pnl_2.add( new JLabel( "Sequences: " ) );
122 inputfile_pnl_2.add( new JLabel( "Number of Sequences:" ) );
123 inputfile_pnl_2.add( _input_seqs_number_tf = new JTextField() );
124 inputfile_pnl_2.add( new JLabel( "Length: median:" ) );
125 inputfile_pnl_2.add( _input_seqs_median_length_tf = new JTextField() );
126 inputfile_pnl_2.add( new JLabel( "min:" ) );
127 inputfile_pnl_2.add( _input_seqs_min_length_tf = new JTextField() );
128 inputfile_pnl_2.add( new JLabel( "max:" ) );
129 inputfile_pnl_2.add( _input_seqs_max_length_tf = new JTextField() );
130 inputfile_pnl_2.add( new JLabel( "Type:" ) );
131 inputfile_pnl_2.add( _input_seqs_type_tf = new JTextField() );
132 inputfile_pnl_3.add( _mafft_cb = new JCheckBox( "MAFFT" ) );
133 inputfile_pnl_3.add( new JLabel( "Parameters: " ) );
134 inputfile_pnl_3.add( _mafft_paramenters_tf = new JTextField() );
135 inputfile_pnl_4.add( _clustalo_cb = new JCheckBox( "ClustalO" ) );
136 inputfile_pnl_4.add( new JLabel( "Parameters: " ) );
137 inputfile_pnl_4.add( _clustalo_paramenters_tf = new JTextField() );
138 _input_seqs_median_length_tf.setColumns( 4 );
139 _input_seqs_min_length_tf.setColumns( 4 );
140 _input_seqs_max_length_tf.setColumns( 4 );
141 _input_seqs_number_tf.setColumns( 4 );
142 _input_seqs_type_tf.setColumns( 2 );
143 _input_seqs_tf.setColumns( 20 );
144 _input_seqs_tf.setEditable( false );
145 _input_seqs_median_length_tf.setEditable( false );
146 _input_seqs_min_length_tf.setEditable( false );
147 _input_seqs_max_length_tf.setEditable( false );
148 _input_seqs_number_tf.setEditable( false );
149 _input_seqs_type_tf.setEditable( false );
150 _mafft_paramenters_tf.setColumns( 26 );
151 _mafft_paramenters_tf.setText( "--maxiterate 1000 --localpair" );
152 _clustalo_paramenters_tf.setColumns( 26 );
153 _clustalo_paramenters_tf.setText( "clustalo options" );
154 _select_input_seqs_btn.addActionListener( this );
155 _pnl.add( inputfile_pnl_1 );
156 _pnl.add( inputfile_pnl_2 );
157 _pnl.add( inputfile_pnl_3 );
158 _pnl.add( inputfile_pnl_4 );
161 setTitle( "Phylogenetic Inference (from already aligned sequences) " );
163 final JPanel inputfile_pnl_1 = new JPanel();
164 final JPanel inputfile_pnl_2 = new JPanel();
165 inputfile_pnl_1.setLayout( new FlowLayout() );
166 inputfile_pnl_2.setLayout( new FlowLayout() );
167 inputfile_pnl_1.add( new JLabel( "Input MSA File:" ) );
168 inputfile_pnl_1.add( _input_msa_file_tf = new JTextField() );
169 inputfile_pnl_1.add( _select_input_msa_btn = new JButton( "Select Input File" ) );
170 inputfile_pnl_2.add( new JLabel( "MSA: " ) );
171 inputfile_pnl_2.add( new JLabel( "Number of Sequences:" ) );
172 inputfile_pnl_2.add( _msa_size_tf = new JTextField() );
173 inputfile_pnl_2.add( new JLabel( "Length:" ) );
174 inputfile_pnl_2.add( _msa_length_tf = new JTextField() );
175 inputfile_pnl_2.add( new JLabel( "Type:" ) );
176 inputfile_pnl_2.add( _msa_type_tf = new JTextField() );
177 _msa_length_tf.setColumns( 4 );
178 _msa_size_tf.setColumns( 4 );
179 _msa_type_tf.setColumns( 2 );
180 _input_msa_file_tf.setColumns( 20 );
181 _input_msa_file_tf.setEditable( false );
182 _msa_length_tf.setEditable( false );
183 _msa_size_tf.setEditable( false );
184 _msa_type_tf.setEditable( false );
185 _select_input_msa_btn.addActionListener( this );
186 _pnl.add( inputfile_pnl_1 );
187 _pnl.add( inputfile_pnl_2 );
190 final JPanel inputfile_pnl_4 = new JPanel();
191 inputfile_pnl_4.setLayout( new FlowLayout() );
192 inputfile_pnl_4.add( new JLabel( "MSA Processing: " ) );
193 inputfile_pnl_4.add( _execute_msa_processing_cb = new JCheckBox( "Process MSA" ) );
194 inputfile_pnl_4.add( _msa_processing_remove_all_gap_columns_cb = new JCheckBox( "Remove all gap columns" ) );
195 inputfile_pnl_4.add( new JLabel( "Max allowed gap ratio: " ) );
196 inputfile_pnl_4.add( _msa_processing_max_allowed_gap_ratio_tf = new JTextField() );
197 inputfile_pnl_4.add( new JLabel( "Min allowed non-gap sequence length: " ) );
198 inputfile_pnl_4.add( _msa_processing_min_allowed_length_tf = new JTextField() );
199 _msa_processing_max_allowed_gap_ratio_tf.setColumns( 4 );
200 _msa_processing_min_allowed_length_tf.setColumns( 4 );
201 final Border b = new LineBorder( Color.DARK_GRAY );
202 inputfile_pnl_4.setBorder( b );
203 _pnl.add( inputfile_pnl_4 );
205 // Distance calculation:
206 // TODO if type==AA...
207 final JPanel distance_calc_pnl_1 = new JPanel();
208 distance_calc_pnl_1.setLayout( new FlowLayout() );
209 distance_calc_pnl_1.add( new JLabel( "Distance calculation:" ) );
210 distance_calc_pnl_1.add( _distance_calc_kimura_rb = new JRadioButton( "Kimura correction" ) );
211 distance_calc_pnl_1.add( _distance_calc_poisson_rb = new JRadioButton( "Poisson" ) );
213 .add( _distance_calc_fract_dissimilarity_rb = new JRadioButton( "Fractional dissimilarity" ) );
214 final ButtonGroup distance_calc_group_1 = new ButtonGroup();
215 distance_calc_group_1.add( _distance_calc_kimura_rb );
216 distance_calc_group_1.add( _distance_calc_poisson_rb );
217 distance_calc_group_1.add( _distance_calc_fract_dissimilarity_rb );
218 _pnl.add( distance_calc_pnl_1 );
219 // Bootstrap resampling:
220 final JPanel bootstrap_pnl = new JPanel();
221 bootstrap_pnl.setLayout( new FlowLayout() );
222 bootstrap_pnl.add( _bootstrap_cb = new JCheckBox( "Perform Bootstrap Resampling" ) );
223 bootstrap_pnl.add( new JLabel( "Number of Bootstrap Samples:" ) );
224 bootstrap_pnl.add( _bootstrap_tf = new JFormattedTextField( AptxUtil.createMaskFormatter( "###" ) ) );
225 _bootstrap_tf.setColumns( 4 );
227 // http://download.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html
228 // _bootstrap_tf.setColumns( 4 );
229 bootstrap_pnl.add( new JLabel( "Random Seed:" ) );
230 bootstrap_pnl.add( _random_seed_tf = new JTextField() );
231 _random_seed_tf.setColumns( 4 );
232 _pnl.add( bootstrap_pnl );
233 final JPanel launch_pnl = new JPanel();
234 launch_pnl.setLayout( new FlowLayout() );
235 _launch_btn = new JButton( "Go!" );
236 _launch_btn.addActionListener( this );
237 launch_pnl.add( _launch_btn );
238 _cancel_btn = new JButton( "Cancel" );
239 _cancel_btn.addActionListener( this );
240 launch_pnl.add( _cancel_btn );
241 _pnl.add( launch_pnl );
242 initializeValues( from_unaligned_seqs );
244 setLocationRelativeTo( getParentFrame() );
245 setResizable( false );
249 public void actionPerformed( final ActionEvent e ) {
250 if ( e.getSource() == _select_input_msa_btn ) {
253 else if ( e.getSource() == _select_input_seqs_btn ) {
256 else if ( e.getSource() == _launch_btn ) {
259 else if ( e.getSource() == _cancel_btn ) {
264 public void activate() {
268 private MainFrameApplication getParentFrame() {
269 return _parent_frame;
272 public PhylogeneticInferenceOptions getPhylogeneticInferenceOptions() {
276 public int getValue() {
280 private void initializeValues( final boolean from_unaligned_seqs ) {
281 _value = JOptionPane.CANCEL_OPTION;
282 if ( from_unaligned_seqs ) {
288 updateMsaProcessingItem();
289 updateDistanceCalcMethod();
290 _bootstrap_tf.setText( getPhylogeneticInferenceOptions().getBootstrapSamples() + "" );
291 _random_seed_tf.setText( getPhylogeneticInferenceOptions().getRandomNumberGeneratorSeed() + "" );
294 private void launch() {
295 processPerformBootstrapResampling();
296 if ( _bootstrap_cb.isSelected() ) {
297 processBootstrapSamplesNumber();
298 processRandomNumberGeneratorSeed();
302 processMsaProcessing();
304 processDistanceCalcMethod();
305 processMsaPrgParameters();
307 _value = JOptionPane.OK_OPTION;
310 private void cancel() {
312 _value = JOptionPane.CANCEL_OPTION;
315 private void processBootstrapSamplesNumber() {
316 int bootstrap_samples = 0;
318 bootstrap_samples = Integer.parseInt( _bootstrap_tf.getText().trim() );
320 catch ( final NumberFormatException e ) {
321 // JOptionPane.showMessageDialog( this, "Could not parse number of bootstrap resamplings from: " + _bootstrap_tf.getText().trim(), "User Error", JOptionPane.ERROR_MESSAGE );
324 if ( bootstrap_samples >= 0 ) {
325 getPhylogeneticInferenceOptions().setBootstrapSamples( bootstrap_samples );
329 private void processRandomNumberGeneratorSeed() {
330 long seed = PhylogeneticInferenceOptions.RANDOM_NUMBER_SEED_DEFAULT;
332 seed = Long.parseLong( _random_seed_tf.getText().trim() );
334 catch ( final NumberFormatException e ) {
337 getPhylogeneticInferenceOptions().setRandomNumberGeneratorSeed( seed );
340 private void processMsaProcessing() {
341 getPhylogeneticInferenceOptions().setExecuteMsaProcessing( _execute_msa_processing_cb.isSelected() );
342 getPhylogeneticInferenceOptions()
343 .setMsaProcessingRemoveAllGapColumns( _msa_processing_remove_all_gap_columns_cb.isSelected() );
346 min_length = Integer.parseInt( _msa_processing_min_allowed_length_tf.getText().trim() );
348 catch ( final NumberFormatException e ) {
351 if ( min_length > 0 ) {
352 getPhylogeneticInferenceOptions().setMsaProcessingMinAllowedLength( min_length );
354 double msa_processing_max_allowed_gap_ratio = -1.0;
356 msa_processing_max_allowed_gap_ratio = Double.parseDouble( _msa_processing_max_allowed_gap_ratio_tf
359 catch ( final NumberFormatException e ) {
360 msa_processing_max_allowed_gap_ratio = -1.0;
362 if ( ( msa_processing_max_allowed_gap_ratio >= 0.0 ) && ( msa_processing_max_allowed_gap_ratio <= 1.0 ) ) {
363 getPhylogeneticInferenceOptions().setMsaProcessingMaxAllowedGapRatio( msa_processing_max_allowed_gap_ratio );
367 private void processDistanceCalcMethod() {
368 if ( ( _distance_calc_kimura_rb != null ) && _distance_calc_kimura_rb.isSelected() ) {
369 getPhylogeneticInferenceOptions().setPwdDistanceMethod( PWD_DISTANCE_METHOD.KIMURA_DISTANCE );
371 else if ( ( _distance_calc_poisson_rb != null ) && _distance_calc_poisson_rb.isSelected() ) {
372 getPhylogeneticInferenceOptions().setPwdDistanceMethod( PWD_DISTANCE_METHOD.POISSON_DISTANCE );
374 else if ( ( _distance_calc_fract_dissimilarity_rb != null )
375 && _distance_calc_fract_dissimilarity_rb.isSelected() ) {
376 getPhylogeneticInferenceOptions().setPwdDistanceMethod( PWD_DISTANCE_METHOD.FRACTIONAL_DISSIMILARITY );
380 private void processPerformBootstrapResampling() {
381 getPhylogeneticInferenceOptions().setPerformBootstrapResampling( _bootstrap_cb.isSelected() );
384 private void processMsaPrgParameters() {
385 if ( _mafft_paramenters_tf != null ) {
386 getPhylogeneticInferenceOptions().setMsaPrgParameters( _mafft_paramenters_tf.getText() );
390 private void readInputFile() {
391 getParentFrame().readMsaFromFile();
395 private void readInputSeqsFile() {
396 getParentFrame().readSeqsFromFile();
400 private void updateDistanceCalcMethod() {
401 switch ( getPhylogeneticInferenceOptions().getPwdDistanceMethod() ) {
402 case KIMURA_DISTANCE:
403 _distance_calc_kimura_rb.setSelected( true );
405 case POISSON_DISTANCE:
406 _distance_calc_poisson_rb.setSelected( true );
408 case FRACTIONAL_DISSIMILARITY:
409 _distance_calc_fract_dissimilarity_rb.setSelected( true );
412 throw new RuntimeException( "invalid distance calc method" );
416 private void updateMsaProcessingItem() {
417 _execute_msa_processing_cb.setSelected( getPhylogeneticInferenceOptions().isExecuteMsaProcessing() );
418 _msa_processing_remove_all_gap_columns_cb.setSelected( getPhylogeneticInferenceOptions()
419 .isMsaProcessingRemoveAllGapColumns() );
420 if ( _opts.getMsaProcessingMaxAllowedGapRatio() > 0 ) {
421 _msa_processing_max_allowed_gap_ratio_tf.setText( _opts.getMsaProcessingMaxAllowedGapRatio() + "" );
423 if ( _opts.getMsaProcessingMinAllowedLength() > 0 ) {
424 _msa_processing_min_allowed_length_tf.setText( _opts.getMsaProcessingMinAllowedLength() + "" );
428 private void updateMsaItems() {
429 if ( getParentFrame().getMsa() != null ) {
430 _input_msa_file_tf.setText( getParentFrame().getMsaFile().toString() );
431 _msa_length_tf.setText( getParentFrame().getMsa().getLength() + "" );
432 _msa_size_tf.setText( getParentFrame().getMsa().getNumberOfSequences() + "" );
433 _msa_type_tf.setText( getParentFrame().getMsa().getType() + "" );
434 _input_msa_file_tf.setEnabled( true );
435 _msa_length_tf.setEnabled( true );
436 _msa_size_tf.setEnabled( true );
437 _msa_type_tf.setEnabled( true );
438 _launch_btn.setEnabled( true );
441 _input_msa_file_tf.setText( "" );
442 _msa_length_tf.setText( "" );
443 _msa_size_tf.setText( "" );
444 _msa_type_tf.setText( "" );
445 _input_msa_file_tf.setEnabled( false );
446 _msa_length_tf.setEnabled( false );
447 _msa_size_tf.setEnabled( false );
448 _msa_type_tf.setEnabled( false );
449 _launch_btn.setEnabled( false );
453 private void updateSeqsItems() {
454 if ( getParentFrame().getSeqs() != null ) {
455 final DescriptiveStatistics stats = calcSequenceStats( getParentFrame().getSeqs() );
456 _input_seqs_tf.setText( getParentFrame().getSeqsFile().toString() );
457 _input_seqs_median_length_tf.setText( ( int ) stats.median() + "" );
458 _input_seqs_min_length_tf.setText( ( int ) stats.getMin() + "" );
459 _input_seqs_max_length_tf.setText( ( int ) stats.getMax() + "" );
460 _input_seqs_number_tf.setText( getParentFrame().getSeqs().size() + "" );
461 _input_seqs_type_tf.setText( getParentFrame().getSeqs().get( 0 ).getType() + "" );
462 _input_seqs_tf.setEnabled( true );
463 _input_seqs_median_length_tf.setEnabled( true );
464 _input_seqs_min_length_tf.setEnabled( true );
465 _input_seqs_max_length_tf.setEnabled( true );
466 _input_seqs_number_tf.setEnabled( true );
467 _input_seqs_type_tf.setEnabled( true );
468 _launch_btn.setEnabled( true );
471 _input_seqs_tf.setText( "" );
472 _input_seqs_median_length_tf.setText( "" );
473 _input_seqs_min_length_tf.setText( "" );
474 _input_seqs_max_length_tf.setText( "" );
475 _input_seqs_number_tf.setText( "" );
476 _input_seqs_type_tf.setText( "" );
477 _input_seqs_tf.setEnabled( false );
478 _input_seqs_median_length_tf.setEnabled( false );
479 _input_seqs_min_length_tf.setEnabled( false );
480 _input_seqs_max_length_tf.setEnabled( false );
481 _input_seqs_number_tf.setEnabled( false );
482 _input_seqs_type_tf.setEnabled( false );
483 _launch_btn.setEnabled( false );
487 DescriptiveStatistics calcSequenceStats( final List<Sequence> seqs ) {
488 final DescriptiveStatistics stats = new BasicDescriptiveStatistics();
489 for( final Sequence s : seqs ) {
490 stats.addValue( s.getLength() );