2019-01-20 23:15:10 +08:00
# Example (JKQTPlotter): Plotting Mathematical Functions as Line Graphs {#JKQTPlotterFunctionPlots}
2019-01-13 01:53:16 +08:00
## Basics
2019-01-20 23:15:10 +08:00
This project (see `./examples/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 ](../simpletest_parsedfunctionplot ) for an example of how to use an internal equation parser provided with JKQTPlotter instead of directly defining functions.
2018-12-24 03:27:24 +08:00
2019-01-13 01:53:16 +08:00
## Simple C++ inline function
2018-12-24 03:27:24 +08:00
The first example shows how to plot a C++ inline function:
2019-01-19 16:40:52 +08:00
```.cpp
2019-01-20 17:49:29 +08:00
JKQTPXFunctionLineGraph* func1=new JKQTPXFunctionLineGraph(plot);
2019-01-26 03:16:04 +08:00
func1->setPlotFunction([](double x) { return 0.2*x*x-0.015*x*x*x; });
2019-01-26 20:00:40 +08:00
func1->setTitle("C++-inline function $0.2x^2-0.015x^3$");
2018-12-24 03:27:24 +08:00
plot->addGraph(func1);
```
2019-01-13 01:53:16 +08:00
## Simple C++ inline function with parameters
2019-01-26 20:00:40 +08:00
In any such plot function, you can also use parameters, provided via the second parameter. Usually these are "internal parameters", defined by `func2->setParamsV(p0, p1, ...)` :
2019-01-19 16:40:52 +08:00
```.cpp
2019-01-20 17:49:29 +08:00
JKQTPXFunctionLineGraph* func2=new JKQTPXFunctionLineGraph(plot);
2019-01-26 03:16:04 +08:00
func2->setPlotFunction([](double x, void* params) {
2018-12-24 03:27:24 +08:00
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
2019-01-26 20:00:40 +08:00
func2->setParamsV(5, 0.2);
func2->setTitle("C++-inline function with int. params $p_0\\cdot\\sin(x*2.0*\\pi\\cdot p_1)$");
2018-12-24 03:27:24 +08:00
plot->addGraph(func2);
```
2019-01-26 20:00:40 +08:00
... but generally any pointer can be used as parameter (the set by `setParameter(static_cast<void*>(myDataObject))` ):
2019-01-19 16:40:52 +08:00
```.cpp
2019-01-20 17:49:29 +08:00
JKQTPXFunctionLineGraph* func3=new JKQTPXFunctionLineGraph(plot);
2019-01-26 03:16:04 +08:00
func3->setPlotFunction([](double x, void* params) {
2018-12-24 03:27:24 +08:00
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;
2019-01-26 20:00:40 +08:00
func3->setParams(¶ms3);
func3->setTitle("C++-inline function with ext. params $p_0\\cdot\\sin(x*2.0*\\pi\\cdot p_1)$");
2018-12-24 03:27:24 +08:00
plot->addGraph(func3);
```
2019-01-13 01:53:16 +08:00
## C++ functors as plot functions
2018-12-24 03:27:24 +08:00
You can also use C++ functors (or function objects):
2019-01-19 16:40:52 +08:00
```.cpp
2018-12-24 03:28:38 +08:00
struct SincSqr {
public:
inline SincSqr(double amplitude): a(amplitude) {}
2018-12-24 19:29:33 +08:00
inline double operator()(double x) {
2018-12-24 03:28:38 +08:00
return a*sin(x)*sin(x)/x/x;
}
private:
double a;
};
// ...
2019-01-20 17:49:29 +08:00
JKQTPXFunctionLineGraph* func4=new JKQTPXFunctionLineGraph(plot);
2019-01-26 03:16:04 +08:00
func4->setPlotFunction(SincSqr(-8));
2019-01-26 20:00:40 +08:00
func4->setTitle("C++ functor $-8*\\sin^2(x)/x^2$");
2018-12-24 03:27:24 +08:00
plot->addGraph(func4);
```
2019-01-13 01:53:16 +08:00
## Static C functions
2018-12-24 22:07:14 +08:00
You can also plot simple static C functions:
2019-01-19 16:40:52 +08:00
```.cpp
2018-12-24 19:29:33 +08:00
double sinc(double x) {
2018-12-24 03:28:38 +08:00
return 10.0*sin(x)/x;
}
// ...
2018-12-24 03:27:24 +08:00
2019-01-20 17:49:29 +08:00
JKQTPXFunctionLineGraph* func5=new JKQTPXFunctionLineGraph(plot);
2019-01-26 03:16:04 +08:00
func5->setPlotFunction(&sinc);
2019-01-26 20:00:40 +08:00
func5->setTitle("static C function $10*\\sin(x)/x$");
2018-12-24 03:27:24 +08:00
plot->addGraph(func5);
```
2019-01-13 01:53:16 +08:00
## Predefined "special" functions
2019-01-20 17:49:29 +08:00
Finally `JKQTPXFunctionLineGraph` provides a small set of special functions (polynomial `p0+p1*x+p2*x^2+...` , exponential `p0+p1*exp(x/p2)` , power-law `p0+p1*x^p2` , ...), which are parametrized from the internal or external parameters:
2019-01-19 16:40:52 +08:00
```.cpp
2019-01-20 17:49:29 +08:00
JKQTPXFunctionLineGraph* func6=new JKQTPXFunctionLineGraph(plot);
func6->setSpecialFunction(JKQTPXFunctionLineGraph::Line);
2018-12-24 22:07:14 +08:00
// here we set offset p0=-1 and slope p1=1.5 of the line p0+p1*x
2019-01-26 20:00:40 +08:00
func6->setParamsV(-1,1.5);
func6->setTitle("special function: linear");
2018-12-24 03:27:24 +08:00
plot->addGraph(func6);
```
2018-12-24 22:07:14 +08:00
To demonstrate how to use parameters from a datastore column, have a look at the next example. It is derived from the special-function plot above, but adds a line with a different offset and slope and reads the parameters from a datastore column `paramCol` , which is initialized from the vector `params` :
2019-01-19 16:40:52 +08:00
```.cpp
2019-01-20 17:49:29 +08:00
JKQTPXFunctionLineGraph* func7=new JKQTPXFunctionLineGraph(plot);
func7->setSpecialFunction(JKQTPXFunctionLineGraph::Line);
2018-12-24 22:07:14 +08:00
// here we set offset p0=1 and slope p1=-1.5 of the line p0+p1*x by adding these into a column
// in the internal datastore and then set that column as parameterColumn for the function graph
QVector< double > params;
params < < /*p0=*/1 < < /*p1=*/-1.5;
size_t paramCol=plot->getDatastore()->addCopiedColumn(params);
2019-01-26 20:00:40 +08:00
func7->setParameterColumn(paramCol);
func7->setTitle("special function: linear");
2018-12-24 22:07:14 +08:00
plot->addGraph(func7);
```
2018-12-24 03:27:24 +08:00
2019-01-13 01:53:16 +08:00
## Screenshot
2018-12-24 03:27:24 +08:00
This code snippets above result in a plot like this:
2019-01-12 20:43:12 +08:00
![jkqtplotter_simpletest_functionplot ](../../screenshots/jkqtplotter_simpletest_functionplot.png )
2018-12-24 03:27:24 +08:00
2019-01-13 01:53:16 +08:00
## Notes
2018-12-24 22:07:14 +08:00
Note that all the different variants to provide parameters can be used with all types of functions!
2019-01-20 23:15:10 +08:00
Also see the example [Plotting Parsed Mathematical Functions as Line Graphs ](../simpletest_parsedfunctionplot ) for details on how the actual plotting algorithm works. That example also shows how to define a function as a string, which is then parsed and evaluated by an expression parser library embedded in JKQTPlotter.
2018-12-24 22:07:14 +08:00
2019-01-20 17:49:29 +08:00
All examples above use the graph class `JKQTPXFunctionLineGraph` , which plots a function `y=f(x)` . If you want to plot a function `x=f(y)` , you can use the class `JKQTPYFunctionLineGraph` instead. If in the examples above, we exchange all `JKQTPXFunctionLineGraph` for `JKQTPYFunctionLineGraph` , the graphs will be rotated by 90 degree, as all functions are interpreted as `x=f(y)` :
2018-12-24 22:07:14 +08:00
2019-01-12 20:43:12 +08:00
![jkqtplotter_simpletest_functionplot_fy ](../../screenshots/jkqtplotter_simpletest_functionplot_fy.png )
2018-12-24 22:07:14 +08:00
2018-12-24 03:27:24 +08:00