BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
Plot1D.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/Plot1D.cpp
6 //! @brief Implements class Plot1D
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"
26 
27 namespace {
28 const int replot_update_interval = 10;
29 
30 int bin(double x, const QCPGraph* graph);
31 } // namespace
32 
33 Plot1D::Plot1D(QWidget* parent)
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(false)
38 {
39  QVBoxLayout* vlayout = new QVBoxLayout(this);
40  vlayout->setContentsMargins(0, 0, 0, 0);
41  vlayout->setSpacing(0);
42  vlayout->addWidget(m_custom_plot);
43  setLayout(vlayout);
44 
45  m_custom_plot->xAxis->setTickLabelFont(
46  QFont(QFont().family(), Constants::plot_tick_label_size()));
47  m_custom_plot->yAxis->setTickLabelFont(
48  QFont(QFont().family(), Constants::plot_tick_label_size()));
49 
51 }
52 
53 PlotEventInfo Plot1D::eventInfo(double xpos, double ypos) const
54 {
55  PlotEventInfo result(plotType());
56  if (!viewItem())
57  return result;
58 
59  result.setX(xpos);
60  result.setValue(ypos);
61 
62  result.setInAxesRange(axesRangeContains(xpos, ypos));
63  result.setNx(bin(result.x(), m_custom_plot->graph()));
64 
65  return result;
66 }
67 
68 void Plot1D::setLog(bool log)
69 {
72 }
73 
75 {
76  viewItem()->resetView();
77 }
78 
79 void Plot1D::onPropertyChanged(const QString& property_name)
80 {
81  if (m_block_update)
82  return;
83 
84  if (property_name == Data1DViewItem::P_AXES_UNITS) {
87  replot();
88  }
89 }
90 
91 void Plot1D::onXaxisRangeChanged(QCPRange newRange)
92 {
93  m_block_update = true;
94  viewItem()->setLowerX(newRange.lower);
95  viewItem()->setUpperX(newRange.upper);
96  m_block_update = false;
97 }
98 
99 void Plot1D::onYaxisRangeChanged(QCPRange newRange)
100 {
101  m_block_update = true;
102  viewItem()->setLowerY(newRange.lower);
103  viewItem()->setUpperY(newRange.upper);
104  m_block_update = false;
105 }
106 
108 {
109  m_custom_plot->replot();
110 }
111 
113 {
114  initPlots();
115  refreshPlotData();
116 
118  [this](const QString& name) { onPropertyChanged(name); }, this);
119 
121  [this](SessionItem* item, const QString name) {
122  if (dynamic_cast<BasicAxisItem*>(item))
124  },
125  this);
126 
127  std::for_each(m_graph_map.begin(), m_graph_map.end(), [caller = this](auto pair) {
128  auto property_item = pair.first;
129  property_item->dataItem()->mapper()->setOnValueChange(
130  [caller]() { caller->refreshPlotData(); }, caller);
131  });
132 
133  setConnected(true);
134 }
135 
137 {
138  m_custom_plot->clearGraphs();
139  std::for_each(m_graph_map.begin(), m_graph_map.end(), [caller = this](auto pair) {
140  pair.first->dataItem()->mapper()->unsubscribe(caller);
141  });
142  m_graph_map.clear();
143  setConnected(false);
144 }
145 
147 {
148  auto property_items = viewItem()->propertyContainerItem()->propertyItems();
149  std::for_each(property_items.begin(), property_items.end(), [this](Data1DProperties* item) {
150  auto graph = m_custom_plot->addGraph();
151  graph->setLineStyle(QCPGraph::lsLine);
152  graph->setPen(QPen(item->color()));
153  m_graph_map[item] = graph;
154  });
155 }
156 
157 void Plot1D::setConnected(bool isConnected)
158 {
159  setAxesRangeConnected(isConnected);
160  setUpdateTimerConnected(isConnected);
161 }
162 
163 void Plot1D::setAxesRangeConnected(bool isConnected)
164 {
165  if (isConnected) {
166  connect(m_custom_plot->xAxis,
167  static_cast<void (QCPAxis::*)(const QCPRange&)>(&QCPAxis::rangeChanged), this,
168  &Plot1D::onXaxisRangeChanged, Qt::UniqueConnection);
169 
170  connect(m_custom_plot->yAxis,
171  static_cast<void (QCPAxis::*)(const QCPRange&)>(&QCPAxis::rangeChanged), this,
172  &Plot1D::onYaxisRangeChanged, Qt::UniqueConnection);
173 
174  } else {
175  disconnect(m_custom_plot->xAxis,
176  static_cast<void (QCPAxis::*)(const QCPRange&)>(&QCPAxis::rangeChanged), this,
178 
179  disconnect(m_custom_plot->yAxis,
180  static_cast<void (QCPAxis::*)(const QCPRange&)>(&QCPAxis::rangeChanged), this,
182  }
183 }
184 
185 void Plot1D::setUpdateTimerConnected(bool isConnected)
186 {
187  if (isConnected)
189  Qt::UniqueConnection);
190  else
192 }
193 
195 {
196  if (m_block_update)
197  return;
198 
199  m_block_update = true;
200 
201  auto view_item = viewItem();
202  ASSERT(view_item);
203 
204  setAxesRangeFromItem(view_item);
205  setAxesLabelsFromItem(view_item);
206  updateAllGraphs();
207 
208  replot();
209 
210  m_block_update = false;
211 }
212 
214 {
215  m_custom_plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
216  m_custom_plot->axisRect()->setupFullAxesBox(true);
217 
218  setAxesRangeConnected(false);
219  m_custom_plot->xAxis->setRange(item->getLowerX(), item->getUpperX());
220  m_custom_plot->yAxis->setRange(item->getLowerY(), item->getUpperY());
221  setLog(item->isLog());
222  setAxesRangeConnected(true);
223 }
224 
226 {
227  setLabel(item->xAxisItem(), m_custom_plot->xAxis, item->getXaxisTitle());
228  setLabel(item->yAxisItem(), m_custom_plot->yAxis, item->getYaxisTitle());
229 }
230 
231 void Plot1D::setLabel(const BasicAxisItem* item, QCPAxis* axis, QString label)
232 {
233  ASSERT(item && axis);
235  axis->setLabel(std::move(label));
236  else
237  axis->setLabel(QString());
238 }
239 
241 {
242  auto property_items = viewItem()->propertyContainerItem()->propertyItems();
243  std::for_each(property_items.begin(), property_items.end(),
244  [this](Data1DProperties* item) { updateGraph(item); });
245 }
246 
248 {
249  auto data_points = viewItem()->graphData(item);
250 
251  auto graph = m_graph_map.at(item);
252  graph->setData(data_points.first, data_points.second, /*sorted =*/true);
253 }
254 
256 {
257  return const_cast<Data1DViewItem*>(static_cast<const Plot1D*>(this)->viewItem());
258 }
259 
261 {
262  const auto result = dynamic_cast<const Data1DViewItem*>(currentItem());
263  ASSERT(result);
264  return result;
265 }
266 
267 void Plot1D::modifyAxesProperties(const QString& axisName, const QString& propertyName)
268 {
269  if (m_block_update)
270  return;
271 
272  if (propertyName == BasicAxisItem::P_TITLE
273  || propertyName == BasicAxisItem::P_TITLE_IS_VISIBLE) {
275  replot();
276  }
277 
278  if (axisName == Data1DViewItem::P_XAXIS) {
279  if (propertyName == BasicAxisItem::P_MIN_DEG || propertyName == BasicAxisItem::P_MAX_DEG) {
280  setAxesRangeConnected(false);
281  m_custom_plot->xAxis->setRange(viewItem()->getLowerX(), viewItem()->getUpperX());
282  setAxesRangeConnected(true);
283  replot();
284  }
285  } else if (axisName == Data1DViewItem::P_YAXIS) {
286  if (propertyName == BasicAxisItem::P_MIN_DEG || propertyName == BasicAxisItem::P_MAX_DEG) {
287  setAxesRangeConnected(false);
288  m_custom_plot->yAxis->setRange(viewItem()->getLowerY(), viewItem()->getUpperY());
289  setAxesRangeConnected(true);
290  replot();
291  } else if (propertyName == AmplitudeAxisItem::P_IS_LOGSCALE) {
292  setLog(viewItem()->isLog());
293  replot();
294  }
295  }
296 }
297 
299 {
301 }
302 
303 namespace {
304 int bin(double x, const QCPGraph* graph)
305 {
306  const int key_start = graph->findBegin(x);
307  const int key_end = graph->findBegin(x, false); // false = do not expand range
308  if (key_end == key_start || key_end == graph->dataCount())
309  return key_start;
310  return (x - graph->dataSortKey(key_start)) <= (graph->dataSortKey(key_end) - x) ? key_start
311  : key_end;
312 }
313 } // namespace
#define ASSERT(condition)
Definition: Assert.h:31
Defines various axis items.
Defines ColorMapUtils namespace.
Defines M_PI and some more mathematical constants.
Defines class Data1DViewItem.
Declares class DataItem.
Defines class DataProperties and its descendants.
Defines class DataPropertyContainer.
Defines class Plot1D.
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_TITLE_IS_VISIBLE
Definition: AxesItems.h:30
static const QString P_MIN_DEG
Definition: AxesItems.h:27
Holds data required for 1D DataItem representation.
View model for 1D DataItem.
static const QString P_YAXIS
double getUpperY() const
bool isLog() const
const AmplitudeAxisItem * yAxisItem() const
static const QString P_AXES_UNITS
DataPropertyContainer * propertyContainerItem()
void resetView()
Set axes viewport to original data.
double getLowerY() const
returns lower and upper zoom ranges of y-axis
const BasicAxisItem * xAxisItem() const
QString getYaxisTitle() const
void setUpperY(double value)
QString getXaxisTitle() const
double getLowerX() const
returns lower and upper zoom ranges of x-axis
QPair< QVector< double >, QVector< double > > graphData(Data1DProperties *property_item)
Returns point data for drawing.
void setLowerX(double value)
void setLowerY(double value)
static const QString P_XAXIS
void setUpperX(double value)
double getUpperX() const
QVector< Data1DProperties * > propertyItems()
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
The Plot1D class presents data of several 1D DataItems contained in a Data1DViewItem.
Definition: Plot1D.h:32
void onTimeToReplot()
Replots SpecularPlot.
Definition: Plot1D.cpp:107
void updateAllGraphs()
Sets data to graphs.
Definition: Plot1D.cpp:240
void initPlots()
creates and initializes the color map
Definition: Plot1D.cpp:146
void setAxesRangeConnected(bool isConnected)
Connects/disconnects signals related to SpecularPlot's X,Y axes rectangle change.
Definition: Plot1D.cpp:163
void resetView()
reset all axes min,max to initial value
Definition: Plot1D.cpp:74
Plot1D(QWidget *parent=nullptr)
Definition: Plot1D.cpp:33
void setAxesLabelsFromItem(Data1DViewItem *item)
Sets X,Y axes labels from item.
Definition: Plot1D.cpp:225
void setAxesRangeFromItem(Data1DViewItem *item)
Sets (xmin,xmax) and (ymin,ymax) of SpecularPlot from specular item.
Definition: Plot1D.cpp:213
void setConnected(bool isConnected)
Definition: Plot1D.cpp:157
void refreshPlotData()
Refresh axes' labels, range and graph data.
Definition: Plot1D.cpp:194
void setUpdateTimerConnected(bool isConnected)
Definition: Plot1D.cpp:185
void replot()
Schedule replot for later execution by onTimeReplot() slot.
Definition: Plot1D.cpp:298
QCustomPlot * m_custom_plot
Definition: Plot1D.h:108
UpdateTimer * m_update_timer
Definition: Plot1D.h:109
PlotEventInfo eventInfo(double xpos, double ypos) const override
Returns PlotEventInfo corresponding to given axes coordinates.
Definition: Plot1D.cpp:53
void updateGraph(Data1DProperties *item)
Sets data to the graph corresponding to the passed Data1DProperties.
Definition: Plot1D.cpp:247
void onPropertyChanged(const QString &property_name)
updates plot depending on IntensityDataItem properties
Definition: Plot1D.cpp:79
void onYaxisRangeChanged(QCPRange newRange)
Propagate ymin, ymax back to IntensityDataItem.
Definition: Plot1D.cpp:99
void setLog(bool log)
sets logarithmic scale
Definition: Plot1D.cpp:68
Data1DViewItem * viewItem()
Definition: Plot1D.cpp:255
bool m_block_update
Definition: Plot1D.h:112
void unsubscribeFromItem() override
Definition: Plot1D.cpp:136
std::map< Data1DProperties *, QCPGraph * > m_graph_map
Definition: Plot1D.h:110
void setLabel(const BasicAxisItem *item, QCPAxis *axis, QString label)
Sets label to axis.
Definition: Plot1D.cpp:231
void onXaxisRangeChanged(QCPRange newRange)
Propagate xmin, xmax back to IntensityDataItem.
Definition: Plot1D.cpp:91
void modifyAxesProperties(const QString &axisName, const QString &propertyName)
Definition: Plot1D.cpp:267
void subscribeToItem() override
Definition: Plot1D.cpp:112
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
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()
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.
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()
void setLogz(QCPColorScale *scale, bool isLogz)
int plot_tick_label_size()
QString const & name(EShape k)
Definition: particles.cpp:21
Defines various constants for plotting.