libpappsomspp
Library for mass spectrometry
Loading...
Searching...
No Matches
massspectraceplotwidget.cpp
Go to the documentation of this file.
1/* This code comes right from the msXpertSuite software project.
2 *
3 * msXpertSuite - mass spectrometry software suite
4 * -----------------------------------------------
5 * Copyright(C) 2009,...,2018 Filippo Rusconi
6 *
7 * http://www.msxpertsuite.org
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 *
22 * END software license
23 */
24
25
26/////////////////////// StdLib includes
27#include <vector>
28
29
30/////////////////////// Qt includes
31#include <QVector>
32
33
34/////////////////////// Local includes
35
36// For the proton mass
37#include "../../types.h"
38
41
42
44 qRegisterMetaType<pappso::MassSpecTracePlotContext>(
45 "pappso::MassSpecTracePlotContext");
46
48 qRegisterMetaType<pappso::MassSpecTracePlotContext *>(
49 "pappso::MassSpecTracePlotContext *");
50
51
52namespace pappso
53{
54
56 : BaseTracePlotWidget(parent)
57{
60
61 // qDebug() << "Data kind:" << static_cast<int>(m_context.m_dataKind);
62}
63
65 const QString &x_axis_label,
66 const QString &y_axis_label)
67 : BaseTracePlotWidget(parent, x_axis_label, y_axis_label)
68{
69 // Set the base context to be of kind DataKind::mz;
70
73
74 // qDebug() << "Data kind:" << static_cast<int>(m_context.m_dataKind);
75}
76
77
81
82
83//! Set the \c m_pressedKeyCode to the key code in \p event.
84void
86{
87 // qDebug() << "ENTER";
89
90 // Before working on the various data belonging to the base context, we need
91 // to get it from the base class and refresh our local context with it.
93
94 // qDebug() << "Going to emit keyPressEventSignal(m_context);";
95
97}
98
99
100//! Handle specific key codes and trigger respective actions.
101void
103{
104 // Before working on the various data belonging to the base context, we need
105 // to get it from the base class and refresh our local context with it.
107
109}
110
111
112//! Handle mouse movements, in particular record all the last visited points.
113/*!
114
115 This function is reponsible for storing at each time the last visited point
116 in the graph. Here, point is intended as any x/y coordinate in the plot
117 widget viewport, not a graph point.
118
119 The stored values are then the basis for a large set of calculations
120 throughout all the plot widget.
121
122 \param pointer to QMouseEvent from which to retrieve the coordinates of the
123 visited viewport points.
124 */
125void
127{
128 // Before working on the various data belonging to the base context, we need
129 // to get it from the base class and refresh our local context with it.
131
133}
134
135
136void
138{
139 // Before working on the various data belonging to the base context, we need
140 // to get it from the base class and refresh our local context with it.
142
144}
145
146
147void
149{
151
152 // Before working on the various data belonging to the base context, we need
153 // to get it from the base class and refresh our local context with it.
155
156 if(m_context.m_mouseButtonsAtMousePress & Qt::LeftButton)
157 {
159 return;
160
161 // qDebug() << "lastMovingMouseButtons:"
162 //<< m_context.m_baseContext.m_lastMovingMouseButtons;
163
164 deconvolute();
166 }
167}
168
169
170//! Record the clicks of the mouse.
171void
173{
174 // Before working on the various data belonging to the base context, we need
175 // to get it from the base class and refresh our local context with it.
177
179}
180
181
182//! React to the release of the mouse buttons.
183void
185{
186 // Before working on the various data belonging to the base context, we need
187 // to get it from the base class and refresh our local context with it.
189
191}
192
193
196{
197 // BasePlotWidget has a member m_context of type BasePlotContext.
198 // Here we also have a m_context *distinct* member that is of type
199 // MassSpecTracePlotContext.
200
201 // While MassSpecTracePlotContext is derived from BasePlotContext, the two
202 // m_context members are distinct and there are lots of housekeeping data that
203 // are managed by the parent BasePlotWidget class in its m_context member
204 // *independently* of what we have in the ::BasePlotContext part of our
205 // m_context member that is of type MassSpecTracePlotContext. We thus need to
206 // resynchronize the data from BasePlotWidget::m_context to our m_context.
207
208 // qDebug().noquote() << "The base plot context:" <<
209 // BasePlotWidget::m_context.toString();
210
212
213 // qDebug().noquote() << "After refreshing the base context, base context:"
214 // << m_context.toString();
215
216 return m_context;
217}
218
219
220void
222 double charge_fractional_part)
223{
224 m_chargeMinimalFractionalPart = charge_fractional_part;
225}
226
227
228double
233
234
235void
240
241
242int
247
248
249//! Deconvolute the mass peaks into charge and molecular mass.
250bool
252{
253
254 // There are two situations: when the user is deconvoluting on the
255 // basis of the distance between two consecutive peaks of a same
256 // isotopic cluster or when the user deconvolutes on the basis of two
257 // different charged-stated peaks that belong to the same envelope.
258
259 // We can tell the difference because in the first case the xDelta
260 // should be less than 1. In the other case, of course the difference
261 // is much greater than 1.
262
263 // In order to do the deconvolutions, we need to know what is the tolerance
264 // on the fractional part of the deconvoluted charge value. This value is set
265 // in the parent window's double spin box.
266
267 if(fabs(m_context.m_xDelta) >= 0 && fabs(m_context.m_xDelta) <= 1.1)
268 {
269 // qDebug() << "m_xDelta:" << m_context.m_xDelta
270 //<< "trying isotope-based deconvolution.";
271
273 }
274
275 // If not deconvoluting on the basis of the isotopic cluster, then:
276
278}
279
280
281//! Deconvolute the mass peaks into charge and molecular mass.
282/*!
283
284 This is one of two methods to deconvolute mass data into a charge value and
285 a Mr value. The method implemented in this function is based on the charge
286 state envelope offered by the mass spectrum (most often for polymers of a
287 reasonable size).
288
289 \param span value representing the number of peaks of the charge state
290 envelope that are spanned by the user selection. Defaults to 1, that is, the
291 span encompasses two \e consecutive mass peaks of a given charge state
292 envelope.
293
294 Set m_lastMz, m_lastZ and m_lastMass.
295
296 \return true if the deconvolution could be performed, false otherwise.
297 */
298bool
300{
301 // We assume that we are dealing with two successive (if span is 1) mass
302 // peaks belonging to a given charge state family.
303
304 // We call span the number of intervals in a given charge state envelope
305 // that separate the initial peak (lowerMz) from the last peak (upperMz).
306 // That parameter defaults to 1, that is the two peaks are immediately
307 // consecutive, that is, there is only one interval.
308
309 // We use the m_contex.basecontext.m_xRegionRange structure that is unsorted.
310 // That is, lower is the start drag point.x and upper is the current drag
311 // point.x. If dragging occurs from left to right, start.x < cur.x.
312 // We use the unsorted values, because we need to know in which direction
313 // the user has drug the mouse, because we want to provide the Mr value
314 // for the peak currently under the mouse cursor, that is under
315 // currentDragPoint, that is the value in
316 // m_context.m_baseContext.m_xRegionRange.upper.
317
318 double startMz = m_context.m_xRegionRangeStart;
319 double curMz = m_context.m_xRegionRangeEnd;
320
321 // qDebug() << "startMz:" << startMz << "curMz:" << curMz;
322
323 if(startMz == curMz)
324 {
325 m_context.m_lastZ = -1;
326 m_context.m_lastMz = std::numeric_limits<double>::min();
327 m_context.m_lastTicIntensity = std::numeric_limits<double>::min();
328 m_context.m_lastMr = std::numeric_limits<double>::min();
329
330 return false;
331 }
332
333 // We need to be aware that the status bar of the window that contains
334 // this plot widget shows the cursor position realtime, and that cursor
335 // position is the m_currentDragPoint.x value, that is, curMz. Thus, we need
336 // to make the calculations with the charge being the one of the polymer under
337 // the cursor position. This is tricky because it changes when the user
338 // switches drag senses: from left to right and right to left.
339 // The way z is calculated always makes it the charge of the highest mz
340 // value. So knowing this, depending on the drag direction we'll have to take
341 // curMz and apply to it either z charge (left to right drag) or (z+span)
342 // charge (right to left).
343
344 // Make sure lower is actually lower, even if drag is from right to left.
345 // This is only to have a single charge calculation.
346 double lowerMz;
347 double upperMz;
348
349 if(startMz < curMz)
350 {
351 lowerMz = startMz;
352 upperMz = curMz;
353 }
354 else
355 {
356 lowerMz = curMz;
357 upperMz = startMz;
358 }
359
360 double chargeTemp = ((lowerMz * span) - span) / (upperMz - lowerMz);
361
362 // Make a judicious roundup.
363
364 double chargeIntPart;
365 double chargeFracPart = modf(chargeTemp, &chargeIntPart);
366
367 // When calculating the charge of the ion, very rarely does it provide a
368 // perfect integer value. Most often (if deconvolution is for bona fide
369 // peaks belonging to the same charge state envelope) that value is with
370 // either a large fractional part or a very small fractional part. What we
371 // test here, it that fractional part. If it is greater than
372 // m_chargeMinimalFractionalPart, then we simply round up to the next integer
373 // value (that is, chargeIntPart = 27 and chargeFracPart 0.995, then we
374 // set charge to 28). If it is lesser or equal to (1 -
375 // m_chargeMinimalFractionalPart /* that is >= 0.01 */, then we let
376 // chargeIntPart unmodified (that is, chargeIntPart = 29 and
377 // chargeFracPart 0.01, then we set charge to 29). If chargeFracPart is in
378 // between (1 - m_chargeMinimalFractionalPart) and
379 // m_chargeMinimalFractionalPart, then we consider that the peaks do not
380 // belong to the same charge state envelope.
381
382 // qDebug() << __FILE__ << __LINE__ << __FUNCTION__
383 //<< "Charge:" << chargeIntPart
384 //<< "Charge fractional part: " << chargeFracPart;
385
386
387 if(chargeFracPart >=
388 (1 - m_chargeMinimalFractionalPart /* that is >= 0.01 */) &&
389 chargeFracPart <= m_chargeMinimalFractionalPart /* that is <= 0.99 */)
390 {
391 m_context.m_lastZ = -1;
392 m_context.m_lastMz = std::numeric_limits<double>::min();
393 m_context.m_lastTicIntensity = std::numeric_limits<double>::min();
394 m_context.m_lastMr = std::numeric_limits<double>::min();
395
396 // qDebug() << "Not a charge state family peak,"
397 //<< "returning from deconvoluteChargeState";
398
399 return false;
400 }
401
402 if(chargeFracPart > m_chargeMinimalFractionalPart)
403 m_context.m_lastZ = chargeIntPart + 1;
404 else
405 m_context.m_lastZ = chargeIntPart;
406
407 // Now, to actually compute the molecular mass based on the charge and on
408 // the currently displayed m/z value, we need to have some thinking:
409
410 if(startMz < curMz)
411 {
412 // The drag was from left to right, that is curMz is greater than
413 // startMz. Fine, the z value is effectively the charge of the ion at
414 // curMz. Easy, no charge value modification here.
415 }
416 else
417 {
418 // The drag was from right to left, that is curMz is less than startMz.
419 // So we want to show the charge of the curMz, that is, z + span.
421 }
422
423 m_context.m_lastMz = curMz;
426
427 // qDebug() << "startMz:" << QString("%1").arg(startMz, 0, 'f', 6)
428 //<< "m_lastMz (curMz):"
429 //<< QString("%1").arg(m_context.m_lastMz, 0, 'f', 6)
430 //<< "m_lastMass:" << QString("%1").arg(m_context.m_lastMr, 0, 'f', 6)
431 //<< "m_lastZ:" << QString("%1").arg(m_context.m_lastZ);
432
433 // qDebug() << "returning true";
434
435 // The m_context was refreshed with the base class context in the calling
436 // chain.
438
439 return true;
440}
441
442
443//! Deconvolute the mass peaks into charge and molecular mass.
444/*!
445
446 This is one of two methods to deconvolute mass data into a charge value and
447 a Mr value. The method implemented in this function is based on the distance
448 that separates two immediately consecutive peaks of an isotopic cluster.
449 This method can be used as long as the instrument produced data with a
450 resolution sufficient to separate reasonably well the different peaks of an
451 isotopic cluster.
452
453 Set m_lastMz, m_lastZ and m_lastMass.
454
455 \return true if the deconvolution could be performed, false otherwise.
456 */
457bool
459{
460
462 {
463 // qDebug() << __FILE__ << __LINE__
464 //<< "Same xRegionRange.upper and xRegionRange.lower:"
465 //<< "returning from deconvoluteIsotopicCluster";
466
467 return false;
468 }
469
470 double chargeTemp = 1 / fabs(m_context.m_xDelta);
471
472 // Make a judicious roundup.
473 double chargeIntPart;
474 double chargeFracPart = modf(chargeTemp, &chargeIntPart);
475
476 // qDebug() << "m_xDelta:" << m_context.m_baseContext.m_xDelta
477 //<< "chargeTemp:" << QString("%1").arg(chargeTemp, 0, 'f', 6)
478 //<< "chargeIntPart:" << chargeIntPart
479 //<< "chargeFracPart:" << QString("%1").arg(chargeFracPart, 0, 'f', 6)
480 //<< "m_chargeMinimalFractionalPart:" << m_chargeMinimalFractionalPart;
481
482 if(chargeFracPart >= (1 - m_chargeMinimalFractionalPart) &&
483 chargeFracPart <= m_chargeMinimalFractionalPart)
484 {
485 m_context.m_lastZ = -1;
486 m_context.m_lastMz = std::numeric_limits<double>::min();
487 m_context.m_lastTicIntensity = std::numeric_limits<double>::min();
488 m_context.m_lastMr = std::numeric_limits<double>::min();
489
490 // qDebug() << "Not in a isotopic cluster peak:"
491 //<< "returning from deconvoluteIsotopicCluster";
492
493 return false;
494 }
495
496 if(chargeFracPart > m_chargeMinimalFractionalPart)
497 {
498 m_context.m_lastZ = chargeIntPart + 1;
499
500 // qDebug() << "chargeFracPart > m_chargeMinimalFractionalPart -> m_lastZ
501 // = "
502 //<< m_context.m_lastZ;
503 }
504 else
505 {
506 m_context.m_lastZ = chargeIntPart;
507
508 // qDebug()
509 //<< "chargeFracPart <= m_chargeMinimalFractionalPart -> m_lastZ = "
510 //<< m_context.m_lastZ;
511 }
512
513 // Now that we have the charge in the form of an int, we can compute the
514 // Mr of the lightest isotopic cluster peak (the one that has the lowest x
515 // value). That value is stored in m_xRangeLower.
516
517 // We need to sort the xRegionRange before being certain that lower is indeed
518 // the left value of the drag span.
519
522
525
526 // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
527 //<< "returning true";
528
529 // The m_context was refreshed with the base class context in the calling
530 // chain.
532
533 return true;
534}
535
536
537bool
539{
540
541 // m_xRangeLower and m_xRangeUpper and m_xDelta (in fabs() form) have been set
542 // during mouve movement handling. Note that the range values *are
543 // sorted*.
544
546 {
547 m_context.m_lastResolvingPower = std::numeric_limits<double>::min();
548
549 return false;
550 }
551
552 // Resolving power is m/z / Delta(m/z), for singly-charged species.
553
554 // qDebug() << "Calculating the resolving power with these data:"
555 //<< "m_context.m_xRegionRangeStart: " << m_context.m_xRegionRangeStart
556 //<< "m_context.m_xRegionRangeEnd: " << m_context.m_xRegionRangeEnd
557 //<< "m_context.m_xDelta / 2: " << m_context.m_xDelta / 2;
558
560 (std::min<double>(m_context.m_xRegionRangeStart,
562 (m_context.m_xDelta / 2)) /
564
565 // The m_context was refreshed with the base class context in the calling
566 // chain.
568
569 return true;
570}
571
572
573} // namespace pappso
Qt::MouseButtons m_mouseButtonsAtMousePress
virtual void mouseMoveHandlerDraggingCursor()
virtual void keyPressEvent(QKeyEvent *event)
KEYBOARD-related EVENTS.
virtual void mouseMoveHandlerNotDraggingCursor()
virtual void mousePressHandler(QMouseEvent *event)
KEYBOARD-related EVENTS.
virtual void mouseReleaseHandler(QMouseEvent *event)
virtual void mouseMoveHandler(QMouseEvent *event)
KEYBOARD-related EVENTS.
virtual void keyReleaseEvent(QKeyEvent *event)
Handle specific key codes and trigger respective actions.
BasePlotContext m_context
virtual void mouseMoveHandler(QMouseEvent *event) override
Handle mouse movements, in particular record all the last visited points.
void resolvingPowerComputationSignal(const MassSpecTracePlotContext &context)
virtual void keyReleaseEvent(QKeyEvent *event) override
Handle specific key codes and trigger respective actions.
const MassSpecTracePlotContext & refreshBaseContext() const
bool deconvoluteChargedState(int span=1)
Deconvolute the mass peaks into charge and molecular mass.
bool deconvoluteIsotopicCluster()
Deconvolute the mass peaks into charge and molecular mass.
bool deconvolute()
Deconvolute the mass peaks into charge and molecular mass.
virtual void mouseMoveHandlerDraggingCursor() override
void keyPressEventSignal(const MassSpecTracePlotContext &context)
void massDeconvolutionSignal(const MassSpecTracePlotContext &context)
virtual void mousePressHandler(QMouseEvent *event) override
Record the clicks of the mouse.
void setChargeMinimalFractionalPart(double charge_fractional_part)
virtual void keyPressEvent(QKeyEvent *event) override
Set the m_pressedKeyCode to the key code in event.
virtual void mouseMoveHandlerNotDraggingCursor() override
virtual void mouseReleaseHandler(QMouseEvent *event) override
React to the release of the mouse buttons.
int massSpecTracePlotContextMetaTypeId
int massSpecTracePlotContextPtrMetaTypeId
tries to keep as much as possible monoisotopes, removing any possible C13 peaks and changes multichar...
Definition aa.cpp:39
const pappso_double MPROTON(1.007276466879)
This header contains all the type re-definitions and all the global variables definitions used in the...