USGS

Isis 3.0 Object Programmers' Reference

Home

ScatterPlotWindow.cpp
1 #include "IsisDebug.h"
2 #include "ScatterPlotWindow.h"
3 
4 #include <QVector>
5 
6 #include <qwt_color_map.h>
7 #include <qwt_double_range.h>
8 #include <qwt_plot.h>
9 #include <qwt_plot_layout.h>
10 #include <qwt_plot_panner.h>
11 #include <qwt_plot_spectrogram.h>
12 #include <qwt_plot_zoomer.h>
13 #include <qwt_scale_draw.h>
14 #include <qwt_scale_widget.h>
15 
16 #include "Histogram.h"
17 #include "MdiCubeViewport.h"
18 #include "Portal.h"
19 #include "ScatterPlotAlarmConfigDialog.h"
20 #include "ScatterPlotData.h"
21 #include "ScatterPlotTool.h"
22 #include "ViewportBuffer.h"
23 #include "ViewportMainWindow.h"
24 #include "Workspace.h"
25 
26 using namespace std;
27 
28 namespace Isis {
44  ScatterPlotWindow::ScatterPlotWindow(QString title,
45  Cube *xAxisCube, int xAxisBand, int xAxisBinCount,
46  Cube *yAxisCube, int yAxisBand, int yAxisBinCount,
47  QwtInterval sampleRange, QwtInterval lineRange,
48  QWidget *parent) :
49  PlotWindow("Scatter Plot", PlotCurve::CubeDN, PlotCurve::CubeDN, parent,
50  (MenuOptions)(
51  AllMenuOptions &
52  ~BackgroundSwitchMenuOption &
53  ~ShowTableMenuOption &
54  ~ClearPlotMenuOption &
55  ~ShowHideMarkersMenuOption &
56  ~ShowHideCurvesMenuOption &
57  ~ConfigurePlotMenuOption)) {
58  m_xAxisCube = xAxisCube;
59  m_yAxisCube = yAxisCube;
60  m_xAxisCubeBand = xAxisBand;
61  m_yAxisCubeBand = yAxisBand;
62 
63  m_sampleRange = sampleRange;
64  m_lineRange = lineRange;
65 
66  m_xCubeDnAlarmRange.first = Null;
67  m_xCubeDnAlarmRange.second = Null;
68  m_yCubeDnAlarmRange.first = Null;
69  m_yCubeDnAlarmRange.second = Null;
70 
71  ScatterPlotData *data = new ScatterPlotData(
72  xAxisCube, xAxisBand, xAxisBinCount,
73  yAxisCube, yAxisBand, yAxisBinCount,
74  sampleRange, lineRange);
75 
76  m_spectrogram = new QwtPlotSpectrogram;
77 
78  m_spectrogram->setData(data);
79  m_spectrogram->setTitle("Scatter Plot Counts");
80  m_spectrogram->attach(plot());
81 
83  zoomer()->zoom(0);
84  plot()->setAxisScale(QwtPlot::xBottom, data->xCubeMin(), data->xCubeMax());
85  plot()->setAxisScale(QwtPlot::yLeft, data->yCubeMin(), data->yCubeMax());
86  zoomer()->setZoomBase();
87  replot();
88 
89  QwtScaleWidget *rightAxis = plot()->axisWidget(QwtPlot::yRight);
90  rightAxis->setTitle("Counts");
91  rightAxis->setColorBarEnabled(true);
92 // rightAxis->setColorMap(m_spectrogram->data()->interval(Qt::ZAxis),
93 // m_spectrogram->colorMap());
94 
95  plot()->setAxisScale(QwtPlot::yRight,
96  m_spectrogram->data()->interval(Qt::ZAxis).minValue(),
97  m_spectrogram->data()->interval(Qt::ZAxis).maxValue());
98  plot()->enableAxis(QwtPlot::yRight);
99 
100  plot()->setAxisTitle(QwtPlot::xBottom,
101  QFileInfo(xAxisCube->fileName()).baseName() + " Band " +
102  QString::number(xAxisBand) + " " +
103  plot()->axisTitle(QwtPlot::xBottom).text());
104  plot()->setAxisTitle(QwtPlot::yLeft,
105  QFileInfo(yAxisCube->fileName()).baseName() + " Band " +
106  QString::number(yAxisBand) + " " +
107  plot()->axisTitle(QwtPlot::yLeft).text());
108 
109  QList<double> contourLevels;
110  QwtInterval range = m_spectrogram->data()->interval(Qt::ZAxis);
111 
112  for (double level = range.minValue();
113  level < range.maxValue();
114  level += ((range.maxValue() - range.minValue()) / 6.0)) {
115  contourLevels += level;
116  }
117 
118  m_spectrogram->setContourLevels(contourLevels);
119 
120  m_colorize = new QAction(this);
121  m_colorize->setText("Colorize");
122  m_colorize->setIcon(QPixmap(FileName("$base/icons/rgb.png").expanded()));
123  connect(m_colorize, SIGNAL(activated()),
124  this, SLOT(colorPlot()));
125 
126  m_contour = new QAction(this);
127  m_contour->setText("Hide Contour Lines");
128  m_contour->setIcon(
129  QPixmap(FileName("$base/icons/scatterplotcontour.png").expanded()));
130  connect(m_contour, SIGNAL(activated()),
131  this, SLOT(showHideContour()));
132 
133  QAction *configureAlarmingAct = new QAction(this);
134  configureAlarmingAct->setText("Change Alarming");
135  configureAlarmingAct->setIcon(
136  QPixmap(FileName("$base/icons/scatterplotalarming.png").expanded()));
137  connect(configureAlarmingAct, SIGNAL(activated()),
138  this, SLOT(configureAlarming()));
139 
140  foreach (QAction *menuAction, menuBar()->actions()) {
141  if (menuAction->text() == "&Options") {
142  QMenu *optsMenu = qobject_cast<QMenu *>(menuAction->parentWidget());
143  optsMenu->addAction(m_colorize);
144  optsMenu->addAction(m_contour);
145  optsMenu->addAction(configureAlarmingAct);
146  }
147  }
148 
149  colorPlot();
150  showHideContour();
151 
152  plot()->canvas()->installEventFilter(this);
153  plot()->canvas()->setMouseTracking(true);
154 
155  replot();
156 
157  QString instanceName = windowTitle();
158  FileName config("$HOME/.Isis/qview/" + instanceName + ".config");
159  QSettings settings(config.expanded(),
160  QSettings::NativeFormat);
161  m_alarmPlot = settings.value("alarmOntoPlot", true).toBool();
162  m_alarmViewport = settings.value("alarmOntoViewport", true).toBool();
163 
164  m_alarmPlotSamples = settings.value("alarmPlotSamples", 25).toInt();
165  m_alarmPlotLines = settings.value("alarmPlotLines", 25).toInt();
166 
167  m_alarmViewportUnits = (AlarmRangeUnits)settings.value("alarmViewportUnits",
168  ScreenUnits).toInt();
169 
171  settings.value("alarmViewportScreenWidth", 5).toInt();
173  settings.value("alarmViewportScreenHeight", 5).toInt();
174 
176  settings.value("alarmViewportXDnBoxSize", 1.0).toDouble();
178  settings.value("alarmViewportYDnBoxSize", 1.0).toDouble();
179  }
180 
181 
182  ScatterPlotWindow::~ScatterPlotWindow() {
183  QString instanceName = windowTitle();
184  FileName config("$HOME/.Isis/qview/" + instanceName + ".config");
185  QSettings settings(config.expanded(),
186  QSettings::NativeFormat);
187  settings.setValue("alarmOntoPlot", m_alarmPlot);
188  settings.setValue("alarmOntoViewport", m_alarmViewport);
189 
190  settings.setValue("alarmPlotSamples", m_alarmPlotSamples);
191  settings.setValue("alarmPlotLines", m_alarmPlotLines);
192 
193  settings.setValue("alarmViewportUnits", (int)m_alarmViewportUnits);
194 
195  settings.setValue("alarmViewportScreenWidth", m_alarmViewportScreenWidth);
196  settings.setValue("alarmViewportScreenHeight", m_alarmViewportScreenHeight);
197 
198  settings.setValue("alarmViewportXDnBoxSize", m_alarmViewportXDnBoxSize);
199  settings.setValue("alarmViewportYDnBoxSize", m_alarmViewportYDnBoxSize);
200  }
201 
202 
209  return m_alarmPlot;
210  }
211 
212 
219  return m_alarmViewport;
220  }
221 
222 
230  }
231 
232 
241  return m_alarmViewportUnits;
242  }
243 
244 
257  }
258 
259 
273  }
274 
275 
285  if (o == plot()->canvas()) {
286  switch (e->type()) {
287  case QEvent::MouseMove: {
288  if (((QMouseEvent *)e)->buttons() == Qt::NoButton)
289  mouseMoveEvent((QMouseEvent *)e);
290  break;
291  }
292  case QEvent::Leave: {
293  mouseLeaveEvent((QMouseEvent *)e);
294  break;
295  }
296  default:
297  break;
298  }
299 
300  return false;
301  }
302  else {
303  return PlotWindow::eventFilter(o, e);
304  }
305  }
306 
307 
316  void ScatterPlotWindow::paint(MdiCubeViewport *vp, QPainter *painter) {
317  PlotWindow::paint(vp, painter);
318 
319  // Do alarming from plot onto viewport
320  if (alarmingViewport() &&
321  !IsSpecial(m_xCubeDnAlarmRange.first) &&
322  !IsSpecial(m_xCubeDnAlarmRange.second) &&
323  !IsSpecial(m_yCubeDnAlarmRange.first) &&
324  !IsSpecial(m_yCubeDnAlarmRange.second)) {
325  painter->setPen(QPen(Qt::red));
326 
327  ViewportBuffer *buffer = vp->grayBuffer();
328 
329  if ((isXCube(vp) || isYCube(vp)) && buffer && !buffer->working()) {
330  int numLines = buffer->bufferXYRect().height();
331 
332  QScopedPointer<Portal> portal;
333 
334  // We are going to read DNs from the cube that isn't in the passed in
335  // viewport. For example, if we're painting X, we're missing the
336  // corresponding Y DN values.
337  if (isXCube(vp))
338  portal.reset(new Portal(1, 1, m_yAxisCube->pixelType()));
339  else
340  portal.reset(new Portal(1, 1, m_xAxisCube->pixelType()));
341 
342  // Iterate through the in-memory DN values for the passed in viewport
343  for (int yIndex = 0; yIndex < numLines; yIndex++) {
344  const vector<double> &line = buffer->getLine(yIndex);
345 
346  for (int xIndex = 0; xIndex < (int)line.size(); xIndex++) {
347  int viewportPointX = xIndex + buffer->bufferXYRect().left();
348  int viewportPointY = yIndex + buffer->bufferXYRect().top();
349 
350  double cubeSample = Null;
351  double cubeLine = Null;
352  vp->viewportToCube(viewportPointX, viewportPointY,
353  cubeSample, cubeLine);
354 
355  // The sample/line range is the actual scatter plotted sample/line
356  // range. Don't alarm outside of this range on the cube ever.
357  if (cubeSample >= m_sampleRange.minValue() - 0.5 &&
358  cubeSample <= m_sampleRange.maxValue() + 0.5 &&
359  cubeLine >= m_lineRange.minValue() - 0.5 &&
360  cubeLine <= m_lineRange.maxValue() + 0.5) {
361  // If the in-memory DN values are within the alarm box range, check
362  // the corresponding DN values for the other axis via cube I/O.
363  if (isXCube(vp) &&
364  line[xIndex] >= m_xCubeDnAlarmRange.first &&
365  line[xIndex] <= m_xCubeDnAlarmRange.second) {
366  portal->SetPosition(cubeSample, cubeLine, m_yAxisCubeBand);
367  m_yAxisCube->read(*portal);
368 
369  double yDnValue = (*portal)[0];
370 
371  if (yDnValue >= m_yCubeDnAlarmRange.first &&
372  yDnValue <= m_yCubeDnAlarmRange.second) {
373  painter->drawPoint(viewportPointX, viewportPointY);
374  }
375  }
376  else if (isYCube(vp) &&
377  line[xIndex] >= m_yCubeDnAlarmRange.first &&
378  line[xIndex] <= m_yCubeDnAlarmRange.second) {
379  portal->SetPosition(cubeSample, cubeLine, m_xAxisCubeBand);
380  m_xAxisCube->read(*portal);
381 
382  double xDnValue = (*portal)[0];
383 
384  if (xDnValue >= m_xCubeDnAlarmRange.first &&
385  xDnValue <= m_xCubeDnAlarmRange.second) {
386  painter->drawPoint(viewportPointX, viewportPointY);
387  }
388  }
389  }
390  }
391  }
392  }
393  }
394  }
395 
396 
406  QPoint mouseLoc) {
407  ScatterPlotData *scatterData =
408  dynamic_cast<ScatterPlotData *>(m_spectrogram->data());
409 
410  if (scatterData) {
411  scatterData->clearAlarms();
412 
413  if (alarmingPlot() && (isXCube(vp) || isYCube(vp))) {
414  QScopedPointer<Portal> xCubePortal(
416  m_xAxisCube->pixelType()));
417  QScopedPointer<Portal> yCubePortal(
419  m_yAxisCube->pixelType()));
420 
421  double cubeSample = Null;
422  double cubeLine = Null;
423 
424  vp->viewportToCube(mouseLoc.x(), mouseLoc.y(), cubeSample, cubeLine);
425 
426  // The sample/line range is the actual scatter plotted sample/line
427  // range. Don't alarm outside of this range on the cube ever.
428  if (cubeSample >= m_sampleRange.minValue() - 0.5 &&
429  cubeSample <= m_sampleRange.maxValue() + 0.5 &&
430  cubeLine >= m_lineRange.minValue() - 0.5 &&
431  cubeLine <= m_lineRange.maxValue() + 0.5) {
432  xCubePortal->SetPosition(cubeSample, cubeLine, m_xAxisCubeBand);
433  m_xAxisCube->read(*xCubePortal);
434  yCubePortal->SetPosition(cubeSample, cubeLine, m_yAxisCubeBand);
435  m_yAxisCube->read(*yCubePortal);
436 
437  ASSERT(xCubePortal->size() == yCubePortal->size());
438  for (int i = 0; i < xCubePortal->size(); i++) {
439  double x = (*xCubePortal)[i];
440  double y = (*yCubePortal)[i];
441 
442  if (!IsSpecial(x) && !IsSpecial(y)) {
443  scatterData->alarm(x, y);
444  }
445  }
446  }
447  }
448 
449  plot()->replot();
450  }
451  }
452 
453 
461  m_alarmPlot = alarming;
462  }
463 
464 
472  m_alarmViewport = alarming;
473  }
474 
475 
484  void ScatterPlotWindow::setAlarmPlotBoxSize(int samples, int lines) {
485  m_alarmPlotSamples = samples;
486  m_alarmPlotLines = lines;
487  }
488 
489 
496  m_alarmViewportUnits = units;
497  }
498 
499 
514  }
515 
516 
529  double yDnBoxSize) {
530  m_alarmViewportXDnBoxSize = xDnBoxSize;
531  m_alarmViewportYDnBoxSize = yDnBoxSize;
532  }
533 
534 
541  m_xAxisCube = NULL;
542  m_yAxisCube = NULL;
543  }
544 
545 
552  if (m_colorize->text().compare("Colorize") == 0) {
553  m_colorize->setIcon(QPixmap(FileName("$base/icons/gray.png").expanded()));
554  m_colorize->setText("Gray");
555  QwtLinearColorMap *colorMap = new QwtLinearColorMap(Qt::darkCyan, Qt::red);
556  colorMap->addColorStop(DBL_EPSILON, Qt::cyan);
557  colorMap->addColorStop(0.3, Qt::green);
558  colorMap->addColorStop(0.50, Qt::yellow);
559  m_spectrogram->setColorMap(colorMap);
560  plot()->setCanvasBackground(Qt::darkCyan);
561  }
562  else {
563  m_colorize->setIcon(QPixmap(FileName("$base/icons/rgb.png").expanded()));
564  m_colorize->setText("Colorize");
565  QwtLinearColorMap *colorMap = new QwtLinearColorMap(Qt::black, Qt::white);
566  colorMap->addColorStop(DBL_EPSILON, Qt::darkGray);
567  m_spectrogram->setColorMap(colorMap);
568  plot()->setCanvasBackground(Qt::black);
569  }
570 
571 // plot()->axisWidget(QwtPlot::yRight)->setColorMap(
572 // m_spectrogram->interval(Qt::ZAxis),
573 // m_spectrogram->colorMap());
575 
576  replot();
577  }
578 
579 
586  if (m_contour->text() == "Show Contour Lines") {
587  m_contour->setText("Hide Contour Lines");
588  m_spectrogram->setDisplayMode(QwtPlotSpectrogram::ContourMode, true);
590  }
591  else {
592  m_contour->setText("Show Contour Lines");
593  m_spectrogram->setDisplayMode(QwtPlotSpectrogram::ContourMode, false);
594  }
595 
596  replot();
597  }
598 
599 
608  return (vp && m_xAxisCube &&
609  vp->cube() == m_xAxisCube && vp->grayBand() == m_xAxisCubeBand &&
610  vp->isGray());
611  }
612 
613 
622  return (vp && m_yAxisCube &&
623  vp->cube() == m_yAxisCube && vp->grayBand() == m_yAxisCubeBand &&
624  vp->isGray());
625  }
626 
627 
635  void ScatterPlotWindow::mouseMoveEvent(QMouseEvent *e) {
636  if (alarmingViewport()) {
637  if (m_alarmViewportUnits == ScreenUnits) {
638  m_xCubeDnAlarmRange.first = plot()->invTransform(
639  QwtPlot::xBottom, e->pos().x() - m_alarmViewportScreenWidth / 2);
640  m_xCubeDnAlarmRange.second = plot()->invTransform(
641  QwtPlot::xBottom, e->pos().x() + m_alarmViewportScreenWidth / 2);
642 
643  m_yCubeDnAlarmRange.first = plot()->invTransform(
644  QwtPlot::yLeft, e->pos().y() + m_alarmViewportScreenHeight / 2);
645  m_yCubeDnAlarmRange.second = plot()->invTransform(
646  QwtPlot::yLeft, e->pos().y() - m_alarmViewportScreenHeight / 2);
647 
648  if (m_xCubeDnAlarmRange.first > m_xCubeDnAlarmRange.second)
649  std::swap(m_xCubeDnAlarmRange.first, m_xCubeDnAlarmRange.second);
650 
651  if (m_yCubeDnAlarmRange.first > m_yCubeDnAlarmRange.second)
652  std::swap(m_yCubeDnAlarmRange.first, m_yCubeDnAlarmRange.second);
653  }
654  else {
655  m_xCubeDnAlarmRange.first = plot()->invTransform(
656  QwtPlot::xBottom, e->pos().x()) - m_alarmViewportXDnBoxSize / 2.0;
657  m_xCubeDnAlarmRange.second = plot()->invTransform(
658  QwtPlot::xBottom, e->pos().x()) + m_alarmViewportXDnBoxSize / 2.0;
659 
660  m_yCubeDnAlarmRange.first = plot()->invTransform(
661  QwtPlot::yLeft, e->pos().y()) - m_alarmViewportYDnBoxSize / 2.0;
662  m_yCubeDnAlarmRange.second = plot()->invTransform(
663  QwtPlot::yLeft, e->pos().y()) + m_alarmViewportYDnBoxSize / 2.0;
664  }
665  }
666  else {
667  m_xCubeDnAlarmRange.first = Null;
668  m_xCubeDnAlarmRange.second = Null;
669  m_yCubeDnAlarmRange.first = Null;
670  m_yCubeDnAlarmRange.second = Null;
671  }
672 
673  emit plotChanged();
674  }
675 
676 
683  void ScatterPlotWindow::mouseLeaveEvent(QMouseEvent *e) {
684  m_xCubeDnAlarmRange.first = Null;
685  m_xCubeDnAlarmRange.second = Null;
686  m_yCubeDnAlarmRange.first = Null;
687  m_yCubeDnAlarmRange.second = Null;
688 
689  emit plotChanged();
690  }
691 
692 
699  if (m_colorize->text() == "Gray") {
700  m_spectrogram->setDefaultContourPen(QPen(Qt::red));
701  }
702  else {
703  m_spectrogram->setDefaultContourPen(QPen(Qt::white));
704  }
705  }
706 
707 
714  connect(config, SIGNAL(finished(int)),
715  config, SLOT(deleteLater()));
716  config->show();
717  }
718 }
719