BornAgain  1.19.79
Simulate and fit neutron and x-ray scattering at grazing incidence
SpecularPlot.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/View/PlotSpecular/SpecularPlot.cpp
6 //! @brief Implements class SpecularPlot
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/Axis/Frame.h"
24 
25 namespace {
26 
27 const int replot_update_interval = 10;
28 
29 int bin(double x, const QCPGraph* graph);
30 
31 } // namespace
32 
34  : ScientificPlot(parent, PLOT_TYPE::Plot1D)
35  , m_custom_plot(new QCustomPlot)
36  , m_update_timer(new UpdateTimer(replot_update_interval, this))
37  , m_block_update(true)
38 {
39  initPlot();
40 
41  auto* vlayout = new QVBoxLayout(this);
42  vlayout->setContentsMargins(0, 0, 0, 0);
43  vlayout->setSpacing(0);
44  vlayout->addWidget(m_custom_plot);
45  m_custom_plot->setAttribute(Qt::WA_NoMousePropagation, false);
46  setLayout(vlayout);
47 
49 }
50 
51 PlotEventInfo SpecularPlot::eventInfo(double xpos, double ypos) const
52 {
53  PlotEventInfo result(plotType());
54  if (!specularItem())
55  return result;
56 
57  result.setX(xpos);
58  result.setValue(ypos);
59 
60  result.setInAxesRange(axesRangeContains(xpos, ypos));
61  result.setNx(bin(result.x(), m_custom_plot->graph()));
62 
63  return result;
64 }
65 
66 void SpecularPlot::setLog(bool log)
67 {
70 }
71 
73 {
75 }
76 
77 void SpecularPlot::onPropertyChanged(const QString& property_name)
78 {
79  if (m_block_update)
80  return;
81 
82  if (DataItem::isAxesUnitsPropertyName(property_name)) {
84  replot();
85  }
86 }
87 
88 void SpecularPlot::onXaxisRangeChanged(QCPRange newRange)
89 {
90  m_block_update = true;
91  specularItem()->setLowerX(newRange.lower);
92  specularItem()->setUpperX(newRange.upper);
93  m_block_update = false;
94 }
95 
96 void SpecularPlot::onYaxisRangeChanged(QCPRange newRange)
97 {
98  m_block_update = true;
99  specularItem()->setLowerY(newRange.lower);
100  specularItem()->setUpperY(newRange.upper);
101  m_block_update = false;
102 }
103 
105 {
106  m_custom_plot->replot();
107 }
108 
110 {
112 
114  [this](const QString& name) { onPropertyChanged(name); }, this);
115 
117  [this](SessionItem* item, const QString name) {
118  if (item->modelType() == BasicAxisItem::M_TYPE
119  || item->modelType() == AmplitudeAxisItem::M_TYPE)
121  },
122  this);
123 
124  specularItem()->mapper()->setOnValueChange([this]() { setPlotFromItem(this->specularItem()); },
125  this);
126 
127  setConnected(true);
128 }
129 
131 {
132  setConnected(false);
133 }
134 
136 {
137  m_custom_plot->addGraph();
138 
139  QPen pen(QColor(0, 0, 255, 200));
140  m_custom_plot->graph()->setLineStyle(QCPGraph::lsLine);
141  m_custom_plot->graph()->setPen(pen);
142 
143  m_custom_plot->xAxis->setTickLabelFont(
144  QFont(QFont().family(), GUI::Constants::plot_tick_label_size()));
145  m_custom_plot->yAxis->setTickLabelFont(
146  QFont(QFont().family(), GUI::Constants::plot_tick_label_size()));
147 }
148 
150 {
151  if (dynamic_cast<RealDataItem*>(specularItem()->parentItem())) {
152  m_custom_plot->graph()->setScatterStyle(QCPScatterStyle::ssDisc);
153  } else {
154  m_custom_plot->graph()->setScatterStyle(QCPScatterStyle::ssNone);
155  }
156  m_custom_plot->replot();
157 }
158 
159 void SpecularPlot::setConnected(bool isConnected)
160 {
161  setAxesRangeConnected(isConnected);
162  setUpdateTimerConnected(isConnected);
163 }
164 
166 {
167  if (isConnected) {
168  connect(m_custom_plot->xAxis,
169  static_cast<void (QCPAxis::*)(const QCPRange&)>(&QCPAxis::rangeChanged), this,
170  &SpecularPlot::onXaxisRangeChanged, Qt::UniqueConnection);
171 
172  connect(m_custom_plot->yAxis,
173  static_cast<void (QCPAxis::*)(const QCPRange&)>(&QCPAxis::rangeChanged), this,
174  &SpecularPlot::onYaxisRangeChanged, Qt::UniqueConnection);
175  } else {
176  disconnect(m_custom_plot->xAxis,
177  static_cast<void (QCPAxis::*)(const QCPRange&)>(&QCPAxis::rangeChanged), this,
179 
180  disconnect(m_custom_plot->yAxis,
181  static_cast<void (QCPAxis::*)(const QCPRange&)>(&QCPAxis::rangeChanged), this,
183  }
184 }
185 
187 {
188  if (isConnected)
190  Qt::UniqueConnection);
191  else
193 }
194 
196 {
197  ASSERT(specularItem);
198 
199  m_block_update = true;
200 
201  m_custom_plot->graph(0)->data()->clear();
205 
206  replot();
207 
208  m_block_update = false;
209 }
210 
212 {
213  m_custom_plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
214  m_custom_plot->axisRect()->setupFullAxesBox(true);
215 
216  setAxesRangeConnected(false);
217  m_custom_plot->xAxis->setRange(item->getLowerX(), item->getUpperX());
218  m_custom_plot->yAxis->setRange(item->getLowerY(), item->getUpperY());
219  setLog(item->isLog());
220  setAxesRangeConnected(true);
221 }
222 
224 {
225  setLabel(item->xAxisItem(), m_custom_plot->xAxis, item->getXaxisTitle());
226  setLabel(item->yAxisItem(), m_custom_plot->yAxis, item->getYaxisTitle());
227 }
228 
229 void SpecularPlot::setLabel(const BasicAxisItem* item, QCPAxis* axis, QString label)
230 {
231  ASSERT(item && axis);
232  if (item->isTitleVisible())
233  axis->setLabel(label);
234  else
235  axis->setLabel(QString());
236 }
237 
239 {
240  ASSERT(item);
241  auto* data = item->getDatafield();
242  if (!data)
243  return;
244 
245  for (size_t i = 0, size = data->size(); i < size; ++i) {
246  double x = data->frame().projectedCoord(i, 0);
247  double y = data->operator[](i);
248  m_custom_plot->graph()->addData(x, y);
249  }
250 }
251 
253 {
254  return const_cast<SpecularDataItem*>(static_cast<const SpecularPlot*>(this)->specularItem());
255 }
256 
258 {
259  const auto* const result = dynamic_cast<const SpecularDataItem*>(currentItem());
260  return result;
261 }
262 
263 void SpecularPlot::modifyAxesProperties(const QString& axisName, const QString& propertyName)
264 {
265  if (m_block_update)
266  return;
267 
268  if (BasicAxisItem::isTitlePropertyName(propertyName)
271  replot();
272  }
273 
275  if (BasicAxisItem::isBoundsPropertiesName(propertyName)) {
276  setAxesRangeConnected(false);
277  m_custom_plot->xAxis->setRange(specularItem()->getLowerX(),
278  specularItem()->getUpperX());
279  setAxesRangeConnected(true);
280  replot();
281  }
282  } else if (SpecularDataItem::isYaxisPropertyName(axisName)) {
283  if (BasicAxisItem::isBoundsPropertiesName(propertyName)) {
284  setAxesRangeConnected(false);
285  m_custom_plot->yAxis->setRange(specularItem()->getLowerY(),
286  specularItem()->getUpperY());
287  setAxesRangeConnected(true);
288  replot();
289  } else if (AmplitudeAxisItem::isLogScalePropertyName(propertyName)) {
290  setLog(specularItem()->isLog());
291  replot();
292  }
293  }
294 }
295 
297 {
299 }
300 
301 namespace {
302 
303 int bin(double x, const QCPGraph* graph)
304 {
305  const int key_start = graph->findBegin(x);
306  const int key_end = graph->findBegin(x, false); // false = do not expand range
307  if (key_end == key_start || key_end == graph->dataCount())
308  return key_start;
309  return (x - graph->dataSortKey(key_start)) <= (graph->dataSortKey(key_end) - x) ? key_start
310  : key_end;
311 }
312 
313 } // namespace
Defines various axis items.
Defines various constants for plotting.
Defines the class PlotEventInfo.
Defines RangeUtils namespace.
Defines class RealDataItem.
Defines class SpecularDataItem.
Defines class SpecularPlot.
Defines class UpdateTimer.
static bool isLogScalePropertyName(const QString &name)
Definition: AxesItems.cpp:193
static constexpr auto M_TYPE
Definition: AxesItems.h:81
bool isTitleVisible() const
Definition: AxesItems.cpp:100
static bool isBoundsPropertiesName(const QString &name)
either lower bound or upper bound property name
Definition: AxesItems.cpp:75
static bool isTitlePropertyName(const QString &name)
Definition: AxesItems.cpp:95
static constexpr auto M_TYPE
Definition: AxesItems.h:35
static bool isTitleVisiblePropertyName(const QString &name)
Definition: AxesItems.cpp:105
static bool isAxesUnitsPropertyName(const QString &name)
Definition: DataItem.cpp:113
Datafield * getDatafield()
Definition: DataItem.h:41
void setOnPropertyChange(std::function< void(QString)> f, const void *caller=nullptr)
Definition: ModelMapper.cpp:39
void setOnValueChange(std::function< void(void)> f, const void *caller=nullptr)
Definition: ModelMapper.cpp:34
void setOnChildPropertyChange(std::function< void(SessionItem *, QString)> f, const void *caller=nullptr)
Calls back on child property change, report childItem and property name.
Definition: ModelMapper.cpp:53
The Plot1D class presents data of several 1D DataItems contained in a Data1DViewItem....
Definition: Plot1D.h:32
Contains parameters of mouse position in 1D or 2D plot.
Definition: PlotEventInfo.h:26
double x() const
Definition: PlotEventInfo.h:42
void setNx(int nx)
Definition: PlotEventInfo.h:49
void setInAxesRange(bool flag)
Definition: PlotEventInfo.h:35
void setX(double x)
Definition: PlotEventInfo.h:41
void setValue(double value)
Definition: PlotEventInfo.h:46
Provides access to experimental data, for display and fitting. Owns an AbstractDataLoader.
Definition: RealDataItem.h:33
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.
void setMouseTrackingEnabled(bool enable)
Tracks move events (used when showing profile histograms and printing status string)
SessionItem * currentItem()
Base class for a GUI data item.
Definition: SessionItem.h:204
QString itemName() const
Get item name, return display name if no name is set.
ModelMapper * mapper()
Returns the current model mapper of this item. Creates new one if necessary.
QString modelType() const
Get model type.
double getLowerY() const
Returns lower and upper zoom ranges of y-axis.
QString getXaxisTitle() const
void setUpperY(double value)
static bool isXaxisPropertyName(const QString &name)
void setUpperX(double value)
void setLowerX(double value)
void setLowerY(double value)
double getUpperY() const
double getLowerX() const
Returns lower and upper zoom ranges of x-axis.
QString getYaxisTitle() const
static bool isYaxisPropertyName(const QString &name)
void resetView()
Set axes viewport to original data.
double getUpperX() const
const AmplitudeAxisItem * yAxisItem() const
const BasicAxisItem * xAxisItem() const
The SpecularPlot class presents 1D intensity data from SpecularDataItem.
Definition: SpecularPlot.h:32
bool m_block_update
Definition: SpecularPlot.h:111
void initPlot()
creates and initializes the color map
void setAxesRangeConnected(bool isConnected)
Connects/disconnects signals related to SpecularPlot's X,Y axes rectangle change.
void setConnected(bool isConnected)
void setAxesLabelsFromItem(SpecularDataItem *item)
Sets X,Y axes labels from item.
SpecularPlot(QWidget *parent=nullptr)
void setLog(bool log)
sets logarithmic scale
PlotEventInfo eventInfo(double xpos, double ypos) const override
Returns PlotEventInfo corresponding to given axes coordinates.
UpdateTimer * m_update_timer
Definition: SpecularPlot.h:109
void setUpdateTimerConnected(bool isConnected)
void onXaxisRangeChanged(QCPRange newRange)
Propagate xmin, xmax back to IntensityDataItem.
void setPlotFromItem(SpecularDataItem *specularItem)
Sets initial state of SpecularPlot to match given intensity item.
void initScatter()
Adds scatter ro real data plot.
void setAxesRangeFromItem(SpecularDataItem *item)
Sets (xmin,xmax) and (ymin,ymax) of SpecularPlot from specular item. Also sets logarithmic scale on y...
void modifyAxesProperties(const QString &axisName, const QString &propertyName)
void onTimeToReplot()
Replots SpecularPlot.
void setLabel(const BasicAxisItem *item, QCPAxis *axis, QString label)
Sets label to axis.
void onPropertyChanged(const QString &property_name)
updates plot depending on IntensityDataItem properties
QCustomPlot * m_custom_plot
Definition: SpecularPlot.h:108
void setDataFromItem(SpecularDataItem *item)
Sets the intensity values to SpecularPlot.
void subscribeToItem() override
SpecularDataItem * specularItem()
void replot()
Schedule replot for later execution by onTimeReplot() slot.
void unsubscribeFromItem() override
void onYaxisRangeChanged(QCPRange newRange)
Propagate ymin, ymax back to IntensityDataItem.
void resetView()
reset all axes min,max to initial value
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()
int plot_tick_label_size()
Definition: PlotConstants.h:23
QString const & name(EShape k)
Definition: particles.cpp:20
void setLogz(QCPColorScale *scale, bool isLogz)
Definition: RangeUtils.cpp:110