/*
**************************************************************
* C++ Mathematical Expression Toolkit Library *
* *
* ExprTk GNUPlot Multi-Curve Example *
* Author: Arash Partow (1999-2025) *
* URL: https://www.partow.net/programming/exprtk/index.html *
* *
* Copyright notice: *
* Free use of the Mathematical Expression Toolkit Library is *
* permitted under the guidelines and in accordance with the *
* most current version of the MIT License. *
* https://www.opensource.org/licenses/MIT *
* SPDX-License-Identifier: MIT *
* *
**************************************************************
*/
#include
#include
#include
#include
#include
#include "exprtk.hpp"
class exprtk_gnuplot_fx;
class exprtk_fx_curve
{
public:
friend class exprtk_gnuplot_fx;
exprtk_fx_curve& set_title(const std::string& title)
{
title_ = title;
return *this;
}
exprtk_fx_curve& set_domain(const double min_x, const double max_x)
{
min_x_ = min_x;
max_x_ = max_x;
return *this;
}
exprtk_fx_curve& set_expression(const std::string& expression)
{
expression_ = expression;
return *this;
}
private:
std::string title_;
std::string expression_;
double min_x_;
double max_x_;
double min_y_;
double max_y_;
};
class exprtk_gnuplot_fx
{
public:
bool plot()
{
for (std::size_t i = 0; i < curve_list_.size(); ++i)
{
if (!generate_data(i,curve_list_[i]))
return false;
}
return generate_gp_script();
}
exprtk_gnuplot_fx& add_curve(const exprtk_fx_curve& curve)
{
curve_list_.push_back(curve);
return *this;
}
private:
bool generate_gp_script()
{
std::ofstream stream("plot.gp");
if (!stream)
{
return false;
}
double min_x = +std::numeric_limits::max();
double max_x = -std::numeric_limits::max();
double min_y = +std::numeric_limits::max();
double max_y = -std::numeric_limits::max();
for (std::size_t i = 0; i < curve_list_.size(); ++i)
{
exprtk_fx_curve& curve = curve_list_[i];
if (curve.min_x_ < min_x) min_x = curve.min_x_;
if (curve.max_x_ > max_x) max_x = curve.max_x_;
if (curve.min_y_ < min_y) min_y = curve.min_y_;
if (curve.max_y_ > max_y) max_y = curve.max_y_;
}
stream << "set term png\n";
stream << "set output 'plot.png'\n";
stream << "set xrange[" << min_x << ":" << max_x <<"]\n";
stream << "set yrange[" << min_y << ":" << max_y <<"]\n";
stream << "set xzeroaxis\n";
stream << "set yzeroaxis\n";
stream << "plot \\\n";
for (std::size_t i = 0; i < curve_list_.size(); ++i)
{
stream << "'data.dat" << i << "' using 1:2:(1.0) smooth unique title '" << curve_list_[i].title_;
stream << (((i + 1) < curve_list_.size()) ? "',\\\n" : "'\n");
}
return true;
}
bool generate_data(const std::size_t index, exprtk_fx_curve& curve)
{
typedef exprtk::symbol_table symbol_table_t;
typedef exprtk::expression expression_t;
typedef exprtk::parser parser_t;
double x = 0.0;
symbol_table_t symbol_table;
symbol_table.add_constants();
symbol_table.add_variable("x",x);
expression_t expression;
expression.register_symbol_table(symbol_table);
parser_t parser;
if (!parser.compile(curve.expression_,expression))
{
return false;
}
const std::string file_name = std::string("data.dat") + (char)('0' + index);
std::ofstream stream(file_name.c_str());
if (!stream)
{
return false;
}
curve.min_y_ = +std::numeric_limits::max();
curve.max_y_ = -std::numeric_limits::max();
stream << std::setprecision(10);
const double increment = std::min(0.00005,std::abs(curve.max_x_ - curve.min_x_) / 1000.0);
for (x = curve.min_x_; x <= curve.max_x_; x += increment)
{
const double y = expression.value();
if (y < curve.min_y_) curve.min_y_ = y;
else if (y > curve.max_y_) curve.max_y_ = y;
stream << x << "\t" << y << "\n";
}
const double diff_y = std::abs(curve.max_y_ - curve.min_y_);
const double perc7_5 = diff_y * 0.075; //7.5%
curve.min_y_ -= perc7_5;
curve.max_y_ += perc7_5;
return true;
}
std::deque curve_list_;
};
int main()
{
exprtk_gnuplot_fx plotter;
plotter
.add_curve(
exprtk_fx_curve()
.set_expression("sin(2 * pi * x) + cos(x / 2 * pi)")
.set_domain(-5,+5)
.set_title("ExprTk Curve 1"))
.add_curve(
exprtk_fx_curve()
.set_expression("clamp(-1.0,sin(2 * pi * x) + cos(x / 2 * pi),+1.0)")
.set_domain(-5,+5)
.set_title("ExprTk Curve 2"));
plotter.plot();
return 0;
}
/*
Build and Run:
1. c++ -pedantic-errors -Wall -Wextra -Werror -Wno-long-long -O3 -DNDEBUG -o exprtk_gnuplot_multi exprtk_gnuplot_multi.cpp -lstdc++
2. ./exprtk_gnuplot_multi
3. gnuplot plot.gp
*/