extensions/net.sf.basedb.genepattern/trunk/src/net/sf/basedb/genepattern/export/GctExporter.java

Code
Comments
Other
Rev Date Author Line
1091 27 May 09 nicklas 1 package net.sf.basedb.genepattern.export;
1091 27 May 09 nicklas 2
1091 27 May 09 nicklas 3 import java.sql.SQLException;
1091 27 May 09 nicklas 4 import java.util.Arrays;
1092 27 May 09 nicklas 5 import java.util.HashSet;
1091 27 May 09 nicklas 6 import java.util.List;
1092 27 May 09 nicklas 7 import java.util.Set;
1091 27 May 09 nicklas 8
1091 27 May 09 nicklas 9 import net.sf.basedb.core.BioAssay;
1091 27 May 09 nicklas 10 import net.sf.basedb.core.BioAssaySet;
1091 27 May 09 nicklas 11 import net.sf.basedb.core.DatabaseException;
1091 27 May 09 nicklas 12 import net.sf.basedb.core.DbControl;
1091 27 May 09 nicklas 13 import net.sf.basedb.core.DynamicResultIterator;
1091 27 May 09 nicklas 14 import net.sf.basedb.core.DynamicSpotQuery;
1091 27 May 09 nicklas 15 import net.sf.basedb.core.IntensityTransform;
1091 27 May 09 nicklas 16 import net.sf.basedb.core.query.Expressions;
1091 27 May 09 nicklas 17 import net.sf.basedb.core.query.SqlResult;
1091 27 May 09 nicklas 18 import net.sf.basedb.util.export.TableWriter;
1091 27 May 09 nicklas 19 import net.sf.basedb.util.export.spotdata.AbstractBioAssaySetExporter;
1091 27 May 09 nicklas 20 import net.sf.basedb.util.export.spotdata.DynamicField;
1091 27 May 09 nicklas 21 import net.sf.basedb.util.export.spotdata.ExportableFieldFactory;
1091 27 May 09 nicklas 22
1091 27 May 09 nicklas 23 /**
1091 27 May 09 nicklas 24   Bioassay set exporter implementation that exports spot data to
1091 27 May 09 nicklas 25   a GenePatter GCT file. The exported
1091 27 May 09 nicklas 26   file contains the following information:
1091 27 May 09 nicklas 27   <ul>
1091 27 May 09 nicklas 28   <li>Intensity values: The ch1 value for one-channel experiments and the
1091 27 May 09 nicklas 29     ratio for two-channel experiments. If the source bioassay set store
1091 27 May 09 nicklas 30     logged values, the output is also logged values.
1091 27 May 09 nicklas 31   <li>Reporter values: externalId and one additional column (default is
1091 27 May 09 nicklas 32     the description)
1091 27 May 09 nicklas 33   </ul>
1091 27 May 09 nicklas 34   <p>
1091 27 May 09 nicklas 35   Before use the following properties must be set:
1091 27 May 09 nicklas 36   <ul>
1091 27 May 09 nicklas 37   <li>{@link #setDbControl(DbControl)}: A DbControl is needed to extract
1091 27 May 09 nicklas 38     information from the database.
1091 27 May 09 nicklas 39   <li>{@link #setSource(BioAssaySet)}: The source bioassay set that we
1091 27 May 09 nicklas 40     should export data from.
1091 27 May 09 nicklas 41   <li>{@link #setWriter(TableWriter)}: The destination that we should write
1091 27 May 09 nicklas 42     the data to.
1091 27 May 09 nicklas 43   </ul>
1091 27 May 09 nicklas 44   <p>
1091 27 May 09 nicklas 45   The exporter can only be used once. A new instance is needed for each bioassay
1091 27 May 09 nicklas 46   set.
1091 27 May 09 nicklas 47   
1091 27 May 09 nicklas 48   @author nicklas
1091 27 May 09 nicklas 49   @since 1.0
1091 27 May 09 nicklas 50 */
1091 27 May 09 nicklas 51 public class GctExporter 
1091 27 May 09 nicklas 52   extends AbstractBioAssaySetExporter
1091 27 May 09 nicklas 53 {
1091 27 May 09 nicklas 54   private TableWriter out;
1091 27 May 09 nicklas 55   private long spotCount;
1091 27 May 09 nicklas 56   public DynamicField description;
1091 27 May 09 nicklas 57   
1091 27 May 09 nicklas 58   /**
1091 27 May 09 nicklas 59     Create a new GCT exporter.
1091 27 May 09 nicklas 60   */
1091 27 May 09 nicklas 61   public GctExporter()
1091 27 May 09 nicklas 62   {}
1091 27 May 09 nicklas 63   
1091 27 May 09 nicklas 64   /*
1091 27 May 09 nicklas 65     More configuration options
1091 27 May 09 nicklas 66   */
1091 27 May 09 nicklas 67   /**
1091 27 May 09 nicklas 68     Set the stream were the exported data should be written.
1091 27 May 09 nicklas 69     It is expected that the given writer is a fresh writer and
1091 27 May 09 nicklas 70     that no data has been written to it yet.
1091 27 May 09 nicklas 71   */
1091 27 May 09 nicklas 72   public void setWriter(TableWriter out)
1091 27 May 09 nicklas 73   {
1091 27 May 09 nicklas 74     this.out = out;
1091 27 May 09 nicklas 75   }
1091 27 May 09 nicklas 76   public void setDescriptionField(DynamicField field)
1091 27 May 09 nicklas 77   {
1091 27 May 09 nicklas 78     this.description = field;
1091 27 May 09 nicklas 79   }
1091 27 May 09 nicklas 80   // --------------------------
1091 27 May 09 nicklas 81   
1091 27 May 09 nicklas 82   /**
1091 27 May 09 nicklas 83     Get the writer that writes the data to the file.
1091 27 May 09 nicklas 84   */
1091 27 May 09 nicklas 85   protected TableWriter getTableWriter()
1091 27 May 09 nicklas 86   {
1091 27 May 09 nicklas 87     return out;
1091 27 May 09 nicklas 88   }
1091 27 May 09 nicklas 89   
1091 27 May 09 nicklas 90   /*
1091 27 May 09 nicklas 91     From AbstractBioAssaySetExporter class
1091 27 May 09 nicklas 92     ---------------------------------------
1091 27 May 09 nicklas 93   */
1091 27 May 09 nicklas 94   /**
1091 27 May 09 nicklas 95     Prepare the export by pre-loading some information and
1091 27 May 09 nicklas 96     configure the queries that we are going to use.
1091 27 May 09 nicklas 97   */
1091 27 May 09 nicklas 98   @Override
1091 27 May 09 nicklas 99   protected void beginExport()
1091 27 May 09 nicklas 100   {
1091 27 May 09 nicklas 101     super.beginExport();
1091 27 May 09 nicklas 102     setAverageOnReporter(true);
1091 27 May 09 nicklas 103     addReporterFields();
1091 27 May 09 nicklas 104     addSpotFields();
1091 27 May 09 nicklas 105     setProgress(0, "Caching reporter data...");
1091 27 May 09 nicklas 106     cacheReporterData();
1091 27 May 09 nicklas 107   }
1091 27 May 09 nicklas 108
1091 27 May 09 nicklas 109   /**
1091 27 May 09 nicklas 110     Writes headers and assay annotations.
1091 27 May 09 nicklas 111     @return TRUE to continue with the data export
1091 27 May 09 nicklas 112   */
1091 27 May 09 nicklas 113   @Override
1091 27 May 09 nicklas 114   protected boolean exportGlobalHeader() 
1091 27 May 09 nicklas 115   {
1091 27 May 09 nicklas 116     // Get configuration options
1091 27 May 09 nicklas 117     DbControl dc = getDbControl();
1091 27 May 09 nicklas 118     BioAssaySet source = getSource();
1091 27 May 09 nicklas 119     List<BioAssay> assays = getBioAssays();
1091 27 May 09 nicklas 120     List<DynamicField> reporterFields = getReporterFields();
1091 27 May 09 nicklas 121     
1091 27 May 09 nicklas 122     // First line is always: #1.2
1091 27 May 09 nicklas 123     out.println("#1.2");
1091 27 May 09 nicklas 124     
1091 27 May 09 nicklas 125     // Second line is: <number of reporters><tab><number of assays>
1091 27 May 09 nicklas 126     out.println(source.getNumReporters() + "\t" + assays.size());
1091 27 May 09 nicklas 127     
1091 27 May 09 nicklas 128     // Third line is data header: NAME<tab>Description<tab> + one column for each assay
1091 27 May 09 nicklas 129     Object[] data = new Object[reporterFields.size() + assays.size()];
1091 27 May 09 nicklas 130     int index = 0;
1091 27 May 09 nicklas 131     
1092 27 May 09 nicklas 132     boolean hasUniqueNames = checkUniqueNames(assays);
1092 27 May 09 nicklas 133     
1091 27 May 09 nicklas 134     // Reporter fields
1091 27 May 09 nicklas 135     for (DynamicField field : reporterFields)
1091 27 May 09 nicklas 136     {
1091 27 May 09 nicklas 137       data[index++] = field.getTitle();
1091 27 May 09 nicklas 138     }
1091 27 May 09 nicklas 139     // ... and one column for each assay
1091 27 May 09 nicklas 140     for (BioAssay ba : assays)
1091 27 May 09 nicklas 141     {
1092 27 May 09 nicklas 142       data[index++] = hasUniqueNames ? ba.getName() : ba.getName() + "-" + ba.getId();
1091 27 May 09 nicklas 143     }
1091 27 May 09 nicklas 144     out.tablePrintData(data);
1091 27 May 09 nicklas 145     
1091 27 May 09 nicklas 146     // This concludes the header section
1091 27 May 09 nicklas 147     out.flush();
1091 27 May 09 nicklas 148     return true;
1091 27 May 09 nicklas 149   }
1091 27 May 09 nicklas 150   
1091 27 May 09 nicklas 151   /**
1091 27 May 09 nicklas 152     Writes spot data.
1091 27 May 09 nicklas 153   */
1091 27 May 09 nicklas 154   @Override
1091 27 May 09 nicklas 155   protected void exportSectionData() 
1091 27 May 09 nicklas 156   {
1091 27 May 09 nicklas 157     // Get configuration settings
1091 27 May 09 nicklas 158     DbControl dc = getDbControl();
1091 27 May 09 nicklas 159     BioAssaySet source = getSource();
1091 27 May 09 nicklas 160     List<DynamicField> reporterFields = getReporterFields();
1091 27 May 09 nicklas 161     int numSpotFields = getSpotFields().size();
1091 27 May 09 nicklas 162     List<BioAssay> assays = getBioAssays();
1091 27 May 09 nicklas 163     IntensityTransform transform = source.getIntensityTransform();
1091 27 May 09 nicklas 164     boolean isLogged = transform == IntensityTransform.LOG10 || 
1091 27 May 09 nicklas 165       transform == IntensityTransform.LOG2;
1091 27 May 09 nicklas 166     spotCount = source.getNumSpots();
1091 27 May 09 nicklas 167     
1091 27 May 09 nicklas 168     // Prepare the query and more
1091 27 May 09 nicklas 169     DynamicSpotQuery spotQuery = getSpotQuery(false);
1091 27 May 09 nicklas 170     prepareAssayIndexMap(assays, reporterFields.size(), 1);
1091 27 May 09 nicklas 171     Object[] data = new Object[reporterFields.size() + assays.size()];
1091 27 May 09 nicklas 172     int posIndex = numSpotFields + 1;
1091 27 May 09 nicklas 173     int colIndex = numSpotFields + 2;
1091 27 May 09 nicklas 174     int currentPosition = -1;
1091 27 May 09 nicklas 175     
1091 27 May 09 nicklas 176     setProgress(10, "Preparing to load spot data...");
1091 27 May 09 nicklas 177     DynamicResultIterator it = spotQuery.iterate(dc);
1091 27 May 09 nicklas 178     try
1091 27 May 09 nicklas 179     {
1091 27 May 09 nicklas 180       long numDone = 0;
1091 27 May 09 nicklas 181       int numLines = 0;
1091 27 May 09 nicklas 182       int progressInterval = 10; // Every ten lines
1091 27 May 09 nicklas 183       
1091 27 May 09 nicklas 184       while (it.hasNext())
1091 27 May 09 nicklas 185       {
1091 27 May 09 nicklas 186         checkInterrupted();
1091 27 May 09 nicklas 187         SqlResult result = it.next();
1091 27 May 09 nicklas 188         ++numDone;
1091 27 May 09 nicklas 189         
1091 27 May 09 nicklas 190         int position = result.getInt(posIndex);
1091 27 May 09 nicklas 191         if (position != currentPosition)
1091 27 May 09 nicklas 192         {
1091 27 May 09 nicklas 193           if (currentPosition != -1) 
1091 27 May 09 nicklas 194           {
1091 27 May 09 nicklas 195             // Write the current data line when the position changes
1091 27 May 09 nicklas 196             ++numLines;
1091 27 May 09 nicklas 197             out.tablePrintData(data);
1091 27 May 09 nicklas 198             Arrays.fill(data, null);
1091 27 May 09 nicklas 199             if (progressInterval % numLines == 0) 
1091 27 May 09 nicklas 200             {
1091 27 May 09 nicklas 201               int percent = 10+(int)((90L * numDone) / spotCount);
1091 27 May 09 nicklas 202               setProgress(percent, "Exporting spot data: " + 
1091 27 May 09 nicklas 203                 numDone + " of " + spotCount + " done");
1091 27 May 09 nicklas 204             }
1091 27 May 09 nicklas 205           }
1091 27 May 09 nicklas 206           // Prepare the next data line by copying the cached reporter fields
1091 27 May 09 nicklas 207           copyReporterFields(position, data, 0);
1091 27 May 09 nicklas 208           currentPosition = position;
1091 27 May 09 nicklas 209         }
1091 27 May 09 nicklas 210       
1091 27 May 09 nicklas 211         // For 1-channel data, get the ch1 intensity...
1091 27 May 09 nicklas 212         double ch1 = result.getFloat(1);
1091 27 May 09 nicklas 213         boolean goodValue = true;
1091 27 May 09 nicklas 214         if (numSpotFields == 2)
1091 27 May 09 nicklas 215         {
1091 27 May 09 nicklas 216           // For 2-channel data, get the ch1/ch2 ratio...
1091 27 May 09 nicklas 217           double ch2 = result.getFloat(2);
1091 27 May 09 nicklas 218           if (isLogged)
1091 27 May 09 nicklas 219           {
1091 27 May 09 nicklas 220             ch1 -= ch2;
1091 27 May 09 nicklas 221           }
1091 27 May 09 nicklas 222           else if (ch2 != 0)
1091 27 May 09 nicklas 223           {
1091 27 May 09 nicklas 224             ch1 /= ch2;
1091 27 May 09 nicklas 225             if (ch1 <= 0) goodValue = false;
1091 27 May 09 nicklas 226           }
1091 27 May 09 nicklas 227           else
1091 27 May 09 nicklas 228           {
1091 27 May 09 nicklas 229             goodValue = false;
1091 27 May 09 nicklas 230           }
1091 27 May 09 nicklas 231         }
1091 27 May 09 nicklas 232         
1091 27 May 09 nicklas 233         // Store result into 'data' array
1091 27 May 09 nicklas 234         short column = result.getShort(colIndex);
1091 27 May 09 nicklas 235         int index = getAssayIndex(column);
1091 27 May 09 nicklas 236         data[index] = goodValue ? ch1 : "";
1091 27 May 09 nicklas 237       }
1091 27 May 09 nicklas 238       // Print the final line of data
1091 27 May 09 nicklas 239       out.tablePrintData(data);
1091 27 May 09 nicklas 240       out.flush();
1091 27 May 09 nicklas 241     }
1091 27 May 09 nicklas 242     catch (SQLException ex)
1091 27 May 09 nicklas 243     {
1091 27 May 09 nicklas 244       throw new DatabaseException(ex);
1091 27 May 09 nicklas 245     }
1091 27 May 09 nicklas 246     finally
1091 27 May 09 nicklas 247     {
1091 27 May 09 nicklas 248       if (it != null) it.close();
1091 27 May 09 nicklas 249     }
1091 27 May 09 nicklas 250   }
1091 27 May 09 nicklas 251
1091 27 May 09 nicklas 252   @Override
1091 27 May 09 nicklas 253   protected void endExport(RuntimeException e) 
1091 27 May 09 nicklas 254   {
1091 27 May 09 nicklas 255     if (e == null) setProgress(100, "Export complete. " + spotCount + " spots done");
1091 27 May 09 nicklas 256     out.flush();
1091 27 May 09 nicklas 257     out = null;
1091 27 May 09 nicklas 258     super.endExport(e);
1091 27 May 09 nicklas 259   }
1091 27 May 09 nicklas 260   // ----------------------------------------
1091 27 May 09 nicklas 261   
1091 27 May 09 nicklas 262   /**
1091 27 May 09 nicklas 263     Adds position, externalId, symbol, plus all admin-defined extended 
1091 27 May 09 nicklas 264     properties as reporter fields.
1091 27 May 09 nicklas 265   */
1091 27 May 09 nicklas 266   protected void addReporterFields()
1091 27 May 09 nicklas 267   {
1091 27 May 09 nicklas 268     addReporterField(ExportableFieldFactory.reporter("externalId", "NAME", null, null));
1091 27 May 09 nicklas 269     if (description != null)
1091 27 May 09 nicklas 270     {
1091 27 May 09 nicklas 271       addReporterField(description);
1091 27 May 09 nicklas 272     }
1091 27 May 09 nicklas 273     else
1091 27 May 09 nicklas 274     {
1091 27 May 09 nicklas 275       addReporterField(ExportableFieldFactory.simple(Expressions.string(""), "Description", null, null));
1091 27 May 09 nicklas 276     }
1091 27 May 09 nicklas 277   }
1091 27 May 09 nicklas 278   
1091 27 May 09 nicklas 279   /**
1091 27 May 09 nicklas 280     Adds channel data as spot fields.
1091 27 May 09 nicklas 281   */
1091 27 May 09 nicklas 282   protected void addSpotFields()
1091 27 May 09 nicklas 283   {
1091 27 May 09 nicklas 284     BioAssaySet source = getSource();
1091 27 May 09 nicklas 285     int channels = source.getRawDataType().getChannels();
1091 27 May 09 nicklas 286     for (int i = 1; i <= channels; ++i)
1091 27 May 09 nicklas 287     {
1091 27 May 09 nicklas 288       addSpotField(ExportableFieldFactory.channel(i, null, null));
1091 27 May 09 nicklas 289     }
1091 27 May 09 nicklas 290   }
1091 27 May 09 nicklas 291   
1092 27 May 09 nicklas 292   /**
1092 27 May 09 nicklas 293     Check if all bioassay names are unique.
1092 27 May 09 nicklas 294     @return TRUE if the names are unique, FALSE otherwise
1092 27 May 09 nicklas 295   */
1092 27 May 09 nicklas 296   private boolean checkUniqueNames(List<BioAssay> assays) 
1092 27 May 09 nicklas 297   {
1092 27 May 09 nicklas 298     Set<String> names = new HashSet<String>();
1092 27 May 09 nicklas 299     for (BioAssay ba : assays)
1092 27 May 09 nicklas 300     {
1092 27 May 09 nicklas 301       if (names.contains(ba.getName())) return false;
1092 27 May 09 nicklas 302       names.add(ba.getName());
1092 27 May 09 nicklas 303     }
1092 27 May 09 nicklas 304     return true;
1092 27 May 09 nicklas 305   }
1092 27 May 09 nicklas 306
1092 27 May 09 nicklas 307   
1091 27 May 09 nicklas 308 }