mirror of
https://github.com/jkriege2/JKQtPlotter.git
synced 2024-12-24 09:31:40 +08:00
improved parsed/evaluated function classes (made C++11-ready) and added examples for them
This commit is contained in:
parent
4e64a493ef
commit
4ac14ed871
@ -52,6 +52,8 @@ addSimpleTest(rgbimageplot_qt)
|
||||
addSimpleTest(impulsesplot)
|
||||
addSimpleTest(paramscatterplot)
|
||||
addSimpleTest(parametriccurve)
|
||||
addSimpleTest(parsedfunctionplot)
|
||||
addSimpleTest(functionplot)
|
||||
#addSimpleTest(imageplot_nodatastore)
|
||||
#addSimpleTest(rgbimageplot_opencv)
|
||||
#addSimpleTest(imageplot_opencv)
|
||||
|
@ -33,6 +33,8 @@ All test-projects are Qt-projects that use qmake to build. You can load them int
|
||||
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_impulsesplot_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/test/simpletest_impulsesplot) | [Impulse Plots](https://github.com/jkriege2/JKQtPlotter/tree/master/test/simpletest_impulsesplot) | `JKQTPimpulsesVerticalGraph` and `JKQTPimpulsesHorizontalGraph`<br/>C++-style QVector as plot data |
|
||||
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_paramscatterplot_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/test/simpletest_paramscatterplot) | [Scatter Graph with Parametrized Symbols/Colors](https://github.com/jkriege2/JKQtPlotter/tree/master/test/simpletest_paramscatterplot) | `JKQTPxyParametrizedScatterGraph`<br/>C++-style QVector as plot data<br/>modify scatter/points/line-graph properties by data |
|
||||
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_parametriccurve_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/test/simpletest_parametriccurve) | [Plotting Parametric Curves](https://github.com/jkriege2/JKQtPlotter/tree/master/test/simpletest_parametriccurve) | `JKQTPxyLineGraph` and `JKQTPxyParametrizedScatterGraph`<br/>C++-style QVector as plot data<br/>parametric curve plotting |
|
||||
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_functionplot_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/test/simpletest_functionplot) | [Plotting Mathematical Functions as Line Graphs](https://github.com/jkriege2/JKQtPlotter/tree/master/test/simpletest_functionplot) | `JKQTPxFunctionLineGraph` <br/>diretly plotting C/C++-functions |
|
||||
[![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_parsedfunctionplot_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/test/simpletest_parsedfunctionplot) | [Plotting Parsed Mathematical Functions as Line Graphs](https://github.com/jkriege2/JKQtPlotter/tree/master/test/simpletest_parsedfunctionplot) | `JKQTPxParsedFunctionLineGraph` <br/>plotting functions with the internal math equation parser/evaluator |
|
||||
|
||||
### Styling the Plot, Keys, Axes, ...
|
||||
|
||||
|
@ -22,7 +22,7 @@ HEADERS += $$PWD/jkqtplotter/jkqtpbaseplotter.h \
|
||||
$$PWD/jkqtplottertools/jkqtpimagetools.h \
|
||||
$$PWD/jkqtplotter/jkqtpgraphsbarchart.h \
|
||||
$$PWD/jkqtplotter/jkqtpgraphsboxplot.h \
|
||||
$$PWD/jkqtplotter/jkqtpgraphsvaluatedfunction.h \
|
||||
$$PWD/jkqtplotter/jkqtpgraphsevaluatedfunction.h \
|
||||
$$PWD/jkqtplotter/jkqtpgraphsfilledcurve.h \
|
||||
$$PWD/jkqtplotter/jkqtpgraphsimpulses.h \
|
||||
$$PWD/jkqtplotter/jkqtpgraphsparsedfunction.h \
|
||||
@ -54,7 +54,7 @@ SOURCES += $$PWD/jkqtplotter/jkqtpbaseplotter.cpp \
|
||||
$$PWD/jkqtplottertools/jkqtpimagetools.cpp \
|
||||
$$PWD/jkqtplotter/jkqtpgraphsbarchart.cpp \
|
||||
$$PWD/jkqtplotter/jkqtpgraphsboxplot.cpp \
|
||||
$$PWD/jkqtplotter/jkqtpgraphsvaluatedfunction.cpp \
|
||||
$$PWD/jkqtplotter/jkqtpgraphsevaluatedfunction.cpp \
|
||||
$$PWD/jkqtplotter/jkqtpgraphsfilledcurve.cpp \
|
||||
$$PWD/jkqtplotter/jkqtpgraphsimpulses.cpp \
|
||||
$$PWD/jkqtplotter/jkqtpgraphsparsedfunction.cpp \
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,290 +1,317 @@
|
||||
/*
|
||||
Copyright (c) 2008-2018 Jan W. Krieger (<jan@jkrieger.de>)
|
||||
|
||||
|
||||
|
||||
This software is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License (LGPL) as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License (LGPL) for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License (LGPL)
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \defgroup jkqtplotter_elements Plot Elements
|
||||
* \ingroup jkqtplotter
|
||||
* \defgroup jkqtplotter_plots Graphs
|
||||
* \ingroup jkqtplotter_elements
|
||||
*/
|
||||
|
||||
/** \file jkqtpgraphs.h
|
||||
* \ingroup jkqtplotter
|
||||
*/
|
||||
|
||||
#include <QString>
|
||||
#include <QPainter>
|
||||
#include <QPair>
|
||||
#include "jkqtplotter/jkqtpgraphs.h"
|
||||
#include "jkqtplottertools/jkqtp_imexport.h"
|
||||
|
||||
#ifndef jkqtpgraphsvaluatedfunction_H
|
||||
#define jkqtpgraphsvaluatedfunction_H
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \brief type of functions that may be plottet
|
||||
\ingroup jkqtplotter_plots
|
||||
|
||||
This is the type of functions \f$ y=f(x, \vec{p}) \f$ that may be plottet by JKQTPxFunctionLineGraph
|
||||
and JKQTPyFunctionLineGraph. It is possible to supply parameters \f$ \vec{p} \f$ to the function that
|
||||
influence its result. Parameters are given as a pointer to some memory location. The function has to
|
||||
know on its own how to interpret these.
|
||||
*/
|
||||
typedef double(*jkqtpPlotFunctionType)(double, void*);
|
||||
|
||||
|
||||
/*! \brief This implements line plots where the data is taken from a user supplied function \f$ y=f(x) \f$
|
||||
\ingroup jkqtplotter_plots
|
||||
|
||||
This class implements an intelligent plotting algorithm for functions. It starts by sampling
|
||||
the function at minSamples positions. Then each function interval is bisected recursively if
|
||||
necessary. To do so the function is evaluated at the mid point and the slopes \f$ \alpha_{\mbox{left}} \f$
|
||||
and \f$ \alpha_{\mbox{right}} \f$ of the two linear segments are compared. the midpoint is added
|
||||
to the graph if \f[ \left|\alpha_{\mbox{right}}-\alpha_{\mbox{left}}\right|>\mbox{slopeTolerance} \f]
|
||||
In addition all sampling points except minimum and maximum are beeing shifted by a random fraction their
|
||||
distance to the other points. This helps to prevent beats when sampling periodic functions.
|
||||
|
||||
the following image
|
||||
\image html plot_functionplots.png
|
||||
*/
|
||||
class LIB_EXPORT JKQTPxFunctionLineGraph: public JKQTPgraph {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
enum SpecialFunction {
|
||||
Polynomial, /*!< \brief a polynomial \f$ f(x)=p_0+p_1x+p_2x^2+p_3x^3+... \f$ The parameters \a params have to be point to a QVector<double> and contain the parameters \f$ p_0, p_1, ... \f$ */
|
||||
Line=Polynomial, /*!< \brief a polynomial \f$ f(x)=p_0+p_1x \f$ The parameters \a params have to be point to a QVector<double> and contain the parameters \f$ p_0, p_1, ... \f$ */
|
||||
Exponential, /*!< \brief an exponential function \f$ f(x)=p_0+p_1\cdot\exp(x/p_2) \f$ or \f$ f(x)=p_0\cdot\exp(x/p_1) \f$ (depending on the number of parameters). The parameters \a params have to be point to a QVector<double> and contain the parameters \f$ p_0, p_1, ... \f$ */
|
||||
PowerLaw /*!< \brief an exponential function \f$ f(x)=p_0+p_1\cdot x^{p_3} \f$ or \f$ f(x)=p_0\cdot x^{p_1} \f$ or \f$ f(x)= x^{p_0} \f$ (depending on the number of parameters) The parameters \a params have to be point to a QVector<double> and contain the parameters \f$ p_0, p_1, ... \f$ */
|
||||
};
|
||||
|
||||
/** \brief class constructor */
|
||||
JKQTPxFunctionLineGraph(JKQtBasePlotter* parent=nullptr);
|
||||
|
||||
/** \brief class constructor */
|
||||
JKQTPxFunctionLineGraph(JKQtPlotter* parent);
|
||||
|
||||
/** \brief class destructor */
|
||||
virtual ~JKQTPxFunctionLineGraph();
|
||||
|
||||
/** \brief plots the graph to the plotter object specified as parent */
|
||||
virtual void draw(JKQTPEnhancedPainter& painter);
|
||||
/** \brief plots a key marker inside the specified rectangle \a rect */
|
||||
virtual void drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect);
|
||||
/** \brief returns the color to be used for the key label */
|
||||
virtual QColor getKeyLabelColor();
|
||||
|
||||
/** \brief get the maximum and minimum x-value of the graph
|
||||
*
|
||||
* This functions returns 0 for both parameters, so that the plotter uses the predefined
|
||||
* min and max values.
|
||||
*/
|
||||
virtual bool getXMinMax(double& minx, double& maxx, double& smallestGreaterZero);
|
||||
/** \brief get the maximum and minimum y-value of the graph
|
||||
*/
|
||||
virtual bool getYMinMax(double& miny, double& maxy, double& smallestGreaterZero);
|
||||
|
||||
/** \brief clear the data sampled from the function. */
|
||||
void clearData();
|
||||
|
||||
JKQTPGET_SET_MACRO(QColor, color)
|
||||
JKQTPGET_SET_MACRO(QColor, fillColor)
|
||||
JKQTPGET_SET_MACRO(Qt::BrushStyle, fillStyle)
|
||||
JKQTPGET_SET_MACRO(Qt::PenStyle, style)
|
||||
JKQTPGET_SET_MACRO(double, lineWidth)
|
||||
JKQTPGET_SET_MACRO(bool, drawLine)
|
||||
JKQTPGET_SET_MACRO_I(jkqtpPlotFunctionType, plotFunction, clearData())
|
||||
JKQTPGET_SET_MACRO_I(void*, params, clearData())
|
||||
/** \brief sets the params as a pointer to an internal COPY of the given vector (not the data of the vector, as then the size would be unknown!!!) */
|
||||
void set_params(const QVector<double>& params);
|
||||
/** \brief sets the params from a copy of the given array of length \a N */
|
||||
void set_copiedParams(const double* params, int N);
|
||||
inline void set_paramsV(double p1) {
|
||||
QVector<double> p;
|
||||
p<<p1;
|
||||
set_params(p);
|
||||
}
|
||||
inline void set_paramsV(double p1, double p2) {
|
||||
QVector<double> p;
|
||||
p<<p1<<p2;
|
||||
set_params(p);
|
||||
}
|
||||
inline void set_paramsV(double p1, double p2, double p3) {
|
||||
QVector<double> p;
|
||||
p<<p1<<p2<<p3;
|
||||
set_params(p);
|
||||
}
|
||||
inline void set_paramsV(double p1, double p2, double p3, double p4) {
|
||||
QVector<double> p;
|
||||
p<<p1<<p2<<p3<<p4;
|
||||
set_params(p);
|
||||
}
|
||||
inline void set_paramsV(double p1, double p2, double p3, double p4, double p5) {
|
||||
QVector<double> p;
|
||||
p<<p1<<p2<<p3<<p4<<p5;
|
||||
set_params(p);
|
||||
}
|
||||
|
||||
QVector<double> get_internalParams() const;
|
||||
QVector<double> get_internalErrorParams() const;
|
||||
JKQTPGET_SET_MACRO(unsigned int, minSamples)
|
||||
JKQTPGET_SET_MACRO(unsigned int, maxRefinementDegree)
|
||||
JKQTPGET_SET_MACRO(double, slopeTolerance)
|
||||
JKQTPGET_SET_MACRO(double, minPixelPerSample)
|
||||
JKQTPGET_SET_MACRO(bool, plotRefinement)
|
||||
JKQTPGET_SET_MACRO(bool, displaySamplePoints)
|
||||
JKQTPGET_SET_MACRO(bool, drawErrorPolygons)
|
||||
JKQTPGET_SET_MACRO(bool, drawErrorLines)
|
||||
JKQTPGET_SET_MACRO(jkqtpPlotFunctionType, errorPlotFunction)
|
||||
JKQTPGET_SET_MACRO(void*, errorParams)
|
||||
/** \brief sets the error params as a pointer to an internal COPY of the given vector (not the data of the vector, as then the size would be unknown!!!) */
|
||||
void set_errorParams(const QVector<double>& errorParams);
|
||||
|
||||
JKQTPGET_SET_MACRO(int, parameterColumn)
|
||||
JKQTPSET_CAST_MACRO(size_t, int, parameterColumn)
|
||||
JKQTPGET_SET_MACRO(int, errorParameterColumn)
|
||||
JKQTPSET_CAST_MACRO(size_t, int, errorParameterColumn)
|
||||
|
||||
JKQTPGET_SET_MACRO(QColor, errorColor)
|
||||
JKQTPGET_SET_MACRO(QColor, errorFillColor)
|
||||
JKQTPGET_SET_MACRO(Qt::BrushStyle, errorFillStyle)
|
||||
JKQTPGET_SET_MACRO(Qt::PenStyle, errorStyle)
|
||||
JKQTPGET_SET_MACRO(double, errorLineWidth)
|
||||
|
||||
/** \copydoc JKQTPgraph::usesColumn() */
|
||||
virtual bool usesColumn(int c);
|
||||
|
||||
|
||||
/** \brief sets function to the given special function */
|
||||
void setSpecialFunction(SpecialFunction function);
|
||||
protected:
|
||||
/** \brief which plot style to use from the parent plotter (via JKQtPlotterBase::getPlotStyle() and JKQtPlotterBase::getNextStyle() ) */
|
||||
int parentPlotStyle;
|
||||
|
||||
struct doublePair {
|
||||
double x;
|
||||
double f;
|
||||
doublePair* next;
|
||||
};
|
||||
/** \brief a linked list holding the datapoints \f$ \left(x, y=f(x, \vec{p})\right) \f$ to be plotted */
|
||||
doublePair* data;
|
||||
|
||||
/** \brief fill the data array with data from the function plotFunction */
|
||||
virtual void createPlotData( bool collectParams=true);
|
||||
|
||||
virtual void collectParameters();
|
||||
|
||||
void refine(doublePair* a, doublePair* b, unsigned int degree=0);
|
||||
|
||||
int parameterColumn;
|
||||
int errorParameterColumn;
|
||||
|
||||
/** \brief color of the graph */
|
||||
QColor color;
|
||||
/** \brief color of the graph fill */
|
||||
QColor fillColor;
|
||||
/** \brief linestyle of the graph lines */
|
||||
Qt::PenStyle style;
|
||||
/** \brief width (pixels) of the graph */
|
||||
double lineWidth;
|
||||
/** \brief fill style, if the curve should be filled */
|
||||
Qt::BrushStyle fillStyle;
|
||||
/** \brief indicates whether to draw a line or not */
|
||||
bool drawLine;
|
||||
/** \brief indicates whether to fill the space between the curve and the x-axis */
|
||||
bool fillCurve;
|
||||
/** \brief the function to be plotted */
|
||||
jkqtpPlotFunctionType plotFunction;
|
||||
/** \brief pointer to the parameters supplied to the plotting funtion */
|
||||
void* params;
|
||||
/** \brief the minimum number of points to evaluate the function at */
|
||||
unsigned int minSamples;
|
||||
/** \brief the maximum number of recursive refinement steps
|
||||
*
|
||||
* each step bisects the interval \f$ [a, b] \f$ into two halfes. So the maximum number
|
||||
* of points plotted at all are thus:
|
||||
* \f[ \mbox{minSamples} \cdot 2^{\mbox{maxRefinementDegree}} \f]
|
||||
*/
|
||||
unsigned int maxRefinementDegree;
|
||||
/** \brief the tolerance for the difference of two subsequent slopes */
|
||||
double slopeTolerance;
|
||||
/** \brief create one sample at least every \a minPixelPerSample pixels */
|
||||
double minPixelPerSample;
|
||||
/** \brief switch on or off [default: on] the plot refinement algorithm */
|
||||
bool plotRefinement;
|
||||
/** \brief if true [default: off] display the points where the function has been sampled */
|
||||
bool displaySamplePoints;
|
||||
/** \brief indicates whether an error polygon should be drawn */
|
||||
bool drawErrorPolygons;
|
||||
/** \brief indicates whether error lines should be drawn */
|
||||
bool drawErrorLines;
|
||||
/** \brief this function calculates the error at a given position */
|
||||
jkqtpPlotFunctionType errorPlotFunction;
|
||||
/** \brief parameters for errorFunction */
|
||||
void* errorParams;
|
||||
/** \brief color of the error graph */
|
||||
QColor errorColor;
|
||||
/** \brief color of the error graph fill */
|
||||
QColor errorFillColor;
|
||||
/** \brief linestyle of the error graph lines */
|
||||
Qt::PenStyle errorStyle;
|
||||
/** \brief width (pixels) of the error graph */
|
||||
double errorLineWidth;
|
||||
/** \brief fill style, if the error curve should be filled */
|
||||
Qt::BrushStyle errorFillStyle;
|
||||
|
||||
|
||||
QBrush getBrush(JKQTPEnhancedPainter& painter) const;
|
||||
QPen getLinePen(JKQTPEnhancedPainter& painter) const;
|
||||
|
||||
QBrush getErrorBrush(JKQTPEnhancedPainter& painter) const;
|
||||
QPen getErrorLinePen(JKQTPEnhancedPainter &painter) const;
|
||||
|
||||
QVector<double> iparams, ierrorparams;
|
||||
};
|
||||
|
||||
/*! \brief This implements line plots where the data is taken from a user supplied function \f$ x=f(y) \f$
|
||||
\ingroup jkqtplotter_plots
|
||||
|
||||
*/
|
||||
class LIB_EXPORT JKQTPyFunctionLineGraph: public JKQTPxFunctionLineGraph {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/** \brief class constructor */
|
||||
inline JKQTPyFunctionLineGraph(JKQtBasePlotter* parent=nullptr):JKQTPxFunctionLineGraph(parent) {}
|
||||
/** \brief class constructor */
|
||||
inline JKQTPyFunctionLineGraph(JKQtPlotter* parent):JKQTPxFunctionLineGraph(parent) {}
|
||||
|
||||
/** \brief plots the graph to the plotter object specified as parent */
|
||||
virtual void draw(JKQTPEnhancedPainter& painter);
|
||||
protected:
|
||||
|
||||
/** \brief fill the data array with data from the function plotFunction */
|
||||
virtual void createPlotData( bool collectParams=true);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // jkqtpgraphsvaluatedfunction_H
|
||||
/*
|
||||
Copyright (c) 2008-2018 Jan W. Krieger (<jan@jkrieger.de>)
|
||||
|
||||
|
||||
|
||||
This software is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License (LGPL) as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License (LGPL) for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License (LGPL)
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \defgroup jkqtplotter_elements Plot Elements
|
||||
* \ingroup jkqtplotter
|
||||
* \defgroup jkqtplotter_plots Graphs
|
||||
* \ingroup jkqtplotter_elements
|
||||
*/
|
||||
|
||||
/** \file jkqtpgraphs.h
|
||||
* \ingroup jkqtplotter
|
||||
*/
|
||||
|
||||
#include <QString>
|
||||
#include <QPainter>
|
||||
#include <QPair>
|
||||
#include "jkqtplotter/jkqtpgraphs.h"
|
||||
#include "jkqtplottertools/jkqtp_imexport.h"
|
||||
#include <functional>
|
||||
|
||||
#ifndef jkqtpgraphsevaluatedfunction_H
|
||||
#define jkqtpgraphsevaluatedfunction_H
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \brief type of functions that may be plottet
|
||||
\ingroup jkqtplotter_plots
|
||||
|
||||
This is the type of functions \f$ y=f(x, \vec{p}) \f$ that may be plottet by JKQTPxFunctionLineGraph
|
||||
and JKQTPyFunctionLineGraph. It is possible to supply parameters \f$ \vec{p} \f$ to the function that
|
||||
influence its result. Parameters are given as a pointer to some memory location. The function has to
|
||||
know on its own how to interpret these.
|
||||
*/
|
||||
typedef std::function<double(double, void*)> jkqtpPlotFunctionType;
|
||||
|
||||
|
||||
/*! \brief This implements line plots where the data is taken from a user supplied function \f$ y=f(x) \f$
|
||||
\ingroup jkqtplotter_plots
|
||||
|
||||
This class implements an intelligent plotting algorithm for functions. It starts by sampling
|
||||
the function at minSamples positions. Then each function interval is bisected recursively if
|
||||
necessary. To do so the function is evaluated at the mid point and the slopes \f$ \alpha_{\mbox{left}} \f$
|
||||
and \f$ \alpha_{\mbox{right}} \f$ of the two linear segments are compared. the midpoint is added
|
||||
to the graph if \f[ \left|\alpha_{\mbox{right}}-\alpha_{\mbox{left}}\right|>\mbox{slopeTolerance} \f]
|
||||
In addition all sampling points except minimum and maximum are beeing shifted by a random fraction their
|
||||
distance to the other points. This helps to prevent beats when sampling periodic functions.
|
||||
|
||||
the following image
|
||||
\image html plot_functionplots.png
|
||||
*/
|
||||
class LIB_EXPORT JKQTPxFunctionLineGraph: public JKQTPgraph {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
enum SpecialFunction {
|
||||
Polynomial, /*!< \brief a polynomial \f$ f(x)=p_0+p_1x+p_2x^2+p_3x^3+... \f$ The parameters \a params have to be point to a QVector<double> and contain the parameters \f$ p_0, p_1, ... \f$ */
|
||||
Line=Polynomial, /*!< \brief a polynomial \f$ f(x)=p_0+p_1x \f$ The parameters \a params have to be point to a QVector<double> and contain the parameters \f$ p_0, p_1, ... \f$ */
|
||||
Exponential, /*!< \brief an exponential function \f$ f(x)=p_0+p_1\cdot\exp(x/p_2) \f$ or \f$ f(x)=p_0\cdot\exp(x/p_1) \f$ (depending on the number of parameters). The parameters \a params have to be point to a QVector<double> and contain the parameters \f$ p_0, p_1, ... \f$ */
|
||||
PowerLaw /*!< \brief an exponential function \f$ f(x)=p_0+p_1\cdot x^{p_3} \f$ or \f$ f(x)=p_0\cdot x^{p_1} \f$ or \f$ f(x)= x^{p_0} \f$ (depending on the number of parameters) The parameters \a params have to be point to a QVector<double> and contain the parameters \f$ p_0, p_1, ... \f$ */
|
||||
};
|
||||
|
||||
/** \brief class constructor */
|
||||
JKQTPxFunctionLineGraph(JKQtBasePlotter* parent=nullptr);
|
||||
|
||||
/** \brief class constructor */
|
||||
JKQTPxFunctionLineGraph(JKQtPlotter* parent);
|
||||
|
||||
/** \brief class destructor */
|
||||
virtual ~JKQTPxFunctionLineGraph();
|
||||
|
||||
/** \brief plots the graph to the plotter object specified as parent */
|
||||
virtual void draw(JKQTPEnhancedPainter& painter);
|
||||
/** \brief plots a key marker inside the specified rectangle \a rect */
|
||||
virtual void drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect);
|
||||
/** \brief returns the color to be used for the key label */
|
||||
virtual QColor getKeyLabelColor();
|
||||
|
||||
/** \brief get the maximum and minimum x-value of the graph
|
||||
*
|
||||
* This functions returns 0 for both parameters, so that the plotter uses the predefined
|
||||
* min and max values.
|
||||
*/
|
||||
virtual bool getXMinMax(double& minx, double& maxx, double& smallestGreaterZero);
|
||||
/** \brief get the maximum and minimum y-value of the graph
|
||||
*/
|
||||
virtual bool getYMinMax(double& miny, double& maxy, double& smallestGreaterZero);
|
||||
|
||||
/** \brief clear the data sampled from the function. */
|
||||
void clearData();
|
||||
|
||||
JKQTPGET_SET_MACRO(QColor, color)
|
||||
JKQTPGET_SET_MACRO(QColor, fillColor)
|
||||
JKQTPGET_SET_MACRO(Qt::BrushStyle, fillStyle)
|
||||
JKQTPGET_SET_MACRO(Qt::PenStyle, style)
|
||||
JKQTPGET_SET_MACRO(double, lineWidth)
|
||||
JKQTPGET_SET_MACRO(bool, drawLine)
|
||||
|
||||
/** \brief sets the property plotFunction to the specified \a __value.
|
||||
*
|
||||
* \details Description of the parameter varname is: <CENTER>\copybrief plotFunction.</CENTER>
|
||||
* \see plotFunction for more information */
|
||||
virtual void set_plotFunction (jkqtpPlotFunctionType && __value);
|
||||
/** \brief sets the property plotFunction to the specified \a __value.
|
||||
*
|
||||
* \details Description of the parameter varname is: <CENTER>\copybrief plotFunction.</CENTER>
|
||||
* \see plotFunction for more information */
|
||||
virtual void set_plotFunction (const jkqtpPlotFunctionType & __value);
|
||||
/** \brief returns the property varname. \see varname for more information */ \
|
||||
virtual jkqtpPlotFunctionType get_plotFunction () const;
|
||||
|
||||
JKQTPGET_SET_MACRO_I(void*, params, clearData())
|
||||
/** \brief sets the params as a pointer to an internal COPY of the given vector (not the data of the vector, as then the size would be unknown!!!) */
|
||||
void set_params(const QVector<double>& params);
|
||||
/** \brief sets the params from a copy of the given array of length \a N */
|
||||
void set_copiedParams(const double* params, int N);
|
||||
inline void set_paramsV(double p1) {
|
||||
QVector<double> p;
|
||||
p<<p1;
|
||||
set_params(p);
|
||||
}
|
||||
inline void set_paramsV(double p1, double p2) {
|
||||
QVector<double> p;
|
||||
p<<p1<<p2;
|
||||
set_params(p);
|
||||
}
|
||||
inline void set_paramsV(double p1, double p2, double p3) {
|
||||
QVector<double> p;
|
||||
p<<p1<<p2<<p3;
|
||||
set_params(p);
|
||||
}
|
||||
inline void set_paramsV(double p1, double p2, double p3, double p4) {
|
||||
QVector<double> p;
|
||||
p<<p1<<p2<<p3<<p4;
|
||||
set_params(p);
|
||||
}
|
||||
inline void set_paramsV(double p1, double p2, double p3, double p4, double p5) {
|
||||
QVector<double> p;
|
||||
p<<p1<<p2<<p3<<p4<<p5;
|
||||
set_params(p);
|
||||
}
|
||||
|
||||
QVector<double> get_internalParams() const;
|
||||
QVector<double> get_internalErrorParams() const;
|
||||
JKQTPGET_SET_MACRO(unsigned int, minSamples)
|
||||
JKQTPGET_SET_MACRO(unsigned int, maxRefinementDegree)
|
||||
JKQTPGET_SET_MACRO(double, slopeTolerance)
|
||||
JKQTPGET_SET_MACRO(double, minPixelPerSample)
|
||||
JKQTPGET_SET_MACRO(bool, plotRefinement)
|
||||
JKQTPGET_SET_MACRO(bool, displaySamplePoints)
|
||||
JKQTPGET_SET_MACRO(bool, drawErrorPolygons)
|
||||
JKQTPGET_SET_MACRO(bool, drawErrorLines)
|
||||
/** \brief sets the property errorPlotFunction to the specified \a __value.
|
||||
*
|
||||
* \details Description of the parameter varname is: <CENTER>\copybrief errorPlotFunction.</CENTER>
|
||||
* \see errorPlotFunction for more information */
|
||||
virtual void set_errorPlotFunction (jkqtpPlotFunctionType && __value);
|
||||
/** \brief sets the property errorPlotFunction to the specified \a __value.
|
||||
*
|
||||
* \details Description of the parameter varname is: <CENTER>\copybrief errorPlotFunction.</CENTER>
|
||||
* \see errorPlotFunction for more information */
|
||||
virtual void set_errorPlotFunction (const jkqtpPlotFunctionType & __value);
|
||||
/** \brief returns the property varname. \see varname for more information */ \
|
||||
virtual jkqtpPlotFunctionType get_errorPlotFunction () const;
|
||||
JKQTPGET_SET_MACRO(void*, errorParams)
|
||||
/** \brief sets the error params as a pointer to an internal COPY of the given vector (not the data of the vector, as then the size would be unknown!!!) */
|
||||
void set_errorParams(const QVector<double>& errorParams);
|
||||
|
||||
JKQTPGET_SET_MACRO(int, parameterColumn)
|
||||
JKQTPSET_CAST_MACRO(size_t, int, parameterColumn)
|
||||
JKQTPGET_SET_MACRO(int, errorParameterColumn)
|
||||
JKQTPSET_CAST_MACRO(size_t, int, errorParameterColumn)
|
||||
|
||||
JKQTPGET_SET_MACRO(QColor, errorColor)
|
||||
JKQTPGET_SET_MACRO(QColor, errorFillColor)
|
||||
JKQTPGET_SET_MACRO(Qt::BrushStyle, errorFillStyle)
|
||||
JKQTPGET_SET_MACRO(Qt::PenStyle, errorStyle)
|
||||
JKQTPGET_SET_MACRO(double, errorLineWidth)
|
||||
|
||||
/** \copydoc JKQTPgraph::usesColumn() */
|
||||
virtual bool usesColumn(int c);
|
||||
|
||||
|
||||
/** \brief sets function to the given special function */
|
||||
void setSpecialFunction(SpecialFunction function);
|
||||
protected:
|
||||
/** \brief which plot style to use from the parent plotter (via JKQtPlotterBase::getPlotStyle() and JKQtPlotterBase::getNextStyle() ) */
|
||||
int parentPlotStyle;
|
||||
|
||||
struct doublePair {
|
||||
double x;
|
||||
double f;
|
||||
doublePair* next;
|
||||
};
|
||||
/** \brief a linked list holding the datapoints \f$ \left(x, y=f(x, \vec{p})\right) \f$ to be plotted */
|
||||
doublePair* data;
|
||||
|
||||
/** \brief fill the data array with data from the function plotFunction */
|
||||
virtual void createPlotData( bool collectParams=true);
|
||||
|
||||
virtual void collectParameters();
|
||||
|
||||
void refine(doublePair* a, doublePair* b, unsigned int degree=0);
|
||||
|
||||
/** \brief if set, the values from this datatsore column are used for the parameters \c p1 , \c p2 , \c p3 , ... of the plot function */
|
||||
int parameterColumn;
|
||||
/** \brief if set, the values from this datatsore column are used for the parameters \c p1 , \c p2 , \c p3 , ... of the error plot function */
|
||||
int errorParameterColumn;
|
||||
|
||||
/** \brief color of the graph */
|
||||
QColor color;
|
||||
/** \brief color of the graph fill */
|
||||
QColor fillColor;
|
||||
/** \brief linestyle of the graph lines */
|
||||
Qt::PenStyle style;
|
||||
/** \brief width (pixels) of the graph */
|
||||
double lineWidth;
|
||||
/** \brief fill style, if the curve should be filled */
|
||||
Qt::BrushStyle fillStyle;
|
||||
/** \brief indicates whether to draw a line or not */
|
||||
bool drawLine;
|
||||
/** \brief indicates whether to fill the space between the curve and the x-axis */
|
||||
bool fillCurve;
|
||||
/** \brief the function to be plotted */
|
||||
jkqtpPlotFunctionType plotFunction;
|
||||
/** \brief pointer to the parameters supplied to the plotting funtion */
|
||||
void* params;
|
||||
/** \brief the minimum number of points to evaluate the function at */
|
||||
unsigned int minSamples;
|
||||
/** \brief the maximum number of recursive refinement steps
|
||||
*
|
||||
* each step bisects the interval \f$ [a, b] \f$ into two halfes. So the maximum number
|
||||
* of points plotted at all are thus:
|
||||
* \f[ \mbox{minSamples} \cdot 2^{\mbox{maxRefinementDegree}} \f]
|
||||
*/
|
||||
unsigned int maxRefinementDegree;
|
||||
/** \brief the tolerance for the difference of two subsequent slopes */
|
||||
double slopeTolerance;
|
||||
/** \brief create one sample at least every \a minPixelPerSample pixels */
|
||||
double minPixelPerSample;
|
||||
/** \brief switch on or off [default: on] the plot refinement algorithm */
|
||||
bool plotRefinement;
|
||||
/** \brief if true [default: off] display the points where the function has been sampled */
|
||||
bool displaySamplePoints;
|
||||
/** \brief indicates whether an error polygon should be drawn */
|
||||
bool drawErrorPolygons;
|
||||
/** \brief indicates whether error lines should be drawn */
|
||||
bool drawErrorLines;
|
||||
/** \brief this function calculates the error at a given position */
|
||||
jkqtpPlotFunctionType errorPlotFunction;
|
||||
/** \brief parameters for errorFunction */
|
||||
void* errorParams;
|
||||
/** \brief color of the error graph */
|
||||
QColor errorColor;
|
||||
/** \brief color of the error graph fill */
|
||||
QColor errorFillColor;
|
||||
/** \brief linestyle of the error graph lines */
|
||||
Qt::PenStyle errorStyle;
|
||||
/** \brief width (pixels) of the error graph */
|
||||
double errorLineWidth;
|
||||
/** \brief fill style, if the error curve should be filled */
|
||||
Qt::BrushStyle errorFillStyle;
|
||||
|
||||
|
||||
QBrush getBrush(JKQTPEnhancedPainter& painter) const;
|
||||
QPen getLinePen(JKQTPEnhancedPainter& painter) const;
|
||||
|
||||
QBrush getErrorBrush(JKQTPEnhancedPainter& painter) const;
|
||||
QPen getErrorLinePen(JKQTPEnhancedPainter &painter) const;
|
||||
|
||||
QVector<double> iparams, ierrorparams;
|
||||
};
|
||||
|
||||
/*! \brief This implements line plots where the data is taken from a user supplied function \f$ x=f(y) \f$
|
||||
\ingroup jkqtplotter_plots
|
||||
|
||||
*/
|
||||
class LIB_EXPORT JKQTPyFunctionLineGraph: public JKQTPxFunctionLineGraph {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/** \brief class constructor */
|
||||
inline JKQTPyFunctionLineGraph(JKQtBasePlotter* parent=nullptr):JKQTPxFunctionLineGraph(parent) {}
|
||||
/** \brief class constructor */
|
||||
inline JKQTPyFunctionLineGraph(JKQtPlotter* parent):JKQTPxFunctionLineGraph(parent) {}
|
||||
|
||||
/** \brief plots the graph to the plotter object specified as parent */
|
||||
virtual void draw(JKQTPEnhancedPainter& painter);
|
||||
protected:
|
||||
|
||||
/** \brief fill the data array with data from the function plotFunction */
|
||||
virtual void createPlotData( bool collectParams=true);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // jkqtpgraphsevaluatedfunction_H
|
@ -26,11 +26,11 @@
|
||||
#include <stdlib.h>
|
||||
#include <QDebug>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include <utility>
|
||||
|
||||
|
||||
double JKQTPxParsedFunctionLineGraphFunction(double x, void* data) {
|
||||
JKQTPxParsedFunctionLineGraphFunctionData* d=(JKQTPxParsedFunctionLineGraphFunctionData*)data;
|
||||
JKQTPxParsedFunctionLineGraph::JKQTPxParsedFunctionLineGraphFunctionData* d=(JKQTPxParsedFunctionLineGraph::JKQTPxParsedFunctionLineGraphFunctionData*)data;
|
||||
if (d && d->parser && d->node) {
|
||||
try {
|
||||
d->parser->addVariableDouble("x", x);
|
||||
@ -102,6 +102,14 @@ JKQTPxParsedFunctionLineGraph::~JKQTPxParsedFunctionLineGraph()
|
||||
delete efdata.parser;
|
||||
}
|
||||
|
||||
void JKQTPxParsedFunctionLineGraph::set_plotFunction(jkqtpPlotFunctionType &&f){
|
||||
JKQTPxFunctionLineGraph::set_plotFunction(std::move(f));
|
||||
}
|
||||
|
||||
void JKQTPxParsedFunctionLineGraph::set_plotFunction(const jkqtpPlotFunctionType &f) {
|
||||
JKQTPxFunctionLineGraph::set_plotFunction(f);
|
||||
}
|
||||
|
||||
void JKQTPxParsedFunctionLineGraph::createPlotData(bool /*collectParams*/)
|
||||
{
|
||||
collectParameters();
|
||||
|
@ -27,19 +27,13 @@
|
||||
#include "jkqtplottertools/jkqtptools.h"
|
||||
#include "jkqtplottertools/jkqtpmathparser.h"
|
||||
#include "jkqtplottertools/jkqtp_imexport.h"
|
||||
#include "jkqtplotter/jkqtpgraphsvaluatedfunction.h"
|
||||
#include "jkqtplotter/jkqtpgraphsevaluatedfunction.h"
|
||||
|
||||
// forward declarations
|
||||
class JKQtBasePlotter;
|
||||
class JKQtPlotter;
|
||||
|
||||
|
||||
struct JKQTPxParsedFunctionLineGraphFunctionData {
|
||||
JKQTPMathParser* parser;
|
||||
JKQTPMathParser::jkmpNode* node;
|
||||
int varcount;
|
||||
};
|
||||
|
||||
|
||||
/*! \brief This implements line plots where the data is taken from a user supplied function \f$ y=f(x) \f$ The function is defined as a string and parsed by JKMathParser
|
||||
\ingroup jkqtplotter_plots
|
||||
@ -63,26 +57,34 @@ class LIB_EXPORT JKQTPxParsedFunctionLineGraph: public JKQTPxFunctionLineGraph {
|
||||
|
||||
JKQTPGET_SET_MACRO(QList<double>, parameters)
|
||||
JKQTPGET_SET_MACRO(QString, function)
|
||||
JKQTPGET_SET_MACRO(int, parameterColumn)
|
||||
|
||||
JKQTPGET_SET_MACRO(QList<double>, errorParameters)
|
||||
JKQTPGET_SET_MACRO(QString, errorFunction)
|
||||
JKQTPGET_SET_MACRO(int, errorParameterColumn)
|
||||
|
||||
/** \brief INTERNAL data structure
|
||||
* \internal
|
||||
*/
|
||||
struct JKQTPxParsedFunctionLineGraphFunctionData {
|
||||
JKQTPMathParser* parser;
|
||||
JKQTPMathParser::jkmpNode* node;
|
||||
int varcount;
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
/** \brief which plot style to use from the parent plotter (via JKQtPlotterBase::getPlotStyle() and JKQtPlotterBase::getNextStyle() ) */
|
||||
/** \brief the function to be evaluated for the plot. Use \c x as the free variable, e.g. \c "x^2+2" */
|
||||
QString function;
|
||||
/** \brief values of the parameters \c p1 , \c p2 , \c p3 , ... */
|
||||
QList<double> parameters;
|
||||
JKQTPxParsedFunctionLineGraphFunctionData fdata;
|
||||
int parameterColumn;
|
||||
|
||||
/** \brief the function to be evaluated to add error indicators to the graph. This function is evaluated to an error for every x. Use \c x as the free variable, e.g. \c "x^2+2". */
|
||||
QString errorFunction;
|
||||
/** \brief values of the parameters \c p1 , \c p2 , \c p3 , ... for the error function*/
|
||||
QList<double> errorParameters;
|
||||
JKQTPxParsedFunctionLineGraphFunctionData efdata;
|
||||
int errorParameterColumn;
|
||||
|
||||
JKQTPGET_SET_MACRO_I(jkqtpPlotFunctionType, plotFunction, clearData())
|
||||
virtual void set_plotFunction(jkqtpPlotFunctionType&& f);
|
||||
virtual void set_plotFunction(const jkqtpPlotFunctionType& f);
|
||||
JKQTPGET_SET_MACRO_I(void*, params, clearData())
|
||||
JKQTPGET_SET_MACRO(jkqtpPlotFunctionType, errorPlotFunction)
|
||||
JKQTPGET_SET_MACRO(void*, errorParams)
|
||||
|
@ -1079,6 +1079,7 @@ JKQTPMathParser::jkmpTokenType JKQTPMathParser::getToken(){
|
||||
// else
|
||||
program->putback(ch1);
|
||||
jkmpError("undefined operator '&'; Did you mean LOGICAL_AND ('&&' / 'and')?");
|
||||
break;
|
||||
}
|
||||
case '|':{
|
||||
char ch1=0;
|
||||
@ -1087,6 +1088,7 @@ JKQTPMathParser::jkmpTokenType JKQTPMathParser::getToken(){
|
||||
// else
|
||||
program->putback(ch1);
|
||||
jkmpError("undefined operator '|'; Did you mean LOGICAL_OR ('||' / 'or')?");
|
||||
break;
|
||||
}
|
||||
case '=':{
|
||||
char ch1=0;
|
||||
|
BIN
screenshots/jkqtplotter_simpletest_functionplot.png
Normal file
BIN
screenshots/jkqtplotter_simpletest_functionplot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 89 KiB |
BIN
screenshots/jkqtplotter_simpletest_functionplot_small.png
Normal file
BIN
screenshots/jkqtplotter_simpletest_functionplot_small.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
BIN
screenshots/jkqtplotter_simpletest_parsedfunctionplot.png
Normal file
BIN
screenshots/jkqtplotter_simpletest_parsedfunctionplot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
BIN
screenshots/jkqtplotter_simpletest_parsedfunctionplot_2overx.png
Normal file
BIN
screenshots/jkqtplotter_simpletest_parsedfunctionplot_2overx.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
BIN
screenshots/jkqtplotter_simpletest_parsedfunctionplot_small.cpt
Normal file
BIN
screenshots/jkqtplotter_simpletest_parsedfunctionplot_small.cpt
Normal file
Binary file not shown.
BIN
screenshots/jkqtplotter_simpletest_parsedfunctionplot_small.png
Normal file
BIN
screenshots/jkqtplotter_simpletest_parsedfunctionplot_small.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
96
test/simpletest_functionplot/README.md
Normal file
96
test/simpletest_functionplot/README.md
Normal file
@ -0,0 +1,96 @@
|
||||
[Back to JKQTPlotter main page](https://github.com/jkriege2/JKQtPlotter/)
|
||||
|
||||
# JKQtPlotter
|
||||
|
||||
## Plotting Mathematical Functions as Line Graphs
|
||||
This project (see `./test/simpletest_functionplot/`) demonstrates how to plot mathematical functions as line graphs. The functions may be defined as static C functions, C++ functors or c++ inline functions. See [test/simpletest_parsedfunctionplot](https://github.com/jkriege2/JKQtPlotter/tree/master/test/simpletest_parsedfunctionplot) for an example of how to use an internal equation parser provided with JKQtPlotter instead of directly defining functions.
|
||||
|
||||
The first example shows how to plot a C++ inline function:
|
||||
```c++
|
||||
JKQTPxFunctionLineGraph* func1=new JKQTPxFunctionLineGraph(plot);
|
||||
func1->set_plotFunction([](double x, void* /*params*/) { return 0.2*x*x-0.015*x*x*x; });
|
||||
func1->set_title("C++-inline function $0.2x^2-0.015x^3$");
|
||||
plot->addGraph(func1);
|
||||
```
|
||||
|
||||
In any such plot function, you can also use parameters, provided via the second parameter. Usually these are "internal parameters", defined by `func2->set_paramsV(p0, p1, ...)`:
|
||||
```c++
|
||||
JKQTPxFunctionLineGraph* func2=new JKQTPxFunctionLineGraph(plot);
|
||||
func2->set_plotFunction([](double x, void* params) {
|
||||
QVector<double>* p=static_cast<QVector<double>*>(params);
|
||||
return p->at(0)*sin(2.0*M_PI*x*p->at(1));
|
||||
});
|
||||
// here we set the parameters p0, p1
|
||||
func2->set_paramsV(5, 0.2);
|
||||
func2->set_title("C++-inline function with int. params $p_0\\cdot\\sin(x*2.0*\\pi\\cdot p_1)$");
|
||||
plot->addGraph(func2);
|
||||
```
|
||||
|
||||
... but generally any pointer can be used as parameter (the set by `set_parameter(static_cast<void*>(myDataObject))`):
|
||||
```c++
|
||||
JKQTPxFunctionLineGraph* func3=new JKQTPxFunctionLineGraph(plot);
|
||||
func3->set_plotFunction([](double x, void* params) {
|
||||
QMap<QString,double>* p=static_cast<QMap<QString,double>*>(params);
|
||||
return p->value("amplitude")*sin(2.0*M_PI*x*p->value("frequency"));
|
||||
});
|
||||
// here we set the parameters p0, p1
|
||||
QMap<QString,double> params3;
|
||||
params3["amplitude"]=-3;
|
||||
params3["frequency"]=0.3;
|
||||
func3->set_params(¶ms3);
|
||||
func3->set_title("C++-inline function with ext. params $p_0\\cdot\\sin(x*2.0*\\pi\\cdot p_1)$");
|
||||
plot->addGraph(func3);
|
||||
```
|
||||
|
||||
You can also use C++ functors (or function objects):
|
||||
```c++
|
||||
struct SincSqr {
|
||||
public:
|
||||
inline SincSqr(double amplitude): a(amplitude) {}
|
||||
inline double operator()(double x, void* /*params*/) {
|
||||
return a*sin(x)*sin(x)/x/x;
|
||||
}
|
||||
private:
|
||||
double a;
|
||||
};
|
||||
|
||||
// ...
|
||||
|
||||
JKQTPxFunctionLineGraph* func4=new JKQTPxFunctionLineGraph(plot);
|
||||
func4->set_plotFunction(SincSqr(-8));
|
||||
func4->set_title("C++ functor $-8*\\sin^2(x)/x^2$");
|
||||
plot->addGraph(func4);
|
||||
```
|
||||
|
||||
... or simple static C functions:
|
||||
```c++
|
||||
double sinc(double x, void* /*params*/) {
|
||||
return 10.0*sin(x)/x;
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
JKQTPxFunctionLineGraph* func5=new JKQTPxFunctionLineGraph(plot);
|
||||
func5->set_plotFunction(&sinc);
|
||||
func5->set_title("static C function $10*\\sin(x)/x$");
|
||||
plot->addGraph(func5);
|
||||
```
|
||||
|
||||
Finally `JKQTPxFunctionLineGraph` provides a small set of special functions (polynomial, exponential, ...), which draw their parameters from the internal or external parameters:
|
||||
```c++
|
||||
JKQTPxFunctionLineGraph* func6=new JKQTPxFunctionLineGraph(plot);
|
||||
func6->setSpecialFunction(JKQTPxFunctionLineGraph::Line);
|
||||
// here we set offset and slope of the line
|
||||
func6->set_paramsV(-1,1.5);
|
||||
func6->set_title("special function: linear");
|
||||
plot->addGraph(func6);
|
||||
```
|
||||
|
||||
|
||||
|
||||
This code snippets above result in a plot like this:
|
||||
|
||||
![jkqtplotter_simpletest_functionplot](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_functionplot.png)
|
||||
|
||||
|
||||
[Back to JKQTPlotter main page](https://github.com/jkriege2/JKQtPlotter/)
|
@ -0,0 +1,105 @@
|
||||
#include <QApplication>
|
||||
#include <QVector>
|
||||
#include <QMap>
|
||||
#include "jkqtplotter/jkqtplotter.h"
|
||||
#include "jkqtplotter/jkqtpgraphsevaluatedfunction.h"
|
||||
|
||||
double sinc(double x, void* params) {
|
||||
return 10.0*sin(x)/x;
|
||||
}
|
||||
|
||||
struct SincSqr {
|
||||
public:
|
||||
inline SincSqr(double amplitude): a(amplitude) {}
|
||||
inline double operator()(double x, void* params) {
|
||||
return a*sin(x)*sin(x)/x/x;
|
||||
}
|
||||
private:
|
||||
double a;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
// 1. create a window that conatins a line-edit to edit a function
|
||||
// and a JKQtPlotter to display the function, combine everything in a layout
|
||||
QWidget mainWin;
|
||||
JKQtPlotter* plot=new JKQtPlotter(&mainWin);
|
||||
QVBoxLayout* layout=new QVBoxLayout;
|
||||
mainWin.setLayout(layout);
|
||||
layout->addWidget(plot);
|
||||
|
||||
// 2. now we add a JKQTPxFunctionLineGraph object, which will draw a simple function
|
||||
// the function is defined as C++ inline function
|
||||
JKQTPxFunctionLineGraph* func1=new JKQTPxFunctionLineGraph(plot);
|
||||
func1->set_plotFunction([](double x, void* /*params*/) { return 0.2*x*x-0.015*x*x*x; });
|
||||
func1->set_title("C++-inline function $0.2x^2-0.015x^3$");
|
||||
plot->addGraph(func1);
|
||||
|
||||
// 3. now we add a JKQTPxFunctionLineGraph object, which will draw a simple function
|
||||
// the function is again defined as C++ inline function, but now uses internal
|
||||
// parameters (handed over to the function as a pointer to QVector<double>
|
||||
JKQTPxFunctionLineGraph* func2=new JKQTPxFunctionLineGraph(plot);
|
||||
func2->set_plotFunction([](double x, void* params) {
|
||||
QVector<double>* p=static_cast<QVector<double>*>(params);
|
||||
return p->at(0)*sin(2.0*M_PI*x*p->at(1));
|
||||
});
|
||||
// here we set the parameters p0, p1
|
||||
func2->set_paramsV(5, 0.2);
|
||||
func2->set_title("C++-inline function with int. params $p_0\\cdot\\sin(x*2.0*\\pi\\cdot p_1)$");
|
||||
plot->addGraph(func2);
|
||||
|
||||
// 4. now we add a JKQTPxFunctionLineGraph object, which will draw a simple function
|
||||
// the function is again defined as C++ inline function, but now uses external
|
||||
// parameters, which may have any type (here QMap<QString,double)
|
||||
JKQTPxFunctionLineGraph* func3=new JKQTPxFunctionLineGraph(plot);
|
||||
func3->set_plotFunction([](double x, void* params) {
|
||||
QMap<QString,double>* p=static_cast<QMap<QString,double>*>(params);
|
||||
return p->value("amplitude")*sin(2.0*M_PI*x*p->value("frequency"));
|
||||
});
|
||||
// here we set the parameters p0, p1
|
||||
QMap<QString,double> params3;
|
||||
params3["amplitude"]=-3;
|
||||
params3["frequency"]=0.3;
|
||||
func3->set_params(¶ms3);
|
||||
func3->set_title("C++-inline function with ext. params $p_0\\cdot\\sin(x*2.0*\\pi\\cdot p_1)$");
|
||||
plot->addGraph(func3);
|
||||
|
||||
// 5. of course the function may also be any C+ funtor object:
|
||||
JKQTPxFunctionLineGraph* func4=new JKQTPxFunctionLineGraph(plot);
|
||||
func4->set_plotFunction(SincSqr(-8));
|
||||
func4->set_title("C++ functor $-8*\\sin^2(x)/x^2$");
|
||||
plot->addGraph(func4);
|
||||
|
||||
|
||||
// 6. now we use a JKQTPxFunctionLineGraph to draw a static C function
|
||||
JKQTPxFunctionLineGraph* func5=new JKQTPxFunctionLineGraph(plot);
|
||||
func5->set_plotFunction(&sinc);
|
||||
func5->set_title("static C function $10*\\sin(x)/x$");
|
||||
plot->addGraph(func5);
|
||||
|
||||
// 6. finally JKQTPxFunctionLineGraph defines a small set of common functions
|
||||
JKQTPxFunctionLineGraph* func6=new JKQTPxFunctionLineGraph(plot);
|
||||
func6->setSpecialFunction(JKQTPxFunctionLineGraph::Line);
|
||||
// here we set offset and slope of the line
|
||||
func6->set_paramsV(-1,1.5);
|
||||
func6->set_title("special function: linear");
|
||||
plot->addGraph(func6);
|
||||
|
||||
|
||||
// 8. set some axis properties (we use LaTeX for nice equation rendering)
|
||||
plot->getXAxis()->set_axisLabel(QObject::tr("x-axis"));
|
||||
plot->getYAxis()->set_axisLabel(QObject::tr("y-axis"));
|
||||
plot->get_plotter()->set_keyPosition(JKQTPkeyOutsideBottomLeft);
|
||||
|
||||
|
||||
// 4. scale the plot so the graph is contained
|
||||
plot->setXY(-10,10,-10,10);
|
||||
|
||||
// show window and make it a decent size
|
||||
mainWin.show();
|
||||
mainWin.resize(800,800);
|
||||
|
||||
return app.exec();
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
# source code for this simple demo
|
||||
SOURCES = jkqtplotter_simpletest_functionplot.cpp
|
||||
|
||||
# configure Qt
|
||||
CONFIG += qt
|
||||
QT += core gui xml svg
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport
|
||||
|
||||
# output executable name
|
||||
TARGET = jkqtplotter_simpletest_functionplot
|
||||
|
||||
|
||||
# include JKQtPlotter source code
|
||||
DEPENDPATH += . ../../lib
|
||||
INCLUDEPATH += ../../lib
|
||||
CONFIG (debug, debug|release):LIBS += -L../../lib/debug -ljkqtplotterlib
|
||||
CONFIG (release):LIBS += -L../../lib/release -ljkqtplotterlib
|
||||
|
||||
win32-msvc*: DEFINES += _USE_MATH_DEFINES
|
||||
|
||||
# here you can activate some debug options
|
||||
#DEFINES += SHOW_JKQTPLOTTER_DEBUG
|
||||
#DEFINES += JKQTBP_AUTOTIMER
|
@ -0,0 +1,8 @@
|
||||
TEMPLATE = subdirs
|
||||
|
||||
SUBDIRS += jkqtplotterlib jkqtplotter_simpletest_functionplot
|
||||
|
||||
jkqtplotterlib.file = ../../lib/jkqtplotterlib.pro
|
||||
|
||||
jkqtplotter_simpletest_functionplot.file=$$PWD/jkqtplotter_simpletest_functionplot.pro
|
||||
jkqtplotter_simpletest_functionplot.depends = jkqtplotterlib
|
53
test/simpletest_parsedfunctionplot/README.md
Normal file
53
test/simpletest_parsedfunctionplot/README.md
Normal file
@ -0,0 +1,53 @@
|
||||
[Back to JKQTPlotter main page](https://github.com/jkriege2/JKQtPlotter/)
|
||||
|
||||
# JKQtPlotter
|
||||
|
||||
## Plotting Parsed Mathematical Functions as Line Graphs
|
||||
This project (see `./test/simpletest_parsedfunctionplot/`) demonstrates how to plot mathematical functions as line graphs. The functions are defined as strings that will be evaluated with the equation parser, integrated into JKQtPlotter.
|
||||
|
||||
Adding an evaluated funtion to a graph is very simple:
|
||||
```c++
|
||||
JKQTPxParsedFunctionLineGraph* parsedFunc=new JKQTPxParsedFunctionLineGraph(plot);
|
||||
parsedFunc->set_function("sin(x*8)*exp(-x/4)");
|
||||
parsedFunc->set_title("user function");
|
||||
```
|
||||
As you can see a graph of the type `JKQTPxParsedFunctionLineGraph` is used, which plots a function that depends on the variable `x`. The given function is parsed and evaluated (see [`lib/jkqtplottertools/jkqtpmathparser.h`](https://github.com/jkriege2/JKQtPlotter/blob/master/lib/jkqtplottertools/jkqtpmathparser.h) for details on the features of the math parser). An intelligent drawing algorithm chooses the number of control points for drawing a smooth graph, with sufficient amount of details, by evaluating locally the slope of the function.
|
||||
|
||||
In the example in [`test/simpletest_parsedfunctionplot/simpletest_parsedfunctionplot.cpp`](https://github.com/jkriege2/JKQtPlotter/blob/master/test/simpletest_parsedfunctionplot/simpletest_parsedfunctionplot.cpp) we do not simply set a fixed function, but add a `QLineEdit` which allows to edit the function and redraws it, once ENTER is pressed:
|
||||
```c++
|
||||
JKQtPlotter* plot=new JKQtPlotter(&mainWin);
|
||||
QLineEdit* edit=new QLineEdit(&mainWin);
|
||||
edit->setToolTip("enter a function in dependence of the variable <tt>x</tt> and press ENTER to update the graph");
|
||||
|
||||
// ...
|
||||
|
||||
|
||||
// 2. now we add a JKQTPxParsedFunctionLineGraph object, which will draw the function from
|
||||
// the line edit
|
||||
JKQTPxParsedFunctionLineGraph* parsedFunc=new JKQTPxParsedFunctionLineGraph(plot);
|
||||
plot->addGraph(parsedFunc);
|
||||
// finally we connect the line edit with the graph, whenever RETURN is pressed,
|
||||
// the graph is updated:
|
||||
auto updateGraphFunctor=
|
||||
[=]() {
|
||||
parsedFunc->set_title("user function: \\verb{"+edit->text()+"}");
|
||||
parsedFunc->set_function(edit->text());
|
||||
plot->update_plot();
|
||||
};
|
||||
QObject::connect(edit, &QLineEdit::returnPressed, updateGraphFunctor);
|
||||
QObject::connect(edit, &QLineEdit::editingFinished, updateGraphFunctor);
|
||||
edit->setText("sin(x*8)*exp(-x/4)");
|
||||
updateGraphFunctor();
|
||||
```
|
||||
|
||||
|
||||
This code snippet results in a plot like this:
|
||||
|
||||
![jkqtplotter_simpletest_parsedfunctionplot](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_parsedfunctionplot.png)
|
||||
|
||||
the adaptive capabilities of the rendering algorithm can be seen, when plotting e.g. `2/x`, which is drawn smoothely, even around the undefined value at `x=0`:
|
||||
|
||||
![jkqtplotter_simpletest_parsedfunctionplot_2overx.png](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_parsedfunctionplot_2overx.png.png)
|
||||
|
||||
|
||||
[Back to JKQTPlotter main page](https://github.com/jkriege2/JKQtPlotter/)
|
@ -0,0 +1,54 @@
|
||||
#include <QApplication>
|
||||
#include <QLineEdit>
|
||||
#include "jkqtplotter/jkqtplotter.h"
|
||||
#include "jkqtplotter/jkqtpgraphsparsedfunction.h"
|
||||
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
// 1. create a window that conatins a line-edit to edit a function
|
||||
// and a JKQtPlotter to display the function, combine everything in a layout
|
||||
QWidget mainWin;
|
||||
QLineEdit* edit=new QLineEdit(&mainWin);
|
||||
edit->setToolTip("enter a function in dependence of the variable <tt>x</tt> and press ENTER to update the graph");
|
||||
JKQtPlotter* plot=new JKQtPlotter(&mainWin);
|
||||
QVBoxLayout* layout=new QVBoxLayout;
|
||||
mainWin.setLayout(layout);
|
||||
layout->addWidget(edit);
|
||||
layout->addWidget(plot);
|
||||
|
||||
// 2. now we add a JKQTPxParsedFunctionLineGraph object, which will draw the function from
|
||||
// the line edit
|
||||
JKQTPxParsedFunctionLineGraph* parsedFunc=new JKQTPxParsedFunctionLineGraph(plot);
|
||||
plot->addGraph(parsedFunc);
|
||||
// finally we connect the line edit with the graph, whenever RETURN is pressed,
|
||||
// the graph is updated:
|
||||
auto updateGraphFunctor=
|
||||
[=]() {
|
||||
parsedFunc->set_title("user function: \\verb{"+edit->text()+"}");
|
||||
parsedFunc->set_function(edit->text());
|
||||
plot->update_plot();
|
||||
};
|
||||
QObject::connect(edit, &QLineEdit::returnPressed, updateGraphFunctor);
|
||||
QObject::connect(edit, &QLineEdit::editingFinished, updateGraphFunctor);
|
||||
edit->setText("sin(x*8)*exp(-x/4)");
|
||||
updateGraphFunctor();
|
||||
|
||||
|
||||
// 3. set some axis properties (we use LaTeX for nice equation rendering)
|
||||
plot->getXAxis()->set_axisLabel(QObject::tr("x-axis"));
|
||||
plot->getYAxis()->set_axisLabel(QObject::tr("y-axis"));
|
||||
|
||||
|
||||
// 4. scale the plot so the graph is contained
|
||||
plot->setXY(-10,10,-10,10);
|
||||
|
||||
// show window and make it a decent size
|
||||
mainWin.show();
|
||||
mainWin.resize(600,400);
|
||||
|
||||
return app.exec();
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
# source code for this simple demo
|
||||
SOURCES = jkqtplotter_simpletest_parsedfunctionplot.cpp
|
||||
|
||||
# configure Qt
|
||||
CONFIG += qt
|
||||
QT += core gui xml svg
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport
|
||||
|
||||
# output executable name
|
||||
TARGET = jkqtplotter_simpletest_parsedfunctionplot
|
||||
|
||||
|
||||
# include JKQtPlotter source code
|
||||
DEPENDPATH += . ../../lib
|
||||
INCLUDEPATH += ../../lib
|
||||
CONFIG (debug, debug|release):LIBS += -L../../lib/debug -ljkqtplotterlib
|
||||
CONFIG (release):LIBS += -L../../lib/release -ljkqtplotterlib
|
||||
|
||||
win32-msvc*: DEFINES += _USE_MATH_DEFINES
|
||||
|
||||
# here you can activate some debug options
|
||||
#DEFINES += SHOW_JKQTPLOTTER_DEBUG
|
||||
#DEFINES += JKQTBP_AUTOTIMER
|
@ -0,0 +1,8 @@
|
||||
TEMPLATE = subdirs
|
||||
|
||||
SUBDIRS += jkqtplotterlib jkqtplotter_simpletest_parsedfunctionplot
|
||||
|
||||
jkqtplotterlib.file = ../../lib/jkqtplotterlib.pro
|
||||
|
||||
jkqtplotter_simpletest_parsedfunctionplot.file=$$PWD/jkqtplotter_simpletest_parsedfunctionplot.pro
|
||||
jkqtplotter_simpletest_parsedfunctionplot.depends = jkqtplotterlib
|
Loading…
Reference in New Issue
Block a user