BornAgain  1.19.79
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/View/PlotComparison/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 
25 
26 namespace {
27 
28 const int replot_update_interval = 10;
29 
30 int bin(double x, const QCPGraph* graph);
31 
32 } // namespace
33 
34 Plot1D::Plot1D(QWidget* parent)
35  : ScientificPlot(parent, PLOT_TYPE::Plot1D)
36  , m_custom_plot(new QCustomPlot)
37  , m_update_timer(new UpdateTimer(replot_update_interval, this))
38  , m_block_update(false)
39 {
40  auto* vlayout = new QVBoxLayout(this);
41  vlayout->setContentsMargins(0, 0, 0, 0);
42  vlayout->setSpacing(0);
43  vlayout->addWidget(m_custom_plot);
44  m_custom_plot->setAttribute(Qt::WA_NoMousePropagation, false);
45  setLayout(vlayout);
46 
47  m_custom_plot->xAxis->setTickLabelFont(
48  QFont(QFont().family(), GUI::Constants::plot_tick_label_size()));
49  m_custom_plot->yAxis->setTickLabelFont(
50  QFont(QFont().family(), GUI::Constants::plot_tick_label_size()));
51 
53 }
54 
55 PlotEventInfo Plot1D::eventInfo(double xpos, double ypos) const
56 {
57  PlotEventInfo result(plotType());
58  if (!viewItem())
59  return result;
60 
61  result.setX(xpos);
62  result.setValue(ypos);
63 
64  result.setInAxesRange(axesRangeContains(xpos, ypos));
65  result.setNx(bin(result.x(), m_custom_plot->graph()));
66 
67  return result;
68 }
69 
70 void Plot1D::setLog(bool log)
71 {
74 }
75 
77 {
78  viewItem()->resetView();
79 }
80 
81 void Plot1D::onPropertyChanged(const QString& property_name)
82 {
83  if (m_block_update)
84  return;
85 
86  if (Data1DViewItem::isAxesUnitsPropertyName(property_name)) {
89  replot();
90  }
91 }
92 
93 void Plot1D::onXaxisRangeChanged(QCPRange newRange)
94 {
95  m_block_update = true;
96  viewItem()->setLowerX(newRange.lower);
97  viewItem()->setUpperX(newRange.upper);
98  m_block_update = false;
99 }
100 
101 void Plot1D::onYaxisRangeChanged(QCPRange newRange)
102 {
103  m_block_update = true;
104  viewItem()->setLowerY(newRange.lower);
105  viewItem()->setUpperY(newRange.upper);
106  m_block_update = false;
107 }
108 
110 {
111  m_custom_plot->replot();
112 }
113 
115 {
116  initPlots();
117  refreshPlotData();
118 
120  [this](const QString& name) { onPropertyChanged(name); }, this);
121 
123  [this](SessionItem* item, const QString name) {
124  if (dynamic_cast<BasicAxisItem*>(item))
126  },
127  this);
128 
129  std::for_each(m_graph_map.begin(), m_graph_map.end(), [caller = this](auto pair) {
130  DataItem* dataItem = pair.first->dataItem();
131  connect(dataItem, &DataItem::datafieldChanged, caller,
132  [=](Datafield*) { caller->refreshPlotData(); });
133  });
134 
135  setConnected(true);
136 }
137 
139 {
140  m_custom_plot->clearGraphs();
141  std::for_each(m_graph_map.begin(), m_graph_map.end(), [caller = this](auto pair) {
142  disconnect(pair.first->dataItem(), nullptr, caller, nullptr);
143  });
144  m_graph_map.clear();
145  setConnected(false);
146 }
147 
149 {
150  auto property_items = viewItem()->propertyContainerItem()->propertyItems();
151 
152  std::for_each(property_items.begin(), property_items.end(), [this](Data1DProperties* item) {
153  auto* graph = m_custom_plot->addGraph();
154  graph->setLineStyle(item->line());
155  graph->setPen(QPen(item->color()));
156  graph->setScatterStyle(item->scatter());
157  m_graph_map[item] = graph;
158  });
159 }
160 
161 void Plot1D::setConnected(bool isConnected)
162 {
163  setAxesRangeConnected(isConnected);
164  setUpdateTimerConnected(isConnected);
165 }
166 
167 void Plot1D::setAxesRangeConnected(bool isConnected)
168 {
169  if (isConnected) {
170  connect(m_custom_plot->xAxis,
171  static_cast<void (QCPAxis::*)(const QCPRange&)>(&QCPAxis::rangeChanged), this,
172  &Plot1D::onXaxisRangeChanged, Qt::UniqueConnection);
173 
174  connect(m_custom_plot->yAxis,
175  static_cast<void (QCPAxis::*)(const QCPRange&)>(&QCPAxis::rangeChanged), this,
176  &Plot1D::onYaxisRangeChanged, Qt::UniqueConnection);
177  } else {
178  disconnect(m_custom_plot->xAxis,
179  static_cast<void (QCPAxis::*)(const QCPRange&)>(&QCPAxis::rangeChanged), this,
181 
182  disconnect(m_custom_plot->yAxis,
183  static_cast<void (QCPAxis::*)(const QCPRange&)>(&QCPAxis::rangeChanged), this,
185  }
186 }
187 
188 void Plot1D::setUpdateTimerConnected(bool isConnected)
189 {
190  if (isConnected)
192  Qt::UniqueConnection);
193  else
195 }
196 
198 {
199  if (m_block_update)
200  return;
201 
202  m_block_update = true;
203 
204  auto* view_item = viewItem();
205  ASSERT(view_item);
206 
207  setAxesRangeFromItem(view_item);
208  setAxesLabelsFromItem(view_item);
209  updateAllGraphs();
210 
211  replot();
212 
213  m_block_update = false;
214 }
215 
217 {
218  m_custom_plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
219  m_custom_plot->axisRect()->setupFullAxesBox(true);
220 
221  setAxesRangeConnected(false);
222  m_custom_plot->xAxis->setRange(item->getLowerX(), item->getUpperX());
223  m_custom_plot->yAxis->setRange(item->getLowerY(), item->getUpperY());
224  setLog(item->isLog());
225  setAxesRangeConnected(true);
226 }
227 
229 {
230  setLabel(item->xAxisItem(), m_custom_plot->xAxis, item->getXaxisTitle());
231  setLabel(item->yAxisItem(), m_custom_plot->yAxis, item->getYaxisTitle());
232 }
233 
234 void Plot1D::setLabel(const BasicAxisItem* item, QCPAxis* axis, QString label)
235 {
236  ASSERT(item && axis);
237  if (item->isTitleVisible())
238  axis->setLabel(label);
239  else
240  axis->setLabel(QString());
241 }
242 
244 {
245  auto property_items = viewItem()->propertyContainerItem()->propertyItems();
246  std::for_each(property_items.begin(), property_items.end(),
247  [this](Data1DProperties* item) { updateGraph(item); });
248 }
249 
251 {
252  auto data_points = viewItem()->graphData(item);
253 
254  auto* graph = m_graph_map.at(item);
255  graph->setData(data_points.first, data_points.second, /*alreadySorted =*/true);
256 }
257 
259 {
260  return const_cast<Data1DViewItem*>(static_cast<const Plot1D*>(this)->viewItem());
261 }
262 
264 {
265  const auto* const result = dynamic_cast<const Data1DViewItem*>(currentItem());
266  ASSERT(result);
267  return result;
268 }
269 
270 void Plot1D::modifyAxesProperties(const QString& axisName, const QString& propertyName)
271 {
272  if (m_block_update)
273  return;
274 
275  if (BasicAxisItem::isTitlePropertyName(propertyName)
278  replot();
279  }
280 
281  if (Data1DViewItem::isXAxisPropertyName(axisName)) {
282  if (BasicAxisItem::isBoundsPropertiesName(propertyName)) {
283  setAxesRangeConnected(false);
284  m_custom_plot->xAxis->setRange(viewItem()->getLowerX(), viewItem()->getUpperX());
285  setAxesRangeConnected(true);
286  replot();
287  }
288  } else if (Data1DViewItem::isYAxisPropertyName(axisName)) {
289  if (BasicAxisItem::isBoundsPropertiesName(propertyName)) {
290  setAxesRangeConnected(false);
291  m_custom_plot->yAxis->setRange(viewItem()->getLowerY(), viewItem()->getUpperY());
292  setAxesRangeConnected(true);
293  replot();
294  } else if (AmplitudeAxisItem::isLogScalePropertyName(propertyName)) {
295  setLog(viewItem()->isLog());
296  replot();
297  }
298  }
299 }
300 
302 {
304 }
305 
306 namespace {
307 
308 int bin(double x, const QCPGraph* graph)
309 {
310  const int key_start = graph->findBegin(x);
311  const int key_end = graph->findBegin(x, false); // false = do not expand range
312  if (key_end == key_start || key_end == graph->dataCount())
313  return key_start;
314  return (x - graph->dataSortKey(key_start)) <= (graph->dataSortKey(key_end) - x) ? key_start
315  : key_end;
316 }
317 
318 } // namespace
Defines various axis items.
Defines class Data1DViewItem.
Declares class DataItem.
Defines class DataProperties and its descendants.
Defines class DataPropertyContainer.
Defines class Plot1D.
Defines various constants for plotting.
Defines the class PlotEventInfo.
Defines RangeUtils namespace.
Defines class UpdateTimer.
static bool isLogScalePropertyName(const QString &name)
Definition: AxesItems.cpp:193
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 bool isTitleVisiblePropertyName(const QString &name)
Definition: AxesItems.cpp:105
Holds data required for 1D DataItem representation.
View model for 1D DataItem. Can represent several items at once. In current implementation the first ...
static bool isXAxisPropertyName(const QString &name)
static bool isAxesUnitsPropertyName(const QString &name)
static bool isYAxisPropertyName(const QString &name)
double getUpperY() const
bool isLog() const
const AmplitudeAxisItem * yAxisItem() const
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)
void setUpperX(double value)
double getUpperX() const
QVector< Data1DProperties * > propertyItems()
void setOnPropertyChange(std::function< void(QString)> f, const void *caller=nullptr)
Definition: ModelMapper.cpp:39
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
void onTimeToReplot()
Replots SpecularPlot.
Definition: Plot1D.cpp:109
void updateAllGraphs()
Sets data to graphs.
Definition: Plot1D.cpp:243
void initPlots()
creates and initializes the color map
Definition: Plot1D.cpp:148
void setAxesRangeConnected(bool isConnected)
Connects/disconnects signals related to SpecularPlot's X,Y axes rectangle change.
Definition: Plot1D.cpp:167
void resetView()
reset all axes min,max to initial value
Definition: Plot1D.cpp:76
Plot1D(QWidget *parent=nullptr)
Definition: Plot1D.cpp:34
void setAxesLabelsFromItem(Data1DViewItem *item)
Sets X,Y axes labels from item.
Definition: Plot1D.cpp:228
void setAxesRangeFromItem(Data1DViewItem *item)
Sets (xmin,xmax) and (ymin,ymax) of SpecularPlot from specular item. Also sets logarithmic scale on y...
Definition: Plot1D.cpp:216
void setConnected(bool isConnected)
Definition: Plot1D.cpp:161
void refreshPlotData()
Refresh axes' labels, range and graph data.
Definition: Plot1D.cpp:197
void setUpdateTimerConnected(bool isConnected)
Definition: Plot1D.cpp:188
void replot()
Schedule replot for later execution by onTimeReplot() slot.
Definition: Plot1D.cpp:301
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:55
void updateGraph(Data1DProperties *item)
Sets data to the graph corresponding to the passed Data1DProperties.
Definition: Plot1D.cpp:250
void onPropertyChanged(const QString &property_name)
updates plot depending on IntensityDataItem properties
Definition: Plot1D.cpp:81
void onYaxisRangeChanged(QCPRange newRange)
Propagate ymin, ymax back to IntensityDataItem.
Definition: Plot1D.cpp:101
void setLog(bool log)
sets logarithmic scale
Definition: Plot1D.cpp:70
Data1DViewItem * viewItem()
Definition: Plot1D.cpp:258
bool m_block_update
Definition: Plot1D.h:112
void unsubscribeFromItem() override
Definition: Plot1D.cpp:138
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:234
void onXaxisRangeChanged(QCPRange newRange)
Propagate xmin, xmax back to IntensityDataItem.
Definition: Plot1D.cpp:93
void modifyAxesProperties(const QString &axisName, const QString &propertyName)
Definition: Plot1D.cpp:270
void subscribeToItem() override
Definition: Plot1D.cpp:114
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()
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.
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