labplot  2.8.2
About: LabPlot is an application for plotting and analysis of 2D and 3D functions and data. It is a complete rewrite of LabPlot1 and lacks in the first release a lot of features available in the predecessor. On the other hand, the GUI and the usability is more superior.
  Fossies Dox: labplot-2.8.2.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

XYCorrelationCurve.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  File : XYCorrelationCurve.cpp
3  Project : LabPlot
4  Description : A xy-curve defined by a correlation
5  --------------------------------------------------------------------
6  Copyright : (C) 2018 Stefan Gerlach (stefan.gerlach@uni.kn)
7 
8  ***************************************************************************/
9 
10 /***************************************************************************
11  * *
12  * This program is free software; you can redistribute it and/or modify *
13  * it under the terms of the GNU General Public License as published by *
14  * the Free Software Foundation; either version 2 of the License, or *
15  * (at your option) any later version. *
16  * *
17  * This program is distributed in the hope that it will be useful, *
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
20  * GNU General Public License for more details. *
21  * *
22  * You should have received a copy of the GNU General Public License *
23  * along with this program; if not, write to the Free Software *
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
25  * Boston, MA 02110-1301 USA *
26  * *
27  ***************************************************************************/
28 
29 /*!
30  \class XYCorrelationCurve
31  \brief A xy-curve defined by a correlation
32 
33  \ingroup worksheet
34 */
35 
36 #include "XYCorrelationCurve.h"
40 #include "backend/lib/macros.h"
41 
42 #include <KLocalizedString>
43 #include <QIcon>
44 #include <QElapsedTimer>
45 #include <QThreadPool>
46 
47 extern "C" {
48 #include <gsl/gsl_math.h>
49 }
50 
53 }
54 
57 }
58 
59 //no need to delete the d-pointer here - it inherits from QGraphicsItem
60 //and is deleted during the cleanup in QGraphicsScene
62 
64  Q_D(XYCorrelationCurve);
65  d->recalculate();
66 }
67 
68 /*!
69  Returns an icon to be used in the project explorer.
70 */
71 QIcon XYCorrelationCurve::icon() const {
72 // return QIcon::fromTheme("labplot-xy-correlation-curve"); //not available yet
73  return QIcon::fromTheme("labplot-xy-curve");
74 }
75 
76 //##############################################################################
77 //########################## getter methods ##################################
78 //##############################################################################
80 
81 const XYCorrelationCurve::CorrelationResult& XYCorrelationCurve::correlationResult() const {
82  Q_D(const XYCorrelationCurve);
83  return d->correlationResult;
84 }
85 
86 //##############################################################################
87 //################# setter methods and undo commands ##########################
88 //##############################################################################
89 STD_SETTER_CMD_IMPL_F_S(XYCorrelationCurve, SetCorrelationData, XYCorrelationCurve::CorrelationData, correlationData, recalculate);
90 void XYCorrelationCurve::setCorrelationData(const XYCorrelationCurve::CorrelationData& correlationData) {
91  Q_D(XYCorrelationCurve);
92  exec(new XYCorrelationCurveSetCorrelationDataCmd(d, correlationData, ki18n("%1: set options and perform the correlation")));
93 }
94 
95 //##############################################################################
96 //######################### Private implementation #############################
97 //##############################################################################
99 }
100 
101 //no need to delete xColumn and yColumn, they are deleted
102 //when the parent aspect is removed
104 
106  DEBUG("XYCorrelationCurvePrivate::recalculate()");
107  QElapsedTimer timer;
108  timer.start();
109 
110  //create correlation result columns if not available yet, clear them otherwise
111  if (!xColumn) {
114  xVector = static_cast<QVector<double>* >(xColumn->data());
115  yVector = static_cast<QVector<double>* >(yColumn->data());
116 
117  xColumn->setHidden(true);
118  q->addChild(xColumn);
119  yColumn->setHidden(true);
120  q->addChild(yColumn);
121 
122  q->setUndoAware(false);
123  q->setXColumn(xColumn);
124  q->setYColumn(yColumn);
125  q->setUndoAware(true);
126  } else {
127  xVector->clear();
128  yVector->clear();
129  }
130 
131  //clear the previous result
133 
134  //determine the data source columns
135  const AbstractColumn* tmpXDataColumn = nullptr;
136  const AbstractColumn* tmpYDataColumn = nullptr;
137  const AbstractColumn* tmpY2DataColumn = nullptr;
139  //spreadsheet columns as data source
140  tmpXDataColumn = xDataColumn;
141  tmpYDataColumn = yDataColumn;
142  tmpY2DataColumn = y2DataColumn;
143  } else {
144  //curve columns as data source (autocorrelation)
145  tmpXDataColumn = dataSourceCurve->xColumn();
146  tmpYDataColumn = dataSourceCurve->yColumn();
147  tmpY2DataColumn = dataSourceCurve->yColumn();
148  }
149 
150  if (tmpYDataColumn == nullptr || tmpY2DataColumn == nullptr) {
152  emit q->dataChanged();
154  return;
155  }
156 
157  //copy all valid data point for the correlation to temporary vectors
158  QVector<double> xdataVector;
159  QVector<double> ydataVector;
160  QVector<double> y2dataVector;
161 
162  double xmin, xmax;
163  if (tmpXDataColumn != nullptr && correlationData.autoRange) {
164  xmin = tmpXDataColumn->minimum();
165  xmax = tmpXDataColumn->maximum();
166  } else {
167  xmin = correlationData.xRange.first();
168  xmax = correlationData.xRange.last();
169  }
170 
171  //only copy those data where values are valid and in range
172  if (tmpXDataColumn != nullptr) { // x-axis present (with possible range)
173  for (int row = 0; row < tmpXDataColumn->rowCount(); ++row) {
174  if (tmpXDataColumn->isValid(row) && !tmpXDataColumn->isMasked(row)
175  && tmpYDataColumn->isValid(row) && !tmpYDataColumn->isMasked(row)) {
176  if (tmpXDataColumn->valueAt(row) >= xmin && tmpXDataColumn->valueAt(row) <= xmax) {
177  xdataVector.append(tmpXDataColumn->valueAt(row));
178  ydataVector.append(tmpYDataColumn->valueAt(row));
179  }
180  }
181  }
182  } else { // no x-axis: take all valid values
183  for (int row = 0; row < tmpYDataColumn->rowCount(); ++row)
184  if (tmpYDataColumn->isValid(row) && !tmpYDataColumn->isMasked(row))
185  ydataVector.append(tmpYDataColumn->valueAt(row));
186  }
187 
188  if (tmpY2DataColumn != nullptr) {
189  for (int row = 0; row < tmpY2DataColumn->rowCount(); ++row)
190  if (tmpY2DataColumn->isValid(row) && !tmpY2DataColumn->isMasked(row))
191  y2dataVector.append(tmpY2DataColumn->valueAt(row));
192  }
193 
194  const size_t n = (size_t)ydataVector.size(); // number of points for signal
195  const size_t m = (size_t)y2dataVector.size(); // number of points for response
196  if (n < 1 || m < 1) {
198  correlationResult.valid = false;
199  correlationResult.status = i18n("Not enough data points available.");
201  emit q->dataChanged();
203  return;
204  }
205 
206  double* xdata = xdataVector.data();
207  double* ydata = ydataVector.data();
208  double* y2data = y2dataVector.data();
209 
210  // correlation settings
211  const double samplingInterval = correlationData.samplingInterval;
214 
215  DEBUG("signal_1 n = " << n << ", signal_2 n = " << m);
216  DEBUG("sampling interval = " << samplingInterval);
217  DEBUG("type = " << nsl_corr_type_name[type]);
218  DEBUG("norm = " << nsl_corr_norm_name[norm]);
219 
220 ///////////////////////////////////////////////////////////
221  size_t np = GSL_MAX(n, m);
222  if (type == nsl_corr_type_linear)
223  np = 2 * np - 1;
224 
225  double* out = (double*)malloc(np * sizeof(double));
226  int status = nsl_corr_correlation(ydata, n, y2data, m, type, norm, out);
227 
228  xVector->resize((int)np);
229  yVector->resize((int)np);
230  // take given x-axis values or use index
231  if (tmpXDataColumn != nullptr) {
232  int size = GSL_MIN(xdataVector.size(), (int)np);
233  memcpy(xVector->data(), xdata, size * sizeof(double));
234  double sampleInterval = (xVector->data()[size-1] - xVector->data()[0])/(xdataVector.size()-1);
235  DEBUG("xdata size = " << xdataVector.size() << ", np = " << np << ", sample interval = " << sampleInterval);
236  for (int i = size; i < (int)np; i++) // fill missing values
237  xVector->data()[i] = xVector->data()[size-1] + (i-size+1) * sampleInterval;
238  } else { // fill with index (starting with 0)
239  if (type == nsl_corr_type_linear)
240  for (size_t i = 0; i < np; i++)
241  xVector->data()[i] = (int)(i-np/2) * samplingInterval;
242  else
243  for (size_t i = 0; i < np; i++)
244  xVector->data()[i] = (int)i * samplingInterval;
245  }
246 
247  memcpy(yVector->data(), out, np * sizeof(double));
248  free(out);
249 ///////////////////////////////////////////////////////////
250 
251  //write the result
253  correlationResult.valid = true;
254  correlationResult.status = QString::number(status);
255  correlationResult.elapsedTime = timer.elapsed();
256 
257  //redraw the curve
259  emit q->dataChanged();
261 }
262 
263 //##############################################################################
264 //################## Serialization/Deserialization ###########################
265 //##############################################################################
266 //! Save as XML
267 void XYCorrelationCurve::save(QXmlStreamWriter* writer) const{
268  Q_D(const XYCorrelationCurve);
269 
270  writer->writeStartElement("xyCorrelationCurve");
271 
272  //write the base class
273  XYAnalysisCurve::save(writer);
274 
275  //write xy-correlation-curve specific information
276  // correlation data
277  writer->writeStartElement("correlationData");
278  writer->writeAttribute( "samplingInterval", QString::number(d->correlationData.samplingInterval) );
279  writer->writeAttribute( "autoRange", QString::number(d->correlationData.autoRange) );
280  writer->writeAttribute( "xRangeMin", QString::number(d->correlationData.xRange.first()) );
281  writer->writeAttribute( "xRangeMax", QString::number(d->correlationData.xRange.last()) );
282  writer->writeAttribute( "type", QString::number(d->correlationData.type) );
283  writer->writeAttribute( "normalize", QString::number(d->correlationData.normalize) );
284  writer->writeEndElement();// correlationData
285 
286  // correlation results (generated columns)
287  writer->writeStartElement("correlationResult");
288  writer->writeAttribute( "available", QString::number(d->correlationResult.available) );
289  writer->writeAttribute( "valid", QString::number(d->correlationResult.valid) );
290  writer->writeAttribute( "status", d->correlationResult.status );
291  writer->writeAttribute( "time", QString::number(d->correlationResult.elapsedTime) );
292 
293  //save calculated columns if available
294  if (d->xColumn) {
295  d->xColumn->save(writer);
296  d->yColumn->save(writer);
297  }
298  writer->writeEndElement(); //"correlationResult"
299 
300  writer->writeEndElement(); //"xyCorrelationCurve"
301 }
302 
303 //! Load from XML
304 bool XYCorrelationCurve::load(XmlStreamReader* reader, bool preview) {
305  DEBUG("XYCorrelationCurve::load()");
306  Q_D(XYCorrelationCurve);
307 
308  KLocalizedString attributeWarning = ki18n("Attribute '%1' missing or empty, default value is used");
309  QXmlStreamAttributes attribs;
310  QString str;
311 
312  while (!reader->atEnd()) {
313  reader->readNext();
314  if (reader->isEndElement() && reader->name() == "xyCorrelationCurve")
315  break;
316 
317  if (!reader->isStartElement())
318  continue;
319 
320  if (reader->name() == "xyAnalysisCurve") {
321  if ( !XYAnalysisCurve::load(reader, preview) )
322  return false;
323  } else if (!preview && reader->name() == "correlationData") {
324  attribs = reader->attributes();
325  READ_DOUBLE_VALUE("samplingInterval", correlationData.samplingInterval);
326  READ_INT_VALUE("autoRange", correlationData.autoRange, bool);
327  READ_DOUBLE_VALUE("xRangeMin", correlationData.xRange.first());
328  READ_DOUBLE_VALUE("xRangeMax", correlationData.xRange.last());
329  READ_INT_VALUE("type", correlationData.type, nsl_corr_type_type);
330  READ_INT_VALUE("normalize", correlationData.normalize, nsl_corr_norm_type);
331  } else if (!preview && reader->name() == "correlationResult") {
332  attribs = reader->attributes();
333  READ_INT_VALUE("available", correlationResult.available, int);
334  READ_INT_VALUE("valid", correlationResult.valid, int);
337  } else if (!preview && reader->name() == "column") {
338  Column* column = new Column(QString(), AbstractColumn::ColumnMode::Numeric);
339  if (!column->load(reader, preview)) {
340  delete column;
341  return false;
342  }
343  if (column->name() == "x")
344  d->xColumn = column;
345  else if (column->name() == "y")
346  d->yColumn = column;
347  }
348  }
349 
350  if (preview)
351  return true;
352 
353  // wait for data to be read before using the pointers
354  QThreadPool::globalInstance()->waitForDone();
355 
356  if (d->xColumn && d->yColumn) {
357  d->xColumn->setHidden(true);
358  addChild(d->xColumn);
359 
360  d->yColumn->setHidden(true);
361  addChild(d->yColumn);
362 
363  d->xVector = static_cast<QVector<double>* >(d->xColumn->data());
364  d->yVector = static_cast<QVector<double>* >(d->yColumn->data());
365 
366  XYCurve::d_ptr->xColumn = d->xColumn;
367  XYCurve::d_ptr->yColumn = d->yColumn;
368 
370  }
371 
372  return true;
373 }
AspectType
STD_SETTER_CMD_IMPL_F_S(XYCorrelationCurve, SetCorrelationData, XYCorrelationCurve::CorrelationData, correlationData, recalculate)
void setUndoAware(bool)
void addChild(AbstractAspect *)
Add the given Aspect to my list of children.
QString name() const
void exec(QUndoCommand *)
Execute the given command, pushing it on the undoStack() if available.
AbstractAspectPrivate * d
void setHidden(bool)
Set "hidden" property, i.e. whether to exclude this aspect from being shown in the explorer.
Interface definition for data with column logic.
virtual double valueAt(int row) const
Return the double value in row 'row'.
bool isMasked(int row) const
Return whether a certain row is masked.
virtual int rowCount() const =0
Return the data vector size.
virtual double maximum(int count=0) const
virtual double minimum(int count=0) const
bool isValid(int row) const
Convenience method for mode-independent testing of validity.
Aspect that manages a column.
Definition: Column.h:42
void * data() const
Definition: Column.cpp:852
bool load(XmlStreamReader *, bool preview) override
Load the column from XML.
Definition: Column.cpp:1152
XYAnalysisCurve::DataSourceType dataSourceType
const AbstractColumn * yDataColumn
const AbstractColumn * y2DataColumn
QVector< double > * xVector
const AbstractColumn * xDataColumn
QVector< double > * yVector
Base class for all analysis curves.
void save(QXmlStreamWriter *) const override
Save as XML.
bool load(XmlStreamReader *, bool preview) override
Load from XML.
XYCorrelationCurvePrivate(XYCorrelationCurve *)
XYCorrelationCurve::CorrelationResult correlationResult
XYCorrelationCurve::CorrelationData correlationData
~XYCorrelationCurvePrivate() override
XYCorrelationCurve *const q
A xy-curve defined by a correlation.
XYCorrelationCurve(const QString &name)
bool load(XmlStreamReader *, bool preview) override
Load from XML.
void save(QXmlStreamWriter *) const override
Save as XML.
~XYCorrelationCurve() override
QIcon icon() const override
const CorrelationResult & correlationResult() const
void recalculate() override
bool sourceDataChangedSinceLastRecalc
const AbstractColumn * xColumn
void recalcLogicalPoints()
Definition: XYCurve.cpp:1090
const AbstractColumn * yColumn
void dataChanged()
XYCurvePrivate *const d_ptr
Definition: XYCurve.h:186
void recalcLogicalPoints()
Definition: XYCurve.cpp:765
XML stream parser that supports errors as well as warnings. This class also adds line and column numb...
#define READ_DOUBLE_VALUE(name, var)
Definition: macros.h:475
#define DEBUG(x)
Definition: macros.h:50
#define READ_INT_VALUE(name, var, type)
Definition: macros.h:468
#define BASIC_SHARED_D_READER_IMPL(classname, type, method, var)
Definition: macros.h:127
#define READ_STRING_VALUE(name, var)
Definition: macros.h:482
#define i18n(m)
Definition: nsl_common.h:38
int nsl_corr_correlation(double s[], size_t n, double r[], size_t m, nsl_corr_type_type type, nsl_corr_norm_type normalize, double out[])
Definition: nsl_corr.c:40
const char * nsl_corr_type_name[]
Definition: nsl_corr.c:37
const char * nsl_corr_norm_name[]
Definition: nsl_corr.c:38
nsl_corr_type_type
Definition: nsl_corr.h:36
@ nsl_corr_type_linear
Definition: nsl_corr.h:36
nsl_corr_norm_type
Definition: nsl_corr.h:45