BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
ColorMap.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/coregui/Views/IntensityDataWidgets/ColorMap.cpp
6 //! @brief Implements class ColorMap
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2018
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
16 #include "Base/Math/Constants.h"
23 
24 namespace {
25 const int replot_update_interval = 10;
26 const int colorbar_width_logz = 50;
27 const int colorbar_width = 80;
28 } // namespace
29 
30 ColorMap::ColorMap(QWidget* parent)
31  : ScientificPlot(parent, PLOT_TYPE::Plot2D)
32  , m_customPlot(new QCustomPlot)
33  , m_colorMap(nullptr)
34  , m_colorScale(nullptr)
35  , m_updateTimer(new UpdateTimer(replot_update_interval, this))
36  , m_colorBarLayout(new QCPLayoutGrid)
37  , m_block_update(true)
38 {
39  initColorMap();
40 
41  QVBoxLayout* vlayout = new QVBoxLayout(this);
42  vlayout->setMargin(0);
43  vlayout->setSpacing(0);
44  vlayout->addWidget(m_customPlot);
45  setLayout(vlayout);
46 
48  // setFixedColorMapMargins();
49 }
50 
52 {
53  QCPRange xrange = m_customPlot->xAxis->range();
54  QCPRange yrange = m_customPlot->yAxis->range();
55  double left = xrange.lower;
56  double right = xrange.upper;
57  double top = yrange.upper;
58  double bottom = yrange.lower;
59 
60  return QRectF(xAxisCoordToPixel(left), yAxisCoordToPixel(top),
61  xAxisCoordToPixel(right) - xAxisCoordToPixel(left),
62  yAxisCoordToPixel(bottom) - yAxisCoordToPixel(top));
63 }
64 
65 PlotEventInfo ColorMap::eventInfo(double xpos, double ypos) const
66 {
67  PlotEventInfo result(plotType());
68  if (!intensityItem())
69  return result;
70 
71  int nx(0), ny(0);
72  m_colorMap->data()->coordToCell(xpos, ypos, &nx, &ny);
73 
74  result.setX(xpos);
75  result.setY(ypos);
76  result.setNx(nx);
77  result.setNy(ny);
78 
79  result.setInAxesRange(axesRangeContains(xpos, ypos));
80  result.setValue(m_colorMap->data()->cell(result.nx(), result.ny()));
81  result.setLogValueAxis(intensityItem()->isLogz());
82 
83  return result;
84 }
85 
86 //! sets logarithmic scale
87 void ColorMap::setLogz(bool logz)
88 {
89  m_colorBarLayout->setMinimumSize(logz ? colorbar_width_logz : colorbar_width, 10);
91 }
92 
93 //! reset all axes min,max to initial value
95 {
97 }
98 
100 {
103  replot();
104 }
105 
106 //! updates color map depending on IntensityDataItem properties
107 void ColorMap::onPropertyChanged(const QString& property_name)
108 {
109  if (m_block_update)
110  return;
111 
112  if (property_name == IntensityDataItem::P_GRADIENT) {
114  replot();
115  } else if (property_name == IntensityDataItem::P_IS_INTERPOLATED) {
116  m_colorMap->setInterpolate(intensityItem()->isInterpolated());
117  replot();
118  } else if (property_name == DataItem::P_AXES_UNITS) {
120  replot();
121  }
122 }
123 
124 void ColorMap::onAxisPropertyChanged(const QString& axisName, const QString& propertyName)
125 {
126  if (m_block_update)
127  return;
128 
129  if (propertyName == BasicAxisItem::P_TITLE
130  || propertyName == BasicAxisItem::P_TITLE_IS_VISIBLE) {
132  replot();
133  }
134 
135  if (axisName == IntensityDataItem::P_XAXIS) {
136  if (propertyName == BasicAxisItem::P_MIN_DEG || propertyName == BasicAxisItem::P_MAX_DEG) {
137  setAxesRangeConnected(false);
139  setAxesRangeConnected(true);
140  replot();
141  }
142  } else if (axisName == IntensityDataItem::P_YAXIS) {
143  if (propertyName == BasicAxisItem::P_MIN_DEG || propertyName == BasicAxisItem::P_MAX_DEG) {
144  setAxesRangeConnected(false);
146  setAxesRangeConnected(true);
147  replot();
148  }
149  }
150 
151  else if (axisName == IntensityDataItem::P_ZAXIS) {
152  if (propertyName == BasicAxisItem::P_MIN_DEG || propertyName == BasicAxisItem::P_MAX_DEG) {
154  replot();
155  } else if (propertyName == AmplitudeAxisItem::P_IS_LOGSCALE) {
156  setLogz(intensityItem()->isLogz());
157  replot();
158 
159  } else if (propertyName == BasicAxisItem::P_IS_VISIBLE) {
161  ->getItem(IntensityDataItem::P_ZAXIS)
162  ->getItemValue(BasicAxisItem::P_IS_VISIBLE)
163  .toBool());
164  replot();
165  }
166  }
167 }
168 
169 //! Propagate zmin, zmax back to IntensityDataItem
170 void ColorMap::onDataRangeChanged(QCPRange newRange)
171 {
172  m_block_update = true;
173  intensityItem()->setLowerAndUpperZ(newRange.lower, newRange.upper);
174  m_block_update = false;
175 }
176 
177 //! Propagate xmin, xmax back to IntensityDataItem
178 void ColorMap::onXaxisRangeChanged(QCPRange newRange)
179 {
180  m_block_update = true;
181  intensityItem()->setLowerX(newRange.lower);
182  intensityItem()->setUpperX(newRange.upper);
183  m_block_update = false;
184 }
185 
186 //! Propagate ymin, ymax back to IntensityDataItem
187 void ColorMap::onYaxisRangeChanged(QCPRange newRange)
188 {
189  m_block_update = true;
190  intensityItem()->setLowerY(newRange.lower);
191  intensityItem()->setUpperY(newRange.upper);
192  m_block_update = false;
193 }
194 
195 //! Schedule replot for later execution by onTimeReplot() slot.
196 
198 {
200 }
201 
202 //! Replots ColorMap.
203 
205 {
206  m_customPlot->replot();
207 }
208 
210 {
212 
214  [this](const QString& name) { onPropertyChanged(name); }, this);
215 
217  [this](SessionItem* item, const QString name) {
218  if (item->modelType() == "BasicAxis" || item->modelType() == "AmplitudeAxis")
220  },
221  this);
222 
223  intensityItem()->mapper()->setOnValueChange([this]() { onIntensityModified(); }, this);
224 
225  setConnected(true);
226 }
227 
229 {
230  setConnected(false);
231 }
232 
233 //! creates and initializes the color map
235 {
236  m_colorMap = new QCPColorMap(m_customPlot->xAxis, m_customPlot->yAxis);
237  m_colorScale = new QCPColorScale(m_customPlot);
238  m_colorMap->setColorScale(m_colorScale);
239 
240  m_colorBarLayout->addElement(0, 0, m_colorScale);
241  m_colorBarLayout->setMinimumSize(colorbar_width_logz, 10);
242  auto base_size = StyleUtils::SizeOfLetterM(this).width() * 0.5;
243  m_colorBarLayout->setMargins(QMargins(base_size, 0, base_size, 0));
244 
245  m_colorScale->axis()->axisRect()->setMargins(QMargins(0, 0, 0, 0));
246  m_colorScale->axis()->axisRect()->setAutoMargins(QCP::msNone);
247 
249  m_colorScale->axis()->setTickLabelFont(
250  QFont(QFont().family(), Constants::plot_tick_label_size()));
251  m_customPlot->xAxis->setTickLabelFont(
252  QFont(QFont().family(), Constants::plot_tick_label_size()));
253  m_customPlot->yAxis->setTickLabelFont(
254  QFont(QFont().family(), Constants::plot_tick_label_size()));
255 
256  connect(m_customPlot, &QCustomPlot::afterReplot, this, &ColorMap::marginsChangedNotify);
257 }
258 
259 void ColorMap::setConnected(bool isConnected)
260 {
261  setAxesRangeConnected(isConnected);
262  setDataRangeConnected(isConnected);
263  setUpdateTimerConnected(isConnected);
264 }
265 
266 //! Connects/disconnects signals related to ColorMap's X,Y axes rectangle change.
267 
268 void ColorMap::setAxesRangeConnected(bool isConnected)
269 {
270  if (isConnected) {
271  connect(m_customPlot->xAxis,
272  static_cast<void (QCPAxis::*)(const QCPRange&)>(&QCPAxis::rangeChanged), this,
273  &ColorMap::onXaxisRangeChanged, Qt::UniqueConnection);
274 
275  connect(m_customPlot->yAxis,
276  static_cast<void (QCPAxis::*)(const QCPRange&)>(&QCPAxis::rangeChanged), this,
277  &ColorMap::onYaxisRangeChanged, Qt::UniqueConnection);
278 
279  } else {
280  disconnect(m_customPlot->xAxis,
281  static_cast<void (QCPAxis::*)(const QCPRange&)>(&QCPAxis::rangeChanged), this,
283 
284  disconnect(m_customPlot->yAxis,
285  static_cast<void (QCPAxis::*)(const QCPRange&)>(&QCPAxis::rangeChanged), this,
287  }
288 }
289 
290 //! Connects/disconnects signals related to ColorMap's Z-axis (min,max) change.
291 
292 void ColorMap::setDataRangeConnected(bool isConnected)
293 {
294  if (isConnected)
295  connect(m_colorMap, &QCPColorMap::dataRangeChanged, this, &ColorMap::onDataRangeChanged,
296  Qt::UniqueConnection);
297  else
298  disconnect(m_colorMap, &QCPColorMap::dataRangeChanged, this, &ColorMap::onDataRangeChanged);
299 }
300 
301 void ColorMap::setUpdateTimerConnected(bool isConnected)
302 {
303  if (isConnected)
305  Qt::UniqueConnection);
306  else
308 }
309 
310 //! to make fixed margins for whole colormap (change in axes labels wont affect axes rectangle)
312 {
314 }
315 
316 //! Sets initial state of ColorMap to match given intensity item.
317 
319 {
321 
322  m_block_update = true;
323 
330 
331  replot();
332 
333  m_block_update = false;
334 }
335 
336 //! Sets (xmin,xmax,nbins) and (ymin,ymax,nbins) of ColorMap from intensity item.
337 
339 {
340  m_customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
341  m_customPlot->axisRect()->setupFullAxesBox(true);
342  m_colorMap->data()->setSize(item->getNbinsX(), item->getNbinsY());
343  m_colorMap->data()->setRange(ColorMapUtils::itemXrange(item), ColorMapUtils::itemYrange(item));
344 }
345 
346 //! Sets zoom range of X,Y axes as in intensity item.
347 
349 {
350  setAxesRangeConnected(false);
351  m_customPlot->xAxis->setRange(item->getLowerX(), item->getUpperX());
352  m_customPlot->yAxis->setRange(item->getLowerY(), item->getUpperY());
353  setAxesRangeConnected(true);
354 }
355 
356 //! Sets X,Y axes labels from item
357 
359 {
360  auto xaxis = item->xAxisItem();
361  if (xaxis->getItemValue(BasicAxisItem::P_TITLE_IS_VISIBLE).toBool())
362  m_customPlot->xAxis->setLabel(item->getXaxisTitle());
363  else
364  m_customPlot->xAxis->setLabel(QString());
365 
366  m_colorScale->setMargins(QMargins(0, 0, 0, 0));
367 
368  auto yaxis = item->yAxisItem();
369  if (yaxis->getItemValue(BasicAxisItem::P_TITLE_IS_VISIBLE).toBool())
370  m_customPlot->yAxis->setLabel(item->getYaxisTitle());
371  else
372  m_customPlot->yAxis->setLabel(QString());
373 }
374 
375 //! Sets the intensity values to ColorMap.
376 
378 {
379  auto data = item->getOutputData();
380  if (!data) {
381  m_colorMap->data()->clear();
382  return;
383  }
384 
385  int nx(item->getNbinsX()); // outside of the loop because of slow retrieval
386  int ny(item->getNbinsY());
387  for (int ix = 0; ix < nx; ++ix)
388  for (int iy = 0; iy < ny; ++iy)
389  m_colorMap->data()->setCell(ix, iy, (*data)[iy + ny * ix]);
390 }
391 
392 //! Sets the appearance of color scale (visibility, gradient type) from intensity item.
393 
395 {
398  .toBool());
400  m_colorMap->setInterpolate(intensityItem()->isInterpolated());
401  // make sure the axis rect and color scale synchronize their bottom and top margins (so they
402  // line up):
403  QCPMarginGroup* marginGroup = new QCPMarginGroup(m_customPlot);
404  m_customPlot->axisRect()->setMarginGroup(QCP::msBottom | QCP::msTop, marginGroup);
405  m_colorScale->setMarginGroup(QCP::msBottom | QCP::msTop, marginGroup);
406 }
407 
409 {
410  setDataRangeConnected(false);
411  m_colorMap->setDataRange(ColorMapUtils::itemDataZoom(item));
412  setLogz(item->isLogz());
413  setDataRangeConnected(true);
414 }
415 
416 void ColorMap::setColorScaleVisible(bool visibility_flag)
417 {
418  m_colorBarLayout->setVisible(visibility_flag);
419  if (visibility_flag) {
420  // add it to the right of the main axis rect
421  m_customPlot->plotLayout()->addElement(0, 1, m_colorBarLayout);
422  } else {
423  m_customPlot->plotLayout()->take(m_colorBarLayout);
424  m_customPlot->plotLayout()->simplify();
425  }
426 }
427 
428 //! Calculates left, right margins around color map to report to projection plot.
429 
431 {
432  QMargins axesMargins = m_customPlot->axisRect()->margins();
433  // QMargins colorBarMargins = m_colorScale->margins();
434  // QMargins colorScaleMargins = m_colorScale->axis()->axisRect()->margins();
435 
436  double left = axesMargins.left();
437  // double right = axesMargins.right() + colorBarMargins.right() + m_colorScale->barWidth()
438  // + colorScaleMargins.right() + m_colorBarLayout->rect().width();
439 
440  double right = axesMargins.right() + m_colorBarLayout->rect().width();
441 
442  emit marginsChanged(left, right);
443 }
444 
446 {
447  return const_cast<IntensityDataItem*>(static_cast<const ColorMap*>(this)->intensityItem());
448 }
449 
451 {
452  return dynamic_cast<const IntensityDataItem*>(currentItem());
453 }
#define ASSERT(condition)
Definition: Assert.h:31
Defines various axis items.
Defines ColorMapUtils namespace.
Defines class ColorMap.
Defines M_PI and some more mathematical constants.
Defines class IntensityDataItem.
Defines the class PlotEventInfo.
Defines class UpdateTimer.
static const QString P_IS_LOGSCALE
Definition: AxesItems.h:55
static const QString P_MAX_DEG
Definition: AxesItems.h:28
static const QString P_TITLE
Definition: AxesItems.h:29
static const QString P_IS_VISIBLE
Definition: AxesItems.h:25
static const QString P_TITLE_IS_VISIBLE
Definition: AxesItems.h:30
static const QString P_MIN_DEG
Definition: AxesItems.h:27
The ColorMap class presents 2D intensity data from IntensityDataItem as color map.
Definition: ColorMap.h:36
QCPColorMap * m_colorMap
Definition: ColorMap.h:101
UpdateTimer * m_updateTimer
Definition: ColorMap.h:103
QRectF viewportRectangleInWidgetCoordinates()
returns rectangle representing current axes zoom state in widget coordinates
Definition: ColorMap.cpp:51
void setAxesRangeFromItem(IntensityDataItem *item)
Sets (xmin,xmax,nbins) and (ymin,ymax,nbins) of ColorMap from intensity item.
Definition: ColorMap.cpp:338
QCPLayoutGrid * m_colorBarLayout
Definition: ColorMap.h:104
bool m_block_update
Definition: ColorMap.h:106
ColorMap(QWidget *parent=nullptr)
Definition: ColorMap.cpp:30
void setUpdateTimerConnected(bool isConnected)
Definition: ColorMap.cpp:301
PlotEventInfo eventInfo(double xpos, double ypos) const override
Returns PlotEventInfo corresponding to given axes coordinates.
Definition: ColorMap.cpp:65
void setConnected(bool isConnected)
Definition: ColorMap.cpp:259
void setFixedColorMapMargins()
to make fixed margins for whole colormap (change in axes labels wont affect axes rectangle)
Definition: ColorMap.cpp:311
void replot()
Schedule replot for later execution by onTimeReplot() slot.
Definition: ColorMap.cpp:197
void unsubscribeFromItem() override
Definition: ColorMap.cpp:228
void onYaxisRangeChanged(QCPRange newRange)
Propagate ymin, ymax back to IntensityDataItem.
Definition: ColorMap.cpp:187
void initColorMap()
creates and initializes the color map
Definition: ColorMap.cpp:234
void marginsChanged(double left, double right)
void setAxesRangeConnected(bool isConnected)
Connects/disconnects signals related to ColorMap's X,Y axes rectangle change.
Definition: ColorMap.cpp:268
void setAxesLabelsFromItem(IntensityDataItem *item)
Sets X,Y axes labels from item.
Definition: ColorMap.cpp:358
void setDataRangeFromItem(IntensityDataItem *item)
Definition: ColorMap.cpp:408
void setColorMapFromItem(IntensityDataItem *intensityItem)
Sets initial state of ColorMap to match given intensity item.
Definition: ColorMap.cpp:318
void setDataRangeConnected(bool isConnected)
Connects/disconnects signals related to ColorMap's Z-axis (min,max) change.
Definition: ColorMap.cpp:292
void onPropertyChanged(const QString &property_name)
updates color map depending on IntensityDataItem properties
Definition: ColorMap.cpp:107
void onAxisPropertyChanged(const QString &axisName, const QString &propertyName)
Definition: ColorMap.cpp:124
void onTimeToReplot()
Replots ColorMap.
Definition: ColorMap.cpp:204
void subscribeToItem() override
Definition: ColorMap.cpp:209
QCPColorScale * m_colorScale
Definition: ColorMap.h:102
void onDataRangeChanged(QCPRange newRange)
Propagate zmin, zmax back to IntensityDataItem.
Definition: ColorMap.cpp:170
void setColorScaleAppearanceFromItem(IntensityDataItem *item)
Sets the appearance of color scale (visibility, gradient type) from intensity item.
Definition: ColorMap.cpp:394
IntensityDataItem * intensityItem()
Definition: ColorMap.cpp:445
void setDataFromItem(IntensityDataItem *item)
Sets the intensity values to ColorMap.
Definition: ColorMap.cpp:377
void resetView()
reset all axes min,max to initial value
Definition: ColorMap.cpp:94
void setLogz(bool logz)
sets logarithmic scale
Definition: ColorMap.cpp:87
void onIntensityModified()
Definition: ColorMap.cpp:99
void onXaxisRangeChanged(QCPRange newRange)
Propagate xmin, xmax back to IntensityDataItem.
Definition: ColorMap.cpp:178
QCustomPlot * m_customPlot
Definition: ColorMap.h:100
void setColorScaleVisible(bool visibility_flag)
Definition: ColorMap.cpp:416
void marginsChangedNotify()
Calculates left, right margins around color map to report to projection plot.
Definition: ColorMap.cpp:430
void setAxesZoomFromItem(IntensityDataItem *item)
Sets zoom range of X,Y axes as in intensity item.
Definition: ColorMap.cpp:348
OutputData< double > * getOutputData()
Definition: DataItem.h:36
static const QString P_AXES_UNITS
Definition: DataItem.h:34
void setLowerX(double value)
static const QString P_ZAXIS
static const QString P_YAXIS
static const QString P_XAXIS
QString getXaxisTitle() const
void setLowerY(double value)
void setLowerAndUpperZ(double zmin, double zmax)
double getLowerY() const
returns lower and upper zoom ranges of y-axis
static const QString P_GRADIENT
void resetView()
Set axes viewport to original data.
const BasicAxisItem * yAxisItem() const
void setUpperX(double value)
QString getYaxisTitle() const
double getUpperY() const
const BasicAxisItem * xAxisItem() const
double getUpperX() const
void setUpperY(double value)
double getLowerX() const
returns lower and upper zoom ranges of x-axis
static const QString P_IS_INTERPOLATED
void setOnValueChange(std::function< void(void)> f, const void *caller=0)
Definition: ModelMapper.cpp:30
void setOnChildPropertyChange(std::function< void(SessionItem *, QString)> f, const void *caller=0)
Calls back on child property change, report childItem and property name.
Definition: ModelMapper.cpp:49
void setOnPropertyChange(std::function< void(QString)> f, const void *caller=0)
Definition: ModelMapper.cpp:35
Contains parameters of mouse position in 1D or 2D plot.
Definition: PlotEventInfo.h:26
void setNx(int nx)
Definition: PlotEventInfo.h:49
void setNy(int ny)
Definition: PlotEventInfo.h:51
int ny() const
Definition: PlotEventInfo.h:52
void setInAxesRange(bool flag)
Definition: PlotEventInfo.h:35
void setX(double x)
Definition: PlotEventInfo.h:41
void setY(double y)
Definition: PlotEventInfo.h:43
void setValue(double value)
Definition: PlotEventInfo.h:46
void setLogValueAxis(bool flag)
Definition: PlotEventInfo.h:38
int nx() const
Definition: PlotEventInfo.h:50
Common interface for plot-descriptor interaction.
PLOT_TYPE plotType() const
Returns the type of current plot.
bool axesRangeContains(double xpos, double ypos) const
Returns true if axes rectangle contains given in axes coordinates.
double yAxisCoordToPixel(double axis_coordinate) const
void setMouseTrackingEnabled(bool enable)
Tracks move events (used when showing profile histograms and printing status string)
double xAxisCoordToPixel(double axis_coordinate) const
transform axes coordinates to CustomPlot widget coordinates
SessionItem * currentItem()
QString itemName() const
Get item name, return display name if no name is set.
QVariant getItemValue(const QString &tag) const
Directly access value of item under given tag.
ModelMapper * mapper()
Returns the current model mapper of this item. Creates new one if necessary.
QString modelType() const
Get model type.
SessionItem * getItem(const QString &tag="", int row=0) const
Returns item in given row of given tag.
The UpdateTimer class accumulates update requests during certain period of time, and at the end of th...
Definition: UpdateTimer.h:27
void scheduleUpdate()
Definition: UpdateTimer.cpp:42
void timeToUpdate()
QCPRange itemDataZoom(const IntensityDataItem *item)
Returns z-axis visible range (zoom).
QCPRange itemZoomY(const IntensityDataItem *item)
Returns y-axis vizible range (zoom).
QCPRange itemXrange(const IntensityDataItem *item)
Returns x-axis range.
void setDefaultMargins(QCustomPlot *customPlot)
Sets default margins for axes rectangle plot.
QCPColorGradient itemGradient(const IntensityDataItem *item)
QCPRange itemYrange(const IntensityDataItem *item)
Returns y-axis range.
QCPRange itemZoomX(const IntensityDataItem *item)
Returns x-axis vizible range (zoom).
void setLogz(QCPColorScale *scale, bool isLogz)
int plot_tick_label_size()
int plot_colorbar_size()
QString const & name(EShape k)
Definition: particles.cpp:21
QSize SizeOfLetterM(const QWidget *widget=nullptr)
Returns size of largest letter of default system font.
Definition: StyleUtils.cpp:110
Defines various constants for plotting.