libpappsomspp
Library for mass spectrometry
basecolormapplotwidget.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 "basecolormapplotwidget.h"
36 #include "../../trace/maptrace.h"
37 #include "../../pappsoexception.h"
38 
39 
40 namespace pappso
41 {
42 
43 
45  const QString &x_axis_label,
46  const QString &y_axis_label)
47  : BasePlotWidget(parent, x_axis_label, y_axis_label)
48 {
49  // Do not call createAllAncillaryItems() in this base class because all the
50  // items will have been created *before* the addition of plots and then the
51  // rendering order will hide them to the viewer, since the rendering order is
52  // according to the order in which the items have been created.
53  //
54  // The fact that the ancillary items are created before trace plots is not a
55  // problem because the trace plots are sparse and do not effectively hide the
56  // data.
57  //
58  // But, in the color map plot widgets, we cannot afford to create the
59  // ancillary items *before* the plot itself because then, the rendering of the
60  // plot (created after) would screen off the ancillary items (created before).
61  //
62  // So, the createAllAncillaryItems() function needs to be called in the
63  // derived classes at the most appropriate moment in the setting up of the
64  // widget.
65  //
66  // In the present case, the function needs to be called right after addition
67  // of the color map plot.
68 }
69 
70 
72  : BasePlotWidget(parent, "x", "y")
73 {
74  // Do not call createAllAncillaryItems() in this base class because all the
75  // items will have been created *before* the addition of plots and then the
76  // rendering order will hide them to the viewer, since the rendering order is
77  // according to the order in which the items have been 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.
90  //
91  // In the present case, the function needs to be called right after addition
92  // of the color map plot.
93 }
94 
95 
96 //! Destruct \c this BaseColorMapPlotWidget instance.
97 /*!
98 
99  The destruction involves clearing the history, deleting all the axis range
100  history items for x and y axes.
101 
102 */
104 {
105  if(mpa_origColorMapData != nullptr)
106  delete mpa_origColorMapData;
107 
108  if(mpa_origColorMapPlotConfig != nullptr)
110 }
111 
112 
113 void
115  const ColorMapPlotConfig &color_map_config)
116 {
117  m_colorMapPlotConfig = color_map_config;
118 }
119 
120 
121 const ColorMapPlotConfig *
123 {
125 }
126 
127 
128 const ColorMapPlotConfig &
130 {
131  return m_colorMapPlotConfig;
132 }
133 
134 
135 QCPColorMap *
137  std::shared_ptr<std::map<double, MapTrace>> double_map_trace_map_sp,
138  const ColorMapPlotConfig color_map_plot_config,
139  const QColor &color)
140 {
141  // qDebug() << "Adding color map with config:" <<
142  // color_map_plot_config.toString();
143 
144  if(!color.isValid())
145  throw PappsoException(
146  QString("The color to be used for the plot graph is invalid."));
147 
148  QCPColorMap *color_map_p = new QCPColorMap(xAxis, yAxis);
149 
150  color_map_p->setLayer("plotsLayer");
151 
152  // Do not forget to copy the config!
153  m_colorMapPlotConfig = color_map_plot_config;
154 
155  // Immediately create a copy of the original data for backup.
156  mpa_origColorMapPlotConfig = new ColorMapPlotConfig(color_map_plot_config);
157 
158 #if 0
159  // This is the code on the QCustomPlot documentation and it works fine.
160  QCPColorMap *color_map_p = new QCPColorMap(xAxis, yAxis);
161 
162  color_map_p->data()->setSize(50, 50);
163  color_map_p->data()->setRange(QCPRange(0, 2), QCPRange(0, 2));
164  for(int x = 0; x < 50; ++x)
165  for(int y = 0; y < 50; ++y)
166  color_map_p->data()->setCell(x, y, qCos(x / 10.0) + qSin(y / 10.0));
167  color_map_p->setGradient(QCPColorGradient::gpPolar);
168  color_map_p->rescaleDataRange(true);
169  rescaleAxes();
170  replot();
171 #endif
172 
173  // Only now can afford to call createAllAncillaryItems() in this derived class
174  // because the color map has been created already. The rendering order will
175  // thus not hide the ancillary items, since they have been created after the
176  // color map plot (since the rendering order is according to the
177  // order in which the items have been created). See contructor note.
179 
180  // Connect the signal of selection change so that we can re-emit it for the
181  // widget that is using *this widget.
182 
183  connect(color_map_p,
184  static_cast<void (QCPAbstractPlottable::*)(bool)>(
185  &QCPAbstractPlottable::selectionChanged),
186  [this, color_map_p]() {
187  emit plottableSelectionChangedSignal(color_map_p,
188  color_map_p->selected());
189  });
190 
191  // qDebug() << "Configuring the color map with this config:"
192  //<< color_map_plot_config.toString();
193 
194  color_map_p->data()->setSize(color_map_plot_config.keyCellCount,
195  color_map_plot_config.mzCellCount);
196 
197  color_map_p->data()->setRange(QCPRange(color_map_plot_config.minKeyValue,
198  color_map_plot_config.maxKeyValue),
199  QCPRange(color_map_plot_config.minMzValue,
200  color_map_plot_config.maxMzValue));
201  color_map_p->data()->fill(0.0);
202 
203  // We have now to fill the color map.
204 
205  for(auto &&pair : *double_map_trace_map_sp)
206  {
207 
208  // The first value is the key and the second value is the MapTrace into
209  // which we need to iterated and for each point (double mz, double
210  // intensity) create a map cell.
211 
212  double dt_or_rt_key = pair.first;
213  MapTrace map_trace = pair.second;
214 
215  for(auto &&data_point_pair : map_trace)
216  {
217  double mz = data_point_pair.first;
218  double intensity = data_point_pair.second;
219 
220  // We are filling dynamically the color map. If a cell had already
221  // something in, then we need to take that into account. This is
222  // because we let QCustomPlot handle the fuzzy transition between
223  // color map plot cells.
224 
225  double prev_intensity = color_map_p->data()->data(dt_or_rt_key, mz);
226  double new_intensity = prev_intensity + intensity;
227 
228  // Record the min/max cell intensity value (origM(in/ax)ZValue). We
229  // will need that later. Also update the lastM(in/ax)ZValue because
230  // when doing this kind of data conversion it is assume that the user
231  // actually changes the data.
233  std::min(m_colorMapPlotConfig.origMinZValue, new_intensity));
234 
236  std::max(m_colorMapPlotConfig.origMaxZValue, new_intensity));
237 
238  // qDebug() << "Setting tri-point:" << dt_or_rt_key << "," << mz <<
239  // ","
240  //<< new_intensity;
241 
242  color_map_p->data()->setData(dt_or_rt_key, mz, new_intensity);
243  }
244  }
245 
246  // At this point we have finished filling-up the color map.
247 
248  // The gpThermal is certainly one of the best.
249 
250  color_map_p->setGradient(QCPColorGradient::gpThermal);
251 
252  color_map_p->rescaleDataRange(true);
253 
254  color_map_p->rescaleAxes();
256 
257  // The pen of the color map itself is of no use. Instead the user will see the
258  // color of the axes' labels.
259 
260  QPen pen = xAxis->basePen();
261  pen.setColor(color);
262 
263  xAxis->setBasePen(pen);
264  xAxis->setLabelColor(color);
265  xAxis->setTickLabelColor(color);
266 
267  yAxis->setBasePen(pen);
268  yAxis->setLabelColor(color);
269  yAxis->setTickLabelColor(color);
270 
271  // And now set the color map's pen to the same color, even if we do not use
272  // it, we need it for coloring the plots that might be integrated from this
273  // color map.
274 
275  color_map_p->setPen(pen);
276 
277  // Copy the original color map's data into a backup copy.
278 
279  mpa_origColorMapData = new QCPColorMapData(*(color_map_p->data()));
280 
281  replot();
282 
283  return color_map_p;
284 }
285 
286 QCPColorMap *
288  const TimsFrame &tims_frame,
289  const ColorMapPlotConfig color_map_plot_config,
290  const QColor &color)
291 {
292  qDebug();
293  if(!color.isValid())
294  throw PappsoException(
295  QString("The color to be used for the plot graph is invalid."));
296 
297  QCPColorMap *color_map_p = new QCPColorMap(xAxis, yAxis);
298 
299  color_map_p->setLayer("plotsLayer");
300 
301  // Do not forget to copy the config!
302  m_colorMapPlotConfig = color_map_plot_config;
303 
304  // Immediately create a copy of the original data for backup.
305  mpa_origColorMapPlotConfig = new ColorMapPlotConfig(color_map_plot_config);
306 
307  qDebug();
308 #if 0
309  // This is the code on the QCustomPlot documentation and it works fine.
310  QCPColorMap *color_map_p = new QCPColorMap(xAxis, yAxis);
311 
312  color_map_p->data()->setSize(50, 50);
313  color_map_p->data()->setRange(QCPRange(0, 2), QCPRange(0, 2));
314  for(int x = 0; x < 50; ++x)
315  for(int y = 0; y < 50; ++y)
316  color_map_p->data()->setCell(x, y, qCos(x / 10.0) + qSin(y / 10.0));
317  color_map_p->setGradient(QCPColorGradient::gpPolar);
318  color_map_p->rescaleDataRange(true);
319  rescaleAxes();
320  replot();
321 #endif
322 
323  // Only now can afford to call createAllAncillaryItems() in this derived class
324  // because the color map has been created already. The rendering order will
325  // thus not hide the ancillary items, since they have been created after the
326  // color map plot (since the rendering order is according to the
327  // order in which the items have been created). See contructor note.
329 
330  qDebug();
331  // Connect the signal of selection change so that we can re-emit it for the
332  // widget that is using *this widget.
333 
334  connect(color_map_p,
335  static_cast<void (QCPAbstractPlottable::*)(bool)>(
336  &QCPAbstractPlottable::selectionChanged),
337  [this, color_map_p]() {
338  emit plottableSelectionChangedSignal(color_map_p,
339  color_map_p->selected());
340  });
341 
342  // qDebug() << "Configuring the color map with this config:"
343  //<< color_map_plot_config.toString();
344 
345  color_map_p->data()->setSize(color_map_plot_config.keyCellCount,
346  color_map_plot_config.mzCellCount);
347 
348  color_map_p->data()->setRange(QCPRange(color_map_plot_config.minKeyValue,
349  color_map_plot_config.maxKeyValue),
350  QCPRange(color_map_plot_config.minMzValue,
351  color_map_plot_config.maxMzValue));
352  color_map_p->data()->fill(0.0);
353  // double max_intensity = 0;
354  qDebug();
355  // We have now to fill the color map.
356  std::size_t number_of_scans = tims_frame.getTotalNumberOfScans();
357  for(std::size_t i = 0; i < number_of_scans; i++)
358  {
359  std::vector<quint32> mz_index_vector = tims_frame.getScanIndexList(i);
360  std::vector<quint32> intensity_index_vector =
361  tims_frame.getScanIntensities(i);
362 
363 
364  // The first value is the key and the second value is the MapTrace into
365  // which we need to iterated and for each point (double mz, double
366  // intensity) create a map cell.
367 
368  double dt_or_rt_key = i;
369  std::size_t vector_index = 0;
370  for(quint32 mzindex : mz_index_vector)
371  {
372  double mz = mzindex;
373  double intensity = intensity_index_vector.at(vector_index);
374  // max_intensity = std::max(max_intensity, intensity);
375  // We are filling dynamically the color map. If a cell had already
376  // something in, then we need to take that into account. This is
377  // because we let QCustomPlot handle the fuzzy transition between
378  // color map plot cells.
379 
380  double prev_intensity = color_map_p->data()->data(dt_or_rt_key, mz);
381  double new_intensity = prev_intensity + intensity;
382 
383  // qDebug() << "mz=" << mz << " int=" << intensity;
384 
385  // Record the min/max cell intensity value (origM(in/ax)ZValue). We
386  // will need that later. Also update the lastM(in/ax)ZValue because
387  // when doing this kind of data conversion it is assume that the user
388  // actually changes the data.
390  std::min(m_colorMapPlotConfig.origMinZValue, new_intensity));
391 
393  std::max(m_colorMapPlotConfig.origMaxZValue, new_intensity));
394 
395  // qDebug() << "Setting tri-point:" << dt_or_rt_key << "," << mz <<
396  // ","
397  //<< new_intensity;
398 
399  color_map_p->data()->setCell(dt_or_rt_key, mz, new_intensity);
400 
401  // qDebug() << "dt_or_rt_key=" << dt_or_rt_key << " mz=" << mz
402  // << " new_intensity=" << new_intensity;
403 
404  vector_index++;
405  }
406  }
407 
408  // At this point we have finished filling-up the color map.
409 
410  // The gpThermal is certainly one of the best.
411 
412  color_map_p->setGradient(QCPColorGradient::gpThermal);
413 
414  color_map_p->data()->recalculateDataBounds();
415  color_map_p->rescaleDataRange(true);
416 
417  color_map_p->rescaleAxes();
419 
420  // The pen of the color map itself is of no use. Instead the user will see the
421  // color of the axes' labels.
422 
423  qDebug();
424  QPen pen = xAxis->basePen();
425  pen.setColor(color);
426 
427  xAxis->setBasePen(pen);
428  xAxis->setLabelColor(color);
429  xAxis->setTickLabelColor(color);
430 
431  yAxis->setBasePen(pen);
432  yAxis->setLabelColor(color);
433  yAxis->setTickLabelColor(color);
434 
435  // And now set the color map's pen to the same color, even if we do not use
436  // it, we need it for coloring the plots that might be integrated from this
437  // color map.
438 
439  color_map_p->setPen(pen);
440 
441  // Copy the original color map's data into a backup copy.
442 
443  mpa_origColorMapData = new QCPColorMapData(*(color_map_p->data()));
444 
445  color_map_p->setInterpolate(false);
446  color_map_p->setTightBoundary(false);
447 
448  replot();
449 
450 
451  qDebug() << color_map_p->data()->keyRange();
452  qDebug() << color_map_p->data()->valueRange();
453  qDebug() << color_map_p->data()->dataBounds();
454  qDebug();
455  return color_map_p;
456 }
457 
458 void
460 {
461  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()" ;
462 
463  QCPColorMap *color_map_p = static_cast<QCPColorMap *>(plottable(0));
464 
465  QCPColorMapData *origData = color_map_p->data();
466 
467  int keySize = origData->keySize();
468  int valueSize = origData->valueSize();
469 
470  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
471  //<< "Orig data size:" << keySize << valueSize;
472 
473  QCPRange keyRange = origData->keyRange();
474  QCPRange valueRange = origData->valueRange();
475 
476  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
477  //<< "Value at cell 80,650:" << origData->cell(80,650);
478 
479  // Transposed map.
480  QCPColorMapData *newData =
481  new QCPColorMapData(valueSize, keySize, valueRange, keyRange);
482 
483  for(int iter = 0; iter < keySize; ++iter)
484  {
485  for(int jter = 0; jter < valueSize; ++jter)
486  {
487  double cellData = origData->cell(iter, jter);
488 
489  newData->setCell(jter, iter, cellData);
490  }
491  }
492 
493  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
494  //<< "New data size:" << newData->keySize() << newData->valueSize();
495 
496  // At this point the transposition has been done.
497 
498  color_map_p->data()->clear();
499  color_map_p->rescaleDataRange(true);
500 
501  // Now we need to invert the labels and data kinds.
502 
505  m_colorMapPlotConfig.yAxisDataKind = temp_data_kind;
506 
507  QString temp_axis_label = xAxis->label();
508  xAxis->setLabel(yAxis->label());
509  yAxis->setLabel(temp_axis_label);
510 
511  // Will take ownership of the newData.
512  color_map_p->setData(newData);
513 
514  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()"
515  //<< "Value at cell 80,650:" << newData->cell(80,650)
516  //<< "Value at cell 650, 80:" << newData->cell(650,80);
517 
518  // QCPAxis *p_keyAxis = mp_colorMap->keyAxis();
519  // QCPAxis *p_valueAxis = mp_colorMap->valueAxis();
520 
521  // mp_colorMap->setKeyAxis(p_valueAxis);
522  // mp_colorMap->setValueAxis(p_keyAxis);
523 
524  color_map_p->rescaleAxes();
525 
526  replot();
527 }
528 
529 
530 void
532 {
533  // The user wants to rescale the intensity values of the color map according
534  // to: new_int = log10(orig_int).
535 
536  // qDebug() << __FILE__ << __LINE__ << __FUNCTION__ << "()" ;
537 
539  {
540  qDebug() << "Asking to change z axis scale to log10 while it is already "
541  "like so.";
542 
543  return;
544  }
545 
546  // qDebug() << "m_colorMapPlotConfig:" << m_colorMapPlotConfig.toString();
547 
548  QCPColorMap *color_map_p = static_cast<QCPColorMap *>(plottable(0));
549 
550  QCPColorMapData *map_data = color_map_p->data();
551 
552  int keySize = map_data->keySize();
553  int valueSize = map_data->valueSize();
554 
555  QCPRange keyRange = map_data->keyRange();
556  QCPRange valueRange = map_data->valueRange();
557 
558  // Make a copy of the current config so that we can modify
559  // the xxxZvalue values.
560  ColorMapPlotConfig new_color_map_plot_config(m_colorMapPlotConfig);
561 
562  // But we need to reset these two values to be able to update them using
563  // std::min() and std::max() below.
564  new_color_map_plot_config.setOrigAndLastMinZValue(
565  std::numeric_limits<double>::max());
566 
567  new_color_map_plot_config.setOrigAndLastMaxZValue(
568  std::numeric_limits<double>::min());
569 
570  // qDebug() << "new_color_map_plot_config"
571  //<< new_color_map_plot_config.toString();
572 
573  // Log-ified heat map.
574  QCPColorMapData *new_map_data =
575  new QCPColorMapData(keySize, valueSize, keyRange, valueRange);
576 
577  // qDebug() << "Starting iteration in the color map.";
578 
579  for(int iter = 0; iter < keySize; ++iter)
580  {
581  for(int jter = 0; jter < valueSize; ++jter)
582  {
583  double cell_data = map_data->cell(iter, jter);
584 
585  double new_cell_data = 0;
586 
587  if(!cell_data)
588  // The log10 would be -inf, but then we'd have a huge data range and
589  // the color map would look totally blue... that is like 0 intensity
590  // all over.
591  new_cell_data = -1;
592  else
593  new_cell_data = std::log10(cell_data);
594 
595  // Store the new values here. Should we change the last or orig or
596  // both ?
597  new_color_map_plot_config.lastMinZValue =
598  //(new_cell_data < new_color_map_plot_config.minZValue
599  //? new_cell_data
600  //: new_color_map_plot_config.minZValue);
601  std::min(new_color_map_plot_config.lastMinZValue, new_cell_data);
602 
603  new_color_map_plot_config.lastMaxZValue =
604  //(new_cell_data > new_color_map_plot_config.maxZValue
605  //? new_cell_data
606  //: new_color_map_plot_config.maxZValue);
607  std::max(new_color_map_plot_config.lastMaxZValue, new_cell_data);
608 
609  // qDebug() << "cell_data:" << cell_data
610  //<< "new_cell_data:" << new_cell_data
611  //<< "new_color_map_plot_config.minZValue:"
612  //<< new_color_map_plot_config.minZValue
613  //<< "new_color_map_plot_config.maxZValue:"
614  //<< new_color_map_plot_config.maxZValue;
615 
616  new_map_data->setCell(iter, jter, new_cell_data);
617  }
618  }
619 
620  // qDebug() << "Finished iteration in the color map.";
621 
622  color_map_p->data()->clear();
623 
624  // Will take ownership of the new_map_data.
625  color_map_p->setData(new_map_data);
626 
627  color_map_p->data()->recalculateDataBounds();
628  color_map_p->rescaleDataRange(true);
629 
630  // At this point the new color map data have taken their place, we can update
631  // the config. This, way any new filtering can take advantage of the new
632  // values and compute the threshold correctly.
633  m_colorMapPlotConfig = new_color_map_plot_config;
634 
635  // Now we need to document the change.
637 
638  // qDebug() << "new_color_map_plot_config"
639  //<< new_color_map_plot_config.toString();
640 
641  // qDebug() << "m_colorMapPlotConfig:" << m_colorMapPlotConfig.toString();
642 
643  // We should not do this, as the user might have zoomed to a region of
644  // interest.
645  // color_map_p->rescaleAxes();
646 
647  replot();
648 }
649 
650 void
652  double threshold_percentage)
653 {
654  // This filter allows all the values smaller than a threshold to remain
655  // unchanged. Instead, all the values above the threshold will be reset to
656  // that threshold.
657  //
658  // The effect of this filter is to enhance the high-intensity signal.
659 
660  QCPColorMap *color_map_p = static_cast<QCPColorMap *>(plottable(0));
661 
662  QCPColorMapData *map_data = color_map_p->data();
663 
664  int keySize = map_data->keySize();
665  int valueSize = map_data->valueSize();
666 
667  QCPRange keyRange = map_data->keyRange();
668  QCPRange valueRange = map_data->valueRange();
669 
670  double minZValue = m_colorMapPlotConfig.lastMinZValue;
671  double maxZValue = m_colorMapPlotConfig.lastMaxZValue;
672 
673  double amplitude = maxZValue - minZValue;
674 
675  double amplitude_fraction = amplitude * threshold_percentage / 100;
676 
677  double threshold = minZValue + amplitude_fraction;
678 
679  // qDebug() << "Before filtering minZValue:" << minZValue
680  //<< "maxZValue:" << maxZValue << "fraction:" << fraction
681  //<< "threshold:" << threshold
682  //<< "new threshold percentage:" << new_threshold_percentage;
683 
684  // Make a copy of the current config so that we can modify
685  // the xxxZvalue values.
686  ColorMapPlotConfig new_color_map_plot_config(m_colorMapPlotConfig);
687 
688  // But we need to reset these two values to be able to update them using
689  // std::min() and std::max() below.
690  new_color_map_plot_config.lastMinZValue = std::numeric_limits<double>::max();
691  new_color_map_plot_config.lastMaxZValue = std::numeric_limits<double>::min();
692 
693  // Filtered
694  QCPColorMapData *new_map_data =
695  new QCPColorMapData(keySize, valueSize, keyRange, valueRange);
696 
697  for(int iter = 0; iter < keySize; ++iter)
698  {
699  for(int jter = 0; jter < valueSize; ++jter)
700  {
701  double cell_data = map_data->cell(iter, jter);
702 
703  double new_cell_data = 0;
704 
705  if(cell_data < threshold)
706  // Keep the value, we are in low-pass
707  new_cell_data = cell_data;
708  else
709  new_cell_data = threshold;
710 
711  // Store the new values here.
712  new_color_map_plot_config.lastMinZValue =
713  //(new_cell_data < new_color_map_plot_config.minZValue
714  //? new_cell_data
715  //: new_color_map_plot_config.minZValue);
716  std::min(new_color_map_plot_config.lastMinZValue, new_cell_data);
717 
718  new_color_map_plot_config.lastMaxZValue =
719  //(new_cell_data > new_color_map_plot_config.maxZValue
720  //? new_cell_data
721  //: new_color_map_plot_config.maxZValue);
722  std::max(new_color_map_plot_config.lastMaxZValue, new_cell_data);
723 
724  // qDebug() << "cell_data:" << cell_data
725  //<< "new_cell_data:" << new_cell_data
726  //<< "new_color_map_plot_config.minZValue:"
727  //<< new_color_map_plot_config.minZValue
728  //<< "new_color_map_plot_config.maxZValue:"
729  //<< new_color_map_plot_config.maxZValue;
730 
731  new_map_data->setCell(iter, jter, new_cell_data);
732  }
733  }
734 
735  color_map_p->data()->clear();
736 
737  // Will take ownership of the new_map_data.
738  color_map_p->setData(new_map_data);
739 
740  color_map_p->data()->recalculateDataBounds();
741  color_map_p->rescaleDataRange(true);
742 
743 
744  // At this point the new color map data have taken their place, we can update
745  // the config. This, way any new filtering can take advantage of the new
746  // values and compute the threshold correctly.
747  m_colorMapPlotConfig = new_color_map_plot_config;
748 
749  // qDebug() << "Member colormap plot config is now, after filter was applied:"
750  //<< m_colorMapPlotConfig.toString();
751 
752  // We should not do this, as the user might have zoomed to a region of
753  // interest.
754  // color_map_p->rescaleAxes();
755 
756  replot();
757 }
758 
759 
760 void
762 {
763 
764  // This filter allows all the values smaller than a threshold to remain
765  // unchanged. Instead, all the values above the threshold will be reset to
766  // that threshold.
767 
768  QCPColorMap *color_map_p = static_cast<QCPColorMap *>(plottable(0));
769 
770  QCPColorMapData *map_data = color_map_p->data();
771 
772  int keySize = map_data->keySize();
773  int valueSize = map_data->valueSize();
774 
775  QCPRange keyRange = map_data->keyRange();
776  QCPRange valueRange = map_data->valueRange();
777 
778  // qDebug() << "Before filtering minZValue:" << minZValue
779  //<< "maxZValue:" << maxZValue << "fraction:" << fraction
780  //<< "threshold:" << threshold
781  //<< "new threshold percentage:" << new_threshold_percentage;
782 
783  // Make a copy of the current config so that we can modify
784  // the xxxZvalue values.
785  ColorMapPlotConfig new_color_map_plot_config(m_colorMapPlotConfig);
786 
787  // But we need to reset these two values to be able to update them using
788  // std::min() and std::max() below.
789  new_color_map_plot_config.lastMinZValue = std::numeric_limits<double>::max();
790  new_color_map_plot_config.lastMaxZValue = std::numeric_limits<double>::min();
791 
792  // Filtered
793  QCPColorMapData *new_map_data =
794  new QCPColorMapData(keySize, valueSize, keyRange, valueRange);
795 
796  for(int iter = 0; iter < keySize; ++iter)
797  {
798  for(int jter = 0; jter < valueSize; ++jter)
799  {
800  double cell_data = map_data->cell(iter, jter);
801 
802  double new_cell_data = 0;
803 
804  if(cell_data < threshold)
805  // Keep the value, we are in low-pass
806  new_cell_data = cell_data;
807  else
808  new_cell_data = threshold;
809 
810  // Store the new values here.
811  new_color_map_plot_config.lastMinZValue =
812  //(new_cell_data < new_color_map_plot_config.minZValue
813  //? new_cell_data
814  //: new_color_map_plot_config.minZValue);
815  std::min(new_color_map_plot_config.lastMinZValue, new_cell_data);
816 
817  new_color_map_plot_config.lastMaxZValue =
818  //(new_cell_data > new_color_map_plot_config.maxZValue
819  //? new_cell_data
820  //: new_color_map_plot_config.maxZValue);
821  std::max(new_color_map_plot_config.lastMaxZValue, new_cell_data);
822 
823  // qDebug() << "cell_data:" << cell_data
824  //<< "new_cell_data:" << new_cell_data
825  //<< "new_color_map_plot_config.minZValue:"
826  //<< new_color_map_plot_config.minZValue
827  //<< "new_color_map_plot_config.maxZValue:"
828  //<< new_color_map_plot_config.maxZValue;
829 
830  new_map_data->setCell(iter, jter, new_cell_data);
831  }
832  }
833 
834  color_map_p->data()->clear();
835 
836  // Will take ownership of the new_map_data.
837  color_map_p->setData(new_map_data);
838 
839  color_map_p->data()->recalculateDataBounds();
840  color_map_p->rescaleDataRange(true);
841 
842 
843  // At this point the new color map data have taken their place, we can update
844  // the config. This, way any new filtering can take advantage of the new
845  // values and compute the threshold correctly.
846  m_colorMapPlotConfig = new_color_map_plot_config;
847 
848  // qDebug() << "Member colormap plot config is now, after filter was applied:"
849  //<< m_colorMapPlotConfig.toString();
850 
851  // We should not do this, as the user might have zoomed to a region of
852  // interest.
853  // color_map_p->rescaleAxes();
854 
855  replot();
856 }
857 
858 void
860  double threshold_percentage)
861 {
862  // This filter allows all the value greater than a threshold to remain
863  // unchanged. Instead, all the values below the threshold will be reset to
864  // that threshold value.
865  //
866  // The effect of this filter is to reduce the low-intensity signal: reduce
867  // noise.
868 
869  QCPColorMap *color_map_p = static_cast<QCPColorMap *>(plottable(0));
870 
871  QCPColorMapData *map_data = color_map_p->data();
872 
873  int keySize = map_data->keySize();
874  int valueSize = map_data->valueSize();
875 
876  QCPRange keyRange = map_data->keyRange();
877  QCPRange valueRange = map_data->valueRange();
878 
879  double minZValue = m_colorMapPlotConfig.lastMinZValue;
880  double maxZValue = m_colorMapPlotConfig.lastMaxZValue;
881 
882  double amplitude = maxZValue - minZValue;
883 
884  double amplitude_fraction = amplitude * threshold_percentage / 100;
885 
886  double threshold = minZValue + amplitude_fraction;
887 
888  // qDebug() << "Before filtering minZValue:" << minZValue
889  //<< "maxZValue:" << maxZValue << "fraction:" << fraction
890  //<< "threshold:" << threshold
891  //<< "new threshold percentage:" << new_threshold_percentage;
892 
893  // Make a copy of the current config so that we can modify
894  // the xxxZvalue values.
895  ColorMapPlotConfig new_color_map_plot_config(m_colorMapPlotConfig);
896 
897  // But we need to reset these two values to be able to update them using
898  // std::min() and std::max() below.
899  new_color_map_plot_config.lastMinZValue = std::numeric_limits<double>::max();
900  new_color_map_plot_config.lastMaxZValue = std::numeric_limits<double>::min();
901 
902  // Filtered
903  QCPColorMapData *new_map_data =
904  new QCPColorMapData(keySize, valueSize, keyRange, valueRange);
905 
906  for(int iter = 0; iter < keySize; ++iter)
907  {
908  for(int jter = 0; jter < valueSize; ++jter)
909  {
910  double cell_data = map_data->cell(iter, jter);
911 
912  double new_cell_data = 0;
913 
914  if(cell_data > threshold)
915  // Keep the value, we are in high-pass
916  new_cell_data = cell_data;
917  else
918  new_cell_data = threshold;
919 
920  // Store the new values here.
921  new_color_map_plot_config.lastMinZValue =
922  //(new_cell_data < new_color_map_plot_config.minZValue
923  //? new_cell_data
924  //: new_color_map_plot_config.minZValue);
925  std::min(new_color_map_plot_config.lastMinZValue, new_cell_data);
926 
927  new_color_map_plot_config.lastMaxZValue =
928  //(new_cell_data > new_color_map_plot_config.maxZValue
929  //? new_cell_data
930  //: new_color_map_plot_config.maxZValue);
931  std::max(new_color_map_plot_config.lastMaxZValue, new_cell_data);
932 
933  // qDebug() << "cell_data:" << cell_data
934  //<< "new_cell_data:" << new_cell_data
935  //<< "new_color_map_plot_config.minZValue:"
936  //<< new_color_map_plot_config.minZValue
937  //<< "new_color_map_plot_config.maxZValue:"
938  //<< new_color_map_plot_config.maxZValue;
939 
940  new_map_data->setCell(iter, jter, new_cell_data);
941  }
942  }
943 
944  color_map_p->data()->clear();
945 
946  // Will take ownership of the new_map_data.
947  color_map_p->setData(new_map_data);
948 
949  color_map_p->data()->recalculateDataBounds();
950  color_map_p->rescaleDataRange(true);
951 
952 
953  // At this point the new color map data have taken their place, we can update
954  // the config. This, way any new filtering can take advantage of the new
955  // values and compute the threshold correctly.
956  m_colorMapPlotConfig = new_color_map_plot_config;
957 
958  // qDebug() << "Member colormap plot config is now, after filter was applied:"
959  //<< m_colorMapPlotConfig.toString();
960 
961  // We should not do this, as the user might have zoomed to a region of
962  // interest.
963  // color_map_p->rescaleAxes();
964 
965  replot();
966 }
967 
968 
969 void
971 {
972  // The user might have changed to the axis scale to log10, for example.
973  // While doing this, the original data were still available in
974  // mpa_origColorMapData,with mpa_origColorMapPlotConfig. We need to reset the
975  // current data to the original data.
976  //
977  // Same thing for filters that might have been applied to the data.
978 
979  QCPColorMap *color_map_p = static_cast<QCPColorMap *>(plottable(0));
980  color_map_p->data()->clear();
981 
982  if(mpa_origColorMapData == nullptr)
983  throw(PappsoException(
984  "Not possible that the mpa_origColorMapData pointer be null."));
985 
986  // We do no want that the color_map_p takes ownership of the data, because
987  // these must remain there always, so pass true, to say that we want to copy
988  // the data not transfer the pointer.
989  color_map_p->setData(mpa_origColorMapData, true);
990 
991  color_map_p->data()->recalculateDataBounds();
992  color_map_p->rescaleDataRange(true);
993 
994  // We should not do this, as the user might have zoomed to a region of
995  // interest.
996  // color_map_p->rescaleAxes();
997 
998  // Reset the current plot config to what it was originally. The member
999  // m_colorMapPlotConfig.zAxisScale is now AxisScale::orig.
1001 
1002  replot();
1003 }
1004 
1005 
1006 DataKind
1008 {
1010 }
1011 
1012 
1013 DataKind
1015 {
1017 }
1018 
1019 
1020 AxisScale
1022 {
1023  if(axis == Axis::x)
1025  else if(axis == Axis::y)
1027  else if(axis == Axis::z)
1029  else
1030  throw PappsoException(
1031  QString("basecolormapplotwidget.cpp: The axis cannot be different than "
1032  "x, y or z."));
1033 
1034  return AxisScale::unset;
1035 }
1036 
1037 
1038 AxisScale
1040 {
1042 }
1043 
1044 
1045 AxisScale
1047 {
1049 }
1050 
1051 
1052 AxisScale
1054 {
1056 }
1057 
1058 
1059 void
1060 BaseColorMapPlotWidget::setPlottingColor(QCPAbstractPlottable *plottable_p,
1061  const QColor &new_color)
1062 {
1063  Q_UNUSED(plottable_p);
1064 
1065  // The pen of the color map itself is of no use. Instead the user will see the
1066  // color of the axes' labels.
1067 
1068  QPen pen = xAxis->basePen();
1069  pen.setColor(new_color);
1070 
1071  xAxis->setBasePen(pen);
1072  xAxis->setLabelColor(new_color);
1073  xAxis->setTickLabelColor(new_color);
1074 
1075  yAxis->setBasePen(pen);
1076  yAxis->setLabelColor(new_color);
1077  yAxis->setTickLabelColor(new_color);
1078 
1079  // And now set the color map's pen to the same color, even if we do not use
1080  // it, we need it for coloring the plots that might be integrated from this
1081  // color map.
1082 
1083  QCPColorMap *color_map_p = static_cast<QCPColorMap *>(plottable(0));
1084 
1085  color_map_p->setPen(pen);
1086 
1087  replot();
1088 }
1089 
1090 
1091 QColor
1093 {
1094  Q_UNUSED(index);
1095 
1096  QPen pen = xAxis->basePen();
1097  return pen.color();
1098 }
1099 
1100 
1101 void
1103 {
1104  // We want to limit the ranges to the visible data range in the plot widget.
1105 
1106  QCPColorMap *color_map_p = static_cast<QCPColorMap *>(plottable(0));
1107  QCPColorMapData *map_data = color_map_p->data();
1108 
1109  bool found_range = false;
1110 
1111  // Get the full data set DT values range because if the context contains no
1112  // values for the currently displayed ranges, then we fall back to them;
1113  QCPRange full_data_range = color_map_p->getKeyRange(found_range);
1114 
1115  if(!found_range)
1116  {
1117  qDebug() << "The range was not found";
1118  return;
1119  }
1120 
1121  // qDebug() << "Full key data range:" << full_data_range.lower << "-"
1122  //<< full_data_range.upper;
1123 
1124  // But what we actually want is the currently visible axes ranges. And these
1125  // are stored in the context.
1126 
1127  double visible_data_range_lower = m_context.m_xRange.lower;
1128  double visible_data_range_upper = m_context.m_xRange.upper;
1129 
1130  // qDebug() << "Visible key data range:" << visible_data_range_lower << "-"
1131  //<< visible_data_range_upper;
1132 
1133  // Note that if there has been *no* panning, rescale, nothing, with the color
1134  // map, then the context has no idea of the ranges. So we need to check that.
1135  // If that is the case, then we use the full key range as the full plot is
1136  // displayed full scale upon its first showing.
1137 
1138  if(!visible_data_range_lower || !visible_data_range_upper)
1139  {
1140  visible_data_range_lower = full_data_range.lower;
1141  visible_data_range_upper = full_data_range.upper;
1142  }
1143 
1144  // qDebug() << "Visible key range:" << visible_data_range_lower << "-"
1145  //<< visible_data_range_upper;
1146 
1147  // And now convert the double value ranges into cell indices, which is what we
1148  // are being asked for.
1149 
1150  map_data->coordToCell(visible_data_range_lower, 0, &lower, nullptr);
1151  map_data->coordToCell(visible_data_range_upper, 0, &upper, nullptr);
1152 
1153  // qDebug() << "Cell indices for currently visible key range:" << lower << "-"
1154  //<< upper;
1155 }
1156 
1157 
1158 void
1160 {
1161  // We want to limit the ranges to the visible data range in the plot widget.
1162 
1163  QCPColorMap *color_map_p = static_cast<QCPColorMap *>(plottable(0));
1164  QCPColorMapData *map_data = color_map_p->data();
1165 
1166  bool found_range = false;
1167 
1168  // Get the full data set MZ values range because if the context contains no
1169  // values for the currently displayed ranges, then we fall back to them;
1170  QCPRange full_data_range = color_map_p->getValueRange(found_range);
1171 
1172  if(!found_range)
1173  {
1174  qDebug() << "The range was not found";
1175  return;
1176  }
1177 
1178  // qDebug() << "Full value data range:" << full_data_range.lower << "-"
1179  //<< full_data_range.upper;
1180 
1181  // But what we actually want is the currently visible axes ranges. And these
1182  // are stored in the context.
1183 
1184  double visible_data_range_lower = m_context.m_yRange.lower;
1185  double visible_data_range_upper = m_context.m_yRange.upper;
1186 
1187  // qDebug() << "Visible value data range:" << visible_data_range_lower << "-"
1188  //<< visible_data_range_upper;
1189 
1190  // Note that if there has been *no* panning, rescale, nothing, with the color
1191  // map, then the context has no idea of the ranges. So we need to check that.
1192  // If that is the case, then we use the full key range as the full plot is
1193  // displayed full scale upon its first showing.
1194 
1195  if(!visible_data_range_lower || !visible_data_range_upper)
1196  {
1197  visible_data_range_lower = full_data_range.lower;
1198  visible_data_range_upper = full_data_range.upper;
1199  }
1200 
1201  // qDebug() << "Final visible value data range:" << visible_data_range_lower
1202  //<< "-" << visible_data_range_upper;
1203 
1204  // And now convert the double value ranges into cell indices, which is what we
1205  // are being asked for.
1206 
1207  map_data->coordToCell(0, visible_data_range_lower, nullptr, &lower);
1208  map_data->coordToCell(0, visible_data_range_upper, nullptr, &upper);
1209 
1210  // qDebug() << "Cell indices for currently visible value range:" << lower <<
1211  // "-"
1212  //<< upper;
1213 }
1214 
1215 
1216 void
1218 {
1219  // We want to export the data to a string in the x y z format, with
1220  // x=key (cell's x coordinate)
1221  // y=value (cell's y coordinate)
1222  // z=intensity (cell value)
1223 
1224  QCPColorMap *color_map_p = static_cast<QCPColorMap *>(plottable(0));
1225  QCPColorMapData *map_data = color_map_p->data();
1226 
1227  int key_index_lower_range;
1228  int key_index_upper_range;
1229  currentXaxisRangeIndices(key_index_lower_range, key_index_upper_range);
1230 
1231  // qDebug() << "Cell indices for currently visible key range:"
1232  //<< key_index_lower_range << "-" << key_index_upper_range;
1233 
1234  int value_index_lower_range;
1235  int value_index_upper_range;
1236  currentYaxisRangeIndices(value_index_lower_range, value_index_upper_range);
1237 
1238  // qDebug() << "Cell indices for currently visible value range:"
1239  //<< value_index_lower_range << "-" << value_index_upper_range;
1240 
1241  data_string.clear();
1242  QString debug_string;
1243 
1244  // Iterate in the matrix' key axis (DT, for example)
1245  for(int key_iter = key_index_lower_range; key_iter < key_index_upper_range;
1246  ++key_iter)
1247  {
1248  // Iterate in the matrix' value axis (MZ, for example)
1249  for(int value_iter = value_index_lower_range;
1250  value_iter < value_index_upper_range;
1251  ++value_iter)
1252  {
1253  // This would be the DT value (x axis)
1254  double key;
1255 
1256  // This would be the MZ value (y axis)
1257  double value;
1258 
1259  map_data->cellToCoord(key_iter, value_iter, &key, &value);
1260 
1261  data_string +=
1262  QString("%1 %2 %3\n")
1263  .arg(key, 0, 'f', 6, ' ')
1264  .arg(value, 0, 'f', 6, ' ')
1265  // The intensity without decimals
1266  .arg(map_data->cell(key_iter, value_iter), 0, 'f', 0, ' ');
1267  }
1268  }
1269 
1270  // qDebug() << "The completed data string has size: " << data_string.size();
1271 }
1272 
1273 
1274 void
1275 BaseColorMapPlotWidget::dataToMatrixString(QString &data_string, bool detailed)
1276 {
1277  // We want to export the data in the form of a matrix, exactly as the data
1278  // appear within the colormap, unless the color is replaced with the intensity
1279  // value.
1280 
1281  // We want to limit the export to the visible data range in the plot widget.
1282 
1283  QCPColorMap *color_map_p = static_cast<QCPColorMap *>(plottable(0));
1284  QCPColorMapData *map_data = color_map_p->data();
1285 
1286  int key_index_lower_range;
1287  int key_index_upper_range;
1288  currentXaxisRangeIndices(key_index_lower_range, key_index_upper_range);
1289 
1290  // qDebug() << "Cell indices for currently visible key range:"
1291  //<< key_index_lower_range << "-" << key_index_upper_range;
1292 
1293  int value_index_lower_range;
1294  int value_index_upper_range;
1295  currentYaxisRangeIndices(value_index_lower_range, value_index_upper_range);
1296 
1297  // qDebug() << "Cell indices for currently visible value range:"
1298  //<< value_index_lower_range << "-" << value_index_upper_range;
1299 
1300  data_string.clear();
1301 
1302  // At this point, we can write the header of the key data (that is the dt
1303  // key values).
1304 
1305  for(int key_iter = key_index_lower_range; key_iter < key_index_upper_range;
1306  ++key_iter)
1307  {
1308  double current_key_value;
1309  map_data->cellToCoord(key_iter, 0, &current_key_value, nullptr);
1310 
1311  data_string += QString("%1 ").arg(current_key_value, 0, 'f', 6, ' ');
1312  }
1313 
1314  // Finally call the newline
1315  data_string += "\n";
1316 
1317  // Now fill in the matrix, from top to down, that is from higher m/z values to
1318  // lower values.
1319 
1320  // The matrix we are exporting looks like this:
1321 
1322  // |
1323  // |
1324  // |
1325  // |
1326  // |
1327  // |
1328  // m/z |
1329  // |
1330  // |
1331  // |
1332  // |
1333  // |______________________________
1334  // dt
1335 
1336  // Because we want the matrix to be presented the same, we need to fill in the
1337  // matrix from top to bottom starting from higher m/z values.
1338 
1339  for(int value_iter = value_index_upper_range;
1340  value_iter >= value_index_lower_range;
1341  --value_iter)
1342  {
1343 
1344  for(int key_iter = key_index_lower_range;
1345  key_iter < key_index_upper_range;
1346  ++key_iter)
1347  {
1348  double intensity = map_data->cell(key_iter, value_iter);
1349 
1350  // Only to report debug messages
1351  double key_double;
1352  double value_double;
1353  map_data->cellToCoord(
1354  key_iter, value_iter, &key_double, &value_double);
1355 
1356  // qDebug() << "Currently iterated cell: " << key_iter << ","
1357  //<< value_iter << "with values:" << key_double << ","
1358  //<< value_double << "with intensity:" << intensity;
1359 
1360  // The intensity without decimals
1361  if(detailed)
1362  data_string += QString("%1/%2/%3 ")
1363  .arg(key_double, 0, 'f', 6, ' ')
1364  .arg(value_double, 0, 'f', 6, ' ')
1365  .arg(intensity);
1366  else
1367  data_string += QString("%1 ").arg(intensity, 0, 'f', 0, ' ');
1368  }
1369 
1370  data_string += "\n";
1371  }
1372 
1373  // qDebug().noquote() << "The matrix: " << data_string;
1374  // qDebug() << "The completed data string has size: " <<
1375  // data_string.size();
1376 
1377  data_string += "\n";
1378 }
1379 
1380 
1381 } // namespace pappso
void dataToMatrixString(QString &data_string, bool detailed=false)
virtual QCPColorMap * addColorMap(std::shared_ptr< std::map< double, MapTrace >> double_map_trace_map_sp, const ColorMapPlotConfig color_map_plot_config, const QColor &color)
void currentYaxisRangeIndices(int &lower, int &upper)
virtual QColor getPlottingColor(int index=0) const override
ColorMapPlotConfig * mpa_origColorMapPlotConfig
void dataTo3ColString(QString &data_string)
virtual void zAxisFilterLowPassThreshold(double threshold)
fix maximum value for the intensity
const ColorMapPlotConfig * getOrigColorMapPlotConfig()
void currentXaxisRangeIndices(int &lower, int &upper)
virtual void setColorMapPlotConfig(const ColorMapPlotConfig &color_map_config)
virtual void setPlottingColor(QCPAbstractPlottable *plottable_p, const QColor &new_color) override
AxisScale axisScale(Axis axis) const
virtual const ColorMapPlotConfig & getColorMapPlotConfig()
virtual void zAxisFilterHighPassPercentage(double threshold_percentage)
virtual ~BaseColorMapPlotWidget()
Destruct this BaseColorMapPlotWidget instance.
virtual void zAxisFilterLowPassPercentage(double threshold_percentage)
virtual void createAllAncillaryItems()
virtual void resetAxesRangeHistory()
void plottableSelectionChangedSignal(QCPAbstractPlottable *plottable_p, bool selected)
BasePlotContext m_context
virtual std::size_t getTotalNumberOfScans() const
get the number of scans contained in this frame each scan represents an ion mobility slice
virtual std::vector< quint32 > getScanIndexList(std::size_t scanNum) const override
get raw index list for one given scan index are not TOF nor m/z, just index on digitizer
Definition: timsframe.cpp:172
virtual std::vector< quint32 > getScanIntensities(std::size_t scanNum) const override
get raw intensities without transformation from one scan it needs intensity normalization
Definition: timsframe.cpp:197
tries to keep as much as possible monoisotopes, removing any possible C13 peaks and changes multichar...
Definition: aa.cpp:39
Axis
Definition: types.h:181
AxisScale
Definition: types.h:190
DataKind
Definition: types.h:172
void setOrigAndLastMaxZValue(double value)
void setOrigAndLastMinZValue(double value)