Java tutorial
/* * Copyright (c) 2007-2012 The Broad Institute, Inc. * SOFTWARE COPYRIGHT NOTICE * This software and its documentation are the copyright of the Broad Institute, Inc. All rights are reserved. * * This software is supplied without any warranty or guaranteed support whatsoever. The Broad Institute is not responsible for its use, misuse, or functionality. * * This software is licensed under the terms of the GNU Lesser General Public License (LGPL), * Version 2.1 which is available at http://www.opensource.org/licenses/lgpl-2.1.php. */ package org.broad.igv.gitools; import org.apache.commons.io.FilenameUtils; import org.apache.commons.math.stat.StatUtils; import org.apache.log4j.Logger; import org.broad.igv.Globals; import org.broad.igv.dev.api.IGVPlugin; import org.broad.igv.feature.FeatureDB; import org.broad.igv.feature.Locus; import org.broad.igv.feature.NamedFeature; import org.broad.igv.feature.genome.Genome; import org.broad.igv.feature.genome.GenomeManager; import org.broad.igv.lists.GeneList; import org.broad.igv.lists.GeneListManagerUI; import org.broad.igv.track.DataTrack; import org.broad.igv.track.RegionScoreType; import org.broad.igv.track.Track; import org.broad.igv.track.TrackType; import org.broad.igv.ui.IGV; import org.broad.igv.ui.util.FileDialogUtils; import org.broad.igv.ui.util.MessageUtils; import org.broad.igv.util.collections.DoubleArrayList; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.*; import java.net.Socket; import java.util.*; /** * Class for integrating with Gitools. Writes out data in TDM format. * We implement GeneListUIActionListener so the gene list can be selected using * our current UI * @author jrobinso * Date: 11/13/12 * Time: 9:26 PM */ public class Gitools implements IGVPlugin { private static Logger log = Logger.getLogger(Gitools.class); public static final String ENABLE_PROPERTY = "enableGitools"; private static int port = 50151; private static String host = "localhost"; @Override public void init() { addMenuItems(); } private static void addMenuItems() { boolean showTDMButton = Boolean.parseBoolean(System.getProperty(Gitools.ENABLE_PROPERTY, "true")); if (showTDMButton) { JMenu gitoolsMenu = new JMenu("Gitools Heatmaps"); JMenuItem directLoadItem = new JMenuItem("Load Gene Matrix in Gitools"); directLoadItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (Gitools.canConnect()) { GeneListManagerUI dialog = GeneListManagerUI.getInstance(IGV.getMainFrame(), "Gitools Load", new Gitools.DirectLoadListener()); dialog.setVisible(true); } else { JOptionPane.showMessageDialog(IGV.getMainFrame(), "To be able to browse the gene matrix you need to install and open Gitools.\n Download it from http://www.gitools.org."); } } }); gitoolsMenu.add(directLoadItem); JMenuItem gitoolsItem = new JMenuItem("Export Gene Matrix (TDM)..."); gitoolsItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { GeneListManagerUI dialog = GeneListManagerUI.getInstance(IGV.getMainFrame(), "Export TDM", new Gitools.ExportFileListener()); dialog.setVisible(true); } }); gitoolsMenu.add(gitoolsItem); IGV.getInstance().addOtherToolMenu(gitoolsMenu); } } public static void main(String[] args) { try { sendCommand("version"); } catch (IOException e) { e.printStackTrace(); } } /** * Send a command to gitools, and read the response. * @param command * @return First line of response only TODO This is stupid but readLine is hanging so hack it for now * @throws IOException */ private static List<String> sendCommand(String command) throws IOException { Socket socket = null; try { socket = new Socket(host, port); socket.setSoTimeout(1000); PrintWriter out = new PrintWriter(socket.getOutputStream(), true); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); out.println(command); List<String> response = new ArrayList<String>(); String line; while ((line = in.readLine()) != null) { response.add(line); break; } return response; } catch (IOException e) { System.out.println(e); throw new IOException("Error communicating with gitools", e); } finally { if (socket != null) socket.close(); } } public static boolean canConnect() { boolean canConnect = false; try { List<String> version = sendCommand("version"); canConnect = version.get(0).toLowerCase().contains("gitools"); } catch (IOException e) { // } return canConnect; } /** * Export data at specified loci to temp file, and tell gitools to load it. * gitools must already be running * @param lociStrings * @return * @throws IOException */ public static List<String> gitoolsLoad(String name, List<String> lociStrings) throws IOException { String prefix = name + "-igv"; prefix = prefix.replace(" ", "_"); File tmpFile = File.createTempFile(prefix, ".tdm"); exportTDM(lociStrings, tmpFile); return sendCommand(String.format("load %s", tmpFile.getAbsolutePath())); } public static void exportTDM(List<String> lociStrings, File file) throws IOException { // Convert the loci strings to a list of loci, if the loci represents multiple features (e.g. isoforms) use the largest int averageFeatureSize = 0; List<NamedFeature> loci = new ArrayList<NamedFeature>(lociStrings.size()); for (String l : lociStrings) { NamedFeature feature = FeatureDB.getFeature(l); if (feature == null) { feature = Locus.fromString(l); } if (feature != null) { loci.add(feature); averageFeatureSize += (feature.getEnd() - feature.getStart()); } } if (loci.size() > 0) averageFeatureSize /= loci.size(); // Determine data types -- all data tracks + mutation, and samples LinkedHashSet<TrackType> loadedTypes = new LinkedHashSet<TrackType>(); List<Track> tracks = IGV.getInstance().getAllTracks(); for (Track t : tracks) { if ((t instanceof DataTrack || t.getTrackType() == TrackType.MUTATION) && t.isVisible()) { loadedTypes.add(t.getTrackType()); //samples.add(t.getSample()); } } // set an appropriate zoom level for this feature set. Very approximate int zoom = 0; Genome genome = GenomeManager.getInstance().getCurrentGenome(); if (genome != null) { double averageChrLength = genome.getTotalLength() / genome.getChromosomes().size(); zoom = (int) (Math.log(averageChrLength / averageFeatureSize) / Globals.log2) + 1; } // Loop though tracks and loci and gather data by sample & gene Map<String, SampleData> sampleDataMap = new LinkedHashMap<String, SampleData>(); for (Track t : tracks) { if (!t.isVisible()) continue; String sampleName = t.getSample(); List<Track> overlays = IGV.getInstance().getOverlayTracks(t); for (NamedFeature locus : loci) { double regionScore; if (t instanceof DataTrack) { DataTrack dataTrack = (DataTrack) t; regionScore = dataTrack.getAverageScore(locus.getChr(), locus.getStart(), locus.getEnd(), zoom); addToSampleData(sampleDataMap, sampleName, locus.getName(), t.getTrackType(), regionScore); } if (overlays != null) { for (Track overlay : overlays) { if (overlay.getTrackType() == TrackType.MUTATION) { regionScore = overlay.getRegionScore(locus.getChr(), locus.getStart(), locus.getEnd(), zoom, RegionScoreType.MUTATION_COUNT, locus.getName()); //Only add if we found a mutation. Should we put it in anyway? if (regionScore > 0) { addToSampleData(sampleDataMap, sampleName, locus.getName(), overlay.getTrackType(), regionScore); } } } } } } writeTDM(loadedTypes, sampleDataMap, file); } /** * Export calculated data to file * @param loadedTypes Ordered set of track types * @param sampleDataMap Map from sample name to SampleData * @param file Output file * @throws IOException */ private static void writeTDM(LinkedHashSet<TrackType> loadedTypes, Map<String, SampleData> sampleDataMap, File file) throws IOException { PrintWriter pw = null; try { pw = new PrintWriter(new BufferedWriter(new FileWriter(file))); pw.print("Sample\tLocus"); for (TrackType tt : loadedTypes) { pw.print("\t" + tt.name()); } pw.println(); for (SampleData sd : sampleDataMap.values()) { pw.print(sd.sample + "\t" + sd.locus); for (TrackType tt : loadedTypes) { pw.print('\t'); double[] values = sd.getValues(tt); if (values == null) { pw.print("-"); } else { double avg = StatUtils.max(values); pw.print(avg); } } pw.println(); } } catch (IOException e) { throw new IOException("Error exporting TDM", e); } finally { if (pw != null) pw.close(); } } private static void addToSampleData(Map<String, SampleData> sampleDataMap, String sampleName, String locusString, TrackType tt, double regionScore) { if (!Double.isNaN(regionScore)) { //String locusString = locus.getName(); String key = sampleName + "_" + locusString; SampleData sd = sampleDataMap.get(key); if (sd == null) { sd = new SampleData(sampleName, locusString); sampleDataMap.put(key, sd); } sd.addValue(tt, regionScore); } } static class SampleData { String sample; String locus; Map<TrackType, DoubleArrayList> valueMap; SampleData(String sample, String locus) { this.sample = sample; this.locus = locus; this.valueMap = new HashMap<TrackType, DoubleArrayList>(); } void addValue(TrackType tt, double value) { DoubleArrayList vlist = valueMap.get(tt); if (vlist == null) { vlist = new DoubleArrayList(); valueMap.put(tt, vlist); } vlist.add(value); } public double[] getValues(TrackType tt) { DoubleArrayList dal = valueMap.get(tt); return dal == null ? null : dal.toArray(); } } public static class ExportFileListener implements GeneListManagerUI.GeneListListener { @Override public void actionPerformed(JDialog dialog, GeneList geneList) { File file = FileDialogUtils.chooseFile("Export TDM file", null, FileDialogUtils.SAVE); // Check file TDM extension String currentExtension = FilenameUtils.getExtension(file.getName()); if (!currentExtension.equalsIgnoreCase("TDM")) { file = new File(file.getAbsolutePath() + ".tdm"); } if (file != null) { try { Gitools.exportTDM(geneList.getLoci(), file); } catch (IOException exc) { MessageUtils.showErrorMessage("Error exporting TDM", exc); } } } } public static class DirectLoadListener implements GeneListManagerUI.GeneListListener { @Override public void actionPerformed(JDialog dialog, GeneList geneList) { //Test communication boolean canConnect = canConnect(); if (!canConnect) { MessageUtils .showMessage("Cannot communicate with gitools, check that it is running on port " + port); return; } try { gitoolsLoad(geneList.getName(), geneList.getLoci()); } catch (IOException exc) { MessageUtils.showErrorMessage(exc.getMessage(), exc); } } } }