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
40namespace 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
106void
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
120void
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
168void
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
184QCPGraph *
185BaseTracePlotWidget::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*/
270bool
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)
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
353std::vector<double>
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
377std::vector<double>
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
401QCPRange
402BaseTracePlotWidget::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
458QCPRange
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
476double
477BaseTracePlotWidget::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
492double
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
504void
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
574void
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
694void
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
742void
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
777void
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
842BaseTracePlotWidget::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
864BaseTracePlotWidget::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
876BaseTracePlotWidget::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:147
std::vector< pappso_double > xValues() const
Definition: trace.cpp:603
std::vector< pappso_double > yValues() const
Definition: trace.cpp:617
tries to keep as much as possible monoisotopes, removing any possible C13 peaks and changes multichar...
Definition: aa.cpp:39