Folders and files
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Repository files navigation
#+OPTIONS: H:3 toc:t \n:nil ::t |:t ^:{} -:t f:t *:t tex:t d:t tags:not-in-toc
#+BLOG: wordpress
#+POSTID: 931
#+DATE: [2019-12-06 Fri 19:40]
#+TITLE: Easy Creation of GnuPlot Scripts from C++
#+TAGS: Cpp, GnuPlot
# trick from https://github.com/rexim/org-cliplink/
[[https://travis-ci.org/vincent-picaud/GnuPlotScript][file:https://travis-ci.org/vincent-picaud/GnuPlotScripting.svg?branch=master]]
* Table of contents :TOC:noexport:
- [[#what-is-it][What is it?]]
- [[#news][News]]
- [[#contributors][Contributors]]
- [[#installation][Installation]]
- [[#examples][Examples]]
- [[#plot-and-fit-data][Plot and fit data]]
- [[#ascii-matrix-data][Ascii matrix data]]
- [[#new-matrix-data][(NEW) Matrix data]]
- [[#histogram][Histogram]]
- [[#graph][Graph]]
- [[#density-plot][Density plot]]
- [[#pipe-example][Pipe example]]
- [[#supported-export-formats][Supported export formats]]
- [[#global-config-demonstration][Global config demonstration]]
- [[#documentation][Documentation]]
- [[#data-classes][Data classes]]
- [[#script-classes][Script classes]]
- [[#global_config-class][Global_Config class]]
- [[#references][References]]
- [[#faq][FAQ]]
* What is it?
A simple C++17 library that allows easy creation and execution of
gnuplot scripts. These scripts will embed their data and can be
replayed/modified later.
The library depends on [[https://github.com/fmtlib/fmt][{fmt} library]].
I use it when I want to plot some data with a minimal effort when I
develop stuff in C++.
For the moment the library is only tested under Linux (it should also
works under Windows but I have not checked yet).
# Feel free to use it: [[https://github.com/vincent-picaud/GnuPlotScripting][GitHub, GnuPlotScripting]].
** News
- [2020-10-20 Tue] \\
- *Version v1.1.0*!
- some compilation warning fixes
- a new Data_Array_2 class
- [2020-01-18 Sat 09:17] \\
- *Version v1.0.0 release!*
- More documentation
- Fix a bug in export_as(...,path/output_filename): the path was ignored
- [2020-01-09 Thu 22:46] \\
- Added =Data_Supervised= class and associated example (see *Density plot*
in *Example* section)
- Code cleaning (no breaking change!)
- Tagged as v0.2.0 (v1.0.0 gets closer :-) )
- [2019-12-09 Mon 18:34] \\
Added SVG, TGIF, PNGCairo and PDFCairo export formats.
Tagged as v0.0.3.
- [2019-12-08 Sun 20:21] \\
Some minor fixes + doc concerning Global_Config logger methods.
Tagged as v0.0.2
- [2019-12-08 Sun 11:21] \\
Initial version.
Tagged as v0.0.1
** Contributors
- [[https://github.com/Gjacquenot][Guillaume Jacquenot]]: Travis CI
* Installation
The library currently uses the [[https://mesonbuild.com/][meson]] build system.
If you are not familiar with meson, the compilation procedure is as follows:
#+BEGIN_SRC sh :eval never
git clone https://github.com/vincent-picaud/GnuPlotScripting.git
cd GnuPlotScripting/
meson build
cd build
ninja test
#+END_SRC
Examples can then be found in the =build/examples/= directory.
If you want to install the package:
#+BEGIN_SRC sh :eval never
ninja install
#+END_SRC
Note that you can define custom installation path, at the beginning of
the compilation procedure, use:
#+BEGIN_SRC sh :eval never
meson --prefix=/install_path/ build
#+END_SRC
instead of =meson build=.
* Examples
** Plot and fit data
#+BEGIN_SRC sh :wrap "src cpp :eval never" :results output :exports results
cat $(pwd)/examples/plot.cpp
#+END_SRC
#+RESULTS:
#+BEGIN_src cpp :eval never
#include "GnuPlotScripting/GnuPlotScripting.hpp"
#include <iostream>
#include <vector>
using namespace GnuPlotScripting;
// From: https://www.cs.hmc.edu/~vrable/gnuplot/using-gnuplot.html
int
main()
{
std::vector<double> time, angle, stdvar;
time = {0.0, 1.0, 2.1, 3.1, 4.2, 5.2, 6.2, 7.2, 8.2, 9.1, 10.0, 11.0, 12.0,
12.9, 13.8, 14.9, 15.9, 17.0, 17.9, 18.9, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0,
26.0, 27.0, 28.0, 29.0, 30.0, 31.0, 32.0, 32.9, 33.8, 34.7, 35.7, 36.6, 37.7};
angle = {-14.7, 8.6, 28.8, 46.7, 47.4, 36.5, 37.0, 5.1, -11.2, -22.4, -35.5, -33.6, -21.1,
-15.0, -1.6, 19.5, 27.5, 32.6, 27.5, 20.2, 13.8, -1.3, -24.5, -25.0, -25.0, -20.2,
-9.9, 5.8, 14.7, 21.8, 29.8, 21.4, 24.6, 25.8, 0.6, -16.6, -24.0, -24.6, -19.8};
stdvar = {3.6, 3.6, 3.0, 3.4, 3.5, 3.4, 10.3, 3.4, 3.4, 3.5, 3.6, 3.9, 3.9,
4.2, 2.7, 3.2, 2.8, 3.5, 2.7, 3.3, 3.4, 4.2, 6.7, 3.3, 3.1, 3.6,
3.2, 3.2, 3.0, 3.5, 2.7, 4.1, 2.7, 12.0, 2.9, 3.2, 3.7, 3.8, 3.5};
Script_File script("plot.gp");
Data_Vector data(
time, angle, stdvar); // <- you can stack as many vector/valarray etc.. as you want
// only size() and operator[] are required.
script.free_form("set title 'Cavendish Data'");
script.free_form("set xlabel 'Time (s)'");
script.free_form("set ylabel 'Angle (mrad)'");
script.free_form("set grid");
script.free_form("plot {} with yerrorbars notitle", data);
script.free_form("replot {} u 1:2 with lines title '{}'", data, "raw data");
script.free_form("theta(t) = theta0 + a * exp(-t / tau) * sin(2 * pi * t / T + phi)");
script.free_form("fit theta(x) {} using 1:2:3 via a, tau, phi, T, theta0", data);
script.free_form("replot theta(x) lw {} lc {} title 'best-fit curve'", 2, 4);
script.export_as(PNG(), "plot");
}
#+END_src
It generates this figure:
[[file:figures/plot.png]]
*Note:* the generated =plot.gp= gnutplot script embeds the data and you
can replay it whenever you want:
#+BEGIN_SRC sh :eval never
gnuplot plot.pg -
#+END_SRC
** Ascii matrix data
#+BEGIN_SRC sh :wrap "src cpp :eval never" :results output :exports results
cat $(pwd)/examples/matrix.cpp
#+END_SRC
#+RESULTS:
#+BEGIN_src cpp :eval never
#include "GnuPlotScripting/GnuPlotScripting.hpp"
#include <iostream>
using namespace GnuPlotScripting;
// Example from: https://stackoverflow.com/a/27049991/2001017
// Also see: https://stackoverflow.com/q/32458753/2001017
//
int
main()
{
Data_Ascii data(
"0.00 0.65 0.65 0.25\n"
"0.25 0.00 0.75 0.25\n"
"0.50 0.60 0.00 0.25\n"
"0.75 0.25 0.10 0.00\n");
Script_File script("matrix.gp");
script.free_form("set autoscale fix");
script.free_form("set cbrange [-1:1]");
script.free_form("unset colorbox");
script.free_form("unset key");
script.free_form(
"plot {} matrix using 1:2:3 with image, '' matrix using "
"1:2:(sprintf('%.2f', $3)) with labels font ',16'",
data);
script.export_as(PNG(), "matrix");
script.export_as(EPSLATEX().set_standalone(true), "matrix");
}
#+END_src
It generates this figure:
[[file:figures/matrix.png]]
It also generates a standalone =matrix.tex= file you can process with
=pdflatex matrix.tex= to get a monochrome =matrix.pdf= file. If you want
colorized pdf simply use:
#+begin_src cpp :eval never
EPSLATEX().set_standalone(true).set_color(true)
#+end_src
** (NEW) Matrix data
You can also use the =Array_2= container to temporary store your data
#+BEGIN_SRC sh :wrap "src cpp :eval never" :results output :exports results
cat $(pwd)/examples/array_2.cpp
#+END_SRC
#+RESULTS:
#+begin_src cpp :eval never
#include "GnuPlotScripting/array_2.hpp"
#include "GnuPlotScripting/GnuPlotScripting.hpp"
#include <iostream>
using namespace GnuPlotScripting;
int
main()
{
const double X = 2, Y = 2;
const std::size_t I = 100, J = 120;
const auto f = [=](const std::size_t i, const std::size_t j) {
const double x = (2 * i / double(I - 1) - 1) * X;
const double y = (2 * j / double(J - 1) - 1) * Y;
return exp(-x * x - y * y);
};
Array_2 array_2(I, J, f);
Data_Array_2 data(array_2);
Script_File script("array_2.gp");
script.free_form("set autoscale fix");
script.free_form("plot {} matrix using 1:2:3 with image", data);
script.export_as(PNG(), "array_2");
}
#+end_src
It generates this figure:
[[file:figures/array_2.png][file:figures/array_2.png]]
** Histogram
#+BEGIN_SRC sh :wrap "src cpp :eval never" :results output :exports results
cat $(pwd)/examples/histogram.cpp
#+END_SRC
#+RESULTS:
#+BEGIN_src cpp :eval never
#include "GnuPlotScripting/GnuPlotScripting.hpp"
#include <iostream>
#include <random>
using namespace GnuPlotScripting;
// Example from:
// https://stackoverflow.com/a/7454274/2001017
//
template <typename T>
void
gnuplot_histogram(Script& script,
const std::vector<T>& data,
const size_t n_bin,
const typename std::vector<T>::value_type min,
const typename std::vector<T>::value_type max)
{
assert(max > min);
assert(n_bin > 0);
Data_Vector gnuplot_data(data);
const double width = (max - min) / n_bin;
script.free_form("width={}", width);
script.free_form("set title 'Histogram min={}, max={}, Δbin={}, #bins={}, #sample={}'",
min,
max,
width,
n_bin,
data.size());
script.free_form("hist(x,width)=width*floor(x/width)+width/2.0");
script.free_form("set boxwidth width*0.9");
script.free_form("set style fill solid 0.5");
script.free_form("plot {} u (hist($1,width)):(1.0) smooth freq w boxes notitle", gnuplot_data);
}
int
main()
{
std::random_device rd;
std::mt19937 gen(rd());
const double a = 2, b = 1;
std::gamma_distribution<> distribution(a, b);
std::vector<double> data(10000);
for (auto& data_i : data) data_i = distribution(gen);
Script_File script("histogram.gp");
gnuplot_histogram(script, data, 100, 0, 3);
script.export_as(PNG(), "histogram");
}
#+END_src
The generated figure is:
[[file:figures/histogram.png]]
** Graph
#+BEGIN_SRC sh :wrap "src cpp :eval never" :results output :exports results
cat $(pwd)/examples/graph.cpp
#+END_SRC
#+RESULTS:
#+BEGIN_src cpp :eval never
#include "GnuPlotScripting/GnuPlotScripting.hpp"
#include <iostream>
using namespace GnuPlotScripting;
// Example from the "Gnuplot in Action" book
int
main()
{
Data_Ascii data(
"-1 -1 0 # A\n"
"-1 1 0 # B\n"
" 1 0 0 # C\n"
" 0 0 1.75 # D\n"
"\n\n"
"-1 -1 0 -1 1 0 \n"
"-1 -1 0 1 0 0 \n"
"-1 -1 0 0 0 1.750 \n"
"-1 1 0 1 0 0 \n"
"-1 1 0 0 0 1.75 \n"
" 1 0 0 0 0 1.75 \n");
Script_File script_a("graph_3D.gp");
script_a.free_form("unset border");
script_a.free_form("unset tics");
script_a.free_form("unset key");
script_a.free_form("set view 75,35");
script_a.free_form("splot {} index 0 with points pointtype 7 pointsize 3", data);
script_a.free_form("replot {} index 1 u 1:2:3:($4-$1):($5-$2):($6-$3) with vectors nohead", data);
script_a.free_form("pause -1");
Script_File script_b("graph_2D.gp");
script_b.free_form("unset border");
script_b.free_form("unset tics");
script_b.free_form("unset key");
script_b.free_form("plot {} index 0 with points pointtype 7 pointsize 3", data);
script_b.free_form("replot {} index 1 u 1:2:($4-$1):($5-$2) with vectors nohead", data);
script_b.export_as(PNG(), "graph");
}
#+END_src
It generates this figure:
[[file:figures/graph.png]]
but also an active gnuplot 3D figure you can rotate etc...
** Density plot
This demo shows how to use the =Data_Supervised= class.
#+BEGIN_SRC sh :wrap "src cpp :eval never" :results output :exports results
cat $(pwd)/examples/density_plot.cpp
#+END_SRC
#+RESULTS:
#+BEGIN_src cpp :eval never
#include "GnuPlotScripting/GnuPlotScripting.hpp"
#include <array>
#include <iostream>
using namespace GnuPlotScripting;
std::array<double, 10> X_1 = {0.1, 0.3, 0.1, 0.6, 0.4, 0.6, 0.5, 0.9, 0.4, 0.7};
std::array<double, 10> X_2 = {0.1, 0.4, 0.5, 0.9, 0.2, 0.3, 0.6, 0.2, 0.4, 0.6};
std::array<int, 10> Y = {1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
int
main()
{
Data_Supervised data(Y, X_1, X_2);
Script_File script("density_plot.gp");
script.free_form("set title 'Supervised learning'");
script.free_form("set pm3d map interpolate 2,2");
script.free_form("set palette model RGB defined ( 0 'gray80', 1 'white' )");
script.free_form("set contour base");
script.free_form("set cntrparam levels discrete 0.5");
script.free_form("unset colorbox"); // no palette
// CAVEAT: for contour use pm3d and not image
script.free_form(
"splot 'density_plot_data.txt' u ($1/60):($2/60):3 matrix with pm3d lw 2 notitle");
for (size_t i = 0; i < data.index_size(); i++)
{
// CAVEAT: to prevent
// <<warning: Cannot contour non grid data. Please use "set dgrid3d">>
// do not forget "nocontour"
script.free_form(
"replot {0} index {1} u 1:2:3 with points pt '{1}' ps 2 notitle nocontour", data, i);
}
script.export_as(PNG(), "density_plot");
return EXIT_SUCCESS;
}
#+END_src
Generated figure:
[[file:figures/density_plot.png]]
** Pipe example
Instead of creating a file, we can create a pipe with =popen()= to
directly send data to gnuplot.
#+BEGIN_SRC sh :wrap "src cpp :eval never" :results output :exports results
cat $(pwd)/examples/pipe.cpp
#+END_SRC
#+RESULTS:
#+BEGIN_src cpp :eval never
#include "GnuPlotScripting/GnuPlotScripting.hpp"
#include <chrono>
#include <iostream>
#include <thread>
#include <utility> // std::pair
#include <vector>
using namespace GnuPlotScripting;
int
main()
{
// AFAIK one has to replot all data at each iteration
//
std::vector<std::pair<size_t, double>> data;
Script_Pipe pipe(Script_Pipe_Mode_Enum::Not_Persistent);
pipe.free_form("set xlabel 'iterations'");
for (size_t i = 0; i < 100; i++)
{
data.push_back({i, 1 / (i + 1.)});
pipe.free_form("plot '-' using 1:2 with lines t \"residue\" ");
for (const auto& data_i : data)
{
pipe.free_form("{} {}", data_i.first, data_i.second);
}
pipe.free_form("e");
pipe.flush();
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
}
#+END_src
** Supported export formats
This example silently exports a basic plot in all supported formats:
#+BEGIN_SRC sh :wrap "src cpp :eval never" :results output :exports results
cat $(pwd)/examples/available_export_formats.cpp
#+END_SRC
#+RESULTS:
#+begin_src cpp :eval never
#include "GnuPlotScripting/GnuPlotScripting.hpp"
#include <iostream>
using namespace GnuPlotScripting;
int
main()
{
Script_File script("available_export_formats.gp", Script_File_Mode_Enum::Silent);
script.free_form("plot sin(x) t 'sin(x)'");
script.export_as(PNG(), "available_export_formats");
script.export_as(EPSLATEX().set_standalone(true), "available_export_formats");
script.export_as(SVG(), "available_export_formats");
script.export_as(TGIF(), "available_export_formats");
script.export_as(PNGCairo(), "available_export_formats_cairo");
script.export_as(PNGCairo().set_color(false), "available_export_formats_cairo_nocolor");
script.export_as(PDFCairo(), "available_export_formats_pdfcairo");
}
#+end_src
** Global config demonstration
This last example shows how to use =Global_Config=.
#+BEGIN_SRC sh :wrap "src cpp :eval never" :results output :exports results
cat $(pwd)/examples/global_config.cpp
#+END_SRC
#+RESULTS:
#+BEGIN_src cpp :eval never
#include "GnuPlotScripting/GnuPlotScripting.hpp"
#include <iostream>
using namespace GnuPlotScripting;
int
main()
{
global_config().set_logger(
[](const char *const msg) { std::cerr << "====> My logger " << msg << std::endl; });
// If you want to remove logger: global_config().set_logger();
// If you want to restore the default one: global_config().set_default_logger();
// If you want to globally overwrite Script_File_Mode_Enum to Persistent, do:
global_config().set_script_file_mode(Script_File_Mode_Enum::Persistent);
for (size_t i = 1; i < 5; i++)
{
Script_File script(fmt::format("script_{}.gp", i), Script_File_Mode_Enum::Silent);
script.free_form("plot sin({0}*x) t 'sin({0}*x)'", i);
}
// To stop overwriting local choice:
global_config().set_script_file_mode();
// Now this will silently run scripts
for (size_t i = 1; i < 5; i++)
{
Script_File script(fmt::format("script_{}.gp", i), Script_File_Mode_Enum::Silent);
script.free_form("plot sin({0}*x) t 'sin({0}*x)'", i);
}
}
#+END_src
* Documentation
The library is quite simple and there is only 3 things you must know:
- Data_XXX are classes to store your data
- Script_XXX are script classes to write your scripts
- global_config() returns a Global_Config object used to define global options.
** Data classes
=Data= classes store data that is embedded into the generated gnuplot
scripts. These classes internally use an =uuid= that insures that data
is embedded only once. By example, when you write:
#+BEGIN_SRC cpp :eval never
script.free_form("plot {} u 1:2",data);
script.free_form("replot {} u 1:3",data);
script.free_form("replot {} u 1:4",data);
#+END_SRC
data is copied *only once* into the script file.
*** =Data_Ascii=
The most basic =Data= classe is the =Data_Ascii= one. It directly uses
data defined by a =std::string=. By example:
#+BEGIN_SRC cpp :eval never
Data_Ascii data(
"0.00 0.65 0.65 0.25\n"
"0.25 0.00 0.75 0.25\n"
"0.50 0.60 0.00 0.25\n"
"0.75 0.25 0.10 0.00\n");
#+END_SRC
*Note:* it is really easy to define your own =Data= class. By example
=Data_Ascii= code is as simple as:
#+BEGIN_SRC cpp :eval never
class Data_Ascii final : public Data
{
public:
Data_Ascii(const std::string& data) : Data(data) {}
};
#+END_SRC
*** (NEW) =Data_Array_2=
Data to plot is defined using an basic two-dimensional array container, Array_2.
#+BEGIN_SRC cpp :eval never
Array_2 array_2(row_size,column_size);
// fill component: array_2(i,j)= ...
Data_Array_2 data(array_2);
// plot data
#+END_SRC
*** =Data_Vector=
Creates columns of data from =std::vector=, =std::valarray=... In fact
only the =size()= method and the =operator[]= operator are used and you
can use any object defining these two methods. By example:
#+BEGIN_SRC cpp :eval never
std::vector<double> v1(10);
std::vector<int> v2(10);
std::valarray<double> v3(10);
// ...
Data_Vector data(v1,v2,v3);
#+END_SRC
*** =Data_Supervised=
The =Data_Supervised= class is similar to the =Data_Vector= except that it
uses and extra _category_ vector. It can be used to plot points
associated to a supervised learning task. By example:
#+BEGIN_SRC cpp :eval never
std::array<double, 10> X_1 = {0.1, 0.3, 0.1, 0.6, 0.4, 0.6, 0.5, 0.9, 0.4, 0.7}; // X_1 feature
std::array<double, 10> X_2 = {0.1, 0.4, 0.5, 0.9, 0.2, 0.3, 0.6, 0.2, 0.4, 0.6}; // X_2 feature
std::array<int, 10> Y = {1, 1, 1, 1, 1, 0, 0, 0, 0, 0}; // category (=label)
Data_Supervised data(Y, X_1, X_2); // note: the category vector Y is always the _first_ argument
std::cout << data.data();
#+END_SRC
*Note:* as AFAK it is not possible to directly plot points with symbols
retrieved from the the Y column (see [[https://stackoverflow.com/questions/29622885/how-set-point-type-from-data-in-gnuplot][SO
how-set-point-type-from-data-in-gnuplot]]), hence the =Data_Supervised=
class sorts and groups the sample according to their categories. By
example the previous code prints:
#+BEGIN_EXAMPLE
0.6 0.3 0
0.9 0.2 0
0.4 0.4 0
0.1 0.1 1
0.1 0.5 1
0.6 0.9 1
0.4 0.2 1
0.5 0.6 2
0.7 0.6 2
0.3 0.4 3
#+END_EXAMPLE
Creating these groups allows to use the gnuplot *index* keyword to plot
all points associated to a given category. By example:
#+BEGIN_SRC gnuplot :eval never
replot "$data_uuid" index i u 1:2:3 with points; # plot points of category i
#+END_SRC
Also note that when data is embedded, the =Y= category column is the
*last one*. The rational is that for:
#+BEGIN_SRC cpp :eval never
Data_Supervised data_a(Y, X_1, X_2);
Data_Vector data_b(X_1, X_2);
#+END_SRC
then in *both* cases, =X_1= column index is 1 and =X_2= column index is 2.
** Script classes
There are two script classes:
- =Script_File= creates a file to store the script.
- =Script_Pipe= creates a pipe to push data directly to GnuPlot, in that
case no file is created.
They inherits from the =Script= base class that provides the following methods:
#+BEGIN_SRC cpp :eval never
template <typename... ARGS>
Script& free_form(ARGS&&... args);
Script& export_as(const Export_As& export_as, const std::filesystem::path& output);
void flush();
#+END_SRC
- =free_form= allows you to write free form using the =fmt= library, by example:
#+BEGIN_SRC cpp :eval never
script.free_form("plot '{}' u {}:{}","data_file.dat",1,2);
#+END_SRC
- =flush()= forces buffer to be flushed
- =export_as()= generates script code to export the figure in the given
format, by example:
#+BEGIN_SRC cpp :eval never
script.export_as(EPSLATEX().set_standalone(true),"filename");
#+END_SRC
*Note:*
- the right extension for =filename= is automatically added (here this
would be =.tex=).
- currently supported formats are =PNG=, =EPSLATEX=, =SVG=, =TGIF=,
=PNGCairo= and =PDFCairo=.
*** =Script_File= class
The only relevant part is the constructor:
#+BEGIN_SRC cpp :eval never
Script_File(const std::filesystem::path& filename,
Script_File_Mode_Enum script_file_mode = Script_File_Mode_Enum::Persistent);
#+END_SRC
- =Filename= is the gnuplot script file name (you are free to use the
file extension you want, on my side I use the =.gp= extension).
- =script_file_mode= is important as it defines what happens at destruction time
- =Script_File_Mode_Enum::None= does nothing
- =Script_File_Mode_Enum::Silent= silently runs GnuPlot (this will generate your exported figures)
- =Script_File_Mode_Enum::Persistent= runs GnuPlot in persistent mode,
it will generates your figures and left a window opened that
allows you to see the result. This is only an opened window and
*not* an active gnuplot session (you *cannot* interact with the plot).
*Note:* to get an active GnuPlot session, you can replay your script with:
#+BEGIN_SRC sh :eval never
gnuplot filename.gp -
#+END_SRC
(note the final '-', see GnuPlot documentation for further details).
Another possibility is to add a pause in your gnuplot script:
#+BEGIN_SRC cpp :eval never
script.free_form("pause -1");
#+END_SRC
*** =Script_Pipe= class
Here instead of writing into a file, we open a pipe with =popen=. This
allows you to directly command GnuPlot during your code execution. Note
that this is only a *unidirectional* channel.
The constructor is:
#+BEGIN_SRC cpp :eval never
Script_Pipe(Script_Pipe_Mode_Enum script_pipe_mode = Script_Pipe_Mode_Enum::Persistent);
#+END_SRC
as for =Script_File= class, =script_pipe_mode= defines what happens at destruction time:
- =Script_Pipe_Mode_Enum::Not_Persistent= does not keep an opened window
- =Script_Pipe_Mode_Enum::Persistent= keeps an opened, but inactive, window
** Global_Config class
This class allows you to define or overwrite globally some options
#+BEGIN_SRC cpp :eval never
const char* gnuplot_exe() const;
Global_Config& set_gnuplot_exe(const char* const gnuplot_executable);
Global_Config& set_logger(); // removes logger
Global_Config& set_default_logger(); // reuses default one
Global_Config& set_logger(const std::function<void(const char* const msg)>& f); // defines your own
bool has_logger() const;
Global_Config& set_log_message(const char* const msg);
Global_Config& set_script_file_mode(
Script_File_Mode_Enum mode); // globally overwrite local 'script_file_mode'
Global_Config& set_script_file_mode(); // stop overwriting local 'script_file_mode'
std::optional<Script_File_Mode_Enum> script_file_mode() const;
#+END_SRC
- =set/gnuplot_exe()= functions allow you to define GnuPlot executable
filename, by default this is =gnuplot= or =gnuplot.exe= for windows.
- =set/logger()= functions allow you to stop or redirect logs, by example:
#+BEGIN_SRC cpp :eval never
global_config().set_logger([](const char *const msg) {
std::cerr << "====> My logger " << msg << std::endl;
});
#+END_SRC
- =set_script_file_mode()= functions are more interesting as they allow
you to overwrite globally what happens at =Script_File= destruction
time. A typical use case is as follows:
Imagine that your code silently generates a lot of scripts:
#+BEGIN_SRC cpp :eval never
for (size_t i = 1; i < 5; i++)
{
Script_File script(fmt::format("script_{}.gp", i), Script_File_Mode_Enum::Silent);
script.free_form("plot sin({0}*x) t 'sin({0}*x)'", i);
}
#+END_SRC
However at debug time, you want to force visualization to see what
happens. In that case you simply have to add
#+BEGIN_SRC cpp :eval never
global_config().set_script_file_mode(Script_File_Mode_Enum::Persistent);
#+END_SRC
*before*
#+BEGIN_SRC cpp :eval never
for (size_t i = 1; i < 5; i++)
{
...
}
#+END_SRC
This will force all =Script_File= to use
=Script_File_Mode_Enum::Persistent=
* References
- [[http://www.gnuplot.info/][GnuPlot]] official page
- [[https://www.manning.com/books/gnuplot-in-action-second-edition][GnuPlot in Action]] a very well written book
- [[http://www.gnuplotting.org/][www.gnuplotting.org]] a lot of great examples
- [[http://folk.uio.no/inf3330/scripting/doc/gnuplot/Kawano/index-e.html][GnuPlot not so Frequently Asked Questions]]
- [[https://en.wikipedia.org/wiki/Gnuplot][Wikipedia]] the free encyclopedia...
# figures/matrix.png http://pixorblog.files.wordpress.com/2019/12/matrix.png
# figures/histogram.png http://pixorblog.files.wordpress.com/2019/12/histogram.png
# figures/graph.png http://pixorblog.files.wordpress.com/2019/12/graph.png
# figures/plot.png http://pixorblog.files.wordpress.com/2019/12/plot.png
* FAQ
-> your question here