/*
* EuroCarbDB, a framework for carbohydrate bioinformatics
*
* Copyright (c) 2006-2009, Eurocarb project, or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
* A copy of this license accompanies this distribution in the file LICENSE.txt.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* Last commit: $Rev: 1930 $ by $Author: david@nixbioinf.org $ on $Date:: 2010-07-29 #$
*/
package org.eurocarbdb.application.glycoworkbench;
import org.eurocarbdb.application.glycanbuilder.*;
import java.io.*;
import java.util.*;
import java.util.regex.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import org.jfree.data.Range;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import javax.xml.transform.sax.TransformerHandler;
import org.xml.sax.helpers.AttributesImpl;
/**
* Document containing a list of labeled peaks
*
* @author Alessio Ceroni (a.ceroni@imperial.ac.uk)
*/
public class PeakList extends BaseDocument implements SAXUtils.SAXWriter {
protected Vector<Peak> peaks;
protected double max_intensity;
/**
* Create an empty peak list
*/
public PeakList() {
super();
max_intensity = 0.;
}
/**
* Create a list containing a single peak with a specified mass/charge value
* and 0 intensity
*/
public PeakList(double m_z) {
super();
max_intensity = 0.;
put(m_z, 1.);
}
/**
* Create a peak list from the specified collection of peaks
*/
public PeakList(Collection<Peak> _peaks) {
super();
max_intensity = 0.;
mergeData(_peaks);
}
public String getName() {
return "PeakList";
}
public javax.swing.ImageIcon getIcon() {
return FileUtils.defaultThemeManager.getImageIcon("peaksdoc");
}
public Collection<javax.swing.filechooser.FileFilter> getFileFormats() {
Vector<javax.swing.filechooser.FileFilter> filters = new Vector<javax.swing.filechooser.FileFilter>();
filters.add(new ExtensionFileFilter("mgf",
"Mascot generic peaklist format files"));
filters.add(new ExtensionFileFilter("xml", "Bruker peak list files"));
filters
.add(new ExtensionFileFilter("msa",
"Cartoonist peak list files"));
filters
.add(new ExtensionFileFilter("ctd", "Cartoonist centroids file"));
filters.add(new ExtensionFileFilter(new String[] { "txt", "csv" },
"Comma separated peak list files"));
filters.add(new ExtensionFileFilter(new String[] { "txt", "csv", "ctd",
"mgf", "msa", "xml" }, "All peak list files"));
return filters;
}
public javax.swing.filechooser.FileFilter getAllFileFormats() {
return new ExtensionFileFilter(new String[] { "txt", "csv", "ctd",
"mgf", "msa", "xml" }, "Peak list files");
}
public void initData() {
peaks = new Vector<Peak>();
max_intensity = 0.;
}
public int size() {
return peaks.size();
}
private int putPVT(double _mz, double _int) {
return putPVT(new Peak(_mz, _int));
}
private int putPVT(Peak toadd) {
int ind = 0;
for (ListIterator<Peak> i = peaks.listIterator(); i.hasNext(); ind++) {
Peak p = i.next();
// insert
if (toadd.compareTo(p) < 0) {
i.previous();
i.add(toadd.clone());
return ind;
}
// set
if (toadd.compareTo(p) == 0) {
p.setIntensity(toadd.getIntensity());
return ind;
}
}
// append
peaks.add(toadd.clone());
return ind;
}
/**
* Add a new peak to the list, if a previous peak with the same mass/charge
* value was present, the intensity is updated
*
* @return the index of the new peak or -1 if the peak was <code>null</code>
*/
public int put(double _mz, double _int) {
int ind = putPVT(_mz, _int);
updateMaxIntensity();
fireDocumentChanged();
return ind;
}
/**
* Add a new peak to the list, if a previous peak with the same mass/charge
* value was present, the intensity is updated
*
* @return the index of the new peak or -1 if the peak was <code>null</code>
*/
public int add(Peak p) {
if (p == null)
return -1;
return put(p.getMZ(), p.getIntensity());
}
/**
* Add a collection of peaks to the list
*/
public void addAll(Collection<Peak> _peaks) {
mergeData(_peaks);
}
/**
* Clear the list and add a collection of peaks to it
*/
public void setData(Collection<Peak> _peaks) {
setData(_peaks, true);
}
private void setData(Collection<Peak> _peaks, boolean fire) {
peaks.clear();
max_intensity = 0.;
for (Iterator<Peak> i = _peaks.iterator(); i.hasNext();)
putPVT(i.next());
updateMaxIntensity();
if (fire)
fireDocumentChanged();
}
/**
* Add a collection of peaks to the list
*/
public void mergeData(Collection<Peak> _peaks) {
mergeData(_peaks, true);
}
private void mergeData(Collection<Peak> _peaks, boolean fire) {
for (Iterator<Peak> i = _peaks.iterator(); i.hasNext();)
putPVT(i.next());
updateMaxIntensity();
if (fire)
fireDocumentChanged();
}
private void removePVT(int ind) {
peaks.removeElementAt(ind);
}
/**
* Remove the specified peak from the list
*
* @param ind
* the index of the peak in the list
*/
public void remove(int ind) {
peaks.removeElementAt(ind);
updateMaxIntensity();
fireDocumentChanged();
}
/**
* Remove the specified peaks from the list
*
* @param inds
* the indexes of the peak in the list
*/
public void remove(int[] inds) {
Arrays.sort(inds);
for (int i = 0; i < inds.length; i++){
int corrected=inds[i] - i;
if(corrected!=this.getPeaks().size()){
removePVT(corrected);
}
}
updateMaxIntensity();
fireDocumentChanged();
}
/**
* Remove the specified peak from the list
*
* @param mz
* the mass/charge value of the peak to remove
*/
public void remove(double mz) {
remove(indexOf(mz));
}
/**
* Return the index of a peak in the list
*
* @param mz
* the mass/charge value of the peak
*/
public int indexOf(double mz) {
for (int i = 0; i < size(); i++) {
if (mz < getMZ(i))
return -1;
if (Math.abs(mz - getMZ(i)) < 0.000001)
return i;
}
return -1;
}
/**
* Return all the peaks in the list
*/
public Collection<Peak> getPeaks() {
return peaks;
}
/**
* Return a specified peak from the list
*
* @param ind
* the index of the peak
*/
public Peak getPeak(int ind) {
return peaks.elementAt(ind);
}
/**
* Set the mass/charge value of a peak in the list
*
* @param ind
* the index of the peak
* @param _mz
* the new mass/charge value
*/
public void setMZ(int ind, double _mz) {
Peak peak=this.peaks.get(ind);
Peak clone=new Peak(_mz,peak.getIntensity());
clone.setCharge(peak.getCharge());
removePVT(ind);
putPVT(clone);
updateMaxIntensity();
fireDocumentChanged();
}
public void setCharge(int ind,int charge){
//System.err.println("Charge is: "+charge);
Peak peak=this.peaks.get(ind);
Peak clone=new Peak(peak.getMZ(),peak.getIntensity());
clone.setCharge(charge);
removePVT(ind);
putPVT(clone);
updateMaxIntensity();
fireDocumentChanged();
}
/**
* Return the mass/charge value of a peak in the list
*
* @param ind
* the index of the peak
*/
public double getMZ(int ind) {
return peaks.elementAt(ind).getMZ();
}
/**
* Set the intensity value of a peak in the list
*
* @param ind
* the index of the peak
* @param _int
* the new intensity value
*/
public void setIntensity(int ind, double _int) {
Peak peak=this.peaks.get(ind);
Peak clone=new Peak(peak.getMZ(),_int);
clone.setCharge(peak.getCharge());
removePVT(ind);
putPVT(clone);
updateMaxIntensity();
fireDocumentChanged();
}
/**
* Return the intensity value of a peak in the list
*
* @param ind
* the index of the peak
*/
public double getIntensity(int ind) {
return peaks.elementAt(ind).getIntensity();
}
public int getCharge(int ind){
return peaks.elementAt(ind).getCharge();
}
/**
* Return the intensity value of a peak normalized by the maximum intensity
* in the list
*
* @param ind
* the index of the peak
*/
public double getRelativeIntensity(int ind) {
if (max_intensity == 0.)
return getIntensity(ind);
return getIntensity(ind) / max_intensity * 100;
}
/**
* Return the minimum mass/charge value of the peaks in the list
*/
public double getMinMZ() {
return peaks.firstElement().getMZ();
}
/**
* Return the maximum mass/charge value of the peaks in the list
*/
public double getMaxMZ() {
return peaks.lastElement().getMZ();
}
/**
* Return the range of mass/charge values of the peaks in the list
*/
public Range getMZRange() {
return new Range(getMinMZ(), getMaxMZ());
}
/**
* Return the peaks at the specified positions
*
* @param inds
* the indexes of the peaks
*/
public Collection<Peak> extract(int[] inds) {
Vector<Peak> ret = new Vector<Peak>();
for (int i = 0; i < inds.length; i++)
ret.add(peaks.elementAt(inds[i]).clone());
return ret;
}
/**
* Update the maximum intensity value after a change in the peaks
*/
public void updateMaxIntensity() {
// update max intensity
max_intensity = 0.;
for (Peak p : peaks)
max_intensity = Math.max(max_intensity, p.getIntensity());
}
/**
* Return the maximum intensity value of the peaks in the list
*/
public double getMaxIntensity() {
return max_intensity;
}
/**
* Return the maximum intensity value of the peaks in a specified
* mass/charge range
*
* @param from_mz
* minimum mass/charge value
* @param to_mz
* maximum mass/charge value
*/
public double getMaxIntensity(double from_mz, double to_mz) {
double ret = 0.;
for (Peak p : peaks) {
if (p.getMZ() >= from_mz && p.getMZ() <= to_mz)
ret = Math.max(p.getIntensity(), ret);
}
return ret;
}
/**
* Return the peaks as a 2xN table contain mass/charge and intensity values
*/
public double[][] getData() {
return getData(getMinMZ(), getMaxMZ(), 0., false);
}
/**
* Return the peaks as a 2xN table contain mass/charge and intensity values
*
* @param rel_int
* <code>true</code> if the intensities should be normalized by
* the maximum intensity
*/
public double[][] getData(boolean rel_int) {
return getData(getMinMZ(), getMaxMZ(), 0., rel_int);
}
/**
* Return the peaks as a 2xN table contain mass/charge and intensity values
*
* @param from_mz
* limit the minimum mass/charge value of the peaks
* @param to_mz
* limit the maximum mass/charge value of the peaks
*/
public double[][] getData(double from_mz, double to_mz) {
return getData(from_mz, to_mz, 0., false);
}
/**
* Return the peaks as a 2xN table contain mass/charge and intensity values
*
* @param from_mz
* limit the minimum mass/charge value of the peaks
* @param to_mz
* limit the maximum mass/charge value of the peaks
* @param rel_int
* <code>true</code> if the intensities should be normalized by
* the maximum intensity
*/
public double[][] getData(double from_mz, double to_mz, boolean rel_int) {
return getData(from_mz, to_mz, 0., rel_int);
}
/**
* Return the peaks as a 2xN table contain mass/charge and intensity values
*
* @param from_mz
* limit the minimum mass/charge value of the peaks
* @param to_mz
* limit the maximum mass/charge value of the peaks
* @param add_boundaries
* add two peaks at beginning and end of the table whose
* mass/charge values differs from their neighbours of the
* specified value
* @param rel_int
* <code>true</code> if the intensities should be normalized by
* the maximum intensity
*/
public double[][] getData(double from_mz, double to_mz,
double add_boundaries, boolean rel_int) {
// count peaks
int no_peaks = 0;
for (Peak p : peaks) {
if (p.getMZ() >= from_mz && p.getMZ() <= to_mz)
no_peaks++;
}
// init vectors
int added = (add_boundaries > 0.) ? 2 : 0;
double[][] ret = new double[2][];
ret[0] = new double[no_peaks + added];
ret[1] = new double[no_peaks + added];
// copy peaks
double div = 1.;
if (rel_int)
div = getMaxIntensity(from_mz, to_mz) / 100.;
int i = 0;
for (Peak p : peaks) {
if (p.getMZ() >= from_mz && p.getMZ() <= to_mz) {
ret[0][i + added / 2] = p.getMZ();
ret[1][i + added / 2] = p.getIntensity() / div;
i++;
}
}
// add boundaries
if (add_boundaries > 0.) {
ret[0][0] = ret[0][1] - add_boundaries;
ret[1][0] = 0.;
ret[0][no_peaks + 1] = ret[0][no_peaks] + add_boundaries;
ret[1][no_peaks + 1] = 0.;
}
return ret;
}
private boolean updatePeakPVT(Peak p) {
int ind = indexOf(p.getMZ());
if (ind == -1)
return false;
peaks.get(ind).setIntensity(p.getIntensity());
return true;
}
/**
* Update the intensity of a peak
*
* @param p
* specifies the mass/charge value and the new intensity
*/
public boolean updatePeak(Peak p) {
if (updatePeakPVT(p)) {
updateMaxIntensity();
fireDocumentChanged();
return true;
}
return false;
}
/**
* Update the intensities of a collection of peaks
*
* @param peaks
* specifies the mass/charge values and the new intensities
*/
public boolean updatePeaks(Collection<Peak> peaks) {
boolean changed = false;
for (Peak p : peaks)
changed |= updatePeakPVT(p);
if (changed) {
updateMaxIntensity();
fireDocumentChanged();
}
return changed;
}
// --------------
// Serialization
private String transform(String buffer, String transformer_path)
throws Exception {
TransformerFactory tf = TransformerFactory.newInstance();
StreamSource in_xslt = new StreamSource(PeakList.class.getResource(
transformer_path).toString());
Transformer t = tf.newTransformer(in_xslt);
StreamSource in = new StreamSource(new StringReader(buffer));
StringWriter sw = new StringWriter();
StreamResult out = new StreamResult(sw);
t.transform(in, out);
return sw.getBuffer().toString();
}
@Override
public boolean open(File file, boolean merge, boolean warning) {
System.err.println("In here ?");
try {
System.err.println("1");
// try CSV
if (readCSV(file, merge))
return true;
System.err.println("2");
// try MGF peak list
if (readMGF(file, merge))
return true;
System.err.println("3");
// try MSA peak list
if (readMSA(file, merge))
return true;
System.err.println("4");
// try bruker xml
if (readBruker(file, merge)){
System.err.println("Read bruker");
return true;
}else{
System.err.println("Failed to read bruker?");
}
System.err.println("5");
// bail out
init();
if (warning){
System.err.println("Unrecognized peak list format");
throw new Exception("Unrecognized peak list format");
}
return false;
} catch (Exception e) {
System.err.println("Caught exception");
LogUtils.report(e);
return false;
}
}
private boolean readMGF(File file, boolean merge) {
try {
org.proteomecommons.io.mgf.MascotGenericFormatPeakListReader mgf_reader = new org.proteomecommons.io.mgf.MascotGenericFormatPeakListReader(
file.getPath());
org.proteomecommons.io.Peak[] mgf_peaks = mgf_reader.getPeakList()
.getPeaks();
if (!merge)
clear();
for (int i = 0; i < mgf_peaks.length; i++){
putPVT(mgf_peaks[i]);
}
updateMaxIntensity();
setFilename(file.getAbsolutePath());
fireDocumentInit();
return true;
} catch (Exception e) {
return false;
}
}
private int putPVT(org.proteomecommons.io.Peak peakCommons){
Peak peak=new Peak();
peak.setIntensity(peakCommons.getIntensity());
peak.setMZ(peakCommons.getMassOverCharge());
peak.setCharge(peakCommons.getCharge());
return putPVT(peak);
}
private boolean readCSV(File file, boolean merge) {
try {
FileInputStream fis = new FileInputStream(file);
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
String buffer = consume(br);
// try text peak list
Collection<Peak> read = parseString(buffer);
if (read.size() > 0) {
if (merge)
mergeData(read, false);
else
setData(read, false);
setFilename(file.getAbsolutePath());
fireDocumentInit();
return true;
}
return false;
} catch (Exception e) {
return false;
}
}
private boolean readBruker(File file, boolean merge) {
try {
System.err.println("In bruker read");
FileInputStream fis = new FileInputStream(file);
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
String buffer = consume(br);
String str=transform(buffer,
"/transforms/bruker_peak_list.xsl");
System.err.println(str);
Collection<Peak> read = parseString(transform(buffer,
"/transforms/bruker_peak_list.xsl"));
if (read.size() > 0) {
if (merge)
mergeData(read, false);
else
setData(read, false);
setFilename(file.getAbsolutePath());
fireDocumentInit();
return true;
}
return false;
} catch (Exception e) {
return false;
}
}
private boolean readMSA(File file, boolean merge) {
AnnotatedPeakList read = new AnnotatedPeakList();
if (!read.open(file, merge, false)){
return false;
}
if(read.getPeaks().size()==0){
return false;
}
if (merge)
mergeData(read.getPeaks(), false);
else
setData(read.getPeaks(), false);
setFilename(file.getAbsolutePath());
fireDocumentInit();
return true;
}
/**
* Create a string representation of the peak list where the peaks are
* separated by newlines
*/
public String toString() {
return toString(peaks);
}
/**
* Create a string representation of a collection of peaks where the peaks
* are separated by newlines
*/
static public String toString(Collection<Peak> peaks) {
StringBuilder ret = new StringBuilder();
for (Iterator<Peak> i = peaks.iterator(); i.hasNext();) {
ret.append(i.next());
ret.append("\n");
}
return ret.toString();
}
/**
* Load a list of peaks to the current list from a string representaion of a
* collection of peaks separated by newlines
*
* @param merge
* if <code>false</code> the list is emptied before adding the
* new peaks
*/
public void fromString(String str, boolean merge) throws Exception {
System.err.println("HERE");
if (merge)
mergeData(parseString(str), false);
else
setData(parseString(str), false);
}
/**
* Create a list of peaks from a string representaion of a collection of
* peaks separated by newlines
*/
static public Collection<Peak> parseString(String str) throws Exception {
Vector<Peak> ret = new Vector<Peak>();
String line;
BufferedReader br = new BufferedReader(new StringReader(str));
while ((line = br.readLine()) != null) {
Peak p = Peak.parseString(line);
if (p != null)
ret.add(p);
}
return ret;
}
/**
* Create a new object from its XML representation as part of a DOM tree.
*/
public void fromXML(Node pl_node, boolean merge) throws Exception {
// clear
if (!merge) {
resetStatus();
initData();
} else
setChanged(true);
// read
Vector<Node> p_nodes = XMLUtils.findAllChildren(pl_node, "Peak");
for (Node p_node : p_nodes) {
Peak p = Peak.fromXML(p_node);
putPVT(p);
}
updateMaxIntensity();
}
/**
* Create an XML representation of this object to be part of a DOM tree.
*/
public Element toXML(Document document) {
if (document == null)
return null;
// create root node
Element pl_node = document.createElement("PeakList");
if (pl_node == null)
return null;
// add peaks
for (Peak p : peaks) {
Element p_node = p.toXML(document);
if (p_node != null)
pl_node.appendChild(p_node);
}
return pl_node;
}
/**
* Default SAX handler to read a representation of this object from an XML
* stream.
*/
public static class SAXHandler extends SAXUtils.ObjectTreeHandler {
private PeakList theDocument;
private boolean merge;
public SAXHandler(PeakList _doc, boolean _merge) {
theDocument = _doc;
merge = _merge;
}
public boolean isElement(String namespaceURI, String localName,
String qName) {
return qName.equals(getNodeElementName());
}
public static String getNodeElementName() {
return "PeakList";
}
protected SAXUtils.ObjectTreeHandler getHandler(String namespaceURI,
String localName, String qName) {
if (qName.equals(Peak.SAXHandler.getNodeElementName()))
return new Peak.SAXHandler();
return null;
}
protected Object finalizeContent(String namespaceURI, String localName,
String qName) throws SAXException {
// clear
if (!merge) {
theDocument.resetStatus();
theDocument.initData();
} else
theDocument.setChanged(true);
// read data
for (Object o : getSubObjects(Peak.SAXHandler.getNodeElementName()))
theDocument.putPVT((Peak)o);
theDocument.updateMaxIntensity();
return (object = theDocument);
}
}
public void write(TransformerHandler th) throws SAXException {
th.startElement("", "", "PeakList", new AttributesImpl());
for (Peak p : peaks)
p.write(th);
th.endElement("", "", "PeakList");
}
}