Kstars

focushfrvplot.cpp
1 /*
2  SPDX-FileCopyrightText: 2012 Jasem Mutlaq <[email protected]>
3  SPDX-FileCopyrightText: 2021 Wolfgang Reissenberger <[email protected]>
4 
5  SPDX-License-Identifier: GPL-2.0-or-later
6 */
7 
8 #include "focushfrvplot.h"
9 
10 #include "klocalizedstring.h"
11 
12 #include "curvefit.h"
13 
14 #define DEFAULT_BASIC_FONT_SIZE 10
15 
16 FocusHFRVPlot::FocusHFRVPlot(QWidget *parent) : QCustomPlot (parent)
17 {
18  setBackground(QBrush(Qt::black));
19 
20  xAxis->setBasePen(QPen(Qt::white, 1));
21  yAxis->setBasePen(QPen(Qt::white, 1));
22 
23  xAxis->setTickPen(QPen(Qt::white, 1));
24  yAxis->setTickPen(QPen(Qt::white, 1));
25 
26  xAxis->setSubTickPen(QPen(Qt::white, 1));
27  yAxis->setSubTickPen(QPen(Qt::white, 1));
28 
29  xAxis->setTickLabelColor(Qt::white);
30  yAxis->setTickLabelColor(Qt::white);
31 
32  xAxis->setLabelColor(Qt::white);
33  yAxis->setLabelColor(Qt::white);
34 
35  xAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine));
36  yAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine));
37  xAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine));
38  yAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine));
39  xAxis->grid()->setZeroLinePen(Qt::NoPen);
40  yAxis->grid()->setZeroLinePen(Qt::NoPen);
41 
42  yAxis->setLabel(i18n("HFR"));
43 
44  setInteractions(QCP::iRangeZoom);
45  setInteraction(QCP::iRangeDrag, true);
46 
47  polynomialGraph = addGraph();
48  polynomialGraph->setLineStyle(QCPGraph::lsLine);
49  polynomialGraph->setPen(QPen(QColor(140, 140, 140), 2, Qt::DotLine));
50  polynomialGraph->setScatterStyle(QCPScatterStyle::ssNone);
51 
52  v_graph = addGraph();
53  v_graph->setLineStyle(QCPGraph::lsNone);
54  v_graph->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, Qt::white, Qt::white, 14));
55 
56  focusPoint = addGraph();
57  focusPoint->setLineStyle(QCPGraph::lsImpulse);
58  focusPoint->setPen(QPen(QColor(140, 140, 140), 2, Qt::SolidLine));
59  focusPoint->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, Qt::white, Qt::yellow, 10));
60 
61  // determine font size
62  if (parent != nullptr)
63  setBasicFontSize(parent->font().pointSize());
64  else
65  setBasicFontSize(DEFAULT_BASIC_FONT_SIZE);
66 
68  {
69  double key = xAxis->pixelToCoord(event->localPos().x());
70  if (xAxis->range().contains(key))
71  {
72  QCPGraph *graph = qobject_cast<QCPGraph *>(plottableAt(event->pos(), false));
73 
74  if (graph)
75  {
76  if(graph == v_graph)
77  {
78  int positionKey = v_graph->findBegin(key);
79  double focusPosition = v_graph->dataMainKey(positionKey);
80  double halfFluxRadius = v_graph->dataMainValue(positionKey);
81  QToolTip::showText(
82  event->globalPos(),
83  i18nc("HFR graphics tooltip; %1 is the Focus Position; %2 is the Half Flux Radius;",
84  "<table>"
85  "<tr><td>POS: </td><td>%1</td></tr>"
86  "<tr><td>HFR: </td><td>%2</td></tr>"
87  "</table>",
88  QString::number(focusPosition, 'f', 0),
89  QString::number(halfFluxRadius, 'f', 2)));
90  }
91  }
92  }
93  });
94  // Add the error bars
95  errorBars = new QCPErrorBars((this)->xAxis, (this)->yAxis);
96 }
97 
98 void FocusHFRVPlot::drawHFRIndices()
99 {
100  // Setup error bars
101  QVector<double> err;
102  if (useErrorBars)
103  {
104  errorBars->removeFromLegend();
105  errorBars->setAntialiased(false);
106  errorBars->setDataPlottable((this)->v_graph);
107  errorBars->setPen(QPen(QColor(180, 180, 180)));
108  }
109 
110  // Put the sample number inside the plot point's circle.
111  for (int i = 0; i < hfr_position.size(); ++i)
112  {
113  QCPItemText *textLabel = new QCPItemText(this);
115  textLabel->position->setType(QCPItemPosition::ptPlotCoords);
116  textLabel->position->setCoords(hfr_position[i], hfr_value[i]);
117  textLabel->setText(QString::number(i + 1));
118  textLabel->setFont(QFont(font().family(), (int) std::round(1.2 * basicFontSize())));
119  textLabel->setPen(Qt::NoPen);
120  textLabel->setColor(Qt::red);
121 
122  if (useErrorBars)
123  err.push_front(hfr_sigma[i]);
124  }
125  // Setup the error bar data if we're using it
126  errorBars->setVisible(useErrorBars);
127  if (useErrorBars)
128  errorBars->setData(err);
129 }
130 
131 void FocusHFRVPlot::init(bool showPosition)
132 {
133  m_showPositions = showPosition;
134  hfr_position.clear();
135  hfr_value.clear();
136  hfr_sigma.clear();
137  polynomialGraph->data()->clear();
138  focusPoint->data().clear();
139  useErrorBars = false;
140  errorBars->data().clear();
141  // the next step seems necessary (QCP bug?)
142  v_graph->setData(QVector<double> {}, QVector<double> {});
143  focusPoint->setData(QVector<double> {}, QVector<double> {});
144  m_polynomialGraphIsVisible = false;
145  m_isVShape = false;
146  maxHFR = -1;
147  FocusHFRVPlot::clearItems();
148  replot();
149 }
150 
151 void FocusHFRVPlot::drawHFRPlot(double currentHFR, int pulseDuration)
152 {
153  // DrawHFRPlot is the base on which other things are built upon.
154  // Clear any previous annotations.
155  FocusHFRVPlot::clearItems();
156 
157  v_graph->setData(hfr_position, hfr_value);
158  drawHFRIndices();
159 
160  if (maxHFR < currentHFR || maxHFR < 0)
161  maxHFR = currentHFR;
162 
163  double minHFRVal = currentHFR / 2.5;
164  if (hfr_value.size() > 0)
165  minHFRVal = std::max(0.0, *std::min_element(hfr_value.begin(), hfr_value.end()));
166 
167  // True for the position-based algorithms and those that simulate position.
168  if (m_showPositions)
169  {
170  const double minPosition = hfr_position.empty() ?
171  0 : *std::min_element(hfr_position.constBegin(), hfr_position.constEnd());
172  const double maxPosition = hfr_position.empty() ?
173  1e6 : *std::max_element(hfr_position.constBegin(), hfr_position.constEnd());
174  xAxis->setRange(minPosition - pulseDuration, maxPosition + pulseDuration);
175  }
176  else
177  {
178  //xAxis->setLabel(i18n("Iteration"));
179  xAxis->setRange(1, hfr_value.count() + 1);
180  }
181 
182  if (hfr_value.size() == 1)
183  // 1 point gets placed in the middle vertically.
184  yAxis->setRange(0, 2 * maxHFR);
185  else
186  {
187  // Allow about 20% of the plot space below the curve, so user can see the min points.
188  const double upper = 1.1 * maxHFR;
189  yAxis->setRange(std::max(0.0, minHFRVal - (0.25 * (upper - minHFRVal))), upper);
190  }
191  replot();
192 }
193 
194 void FocusHFRVPlot::addPosition(double pos, double newHFR, int pulseDuration, bool plot)
195 {
196  hfr_position.append(pos);
197  hfr_value.append(newHFR);
198  useErrorBars = false;
199  if (plot)
200  drawHFRPlot(newHFR, pulseDuration);
201 }
202 
203 void FocusHFRVPlot::addPositionWithSigma(double pos, double newHFR, double sigma, int pulseDuration, bool plot)
204 {
205  hfr_position.append(pos);
206  hfr_value.append(newHFR);
207  hfr_sigma.append(sigma);
208  useErrorBars = true;
209  if (plot)
210  drawHFRPlot(newHFR, pulseDuration);
211 }
212 void FocusHFRVPlot::setTitle(const QString &title, bool plot)
213 {
214  plotTitle = new QCPItemText(this);
215  plotTitle->setColor(QColor(255, 255, 255));
216  plotTitle->setPositionAlignment(Qt::AlignTop | Qt::AlignHCenter);
217  plotTitle->position->setType(QCPItemPosition::ptAxisRectRatio);
218  plotTitle->position->setCoords(0.5, 0);
219  plotTitle->setText("");
220  plotTitle->setFont(QFont(font().family(), 11));
221  plotTitle->setVisible(true);
222 
223  plotTitle->setText(title);
224  if (plot) replot();
225 }
226 
227 void FocusHFRVPlot::updateTitle(const QString &title, bool plot)
228 {
229  // Update a previous set title without having to redraw everything
230  if (plotTitle != nullptr)
231  {
232  plotTitle->setText(title);
233  if (plot) replot();
234  }
235 }
236 void FocusHFRVPlot::setSolutionVShape(bool isVShape)
237 {
238  m_isVShape = isVShape;
239 
240  QPen pen;
241  pen.setWidth(1);
242 
243  if (isVShape)
244  {
245  pen.setColor(QColor(180, 180, 180));
246  }
247  else
248  {
249  pen.setColor(QColor(254, 0, 0));
250  // clear focus point
251  focusPoint->data().clear();
252  }
253 
254  polynomialGraph->setPen(pen);
255 }
256 
257 void FocusHFRVPlot::clearItems()
258 {
259  // Clear all the items on the HFR plot and reset pointers
261  plotTitle = nullptr;
262 }
263 
264 void FocusHFRVPlot::drawMinimum(double solutionPosition, double solutionValue, bool plot)
265 {
266  focusPoint->data()->clear();
267 
268  // do nothing for invalid positions
269  if (solutionPosition < 0)
270  return;
271 
272  focusPoint->addData(solutionPosition, solutionValue);
273  QCPItemText *textLabel = new QCPItemText(this);
275  textLabel->setColor(Qt::red);
276  textLabel->setPadding(QMargins(0, 0, 0, 0));
277  textLabel->setBrush(Qt::white);
278  textLabel->setPen(Qt::NoPen);
279  textLabel->setFont(QFont(font().family(), (int) std::round(0.8 * basicFontSize())));
280  textLabel->position->setType(QCPItemPosition::ptPlotCoords);
281  textLabel->position->setCoords(solutionPosition, (maxHFR + 2 * solutionValue) / 3);
282  textLabel->setText(QString::number(solutionPosition, 'f', 0));
283  if (plot) replot();
284 }
285 
286 void FocusHFRVPlot::drawPolynomial(Ekos::PolynomialFit *polyFit, bool isVShape, bool makeVisible, bool plot)
287 {
288  if (polyFit == nullptr)
289  return;
290 
291  // do nothing if graph is not visible and should not be made as such
292  if(makeVisible)
293  m_polynomialGraphIsVisible = true;
294  else if (m_polynomialGraphIsVisible == false)
295  return;
296 
297  setSolutionVShape(isVShape);
298  if (polynomialGraph != nullptr)
299  {
300  polynomialGraph->data()->clear();
301  QCPRange range = xAxis->range();
302  double interval = range.size() / 20.0;
303 
304  for(double x = range.lower ; x < range.upper ; x += interval)
305  {
306  double y = polyFit->f(x);
307  polynomialGraph->addData(x, y);
308  }
309  if (plot) replot();
310  }
311 }
312 
313 void FocusHFRVPlot::drawCurve(Ekos::CurveFitting *curveFit, bool isVShape, bool makeVisible, bool plot)
314 {
315  if (curveFit == nullptr)
316  return;
317 
318  // do nothing if graph is not visible and should not be made as such
319  if(makeVisible)
320  m_polynomialGraphIsVisible = true;
321  else if (m_polynomialGraphIsVisible == false)
322  return;
323 
324  setSolutionVShape(isVShape);
325  if (polynomialGraph != nullptr)
326  {
327  polynomialGraph->data()->clear();
328  QCPRange range = xAxis->range();
329  double interval = range.size() / 20.0;
330 
331  for(double x = range.lower ; x < range.upper ; x += interval)
332  {
333  double y = curveFit->f(x);
334  polynomialGraph->addData(x, y);
335  }
336  if (plot) replot();
337  }
338 }
339 
340 void FocusHFRVPlot::redraw(Ekos::PolynomialFit *polyFit, double solutionPosition, double solutionValue)
341 {
342  if (hfr_value.empty() == false)
343  drawHFRPlot(hfr_value.last(), 0);
344 
345  drawPolynomial(polyFit, m_isVShape, false);
346  drawMinimum(solutionPosition, solutionValue);
347 }
348 
349 void FocusHFRVPlot::redrawCurve(Ekos::CurveFitting *curveFit, double solutionPosition, double solutionValue)
350 {
351  if (hfr_value.empty() == false)
352  drawHFRPlot(hfr_value.last(), 0);
353 
354  drawCurve(curveFit, m_isVShape, false);
355  drawMinimum(solutionPosition, solutionValue);
356 }
357 
358 void FocusHFRVPlot::setBasicFontSize(int basicFontSize)
359 {
360  m_basicFontSize = basicFontSize;
361 
362  // Axis Labels Settings
363  yAxis->setLabelFont(QFont(font().family(), basicFontSize));
364  xAxis->setTickLabelFont(QFont(font().family(), (int) std::round(0.9 * basicFontSize)));
365  yAxis->setTickLabelFont(QFont(font().family(), (int) std::round(0.9 * basicFontSize)));
366 }
367 
@ ssCircle
\enumimage{ssCircle.png} a circle
Definition: qcustomplot.h:2478
AlignCenter
@ lsImpulse
each data point is represented by a line parallel to the value axis, which reaches from the data poin...
Definition: qcustomplot.h:5462
QString number(int n, int base)
virtual bool event(QEvent *event) override
A plottable that adds a set of error bars to other plottables.
Definition: qcustomplot.h:6272
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void setCoords(double key, double value)
Represents the visual appearance of scatter points.
Definition: qcustomplot.h:2444
void setColor(const QColor &color)
QString i18n(const char *text, const TYPE &arg...)
void setPositionAlignment(Qt::Alignment alignment)
void setColor(const QColor &color)
void setBrush(const QBrush &brush)
@ ptAxisRectRatio
Static positioning given by a fraction of the axis rect size (see setAxisRect).
Definition: qcustomplot.h:3602
void setType(PositionType type)
void setWidth(int width)
void setPen(const QPen &pen)
A text label.
Definition: qcustomplot.h:6571
@ ptPlotCoords
Dynamic positioning at a plot coordinate defined by two axes (see setAxes).
Definition: qcustomplot.h:3605
void setFont(const QFont &font)
@ lsNone
data points are not connected with any lines (e.g.
Definition: qcustomplot.h:5456
Represents the range an axis is encompassing.
Definition: qcustomplot.h:778
The central class of the library. This is the QWidget which displays the plot and interacts with the ...
Definition: qcustomplot.h:3735
void push_front(T &&value)
void setText(const QString &text)
void mouseMove(QMouseEvent *event)
double size() const
Definition: qcustomplot.h:800
@ lsLine
data points are connected by a straight line
Definition: qcustomplot.h:5458
@ ssNone
no scatter symbols are drawn (e.g. in QCPGraph, data only represented with lines)
Definition: qcustomplot.h:2474
@ iRangeZoom
0x002 Axis ranges are zoomable with the mouse wheel (see QCPAxisRect::setRangeZoom,...
Definition: qcustomplot.h:256
QObject * parent() const const
@ iRangeDrag
0x001 Axis ranges are draggable (see QCPAxisRect::setRangeDrag, QCPAxisRect::setRangeDragAxes)
Definition: qcustomplot.h:255
void setPadding(const QMargins &padding)
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Mon Aug 8 2022 04:13:20 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.