mirror of
https://github.com/jkriege2/JKQtPlotter.git
synced 2024-12-24 09:31:40 +08:00
tidied up code of parsed function graphs, added f(y) parsed function class (JKQTPyParsedFunctionLineGraph), improved examples
This commit is contained in:
parent
94acc1b7d5
commit
d70c6cf377
@ -711,8 +711,9 @@ void JKQTPyFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
|
||||
}
|
||||
|
||||
|
||||
void JKQTPyFunctionLineGraph::createPlotData(bool /*collectParams*/) {
|
||||
void JKQTPyFunctionLineGraph::createPlotData(bool collectParams) {
|
||||
clearData();
|
||||
if (collectParams) collectParameters();
|
||||
|
||||
if (parent==nullptr) return;
|
||||
if (!plotFunction && !simplePlotFunction) return;
|
||||
|
@ -17,8 +17,6 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "jkqtplotter/jkqtpgraphsparsedfunction.h"
|
||||
#include "jkqtplotter/jkqtpgraphs.h"
|
||||
#include "jkqtplotter/jkqtpbaseplotter.h"
|
||||
@ -29,32 +27,6 @@
|
||||
#include <utility>
|
||||
|
||||
|
||||
double JKQTPxParsedFunctionLineGraphFunction(double x, void* data) {
|
||||
JKQTPxParsedFunctionLineGraph::JKQTPxParsedFunctionLineGraphFunctionData* d=(JKQTPxParsedFunctionLineGraph::JKQTPxParsedFunctionLineGraphFunctionData*)data;
|
||||
if (d && d->parser && d->node) {
|
||||
try {
|
||||
d->parser->addVariableDouble("x", x);
|
||||
JKQTPMathParser::jkmpResult r=d->node->evaluate();
|
||||
|
||||
if (r.isValid) {
|
||||
if (r.type==JKQTPMathParser::jkmpBool) {
|
||||
return r.boolean?1.0:0.0;
|
||||
} else if (r.type==JKQTPMathParser::jkmpDouble) {
|
||||
return r.num;
|
||||
}
|
||||
}
|
||||
} catch(std::exception& /*E*/) {
|
||||
//qDebug()<<QString("parser error: %1").arg(E.what());
|
||||
/*ok= QMessageBox::critical(this, tr("QuickFit-table"),
|
||||
tr("An error occured while parsing the expression '%1' in cell (row, column)=(%3, %4):\n%2\n\n\"OK\" will still go on evaluating\n\"Cancel\" will cancel evaluation for the rest of the cells.").arg(dlgMathExpression->getExpression()).arg(E.what()).arg(row).arg(column),
|
||||
QMessageBox::Ok|QMessageBox::Cancel, QMessageBox::Ok)==QMessageBox::Ok;*/
|
||||
|
||||
}
|
||||
}
|
||||
return NAN;
|
||||
|
||||
}
|
||||
|
||||
JKQTPxParsedFunctionLineGraph::JKQTPxParsedFunctionLineGraph(JKQtBasePlotter *parent):
|
||||
JKQTPxFunctionLineGraph(parent)
|
||||
{
|
||||
@ -64,7 +36,7 @@ JKQTPxParsedFunctionLineGraph::JKQTPxParsedFunctionLineGraph(JKQtBasePlotter *pa
|
||||
function="";
|
||||
parameterColumn=-1;
|
||||
set_params(&fdata);
|
||||
set_plotFunction(JKQTPxParsedFunctionLineGraphFunction);
|
||||
set_plotFunction(&JKQTPxParsedFunctionLineGraph::JKQTPxParsedFunctionLineGraphFunction);
|
||||
|
||||
efdata.parser=new JKQTPMathParser();
|
||||
efdata.node=nullptr;
|
||||
@ -72,7 +44,7 @@ JKQTPxParsedFunctionLineGraph::JKQTPxParsedFunctionLineGraph(JKQtBasePlotter *pa
|
||||
errorFunction="";
|
||||
errorParameterColumn=-1;
|
||||
set_errorParams(&efdata);
|
||||
set_errorPlotFunction(JKQTPxParsedFunctionLineGraphFunction);
|
||||
set_errorPlotFunction(&JKQTPxParsedFunctionLineGraph::JKQTPxParsedFunctionLineGraphFunction);
|
||||
}
|
||||
|
||||
JKQTPxParsedFunctionLineGraph::JKQTPxParsedFunctionLineGraph(JKQtPlotter *parent):
|
||||
@ -84,7 +56,7 @@ JKQTPxParsedFunctionLineGraph::JKQTPxParsedFunctionLineGraph(JKQtPlotter *parent
|
||||
function="";
|
||||
parameterColumn=-1;
|
||||
set_params(&fdata);
|
||||
set_plotFunction(JKQTPxParsedFunctionLineGraphFunction);
|
||||
set_plotFunction(&JKQTPxParsedFunctionLineGraph::JKQTPxParsedFunctionLineGraphFunction);
|
||||
|
||||
efdata.parser=new JKQTPMathParser();
|
||||
efdata.node=nullptr;
|
||||
@ -92,8 +64,9 @@ JKQTPxParsedFunctionLineGraph::JKQTPxParsedFunctionLineGraph(JKQtPlotter *parent
|
||||
errorFunction="";
|
||||
errorParameterColumn=-1;
|
||||
set_errorParams(&efdata);
|
||||
set_errorPlotFunction(JKQTPxParsedFunctionLineGraphFunction);
|
||||
set_errorPlotFunction(&JKQTPxParsedFunctionLineGraph::JKQTPxParsedFunctionLineGraphFunction);
|
||||
}
|
||||
|
||||
JKQTPxParsedFunctionLineGraph::~JKQTPxParsedFunctionLineGraph()
|
||||
{
|
||||
if (fdata.node) delete fdata.node;
|
||||
@ -102,13 +75,6 @@ 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*/)
|
||||
{
|
||||
@ -121,23 +87,13 @@ void JKQTPxParsedFunctionLineGraph::createPlotData(bool /*collectParams*/)
|
||||
}
|
||||
fdata.varcount=0;
|
||||
try {
|
||||
if (parent && parameterColumn>=0) {
|
||||
|
||||
JKQTPdatastore* datastore=parent->getDatastore();
|
||||
int imin=0;
|
||||
int imax=datastore->getColumn(parameterColumn).getRows();
|
||||
|
||||
for (int i=imin; i<imax; i++) {
|
||||
double xv=datastore->get(parameterColumn,i);
|
||||
fdata.parser->addVariableDouble(std::string("p")+jkqtp_inttostr(fdata.varcount+1), xv);
|
||||
QVector<double>* parameters=static_cast<QVector<double>*>(params);
|
||||
if (parameters) {
|
||||
for (int i=0; i<parameters->size(); i++) {
|
||||
fdata.parser->addVariableDouble(std::string("p")+jkqtp_inttostr(fdata.varcount+1), parameters->at(i));
|
||||
fdata.varcount=fdata.varcount+1;
|
||||
|
||||
}
|
||||
}
|
||||
for (int i=0; i<parameters.size(); i++) {
|
||||
fdata.parser->addVariableDouble(std::string("p")+jkqtp_inttostr(fdata.varcount+1), parameters[i]);
|
||||
fdata.varcount=fdata.varcount+1;
|
||||
}
|
||||
fdata.parser->addVariableDouble(std::string("x"), 0.0);
|
||||
if (fdata.node) delete fdata.node;
|
||||
//qint64 t=timer.elapsed();
|
||||
@ -156,23 +112,13 @@ void JKQTPxParsedFunctionLineGraph::createPlotData(bool /*collectParams*/)
|
||||
}
|
||||
efdata.varcount=0;
|
||||
try {
|
||||
if (parent && errorParameterColumn>=0) {
|
||||
|
||||
JKQTPdatastore* datastore=parent->getDatastore();
|
||||
int imin=0;
|
||||
int imax=datastore->getColumn(errorParameterColumn).getRows();
|
||||
|
||||
for (int i=imin; i<imax; i++) {
|
||||
double xv=datastore->get(errorParameterColumn,i);
|
||||
efdata.parser->addVariableDouble(std::string("p")+jkqtp_inttostr(efdata.varcount+1), xv);
|
||||
QVector<double>* errorParameters=static_cast<QVector<double>*>(errorParams);
|
||||
if (errorParameters) {
|
||||
for (int i=0; i<errorParameters->size(); i++) {
|
||||
efdata.parser->addVariableDouble(std::string("p")+jkqtp_inttostr(efdata.varcount+1), errorParameters->at(i));
|
||||
efdata.varcount=efdata.varcount+1;
|
||||
|
||||
}
|
||||
}
|
||||
for (int i=0; i<errorParameters.size(); i++) {
|
||||
efdata.parser->addVariableDouble(std::string("p")+jkqtp_inttostr(efdata.varcount+1), errorParameters[i]);
|
||||
efdata.varcount=efdata.varcount+1;
|
||||
}
|
||||
efdata.parser->addVariableDouble(std::string("x"), 0.0);
|
||||
if (efdata.node) delete efdata.node;
|
||||
//qint64 t=timer.elapsed();
|
||||
@ -200,3 +146,194 @@ void JKQTPxParsedFunctionLineGraph::createPlotData(bool /*collectParams*/)
|
||||
}
|
||||
qDebug()<<"refined to "<<count<<" daatapoints";*/
|
||||
}
|
||||
|
||||
|
||||
double JKQTPxParsedFunctionLineGraph::JKQTPxParsedFunctionLineGraphFunction(double x, void* data) {
|
||||
JKQTPxParsedFunctionLineGraph::JKQTPxParsedFunctionLineGraphFunctionData* d=(JKQTPxParsedFunctionLineGraph::JKQTPxParsedFunctionLineGraphFunctionData*)data;
|
||||
if (d && d->parser && d->node) {
|
||||
try {
|
||||
d->parser->addVariableDouble("x", x);
|
||||
JKQTPMathParser::jkmpResult r=d->node->evaluate();
|
||||
|
||||
if (r.isValid) {
|
||||
if (r.type==JKQTPMathParser::jkmpBool) {
|
||||
return r.boolean?1.0:0.0;
|
||||
} else if (r.type==JKQTPMathParser::jkmpDouble) {
|
||||
return r.num;
|
||||
}
|
||||
}
|
||||
} catch(std::exception& /*E*/) {
|
||||
//qDebug()<<QString("parser error: %1").arg(E.what());
|
||||
/*ok= QMessageBox::critical(this, tr("QuickFit-table"),
|
||||
tr("An error occured while parsing the expression '%1' in cell (row, column)=(%3, %4):\n%2\n\n\"OK\" will still go on evaluating\n\"Cancel\" will cancel evaluation for the rest of the cells.").arg(dlgMathExpression->getExpression()).arg(E.what()).arg(row).arg(column),
|
||||
QMessageBox::Ok|QMessageBox::Cancel, QMessageBox::Ok)==QMessageBox::Ok;*/
|
||||
|
||||
}
|
||||
}
|
||||
return NAN;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
JKQTPyParsedFunctionLineGraph::JKQTPyParsedFunctionLineGraph(JKQtBasePlotter *parent):
|
||||
JKQTPyFunctionLineGraph(parent)
|
||||
{
|
||||
fdata.parser=new JKQTPMathParser();
|
||||
fdata.node=nullptr;
|
||||
fdata.varcount=0;
|
||||
function="";
|
||||
parameterColumn=-1;
|
||||
set_params(&fdata);
|
||||
set_plotFunction(&JKQTPyParsedFunctionLineGraph::JKQTPyParsedFunctionLineGraphFunction);
|
||||
|
||||
efdata.parser=new JKQTPMathParser();
|
||||
efdata.node=nullptr;
|
||||
efdata.varcount=0;
|
||||
errorFunction="";
|
||||
errorParameterColumn=-1;
|
||||
set_errorParams(&efdata);
|
||||
set_errorPlotFunction(&JKQTPyParsedFunctionLineGraph::JKQTPyParsedFunctionLineGraphFunction);
|
||||
}
|
||||
|
||||
JKQTPyParsedFunctionLineGraph::JKQTPyParsedFunctionLineGraph(JKQtPlotter *parent):
|
||||
JKQTPyFunctionLineGraph(parent)
|
||||
{
|
||||
fdata.parser=new JKQTPMathParser();
|
||||
fdata.node=nullptr;
|
||||
fdata.varcount=0;
|
||||
function="";
|
||||
parameterColumn=-1;
|
||||
set_params(&fdata);
|
||||
set_plotFunction(&JKQTPyParsedFunctionLineGraph::JKQTPyParsedFunctionLineGraphFunction);
|
||||
|
||||
efdata.parser=new JKQTPMathParser();
|
||||
efdata.node=nullptr;
|
||||
efdata.varcount=0;
|
||||
errorFunction="";
|
||||
errorParameterColumn=-1;
|
||||
set_errorParams(&efdata);
|
||||
set_errorPlotFunction(&JKQTPyParsedFunctionLineGraph::JKQTPyParsedFunctionLineGraphFunction);
|
||||
}
|
||||
|
||||
JKQTPyParsedFunctionLineGraph::~JKQTPyParsedFunctionLineGraph()
|
||||
{
|
||||
if (fdata.node) delete fdata.node;
|
||||
delete fdata.parser;
|
||||
if (efdata.node) delete efdata.node;
|
||||
delete efdata.parser;
|
||||
}
|
||||
|
||||
void JKQTPyParsedFunctionLineGraph::createPlotData(bool /*collectParams*/)
|
||||
{
|
||||
collectParameters();
|
||||
|
||||
//QElapsedTimer timer;
|
||||
//timer.start();
|
||||
for (int i=0; i<fdata.varcount; i++) {
|
||||
fdata.parser->deleteVariable(std::string("p")+jkqtp_inttostr(i+1));
|
||||
}
|
||||
fdata.varcount=0;
|
||||
try {
|
||||
QVector<double>* parameters=static_cast<QVector<double>*>(params);
|
||||
if (parameters) {
|
||||
for (int i=0; i<parameters->size(); i++) {
|
||||
fdata.parser->addVariableDouble(std::string("p")+jkqtp_inttostr(fdata.varcount+1), parameters->at(i));
|
||||
fdata.varcount=fdata.varcount+1;
|
||||
}
|
||||
}
|
||||
fdata.parser->addVariableDouble(std::string("x"), 0.0);
|
||||
fdata.parser->addVariableDouble(std::string("y"), 0.0);
|
||||
if (fdata.node) delete fdata.node;
|
||||
//qint64 t=timer.elapsed();
|
||||
|
||||
|
||||
//qDebug()<<"createPlotData(): adding variables: "<<t<<"ms";
|
||||
fdata.node=fdata.parser->parse(function.toStdString());
|
||||
//qDebug()<<"createPlotData(): parsing: "<<timer.elapsed()-t<<"ms";
|
||||
} catch(std::exception& /*E*/) {
|
||||
//qDebug()<<QString("parser error: %1").arg(E.what());
|
||||
}
|
||||
|
||||
//qint64 t0=timer.elapsed();
|
||||
for (int i=0; i<efdata.varcount; i++) {
|
||||
efdata.parser->deleteVariable(std::string("p")+jkqtp_inttostr(i+1));
|
||||
}
|
||||
efdata.varcount=0;
|
||||
try {
|
||||
QVector<double>* errorParameters=static_cast<QVector<double>*>(errorParams);
|
||||
if (errorParameters) {
|
||||
for (int i=0; i<errorParameters->size(); i++) {
|
||||
efdata.parser->addVariableDouble(std::string("p")+jkqtp_inttostr(efdata.varcount+1), errorParameters->at(i));
|
||||
efdata.varcount=efdata.varcount+1;
|
||||
}
|
||||
}
|
||||
efdata.parser->addVariableDouble(std::string("x"), 0.0);
|
||||
efdata.parser->addVariableDouble(std::string("y"), 0.0);
|
||||
if (efdata.node) delete efdata.node;
|
||||
//qint64 t=timer.elapsed();
|
||||
//qDebug()<<"createPlotData(): adding variables: "<<t-t0<<"ms";
|
||||
efdata.node=efdata.parser->parse(errorFunction.toStdString());
|
||||
//qDebug()<<"createPlotData(): parsing: "<<timer.elapsed()-t<<"ms";
|
||||
} catch(std::exception& /*E*/) {
|
||||
//qDebug()<<QString("parser error: %1").arg(E.what());
|
||||
}
|
||||
|
||||
set_params(&fdata);
|
||||
set_plotFunction(JKQTPyParsedFunctionLineGraphFunction);
|
||||
set_errorParams(&efdata);
|
||||
set_errorPlotFunction(JKQTPyParsedFunctionLineGraphFunction);
|
||||
|
||||
//qint64 t=timer.elapsed();
|
||||
JKQTPyFunctionLineGraph::createPlotData(false);
|
||||
//qDebug()<<"createPlotData(): JKQTPyFunctionLineGraph::createPlotData(): "<<timer.elapsed()-t<<"ms";
|
||||
|
||||
/*int count=0;
|
||||
doublePair* d=data;
|
||||
while (d!=nullptr) {
|
||||
count++;
|
||||
d=d->next;
|
||||
}
|
||||
qDebug()<<"refined to "<<count<<" daatapoints";*/
|
||||
}
|
||||
|
||||
double JKQTPyParsedFunctionLineGraph::JKQTPyParsedFunctionLineGraphFunction(double x, void* data) {
|
||||
JKQTPyParsedFunctionLineGraph::JKQTPyParsedFunctionLineGraphFunctionData* d=(JKQTPyParsedFunctionLineGraph::JKQTPyParsedFunctionLineGraphFunctionData*)data;
|
||||
if (d && d->parser && d->node) {
|
||||
try {
|
||||
d->parser->addVariableDouble("x", x);
|
||||
d->parser->addVariableDouble("y", x);
|
||||
JKQTPMathParser::jkmpResult r=d->node->evaluate();
|
||||
|
||||
if (r.isValid) {
|
||||
if (r.type==JKQTPMathParser::jkmpBool) {
|
||||
return r.boolean?1.0:0.0;
|
||||
} else if (r.type==JKQTPMathParser::jkmpDouble) {
|
||||
return r.num;
|
||||
}
|
||||
}
|
||||
} catch(std::exception& /*E*/) {
|
||||
//qDebug()<<QString("parser error: %1").arg(E.what());
|
||||
/*ok= QMessageBox::critical(this, tr("QuickFit-table"),
|
||||
tr("An error occured while parsing the expression '%1' in cell (row, column)=(%3, %4):\n%2\n\n\"OK\" will still go on evaluating\n\"Cancel\" will cancel evaluation for the rest of the cells.").arg(dlgMathExpression->getExpression()).arg(E.what()).arg(row).arg(column),
|
||||
QMessageBox::Ok|QMessageBox::Cancel, QMessageBox::Ok)==QMessageBox::Ok;*/
|
||||
|
||||
}
|
||||
}
|
||||
return NAN;
|
||||
|
||||
}
|
||||
|
@ -40,9 +40,11 @@ class JKQtPlotter;
|
||||
|
||||
Additional function parameters may be given in the vector parameters. They are accessible in the function as \c p1 , \c p2 , \c p3 , ...
|
||||
Parameters may also be given from a data column. Then first the params from the column and the the parameters from the vector are numbered.
|
||||
|
||||
Use the variable \c x in an equation to refer to the free parameter of the curve.
|
||||
*/
|
||||
class LIB_EXPORT JKQTPxParsedFunctionLineGraph: public JKQTPxFunctionLineGraph {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
|
||||
@ -55,10 +57,8 @@ class LIB_EXPORT JKQTPxParsedFunctionLineGraph: public JKQTPxFunctionLineGraph {
|
||||
/** \brief class destructor */
|
||||
virtual ~JKQTPxParsedFunctionLineGraph();
|
||||
|
||||
JKQTPGET_SET_MACRO(QList<double>, parameters)
|
||||
JKQTPGET_SET_MACRO(QString, function)
|
||||
|
||||
JKQTPGET_SET_MACRO(QList<double>, errorParameters)
|
||||
JKQTPGET_SET_MACRO(QString, errorFunction)
|
||||
|
||||
/** \brief INTERNAL data structure
|
||||
@ -73,23 +73,81 @@ class LIB_EXPORT JKQTPxParsedFunctionLineGraph: public JKQTPxFunctionLineGraph {
|
||||
protected:
|
||||
/** \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;
|
||||
|
||||
/** \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;
|
||||
|
||||
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)
|
||||
// hide functions that should not be used in this class!
|
||||
using JKQTPxFunctionLineGraph::set_plotFunction;
|
||||
using JKQTPxFunctionLineGraph::set_params;
|
||||
using JKQTPxFunctionLineGraph::set_errorPlotFunction;
|
||||
using JKQTPxFunctionLineGraph::set_errorParams;
|
||||
|
||||
/** \brief fill the data array with data from the function plotFunction */
|
||||
virtual void createPlotData(bool collectParams=true);
|
||||
|
||||
/** \brief implements the actual plot function */
|
||||
static double JKQTPxParsedFunctionLineGraphFunction(double x, void *data);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \brief This implements line plots where the data is taken from a user supplied function \f$ x=f(y) \f$ The function is defined as a string and parsed by JKMathParser
|
||||
\ingroup jkqtplotter_plots
|
||||
|
||||
Additional function parameters may be given in the vector parameters. They are accessible in the function as \c p1 , \c p2 , \c p3 , ...
|
||||
Parameters may also be given from a data column. Then first the params from the column and the the parameters from the vector are numbered.
|
||||
|
||||
Use the variable \c y in an equation to refer to the free parameter of the curve (\c is also understood for convenience).
|
||||
*/
|
||||
class LIB_EXPORT JKQTPyParsedFunctionLineGraph: public JKQTPyFunctionLineGraph {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
|
||||
/** \brief class constructor */
|
||||
JKQTPyParsedFunctionLineGraph(JKQtBasePlotter* parent=nullptr);
|
||||
/** \brief class constructor */
|
||||
JKQTPyParsedFunctionLineGraph(JKQtPlotter* parent);
|
||||
|
||||
|
||||
/** \brief class destructor */
|
||||
virtual ~JKQTPyParsedFunctionLineGraph();
|
||||
|
||||
JKQTPGET_SET_MACRO(QString, function)
|
||||
|
||||
JKQTPGET_SET_MACRO(QString, errorFunction)
|
||||
|
||||
/** \brief INTERNAL data structure
|
||||
* \internal
|
||||
*/
|
||||
struct JKQTPyParsedFunctionLineGraphFunctionData {
|
||||
JKQTPMathParser* parser;
|
||||
JKQTPMathParser::jkmpNode* node;
|
||||
int varcount;
|
||||
};
|
||||
|
||||
protected:
|
||||
/** \brief the function to be evaluated for the plot. Use \c x as the free variable, e.g. \c "x^2+2" */
|
||||
QString function;
|
||||
JKQTPyParsedFunctionLineGraphFunctionData fdata;
|
||||
|
||||
/** \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;
|
||||
JKQTPyParsedFunctionLineGraphFunctionData efdata;
|
||||
|
||||
// hide functions that should not be used in this class!
|
||||
using JKQTPxFunctionLineGraph::set_plotFunction;
|
||||
using JKQTPxFunctionLineGraph::set_params;
|
||||
using JKQTPxFunctionLineGraph::set_errorPlotFunction;
|
||||
using JKQTPxFunctionLineGraph::set_errorParams;
|
||||
|
||||
/** \brief fill the data array with data from the function plotFunction */
|
||||
virtual void createPlotData(bool collectParams=true);
|
||||
/** \brief implements the actual plot function */
|
||||
static double JKQTPyParsedFunctionLineGraphFunction(double x, void *data);
|
||||
};
|
||||
#endif // jkqtpgraphsparsedfunction_H
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 96 KiB |
BIN
screenshots/jkqtplotter_simpletest_functionplot_fy.png
Normal file
BIN
screenshots/jkqtplotter_simpletest_functionplot_fy.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 101 KiB |
BIN
screenshots/jkqtplotter_simpletest_parsedfunctionplot_fy.png
Normal file
BIN
screenshots/jkqtplotter_simpletest_parsedfunctionplot_fy.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
@ -1,8 +1,8 @@
|
||||
TEMPLATE = subdirs
|
||||
|
||||
SUBDIRS += jkqtplotterlib jkqtplot_test
|
||||
|
||||
jkqtplotterlib.file = ../../lib/jkqtplotterlib.pro
|
||||
|
||||
jkqtplot_test.file=$$PWD/jkqtplot_test.pro
|
||||
jkqtplot_test.depends = jkqtplotterlib
|
||||
TEMPLATE = subdirs
|
||||
|
||||
SUBDIRS += jkqtplotterlib jkqtplot_test
|
||||
|
||||
jkqtplotterlib.file = ../../lib/jkqtplotterlib.pro
|
||||
|
||||
jkqtplot_test.file=$$PWD/jkqtplot_test.pro
|
||||
jkqtplot_test.depends = jkqtplotterlib
|
@ -3,8 +3,10 @@
|
||||
# JKQtPlotter
|
||||
|
||||
## Plotting Mathematical Functions as Line Graphs
|
||||
### Basics
|
||||
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.
|
||||
|
||||
### Simple C++ inline function
|
||||
The first example shows how to plot a C++ inline function:
|
||||
```c++
|
||||
JKQTPxFunctionLineGraph* func1=new JKQTPxFunctionLineGraph(plot);
|
||||
@ -13,6 +15,7 @@ The first example shows how to plot a C++ inline function:
|
||||
plot->addGraph(func1);
|
||||
```
|
||||
|
||||
### Simple C++ inline function with parameters
|
||||
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);
|
||||
@ -42,6 +45,7 @@ In any such plot function, you can also use parameters, provided via the second
|
||||
plot->addGraph(func3);
|
||||
```
|
||||
|
||||
### C++ functors as plot functions
|
||||
You can also use C++ functors (or function objects):
|
||||
```c++
|
||||
struct SincSqr {
|
||||
@ -62,7 +66,8 @@ You can also use C++ functors (or function objects):
|
||||
plot->addGraph(func4);
|
||||
```
|
||||
|
||||
... or simple static C functions:
|
||||
### Static C functions
|
||||
You can also plot simple static C functions:
|
||||
```c++
|
||||
double sinc(double x) {
|
||||
return 10.0*sin(x)/x;
|
||||
@ -76,21 +81,44 @@ You can also use C++ functors (or function objects):
|
||||
plot->addGraph(func5);
|
||||
```
|
||||
|
||||
Finally `JKQTPxFunctionLineGraph` provides a small set of special functions (polynomial, exponential, ...), which draw their parameters from the internal or external parameters:
|
||||
### Predefined "special" functions
|
||||
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:
|
||||
```c++
|
||||
JKQTPxFunctionLineGraph* func6=new JKQTPxFunctionLineGraph(plot);
|
||||
func6->setSpecialFunction(JKQTPxFunctionLineGraph::Line);
|
||||
// here we set offset and slope of the line
|
||||
// here we set offset p0=-1 and slope p1=1.5 of the line p0+p1*x
|
||||
func6->set_paramsV(-1,1.5);
|
||||
func6->set_title("special function: linear");
|
||||
plot->addGraph(func6);
|
||||
```
|
||||
|
||||
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`:
|
||||
```c++
|
||||
JKQTPxFunctionLineGraph* func7=new JKQTPxFunctionLineGraph(plot);
|
||||
func7->setSpecialFunction(JKQTPxFunctionLineGraph::Line);
|
||||
// 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);
|
||||
func7->set_parameterColumn(paramCol);
|
||||
func7->set_title("special function: linear");
|
||||
plot->addGraph(func7);
|
||||
```
|
||||
|
||||
|
||||
### Screenshot
|
||||
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)
|
||||
|
||||
### Notes
|
||||
Note that all the different variants to provide parameters can be used with all types of functions!
|
||||
|
||||
Also see the example [Plotting Parsed Mathematical Functions as Line Graphs](https://github.com/jkriege2/JKQtPlotter/tree/master/test/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.
|
||||
|
||||
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)`:
|
||||
|
||||
![jkqtplotter_simpletest_functionplot_fy](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_functionplot_fy.png)
|
||||
|
||||
|
||||
[Back to JKQTPlotter main page](https://github.com/jkriege2/JKQtPlotter/)
|
@ -79,14 +79,26 @@ int main(int argc, char* argv[])
|
||||
func5->set_title("static C function $10*\\sin(x)/x$");
|
||||
plot->addGraph(func5);
|
||||
|
||||
// 6. finally JKQTPxFunctionLineGraph defines a small set of common functions
|
||||
// 7. 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
|
||||
// here we set offset p0=-1 and slope p1=1.5 of the line p0+p1*x
|
||||
func6->set_paramsV(-1,1.5);
|
||||
func6->set_title("special function: linear");
|
||||
func6->set_title("special function: linear p_0=-1, p_1=1.5");
|
||||
plot->addGraph(func6);
|
||||
|
||||
// 7. finally JKQTPxFunctionLineGraph defines a small set of common functions
|
||||
JKQTPxFunctionLineGraph* func7=new JKQTPxFunctionLineGraph(plot);
|
||||
func7->setSpecialFunction(JKQTPxFunctionLineGraph::Line);
|
||||
// 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);
|
||||
func7->set_parameterColumn(paramCol);
|
||||
func7->set_title("special function: linear p_0=1, p_1=-1.5");
|
||||
plot->addGraph(func7);
|
||||
|
||||
|
||||
// 8. set some axis properties (we use LaTeX for nice equation rendering)
|
||||
plot->getXAxis()->set_axisLabel(QObject::tr("x-axis"));
|
||||
|
@ -3,7 +3,10 @@
|
||||
# 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.
|
||||
### Plot Function f(x)
|
||||
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.
|
||||
|
||||
Note: See the example [Plotting Mathematical Functions as Line Graphs](https://github.com/jkriege2/JKQtPlotter/tree/master/test/simpletest_functionplot) if you don't want to draw parsed functions, but want to provide a C function, or C++ functor!
|
||||
|
||||
Adding an evaluated funtion to a graph is very simple:
|
||||
```c++
|
||||
@ -45,6 +48,23 @@ This code snippet results in a plot like this:
|
||||
|
||||
![jkqtplotter_simpletest_parsedfunctionplot](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_parsedfunctionplot.png)
|
||||
|
||||
### Plotting with parameters
|
||||
As shown in [Plotting Mathematical Functions as Line Graphs](https://github.com/jkriege2/JKQtPlotter/tree/master/test/simpletest_functionplot) you can also use externally set parameters in a plot function. These parameters can be double numbers and may be set with either as an internal parameter vector, or may be read from a parameter column (as shown in the [linked example](https://github.com/jkriege2/JKQtPlotter/tree/master/test/simpletest_functionplot)). These parameters are available as variables `p1`, `p2`, ... in the function string. Here is a small example:
|
||||
|
||||
```c++
|
||||
JKQTPxParsedFunctionLineGraph* parsedFunc=new JKQTPxParsedFunctionLineGraph(plot);
|
||||
parsedFunc->set_function("sin(x*p1)*exp(-x/p2)");
|
||||
parsedFunc->set_paramV(/*p1=*/8, /*p2=*/4);
|
||||
parsedFunc->set_title("user function");
|
||||
```
|
||||
|
||||
### Plot Function f(y)
|
||||
If you use the graph class `JKQTPyParsedFunctionLineGraph` instead of `JKQTPxParsedFunctionLineGraph`, you can plot functions `x=f(y)` (instead of `y=f(x)`). The function from the example above will then ahve to be changed to `sin(y*8)*exp(-y/4)` and the result will look like this:
|
||||
|
||||
![jkqtplotter_simpletest_parsedfunctionplot_fy](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_parsedfunctionplot_fy.png)
|
||||
|
||||
|
||||
### Properties of the Adaptive Plotting Algorithm
|
||||
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)
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include <QApplication>
|
||||
#include <QLineEdit>
|
||||
#include <QCheckBox>
|
||||
#include <QFormLayout>
|
||||
#include <QDoubleSpinBox>
|
||||
#include "jkqtplotter/jkqtplotter.h"
|
||||
#include "jkqtplotter/jkqtpgraphsparsedfunction.h"
|
||||
|
||||
@ -16,11 +18,23 @@ int main(int argc, char* argv[])
|
||||
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");
|
||||
QCheckBox* check=new QCheckBox("display sample points");
|
||||
QDoubleSpinBox* spinP1=new QDoubleSpinBox(&mainWin);
|
||||
spinP1->setValue(8);
|
||||
spinP1->setRange(-10000,10000);
|
||||
spinP1->setToolTip("enter a Value for parameter <tt>p1</tt> and press ENTER to update the graph");
|
||||
QDoubleSpinBox* spinP2=new QDoubleSpinBox(&mainWin);
|
||||
spinP2->setValue(4);
|
||||
spinP2->setRange(-10000,10000);
|
||||
spinP2->setToolTip("enter a Value for parameter <tt>p1</tt> and press ENTER to update the graph");
|
||||
JKQtPlotter* plot=new JKQtPlotter(&mainWin);
|
||||
QFormLayout* flayout=new QFormLayout;
|
||||
QVBoxLayout* layout=new QVBoxLayout;
|
||||
mainWin.setLayout(layout);
|
||||
layout->addWidget(edit);
|
||||
layout->addWidget(check);
|
||||
flayout->addRow("equation:", edit);
|
||||
flayout->addRow("p1 =", spinP1);
|
||||
flayout->addRow("p2 =", spinP2);
|
||||
flayout->addRow("", check);
|
||||
layout->addLayout(flayout);
|
||||
layout->addWidget(plot);
|
||||
|
||||
// 2. now we add a JKQTPxParsedFunctionLineGraph object, which will draw the function from
|
||||
@ -31,15 +45,18 @@ int main(int argc, char* argv[])
|
||||
// the graph is updated:
|
||||
auto updateGraphFunctor=
|
||||
[=]() {
|
||||
parsedFunc->set_title("user function: \\verb{"+edit->text()+"}");
|
||||
parsedFunc->set_function(edit->text());
|
||||
parsedFunc->set_displaySamplePoints(check->isChecked());
|
||||
plot->update_plot();
|
||||
parsedFunc->set_title(QString("user function: \\verb{"+edit->text()+"}, p_1=%1, p_2=%2").arg(spinP1->value()).arg(spinP2->value()));
|
||||
parsedFunc->set_function(edit->text());
|
||||
parsedFunc->set_paramsV(spinP1->value(), spinP2->value());
|
||||
parsedFunc->set_displaySamplePoints(check->isChecked());
|
||||
plot->update_plot();
|
||||
};
|
||||
QObject::connect(edit, &QLineEdit::returnPressed, updateGraphFunctor);
|
||||
QObject::connect(edit, &QLineEdit::editingFinished, updateGraphFunctor);
|
||||
QObject::connect(check, &QCheckBox::toggled, updateGraphFunctor);
|
||||
edit->setText("sin(x*8)*exp(-x/4)");
|
||||
QObject::connect(spinP1, &QDoubleSpinBox::editingFinished, updateGraphFunctor);
|
||||
QObject::connect(spinP2, &QDoubleSpinBox::editingFinished, updateGraphFunctor);
|
||||
edit->setText("sin(x*p1)*exp(-x/p2)");
|
||||
updateGraphFunctor();
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user