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