libpappsomspp
Library for mass spectrometry
basetraceplotwidget.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 #include "basetraceplotwidget.h"
36 #include "../../exception/exceptionnotpossible.h"
37 #include "../../pappsoexception.h"
38 
39 
40 namespace pappso
41 {
42 
43 
45  : BasePlotWidget(parent)
46 {
47  // We can afford to call createAllAncillaryItems() in this derived class
48  // because all the items will have been created *before* the addition of plots
49  // and then the rendering order will hide them to the viewer, since the
50  // rendering order is according to the order in which the items have been
51  // created.
52  //
53  // The fact that the ancillary items are created before trace plots is not a
54  // problem because the trace plots are sparse and do not effectively hide the
55  // data.
56  //
57  // But, in the color map plot widgets, we cannot afford to create the
58  // ancillary items *before* the plot itself because then, the rendering of the
59  // plot (created after) would screen off the ancillary items (created before).
60  //
61  // So, the createAllAncillaryItems() function needs to be called in the
62  // derived classes at the most appropriate moment in the setting up of the
63  // widget.
65 }
66 
67 
69  const QString &x_axis_label,
70  const QString &y_axis_label)
71  : BasePlotWidget(parent, x_axis_label, y_axis_label)
72 {
73  // We can afford to call createAllAncillaryItems() in this derived class
74  // because all the items will have been created *before* the addition of plots
75  // and then the rendering order will hide them to the viewer, since the
76  // rendering order is according to the order in which the items have been
77  // created.
78  //
79  // The fact that the ancillary items are created before trace plots is not a
80  // problem because the trace plots are sparse and do not effectively hide the
81  // data.
82  //
83  // But, in the color map plot widgets, we cannot afford to create the
84  // ancillary items *before* the plot itself because then, the rendering of the
85  // plot (created after) would screen off the ancillary items (created before).
86  //
87  // So, the createAllAncillaryItems() function needs to be called in the
88  // derived classes at the most appropriate moment in the setting up of the
89  // widget.
91 }
92 
93 
94 //! Destruct \c this BaseTracePlotWidget instance.
95 /*!
96 
97  The destruction involves clearing the history, deleting all the axis range
98  history items for x and y axes.
99 
100 */
102 {
103 }
104 
105 
106 void
108  const std::vector<double> &keys,
109  const std::vector<double> &values)
110 {
111  QCPGraph *graph_p = graph(graph_index);
112 
113  if(graph_p == nullptr)
114  qFatal("Programming error.");
115 
116  return setGraphData(graph_p, keys, values);
117 }
118 
119 
120 void
122  const std::vector<double> &keys,
123  const std::vector<double> &values)
124 {
125  if(graph_p == nullptr)
126  qFatal("Pointer cannot be nullptr.");
127 
128  // Version that is now deprecated (20200924)
129  // graph_p->setData(QVector<double>::fromStdVector(keys),
130  // QVector<double>::fromStdVector(values));
131 
132  QVector<double> key_qvector;
133  QVector<double> value_qvector;
134 
135 
136 #if 0
137  // Now replace the graph's data. Note that the data are
138  // inherently sorted (true below).
139 
140  // The begin() -- end() ranges constructor did not work as of
141  // Qt 5.14.2 this day: 20200721
142 
143  key_qvector =
144  QVector(keys.begin(),
145  keys.end());
146  value_qvector =
147  QVector(values.begin(),
148  values.end());
149 #endif
150 
151  for(auto &value : keys)
152  key_qvector.push_back(value);
153 
154  for(auto &value : values)
155  value_qvector.push_back(value);
156 
157  graph_p->setData(key_qvector, value_qvector, true);
158 
159  graph_p->setPen(m_pen);
160 
161  rescaleAxes();
163  replot();
164 }
165 
166 
167 void
169 {
170  QCPGraph *graph_p = graph(graph_index);
171 
172  if(graph_p == nullptr)
173  qFatal("Programming error.");
174 
175  graph_p->data().clear();
176 
177  rescaleAxes();
179  replot();
180 }
181 
182 
183 QCPGraph *
184 BaseTracePlotWidget::addTrace(const pappso::Trace &trace, const QColor &color)
185 {
186  // qDebug();
187 
188  if(!color.isValid())
189  throw PappsoException(
190  QString("The color to be used for the plot graph is invalid."));
191 
192  // This seems to be unpleasant.
193  // setFocus();
194 
195  QCPGraph *graph_p = addGraph();
196 
197  graph_p->setLayer("plotsLayer");
198 
199  // Now depracated as of 20200924
200  // graph_p->setData(QVector<double>::fromStdVector(trace.xValues()),
201  // QVector<double>::fromStdVector(trace.yValues()));
202 
203  QVector<double> key_qvector;
204  QVector<double> value_qvector;
205 
206 #if 0
207  // Now replace the graph's data. Note that the data are
208  // inherently sorted (true below).
209 
210  // The begin() -- end() ranges constructor did not work as of
211  // Qt 5.14.2 this day: 20200721
212 
213  key_qvector =
214  QVector(trace.xValues().begin(),
215  .trace.xValues()end());
216  value_qvector =
217  QVector(trace.yValues().begin(),
218  trace.yValues().end());
219 #endif
220 
221  for(auto &value : trace.xValues())
222  key_qvector.push_back(value);
223 
224  for(auto &value : trace.yValues())
225  value_qvector.push_back(value);
226 
227  graph_p->setData(key_qvector, value_qvector, true);
228 
229  QPen pen = graph()->pen();
230  pen.setColor(color);
231  graph()->setPen(pen);
232 
233  // Connect the signal of selection change so that we can re-emit it for the
234  // widget that is using *this widget.
235 
236  connect(graph_p,
237  static_cast<void (QCPAbstractPlottable::*)(bool)>(
238  &QCPAbstractPlottable::selectionChanged),
239  [this, graph_p]() {
240  emit plottableSelectionChangedSignal(graph_p, graph_p->selected());
241  });
242 
243  // Rescaling the axes is actually unpleasant if there are more than one
244  // graph in the plot widget and that we are adding one. So only, rescale if
245  // the number of graphs is == 1, that is we are adding the first one.
246 
247  if(graphCount() == 1)
248  {
249  rescaleAxes();
251  }
252 
253  replot();
254 
255  return graph_p;
256 }
257 
258 
259 //! Find a minimal integration range starting at an existing data point
260 /*!
261 
262  If the user clicks onto a plot at a location that is not a true data point,
263  get a data range that begins at the preceding data point and that ends at
264  the clicked location point.
265 
266 */
267 bool
269  double key,
270  QCPRange &range)
271 {
272 
273  // Given a key double value, we want to know what is the range that will
274  // frame correctly the key double value if that key value is not exactly
275  // the one of a point of the trace.
276 
277  // First of all get the keys of the graph.
278 
279  QCPGraph *theGraph = graph(index);
280 
281  if(theGraph == nullptr)
282  throw ExceptionNotPossible(
283  "basetraceplotwidget.cpp @ indIntegrationLowerRangeForKey() -- ERROR "
284  "theGraph cannot be nullptr.");
285 
286  // QCPGraphDataContainer is a typedef QCPDataContainer<QCPGraphData> and
287  // QCPDataContainer< DataType > is a Class Template. So in this context,
288  // DataType is QCPGraphData.
289  // QCPGraphData is the data point, that is the (key,value) pair.
290  QSharedPointer<QCPGraphDataContainer> graph_data_container_p =
291  theGraph->data();
292 
293  QCPDataRange dataRange = graph_data_container_p->dataRange();
294 
295  if(!dataRange.isValid())
296  return false;
297 
298  if(!dataRange.size())
299  return false;
300 
301  if(dataRange.size() > 1)
302  {
303  double firstKey = graph_data_container_p->at(dataRange.begin())->key;
304  double lastKey = graph_data_container_p->at(dataRange.end())->key;
305 
306  // There is one check to be done: the user might erroneously set the mouse
307  // cursor beyond the last point of the graph. If that is the case, then
308  // upper key needs to be that very point. All we need to do is return the
309  // lower key, that is the pre-last key of the keys list. No need to
310  // iterate in the keys list.
311 
312  if(key > lastKey)
313  {
314  // No need to search for the key in the keys, just get the lower key
315  // immediately, that is, the key that is one slot left the last key.
316  range.lower = graph_data_container_p->at(dataRange.end() - 2)->key;
317  range.upper = graph_data_container_p->at(dataRange.end() - 1)->key;
318 
319  return true;
320  }
321 
322  // Likewise, if the cursor is set left of the first plot point, then that
323  // will be the lower range point. All we need is to provide the upper
324  // range point as the second point of the plot.
325 
326  if(key < firstKey)
327  {
328  range.lower = firstKey;
329  range.upper = graph_data_container_p->at(dataRange.begin() + 1)->key;
330 
331  return true;
332  }
333 
334  // Finally the generic case where the user point to any point *in* the
335  // graph.
336 
337  range.lower =
338  graph_data_container_p->findBegin(key, /*expandedRange*/ true)->key;
339  range.upper =
340  std::prev(graph_data_container_p->findEnd(key, /*expandedRange*/ true))
341  ->key;
342 
343  return true;
344  }
345 
346  return false;
347 }
348 
349 
350 std::vector<double>
351 BaseTracePlotWidget::getValuesX(int graph_index) const
352 {
353  std::vector<double> keys;
354 
355  QCPGraph *graph_p = graph(graph_index);
356 
357  if(graph_p == nullptr)
358  qFatal("Programming error.");
359 
360  QSharedPointer<QCPGraphDataContainer> graph_data_container_p =
361  graph_p->data();
362 
363  // Iterate in the keys
364  auto beginIt = graph_data_container_p->begin();
365  auto endIt = graph_data_container_p->end();
366 
367  for(auto iter = beginIt; iter != endIt; ++iter)
368  keys.push_back(iter->key);
369 
370  return keys;
371 }
372 
373 
374 std::vector<double>
375 BaseTracePlotWidget::getValuesY(int graph_index) const
376 {
377  std::vector<double> values;
378 
379  QCPGraph *graph_p = graph(graph_index);
380 
381  if(graph_p == nullptr)
382  qFatal("Programming error.");
383 
384  QSharedPointer<QCPGraphDataContainer> graph_data_container_p =
385  graph_p->data();
386 
387  // Iterate in the values
388  auto beginIt = graph_data_container_p->begin();
389  auto endIt = graph_data_container_p->end();
390 
391  for(auto iter = beginIt; iter != endIt; ++iter)
392  values.push_back(iter->key);
393 
394  return values;
395 }
396 
397 
398 QCPRange
399 BaseTracePlotWidget::getValueRangeOnKeyRange(QCPAbstractPlottable *plottable_p,
400  bool &ok)
401 {
402 
403  // The X axis range is set. But we want to find for that X axis range the
404  // min and max Y values. This function is useful when the user asks that
405  // while changing the X axis range, the trace be always in full scale on the
406  // Y axis.
407 
408  QCPRange key_range(xAxis->range().lower, xAxis->range().upper);
409 
410  if(plottable_p != nullptr)
411  {
412 
413  return plottable_p->getValueRange(ok, QCP::SignDomain::sdBoth, key_range);
414  }
415  else
416  {
417 
418  // How many graphs are currently plotted in this plot widget ?
419  int graph_count = graphCount();
420 
421  // Iterate in each graph and get the y max value. Then compare with the
422  // largest one and update if necessary. Store the pointer to the graph
423  // that has a larger y value. At the end of the iteration, it will be
424  // the winner.
425 
426  double temp_min_value = std::numeric_limits<double>::max();
427  double temp_max_value = std::numeric_limits<double>::min();
428 
429  bool found_range = false;
430 
431  for(int iter = 0; iter < graph_count; ++iter)
432  {
433  QCPGraph *plottable_p = graph(iter);
434 
435  QCPRange value_range =
436  plottable_p->getValueRange(ok, QCP::SignDomain::sdBoth, key_range);
437 
438  if(ok)
439  found_range = true;
440 
441  if(value_range.lower < temp_min_value)
442  temp_min_value = value_range.lower;
443  if(value_range.upper > temp_max_value)
444  temp_max_value = value_range.upper;
445  }
446 
447  // At this point return the range.
448 
449  ok = found_range;
450  return QCPRange(temp_min_value, temp_max_value);
451  }
452 }
453 
454 
455 QCPRange
457 {
458 
459  // The X axis range is set. But we want to find for that X axis range the
460  // min and max Y values. This function is useful when the user asks that
461  // while changing the X axis range, the trace be always in full scale on the
462  // Y axis.
463 
464  QCPAbstractPlottable *plottable_p = plottable(index);
465 
466  if(plottable_p == nullptr)
467  qFatal("Programming error.");
468 
469  return getValueRangeOnKeyRange(plottable_p, ok);
470 }
471 
472 
473 double
474 BaseTracePlotWidget::getYatX(double x, QCPGraph *graph_p)
475 {
476  if(graph_p == nullptr)
477  qFatal("Programming error.");
478 
479  QCPItemTracer tracer(this);
480  tracer.setGraph(graph_p);
481  tracer.setInterpolating(true);
482  tracer.setGraphKey(x);
483  tracer.updatePosition();
484 
485  return tracer.position->value();
486 }
487 
488 
489 double
490 BaseTracePlotWidget::getYatX(double x, int index)
491 {
492  QCPGraph *graph_p = graph(index);
493 
494  if(graph_p == nullptr)
495  qFatal("Programming error.");
496 
497  return getYatX(x, graph_p);
498 }
499 
500 
501 void
503  QCPAxis *axis,
504  [[maybe_unused]] QCPAxis::SelectablePart part,
505  QMouseEvent *event)
506 {
507  //qDebug();
508 
509  m_context.m_keyboardModifiers = QGuiApplication::queryKeyboardModifiers();
510 
511  if(m_context.m_keyboardModifiers & Qt::ControlModifier)
512  {
513  //qDebug();
514 
515  // If the Ctrl modifiers is active, then both axes are to be reset. Also
516  // the histories are reset also.
517 
518  rescaleAxes();
520  }
521  else
522  {
523  //qDebug();
524 
525  // Only the axis passed as parameter is to be rescaled.
526  // Reset the range of that axis to the max view possible, but for the y
527  // axis check if the Shift keyboard key is pressed. If so the full scale
528  // should be calculated only on the data in the current x range.
529 
530  if(axis->orientation() == Qt::Vertical)
531  {
532  if(m_context.m_keyboardModifiers & Qt::ShiftModifier)
533  {
534 
535  // In this case, we want to make a rescale of the Y axis such
536  // that it displays full scale the data in the current X axis
537  // range only.
538 
539  bool ok = false;
540 
541  QCPRange value_range = getValueRangeOnKeyRange(nullptr, ok);
542 
543  yAxis->setRange(value_range);
544  }
545  else
546  axis->rescale();
547  }
548  else
549  axis->rescale();
550 
552 
553  event->accept();
554  }
555 
556  // The double-click event does not cancel the mouse press event. That is, if
557  // left-double-clicking, at the end of the operation the button still
558  // "pressed". We need to remove manually the button from the pressed buttons
559  // context member.
560 
561  m_context.m_pressedMouseButtons ^= event->button();
562 
564 
566 
567  replot();
568 }
569 
570 
571 void
573 {
574  double xLower = xAxis->range().lower;
575  double xUpper = xAxis->range().upper;
576 
577  // Get the current y lower/upper range.
578  double yLower = yAxis->range().lower;
579  double yUpper = yAxis->range().upper;
580 
581  // This function is called only when the user has clicked on the x/y axis or
582  // when the user has dragged the left mouse button with the Ctrl key
583  // modifier. The m_context.m_wasClickOnXAxis is then simulated in the mouse
584  // move handler. So we need to test which axis was clicked-on.
585 
587  {
588 
589  // We are changing the range of the X axis.
590 
591  // What is the x delta ?
592  double xDelta =
594 
595  // If xDelta is < 0, the we were dragging from right to left, we are
596  // compressing the view on the x axis, by adding new data to the right
597  // hand size of the graph. So we add xDelta to the upper bound of the
598  // range. Otherwise we are uncompressing the view on the x axis and
599  // remove the xDelta from the upper bound of the range. This is why we
600  // have the
601  // '-'
602  // and not '+' below;
603 
604  // qDebug() << "Setting xaxis:" << xLower << "--" << xUpper - xDelta;
605 
606  xAxis->setRange(xLower, xUpper - xDelta);
607 
608 
609  // Old version
610  // if(xDelta < 0)
611  //{
612  //// The dragging operation was from right to left, we are enlarging
613  //// the range (thus, we are unzooming the view, since the widget
614  //// always has the same size).
615 
616  // xAxis->setRange(xLower, xUpper + fabs(xDelta));
617  //}
618  // else
619  //{
620  //// The dragging operation was from left to right, we are reducing
621  //// the range (thus, we are zooming the view, since the widget
622  //// always has the same size).
623 
624  // xAxis->setRange(xLower, xUpper - fabs(xDelta));
625  //}
626 
627  // We may either leave the scale of the Y axis as is (default) or
628  // the user may want an automatic scale of the Y axis such that the
629  // data displayed in the new X axis range are full scale on the Y
630  // axis. For this, the Shift modifier key should be pressed.
631 
632  if(m_context.m_keyboardModifiers & Qt::ShiftModifier)
633  {
634 
635  // In this case, we want to make a rescale of the Y axis such that
636  // it displays full scale the data in the current X axis range only.
637 
638  bool ok = false;
639 
640  QCPRange value_range = getValueRangeOnKeyRange(nullptr, ok);
641 
642  yAxis->setRange(value_range);
643  }
644  // else, do leave the Y axis range unchanged.
645  }
646  // End of
647  // if(m_context.m_wasClickOnXAxis)
648  else // that is, if(m_context.m_wasClickOnYAxis)
649  {
650  // We are changing the range of the Y axis.
651 
652  // What is the y delta ?
653  double yDelta =
655 
656  // See above for an explanation of the computation.
657 
658  yAxis->setRange(yLower, yUpper - yDelta);
659 
660  // Old version
661  // if(yDelta < 0)
662  //{
663  //// The dragging operation was from top to bottom, we are enlarging
664  //// the range (thus, we are unzooming the view, since the widget
665  //// always has the same size).
666 
667  // yAxis->setRange(yLower, yUpper + fabs(yDelta));
668  //}
669  // else
670  //{
671  //// The dragging operation was from bottom to top, we are reducing
672  //// the range (thus, we are zooming the view, since the widget
673  //// always has the same size).
674 
675  // yAxis->setRange(yLower, yUpper - fabs(yDelta));
676  //}
677  }
678  // End of
679  // else // that is, if(m_context.m_wasClickOnYAxis)
680 
681  // Update the context with the current axes ranges
682 
684 
686 
687  replot();
688 }
689 
690 
691 void
693 {
694  //qDebug();
695 
696  // double sorted_start_drag_point_x =
697  // std::min(m_context.m_startDragPoint.x(), m_context.m_currentDragPoint.x());
698 
699  // xAxis->setRange(sorted_start_drag_point_x,
700  // sorted_start_drag_point_x + fabs(m_context.m_xDelta));
701 
702  xAxis->setRange(
704 
705  // Note that the y axis should be rescaled from current lower value to new
706  // upper value matching the y-axis position of the cursor when the mouse
707  // button was released.
708 
709  yAxis->setRange(xAxis->range().lower,
710  std::max<double>(m_context.m_yRegionRangeStart,
712 
713  // qDebug() << "xaxis:" << xAxis->range().lower << "-" <<
714  // xAxis->range().upper
715  //<< "yaxis:" << yAxis->range().lower << "-" << yAxis->range().upper;
716 
717  // If the shift modifier key is pressed, then the user want the y axis
718  // to be full scale.
719  if(m_context.m_keyboardModifiers & Qt::ShiftModifier)
720  {
721 
722  bool ok = false;
723 
724  QCPRange value_range = getValueRangeOnKeyRange(nullptr, ok);
725 
726  yAxis->setRange(value_range);
727  }
728  // else do nothing, let the y axis range as is.
729 
731 
734 
735  replot();
736 }
737 
738 
739 void
741 {
742 
743  // Use the m_context.m_xRegionRangeStart/End values, but we need to sort the
744  // values before using them, because now we want to really have the lower x
745  // value. Simply craft a QCPRange that will swap the values if lower is not
746  // < than upper QCustomPlot calls this normalization).
747 
748  xAxis->setRange(
750 
751  // If the shift modifier key is pressed, then the user want the y axis
752  // to be full scale.
753  if(m_context.m_keyboardModifiers & Qt::ShiftModifier)
754  {
755 
756  bool ok = false;
757 
758  QCPRange value_range = getValueRangeOnKeyRange(nullptr, ok);
759 
760  yAxis->setRange(value_range);
761  }
762  else
763  yAxis->setRange(
765 
767 
770 
771  replot();
772 }
773 
774 void
776 {
777  //qDebug();
778 
779  // Sanity check
781  qFatal(
782  "This function can only be called if the mouse click was on one of the "
783  "axes");
784 
786  {
787  xAxis->setRange(m_context.m_xRange.lower - m_context.m_xDelta,
789 
790  // If the shift modifier key is pressed, then the user want the y axis
791  // to be full scale.
792  if(m_context.m_keyboardModifiers & Qt::ShiftModifier)
793  {
794 
795  bool ok = false;
796 
797  QCPRange value_range = getValueRangeOnKeyRange(nullptr, ok);
798 
799  yAxis->setRange(value_range);
800  }
801  // else nothing to do we do not change the y axis scale.
802  }
803 
805  {
806  yAxis->setRange(m_context.m_yRange.lower - m_context.m_yDelta,
808  }
809 
811 
812  //qDebug() << "The updated context:" << m_context.toString();
813 
814  // We cannot store the new ranges in the history, because the pan operation
815  // involved a huge quantity of micro-movements elicited upon each mouse move
816  // cursor event so we would have a huge history.
817  // updateAxesRangeHistory();
818 
819  // Now that the contex has the right range values, we can emit the
820  // signal that will be used by this plot widget users, typically to
821  // abide by the x/y range lock required by the user.
822 
824 
825  replot();
826 }
827 
828 
831 {
832  QCPGraph *graph_p = graph(index);
833 
834  return toTrace(graph_p);
835 }
836 
837 
839 BaseTracePlotWidget::toTrace(const QCPGraph *graph_p) const
840 {
841  if(graph_p == nullptr)
842  qFatal("Programming error. Pointer cannot be nullptr.");
843 
844  pappso::Trace trace;
845 
846  QSharedPointer<QCPGraphDataContainer> graph_data_container_p =
847  graph_p->data();
848 
849  // Iterate in the keys
850  auto beginIt = graph_data_container_p->begin();
851  auto endIt = graph_data_container_p->end();
852 
853  for(auto iter = beginIt; iter != endIt; ++iter)
854  trace.push_back(pappso::DataPoint(iter->key, iter->value));
855 
856  return trace;
857 }
858 
859 
861 BaseTracePlotWidget::toTrace(const QCPRange &x_axis_range, int index) const
862 {
863  QCPGraph *graph_p = graph(index);
864 
865  if(graph_p == nullptr)
866  qFatal("Programming error.");
867 
868  return toTrace(x_axis_range, graph_p);
869 }
870 
871 
873 BaseTracePlotWidget::toTrace(const QCPRange &x_axis_range,
874  const QCPGraph *graph_p) const
875 {
876 
877  // Make a Trace with the data in the range.
878  Trace data_trace;
879 
880  QSharedPointer<QCPGraphDataContainer> graph_data_container_sp;
881 
882  graph_data_container_sp = graph_p->data();
883 
884  // Grab the iterator to the start to the x axis range
885  auto beginIt = graph_data_container_sp->findBegin(x_axis_range.lower,
886  /*expandedRange*/ true);
887  // Grab the iterator to the end of the axis range
888  auto endIt = graph_data_container_sp->findEnd(x_axis_range.upper,
889  /*expandedRange*/ true);
890 
891  for(auto iter = beginIt; iter != endIt; ++iter)
892  data_trace.push_back(DataPoint(iter->key, iter->value));
893 
894  return data_trace;
895 }
896 
897 
898 } // namespace pappso
Qt::KeyboardModifiers m_keyboardModifiers
Qt::MouseButtons m_pressedMouseButtons
virtual void updateAxesRangeHistory()
Create new axis range history items and append them to the history.
virtual void createAllAncillaryItems()
QPen m_pen
Pen used to draw the graph and textual elements in the plot widget.
virtual void resetAxesRangeHistory()
virtual void updateContextXandYAxisRanges()
void plottableSelectionChangedSignal(QCPAbstractPlottable *plottable_p, bool selected)
void plotRangesChangedSignal(const BasePlotContext &context)
BasePlotContext m_context
QCPRange getValueRangeOnKeyRange(QCPAbstractPlottable *plottable_p, bool &ok)
virtual bool findIntegrationLowerRangeForKey(int index, double key, QCPRange &range)
Find a minimal integration range starting at an existing data point.
virtual void axisDoubleClickHandler(QCPAxis *axis, QCPAxis::SelectablePart part, QMouseEvent *event) override
virtual void axisRescale() override
RANGE-related functions.
virtual ~BaseTracePlotWidget()
Destruct this BaseTracePlotWidget instance.
virtual void setGraphData(int graph_index, const std::vector< double > &keys, const std::vector< double > &values)
std::vector< double > getValuesY(int index) const
BaseTracePlotWidget(QWidget *parent=0)
virtual QCPGraph * addTrace(const pappso::Trace &trace, const QColor &color)
std::vector< double > getValuesX(int index) const
virtual void axisPan() override
virtual void axisZoom() override
virtual void clearGraphData(int graph_index)
pappso::Trace toTrace(int index) const
double getYatX(double x, QCPGraph *graph_p)
virtual void axisReframe() override
A simple container of DataPoint instances.
Definition: trace.h:148
std::vector< pappso_double > xValues() const
Definition: trace.cpp:623
std::vector< pappso_double > yValues() const
Definition: trace.cpp:637
tries to keep as much as possible monoisotopes, removing any possible C13 peaks and changes multichar...
Definition: aa.cpp:39