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