in progress...
[jalview.git] / forester / java / src / org / forester / msa_compactor / Chart.java
1 // $Id:
2 // FORESTER -- software libraries and applications
3 // for evolutionary biology research and applications.
4 //
5 // Copyright (C) 2014 Christian M. Zmasek
6 // Copyright (C) 2014 Sanford-Burnham Medical Research Institute
7 // All rights reserved
8 //
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.
13 //
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.
18 //
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
22 //
23 // WWW: https://sites.google.com/site/cmzmasek/home/software/forester
24
25 package org.forester.msa_compactor;
26
27 import java.awt.BorderLayout;
28 import java.awt.event.ActionListener;
29 import java.text.DecimalFormat;
30 import java.text.NumberFormat;
31 import java.util.List;
32
33 import javax.swing.JDialog;
34 import javax.swing.JMenu;
35 import javax.swing.JMenuBar;
36 import javax.swing.JMenuItem;
37 import javax.swing.JPanel;
38 import javax.swing.UIManager;
39 import javax.swing.WindowConstants;
40
41 import org.forester.util.ForesterUtil;
42
43 import com.approximatrix.charting.coordsystem.BoxCoordSystem;
44 import com.approximatrix.charting.model.MultiScatterDataModel;
45 import com.approximatrix.charting.render.MultiScatterChartRenderer;
46 import com.approximatrix.charting.swing.ChartPanel;
47
48 public final class Chart extends JDialog implements ActionListener {
49
50     final private static NumberFormat NF_1             = new DecimalFormat( "0.##" );
51     private static final long         serialVersionUID = -5292420246132943515L;
52     private ChartPanel                _chart_panel     = null;
53     private final int                 _initial_number_of_seqs;
54     private final JMenuItem           _m_exit          = new JMenuItem();
55     private final List<MsaProperties> _msa_props;
56     private final boolean             _show_msa_qual;
57     private final String              _title;
58
59     private Chart( final List<MsaProperties> msa_props,
60                    final int initial_number_of_seqs,
61                    final boolean show_msa_qual,
62                    final String title ) {
63         super();
64         _msa_props = msa_props;
65         _title = title;
66         _initial_number_of_seqs = initial_number_of_seqs;
67         _show_msa_qual = show_msa_qual;
68         setTitle( "msa compactor" );
69         setSize( 600, 500 );
70         setResizable( true );
71         final JPanel content_pane = new JPanel();
72         content_pane.setLayout( new BorderLayout() );
73         setContentPane( content_pane );
74         final JMenuBar menu_bar = new JMenuBar();
75         final JMenu file_menu = new JMenu();
76         file_menu.setText( "File" );
77         _m_exit.setText( "Exit" );
78         file_menu.add( _m_exit );
79         menu_bar.add( file_menu );
80         setJMenuBar( menu_bar );
81         setDefaultCloseOperation( WindowConstants.DISPOSE_ON_CLOSE );
82         _m_exit.addActionListener( this );
83         content_pane.add( obtainChartPanel(), BorderLayout.CENTER );
84     }
85
86     @Override
87     public void actionPerformed( final java.awt.event.ActionEvent e ) {
88         if ( e.getSource() == _m_exit ) {
89             dispose();
90         }
91     }
92
93     private ChartPanel obtainChartPanel() {
94         if ( _chart_panel == null ) {
95             final MultiScatterDataModel model = new MultiScatterDataModel();
96             final double[][] seqs_length = new double[ _msa_props.size() ][ 2 ];
97             int max_length = -1;
98             int min_length = Integer.MAX_VALUE;
99             double max_gap_ratio = -1;
100             double min_gap_ratio = Double.MAX_VALUE;
101             double max_avg_gap_count = -1;
102             double min_avg_gap_count = Double.MAX_VALUE;
103             for( int i = 0; i < _msa_props.size(); ++i ) {
104                 seqs_length[ i ][ 0 ] = _initial_number_of_seqs - _msa_props.get( i ).getNumberOfSequences();
105                 //
106                 final int length = _msa_props.get( i ).getLength();
107                 seqs_length[ i ][ 1 ] = length;
108                 if ( length > max_length ) {
109                     max_length = length;
110                 }
111                 if ( length < min_length ) {
112                     min_length = length;
113                 }
114                 //
115                 final double gap_ratio = _msa_props.get( i ).getGapRatio();
116                 if ( gap_ratio > max_gap_ratio ) {
117                     max_gap_ratio = gap_ratio;
118                 }
119                 if ( gap_ratio < min_gap_ratio ) {
120                     min_gap_ratio = gap_ratio;
121                 }
122                 //
123                 final double avg_gap_count = _msa_props.get( i ).getAvgNumberOfGaps();
124                 if ( avg_gap_count > max_avg_gap_count ) {
125                     max_avg_gap_count = avg_gap_count;
126                 }
127                 if ( avg_gap_count < min_avg_gap_count ) {
128                     min_avg_gap_count = avg_gap_count;
129                 }
130             }
131             model.addData( seqs_length, "Length" + " (" + minMaxToString( min_length, max_length ) + ")" );
132             model.setSeriesLine( "Series " + "Length", true );
133             model.setSeriesMarker( "Series " + "Length", false );
134             final double[][] seqs_gaps = new double[ _msa_props.size() ][ 2 ];
135             double max_ent7 = -1;
136             double max_ent21 = -1;
137             double min_ent7 = Double.MAX_VALUE;
138             double min_ent21 = Double.MAX_VALUE;
139             if ( _show_msa_qual ) {
140                 for( int i = 0; i < _msa_props.size(); ++i ) {
141                     final double ent7 = _msa_props.get( i ).getEntropy7();
142                     if ( ent7 > max_ent7 ) {
143                         max_ent7 = ent7;
144                     }
145                     if ( ent7 < max_ent7 ) {
146                         min_ent7 = ent7;
147                     }
148                     final double ent21 = _msa_props.get( i ).getEntropy21();
149                     if ( ent21 > min_ent21 ) {
150                         max_ent21 = ent21;
151                     }
152                     if ( ent21 < min_ent21 ) {
153                         min_ent21 = ent21;
154                     }
155                 }
156             }
157             final double gap_ratio_factor = ( max_length / 2.0 ) / max_gap_ratio;
158             final double avg_gaps_counts_factor = ( max_length / 2.0 ) / max_avg_gap_count;
159             final double ent7_factor = ( max_length / 2.0 ) / max_ent7;
160             final double ent21_factor = ( max_length / 2.0 ) / max_ent21;
161             for( int i = 0; i < _msa_props.size(); ++i ) {
162                 seqs_gaps[ i ][ 0 ] = _initial_number_of_seqs - _msa_props.get( i ).getNumberOfSequences();
163                 seqs_gaps[ i ][ 1 ] = ForesterUtil.roundToInt( _msa_props.get( i ).getGapRatio() * gap_ratio_factor );
164             }
165             model.addData( seqs_gaps, "Gap Ratio" + " (" + minMaxToString( min_gap_ratio, max_gap_ratio ) + ")" );
166             model.setSeriesLine( "Series " + "Gap Ratio", true );
167             model.setSeriesMarker( "Series " + "Gap Ratio", false );
168             final double[][] gap_counts = new double[ _msa_props.size() ][ 2 ];
169             for( int i = 0; i < _msa_props.size(); ++i ) {
170                 gap_counts[ i ][ 0 ] = _initial_number_of_seqs - _msa_props.get( i ).getNumberOfSequences();
171                 gap_counts[ i ][ 1 ] = ForesterUtil.roundToInt( _msa_props.get( i ).getAvgNumberOfGaps()
172                                                                 * avg_gaps_counts_factor );
173             }
174             model.addData( gap_counts, "Mean Gap Count" + " (" + minMaxToString( min_avg_gap_count, max_avg_gap_count )
175                     + ")" );
176             model.setSeriesLine( "Series " + "Mean Gap Count", true );
177             model.setSeriesMarker( "Series " + "Mean Gap Count", false );
178             if ( _show_msa_qual ) {
179                 final double[][] entropy7 = new double[ _msa_props.size() ][ 2 ];
180                 for( int i = 0; i < _msa_props.size(); ++i ) {
181                     entropy7[ i ][ 0 ] = _initial_number_of_seqs - _msa_props.get( i ).getNumberOfSequences();
182                     entropy7[ i ][ 1 ] = ForesterUtil.roundToInt( _msa_props.get( i ).getEntropy7() * ent7_factor );
183                 }
184                 model.addData( entropy7, "Entropy norm 7" + " (" + minMaxToString( min_ent7, max_ent7 ) + ")" );
185                 model.setSeriesLine( "Series " + "Entropy norm 7", true );
186                 model.setSeriesMarker( "Series " + "Entropy norm 7", false );
187                 //
188                 final double[][] entropy21 = new double[ _msa_props.size() ][ 2 ];
189                 for( int i = 0; i < _msa_props.size(); ++i ) {
190                     entropy21[ i ][ 0 ] = _initial_number_of_seqs - _msa_props.get( i ).getNumberOfSequences();
191                     entropy21[ i ][ 1 ] = ForesterUtil.roundToInt( _msa_props.get( i ).getEntropy21() * ent21_factor );
192                 }
193                 model.addData( entropy21, "Entropy norm 21" + " (" + minMaxToString( min_ent21, max_ent21 ) + ")" );
194                 model.setSeriesLine( "Series " + "Entropy norm 21", true );
195                 model.setSeriesMarker( "Series " + "Entropy norm 21", false );
196             }
197             final BoxCoordSystem coord = new BoxCoordSystem( model );
198             coord.setUnitFont( coord.getUnitFont().deriveFont( 16.0f ) );
199             coord.setXAxisUnit( "Number of Removed Sequences" );
200             coord.setPaintGrid( true );
201             coord.setYAxisUnit( "MSA Length" );
202             _chart_panel = new ChartPanel( model, _title );
203             _chart_panel.setCoordSystem( coord );
204             final MultiScatterChartRenderer renderer = new MultiScatterChartRenderer( coord, model );
205             renderer.setAllowBuffer( false );
206             _chart_panel.addChartRenderer( renderer, 0 );
207         }
208         return _chart_panel;
209     }
210
211     private final static String minMaxToString( final double min, final double max ) {
212         return NF_1.format( min ) + "-" + NF_1.format( max );
213     }
214
215     public static void display( final List<MsaProperties> msa_props,
216                                 final int initial_number_of_seqs,
217                                 final boolean show_msa_qual,
218                                 final String title ) {
219         try {
220             UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
221         }
222         catch ( final Exception e ) {
223             e.printStackTrace();
224         }
225         final Chart chart = new Chart( msa_props, initial_number_of_seqs, show_msa_qual, title );
226         chart.setVisible( true );
227     }
228
229     public static void main( final String[] args ) {
230         try {
231             UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
232         }
233         catch ( final Exception e ) {
234             e.printStackTrace();
235         }
236         final Chart temp = new Chart( null, 0, true, "title" );
237         temp.setVisible( true );
238     }
239 }