BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
ProjectionsPlot.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/ProjectionsPlot.cpp
6 //! @brief Defines class ProjectionCanvas
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 
24 #include <qcustomplot.h>
25 
26 ProjectionsPlot::ProjectionsPlot(const QString& projectionType, QWidget* parent)
27  : SessionItemWidget(parent)
28  , m_projectionType(projectionType)
29  , m_customPlot(new QCustomPlot)
30  , m_block_plot_update(false)
31 {
32  QVBoxLayout* vlayout = new QVBoxLayout(this);
33  vlayout->setMargin(0);
34  vlayout->setSpacing(0);
35  vlayout->addWidget(m_customPlot);
36  setLayout(vlayout);
37 
38  m_customPlot->xAxis->setTickLabelFont(
39  QFont(QFont().family(), Constants::plot_tick_label_size()));
40  m_customPlot->yAxis->setTickLabelFont(
41  QFont(QFont().family(), Constants::plot_tick_label_size()));
42 
44 }
45 
47 {
49 }
50 
51 void ProjectionsPlot::onMarginsChanged(double left, double right)
52 {
53  QMargins orig = m_customPlot->axisRect()->margins();
54  m_customPlot->axisRect()->setMargins(QMargins(left, orig.top(), right, orig.bottom()));
55  replot();
56 }
57 
59 {
60  // Update projection plot on new item appearance
62  [this](SessionItem* item) {
63  if (item)
65  },
66  this);
67 
68  // Remove projection plot
70  [this](SessionItem* item) { clearProjection(item); }, this);
71 
72  // Update projection position
74  [this](SessionItem* item, const QString& name) { onProjectionPropertyChanged(item, name); },
75  this);
76 
77  // Values of intensity changed, regenerate everything.
79  [this]() {
82  },
83  this);
84 
85  // IntensityItem property (e.g. interpolation changed)
87  [this](const QString& name) { onIntensityItemPropertyChanged(name); }, this);
88 
89  // Update to changed IntensityDataItem axes
91  [this](SessionItem* item, const QString name) {
92  if (item->modelType() == "BasicAxis" || item->modelType() == "AmplitudeAxis")
94  },
95  this);
96 
99 }
100 
102 {
105 }
106 
107 void ProjectionsPlot::onProjectionPropertyChanged(SessionItem* item, const QString& property)
108 {
110  return;
111 
112  m_block_plot_update = true;
113 
114  if (property == HorizontalLineItem::P_POSY || property == VerticalLineItem::P_POSX) {
115  if (auto graph = graphForItem(item))
116  setGraphFromItem(graph, item);
117 
118  replot();
119  }
120 
121  m_block_plot_update = false;
122 }
123 
125 {
126  IntensityDataItem* result = dynamic_cast<IntensityDataItem*>(currentItem());
127  ASSERT(result);
128  return result;
129 }
130 
132 {
133  ProjectionContainerItem* result = dynamic_cast<ProjectionContainerItem*>(
135  ASSERT(result);
136  return result;
137 }
138 
139 QVector<SessionItem*> ProjectionsPlot::projectionItems()
140 {
142 }
143 
145 {
146  if (item->modelType() != m_projectionType)
147  return nullptr;
148 
149  QCPGraph* graph = m_item_to_graph[item];
150  if (!graph) {
151  graph = m_customPlot->addGraph();
152  QPen pen;
153  pen.setColor(QColor(0, 0, 255, 200));
154  graph->setLineStyle(intensityItem()->isInterpolated() ? QCPGraph::lsLine
155  : QCPGraph::lsStepCenter);
156  graph->setPen(pen);
157  m_item_to_graph[item] = graph;
158  }
159 
160  return graph;
161 }
162 
164 {
165  if (currentItem())
167 }
168 
169 //! Creates cached 2D histogram for later projection calculations.
170 
172 {
173  m_hist2d = std::make_unique<Histogram2D>(*intensityItem()->getOutputData());
174  updateAxesRange();
175  updateAxesTitle();
176  setLogz(intensityItem()->isLogz());
177 }
178 
179 //! Runs through all projection items and generates missed plots.
180 
182 {
184  return;
185 
186  m_block_plot_update = true;
187 
188  for (auto projItem : projectionItems())
189  setGraphFromItem(graphForItem(projItem), projItem);
190 
191  replot();
192 
193  m_block_plot_update = false;
194 }
195 
196 //! Updates canva's axes to match current zoom level of IntensityDataItem
197 
199 {
200  if (isHorizontalType())
202  else
204 
206 }
207 
209 {
210  if (isHorizontalType())
211  m_customPlot->xAxis->setLabel(intensityItem()->getXaxisTitle());
212  else
213  m_customPlot->xAxis->setLabel(intensityItem()->getYaxisTitle());
214 }
215 
216 //! Clears all graphs corresponding to projection items.
217 
219 {
220  m_block_plot_update = true;
221 
222  m_customPlot->clearPlottables();
223  m_item_to_graph.clear();
224 
225  replot();
226 
227  m_block_plot_update = false;
228 }
229 
230 //! Removes plot corresponding to given projection item.
231 
233 {
234  if (auto graph = graphForItem(item)) {
235  m_block_plot_update = true;
236  m_customPlot->removePlottable(graph);
237  m_item_to_graph.remove(item);
238  replot();
239  m_block_plot_update = false;
240  }
241 }
242 
243 //! Updates projection appearance (line style, etc)
244 
245 void ProjectionsPlot::onIntensityItemPropertyChanged(const QString& propertyName)
246 {
247  if (propertyName == IntensityDataItem::P_IS_INTERPOLATED) {
248  setInterpolate(intensityItem()->isInterpolated());
249  replot();
250  }
251 }
252 
253 //! Updates zoom of projections in accordance with IntensityDataItem.
254 
255 void ProjectionsPlot::onAxisPropertyChanged(const QString& axisName, const QString& propertyName)
256 {
257  Q_UNUSED(axisName);
258 
259  if (propertyName == BasicAxisItem::P_MIN_DEG || propertyName == BasicAxisItem::P_MAX_DEG)
260  updateAxesRange();
261  else if (propertyName == BasicAxisItem::P_TITLE)
262  updateAxesTitle();
263  else if (propertyName == AmplitudeAxisItem::P_IS_LOGSCALE)
264  setLogz(intensityItem()->isLogz());
265 
266  replot();
267 }
268 
269 //! Sets the data to graph from given projection iten.
270 
271 void ProjectionsPlot::setGraphFromItem(QCPGraph* graph, SessionItem* item)
272 {
273  std::unique_ptr<Histogram1D> hist;
274 
275  if (item->modelType() == "HorizontalLineMask") {
276  double value = item->getItemValue(HorizontalLineItem::P_POSY).toDouble();
277  hist.reset(m_hist2d->projectionX(value));
278  } else {
279  double value = item->getItemValue(VerticalLineItem::P_POSX).toDouble();
280  hist.reset(m_hist2d->projectionY(value));
281  }
282 
283 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
284  auto centers = hist->binCenters();
285  auto values = hist->binValues();
286  graph->setData(QVector<double>(centers.begin(), centers.end()),
287  QVector<double>(values.begin(), values.end()));
288 #else
289  graph->setData(QVector<double>::fromStdVector(hist->binCenters()),
290  QVector<double>::fromStdVector(hist->binValues()));
291 #endif
292 }
293 
294 void ProjectionsPlot::setInterpolate(bool isInterpolated)
295 {
296  for (auto graph : m_item_to_graph)
297  graph->setLineStyle(isInterpolated ? QCPGraph::lsLine : QCPGraph::lsStepCenter);
298 }
299 
300 void ProjectionsPlot::setLogz(bool isLogz)
301 {
302  ColorMapUtils::setLogz(m_customPlot->yAxis, isLogz);
303 }
304 
306 {
307  m_customPlot->replot();
308 }
309 
310 //! Returns true, if widget is intended for horizontal projections.
311 
313 {
314  return m_projectionType == "HorizontalLineMask";
315 }
#define ASSERT(condition)
Definition: Assert.h:31
Defines various axis items.
Defines ColorMapUtils namespace.
Defines class Histogram1D.
Defines class Histogram2D.
Defines class IntensityDataItem.
Defines MaskItems classes.
Defines items related to projections over color map.
Defines class ProjectionsPlot.
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_MIN_DEG
Definition: AxesItems.h:27
static const QString P_POSY
Definition: MaskItems.h:81
static const QString T_PROJECTIONS
static const QString P_IS_INTERPOLATED
void unsubscribe(const void *caller)
Cancells all subscribtion of given caller.
Definition: ModelMapper.cpp:98
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 setOnAboutToRemoveChild(std::function< void(SessionItem *)> f, const void *caller=0)
Definition: ModelMapper.cpp:92
void setOnPropertyChange(std::function< void(QString)> f, const void *caller=0)
Definition: ModelMapper.cpp:35
void setOnChildrenChange(std::function< void(SessionItem *)> f, const void *caller=0)
Calls back when number of children has changed, reports newChild.
Definition: ModelMapper.cpp:68
A container to hold ProjectionItems, intended to store projections of color map on X,...
QCustomPlot * m_customPlot
void updateProjectionsData()
Creates cached 2D histogram for later projection calculations.
std::unique_ptr< Histogram2D > m_hist2d
IntensityDataItem * intensityItem()
void onIntensityItemPropertyChanged(const QString &propertyName)
Updates projection appearance (line style, etc)
QVector< SessionItem * > projectionItems()
void clearProjection(SessionItem *item)
Removes plot corresponding to given projection item.
void setGraphFromItem(QCPGraph *graph, SessionItem *item)
Sets the data to graph from given projection iten.
void onMarginsChanged(double left, double right)
ProjectionsPlot(const QString &projectionType, QWidget *parent=0)
QString m_projectionType
void unsubscribeFromChildren()
void updateAxesRange()
Updates canva's axes to match current zoom level of IntensityDataItem.
void setLogz(bool isLogz)
QCPGraph * graphForItem(SessionItem *item)
QMap< SessionItem *, QCPGraph * > m_item_to_graph
bool isHorizontalType()
Returns true, if widget is intended for horizontal projections.
void updateProjections()
Runs through all projection items and generates missed plots.
ProjectionContainerItem * projectionContainerItem()
void onAxisPropertyChanged(const QString &axisName, const QString &propertyName)
Updates zoom of projections in accordance with IntensityDataItem.
void setInterpolate(bool isInterpolated)
void clearProjections()
Clears all graphs corresponding to projection items.
void onProjectionPropertyChanged(SessionItem *item, const QString &property)
The SessionItemWidget class is a base for all widgets representing the content of SessionItem.
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.
QVector< SessionItem * > getChildrenOfType(const QString &model_type) const
Returns a vector of all children of the given type.
QString modelType() const
Get model type.
SessionItem * getItem(const QString &tag="", int row=0) const
Returns item in given row of given tag.
static const QString P_POSX
Definition: MaskItems.h:73
QCPRange itemDataZoom(const IntensityDataItem *item)
Returns z-axis visible range (zoom).
QCPRange itemZoomY(const IntensityDataItem *item)
Returns y-axis vizible range (zoom).
void setDefaultMargins(QCustomPlot *customPlot)
Sets default margins for axes rectangle plot.
QCPRange itemZoomX(const IntensityDataItem *item)
Returns x-axis vizible range (zoom).
void setLogz(QCPColorScale *scale, bool isLogz)
int plot_tick_label_size()
QVector< double > fromStdVector(const std::vector< double > &data)
Definition: GUIHelpers.cpp:225
QString const & name(EShape k)
Definition: particles.cpp:21
Defines various constants for plotting.