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