001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021package org.biojava.bio.program.blast2html; 022 023 024/** 025 * <p> 026 * Class to do simple HTML colouring of sequence alignments. 027 * </p> 028 * 029 * <p> 030 * For any particular alignment position, the colouring depends only on the two 031 * characters at that position. The decision is made in two stages:- 032 * <ol> 033 * <li>Whether to colour or not in the <CODE>ColourCommand.isColoured()</CODE> 034 * method</li> 035 * <li>what the colours are in the <CODE>AlignmentStyler.getStyle()</CODE> 036 * method</li> 037 * </ol> 038 * </p> 039 * 040 * <p> 041 * This allows simple choices to highlight the mismatches, the identities or 042 * simply colour up everything. 043 * </p> 044 * 045 * <p> 046 * The current implemention of step 2. is a simple colour lookup. 047 * </p> 048 * 049 * <p> 050 * Limitations: 051 * </p> 052 * 053 * <p> 054 * As the FONT styles need to be defined before being used in the HTML, 055 * it means the all colours to be used have to calculated up front. 056 * </p> 057 * 058 * <p> 059 * The position in the alignment is not passed in so position dependent 060 * colouring ( say against a HMM profile ) would be involve either 061 * changing the interfaces or implementing them such that they knew the 062 * required information via another route. 063 * </p> 064 * 065 * <p><pre> 066 * Primary author - 067 * Colin Hardman (CAT) 068 * Other authors - 069 * Tim Dilks (CAT) 070 * Simon Brocklehurst (CAT) 071 * Stuart Johnston (CAT) 072 * Lawerence Bower (CAT) 073 * Derek Crockford (CAT) 074 * Neil Benn (CAT) 075 * 076 * Copyright 2001 Cambridge Antibody Technology Group plc. 077 * </pre></p> 078 * 079 * <p> 080 * This code released to the biojava project, May 2001 081 * under the LGPL license. 082 * </p> 083 * 084 * @author Cambridge Antibody Technology Group plc 085 * @author Greg Cox 086 * @version 1.0 087 */ 088public class AlignmentMarker { 089 090 /** 091 * Resuable StringBuffers for the markup of the alignments 092 */ 093 private StringBuffer[] markedUp = new StringBuffer[ 3 ]; 094 { 095 markedUp[0] = new StringBuffer( 150 ); 096 markedUp[1] = new StringBuffer( 150 ); 097 markedUp[2] = new StringBuffer( 150 ); 098 } 099 100 101 /** 102 * Holds the current style for query, hit and consensus 103 */ 104 private String[] oCurrentStyle = new String[3]; 105 { 106 oCurrentStyle[0] = null; 107 oCurrentStyle[1] = null; 108 oCurrentStyle[2] = null; 109 } 110 111 112 /** 113 * Holds the NewStyles for query, hit and consensus 114 */ 115 private String[] oNewStyle = new String[ 3 ]; 116 117 /** 118 * Single method interface for deciding whether to colour 119 * a particular alignment pair. 120 */ 121 private ColourCommand oColourCommand; 122 123 /** 124 * Class that determines the style for each char 125 */ 126 private AlignmentStyler oStyler; 127 128 /** 129 * Creates a new <code>AlignmentMarker</code> instance. 130 * 131 * @param poColourCommand - controls whether a particular alignment pair 132 * should be coloured 133 * @param poStyler - specifies all possible styles and where each style 134 * is used 135 */ 136 public AlignmentMarker( ColourCommand poColourCommand, 137 AlignmentStyler poStyler ) { 138 139 oColourCommand = poColourCommand; 140 oStyler = poStyler; 141 } 142 143 144 /** 145 * <p> 146 * Delegate to the AlignmentStyler 147 * </p> 148 * 149 * <p> 150 * Returns a fragment of HTML that defines the FONT 151 * styles to be used in the alignment markup. 152 * </p> 153 * 154 * <p> 155 * For example: 156 * <PRE> 157 * FONT.C2-S{background-color:#FFFC50;color:#000000} 158 * FONT.C4-S{background-color:#FC50FF;color:#000000} 159 * FONT.C3-S{background-color:#FF7272;color:#000000} 160 * FONT.C0-S{background-color:#50FF78;color:#000000} 161 * FONT.C1-S{background-color:#FFCA50;color:#000000} 162 * FONT.C5-S{background-color:#A5A5FF;color:#000000} 163 * </PRE> 164 * </p> 165 * 166 * @return String - the HTML 167 */ 168 String getAlignmentStyles() { 169 170 return oStyler.getAlignmentStyles(); 171 } 172 173 /** 174 * Takes three sequences ( of the same length ) as strings and 175 * returns three strings with colour markup in HTML. 176 * 177 * @param poAlignment - three strings representing a pairwise alignment 178 * query, hit, consensus 179 */ 180 void alignment2HTML( String[] poAlignment ) { 181 182 if ( poAlignment == null || poAlignment.length != 3 183 || poAlignment[0].length() != poAlignment[1].length() 184 || poAlignment[0].length() != poAlignment[2].length() ) { 185 186 System.err.println( "-->" + poAlignment[0] + "<--" ); 187 System.err.println( "-->" + poAlignment[1] + "<--" ); 188 System.err.println( "-->" + poAlignment[2] + "<--" ); 189 190 throw new IllegalArgumentException 191 ( "Only accept array of three strings, all of same length" ); 192 } 193 194 if ( oStyler == null ) { // then no styles 195 return; 196 } 197 198 // Initialise 199 200 markedUp[0].setLength(0); 201 markedUp[1].setLength(0); 202 markedUp[2].setLength(0); 203 204 oCurrentStyle[0] = null; 205 oCurrentStyle[1] = null; 206 oCurrentStyle[2] = null; 207 208 // For each position 209 210 for( int i= 0, n = poAlignment[0].length(); i < n ; i++) { 211 212 String oFirst = String.valueOf( poAlignment[0].charAt( i ) ); 213 String oSecond = String.valueOf( poAlignment[1].charAt( i ) ); 214 215 // Decide whether to apply colours. 216 if ( oColourCommand.isColoured( oFirst, oSecond ) ) { 217 oStyler.getStyle( oFirst, oSecond, 218 oNewStyle ); 219 220 } else { 221 // put in a loop if want to change the number 222 oNewStyle[0] = null; 223 oNewStyle[1] = null; 224 oNewStyle[2] = null; 225 } 226 227 this.applyStyles( oCurrentStyle, oNewStyle, markedUp ); 228 229 markedUp[0].append( oFirst ); 230 markedUp[1].append( oSecond ); 231 markedUp[2].append( poAlignment[2].charAt( i ) ); 232 233 System.arraycopy( oNewStyle, 0, oCurrentStyle, 234 0, oNewStyle.length ); 235 236 } // for each char in sequence 237 238 this.flushStyles( oCurrentStyle, markedUp ); 239 240 poAlignment[0] = markedUp[0].substring(0); 241 poAlignment[1] = markedUp[1].substring(0); 242 poAlignment[2] = markedUp[2].substring(0); 243 } 244 245 246 /** 247 * Simple utility function to call applyStyle on seq1, markup & 248 * seq2. 249 * 250 * @param poCurrentStyle a <code>String[]</code> 251 * @param poNewStyle a <code>String[]</code> 252 * @param poMarkedUp a <code>StringBuffer[]</code> 253 */ 254 private void applyStyles( String[] poCurrentStyle, 255 String[] poNewStyle, 256 StringBuffer[] poMarkedUp ) { 257 258 for ( int i=0, n = poCurrentStyle.length; i < n ; i++ ) { 259 this.applyStyle( poCurrentStyle[i], poNewStyle[i], poMarkedUp[i] ); 260 } 261 } 262 263 /** 264 * <p> 265 * Apply the new style to the output. 266 * </p> 267 * 268 * <p> 269 * Takes care of runs of the same style and 270 * changing styles. 271 * </p> 272 * 273 * @param poCurrentStyle <code>String</code> - the current style 274 * @param poNewStyle <code>String</code> - the new style 275 * @param poOutput <code>StringBuffer</code> - the styled output 276 */ 277 private void applyStyle( String poCurrentStyle, 278 String poNewStyle, 279 StringBuffer poOutput ) { 280 // 281 // If new style is null we just need to close the old style 282 // if it was different. 283 // 284 // else if the new style is different from the old 285 // start a new style. 286 // 287 if ( poNewStyle == null ) { 288 289 if ( poCurrentStyle != null ) { 290 poOutput.append( "</FONT>" ); 291 } 292 } else if ( !poNewStyle.equals( poCurrentStyle ) ) { 293 if ( poCurrentStyle != null ) { 294 poOutput.append( "</FONT>" ); 295 } 296 // start a new one 297 poOutput.append("<FONT CLASS=" + poNewStyle + ">"); 298 } 299 } 300 301 /** 302 * If the last style is not null then close it. 303 * 304 */ 305 private void flushStyles( String[] poCurrentStyle, 306 StringBuffer[] poMarkedUp ) { 307 308 for ( int i=0, n = poCurrentStyle.length; i < n ; i++ ) { 309 if ( poCurrentStyle[i] != null ) { //then close 310 poMarkedUp[i].append( "</FONT>" ); 311 } 312 } 313 } 314} 315 316