libpappsomspp
Library for mass spectrometry
qcpspectrum.cpp
Go to the documentation of this file.
1/**
2 * \file pappsomspp/widget/spectrumwidget/qcpspectrum.cpp
3 * \date 31/12/2017
4 * \author Olivier Langella
5 * \brief Custom plot derivative to plot a spectrum
6 */
7
8
9/*******************************************************************************
10 * Copyright (c) 2017 Olivier Langella <Olivier.Langella@u-psud.fr>.
11 *
12 * This file is part of the PAPPSOms++ library.
13 *
14 * PAPPSOms++ is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * PAPPSOms++ is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with PAPPSOms++. If not, see <http://www.gnu.org/licenses/>.
26 *
27 * Contributors:
28 * Olivier Langella <Olivier.Langella@u-psud.fr> - initial API and
29 *implementation
30 ******************************************************************************/
31
32#include "qcpspectrum.h"
33#include "massspectrumwidget.h"
34
35using namespace pappso;
36
37QCPSpectrum::QCPSpectrum(MassSpectrumWidget *parent, bool visible)
38 : QCustomPlot(parent)
39{
40 qDebug() << "QCPSpectrum::QCPSpectrum begin";
41
42 setFocusPolicy(Qt::ClickFocus);
43 _parent = parent;
44 _mz_range.lower = 0;
45 _mz_range.upper = 0;
46 _intensity_range.lower = 0;
47 _intensity_range.upper = 0;
48 _mass_delta_range.upper = -100;
49 _mass_delta_range.lower = 100;
50
51
52 // make axis rects' left side line up:
53 QCPMarginGroup *group = new QCPMarginGroup(this);
54 this->axisRect()->setMarginGroup(QCP::msLeft | QCP::msRight, group);
55
56
57 _p_peak_bars = new QCPBars(xAxis, yAxis);
58 _p_peak_bars->setWidthType(QCPBars::WidthType::wtAbsolute);
59 _p_peak_bars->setWidth(_bar_width);
60 _p_peak_bars->setPen(QPen(Qt::black, 1));
61 _p_peak_bars->setVisible(true);
62
63 _p_peak_bars_isotope = new QCPBars(xAxis, yAxis);
64 _p_peak_bars_isotope->setWidthType(QCPBars::WidthType::wtAbsolute);
65 _p_peak_bars_isotope->setWidth(_bar_width * 10);
66 QColor red(Qt::red);
67 red.setAlpha(100);
68 _p_peak_bars_isotope->setPen(QPen(red, 1));
69 _p_peak_bars_isotope->setBrush(QBrush(red));
70
71 mp_peak_bars_precursor = new QCPBars(xAxis, yAxis);
72 mp_peak_bars_precursor->setWidthType(QCPBars::WidthType::wtAbsolute);
73 mp_peak_bars_precursor->setWidth(_bar_width * 1.5);
74 mp_peak_bars_precursor->setPen(QPen(Qt::cyan, 1));
75 mp_peak_bars_precursor->setVisible(true);
76
77 connect(this->xAxis,
78 SIGNAL(rangeChanged(QCPRange)),
79 this,
80 SLOT(setMzRangeChanged(QCPRange)));
81
82
83 std::vector<PeptideIon> all_ion_list = {
92 PeptideIon::y, ///< Cter amino ions
93 PeptideIon::ystar, ///< Cter amino ions + NH3 loss
94 PeptideIon::yo, ///< Cter amino ions + H2O loss
95 PeptideIon::z, ///< Cter carbocations
98 qDebug() << "SpectrumWidget::setVisibleMassDelta 5";
99
100 for(PeptideIon ion_type : all_ion_list)
101 {
102 QCPBars *p_peak_bars = new QCPBars(xAxis, yAxis);
103 p_peak_bars->setWidthType(QCPBars::WidthType::wtAbsolute);
104 p_peak_bars->setWidth(_bar_width);
105 p_peak_bars->setPen(
106 QPen(PeptideFragmentIon::getPeptideIonColor(ion_type), 1));
107
108 p_peak_bars->setVisible(true);
109 _map_ion_type_bars.insert(
110 std::pair<PeptideIon, QCPBars *>(ion_type, p_peak_bars));
111 }
112 qDebug() << "SpectrumWidget::setVisibleMassDelta visible ?";
113 setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
114 if(visible)
115 {
116
117 _p_delta_axis_rect = new QCPAxisRect(this);
118 this->plotLayout()->addElement(1, 0, _p_delta_axis_rect);
119 _p_delta_axis_rect->axis(QCPAxis::atBottom)->setLayer("axes");
120 _p_delta_axis_rect->axis(QCPAxis::atBottom)->grid()->setLayer("grid");
121 _p_delta_axis_rect->axis(QCPAxis::atLeft)->setLabel("mass delta");
122 // bring bottom and main axis rect closer together:
123 this->plotLayout()->setRowSpacing(0);
124 _p_delta_axis_rect->setAutoMargins(QCP::msLeft | QCP::msRight |
125 QCP::msBottom);
126 _p_delta_axis_rect->setMargins(QMargins(0, 0, 0, 0));
127 this->setAutoAddPlottableToLegend(false);
128 _p_delta_graph = new QCPGraph(_p_delta_axis_rect->axis(QCPAxis::atBottom),
129 _p_delta_axis_rect->axis(QCPAxis::atLeft));
130 _p_delta_graph->setLineStyle(QCPGraph::LineStyle::lsNone);
131 _p_delta_graph->setScatterStyle(
132 QCPScatterStyle(QCPScatterStyle::ssDisc, 4.0));
133
134 _p_delta_axis_rect->setMarginGroup(QCP::msLeft | QCP::msRight, group);
135 _p_delta_axis_rect->setMaximumSize(QSize(QWIDGETSIZE_MAX, 100));
136
137
138 //_p_delta_axis_rect->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom );
139 _p_delta_axis_rect->setRangeDrag(Qt::Horizontal | Qt::Vertical);
140 _p_delta_axis_rect->setRangeZoom(Qt::Vertical);
141
142
143 connect(_p_delta_axis_rect->axis(QCPAxis::atBottom),
144 SIGNAL(rangeChanged(QCPRange)),
145 this,
146 SLOT(setMzRangeChanged(QCPRange)));
147 }
148 else
149 {
150 _p_delta_axis_rect = nullptr;
151 }
152 qDebug() << "QCPSpectrum::QCPSpectrum end";
153}
155{
156}
157
158void
160{
161 _mass_delta_range.upper = -100;
162 _mass_delta_range.lower = 100;
163 // generate basic peaks:
164 _p_spectrum = spectrum;
165 if((spectrum != nullptr) && (spectrum->size() != 0))
166 {
167 // throw PappsoException(QObject::tr("Error in
168 // SpectrumWidget::setSpectrumSp :\n_spectrum_sp.get() == nullptr"));
169 //}
170 _p_peak_bars->setVisible(true);
171 for(const DataPoint &peak : *spectrum)
172 {
173 _p_peak_bars->addData(peak.x, peak.y);
174 }
175 _mz_range.lower = spectrum->front().x - 1;
176 _mz_range.upper = spectrum->back().x + 1;
177 _intensity_range.lower = 0;
178 _intensity_range.upper = spectrum->maxY();
179 }
180 else
181 {
182 _mz_range.lower = 0;
183 _mz_range.upper = 0;
184 _intensity_range.lower = 0;
185 _intensity_range.upper = 0;
186 }
187}
188
189void
191{
192 _p_peak_bars->setVisible(true);
193
194 //_p_peak_bars->rescaleAxes(false);
195 // this->rescaleAxes(false);
196
197
198 if(_mz_range.lower < 0)
199 {
200 _mz_range.lower = 0;
201 }
202 if(_mz_range.upper < 0)
203 {
204 _mz_range.upper = 1000;
205 }
206 else
207 {
208 xAxis->setRange(_mz_range);
209 yAxis->setRange(_intensity_range);
210 if(_p_delta_axis_rect != nullptr)
211 {
212 _p_delta_axis_rect->axis(QCPAxis::AxisType::atLeft)
213 ->setRange(_mass_delta_range);
214 }
215 }
216}
217
218void
220{
221 qDebug() << "QCPSpectrum::setMzRangeChanged _mz_range.lower"
222 << _mz_range.lower;
223 if(_mz_range.lower > 0)
224 {
225 if(range.lower < _mz_range.lower)
226 {
227 range.lower = _mz_range.lower;
228 }
229 if(range.upper > _mz_range.upper)
230 {
231 range.upper = _mz_range.upper;
232 }
233 }
234
235 xAxis->setRange(range);
236
237 if(_p_delta_axis_rect != nullptr)
238 {
239 _p_delta_axis_rect->axis(QCPAxis::atBottom)->setRange(range);
240 }
241}
242
243void
245{
246 qDebug();
247 _p_peak_bars->setData(QVector<double>(), QVector<double>());
248 _p_peak_bars->data().clear();
249 qDebug();
250 _p_peak_bars_isotope->setData(QVector<double>(), QVector<double>());
251 _p_peak_bars_isotope->data().clear();
252 qDebug();
253 mp_peak_bars_precursor->setData(QVector<double>(), QVector<double>());
254 mp_peak_bars_precursor->data().clear();
255 for(std::pair<PeptideIon, QCPBars *> pair_ion_bar : _map_ion_type_bars)
256 {
257 pair_ion_bar.second->setData(QVector<double>(), QVector<double>());
258 pair_ion_bar.second->data().clear();
259 }
260 // this->clearPlottables();
261 // this->clearItems();
262 if(_p_delta_axis_rect != nullptr)
263 {
264 _p_delta_graph->setData(QVector<double>(), QVector<double>());
265 _p_delta_graph->data().clear();
266 }
267
268 _mz_range.lower = 0;
269 _mz_range.upper = 0;
270
271 _mass_delta_range.upper = -100;
272 _mass_delta_range.lower = 100;
273 qDebug();
274}
275
276void
278{
279 if(event->key() == Qt::Key_Control)
280 {
281 _control_key = true;
282 }
283 qDebug() << "QCPSpectrum::keyPressEvent end";
284}
285
286void
288{
289 if(event->key() == Qt::Key_Control)
290 {
291 _control_key = false;
292 }
293 qDebug() << "QCPSpectrum::keyReleaseEvent end";
294}
295
296void
298{
299 /*qDebug() << "QCPSpectrum::mousePressEvent begin "
300 << xAxis->pixelToCoord(event->x()) << " "
301 << yAxis->pixelToCoord(event->y());*/
302 _click = true;
303
304#if QT_VERSION < 0x060000
305 _old_x = event->x();
306 _old_y = yAxis->pixelToCoord(event->y());
307#else
308 _old_x = event->position().x();
309 _old_y = yAxis->pixelToCoord(event->position().y());
310#endif
311 if(_old_y < 0)
312 _old_y = 0;
313 /* qDebug() << "QCPSpectrum::mousePressEvent end";*/
314}
315void
316QCPSpectrum::mouseReleaseEvent(QMouseEvent *event [[maybe_unused]])
317{
318 /*qDebug() << "QCPSpectrum::mouseReleaseEvent begin "
319 << xAxis->pixelToCoord(event->x()) << " "
320 << yAxis->pixelToCoord(event->y());*/
321 _click = false;
322 // qDebug() << "QCPSpectrum::mouseReleaseEvent end";
323}
324void
326{
327
328#if QT_VERSION < 0x060000
329 pappso::pappso_double x = xAxis->pixelToCoord(event->x());
330#else
331 pappso::pappso_double x = xAxis->pixelToCoord(event->position().x());
332#endif
333 if(_click)
334 {
335 /* qDebug() << "QCPSpectrum::mouseMoveEvent begin "
336 << xAxis->pixelToCoord(event->x()) << " "
337 << yAxis->pixelToCoord(event->y());*/
338
339#if QT_VERSION < 0x060000
340 pappso::pappso_double y = yAxis->pixelToCoord(event->y());
341#else
342 pappso::pappso_double y = yAxis->pixelToCoord(event->position().y());
343#endif
344 if(y < 0)
345 {
346 y = 0;
347 }
348 if(_control_key)
349 {
350 if(y > 0)
351 {
352 this->yAxis->scaleRange(_old_y / y, 0);
353 }
354 }
355 else
356 {
357
358#if QT_VERSION < 0x060000
359 this->xAxis->moveRange(xAxis->pixelToCoord(_old_x) -
360 xAxis->pixelToCoord(event->x()));
361#else
362 this->xAxis->moveRange(xAxis->pixelToCoord(_old_x) -
363 xAxis->pixelToCoord(event->position().x()));
364#endif
365 }
366
367#if QT_VERSION < 0x060000
368 _old_x = event->x();
369#else
370 _old_x = event->position().x();
371#endif
372 _old_y = y;
373 replot();
374 // qDebug() << "QCPSpectrum::mouseMoveEvent end";
375 }
376 else
377 {
378 if(_p_spectrum != nullptr)
379 {
380 pappso::pappso_double mouse_mz_range =
381 xAxis->pixelToCoord(10) - xAxis->pixelToCoord(8);
382 getMostIntensePeakBetween(x, mouse_mz_range);
384 }
385 }
386}
387
388void
390 pappso_double mouse_mz_range) const
391{
392 /*qDebug() << "QCPSpectrum::getNearestPeakBetween begin " << mz << " "
393 << mouse_mz_range;*/
394 const DataPoint *p_peak_match;
395 p_peak_match = nullptr;
396 pappso_double min = mz - mouse_mz_range;
397 pappso_double max = mz + mouse_mz_range;
398
399 for(const DataPoint &peak : *_p_spectrum)
400 {
401 if((peak.x > min) && (peak.x < max))
402 {
403 if(p_peak_match == nullptr)
404 {
405 p_peak_match = &peak;
406 }
407 else
408 {
409 if(fabs(mz - peak.x) < fabs(mz - p_peak_match->x))
410 {
411 p_peak_match = &peak;
412 }
413 }
414 }
415 }
416 _parent->peakChangeEvent(p_peak_match);
417 // qDebug() << "QCPSpectrum::getNearestPeakBetween end";
418}
419
420
421void
423 pappso_double mouse_mz_range) const
424{
425 /*qDebug() << "QCPSpectrum::getNearestPeakBetween begin " << mz << " "
426 << mouse_mz_range;*/
427 const DataPoint *p_peak_match;
428 p_peak_match = nullptr;
429 pappso_double min = mz - mouse_mz_range;
430 pappso_double max = mz + mouse_mz_range;
431
432 for(const DataPoint &peak : *_p_spectrum)
433 {
434 if((peak.x > min) && (peak.x < max))
435 {
436 if(p_peak_match == nullptr)
437 {
438 p_peak_match = &peak;
439 }
440 else
441 {
442 if(p_peak_match->y < peak.y)
443 {
444 p_peak_match = &peak;
445 }
446 }
447 }
448 }
449 _parent->peakChangeEvent(p_peak_match);
450 // qDebug() << "QCPSpectrum::getNearestPeakBetween end";
451}
452
453void
455{
456 if(_p_delta_axis_rect != nullptr)
457 {
458 // observed - theoretical
459 double diff =
460 peak_ion_match.getPeak().x -
461 peak_ion_match.getPeptideNaturalIsotopeAverageSp().get()->getMz();
462 _p_delta_graph->addData(peak_ion_match.getPeak().x, diff);
463
464 if(diff > _mass_delta_range.upper)
465 _mass_delta_range.upper = diff;
466 if(diff < _mass_delta_range.lower)
467 _mass_delta_range.lower = diff;
468
469 _p_delta_axis_rect->axis(QCPAxis::AxisType::atLeft)
470 ->setRange(_mass_delta_range);
471 }
472}
473
474void
476{
477 _map_ion_type_bars[peak_ion_match.getPeptideIonType()]->addData(
478 peak_ion_match.getPeak().x, peak_ion_match.getPeak().y);
479}
480
481void
483 const std::vector<pappso::PeptideNaturalIsotopeAverageSp> &isotope_mass_list,
484 pappso_double intensity)
485{
486 pappso_double total_intensity =
487 ((pappso_double)1.0 / isotope_mass_list.at(0).get()->getIntensityRatio()) *
488 intensity;
489 for(PeptideNaturalIsotopeAverageSp peptide : isotope_mass_list)
490 {
491 _p_peak_bars_isotope->addData(peptide.get()->getMz(),
492 peptide.get()->getIntensityRatio() *
493 total_intensity);
494 }
495}
496
497void
499 int charge,
500 PrecisionPtr ms2_precision)
501{
502 MzRange range(precursor_mz, ms2_precision);
503 double precursor_mz_c13 = precursor_mz + (DIFFC12C13 / charge);
504 MzRange range_c13(precursor_mz_c13, ms2_precision);
505
506 for(const DataPoint &peak : *_p_spectrum)
507 {
508 if(((peak.x > range.lower()) && (peak.x < range.upper())) ||
509 ((peak.x > range_c13.lower()) && (peak.x < range_c13.upper())))
510 {
511 mp_peak_bars_precursor->addData(peak.x, peak.y);
512 QCPItemText *text_label = new QCPItemText(this);
513 text_label->setVisible(true);
514 text_label->setPositionAlignment(Qt::AlignBottom | Qt::AlignHCenter);
515 text_label->position->setType(QCPItemPosition::ptPlotCoords);
516 text_label->position->setCoords(peak.x, peak.y);
517 // place position at center/top of axis rect
518 text_label->setFont(QFont(font().family(), 8));
519 text_label->setText("precursor");
520 text_label->setColor(Qt::cyan);
521 }
522 }
523}
void mzChangeEvent(pappso_double mz) const
void peakChangeEvent(const DataPoint *p_peak_match)
Class to represent a mass spectrum.
Definition: massspectrum.h:71
pappso_double lower() const
Definition: mzrange.h:71
pappso_double upper() const
Definition: mzrange.h:77
virtual const PeptideNaturalIsotopeAverageSp & getPeptideNaturalIsotopeAverageSp() const
const DataPoint & getPeak() const
PeptideIon getPeptideIonType() const
static const QColor getPeptideIonColor(PeptideIon ion_type)
QCPGraph * _p_delta_graph
Definition: qcpspectrum.h:92
void highlightPrecursorPeaks(double precursor_mz, int charge, PrecisionPtr ms2_precision)
virtual void keyPressEvent(QKeyEvent *event) override
QCPAxisRect * _p_delta_axis_rect
Definition: qcpspectrum.h:91
QCPBars * _p_peak_bars
Definition: qcpspectrum.h:87
MassSpectrumWidget * _parent
Definition: qcpspectrum.h:82
QCPRange _mass_delta_range
Definition: qcpspectrum.h:86
void addPeakIonIsotopeMatch(const PeakIonIsotopeMatch &peak_ion_match)
virtual void mouseReleaseEvent(QMouseEvent *event) override
QCPRange _intensity_range
Definition: qcpspectrum.h:85
void addMassDelta(const PeakIonIsotopeMatch &peak_ion_match)
void getNearestPeakBetween(pappso_double mz, pappso_double mouse_mz_range) const
virtual void mouseMoveEvent(QMouseEvent *event) override
pappso::pappso_double _old_x
Definition: qcpspectrum.h:96
void getMostIntensePeakBetween(pappso_double mz, pappso_double mouse_mz_range) const
QCPBars * mp_peak_bars_precursor
Definition: qcpspectrum.h:89
void setSpectrumP(const MassSpectrum *spectrum)
void addMs1IsotopePattern(const std::vector< pappso::PeptideNaturalIsotopeAverageSp > &isotope_mass_list, pappso_double intensity)
std::map< PeptideIon, QCPBars * > _map_ion_type_bars
Definition: qcpspectrum.h:90
virtual void keyReleaseEvent(QKeyEvent *event) override
QCPBars * _p_peak_bars_isotope
Definition: qcpspectrum.h:88
const MassSpectrum * _p_spectrum
Definition: qcpspectrum.h:83
virtual void mousePressEvent(QMouseEvent *event) override
Q_SLOT void setMzRangeChanged(QCPRange range)
pappso::pappso_double _old_y
Definition: qcpspectrum.h:97
tries to keep as much as possible monoisotopes, removing any possible C13 peaks and changes multichar...
Definition: aa.cpp:39
PeptideIon
PeptideIon enum defines all types of ions (Nter or Cter)
Definition: types.h:400
@ a
Nter aldimine ions.
@ y
Cter amino ions.
@ c
Nter amino ions.
@ astar
Nter aldimine ions + NH3 loss.
@ ystar
Cter amino ions + NH3 loss.
@ yo
Cter amino ions + H2O loss.
@ bstar
Nter acylium ions + NH3 loss.
@ b
Nter acylium ions.
@ x
Cter acylium ions.
@ bo
Nter acylium ions + H2O loss.
@ ao
Nter aldimine ions + H2O loss.
@ z
Cter carbocations.
double pappso_double
A type definition for doubles.
Definition: types.h:49
std::shared_ptr< const PeptideNaturalIsotopeAverage > PeptideNaturalIsotopeAverageSp
@ max
maximum of intensities
const pappso_double DIFFC12C13(1.0033548378)
pappso_double x
Definition: datapoint.h:23
pappso_double y
Definition: datapoint.h:24