diff templates/spectrum_gen.js @ 0:cce6989ed423

new NIST wrapper demo tools
author pieter.lukasse@wur.nl
date Thu, 22 Jan 2015 16:14:57 +0100
parents
children 82368bd06e1d
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/spectrum_gen.js	Thu Jan 22 16:14:57 2015 +0100
@@ -0,0 +1,277 @@
+function getMax(values)
+{
+	var result = 0;
+	for (var i = 0; i < values.length; i++)
+	{
+		if (values[i] > result)
+			result = values[i];
+	}
+	return result;
+}
+
+/**
+ * This function will first convert the spectrum mass and intensities list in MSP format
+ * to the internal lists needed by renderSpectrum function.
+ * 
+ * @param spectrumMSPString : list of masses and intensities in the following format:
+ *  e.g. :  "14 8; 15 15; 27 18; 28 15; 29 15; 30 11; 32 19; 39 32; 40 12; 41 68;"
+ */
+function renderSpectrumFromMSPString(spectrumMSPString, targetElement)
+{
+	var spectrum1 = getSpectrumObjectFromMSPString(spectrumMSPString);	
+	renderSpectrum(spectrum1, null,targetElement);
+}
+
+function endsWith(str, suffix) {
+    return str.indexOf(suffix, str.length - suffix.length) !== -1;
+}
+
+function getSpectrumObjectFromCouplesString(spectrumCouplesString, couplesSeparator, massAndIntensitySeparator)
+{
+	var couples = spectrumCouplesString.split(couplesSeparator);
+	var masses = new Array();
+	var intensities = new Array();
+	for (var i = 0; i < couples.length; i++)
+	{
+		var couple = couples[i].trim().split(massAndIntensitySeparator)
+		var mass = parseInt(couple[0])
+		var intensity = parseInt(couple[1])
+		masses.push(mass);
+		intensities.push(intensity);
+	}
+	var spectrum1 = new Object();
+	spectrum1.masses = masses;
+	spectrum1.intensities = intensities;
+	return spectrum1;
+}
+
+function getSpectrumObjectFromMSPString(spectrumMSPString)
+{
+	spectrumMSPString = spectrumMSPString.trim();
+	if (endsWith(spectrumMSPString, ";"))
+		spectrumMSPString = spectrumMSPString.substring(0, spectrumMSPString.length - 1);
+	return getSpectrumObjectFromCouplesString(spectrumMSPString, ';', ' ');
+}
+
+
+function getSpectrumObjectFromJCAMPString(spectrumJCAMPString)
+{
+	var spectrum = getSpectrumObjectFromCouplesString(spectrumJCAMPString, ' ', ',');
+	for (var i = 0; i < spectrum.intensities.length; i++)
+		spectrum.intensities[i] = spectrum.intensities[i]/10;
+	return spectrum;
+}
+
+/**
+ * This function will render a comparison spectrum comparable to 
+ * the NIST "head to tail" visualization to compare the measured spectrum 
+ * with the matched library spectrum. 
+ * 
+ * NB: One important detail in this function 
+ * is that the library spectrum is not available in NIST output, so 
+ * its representative is retrieved from NIST's webbook website in this case.
+ * (e.g. http://webbook.nist.gov/cgi/cbook.cgi?JCAMP=C537268&Index=0&Type=Mass
+ *  for casNr = "C537268" ) 
+ * 
+ * 
+ * @param spectrumMSPString
+ * @param casNr
+ * @param targetElement
+ */
+function renderComparisonSpectrum(spectrumMSPString, casNr, targetElement)
+{
+	var peakTable;
+	try
+	{
+		//remove dashes:
+		casNr = casNr.replace("-", "");
+		peakTable = httpGet2("/nist_controller/get_nistdata?casnr="+casNr);
+		
+	}
+	catch(e)
+	{
+		//assume running locally:
+		alert("Error while trying to get data from NIST. Rendering library spectrum with dummy data.");
+		peakTable = "55,290 56,240 57,100 58,80"+
+					" 63,30 65,150 66,50 67,1271"+
+					" 68,370 69,100 70,210 71,10"+
+					" 74,50 75,60 76,120 77,2312"+
+					" 78,220 79,120 80,190 81,630"+
+					" 82,4884 83,2702 84,240 85,20"+
+					" 91,180 92,50 93,210 94,3353"+
+					" 95,1371 96,1261 97,370 98,120"+
+					" 105,1621 106,160 107,70 108,220"+
+					" 109,80 110,60 111,30 112,40"+
+					" 121,30 122,460 123,940 124,9999";
+		//note that the intensities in jcamp response are 10x when compared to MSP format
+	}
+	var spectrum1 = getSpectrumObjectFromMSPString(spectrumMSPString);
+	var spectrum2 = getSpectrumObjectFromJCAMPString(peakTable);
+	renderSpectrum(spectrum1, spectrum2,targetElement);	
+}
+
+function httpGet2(theUrl)
+{
+    //Tried many options: the solution was to add a new service to our
+	//Galaxy server to act as a proxy to the NIST site and then retrieve the data.
+	
+	//way of working: added a new controller to 
+	// /home/lukas007/galaxy-dist/lib/galaxy/webapps/galaxy/controllers
+	// which gives the service "/nist_controller/get_nistdata?casnr=<casnr>"
+	
+	var xmlHttp = null;
+
+    xmlHttp = new XMLHttpRequest();
+    xmlHttp.open( "GET", theUrl, false );
+    xmlHttp.send( null );
+    return xmlHttp.responseText;
+}
+
+
+
+/**
+ * This function will ensure only the local highest peaks get a label 
+ * to make the spectrum more readable and avoid all the overlapping labels
+ * of minor peaks. 
+ * 
+ * @param spectrum
+ */
+function getSpectrumLabels(spectrum)
+{
+	//TODO - improve logic to include more labels when area of peaks is sparse enough.
+	//for now we let all labels, keep only the ones where intensity > 100:
+	//and leave the largest/last mass as well:
+	var result = new Array();
+	for (var i = 0; i < spectrum.masses.length; i++)
+	{
+		if (spectrum.intensities[i] > 100 || i == spectrum.masses.length-1)
+			result.push(spectrum.masses[i]);
+		else
+			result.push("");
+	}
+	return result;
+}
+
+function renderSpectrum(spectrum1, spectrum2, targetElement)
+{
+	var maxMassSpectrum1 = getMax(spectrum1.masses);
+	var maxX = maxMassSpectrum1;
+	spectrum1.labels = getSpectrumLabels(spectrum1)
+	var maxMassSpectrum2 = 0;
+	if (spectrum2 != null)
+	{
+		maxMassSpectrum2 = getMax(spectrum2.masses);
+		if (maxMassSpectrum2 > maxMassSpectrum1)
+			maxX = maxMassSpectrum2;
+		spectrum2.labels = getSpectrumLabels(spectrum2)
+	}
+	maxX += 20;
+	
+	var margin = {top: 80, right: 80, bottom: 80, left: 80};
+	//var width = maxX*2 - margin.left - margin.right;
+	//fixed width is better:
+	var width = 600 - margin.left - margin.right;
+	var zoomFactor = 1;
+	
+	var height;
+	//if (spectrum2 != null)
+		//height = 800 - margin.top - margin.bottom;
+	//else
+		height = 400 - margin.top - margin.bottom;
+		
+	//var x = d3.scale.ordinal()
+	  // .rangeRoundBands([0, width], .1);
+	
+	var x = d3.scale.linear().domain([0, maxX]).range([0, width]);
+	
+	var y0 = d3.scale.linear().domain([300, 1100]).range([height, 0]);
+	
+	var xAxis = d3.svg.axis()
+	    .scale(x)
+	    .orient("center");
+	
+	// create left yAxis
+	var yAxisLeft = d3.svg.axis().scale(y0).ticks(4).orient("left");
+	
+	
+	var svg = d3.select(targetElement).append("svg")
+	    .attr("width", width + margin.left + margin.right)
+	    .attr("height", height + margin.top + margin.bottom)
+	  .append("g")
+	    .attr("class", "graph")
+	    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
+	
+	
+	 //x.domain([0,10,500]);
+	 if (spectrum2 != null)
+	 {
+	 	y0.domain([-999, 999]);
+	 }
+	 else
+ 	 {
+		y0.domain([0, 999]);
+ 	 }
+	 svg.append("g")
+     .attr("class", "x axis")
+   	 .append("line")
+     .attr("y1", y0(0))
+     .attr("y2", y0(0))
+     .attr("x2", width);
+	 
+	 svg.append("g")
+	  .attr("class", "y axis axisLeft")
+	  .attr("transform", "translate(0,0)")
+	  .call(yAxisLeft)
+	.append("text")
+	  .attr("y", 6)
+	  .attr("dy", "-2em")
+	  .style("text-anchor", "end")
+	  .text("Relative Intensity");
+	
+
+	 
+	//for each mass in spectrum 1, generate bar:
+	for (var i = 0; i < spectrum1.masses.length; i++)
+	{
+		var heightFactor = 1;
+		if (spectrum2 != null)
+			heightFactor = 2;
+		
+		svg.append("rect")
+		     .attr("class", "bar1")
+		     .attr("x", x(spectrum1.masses[i]*zoomFactor))
+		     .attr("width", 1)
+		     .attr("y", y0(spectrum1.intensities[i]))
+		 	 .attr("height", height/heightFactor - y0(spectrum1.intensities[i]));
+		svg.append("text")
+		  .attr("x", x(spectrum1.masses[i]*zoomFactor))
+		  .attr("y", y0(spectrum1.intensities[i]))
+		  .attr("dy", "-1em")
+		  .attr("dx", "-1em")
+		  .style("text-anchor", "start")
+		  .text(spectrum1.labels[i]);
+	}
+	
+	if (spectrum2 != null)
+	{
+		for (var i = 0; i < spectrum2.masses.length; i++)
+		{
+			heightFactor = 2;
+			
+			svg.append("rect")
+			     .attr("class", "bar2")
+			     .attr("x", x(spectrum2.masses[i]*zoomFactor))
+			     .attr("width", 1)
+			     .attr("y", y0(0))
+			 	 .attr("height", height/heightFactor - y0(spectrum2.intensities[i]));
+			svg.append("text")
+			  .attr("x", x(spectrum2.masses[i]*zoomFactor))
+			  .attr("y", y0(-spectrum2.intensities[i]))
+			  .attr("dy", "1.5em")
+			  .attr("dx", "-1em")
+			  .style("text-anchor", "start")
+			  .text(spectrum2.labels[i]);
+		}
+	}
+
+}