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 
35 using namespace pappso;
36 
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 
158 void
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 
189 void
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 
218 void
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 
243 void
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 
276 void
277 QCPSpectrum::keyPressEvent(QKeyEvent *event)
278 {
279  if(event->key() == Qt::Key_Control)
280  {
281  _control_key = true;
282  }
283  qDebug() << "QCPSpectrum::keyPressEvent end";
284 }
285 
286 void
288 {
289  if(event->key() == Qt::Key_Control)
290  {
291  _control_key = false;
292  }
293  qDebug() << "QCPSpectrum::keyReleaseEvent end";
294 }
295 
296 void
297 QCPSpectrum::mousePressEvent(QMouseEvent *event)
298 {
299  /*qDebug() << "QCPSpectrum::mousePressEvent begin "
300  << xAxis->pixelToCoord(event->x()) << " "
301  << yAxis->pixelToCoord(event->y());*/
302  _click = true;
303  _old_x = event->x();
304  _old_y = yAxis->pixelToCoord(event->y());
305  if(_old_y < 0)
306  _old_y = 0;
307  /* qDebug() << "QCPSpectrum::mousePressEvent end";*/
308 }
309 void
310 QCPSpectrum::mouseReleaseEvent(QMouseEvent *event [[maybe_unused]])
311 {
312  /*qDebug() << "QCPSpectrum::mouseReleaseEvent begin "
313  << xAxis->pixelToCoord(event->x()) << " "
314  << yAxis->pixelToCoord(event->y());*/
315  _click = false;
316  // qDebug() << "QCPSpectrum::mouseReleaseEvent end";
317 }
318 void
319 QCPSpectrum::mouseMoveEvent(QMouseEvent *event)
320 {
321  pappso::pappso_double x = xAxis->pixelToCoord(event->x());
322  if(_click)
323  {
324  /* qDebug() << "QCPSpectrum::mouseMoveEvent begin "
325  << xAxis->pixelToCoord(event->x()) << " "
326  << yAxis->pixelToCoord(event->y());*/
327  pappso::pappso_double y = yAxis->pixelToCoord(event->y());
328  if(y < 0)
329  {
330  y = 0;
331  }
332  if(_control_key)
333  {
334  if(y > 0)
335  {
336  this->yAxis->scaleRange(_old_y / y, 0);
337  }
338  }
339  else
340  {
341  this->xAxis->moveRange(xAxis->pixelToCoord(_old_x) -
342  xAxis->pixelToCoord(event->x()));
343  }
344  _old_x = event->x();
345  _old_y = y;
346  replot();
347  // qDebug() << "QCPSpectrum::mouseMoveEvent end";
348  }
349  else
350  {
351  if(_p_spectrum != nullptr)
352  {
353  pappso::pappso_double mouse_mz_range =
354  xAxis->pixelToCoord(10) - xAxis->pixelToCoord(8);
355  getMostIntensePeakBetween(x, mouse_mz_range);
357  }
358  }
359 }
360 
361 void
363  pappso_double mouse_mz_range) const
364 {
365  /*qDebug() << "QCPSpectrum::getNearestPeakBetween begin " << mz << " "
366  << mouse_mz_range;*/
367  const DataPoint *p_peak_match;
368  p_peak_match = nullptr;
369  pappso_double min = mz - mouse_mz_range;
370  pappso_double max = mz + mouse_mz_range;
371 
372  for(const DataPoint &peak : *_p_spectrum)
373  {
374  if((peak.x > min) && (peak.x < max))
375  {
376  if(p_peak_match == nullptr)
377  {
378  p_peak_match = &peak;
379  }
380  else
381  {
382  if(fabs(mz - peak.x) < fabs(mz - p_peak_match->x))
383  {
384  p_peak_match = &peak;
385  }
386  }
387  }
388  }
389  _parent->peakChangeEvent(p_peak_match);
390  // qDebug() << "QCPSpectrum::getNearestPeakBetween end";
391 }
392 
393 
394 void
396  pappso_double mouse_mz_range) const
397 {
398  /*qDebug() << "QCPSpectrum::getNearestPeakBetween begin " << mz << " "
399  << mouse_mz_range;*/
400  const DataPoint *p_peak_match;
401  p_peak_match = nullptr;
402  pappso_double min = mz - mouse_mz_range;
403  pappso_double max = mz + mouse_mz_range;
404 
405  for(const DataPoint &peak : *_p_spectrum)
406  {
407  if((peak.x > min) && (peak.x < max))
408  {
409  if(p_peak_match == nullptr)
410  {
411  p_peak_match = &peak;
412  }
413  else
414  {
415  if(p_peak_match->y < peak.y)
416  {
417  p_peak_match = &peak;
418  }
419  }
420  }
421  }
422  _parent->peakChangeEvent(p_peak_match);
423  // qDebug() << "QCPSpectrum::getNearestPeakBetween end";
424 }
425 
426 void
428 {
429  if(_p_delta_axis_rect != nullptr)
430  {
431  // observed - theoretical
432  double diff =
433  peak_ion_match.getPeak().x -
434  peak_ion_match.getPeptideNaturalIsotopeAverageSp().get()->getMz();
435  _p_delta_graph->addData(peak_ion_match.getPeak().x, diff);
436 
437  if(diff > _mass_delta_range.upper)
438  _mass_delta_range.upper = diff;
439  if(diff < _mass_delta_range.lower)
440  _mass_delta_range.lower = diff;
441 
442  _p_delta_axis_rect->axis(QCPAxis::AxisType::atLeft)
443  ->setRange(_mass_delta_range);
444  }
445 }
446 
447 void
449 {
450  _map_ion_type_bars[peak_ion_match.getPeptideIonType()]->addData(
451  peak_ion_match.getPeak().x, peak_ion_match.getPeak().y);
452 }
453 
454 void
456  const std::vector<pappso::PeptideNaturalIsotopeAverageSp> &isotope_mass_list,
457  pappso_double intensity)
458 {
459  pappso_double total_intensity =
460  ((pappso_double)1.0 / isotope_mass_list.at(0).get()->getIntensityRatio()) *
461  intensity;
462  for(PeptideNaturalIsotopeAverageSp peptide : isotope_mass_list)
463  {
464  _p_peak_bars_isotope->addData(peptide.get()->getMz(),
465  peptide.get()->getIntensityRatio() *
466  total_intensity);
467  }
468 }
469 
470 void
472  int charge,
473  PrecisionPtr ms2_precision)
474 {
475  MzRange range(precursor_mz, ms2_precision);
476  double precursor_mz_c13 = precursor_mz + (DIFFC12C13 / charge);
477  MzRange range_c13(precursor_mz_c13, ms2_precision);
478 
479  for(const DataPoint &peak : *_p_spectrum)
480  {
481  if(((peak.x > range.lower()) && (peak.x < range.upper())) ||
482  ((peak.x > range_c13.lower()) && (peak.x < range_c13.upper())))
483  {
484  mp_peak_bars_precursor->addData(peak.x, peak.y);
485  QCPItemText *text_label = new QCPItemText(this);
486  text_label->setVisible(true);
487  text_label->setPositionAlignment(Qt::AlignBottom | Qt::AlignHCenter);
488  text_label->position->setType(QCPItemPosition::ptPlotCoords);
489  text_label->position->setCoords(peak.x, peak.y);
490  // place position at center/top of axis rect
491  text_label->setFont(QFont(font().family(), 8));
492  text_label->setText("precursor");
493  text_label->setColor(Qt::cyan);
494  }
495  }
496 }
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:72
pappso_double upper() const
Definition: mzrange.h:78
virtual const PeptideNaturalIsotopeAverageSp & getPeptideNaturalIsotopeAverageSp() const
PeptideIon getPeptideIonType() const
Definition: peakionmatch.h:67
const DataPoint & getPeak() const
Definition: peakionmatch.h:55
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)
QCPSpectrum(MassSpectrumWidget *parent, bool visible)
Definition: qcpspectrum.cpp:37
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:385
@ 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:48
std::shared_ptr< const PeptideNaturalIsotopeAverage > PeptideNaturalIsotopeAverageSp
@ max
maximum of intensities
const pappso_double DIFFC12C13(1.0033548378)
pappso_double x
Definition: datapoint.h:22
pappso_double y
Definition: datapoint.h:23