[kde-doc-english] [labplot/analysis_interpolation] /: finished interpolation
Stefan Gerlach
stefan.gerlach at uni-konstanz.de
Sat Apr 9 19:32:22 UTC 2016
Git commit 7294844260c45b1363a89b786cd94248477f9938 by Stefan Gerlach.
Committed on 09/04/2016 at 19:31.
Pushed by sgerlach into branch 'analysis_interpolation'.
finished interpolation
1. use evaluation
2. check minimum number of points
3. fix bugs
4. documentation
M +27 -4 doc/index.docbook
M +9 -10 src/backend/worksheet/plots/cartesian/XYFourierFilterCurve.cpp
M +25 -14 src/backend/worksheet/plots/cartesian/XYInterpolationCurve.cpp
M +0 -4 src/backend/worksheet/plots/cartesian/XYInterpolationCurve.h
M +1 -1 src/kdefrontend/dockwidgets/AxisDock.cpp
M +1 -1 src/kdefrontend/dockwidgets/XYEquationCurveDock.cpp
M +1 -1 src/kdefrontend/dockwidgets/XYFitCurveDock.cpp
M +1 -1 src/kdefrontend/dockwidgets/XYFourierFilterCurveDock.cpp
M +75 -14 src/kdefrontend/dockwidgets/XYInterpolationCurveDock.cpp
http://commits.kde.org/labplot/7294844260c45b1363a89b786cd94248477f9938
diff --git a/doc/index.docbook b/doc/index.docbook
index e771d00..7791153 100644
--- a/doc/index.docbook
+++ b/doc/index.docbook
@@ -51,7 +51,7 @@
</copyright>
<legalnotice>&FDLNotice;</legalnotice>
-<date>2016-04-03</date>
+<date>2016-04-09</date>
<releaseinfo>3.1</releaseinfo>
<abstract>
@@ -778,15 +778,38 @@ The menu is only available when a datapicker object is selected on the <guilabel
<chapter id="analysis">
<title>Analysis functions</title>
- <para>&LabPlot; supports the data analysis functions nonlinear curve fitting and Fourier filter.
+ <para>&LabPlot; supports the data analysis functions interpolation, nonlinear curve fitting and Fourier filter.
Both can be applied to any data consisting of x- and y-columns.
The analysis functions can be accessed using the Analysis menu or the context menu of a worksheet.</para>
<para>The newly created curves can be customized (line style, symbol style, &etc;) like any x-y-curve.</para>
+ <sect1 id="interpolation">
+ <title>Interpolation</title>
+ <para>
+ Interpolation of data can be done with several algorithm:
+ </para>
+ <itemizedlist>
+ <listitem><para>Linear</para></listitem>
+ <listitem><para>Polynomial</para></listitem>
+ <listitem><para>cubic spline</para></listitem>
+ <listitem><para>cubic spline (periodic)</para></listitem>
+ <listitem><para>Akima spline</para></listitem>
+ <listitem><para>Akima spline (periodic)</para></listitem>
+ <listitem><para>Steffen spline (needs GSL >= 2.0)</para></listitem>
+ </itemizedlist>
+ <para>
+ The interpolating function is calculated with the given number of data points an evaluated as:
+ </para>
+ <itemizedlist>
+ <listitem><para>function</para></listitem>
+ <listitem><para>derivative</para></listitem>
+ <listitem><para>second derivative</para></listitem>
+ <listitem><para>integral (starting from zero)</para></listitem>
+ </itemizedlist>
+ </sect1>
+
<sect1 id="fitting">
<title>Curve fitting</title>
<para>
- <!-- Linear and non-linear fits to data, several fit-models are predefined and custom models with
- arbitrary number of parameters can be provided -->
Linear and non-linear curve fitting of data can be done with several predefined fit-models
(for instance polynomial, exponential, Gaussian or custom) to data consisting of x- and y-columns
with an optional weight column. With a custom model any function with unlimited number of parameters
diff --git a/src/backend/worksheet/plots/cartesian/XYFourierFilterCurve.cpp b/src/backend/worksheet/plots/cartesian/XYFourierFilterCurve.cpp
index 733ae27..16b8dc7 100644
--- a/src/backend/worksheet/plots/cartesian/XYFourierFilterCurve.cpp
+++ b/src/backend/worksheet/plots/cartesian/XYFourierFilterCurve.cpp
@@ -38,11 +38,9 @@
#include "backend/core/AbstractColumn.h"
#include "backend/core/column/Column.h"
#include "backend/lib/commandtemplates.h"
+
#include <cmath> // isnan
-/*#include "backend/gsl/ExpressionParser.h"
-#include "backend/gsl/parser_extern.h"
-*/
-//#include <gsl/gsl_version.h>
+#include <gsl_errno.h>
#include <gsl/gsl_fft_real.h>
#include <gsl/gsl_fft_halfcomplex.h>
#include <gsl/gsl_sf_pow_int.h>
@@ -215,7 +213,7 @@ void XYFourierFilterCurvePrivate::recalculate() {
return;
}
- //copy all valid data point for the fit to temporary vectors
+ //copy all valid data point for the filter to temporary vectors
QVector<double> xdataVector;
QVector<double> ydataVector;
for (int row=0; row<xDataColumn->rowCount(); ++row) {
@@ -228,7 +226,7 @@ void XYFourierFilterCurvePrivate::recalculate() {
}
}
- //number of data points to fit
+ //number of data points to filter
unsigned int n = ydataVector.size();
if (n == 0) {
filterResult.available = true;
@@ -258,12 +256,13 @@ void XYFourierFilterCurvePrivate::recalculate() {
qDebug()<<"unit :"<<unit<<unit2;
#endif
///////////////////////////////////////////////////////////
+ int status;
// 1. transform
gsl_fft_real_workspace *work = gsl_fft_real_workspace_alloc (n);
gsl_fft_real_wavetable *real = gsl_fft_real_wavetable_alloc (n);
- gsl_fft_real_transform (ydata, 1, n, real, work);
- gsl_fft_real_wavetable_free (real);
+ status = gsl_fft_real_transform(ydata, 1, n, real, work);
+ gsl_fft_real_wavetable_free(real);
// calculate index
double cutindex=0, cutindex2=0;
@@ -379,7 +378,7 @@ void XYFourierFilterCurvePrivate::recalculate() {
// 3. back transform
gsl_fft_halfcomplex_wavetable *hc = gsl_fft_halfcomplex_wavetable_alloc (n);
- gsl_fft_halfcomplex_inverse (ydata, 1, n, hc, work);
+ status = gsl_fft_halfcomplex_inverse(ydata, 1, n, hc, work);
gsl_fft_halfcomplex_wavetable_free (hc);
gsl_fft_real_workspace_free (work);
@@ -394,7 +393,7 @@ void XYFourierFilterCurvePrivate::recalculate() {
//write the result
filterResult.available = true;
filterResult.valid = true;
- filterResult.status = i18n("OK");
+ filterResult.status = QString(gsl_strerror(status));;
filterResult.elapsedTime = timer.elapsed();
//redraw the curve
diff --git a/src/backend/worksheet/plots/cartesian/XYInterpolationCurve.cpp b/src/backend/worksheet/plots/cartesian/XYInterpolationCurve.cpp
index 406ce9a..e73ef82 100644
--- a/src/backend/worksheet/plots/cartesian/XYInterpolationCurve.cpp
+++ b/src/backend/worksheet/plots/cartesian/XYInterpolationCurve.cpp
@@ -38,10 +38,9 @@
#include "backend/core/AbstractColumn.h"
#include "backend/core/column/Column.h"
#include "backend/lib/commandtemplates.h"
+
#include <cmath> // isnan
-/*#include "backend/gsl/ExpressionParser.h"
-#include "backend/gsl/parser_extern.h"
-*/
+#include <gsl_errno.h>
#include <gsl/gsl_interp.h>
#include <gsl/gsl_spline.h>
@@ -213,7 +212,7 @@ void XYInterpolationCurvePrivate::recalculate() {
return;
}
- //copy all valid data point for the fit to temporary vectors
+ //copy all valid data point for the interpolation to temporary vectors
QVector<double> xdataVector;
QVector<double> ydataVector;
for (int row=0; row<xDataColumn->rowCount(); ++row) {
@@ -228,10 +227,10 @@ void XYInterpolationCurvePrivate::recalculate() {
//number of data points to fit
unsigned int n = ydataVector.size();
- if (n == 0) {
+ if (n < 2) {
interpolationResult.available = true;
interpolationResult.valid = false;
- interpolationResult.status = i18n("No data points available.");
+ interpolationResult.status = i18n("Not enough data points available.");
emit (q->dataChanged());
sourceDataChangedSinceLastInterpolation = false;
return;
@@ -253,9 +252,8 @@ void XYInterpolationCurvePrivate::recalculate() {
qDebug()<<"npoints ="<<npoints;
#endif
///////////////////////////////////////////////////////////
+ int status;
//TODO:
- // * check minimum number of points
- // * evaluate "evaluate"
// * check Steffen spline with GSL 2.X
gsl_interp_accel *acc = gsl_interp_accel_alloc();
@@ -279,21 +277,34 @@ void XYInterpolationCurvePrivate::recalculate() {
case XYInterpolationCurve::AkimaPeriodic:
spline = gsl_spline_alloc(gsl_interp_akima_periodic, n);
break;
-#if GSL_MAJOR_VERSION >= 2
case XYInterpolationCurve::Steffen:
+#if GSL_MAJOR_VERSION >= 2
spline = gsl_spline_alloc(gsl_interp_steffen, n);
- break;
#endif
+ break;
}
- gsl_spline_init (spline, xdata, ydata, n);
+ status = gsl_spline_init (spline, xdata, ydata, n);
xVector->resize(npoints);
yVector->resize(npoints);
- for (int i = 0; i<npoints; i++) {
+ for (unsigned int i = 0; i<npoints; i++) {
double x = min + i*(max-min)/(npoints-1);
(*xVector)[i] = x;
- (*yVector)[i] = gsl_spline_eval (spline, x, acc);
+ switch(evaluate) {
+ case XYInterpolationCurve::Function:
+ (*yVector)[i] = gsl_spline_eval(spline, x, acc);
+ break;
+ case XYInterpolationCurve::Derivative:
+ (*yVector)[i] = gsl_spline_eval_deriv(spline, x, acc);
+ break;
+ case XYInterpolationCurve::Derivative2:
+ (*yVector)[i] = gsl_spline_eval_deriv2(spline, x, acc);
+ break;
+ case XYInterpolationCurve::Integral:
+ (*yVector)[i] = gsl_spline_eval_integ(spline, min, x, acc);
+ break;
+ }
}
gsl_spline_free(spline);
@@ -304,7 +315,7 @@ void XYInterpolationCurvePrivate::recalculate() {
//write the result
interpolationResult.available = true;
interpolationResult.valid = true;
- interpolationResult.status = i18n("OK");
+ interpolationResult.status = QString(gsl_strerror(status));;
interpolationResult.elapsedTime = timer.elapsed();
//redraw the curve
diff --git a/src/backend/worksheet/plots/cartesian/XYInterpolationCurve.h b/src/backend/worksheet/plots/cartesian/XYInterpolationCurve.h
index bc6c9e8..cf0339c 100644
--- a/src/backend/worksheet/plots/cartesian/XYInterpolationCurve.h
+++ b/src/backend/worksheet/plots/cartesian/XYInterpolationCurve.h
@@ -37,11 +37,7 @@ class XYInterpolationCurve: public XYCurve {
Q_OBJECT
public:
-#if GSL_MAJOR_VERSION >= 2
enum InterpolationType {Linear,Polynomial,CSpline,CSplinePeriodic,Akima,AkimaPeriodic,Steffen}; // TODO:more
-#else
- enum InterpolationType {Linear,Polynomial,CSpline,CSplinePeriodic,Akima,AkimaPeriodic}; // TODO:more
-#endif
enum InterpolationEval {Function,Derivative,Derivative2,Integral};
struct InterpolationData {
diff --git a/src/kdefrontend/dockwidgets/AxisDock.cpp b/src/kdefrontend/dockwidgets/AxisDock.cpp
index 42ef646..95a5b1c 100644
--- a/src/kdefrontend/dockwidgets/AxisDock.cpp
+++ b/src/kdefrontend/dockwidgets/AxisDock.cpp
@@ -1,5 +1,5 @@
/***************************************************************************
- File : AxisDock.cc
+ File : AxisDock.cpp
Project : LabPlot
Description : axes widget class
--------------------------------------------------------------------
diff --git a/src/kdefrontend/dockwidgets/XYEquationCurveDock.cpp b/src/kdefrontend/dockwidgets/XYEquationCurveDock.cpp
index 314cc99..62e1f89 100644
--- a/src/kdefrontend/dockwidgets/XYEquationCurveDock.cpp
+++ b/src/kdefrontend/dockwidgets/XYEquationCurveDock.cpp
@@ -1,5 +1,5 @@
/***************************************************************************
- File : XYEquationCurveDock.h
+ File : XYEquationCurveDock.cpp
Project : LabPlot
--------------------------------------------------------------------
Copyright : (C) 2014 Alexander Semke (alexander.semke at web.de)
diff --git a/src/kdefrontend/dockwidgets/XYFitCurveDock.cpp b/src/kdefrontend/dockwidgets/XYFitCurveDock.cpp
index 9d1288d..a5d9445 100644
--- a/src/kdefrontend/dockwidgets/XYFitCurveDock.cpp
+++ b/src/kdefrontend/dockwidgets/XYFitCurveDock.cpp
@@ -1,5 +1,5 @@
/***************************************************************************
- File : XYFitCurveDock.h
+ File : XYFitCurveDock.cpp
Project : LabPlot
--------------------------------------------------------------------
Copyright : (C) 2014-2016 Alexander Semke (alexander.semke at web.de)
diff --git a/src/kdefrontend/dockwidgets/XYFourierFilterCurveDock.cpp b/src/kdefrontend/dockwidgets/XYFourierFilterCurveDock.cpp
index 8b65d24..0a70b16 100644
--- a/src/kdefrontend/dockwidgets/XYFourierFilterCurveDock.cpp
+++ b/src/kdefrontend/dockwidgets/XYFourierFilterCurveDock.cpp
@@ -1,5 +1,5 @@
/***************************************************************************
- File : XYFourierFilterCurveDock.h
+ File : XYFourierFilterCurveDock.cpp
Project : LabPlot
--------------------------------------------------------------------
Copyright : (C) 2016 Stefan Gerlach (stefan.gerlach at uni.kn)
diff --git a/src/kdefrontend/dockwidgets/XYInterpolationCurveDock.cpp b/src/kdefrontend/dockwidgets/XYInterpolationCurveDock.cpp
index 269393a..bb6a540 100644
--- a/src/kdefrontend/dockwidgets/XYInterpolationCurveDock.cpp
+++ b/src/kdefrontend/dockwidgets/XYInterpolationCurveDock.cpp
@@ -1,5 +1,5 @@
/***************************************************************************
- File : XYInterpolationCurveDock.h
+ File : XYInterpolationCurveDock.cpp
Project : LabPlot
--------------------------------------------------------------------
Copyright : (C) 2016 Stefan Gerlach (stefan.gerlach at uni.kn)
@@ -33,6 +33,9 @@
#include "commonfrontend/widgets/TreeViewComboBox.h"
#include <QMenu>
#include <QWidgetAction>
+#include <QStandardItemModel>
+#include <gsl_interp.h> // gsl_interp types
+#include <cmath> // isnan
#include <QDebug>
/*!
@@ -102,7 +105,6 @@ void XYInterpolationCurveDock::setupGeneral() {
connect( uiGeneralTab.cbEval, SIGNAL(currentIndexChanged(int)), this, SLOT(evaluateChanged(int)) );
connect( uiGeneralTab.sbPoints, SIGNAL(valueChanged(int)), this, SLOT(numberOfPointsChanged(int)) );
-// connect( uiGeneralTab.pbOptions, SIGNAL(clicked()), this, SLOT(showOptions()) );
connect( uiGeneralTab.pbRecalculate, SIGNAL(clicked()), this, SLOT(recalculateClicked()) );
}
@@ -131,6 +133,8 @@ void XYInterpolationCurveDock::initGeneralTab() {
Q_ASSERT(m_interpolationCurve);
XYCurveDock::setModelIndexFromColumn(cbXDataColumn, m_interpolationCurve->xDataColumn());
XYCurveDock::setModelIndexFromColumn(cbYDataColumn, m_interpolationCurve->yDataColumn());
+ // update list of selectable types
+ xDataColumnChanged(cbXDataColumn->currentModelIndex());
uiGeneralTab.cbType->setCurrentIndex(m_interpolationData.type);
this->typeChanged(m_interpolationData.type);
@@ -162,11 +166,12 @@ void XYInterpolationCurveDock::setModel() {
cbXDataColumn->setSelectableClasses(list);
cbYDataColumn->setSelectableClasses(list);
+ connect( cbXDataColumn, SIGNAL(currentModelIndexChanged(QModelIndex)), this, SLOT(xDataColumnChanged(QModelIndex)) );
+ connect( cbYDataColumn, SIGNAL(currentModelIndexChanged(QModelIndex)), this, SLOT(yDataColumnChanged(QModelIndex)) );
+
cbXDataColumn->setModel(m_aspectTreeModel);
cbYDataColumn->setModel(m_aspectTreeModel);
- connect( cbXDataColumn, SIGNAL(currentModelIndexChanged(QModelIndex)), this, SLOT(xDataColumnChanged(QModelIndex)) );
- connect( cbYDataColumn, SIGNAL(currentModelIndexChanged(QModelIndex)), this, SLOT(yDataColumnChanged(QModelIndex)) );
XYCurveDock::setModel();
}
@@ -205,9 +210,6 @@ void XYInterpolationCurveDock::commentChanged(){
}
void XYInterpolationCurveDock::xDataColumnChanged(const QModelIndex& index) {
- if (m_initializing)
- return;
-
AbstractAspect* aspect = static_cast<AbstractAspect*>(index.internalPointer());
AbstractColumn* column = 0;
if (aspect) {
@@ -218,9 +220,70 @@ void XYInterpolationCurveDock::xDataColumnChanged(const QModelIndex& index) {
foreach(XYCurve* curve, m_curvesList)
dynamic_cast<XYInterpolationCurve*>(curve)->setXDataColumn(column);
- // update range of cutoff spin boxes (like a unit change)
-// unitChanged(uiGeneralTab.cbUnit->currentIndex());
-// unit2Changed(uiGeneralTab.cbUnit2->currentIndex());
+ // disable types that need more data points
+ if(column != 0) {
+ unsigned int n=0;
+ for(int row=0;row < column->rowCount();row++)
+ if (!isnan(column->valueAt(row)) && !column->isMasked(row))
+ n++;
+
+ const QStandardItemModel* model = qobject_cast<const QStandardItemModel*>(uiGeneralTab.cbType->model());
+ QStandardItem* item = model->item(XYInterpolationCurve::Polynomial);
+ if(n < gsl_interp_type_min_size(gsl_interp_polynomial)) {
+ item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
+ if(uiGeneralTab.cbType->currentIndex() == XYInterpolationCurve::Polynomial)
+ uiGeneralTab.cbType->setCurrentIndex(0);
+ }
+ else
+ item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
+
+ item = model->item(XYInterpolationCurve::CSpline);
+ if(n < gsl_interp_type_min_size(gsl_interp_cspline)) {
+ item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
+ if(uiGeneralTab.cbType->currentIndex() == XYInterpolationCurve::CSpline)
+ uiGeneralTab.cbType->setCurrentIndex(0);
+ }
+ else
+ item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
+
+ item = model->item(XYInterpolationCurve::CSplinePeriodic);
+ if(n < gsl_interp_type_min_size(gsl_interp_cspline_periodic)) {
+ item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
+ if(uiGeneralTab.cbType->currentIndex() == XYInterpolationCurve::CSplinePeriodic)
+ uiGeneralTab.cbType->setCurrentIndex(0);
+ }
+ else
+ item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
+
+ item = model->item(XYInterpolationCurve::Akima);
+ if(n < gsl_interp_type_min_size(gsl_interp_akima)) {
+ item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
+ if(uiGeneralTab.cbType->currentIndex() == XYInterpolationCurve::Akima)
+ uiGeneralTab.cbType->setCurrentIndex(0);
+ }
+ else
+ item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
+
+ item = model->item(XYInterpolationCurve::AkimaPeriodic);
+ if(n < gsl_interp_type_min_size(gsl_interp_akima_periodic)) {
+ item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
+ if(uiGeneralTab.cbType->currentIndex() == XYInterpolationCurve::AkimaPeriodic)
+ uiGeneralTab.cbType->setCurrentIndex(0);
+ }
+ else
+ item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
+
+#if GSL_MAJOR_VERSION >= 2
+ item = model->item(XYInterpolationCurve::Steffen);
+ if(n < gsl_interp_type_min_size(gsl_interp_steffen)) {
+ item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
+ if(uiGeneralTab.cbType->currentIndex() == XYInterpolationCurve::Steffen)
+ uiGeneralTab.cbType->setCurrentIndex(0);
+ }
+ else
+ item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
+#endif
+ }
}
void XYInterpolationCurveDock::yDataColumnChanged(const QModelIndex& index) {
@@ -239,16 +302,14 @@ void XYInterpolationCurveDock::yDataColumnChanged(const QModelIndex& index) {
}
void XYInterpolationCurveDock::typeChanged(int index) {
- XYInterpolationCurve::InterpolationType type = (XYInterpolationCurve::InterpolationType)index;
+ //XYInterpolationCurve::InterpolationType type = (XYInterpolationCurve::InterpolationType)index;
m_interpolationData.type = (XYInterpolationCurve::InterpolationType)uiGeneralTab.cbType->currentIndex();
- //TODO
-
uiGeneralTab.pbRecalculate->setEnabled(true);
}
void XYInterpolationCurveDock::evaluateChanged(int index) {
- XYInterpolationCurve::InterpolationEval eval = (XYInterpolationCurve::InterpolationEval)index;
+ //XYInterpolationCurve::InterpolationEval eval = (XYInterpolationCurve::InterpolationEval)index;
m_interpolationData.evaluate = (XYInterpolationCurve::InterpolationEval)uiGeneralTab.cbEval->currentIndex();
uiGeneralTab.pbRecalculate->setEnabled(true);
More information about the kde-doc-english
mailing list