0
|
1 function getMax(values)
|
|
2 {
|
|
3 var result = 0;
|
|
4 for (var i = 0; i < values.length; i++)
|
|
5 {
|
|
6 if (values[i] > result)
|
|
7 result = values[i];
|
|
8 }
|
|
9 return result;
|
|
10 }
|
|
11
|
|
12 /**
|
|
13 * This function will first convert the spectrum mass and intensities list in MSP format
|
|
14 * to the internal lists needed by renderSpectrum function.
|
|
15 *
|
|
16 * @param spectrumMSPString : list of masses and intensities in the following format:
|
|
17 * e.g. : "14 8; 15 15; 27 18; 28 15; 29 15; 30 11; 32 19; 39 32; 40 12; 41 68;"
|
|
18 */
|
|
19 function renderSpectrumFromMSPString(spectrumMSPString, targetElement)
|
|
20 {
|
|
21 var spectrum1 = getSpectrumObjectFromMSPString(spectrumMSPString);
|
|
22 renderSpectrum(spectrum1, null,targetElement);
|
|
23 }
|
|
24
|
|
25 function endsWith(str, suffix) {
|
|
26 return str.indexOf(suffix, str.length - suffix.length) !== -1;
|
|
27 }
|
|
28
|
|
29 function getSpectrumObjectFromCouplesString(spectrumCouplesString, couplesSeparator, massAndIntensitySeparator)
|
|
30 {
|
|
31 var couples = spectrumCouplesString.split(couplesSeparator);
|
|
32 var masses = new Array();
|
|
33 var intensities = new Array();
|
|
34 for (var i = 0; i < couples.length; i++)
|
|
35 {
|
|
36 var couple = couples[i].trim().split(massAndIntensitySeparator)
|
|
37 var mass = parseInt(couple[0])
|
|
38 var intensity = parseInt(couple[1])
|
|
39 masses.push(mass);
|
|
40 intensities.push(intensity);
|
|
41 }
|
|
42 var spectrum1 = new Object();
|
|
43 spectrum1.masses = masses;
|
|
44 spectrum1.intensities = intensities;
|
|
45 return spectrum1;
|
|
46 }
|
|
47
|
|
48 function getSpectrumObjectFromMSPString(spectrumMSPString)
|
|
49 {
|
|
50 spectrumMSPString = spectrumMSPString.trim();
|
|
51 if (endsWith(spectrumMSPString, ";"))
|
|
52 spectrumMSPString = spectrumMSPString.substring(0, spectrumMSPString.length - 1);
|
|
53 return getSpectrumObjectFromCouplesString(spectrumMSPString, ';', ' ');
|
|
54 }
|
|
55
|
|
56
|
|
57 function getSpectrumObjectFromJCAMPString(spectrumJCAMPString)
|
|
58 {
|
|
59 var spectrum = getSpectrumObjectFromCouplesString(spectrumJCAMPString, ' ', ',');
|
|
60 for (var i = 0; i < spectrum.intensities.length; i++)
|
|
61 spectrum.intensities[i] = spectrum.intensities[i]/10;
|
|
62 return spectrum;
|
|
63 }
|
|
64
|
|
65 /**
|
|
66 * This function will render a comparison spectrum comparable to
|
|
67 * the NIST "head to tail" visualization to compare the measured spectrum
|
|
68 * with the matched library spectrum.
|
|
69 *
|
|
70 * NB: One important detail in this function
|
|
71 * is that the library spectrum is not available in NIST output, so
|
|
72 * its representative is retrieved from NIST's webbook website in this case.
|
|
73 * (e.g. http://webbook.nist.gov/cgi/cbook.cgi?JCAMP=C537268&Index=0&Type=Mass
|
|
74 * for casNr = "C537268" )
|
|
75 *
|
|
76 *
|
|
77 * @param spectrumMSPString
|
|
78 * @param casNr
|
|
79 * @param targetElement
|
|
80 */
|
|
81 function renderComparisonSpectrum(spectrumMSPString, casNr, targetElement)
|
|
82 {
|
|
83 var peakTable;
|
|
84 try
|
|
85 {
|
|
86 //remove dashes:
|
|
87 casNr = casNr.replace("-", "");
|
|
88 peakTable = httpGet2("/nist_controller/get_nistdata?casnr="+casNr);
|
|
89
|
|
90 }
|
|
91 catch(e)
|
|
92 {
|
17
|
93 try
|
|
94 {
|
|
95 //workaround for galaxy.wur.nl/galaxy_production/ scenario TODO: make more robust code:
|
|
96 peakTable = httpGet2("/galaxy_production/nist_controller/get_nistdata?casnr="+casNr);
|
|
97 }
|
|
98 catch(e2)
|
|
99 {
|
|
100 //assume running locally:
|
|
101 alert("Error while trying to get data from NIST. Rendering library spectrum with dummy data.");
|
|
102 peakTable = "55,290 56,240 57,100 58,80"+
|
|
103 " 63,30 65,150 66,50 67,1271"+
|
|
104 " 68,370 69,100 70,210 71,10"+
|
|
105 " 74,50 75,60 76,120 77,2312"+
|
|
106 " 78,220 79,120 80,190 81,630"+
|
|
107 " 82,4884 83,2702 84,240 85,20"+
|
|
108 " 91,180 92,50 93,210 94,3353"+
|
|
109 " 95,1371 96,1261 97,370 98,120"+
|
|
110 " 105,1621 106,160 107,70 108,220"+
|
|
111 " 109,80 110,60 111,30 112,40"+
|
|
112 " 121,30 122,460 123,940 124,9999";
|
|
113 //note that the intensities in jcamp response are 10x when compared to MSP format
|
|
114 }
|
0
|
115 }
|
|
116 var spectrum1 = getSpectrumObjectFromMSPString(spectrumMSPString);
|
|
117 var spectrum2 = getSpectrumObjectFromJCAMPString(peakTable);
|
|
118 renderSpectrum(spectrum1, spectrum2,targetElement);
|
|
119 }
|
|
120
|
|
121 function httpGet2(theUrl)
|
|
122 {
|
|
123 //Tried many options: the solution was to add a new service to our
|
|
124 //Galaxy server to act as a proxy to the NIST site and then retrieve the data.
|
|
125
|
|
126 //way of working: added a new controller to
|
|
127 // /home/lukas007/galaxy-dist/lib/galaxy/webapps/galaxy/controllers
|
|
128 // which gives the service "/nist_controller/get_nistdata?casnr=<casnr>"
|
|
129
|
|
130 var xmlHttp = null;
|
|
131
|
|
132 xmlHttp = new XMLHttpRequest();
|
|
133 xmlHttp.open( "GET", theUrl, false );
|
|
134 xmlHttp.send( null );
|
17
|
135 if (xmlHttp.status == 404)
|
|
136 throw new Exception("Error while trying to access the data: " + xmlHttp.statusText)
|
0
|
137 return xmlHttp.responseText;
|
|
138 }
|
|
139
|
|
140
|
|
141
|
|
142 /**
|
|
143 * This function will ensure only the local highest peaks get a label
|
|
144 * to make the spectrum more readable and avoid all the overlapping labels
|
|
145 * of minor peaks.
|
|
146 *
|
|
147 * @param spectrum
|
|
148 */
|
|
149 function getSpectrumLabels(spectrum)
|
|
150 {
|
|
151 //TODO - improve logic to include more labels when area of peaks is sparse enough.
|
|
152 //for now we let all labels, keep only the ones where intensity > 100:
|
|
153 //and leave the largest/last mass as well:
|
|
154 var result = new Array();
|
|
155 for (var i = 0; i < spectrum.masses.length; i++)
|
|
156 {
|
|
157 if (spectrum.intensities[i] > 100 || i == spectrum.masses.length-1)
|
|
158 result.push(spectrum.masses[i]);
|
|
159 else
|
|
160 result.push("");
|
|
161 }
|
|
162 return result;
|
|
163 }
|
|
164
|
|
165 function renderSpectrum(spectrum1, spectrum2, targetElement)
|
|
166 {
|
|
167 var maxMassSpectrum1 = getMax(spectrum1.masses);
|
|
168 var maxX = maxMassSpectrum1;
|
|
169 spectrum1.labels = getSpectrumLabels(spectrum1)
|
|
170 var maxMassSpectrum2 = 0;
|
|
171 if (spectrum2 != null)
|
|
172 {
|
|
173 maxMassSpectrum2 = getMax(spectrum2.masses);
|
|
174 if (maxMassSpectrum2 > maxMassSpectrum1)
|
|
175 maxX = maxMassSpectrum2;
|
|
176 spectrum2.labels = getSpectrumLabels(spectrum2)
|
|
177 }
|
|
178 maxX += 20;
|
|
179
|
|
180 var margin = {top: 80, right: 80, bottom: 80, left: 80};
|
|
181 //var width = maxX*2 - margin.left - margin.right;
|
|
182 //fixed width is better:
|
|
183 var width = 600 - margin.left - margin.right;
|
|
184 var zoomFactor = 1;
|
|
185
|
|
186 var height;
|
|
187 //if (spectrum2 != null)
|
|
188 //height = 800 - margin.top - margin.bottom;
|
|
189 //else
|
|
190 height = 400 - margin.top - margin.bottom;
|
|
191
|
|
192 //var x = d3.scale.ordinal()
|
|
193 // .rangeRoundBands([0, width], .1);
|
|
194
|
|
195 var x = d3.scale.linear().domain([0, maxX]).range([0, width]);
|
|
196
|
|
197 var y0 = d3.scale.linear().domain([300, 1100]).range([height, 0]);
|
|
198
|
|
199 var xAxis = d3.svg.axis()
|
|
200 .scale(x)
|
|
201 .orient("center");
|
|
202
|
|
203 // create left yAxis
|
|
204 var yAxisLeft = d3.svg.axis().scale(y0).ticks(4).orient("left");
|
|
205
|
|
206
|
|
207 var svg = d3.select(targetElement).append("svg")
|
|
208 .attr("width", width + margin.left + margin.right)
|
|
209 .attr("height", height + margin.top + margin.bottom)
|
|
210 .append("g")
|
|
211 .attr("class", "graph")
|
|
212 .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
|
|
213
|
|
214
|
|
215 //x.domain([0,10,500]);
|
|
216 if (spectrum2 != null)
|
|
217 {
|
|
218 y0.domain([-999, 999]);
|
|
219 }
|
|
220 else
|
|
221 {
|
|
222 y0.domain([0, 999]);
|
|
223 }
|
|
224 svg.append("g")
|
|
225 .attr("class", "x axis")
|
|
226 .append("line")
|
|
227 .attr("y1", y0(0))
|
|
228 .attr("y2", y0(0))
|
|
229 .attr("x2", width);
|
|
230
|
|
231 svg.append("g")
|
|
232 .attr("class", "y axis axisLeft")
|
|
233 .attr("transform", "translate(0,0)")
|
|
234 .call(yAxisLeft)
|
|
235 .append("text")
|
|
236 .attr("y", 6)
|
|
237 .attr("dy", "-2em")
|
|
238 .style("text-anchor", "end")
|
|
239 .text("Relative Intensity");
|
|
240
|
|
241
|
|
242
|
|
243 //for each mass in spectrum 1, generate bar:
|
|
244 for (var i = 0; i < spectrum1.masses.length; i++)
|
|
245 {
|
|
246 var heightFactor = 1;
|
|
247 if (spectrum2 != null)
|
|
248 heightFactor = 2;
|
|
249
|
|
250 svg.append("rect")
|
|
251 .attr("class", "bar1")
|
|
252 .attr("x", x(spectrum1.masses[i]*zoomFactor))
|
|
253 .attr("width", 1)
|
|
254 .attr("y", y0(spectrum1.intensities[i]))
|
|
255 .attr("height", height/heightFactor - y0(spectrum1.intensities[i]));
|
|
256 svg.append("text")
|
|
257 .attr("x", x(spectrum1.masses[i]*zoomFactor))
|
|
258 .attr("y", y0(spectrum1.intensities[i]))
|
|
259 .attr("dy", "-1em")
|
|
260 .attr("dx", "-1em")
|
|
261 .style("text-anchor", "start")
|
|
262 .text(spectrum1.labels[i]);
|
|
263 }
|
|
264
|
|
265 if (spectrum2 != null)
|
|
266 {
|
|
267 for (var i = 0; i < spectrum2.masses.length; i++)
|
|
268 {
|
|
269 heightFactor = 2;
|
|
270
|
|
271 svg.append("rect")
|
|
272 .attr("class", "bar2")
|
|
273 .attr("x", x(spectrum2.masses[i]*zoomFactor))
|
|
274 .attr("width", 1)
|
|
275 .attr("y", y0(0))
|
|
276 .attr("height", height/heightFactor - y0(spectrum2.intensities[i]));
|
|
277 svg.append("text")
|
|
278 .attr("x", x(spectrum2.masses[i]*zoomFactor))
|
|
279 .attr("y", y0(-spectrum2.intensities[i]))
|
|
280 .attr("dy", "1.5em")
|
|
281 .attr("dx", "-1em")
|
|
282 .style("text-anchor", "start")
|
|
283 .text(spectrum2.labels[i]);
|
|
284 }
|
|
285 }
|
|
286
|
|
287 }
|